aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw/ipath/ipath_intr.c
diff options
context:
space:
mode:
authorJohn Gregor <john.gregor@qlogic.com>2008-04-17 00:09:24 -0400
committerRoland Dreier <rolandd@cisco.com>2008-04-17 00:09:24 -0400
commit58411d1c012dca53ec9107bd98acb63f648e2435 (patch)
treed48edc5c3c64d91311bb4134b83bfe7b62b10ec4 /drivers/infiniband/hw/ipath/ipath_intr.c
parent6be979d71a5e8720c8560cc58713407947e5f691 (diff)
IB/ipath: Head of Line blocking vs forward progress of user apps
There's a conflict between our need to quiesce PSM-based applications to avoid HoL blocking when the IB link goes down and the apps' desire to remain running so that their quiescence timout mechanism can keep running. The compromise is to STOP the processes for a fixed period of time and then alternate between CONT and STOP until the link is again active. If there are poor interactions with subnet manager configuration at a given site, the interval can be adjusted via a module paramter. Signed-off-by: John Gregor <john.gregor@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_intr.c')
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c287
1 files changed, 136 insertions, 151 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index ed2a227ceced..dde5dfc9fcf5 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -32,6 +32,7 @@
32 */ 32 */
33 33
34#include <linux/pci.h> 34#include <linux/pci.h>
35#include <linux/delay.h>
35 36
36#include "ipath_kernel.h" 37#include "ipath_kernel.h"
37#include "ipath_verbs.h" 38#include "ipath_verbs.h"
@@ -256,24 +257,20 @@ void ipath_format_hwerrors(u64 hwerrs,
256} 257}
257 258
258/* return the strings for the most common link states */ 259/* return the strings for the most common link states */
259static char *ib_linkstate(u32 linkstate) 260static char *ib_linkstate(struct ipath_devdata *dd, u64 ibcs)
260{ 261{
261 char *ret; 262 char *ret;
263 u32 state;
262 264
263 switch (linkstate) { 265 state = ipath_ib_state(dd, ibcs);
264 case IPATH_IBSTATE_INIT: 266 if (state == dd->ib_init)
265 ret = "Init"; 267 ret = "Init";
266 break; 268 else if (state == dd->ib_arm)
267 case IPATH_IBSTATE_ARM:
268 ret = "Arm"; 269 ret = "Arm";
269 break; 270 else if (state == dd->ib_active)
270 case IPATH_IBSTATE_ACTIVE:
271 ret = "Active"; 271 ret = "Active";
272 break; 272 else
273 default:
274 ret = "Down"; 273 ret = "Down";
275 }
276
277 return ret; 274 return ret;
278} 275}
279 276
@@ -288,103 +285,137 @@ void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev)
288} 285}
289 286
290static void handle_e_ibstatuschanged(struct ipath_devdata *dd, 287static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
291 ipath_err_t errs, int noprint) 288 ipath_err_t errs)
292{ 289{
293 u64 val; 290 u32 ltstate, lstate, ibstate, lastlstate;
294 u32 ltstate, lstate; 291 u32 init = dd->ib_init;
292 u32 arm = dd->ib_arm;
293 u32 active = dd->ib_active;
294 const u64 ibcs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
295
296 lstate = ipath_ib_linkstate(dd, ibcs); /* linkstate */
297 ibstate = ipath_ib_state(dd, ibcs);
298 /* linkstate at last interrupt */
299 lastlstate = ipath_ib_linkstate(dd, dd->ipath_lastibcstat);
300 ltstate = ipath_ib_linktrstate(dd, ibcs); /* linktrainingtate */
295 301
296 /* 302 /*
297 * even if diags are enabled, we want to notice LINKINIT, etc. 303 * if linkstate transitions into INIT from any of the various down
298 * We just don't want to change the LED state, or 304 * states, or if it transitions from any of the up (INIT or better)
299 * dd->ipath_kregs->kr_ibcctrl 305 * states into any of the down states (except link recovery), then
306 * call the chip-specific code to take appropriate actions.
300 */ 307 */
301 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus); 308 if (lstate >= INFINIPATH_IBCS_L_STATE_INIT &&
302 lstate = val & IPATH_IBSTATE_MASK; 309 lastlstate == INFINIPATH_IBCS_L_STATE_DOWN) {
310 /* transitioned to UP */
311 if (dd->ipath_f_ib_updown(dd, 1, ibcs)) {
312 ipath_cdbg(LINKVERB, "LinkUp handled, skipped\n");
313 goto skip_ibchange; /* chip-code handled */
314 }
315 } else if ((lastlstate >= INFINIPATH_IBCS_L_STATE_INIT ||
316 (dd->ipath_flags & IPATH_IB_FORCE_NOTIFY)) &&
317 ltstate <= INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE &&
318 ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) {
319 int handled;
320 handled = dd->ipath_f_ib_updown(dd, 0, ibcs);
321 dd->ipath_flags &= ~IPATH_IB_FORCE_NOTIFY;
322 if (handled) {
323 ipath_cdbg(LINKVERB, "LinkDown handled, skipped\n");
324 goto skip_ibchange; /* chip-code handled */
325 }
326 }
303 327
304 /* 328 /*
305 * this is confusing enough when it happens that I want to always put it 329 * Significant enough to always print and get into logs, if it was
306 * on the console and in the logs. If it was a requested state change, 330 * unexpected. If it was a requested state change, we'll have
307 * we'll have already cleared the flags, so we won't print this warning 331 * already cleared the flags, so we won't print this warning
308 */ 332 */
309 if ((lstate != IPATH_IBSTATE_ARM && lstate != IPATH_IBSTATE_ACTIVE) 333 if ((ibstate != arm && ibstate != active) &&
310 && (dd->ipath_flags & (IPATH_LINKARMED | IPATH_LINKACTIVE))) { 334 (dd->ipath_flags & (IPATH_LINKARMED | IPATH_LINKACTIVE))) {
311 dev_info(&dd->pcidev->dev, "Link state changed from %s to %s\n", 335 dev_info(&dd->pcidev->dev, "Link state changed from %s "
312 (dd->ipath_flags & IPATH_LINKARMED) ? "ARM" : "ACTIVE", 336 "to %s\n", (dd->ipath_flags & IPATH_LINKARMED) ?
313 ib_linkstate(lstate)); 337 "ARM" : "ACTIVE", ib_linkstate(dd, ibcs));
314 /*
315 * Flush all queued sends when link went to DOWN or INIT,
316 * to be sure that they don't block SMA and other MAD packets
317 */
318 ipath_cancel_sends(dd, 1);
319 }
320 else if (lstate == IPATH_IBSTATE_INIT || lstate == IPATH_IBSTATE_ARM ||
321 lstate == IPATH_IBSTATE_ACTIVE) {
322 /*
323 * only print at SMA if there is a change, debug if not
324 * (sometimes we want to know that, usually not).
325 */
326 if (lstate == ((unsigned) dd->ipath_lastibcstat
327 & IPATH_IBSTATE_MASK)) {
328 ipath_dbg("Status change intr but no change (%s)\n",
329 ib_linkstate(lstate));
330 }
331 else
332 ipath_cdbg(VERBOSE, "Unit %u link state %s, last "
333 "was %s\n", dd->ipath_unit,
334 ib_linkstate(lstate),
335 ib_linkstate((unsigned)
336 dd->ipath_lastibcstat
337 & IPATH_IBSTATE_MASK));
338 }
339 else {
340 lstate = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK;
341 if (lstate == IPATH_IBSTATE_INIT ||
342 lstate == IPATH_IBSTATE_ARM ||
343 lstate == IPATH_IBSTATE_ACTIVE)
344 ipath_cdbg(VERBOSE, "Unit %u link state down"
345 " (state 0x%x), from %s\n",
346 dd->ipath_unit,
347 (u32)val & IPATH_IBSTATE_MASK,
348 ib_linkstate(lstate));
349 else
350 ipath_cdbg(VERBOSE, "Unit %u link state changed "
351 "to 0x%x from down (%x)\n",
352 dd->ipath_unit, (u32) val, lstate);
353 } 338 }
354 ltstate = (val >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
355 INFINIPATH_IBCS_LINKTRAININGSTATE_MASK;
356 lstate = (val >> INFINIPATH_IBCS_LINKSTATE_SHIFT) &
357 INFINIPATH_IBCS_LINKSTATE_MASK;
358 339
359 if (ltstate == INFINIPATH_IBCS_LT_STATE_POLLACTIVE || 340 if (ltstate == INFINIPATH_IBCS_LT_STATE_POLLACTIVE ||
360 ltstate == INFINIPATH_IBCS_LT_STATE_POLLQUIET) { 341 ltstate == INFINIPATH_IBCS_LT_STATE_POLLQUIET) {
361 u32 last_ltstate; 342 u32 lastlts;
362 343 lastlts = ipath_ib_linktrstate(dd, dd->ipath_lastibcstat);
363 /* 344 /*
364 * Ignore cycling back and forth from Polling.Active 345 * Ignore cycling back and forth from Polling.Active to
365 * to Polling.Quiet while waiting for the other end of 346 * Polling.Quiet while waiting for the other end of the link
366 * the link to come up. We will cycle back and forth 347 * to come up, except to try and decide if we are connected
367 * between them if no cable is plugged in, 348 * to a live IB device or not. We will cycle back and
368 * the other device is powered off or disabled, etc. 349 * forth between them if no cable is plugged in, the other
350 * device is powered off or disabled, etc.
369 */ 351 */
370 last_ltstate = (dd->ipath_lastibcstat >> 352 if (lastlts == INFINIPATH_IBCS_LT_STATE_POLLACTIVE ||
371 INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) 353 lastlts == INFINIPATH_IBCS_LT_STATE_POLLQUIET) {
372 & INFINIPATH_IBCS_LINKTRAININGSTATE_MASK; 354 if (++dd->ipath_ibpollcnt == 40) {
373 if (last_ltstate == INFINIPATH_IBCS_LT_STATE_POLLACTIVE
374 || last_ltstate ==
375 INFINIPATH_IBCS_LT_STATE_POLLQUIET) {
376 if (dd->ipath_ibpollcnt > 40) {
377 dd->ipath_flags |= IPATH_NOCABLE; 355 dd->ipath_flags |= IPATH_NOCABLE;
378 *dd->ipath_statusp |= 356 *dd->ipath_statusp |=
379 IPATH_STATUS_IB_NOCABLE; 357 IPATH_STATUS_IB_NOCABLE;
380 } else 358 ipath_cdbg(LINKVERB, "Set NOCABLE\n");
381 dd->ipath_ibpollcnt++; 359 }
360 ipath_cdbg(LINKVERB, "POLL change to %s (%x)\n",
361 ipath_ibcstatus_str[ltstate], ibstate);
382 goto skip_ibchange; 362 goto skip_ibchange;
383 } 363 }
384 } 364 }
385 dd->ipath_ibpollcnt = 0; /* some state other than 2 or 3 */ 365
366 dd->ipath_ibpollcnt = 0; /* not poll*, now */
386 ipath_stats.sps_iblink++; 367 ipath_stats.sps_iblink++;
387 if (ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) { 368
369 if (ibstate == init || ibstate == arm || ibstate == active) {
370 *dd->ipath_statusp &= ~IPATH_STATUS_IB_NOCABLE;
371 if (ibstate == init || ibstate == arm) {
372 *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
373 if (dd->ipath_flags & IPATH_LINKACTIVE)
374 signal_ib_event(dd, IB_EVENT_PORT_ERR);
375 }
376 if (ibstate == arm) {
377 dd->ipath_flags |= IPATH_LINKARMED;
378 dd->ipath_flags &= ~(IPATH_LINKUNK |
379 IPATH_LINKINIT | IPATH_LINKDOWN |
380 IPATH_LINKACTIVE | IPATH_NOCABLE);
381 ipath_hol_down(dd);
382 } else if (ibstate == init) {
383 /*
384 * set INIT and DOWN. Down is checked by
385 * most of the other code, but INIT is
386 * useful to know in a few places.
387 */
388 dd->ipath_flags |= IPATH_LINKINIT |
389 IPATH_LINKDOWN;
390 dd->ipath_flags &= ~(IPATH_LINKUNK |
391 IPATH_LINKARMED | IPATH_LINKACTIVE |
392 IPATH_NOCABLE);
393 ipath_hol_down(dd);
394 } else { /* active */
395 *dd->ipath_statusp |=
396 IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF;
397 dd->ipath_flags |= IPATH_LINKACTIVE;
398 dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT
399 | IPATH_LINKDOWN | IPATH_LINKARMED |
400 IPATH_NOCABLE);
401 signal_ib_event(dd, IB_EVENT_PORT_ACTIVE);
402 /* LED active not handled in chip _f_updown */
403 dd->ipath_f_setextled(dd, lstate, ltstate);
404 ipath_hol_up(dd);
405 }
406
407 /*
408 * print after we've already done the work, so as not to
409 * delay the state changes and notifications, for debugging
410 */
411 if (lstate == lastlstate)
412 ipath_cdbg(LINKVERB, "Unchanged from last: %s "
413 "(%x)\n", ib_linkstate(dd, ibcs), ibstate);
414 else
415 ipath_cdbg(VERBOSE, "Unit %u: link up to %s %s (%x)\n",
416 dd->ipath_unit, ib_linkstate(dd, ibcs),
417 ipath_ibcstatus_str[ltstate], ibstate);
418 } else { /* down */
388 if (dd->ipath_flags & IPATH_LINKACTIVE) 419 if (dd->ipath_flags & IPATH_LINKACTIVE)
389 signal_ib_event(dd, IB_EVENT_PORT_ERR); 420 signal_ib_event(dd, IB_EVENT_PORT_ERR);
390 dd->ipath_flags |= IPATH_LINKDOWN; 421 dd->ipath_flags |= IPATH_LINKDOWN;
@@ -393,65 +424,22 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
393 IPATH_LINKARMED); 424 IPATH_LINKARMED);
394 *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; 425 *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
395 dd->ipath_lli_counter = 0; 426 dd->ipath_lli_counter = 0;
396 if (!noprint) {
397 if (((dd->ipath_lastibcstat >>
398 INFINIPATH_IBCS_LINKSTATE_SHIFT) &
399 INFINIPATH_IBCS_LINKSTATE_MASK)
400 == INFINIPATH_IBCS_L_STATE_ACTIVE)
401 /* if from up to down be more vocal */
402 ipath_cdbg(VERBOSE,
403 "Unit %u link now down (%s)\n",
404 dd->ipath_unit,
405 ipath_ibcstatus_str[ltstate]);
406 else
407 ipath_cdbg(VERBOSE, "Unit %u link is "
408 "down (%s)\n", dd->ipath_unit,
409 ipath_ibcstatus_str[ltstate]);
410 }
411 427
412 dd->ipath_f_setextled(dd, lstate, ltstate); 428 if (lastlstate != INFINIPATH_IBCS_L_STATE_DOWN)
413 } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_ACTIVE) { 429 ipath_cdbg(VERBOSE, "Unit %u link state down "
414 dd->ipath_flags |= IPATH_LINKACTIVE; 430 "(state 0x%x), from %s\n",
415 dd->ipath_flags &= 431 dd->ipath_unit, lstate,
416 ~(IPATH_LINKUNK | IPATH_LINKINIT | IPATH_LINKDOWN | 432 ib_linkstate(dd, dd->ipath_lastibcstat));
417 IPATH_LINKARMED | IPATH_NOCABLE); 433 else
418 *dd->ipath_statusp &= ~IPATH_STATUS_IB_NOCABLE; 434 ipath_cdbg(LINKVERB, "Unit %u link state changed "
419 *dd->ipath_statusp |= 435 "to %s (0x%x) from down (%x)\n",
420 IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF; 436 dd->ipath_unit,
421 dd->ipath_f_setextled(dd, lstate, ltstate); 437 ipath_ibcstatus_str[ltstate],
422 signal_ib_event(dd, IB_EVENT_PORT_ACTIVE); 438 ibstate, lastlstate);
423 } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) {
424 if (dd->ipath_flags & IPATH_LINKACTIVE)
425 signal_ib_event(dd, IB_EVENT_PORT_ERR);
426 /*
427 * set INIT and DOWN. Down is checked by most of the other
428 * code, but INIT is useful to know in a few places.
429 */
430 dd->ipath_flags |= IPATH_LINKINIT | IPATH_LINKDOWN;
431 dd->ipath_flags &=
432 ~(IPATH_LINKUNK | IPATH_LINKACTIVE | IPATH_LINKARMED
433 | IPATH_NOCABLE);
434 *dd->ipath_statusp &= ~(IPATH_STATUS_IB_NOCABLE
435 | IPATH_STATUS_IB_READY);
436 dd->ipath_f_setextled(dd, lstate, ltstate);
437 } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_ARM) {
438 if (dd->ipath_flags & IPATH_LINKACTIVE)
439 signal_ib_event(dd, IB_EVENT_PORT_ERR);
440 dd->ipath_flags |= IPATH_LINKARMED;
441 dd->ipath_flags &=
442 ~(IPATH_LINKUNK | IPATH_LINKDOWN | IPATH_LINKINIT |
443 IPATH_LINKACTIVE | IPATH_NOCABLE);
444 *dd->ipath_statusp &= ~(IPATH_STATUS_IB_NOCABLE
445 | IPATH_STATUS_IB_READY);
446 dd->ipath_f_setextled(dd, lstate, ltstate);
447 } else {
448 if (!noprint)
449 ipath_dbg("IBstatuschange unit %u: %s (%x)\n",
450 dd->ipath_unit,
451 ipath_ibcstatus_str[ltstate], ltstate);
452 } 439 }
440
453skip_ibchange: 441skip_ibchange:
454 dd->ipath_lastibcstat = val; 442 dd->ipath_lastibcstat = ibcs;
455} 443}
456 444
457static void handle_supp_msgs(struct ipath_devdata *dd, 445static void handle_supp_msgs(struct ipath_devdata *dd,
@@ -743,16 +731,13 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
743 dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT 731 dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT
744 | IPATH_LINKARMED | IPATH_LINKACTIVE); 732 | IPATH_LINKARMED | IPATH_LINKACTIVE);
745 *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; 733 *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
746 if (!noprint) {
747 u64 st = ipath_read_kreg64(
748 dd, dd->ipath_kregs->kr_ibcstatus);
749 734
750 ipath_dbg("Lost link, link now down (%s)\n", 735 ipath_dbg("Lost link, link now down (%s)\n",
751 ipath_ibcstatus_str[st & 0xf]); 736 ipath_ibcstatus_str[ipath_read_kreg64(dd,
752 } 737 dd->ipath_kregs->kr_ibcstatus) & 0xf]);
753 } 738 }
754 if (errs & INFINIPATH_E_IBSTATUSCHANGED) 739 if (errs & INFINIPATH_E_IBSTATUSCHANGED)
755 handle_e_ibstatuschanged(dd, errs, noprint); 740 handle_e_ibstatuschanged(dd, errs);
756 741
757 if (errs & INFINIPATH_E_RESET) { 742 if (errs & INFINIPATH_E_RESET) {
758 if (!noprint) 743 if (!noprint)