From 4ae8c3a83e5e7e106d70c47c458ed873d12c3cd3 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Thu, 22 Apr 2021 16:24:09 -0700 Subject: [PATCH 1/3] pci: msm: Handle AER in threaded irq context AER handling requires finding the source pci device on the bus which causes the AER. Source pci device is found using bus, device and function number. Finding pci device requires sleeping context because bus is walked by holding semaphore. Hence move AER handling to threaded irq context. Change-Id: Ia51b91560326be2a85e17ce98315ea39d25641e2 Signed-off-by: Hemant Kumar --- drivers/pci/controller/pci-msm.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 536a53b39fec..74a2f7fe8880 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -5471,6 +5471,7 @@ static irqreturn_t handle_global_irq(int irq, void *data) struct msm_pcie_dev_t *dev = data; unsigned long irqsave_flags; u32 status = 0; + irqreturn_t ret = IRQ_HANDLED; spin_lock_irqsave(&dev->irq_lock, irqsave_flags); @@ -5478,8 +5479,7 @@ static irqreturn_t handle_global_irq(int irq, void *data) PCIE_DBG2(dev, "PCIe: RC%d is currently suspending.\n", dev->rc_idx); - spin_unlock_irqrestore(&dev->irq_lock, irqsave_flags); - return IRQ_HANDLED; + goto done; } status = readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_STATUS) & @@ -5507,13 +5507,13 @@ static irqreturn_t handle_global_irq(int irq, void *data) PCIE_DBG(dev, "PCIe: RC%d: AER legacy event.\n", dev->rc_idx); - handle_aer_irq(irq, data); + ret = IRQ_WAKE_THREAD; break; case MSM_PCIE_INT_EVT_AER_ERR: PCIE_DBG(dev, "PCIe: RC%d: AER event.\n", dev->rc_idx); - handle_aer_irq(irq, data); + ret = IRQ_WAKE_THREAD; break; default: PCIE_DUMP(dev, @@ -5523,9 +5523,10 @@ static irqreturn_t handle_global_irq(int irq, void *data) } } +done: spin_unlock_irqrestore(&dev->irq_lock, irqsave_flags); - return IRQ_HANDLED; + return ret; } static int32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev) @@ -5544,10 +5545,11 @@ static int32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev) } if (dev->irq[MSM_PCIE_INT_GLOBAL_INT].num) { - rc = devm_request_irq(pdev, + rc = devm_request_threaded_irq(pdev, dev->irq[MSM_PCIE_INT_GLOBAL_INT].num, handle_global_irq, - IRQF_TRIGGER_RISING, + handle_aer_irq, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, dev->irq[MSM_PCIE_INT_GLOBAL_INT].name, dev); if (rc) { From b492f59d0f4d9cae5c8a067a44951ea4208dbd75 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Wed, 10 Feb 2021 15:31:11 -0800 Subject: [PATCH 2/3] pci: msm: Use operation config read/write APIs in AER handler AER handler is directly using raw read and write APIs to access endpoint config space. Instead, use PCI framework provided APIs as well as the register macros to stream line all config space reads and writes to go through PCI read and write operation. Also, use PCI framework APIs to find the pci device using BDF this removes the dependency on local pci device table. Change-Id: I5b0fa2dc6eb383d9db2dc42f026a2b6cb85b3d71 Signed-off-by: Hemant Kumar --- drivers/pci/controller/pci-msm.c | 104 ++++++++++++++++++------------- 1 file changed, 59 insertions(+), 45 deletions(-) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 74a2f7fe8880..9d5859810af5 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -638,7 +638,6 @@ struct msm_pcie_device_info { int domain; void __iomem *conf_base; unsigned long phy_address; - u32 dev_ctrlstts_offset; struct msm_pcie_register_event *event_reg; bool registered; }; @@ -5218,16 +5217,30 @@ out: mutex_unlock(&dev->recovery_lock); } +static struct pci_dev *find_pci_dev_from_bdf(u16 bdf, int domain) +{ + u8 busnr, devfn; + struct pci_bus *bus; + + busnr = bdf >> 8; + devfn = bdf & 0xff; + + bus = pci_find_bus(domain, busnr); + if (!bus) + return NULL; + + return pci_get_slot(bus, devfn); +} + static irqreturn_t handle_aer_irq(int irq, void *data) { struct msm_pcie_dev_t *dev = data; - + struct pci_dev *pcidev; + u16 aer_cap, ep_src_bdf = 0, ep_dev_stts = 0; int corr_val = 0, uncorr_val = 0, rc_err_status = 0; - int ep_corr_val = 0, ep_uncorr_val = 0; - int rc_dev_ctrlstts = 0, ep_dev_ctrlstts = 0; - u32 ep_dev_ctrlstts_offset = 0; - int i, j, ep_src_bdf = 0; - void __iomem *ep_base = NULL; + u32 ep_corr_val = 0, ep_uncorr_val = 0; + int rc_dev_ctrlstts = 0; + int i; PCIE_DBG2(dev, "AER Interrupt handler fired for RC%d irq %d\nrc_corr_counter: %lu\nrc_non_fatal_counter: %lu\nrc_fatal_counter: %lu\nep_corr_counter: %lu\nep_non_fatal_counter: %lu\nep_fatal_counter: %lu\n", @@ -5269,43 +5282,42 @@ static irqreturn_t handle_aer_irq(int irq, void *data) for (i = 0; i < 2; i++) { if (i) - ep_src_bdf = readl_relaxed(dev->dm_core + - PCIE20_AER_ERR_SRC_ID_REG) & ~0xffff; - else ep_src_bdf = (readl_relaxed(dev->dm_core + - PCIE20_AER_ERR_SRC_ID_REG) & 0xffff) << 16; + PCIE20_AER_ERR_SRC_ID_REG) & ~0xffff) >> 16; + else + ep_src_bdf = readl_relaxed(dev->dm_core + + PCIE20_AER_ERR_SRC_ID_REG) & 0xffff; if (!ep_src_bdf) continue; - for (j = 0; j < MAX_DEVICE_NUM; j++) { - if (ep_src_bdf == dev->pcidev_table[j].bdf) { - PCIE_DBG2(dev, - "PCIe: %s Error from Endpoint: %02x:%02x.%01x\n", - i ? "Uncorrectable" : "Correctable", - dev->pcidev_table[j].bdf >> 24, - dev->pcidev_table[j].bdf >> 19 & 0x1f, - dev->pcidev_table[j].bdf >> 16 & 0x07); - ep_base = dev->pcidev_table[j].conf_base; - ep_dev_ctrlstts_offset = - dev->pcidev_table[j].dev_ctrlstts_offset; - break; - } - } - - if (!ep_base) { + pcidev = find_pci_dev_from_bdf(ep_src_bdf, + pci_domain_nr(dev->dev->bus)); + if (!pcidev) { PCIE_ERR(dev, "PCIe: RC%d no endpoint found for reported error\n", dev->rc_idx); goto out; } - ep_uncorr_val = readl_relaxed(ep_base + - PCIE20_AER_UNCORR_ERR_STATUS_REG); - ep_corr_val = readl_relaxed(ep_base + - PCIE20_AER_CORR_ERR_STATUS_REG); - ep_dev_ctrlstts = readl_relaxed(ep_base + - ep_dev_ctrlstts_offset); + PCIE_DBG2(dev, + "PCIe: %s Error from Endpoint: %02x:%02x.%01x\n", + i ? "Uncorrectable" : "Correctable", + ep_src_bdf >> 24, ep_src_bdf >> 19 & 0x1f, + ep_src_bdf >> 16 & 0x07); + + aer_cap = pci_find_ext_capability(pcidev, PCI_EXT_CAP_ID_ERR); + if (!aer_cap) { + PCIE_ERR(dev, "PCIe: BDF 0x%04x does not support AER\n", + PCI_DEVID(pcidev->bus->number, pcidev->devfn)); + goto out; + } + + pci_read_config_dword(pcidev, aer_cap + PCI_ERR_UNCOR_STATUS, + &ep_uncorr_val); + pci_read_config_dword(pcidev, aer_cap + PCI_ERR_COR_STATUS, + &ep_corr_val); + pcie_capability_read_word(pcidev, PCI_EXP_DEVSTA, &ep_dev_stts); if (ep_uncorr_val) PCIE_DBG(dev, @@ -5316,22 +5328,25 @@ static irqreturn_t handle_aer_irq(int irq, void *data) "EP's PCIE20_AER_CORR_ERR_STATUS_REG:0x%x\n", ep_corr_val); - if ((ep_dev_ctrlstts >> 18) & 0x1) + if (ep_dev_stts & PCI_EXP_DEVSTA_FED) dev->ep_fatal_counter++; - if ((ep_dev_ctrlstts >> 17) & 0x1) + if (ep_dev_stts & PCI_EXP_DEVSTA_NFED) dev->ep_non_fatal_counter++; - if ((ep_dev_ctrlstts >> 16) & 0x1) + if (ep_dev_stts & PCI_EXP_DEVSTA_CED) dev->ep_corr_counter++; - msm_pcie_write_mask(ep_base + ep_dev_ctrlstts_offset, 0, - BIT(18)|BIT(17)|BIT(16)); + pcie_capability_clear_and_set_word(pcidev, PCI_EXP_DEVSTA, 0, + PCI_EXP_DEVSTA_CED | + PCI_EXP_DEVSTA_NFED | + PCI_EXP_DEVSTA_FED); - msm_pcie_write_reg_field(ep_base, - PCIE20_AER_UNCORR_ERR_STATUS_REG, - 0x3fff031, 0x3fff031); - msm_pcie_write_reg_field(ep_base, - PCIE20_AER_CORR_ERR_STATUS_REG, - 0xf1c1, 0xf1c1); + pci_write_config_dword(pcidev, aer_cap + PCI_ERR_COR_STATUS, + ep_corr_val); + +#ifdef CONFIG_PCI_QTI + /* Clear status bits for ERR_NONFATAL errors only */ + pci_cleanup_aer_uncorrect_error_status(pcidev); +#endif } out: if (((dev->rc_corr_counter < corr_counter_limit) && @@ -6394,7 +6409,6 @@ static int msm_pcie_probe(struct platform_device *pdev) pcie_dev->pcidev_table[i].domain = rc_idx; pcie_dev->pcidev_table[i].conf_base = NULL; pcie_dev->pcidev_table[i].phy_address = 0; - pcie_dev->pcidev_table[i].dev_ctrlstts_offset = 0; pcie_dev->pcidev_table[i].event_reg = NULL; pcie_dev->pcidev_table[i].registered = true; } From aae80a9b0f54a5d0d18bc72bdaa7cd6fc1187d33 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Thu, 28 Jan 2021 18:47:26 -0800 Subject: [PATCH 3/3] pci: msm: Add dynamic iATU config for ep config space access It possible that EP gets PCI probe and tries to access EP config space before driver could finish setting up PCIe device table. Due to this race before driver could populate the config base address in table, operation config call back from framework tries to de-reference config base address which is NULL. Fix this issue by dynamically configuring iATU with config space address range mapping to the BDF for which config space is requested for. This prevents access to pcie device table which is used for static mapping for multiple device config space to its BDF. Change-Id: Ie6a83355087912369e46f028d8ffe5e4b5a5fba5 Signed-off-by: Hemant Kumar --- drivers/pci/controller/pci-msm.c | 81 +++++--------------------------- 1 file changed, 11 insertions(+), 70 deletions(-) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 9d5859810af5..70dffb8388ef 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -636,8 +636,6 @@ struct msm_pcie_device_info { short short_bdf; u32 sid; int domain; - void __iomem *conf_base; - unsigned long phy_address; struct msm_pcie_register_event *event_reg; bool registered; }; @@ -3030,9 +3028,8 @@ static int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper, void __iomem *config_base; bool rc = false; u32 rc_idx, *filtered_bdf; - int rv = 0; + int i, rv = 0; u32 bdf = BDF_OFFSET(bus->number, devfn); - int i; dev = PCIE_BUS_PRIV_DATA(bus); @@ -3098,28 +3095,14 @@ static int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper, } } - if (!rc && !dev->enumerated) + if (!rc) msm_pcie_cfg_bdf(dev, bus->number, devfn); word_offset = where & ~0x3; byte_offset = where & 0x3; mask = ((u32)~0 >> (8 * (4 - size))) << (8 * byte_offset); - if (rc || !dev->enumerated) { - config_base = rc ? dev->dm_core : dev->conf; - } else { - for (i = 0; i < MAX_DEVICE_NUM; i++) { - if (dev->pcidev_table[i].bdf == bdf) { - config_base = dev->pcidev_table[i].conf_base; - break; - } - } - if (i == MAX_DEVICE_NUM) { - *val = ~0; - rv = PCIBIOS_DEVICE_NOT_FOUND; - goto unlock; - } - } + config_base = rc ? dev->dm_core : dev->conf; rd_val = readl_relaxed(config_base + word_offset); @@ -3664,25 +3647,6 @@ static int pcie_phy_init(struct msm_pcie_dev_t *dev) return 0; } -static void msm_pcie_iatu_config_all_ep(struct msm_pcie_dev_t *dev) -{ - int i; - u8 type; - struct msm_pcie_device_info *dev_table = dev->pcidev_table; - - for (i = 0; i < MAX_DEVICE_NUM; i++) { - if (!dev_table[i].bdf) - break; - - type = dev_table[i].bdf >> 24 == 0x1 ? - PCIE20_CTRL1_TYPE_CFG0 : PCIE20_CTRL1_TYPE_CFG1; - - msm_pcie_iatu_config(dev, i, type, dev_table[i].phy_address, - dev_table[i].phy_address + SZ_4K - 1, - dev_table[i].bdf); - } -} - static void msm_pcie_config_core_preset(struct msm_pcie_dev_t *pcie_dev) { u32 supported_link_speed = @@ -3745,14 +3709,11 @@ static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev) /* * program and enable address translation region 0 (device config * address space); region type config; - * axi config address range to device config address range + * axi config address range to device config address range. Enable + * translation for bus 1 dev 0 fn 0. */ - if (dev->enumerated) { - msm_pcie_iatu_config_all_ep(dev); - } else { - dev->current_bdf = 0; /* to force IATU re-config */ - msm_pcie_cfg_bdf(dev, 1, 0); - } + dev->current_bdf = 0; /* to force IATU re-config */ + msm_pcie_cfg_bdf(dev, 1, 0); /* configure N_FTS */ PCIE_DBG2(dev, "Original PCIE20_ACK_F_ASPM_CTRL_REG:0x%x\n", @@ -4829,14 +4790,10 @@ static void msm_pcie_disable(struct msm_pcie_dev_t *dev) static int msm_pcie_config_device_table(struct pci_dev *pcidev, void *pdev) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *) pdev; - struct resource *axi_conf = pcie_dev->res[MSM_PCIE_RES_CONF].resource; int ret = 0; u32 rc_idx = pcie_dev->rc_idx; u32 i; u32 bdf = 0; - u8 type; - u32 h_type; - u32 bme; PCIE_DBG(pcie_dev, "PCI device found: vendor-id:0x%x device-id:0x%x\n", @@ -4846,8 +4803,6 @@ static int msm_pcie_config_device_table(struct pci_dev *pcidev, void *pdev) return ret; bdf = BDF_OFFSET(pcidev->bus->number, pcidev->devfn); - type = pcidev->bus->number == 1 ? - PCIE20_CTRL1_TYPE_CFG0 : PCIE20_CTRL1_TYPE_CFG1; for (i = 0; i < MAX_DEVICE_NUM; i++) { struct msm_pcie_device_info *dev_table_t = @@ -4858,27 +4813,15 @@ static int msm_pcie_config_device_table(struct pci_dev *pcidev, void *pdev) dev_table_t->dev = pcidev; dev_table_t->domain = rc_idx; - dev_table_t->conf_base = pcie_dev->conf + i * SZ_4K; - dev_table_t->phy_address = axi_conf->start + i * SZ_4K; - msm_pcie_iatu_config(pcie_dev, i, type, - dev_table_t->phy_address, - dev_table_t->phy_address + SZ_4K - 1, bdf); - - h_type = readl_relaxed(dev_table_t->conf_base + - PCIE20_HEADER_TYPE); - - bme = readl_relaxed(dev_table_t->conf_base + - PCIE20_COMMAND_STATUS); - - if (h_type & (1 << 16)) { - pci_write_config_dword(pcidev, PCIE20_COMMAND_STATUS, - bme | 0x06); - } else { + if (pci_pcie_type(pcidev) == PCI_EXP_TYPE_ENDPOINT) { pcie_dev->num_ep++; dev_table_t->registered = false; } + if (pci_pcie_type(pcidev) == PCI_EXP_TYPE_UPSTREAM) + pci_set_master(pcidev); + if (pcie_dev->num_ep > 1) pcie_dev->pending_ep_reg = true; @@ -6407,8 +6350,6 @@ static int msm_pcie_probe(struct platform_device *pdev) pcie_dev->pcidev_table[i].short_bdf = 0; pcie_dev->pcidev_table[i].sid = 0; pcie_dev->pcidev_table[i].domain = rc_idx; - pcie_dev->pcidev_table[i].conf_base = NULL; - pcie_dev->pcidev_table[i].phy_address = 0; pcie_dev->pcidev_table[i].event_reg = NULL; pcie_dev->pcidev_table[i].registered = true; }