summaryrefslogtreecommitdiff
path: root/drivers/pci/controller/pcie-iproc.c
diff options
context:
space:
mode:
authorRay Jui <ray.jui@broadcom.com>2018-06-11 17:21:06 -0700
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2018-07-13 11:56:55 +0100
commitf78e60a29d4ff27531770cf2c6eee89292379209 (patch)
tree10d900903255dc58311052926fe2298624532ac5 /drivers/pci/controller/pcie-iproc.c
parent1e5748c27ad6669ec4a377f44ef40898c28184e5 (diff)
PCI: iproc: Reject unconfigured physical functions from PAXC
PAXC is an emulated PCIe root complex internally in various Broadcom based SoCs. PAXC internally connects to the embedded network processor within these SoCs, with the embedeed network processor exposed as an endpoint device. The number of physical functions from the embedded network processor that can be accessed depends on the firmware configuration. Unfortunately, due to an ASIC bug, unconfigured physical functions cannot be properly hidden from the root complex during enumerattion. As a result, config write access to these unconfigured physical functions during enumeration will cause a bus lock up on the embedded network processor. Fortunately, these unconfigured physical functions contain a very specific, staled PCIe device ID 0x168e. By making use of this device ID, one is able to terminate the enumeration early in the vendor/device ID config read. Signed-off-by: Ray Jui <ray.jui@broadcom.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Reviewed-by: Scott Branden <scott.branden@broadcom.com> Reviewed-by: Oza Pawandeep <poza@codeaurora.org>
Diffstat (limited to 'drivers/pci/controller/pcie-iproc.c')
-rw-r--r--drivers/pci/controller/pcie-iproc.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c
index 0804aa284b87..59be1e02ba65 100644
--- a/drivers/pci/controller/pcie-iproc.c
+++ b/drivers/pci/controller/pcie-iproc.c
@@ -582,6 +582,25 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
if (size <= 2)
*val = (data >> (8 * (where & 3))) & ((1 << (size * 8)) - 1);
+ /*
+ * For PAXC and PAXCv2, the total number of PFs that one can enumerate
+ * depends on the firmware configuration. Unfortunately, due to an ASIC
+ * bug, unconfigured PFs cannot be properly hidden from the root
+ * complex. As a result, write access to these PFs will cause bus lock
+ * up on the embedded processor
+ *
+ * Since all unconfigured PFs are left with an incorrect, staled device
+ * ID of 0x168e (PCI_DEVICE_ID_NX2_57810), we try to catch those access
+ * early here and reject them all
+ */
+#define DEVICE_ID_MASK 0xffff0000
+#define DEVICE_ID_SHIFT 16
+ if (pcie->rej_unconfig_pf &&
+ (where & CFG_ADDR_REG_NUM_MASK) == PCI_VENDOR_ID)
+ if ((*val & DEVICE_ID_MASK) ==
+ (PCI_DEVICE_ID_NX2_57810 << DEVICE_ID_SHIFT))
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+
return PCIBIOS_SUCCESSFUL;
}
@@ -681,7 +700,7 @@ static int iproc_pcie_config_read32(struct pci_bus *bus, unsigned int devfn,
struct iproc_pcie *pcie = iproc_data(bus);
iproc_pcie_apb_err_disable(bus, true);
- if (pcie->type == IPROC_PCIE_PAXB_V2)
+ if (pcie->iproc_cfg_read)
ret = iproc_pcie_config_read(bus, devfn, where, size, val);
else
ret = pci_generic_config_read32(bus, devfn, where, size, val);
@@ -1336,6 +1355,7 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie)
break;
case IPROC_PCIE_PAXB:
regs = iproc_pcie_reg_paxb;
+ pcie->iproc_cfg_read = true;
pcie->has_apb_err_disable = true;
if (pcie->need_ob_cfg) {
pcie->ob_map = paxb_ob_map;
@@ -1358,10 +1378,14 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie)
case IPROC_PCIE_PAXC:
regs = iproc_pcie_reg_paxc;
pcie->ep_is_internal = true;
+ pcie->iproc_cfg_read = true;
+ pcie->rej_unconfig_pf = true;
break;
case IPROC_PCIE_PAXC_V2:
regs = iproc_pcie_reg_paxc_v2;
pcie->ep_is_internal = true;
+ pcie->iproc_cfg_read = true;
+ pcie->rej_unconfig_pf = true;
pcie->need_msi_steer = true;
break;
default: