diff options
author | John Gregor <john.gregor@qlogic.com> | 2008-05-07 14:01:10 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2008-05-07 14:01:10 -0400 |
commit | ab69b3cf1219e0d07bb4ea373f36b1de38af531c (patch) | |
tree | cad988230450defcdc2d598fd70b6f4ed89df044 /drivers/infiniband | |
parent | e2ab41cae418108f376ad1634d7507f56379f7a2 (diff) |
IB/ipath: Fix SDMA error recovery in absence of link status change
What's fixed:
in ipath_cancel_sends()
We need to unconditionally set ABORTING. So, swap the tests
so the set_bit() isn't shadowed by the &&.
If we've disarmed the piobufs, then we need to unconditionally
set DISARMED. So, move it out from the overly protective if
at the bottom.
in sdma_abort_task()
Abort_task was written knowing that the SDMA engine would always
be reset (and restarted) on error. A recent change broke that
fundamental assumption by taking the restart portion and making
it conditional on a link status change. But, SDMA can go boom
without a link status change in some conditions.
Signed-off-by: John Gregor <john.gregor@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_driver.c | 8 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_sdma.c | 31 |
2 files changed, 29 insertions, 10 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 2036d38fac47..ce7b7c34360e 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c | |||
@@ -1898,8 +1898,8 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl) | |||
1898 | 1898 | ||
1899 | spin_lock_irqsave(&dd->ipath_sdma_lock, flags); | 1899 | spin_lock_irqsave(&dd->ipath_sdma_lock, flags); |
1900 | skip_cancel = | 1900 | skip_cancel = |
1901 | !test_bit(IPATH_SDMA_DISABLED, statp) && | 1901 | test_and_set_bit(IPATH_SDMA_ABORTING, statp) |
1902 | test_and_set_bit(IPATH_SDMA_ABORTING, statp); | 1902 | && !test_bit(IPATH_SDMA_DISABLED, statp); |
1903 | spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags); | 1903 | spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags); |
1904 | if (skip_cancel) | 1904 | if (skip_cancel) |
1905 | goto bail; | 1905 | goto bail; |
@@ -1930,6 +1930,9 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl) | |||
1930 | ipath_disarm_piobufs(dd, 0, | 1930 | ipath_disarm_piobufs(dd, 0, |
1931 | dd->ipath_piobcnt2k + dd->ipath_piobcnt4k); | 1931 | dd->ipath_piobcnt2k + dd->ipath_piobcnt4k); |
1932 | 1932 | ||
1933 | if (dd->ipath_flags & IPATH_HAS_SEND_DMA) | ||
1934 | set_bit(IPATH_SDMA_DISARMED, &dd->ipath_sdma_status); | ||
1935 | |||
1933 | if (restore_sendctrl) { | 1936 | if (restore_sendctrl) { |
1934 | /* else done by caller later if needed */ | 1937 | /* else done by caller later if needed */ |
1935 | spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); | 1938 | spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); |
@@ -1949,7 +1952,6 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl) | |||
1949 | /* only wait so long for intr */ | 1952 | /* only wait so long for intr */ |
1950 | dd->ipath_sdma_abort_intr_timeout = jiffies + HZ; | 1953 | dd->ipath_sdma_abort_intr_timeout = jiffies + HZ; |
1951 | dd->ipath_sdma_reset_wait = 200; | 1954 | dd->ipath_sdma_reset_wait = 200; |
1952 | __set_bit(IPATH_SDMA_DISARMED, &dd->ipath_sdma_status); | ||
1953 | if (!test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status)) | 1955 | if (!test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status)) |
1954 | tasklet_hi_schedule(&dd->ipath_sdma_abort_task); | 1956 | tasklet_hi_schedule(&dd->ipath_sdma_abort_task); |
1955 | spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags); | 1957 | spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags); |
diff --git a/drivers/infiniband/hw/ipath/ipath_sdma.c b/drivers/infiniband/hw/ipath/ipath_sdma.c index 0d07682c7310..3697449c1ba4 100644 --- a/drivers/infiniband/hw/ipath/ipath_sdma.c +++ b/drivers/infiniband/hw/ipath/ipath_sdma.c | |||
@@ -308,13 +308,15 @@ static void sdma_abort_task(unsigned long opaque) | |||
308 | spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags); | 308 | spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags); |
309 | 309 | ||
310 | /* | 310 | /* |
311 | * Don't restart sdma here. Wait until link is up to ACTIVE. | 311 | * Don't restart sdma here (with the exception |
312 | * VL15 MADs used to bring the link up use PIO, and multiple | 312 | * below). Wait until link is up to ACTIVE. VL15 MADs |
313 | * link transitions otherwise cause the sdma engine to be | 313 | * used to bring the link up use PIO, and multiple link |
314 | * transitions otherwise cause the sdma engine to be | ||
314 | * stopped and started multiple times. | 315 | * stopped and started multiple times. |
315 | * The disable is done here, including the shadow, so the | 316 | * The disable is done here, including the shadow, |
316 | * state is kept consistent. | 317 | * so the state is kept consistent. |
317 | * See ipath_restart_sdma() for the actual starting of sdma. | 318 | * See ipath_restart_sdma() for the actual starting |
319 | * of sdma. | ||
318 | */ | 320 | */ |
319 | spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); | 321 | spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); |
320 | dd->ipath_sendctrl &= ~INFINIPATH_S_SDMAENABLE; | 322 | dd->ipath_sendctrl &= ~INFINIPATH_S_SDMAENABLE; |
@@ -326,6 +328,13 @@ static void sdma_abort_task(unsigned long opaque) | |||
326 | /* make sure I see next message */ | 328 | /* make sure I see next message */ |
327 | dd->ipath_sdma_abort_jiffies = 0; | 329 | dd->ipath_sdma_abort_jiffies = 0; |
328 | 330 | ||
331 | /* | ||
332 | * Not everything that takes SDMA offline is a link | ||
333 | * status change. If the link was up, restart SDMA. | ||
334 | */ | ||
335 | if (dd->ipath_flags & IPATH_LINKACTIVE) | ||
336 | ipath_restart_sdma(dd); | ||
337 | |||
329 | goto done; | 338 | goto done; |
330 | } | 339 | } |
331 | 340 | ||
@@ -427,7 +436,12 @@ int setup_sdma(struct ipath_devdata *dd) | |||
427 | goto done; | 436 | goto done; |
428 | } | 437 | } |
429 | 438 | ||
430 | dd->ipath_sdma_status = 0; | 439 | /* |
440 | * Set initial status as if we had been up, then gone down. | ||
441 | * This lets initial start on transition to ACTIVE be the | ||
442 | * same as restart after link flap. | ||
443 | */ | ||
444 | dd->ipath_sdma_status = IPATH_SDMA_ABORT_ABORTED; | ||
431 | dd->ipath_sdma_abort_jiffies = 0; | 445 | dd->ipath_sdma_abort_jiffies = 0; |
432 | dd->ipath_sdma_generation = 0; | 446 | dd->ipath_sdma_generation = 0; |
433 | dd->ipath_sdma_descq_tail = 0; | 447 | dd->ipath_sdma_descq_tail = 0; |
@@ -618,6 +632,9 @@ void ipath_restart_sdma(struct ipath_devdata *dd) | |||
618 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); | 632 | ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); |
619 | spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); | 633 | spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); |
620 | 634 | ||
635 | /* notify upper layers */ | ||
636 | ipath_ib_piobufavail(dd->verbs_dev); | ||
637 | |||
621 | bail: | 638 | bail: |
622 | return; | 639 | return; |
623 | } | 640 | } |