From patchwork Tue Oct 31 11:54:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Minda Chen X-Patchwork-Id: 160083 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b90f:0:b0:403:3b70:6f57 with SMTP id t15csp178505vqg; Tue, 31 Oct 2023 04:56:04 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHFRIVSid45+aghx0ctAoyoWgTz1BpDTu+NOoQoT9GPAM5Pn8cGEKkcPvfcewQeU25wmPyw X-Received: by 2002:a05:6a00:2350:b0:6b4:6b34:8ce0 with SMTP id j16-20020a056a00235000b006b46b348ce0mr15989008pfj.31.1698753364200; Tue, 31 Oct 2023 04:56:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1698753364; cv=none; d=google.com; s=arc-20160816; b=Nv9vgxsPtCO2bOyudTkL7Vl5bTlcoDdMg7Nm9Uiq2Ulzu150N1kwYStb9axxj7xnfQ YsJVTv1QhyvuvHLOE3CCTdFggVuLzIhaYJf+qsJ7SEBd24svtKR59YSdzK4Ux97CzBZ0 5jmr9bnCof96eRWvUv1kaYvHaCodZWA1PPwJ5HSZSOMwUXfdhIlfK/IFfKc/F55oe67l +UdiqCqQc/Qm8PiPtoTqWhlx5r4FoRPfYCsmiziPYn/u8vlEhzZmrTMT/zK/YejDdzDU uE9v0GmsXsDOAruRamTbJVU8B6rgnUhKHtM688nGQ2/pSdqIzVack5Y19GC6bGfhuIrZ qPqg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from; bh=TQurtbL898QOnzWSydTrfaFjzzTnn6kDtR701XE9a84=; fh=ld3UXb1S5Y4IkunPfuj6e9Ppmc+fy6ncC+eQtrVLfK8=; b=aMI6C9CRdIiPIPWdnOGjh8h9VxQdbyqhv7EC8UJ7vQNWcmHedRZ7HUsEBhhhXTlKxx iArv4u85563kr1aISspjXUR/xPYoTD2bna2lGKPt6PvPd62cOrLO9kGekDxhAIqvMD50 cQnbfKf/oNOhHvv2oWu2dfzZlMcnKSxdGApyGqcADViIxHBNmOK5Vutuykb4LMz01330 RvIhLKpHRD4wRSMN95+3wTDS0fauwRXK68c3ZcrmcHMSUTuT2dHsLPKMjmXc0s73vN+8 tyc26pdfFLJ0sygfX7vgswO3RKfVvdwT62fpk6Gv8YLNmW2gN0O84Aj5C028ApXVAFI9 hHYA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.32 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from agentk.vger.email (agentk.vger.email. [23.128.96.32]) by mx.google.com with ESMTPS id j71-20020a63804a000000b005b92b048254si930368pgd.201.2023.10.31.04.56.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Oct 2023 04:56:04 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.32 as permitted sender) client-ip=23.128.96.32; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.32 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by agentk.vger.email (Postfix) with ESMTP id 9581680BEF38; Tue, 31 Oct 2023 04:56:00 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at agentk.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344186AbjJaLzm (ORCPT + 33 others); Tue, 31 Oct 2023 07:55:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57620 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235361AbjJaLzA (ORCPT ); Tue, 31 Oct 2023 07:55:00 -0400 Received: from fd01.gateway.ufhost.com (fd01.gateway.ufhost.com [61.152.239.71]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B782CE4; Tue, 31 Oct 2023 04:54:49 -0700 (PDT) Received: from EXMBX166.cuchost.com (unknown [175.102.18.54]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "EXMBX166", Issuer "EXMBX166" (not verified)) by fd01.gateway.ufhost.com (Postfix) with ESMTP id AAF738155; Tue, 31 Oct 2023 19:54:47 +0800 (CST) Received: from EXMBX171.cuchost.com (172.16.6.91) by EXMBX166.cuchost.com (172.16.6.76) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Tue, 31 Oct 2023 19:54:47 +0800 Received: from ubuntu.localdomain (113.72.146.247) by EXMBX171.cuchost.com (172.16.6.91) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Tue, 31 Oct 2023 19:54:46 +0800 From: Minda Chen To: Conor Dooley , =?utf-8?q?Krzysztof_Wilczy=C5=84ski?= , Rob Herring , Bjorn Helgaas , Lorenzo Pieralisi , "Daire McNamara" , Emil Renner Berthing , Krzysztof Kozlowski CC: , , , , Paul Walmsley , Palmer Dabbelt , Albert Ou , Philipp Zabel , Mason Huo , Leyfoon Tan , Kevin Xie , Minda Chen Subject: [PATCH v10 17/20] PCI: plda: Add event interrupt codes and host init/deinit functions Date: Tue, 31 Oct 2023 19:54:27 +0800 Message-ID: <20231031115430.113586-18-minda.chen@starfivetech.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20231031115430.113586-1-minda.chen@starfivetech.com> References: <20231031115430.113586-1-minda.chen@starfivetech.com> MIME-Version: 1.0 X-Originating-IP: [113.72.146.247] X-ClientProxiedBy: EXCAS062.cuchost.com (172.16.6.22) To EXMBX171.cuchost.com (172.16.6.91) X-YovoleRuleAgent: yovoleflag X-Spam-Status: No, score=-0.8 required=5.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on agentk.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (agentk.vger.email [0.0.0.0]); Tue, 31 Oct 2023 04:56:00 -0700 (PDT) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1781272007628841141 X-GMAIL-MSGID: 1781272007628841141 PLDA implements new codes and IRQ domain ops like PolarFire. plda_get_events() adds interrupt register to event num mapping codes for PLDA local event except DMA engine interrupt events. The DMA engine interrupt events are implemented by vendors. Add PLDA host init and deinit functions. So vendor can use it to init PLDA PCIe host core. Signed-off-by: Minda Chen --- drivers/pci/controller/plda/pcie-plda-host.c | 230 +++++++++++++++++-- drivers/pci/controller/plda/pcie-plda.h | 49 ++++ 2 files changed, 266 insertions(+), 13 deletions(-) diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c index e155d1d78627..10ad26216505 100644 --- a/drivers/pci/controller/plda/pcie-plda-host.c +++ b/drivers/pci/controller/plda/pcie-plda-host.c @@ -3,6 +3,7 @@ * PLDA PCIe XpressRich host controller driver * * Copyright (C) 2023 Microchip Co. Ltd + * StarFive Co. Ltd * * Author: Daire McNamara */ @@ -18,6 +19,15 @@ #include "pcie-plda.h" +void __iomem *plda_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, + int where) +{ + struct plda_pcie_rp *pcie = bus->sysdata; + + return pcie->config_base + PCIE_ECAM_OFFSET(bus->number, devfn, where); +} +EXPORT_SYMBOL_GPL(plda_pcie_map_bus); + static void plda_handle_msi(struct irq_desc *desc) { struct plda_pcie_rp *port = irq_desc_get_handler_data(desc); @@ -262,6 +272,107 @@ static irqreturn_t plda_event_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static u32 plda_get_events(struct plda_pcie_rp *port) +{ + u32 events, val, origin; + + origin = readl_relaxed(port->bridge_addr + ISTATUS_LOCAL); + + /* Error events and doorbell events */ + events = (origin & ERROR_AND_DOORBELL_MASK) >> A_ATR_EVT_POST_ERR_SHIFT; + + /* INTx events */ + if (origin & PM_MSI_INT_INTX_MASK) + events |= BIT(EVENT_PM_MSI_INT_INTX); + + /* MSI event and sys events */ + val = (origin & SYS_AND_MSI_MASK) >> PM_MSI_INT_MSI_SHIFT; + events |= val << EVENT_PM_MSI_INT_MSI; + + return events; +} + +static u32 plda_hwirq_to_mask(int hwirq) +{ + u32 mask; + + if (hwirq < EVENT_PM_MSI_INT_INTX) + mask = BIT(hwirq + A_ATR_EVT_POST_ERR_SHIFT); + else if (hwirq == EVENT_PM_MSI_INT_INTX) + mask = PM_MSI_INT_INTX_MASK; + else + mask = BIT(hwirq + PM_MSI_TO_MASK_OFFSET); + + return mask; +} + +static void plda_ack_event_irq(struct irq_data *data) +{ + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); + + writel_relaxed(plda_hwirq_to_mask(data->hwirq), + port->bridge_addr + ISTATUS_LOCAL); +} + +static void plda_mask_event_irq(struct irq_data *data) +{ + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); + u32 mask, val; + + mask = plda_hwirq_to_mask(data->hwirq); + + raw_spin_lock(&port->lock); + val = readl_relaxed(port->bridge_addr + IMASK_LOCAL); + val &= ~mask; + writel_relaxed(val, port->bridge_addr + IMASK_LOCAL); + raw_spin_unlock(&port->lock); +} + +static void plda_unmask_event_irq(struct irq_data *data) +{ + struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); + u32 mask, val; + + mask = plda_hwirq_to_mask(data->hwirq); + + raw_spin_lock(&port->lock); + val = readl_relaxed(port->bridge_addr + IMASK_LOCAL); + val |= mask; + writel_relaxed(val, port->bridge_addr + IMASK_LOCAL); + raw_spin_unlock(&port->lock); +} + +static struct irq_chip plda_event_irq_chip = { + .name = "PLDA PCIe EVENT", + .irq_ack = plda_ack_event_irq, + .irq_mask = plda_mask_event_irq, + .irq_unmask = plda_unmask_event_irq, +}; + +static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &plda_event_irq_chip, handle_level_irq); + irq_set_chip_data(irq, domain->host_data); + + return 0; +} + +static const struct irq_domain_ops plda_evt_dom_ops = { + .map = plda_pcie_event_map, +}; + +static const struct plda_event_ops plda_event_ops = { + .get_events = plda_get_events, +}; + +static const struct plda_event plda_default_event = { + .domain_ops = &plda_evt_dom_ops, + .event_ops = &plda_event_ops, + .intx_event = EVENT_PM_MSI_INT_INTX, + .msi_event = EVENT_PM_MSI_INT_MSI +}; + static void plda_handle_event(struct irq_desc *desc) { struct plda_pcie_rp *port = irq_desc_get_handler_data(desc); @@ -325,8 +436,7 @@ int plda_init_interrupts(struct platform_device *pdev, const struct plda_event *event) { struct device *dev = &pdev->dev; - int irq; - int i, intx_irq, msi_irq, event_irq; + int i, event_irq; int ret; if (!event->event_ops || !event->event_ops->get_events) { @@ -340,8 +450,8 @@ int plda_init_interrupts(struct platform_device *pdev, return ret; } - irq = platform_get_irq(pdev, 0); - if (irq < 0) + port->irq = platform_get_irq(pdev, 0); + if (port->irq < 0) return -ENODEV; port->event_ops = event->event_ops; @@ -366,26 +476,26 @@ int plda_init_interrupts(struct platform_device *pdev, } } - intx_irq = irq_create_mapping(port->event_domain, - event->intx_event); - if (!intx_irq) { + port->intx_irq = irq_create_mapping(port->event_domain, + event->intx_event); + if (!port->intx_irq) { dev_err(dev, "failed to map INTx interrupt\n"); return -ENXIO; } /* Plug the INTx chained handler */ - irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port); + irq_set_chained_handler_and_data(port->intx_irq, plda_handle_intx, port); - msi_irq = irq_create_mapping(port->event_domain, - event->msi_event); - if (!msi_irq) + port->msi_irq = irq_create_mapping(port->event_domain, + event->msi_event); + if (!port->msi_irq) return -ENXIO; /* Plug the MSI chained handler */ - irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port); + irq_set_chained_handler_and_data(port->msi_irq, plda_handle_msi, port); /* Plug the main event chained handler */ - irq_set_chained_handler_and_data(irq, plda_handle_event, port); + irq_set_chained_handler_and_data(port->irq, plda_handle_event, port); return 0; } @@ -451,3 +561,97 @@ int plda_pcie_setup_iomems(struct pci_host_bridge *bridge, return 0; } EXPORT_SYMBOL_GPL(plda_pcie_setup_iomems); + +static void plda_pcie_irq_domain_deinit(struct plda_pcie_rp *pcie) +{ + irq_set_chained_handler_and_data(pcie->irq, NULL, NULL); + irq_set_chained_handler_and_data(pcie->msi_irq, NULL, NULL); + irq_set_chained_handler_and_data(pcie->intx_irq, NULL, NULL); + + irq_domain_remove(pcie->msi.msi_domain); + irq_domain_remove(pcie->msi.dev_domain); + + irq_domain_remove(pcie->intx_domain); + irq_domain_remove(pcie->event_domain); +} + +int plda_pcie_host_init(struct plda_pcie_rp *port, struct pci_ops *ops) +{ + struct device *dev = port->dev; + struct pci_host_bridge *bridge; + struct platform_device *pdev = to_platform_device(dev); + struct resource *cfg_res; + int ret; + + pdev = to_platform_device(dev); + + port->bridge_addr = + devm_platform_ioremap_resource_byname(pdev, "apb"); + + if (IS_ERR(port->bridge_addr)) + return dev_err_probe(dev, PTR_ERR(port->bridge_addr), + "failed to map reg memory\n"); + + cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); + if (!cfg_res) + return dev_err_probe(dev, -ENODEV, + "failed to get config memory\n"); + + port->config_base = devm_ioremap_resource(dev, cfg_res); + if (IS_ERR(port->config_base)) + return dev_err_probe(dev, PTR_ERR(port->config_base), + "failed to map config memory\n"); + + bridge = devm_pci_alloc_host_bridge(dev, 0); + if (!bridge) + return dev_err_probe(dev, -ENOMEM, + "failed to alloc bridge\n"); + + if (port->host_ops && port->host_ops->host_init) { + ret = port->host_ops->host_init(port); + if (ret) + return ret; + } + + port->bridge = bridge; + plda_pcie_setup_window(port->bridge_addr, 0, cfg_res->start, 0, + resource_size(cfg_res)); + plda_pcie_setup_iomems(bridge, port); + plda_set_default_msi(&port->msi); + ret = plda_init_interrupts(pdev, port, &plda_default_event); + if (ret) + goto err_host; + + /* Set default bus ops */ + bridge->ops = ops; + bridge->sysdata = port; + + ret = pci_host_probe(bridge); + if (ret < 0) { + dev_err_probe(dev, ret, "failed to probe pci host\n"); + goto err_probe; + } + + return ret; + +err_probe: + plda_pcie_irq_domain_deinit(port); +err_host: + if (port->host_ops && port->host_ops->host_deinit) + port->host_ops->host_deinit(port); + + return ret; +} +EXPORT_SYMBOL_GPL(plda_pcie_host_init); + +void plda_pcie_host_deinit(struct plda_pcie_rp *port) +{ + pci_stop_root_bus(port->bridge->bus); + pci_remove_root_bus(port->bridge->bus); + + plda_pcie_irq_domain_deinit(port); + + if (port->host_ops && port->host_ops->host_deinit) + port->host_ops->host_deinit(port); +} +EXPORT_SYMBOL_GPL(plda_pcie_host_deinit); diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h index ce7787aef4b7..6b29bf1f5293 100644 --- a/drivers/pci/controller/plda/pcie-plda.h +++ b/drivers/pci/controller/plda/pcie-plda.h @@ -40,6 +40,7 @@ #define P_ATR_EVT_DISCARD_ERR_SHIFT 22 #define P_ATR_EVT_DOORBELL_MASK 0x00000000u #define P_ATR_EVT_DOORBELL_SHIFT 23 +#define ERROR_AND_DOORBELL_MASK GENMASK(23, 16) #define PM_MSI_INT_INTA_MASK 0x01000000u #define PM_MSI_INT_INTA_SHIFT 24 #define PM_MSI_INT_INTB_MASK 0x02000000u @@ -58,6 +59,7 @@ #define PM_MSI_INT_EVENTS_SHIFT 30 #define PM_MSI_INT_SYS_ERR_MASK 0x80000000u #define PM_MSI_INT_SYS_ERR_SHIFT 31 +#define SYS_AND_MSI_MASK GENMASK(31, 28) #define NUM_LOCAL_EVENTS 15 #define ISTATUS_LOCAL 0x184 #define IMASK_HOST 0x188 @@ -102,12 +104,43 @@ #define EVENT_PM_MSI_INT_SYS_ERR 12 #define NUM_PLDA_EVENTS 13 +/* + * PLDA local interrupt register + * + * 31 27 23 15 7 0 + * +--+--+--+-+------+-+-+-+-+-+-+-+-+-----------+-----------+ + * |12|11|10|9| intx |7|6|5|4|3|2|1|0| DMA error | DMA end | + * +--+--+--+-+------+-+-+-+-+-+-+-+-+-----------+-----------+ + * 0: AXI post error + * 1: AXI fetch error + * 2: AXI discard error + * 3: AXI doorbell + * 4: PCIe post error + * 5: PCIe fetch error + * 6: PCIe discard error + * 7: PCIe doorbell + * 8: 4 INTx interruts + * 9: MSI interrupt + * 10: AER event + * 11: PM/LTR/Hotplug + * 12: System error + * DMA error : reserved for vendor implement + * DMA end : reserved for vendor implement + */ + +#define PM_MSI_TO_MASK_OFFSET 19 + struct plda_pcie_rp; struct plda_event_ops { u32 (*get_events)(struct plda_pcie_rp *pcie); }; +struct plda_pcie_host_ops { + int (*host_init)(struct plda_pcie_rp *pcie); + void (*host_deinit)(struct plda_pcie_rp *pcie); +}; + struct plda_msi { struct mutex lock; /* Protect used bitmap */ struct irq_domain *msi_domain; @@ -119,12 +152,18 @@ struct plda_msi { struct plda_pcie_rp { struct device *dev; + struct pci_host_bridge *bridge; struct irq_domain *intx_domain; struct irq_domain *event_domain; raw_spinlock_t lock; struct plda_msi msi; const struct plda_event_ops *event_ops; + const struct plda_pcie_host_ops *host_ops; void __iomem *bridge_addr; + void __iomem *config_base; + int irq; + int msi_irq; + int intx_irq; int num_events; }; @@ -137,6 +176,8 @@ struct plda_event { int msi_event; }; +void __iomem *plda_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, + int where); int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port, const struct plda_event *event); @@ -145,4 +186,12 @@ void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index, size_t size); int plda_pcie_setup_iomems(struct pci_host_bridge *bridge, struct plda_pcie_rp *port); +int plda_pcie_host_init(struct plda_pcie_rp *pcie, struct pci_ops *ops); +void plda_pcie_host_deinit(struct plda_pcie_rp *pcie); + +static inline void plda_set_default_msi(struct plda_msi *msi) +{ + msi->vector_phy = IMSI_ADDR; + msi->num_vectors = PLDA_MAX_NUM_MSI_IRQS; +} #endif