diff options
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_iba6120.c')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_iba6120.c | 73 |
1 files changed, 51 insertions, 22 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c index 05918e1e7c36..1b9c30857754 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c | |||
@@ -43,6 +43,8 @@ | |||
43 | #include "ipath_kernel.h" | 43 | #include "ipath_kernel.h" |
44 | #include "ipath_registers.h" | 44 | #include "ipath_registers.h" |
45 | 45 | ||
46 | static void ipath_setup_pe_setextled(struct ipath_devdata *, u64, u64); | ||
47 | |||
46 | /* | 48 | /* |
47 | * This file contains all the chip-specific register information and | 49 | * This file contains all the chip-specific register information and |
48 | * access functions for the QLogic InfiniPath PCI-Express chip. | 50 | * access functions for the QLogic InfiniPath PCI-Express chip. |
@@ -207,8 +209,8 @@ static const struct ipath_kregs ipath_pe_kregs = { | |||
207 | .kr_ibpllcfg = IPATH_KREG_OFFSET(IBPLLCfg), | 209 | .kr_ibpllcfg = IPATH_KREG_OFFSET(IBPLLCfg), |
208 | 210 | ||
209 | /* | 211 | /* |
210 | * These should not be used directly via ipath_read_kreg64(), | 212 | * These should not be used directly via ipath_write_kreg64(), |
211 | * use them with ipath_read_kreg64_port() | 213 | * use them with ipath_write_kreg64_port(), |
212 | */ | 214 | */ |
213 | .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0), | 215 | .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0), |
214 | .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0), | 216 | .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0), |
@@ -321,6 +323,12 @@ static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = { | |||
321 | INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"), | 323 | INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"), |
322 | }; | 324 | }; |
323 | 325 | ||
326 | #define TXE_PIO_PARITY ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | \ | ||
327 | INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \ | ||
328 | << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) | ||
329 | |||
330 | static int ipath_pe_txe_recover(struct ipath_devdata *); | ||
331 | |||
324 | /** | 332 | /** |
325 | * ipath_pe_handle_hwerrors - display hardware errors. | 333 | * ipath_pe_handle_hwerrors - display hardware errors. |
326 | * @dd: the infinipath device | 334 | * @dd: the infinipath device |
@@ -394,32 +402,21 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg, | |||
394 | * occur if a processor speculative read is done to the PIO | 402 | * occur if a processor speculative read is done to the PIO |
395 | * buffer while we are sending a packet, for example. | 403 | * buffer while we are sending a packet, for example. |
396 | */ | 404 | */ |
397 | if (hwerrs & ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | | 405 | if ((hwerrs & TXE_PIO_PARITY) && ipath_pe_txe_recover(dd)) |
398 | INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) | 406 | hwerrs &= ~TXE_PIO_PARITY; |
399 | << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) { | ||
400 | ipath_stats.sps_txeparity++; | ||
401 | ipath_dbg("Recovering from TXE parity error (%llu), " | ||
402 | "hwerrstatus=%llx\n", | ||
403 | (unsigned long long) ipath_stats.sps_txeparity, | ||
404 | (unsigned long long) hwerrs); | ||
405 | ipath_disarm_senderrbufs(dd); | ||
406 | hwerrs &= ~((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | | ||
407 | INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) | ||
408 | << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT); | ||
409 | if (!hwerrs) { /* else leave in freeze mode */ | ||
410 | ipath_write_kreg(dd, | ||
411 | dd->ipath_kregs->kr_control, | ||
412 | dd->ipath_control); | ||
413 | return; | ||
414 | } | ||
415 | } | ||
416 | if (hwerrs) { | 407 | if (hwerrs) { |
417 | /* | 408 | /* |
418 | * if any set that we aren't ignoring only make the | 409 | * if any set that we aren't ignoring only make the |
419 | * complaint once, in case it's stuck or recurring, | 410 | * complaint once, in case it's stuck or recurring, |
420 | * and we get here multiple times | 411 | * and we get here multiple times |
412 | * Force link down, so switch knows, and | ||
413 | * LEDs are turned off | ||
421 | */ | 414 | */ |
422 | if (dd->ipath_flags & IPATH_INITTED) { | 415 | if (dd->ipath_flags & IPATH_INITTED) { |
416 | ipath_set_linkstate(dd, IPATH_IB_LINKDOWN); | ||
417 | ipath_setup_pe_setextled(dd, | ||
418 | INFINIPATH_IBCS_L_STATE_DOWN, | ||
419 | INFINIPATH_IBCS_LT_STATE_DISABLED); | ||
423 | ipath_dev_err(dd, "Fatal Hardware Error (freeze " | 420 | ipath_dev_err(dd, "Fatal Hardware Error (freeze " |
424 | "mode), no longer usable, SN %.16s\n", | 421 | "mode), no longer usable, SN %.16s\n", |
425 | dd->ipath_serial); | 422 | dd->ipath_serial); |
@@ -493,7 +490,8 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg, | |||
493 | dd->ipath_hwerrmask); | 490 | dd->ipath_hwerrmask); |
494 | } | 491 | } |
495 | 492 | ||
496 | ipath_dev_err(dd, "%s hardware error\n", msg); | 493 | if (*msg) |
494 | ipath_dev_err(dd, "%s hardware error\n", msg); | ||
497 | if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) { | 495 | if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) { |
498 | /* | 496 | /* |
499 | * for /sys status file ; if no trailing } is copied, we'll | 497 | * for /sys status file ; if no trailing } is copied, we'll |
@@ -581,6 +579,8 @@ static void ipath_pe_init_hwerrors(struct ipath_devdata *dd) | |||
581 | 579 | ||
582 | if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST)) | 580 | if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST)) |
583 | ipath_dev_err(dd, "MemBIST did not complete!\n"); | 581 | ipath_dev_err(dd, "MemBIST did not complete!\n"); |
582 | if (extsval & INFINIPATH_EXTS_MEMBIST_FOUND) | ||
583 | ipath_dbg("MemBIST corrected\n"); | ||
584 | 584 | ||
585 | val = ~0ULL; /* barring bugs, all hwerrors become interrupts, */ | 585 | val = ~0ULL; /* barring bugs, all hwerrors become interrupts, */ |
586 | 586 | ||
@@ -1330,6 +1330,35 @@ static void ipath_pe_free_irq(struct ipath_devdata *dd) | |||
1330 | dd->ipath_irq = 0; | 1330 | dd->ipath_irq = 0; |
1331 | } | 1331 | } |
1332 | 1332 | ||
1333 | /* | ||
1334 | * On platforms using this chip, and not having ordered WC stores, we | ||
1335 | * can get TXE parity errors due to speculative reads to the PIO buffers, | ||
1336 | * and this, due to a chip bug can result in (many) false parity error | ||
1337 | * reports. So it's a debug print on those, and an info print on systems | ||
1338 | * where the speculative reads don't occur. | ||
1339 | * Because we can get lots of false errors, we have no upper limit | ||
1340 | * on recovery attempts on those platforms. | ||
1341 | */ | ||
1342 | static int ipath_pe_txe_recover(struct ipath_devdata *dd) | ||
1343 | { | ||
1344 | if (ipath_unordered_wc()) | ||
1345 | ipath_dbg("Recovering from TXE PIO parity error\n"); | ||
1346 | else { | ||
1347 | int cnt = ++ipath_stats.sps_txeparity; | ||
1348 | if (cnt >= IPATH_MAX_PARITY_ATTEMPTS) { | ||
1349 | if (cnt == IPATH_MAX_PARITY_ATTEMPTS) | ||
1350 | ipath_dev_err(dd, | ||
1351 | "Too many attempts to recover from " | ||
1352 | "TXE parity, giving up\n"); | ||
1353 | return 0; | ||
1354 | } | ||
1355 | dev_info(&dd->pcidev->dev, | ||
1356 | "Recovering from TXE PIO parity error\n"); | ||
1357 | } | ||
1358 | ipath_disarm_senderrbufs(dd, 1); | ||
1359 | return 1; | ||
1360 | } | ||
1361 | |||
1333 | /** | 1362 | /** |
1334 | * ipath_init_iba6120_funcs - set up the chip-specific function pointers | 1363 | * ipath_init_iba6120_funcs - set up the chip-specific function pointers |
1335 | * @dd: the infinipath device | 1364 | * @dd: the infinipath device |