summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@fingolfin.org>2022-10-12 16:47:27 +0000
committerRobert Mustacchi <rm@fingolfin.org>2022-10-19 20:16:19 +0000
commit89cd7a0dac26a375a2d8df0e6a5737eb57c6f224 (patch)
tree6d585d5558e0b7ea10062f61a967ce8630007e52
parentf23ed011dd1990f5b6b2d755feeaa7baf5a22caa (diff)
downloadillumos-gate-89cd7a0dac26a375a2d8df0e6a5737eb57c6f224.tar.gz
15056 Missing pcie cap leads to panic in pcie_fabric_feature_scan()
Reviewed by: Patrick Mooney <pmooney@pfmooney.com> Reviewed by: Dan Cross <cross@oxidecomputer.com> Approved by: Richard Lowe <richlowe@richlowe.net>
-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);