summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan McDonald <danmcd@mnx.io>2022-10-20 10:01:43 -0400
committerDan McDonald <danmcd@mnx.io>2022-10-20 10:01:43 -0400
commitea86097554f0871dbabeca5804080e01ae908d6d (patch)
treefb3e096a6a8df42ac29d2392858df4c0f061c3c2
parent00cae703489661f6bf04c41dfbc11cec67ed2d46 (diff)
parent89cd7a0dac26a375a2d8df0e6a5737eb57c6f224 (diff)
downloadillumos-joyent-ea86097554f0871dbabeca5804080e01ae908d6d.tar.gz
[illumos-gate merge]
commit 89cd7a0dac26a375a2d8df0e6a5737eb57c6f224 15056 Missing pcie cap leads to panic in pcie_fabric_feature_scan()
-rw-r--r--usr/src/uts/common/io/pciex/pcie.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/usr/src/uts/common/io/pciex/pcie.c b/usr/src/uts/common/io/pciex/pcie.c
index acf2e3880c..0f461da167 100644
--- a/usr/src/uts/common/io/pciex/pcie.c
+++ b/usr/src/uts/common/io/pciex/pcie.c
@@ -3585,6 +3585,21 @@ pcie_fabric_feature_scan(dev_info_t *dip, void *arg)
fab->pfd_flags |= PCIE_FABRIC_F_COMPLEX;
return (DDI_WALK_TERMINATE);
}
+
+ /*
+ * In a similar case, there is hardware out there which is a PCIe
+ * device, but does not advertise a PCIe capability. An example of this
+ * is the IDT Tsi382A which can hide its PCIe capability. If this is
+ * the case, we immediately terminate scanning and flag this as a
+ * 'complex' case which causes us to use guaranteed safe settings.
+ */
+ if (bus_p->bus_pcie_off == 0) {
+ dev_err(dip, CE_WARN, "encountered PCIe device without PCIe "
+ "capability");
+ fab->pfd_flags |= PCIE_FABRIC_F_COMPLEX;
+ return (DDI_WALK_TERMINATE);
+ }
+
rcdip = pcie_get_rc_dip(dip);
/*
@@ -3686,10 +3701,11 @@ pcie_fabric_feature_set(dev_info_t *dip, void *arg)
/*
* The missing bus_t sent us into the complex case previously. We still
* need to make sure all devices have values we expect here and thus
- * don't terminate like the above.
+ * don't terminate like the above. The same is true for the case where
+ * there is no PCIe capability.
*/
bus_p = PCIE_DIP2BUS(dip);
- if (bus_p == NULL) {
+ if (bus_p == NULL || bus_p->bus_pcie_off == 0) {
return (DDI_WALK_CONTINUE);
}
rcdip = pcie_get_rc_dip(dip);