aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/devices/hypertransport.c40
1 files changed, 33 insertions, 7 deletions
diff --git a/src/devices/hypertransport.c b/src/devices/hypertransport.c
index c61efa6c7b..6d37ab5764 100644
--- a/src/devices/hypertransport.c
+++ b/src/devices/hypertransport.c
@@ -278,7 +278,20 @@ static void ht_collapse_early_enumeration(struct bus *bus, unsigned offset_uniti
}
/* Has the link failed? */
if (ctrl & (1 << 4)) {
- return;
+ /*
+ * Either the link has failed, or we have
+ * a CRC error.
+ * Sometimes this can happen due to link
+ * retrain, so lets knock it down and see
+ * if its transient
+ */
+ ctrl |= ((1 << 4) | (1 <<8)); // Link fail + Crc
+ pci_write_config16(prev.dev, prev.pos + prev.ctrl_off, ctrl);
+ ctrl = pci_read_config16(prev.dev, prev.pos + prev.ctrl_off);
+ if (ctrl & ((1 << 4) | (1 << 8))) {
+ printk_alert("Detected error on Hypertransport Link\n");
+ return;
+ }
}
} while((ctrl & (1 << 5)) == 0);
@@ -382,12 +395,25 @@ unsigned int hypertransport_scan_chain(struct bus *bus,
/* Wait until the link initialization is complete */
do {
ctrl = pci_read_config16(prev.dev, prev.pos + prev.ctrl_off);
- /* Is this the end of the hypertransport chain?
- * Has the link failed?
- * If so further scanning is pointless.
- */
- if (ctrl & ((1 << 6) | (1 << 4))) {
- goto end_of_chain;
+
+ if (ctrl & (1 << 6))
+ goto end_of_chain; // End of chain
+
+ if (ctrl & ((1 << 4) | (1 << 8))) {
+ /*
+ * Either the link has failed, or we have
+ * a CRC error.
+ * Sometimes this can happen due to link
+ * retrain, so lets knock it down and see
+ * if its transient
+ */
+ ctrl |= ((1 << 4) | (1 <<8)); // Link fail + Crc
+ pci_write_config16(prev.dev, prev.pos + prev.ctrl_off, ctrl);
+ ctrl = pci_read_config16(prev.dev, prev.pos + prev.ctrl_off);
+ if (ctrl & ((1 << 4) | (1 << 8))) {
+ printk_alert("Detected error on Hypertransport Link\n");
+ goto end_of_chain;
+ }
}
} while((ctrl & (1 << 5)) == 0);