From d9bd520fdf24c7ee6d738f98dc82c25d229cae55 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Sun, 21 Mar 2021 19:25:44 -0700 Subject: [PATCH] pci: msm: Add support for BDF filtering Do not allow configuration access request to certain BDFs. This is required for PCIe switches, unable to respond to configuration access request to certain supported BDFs. Without filtering, such BDFs are causing system bus hang or enumeration failure of downstream ports of switch. Change-Id: I4c4fa5cc4921dfe0217e05aaad4600abebcacd2b Signed-off-by: Hemant Kumar --- drivers/pci/controller/pci-msm.c | 37 ++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 7be12a223301..8e149cf06896 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -851,6 +851,9 @@ struct msm_pcie_dev_t { bool drv_supported; void (*rumi_init)(struct msm_pcie_dev_t *pcie_dev); + + u32 *filtered_bdfs; + u32 bdf_count; }; struct msm_root_dev_t { @@ -3004,7 +3007,7 @@ static int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper, struct msm_pcie_dev_t *dev; void __iomem *config_base; bool rc = false; - u32 rc_idx; + u32 rc_idx, *filtered_bdf; int rv = 0; u32 bdf = BDF_OFFSET(bus->number, devfn); int i; @@ -3060,6 +3063,19 @@ static int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper, goto unlock; } + /* 32-bit BDF filtering */ + if (dev->bdf_count) { + i = dev->bdf_count; + filtered_bdf = dev->filtered_bdfs; + while (i--) { + if (*filtered_bdf == bdf) { + *val = ~0; + goto unlock; + } + filtered_bdf++; + } + } + if (!rc && !dev->enumerated) msm_pcie_cfg_bdf(dev, bus->number, devfn); @@ -5932,7 +5948,7 @@ static int msm_pcie_probe(struct platform_device *pdev) { int ret = 0; int rc_idx = -1; - int i, j; + int i, j, size; struct msm_pcie_dev_t *pcie_dev; struct device_node *of_node; @@ -6244,6 +6260,23 @@ static int msm_pcie_probe(struct platform_device *pdev) pcie_dev->drv_ready = true; + of_get_property(pdev->dev.of_node, "qcom,filtered-bdfs", &size); + if (size) { + pcie_dev->filtered_bdfs = devm_kzalloc(&pdev->dev, size, + GFP_KERNEL); + if (!pcie_dev->filtered_bdfs) + return -ENOMEM; + + pcie_dev->bdf_count = size / sizeof(*pcie_dev->filtered_bdfs); + + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,filtered-bdfs", + pcie_dev->filtered_bdfs, + pcie_dev->bdf_count); + if (ret) + pcie_dev->bdf_count = 0; + } + if (pcie_dev->boot_option & MSM_PCIE_NO_PROBE_ENUMERATION) { PCIE_DBG(pcie_dev, "PCIe: RC%d will be enumerated by client or endpoint.\n",