Commit ab69b3cf authored by John Gregor's avatar John Gregor Committed by Roland Dreier

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: default avatarJohn Gregor <john.gregor@qlogic.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent e2ab41ca
...@@ -1898,8 +1898,8 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl) ...@@ -1898,8 +1898,8 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
spin_lock_irqsave(&dd->ipath_sdma_lock, flags); spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
skip_cancel = skip_cancel =
!test_bit(IPATH_SDMA_DISABLED, statp) && test_and_set_bit(IPATH_SDMA_ABORTING, statp)
test_and_set_bit(IPATH_SDMA_ABORTING, statp); && !test_bit(IPATH_SDMA_DISABLED, statp);
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags); spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
if (skip_cancel) if (skip_cancel)
goto bail; goto bail;
...@@ -1930,6 +1930,9 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl) ...@@ -1930,6 +1930,9 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
ipath_disarm_piobufs(dd, 0, ipath_disarm_piobufs(dd, 0,
dd->ipath_piobcnt2k + dd->ipath_piobcnt4k); dd->ipath_piobcnt2k + dd->ipath_piobcnt4k);
if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
set_bit(IPATH_SDMA_DISARMED, &dd->ipath_sdma_status);
if (restore_sendctrl) { if (restore_sendctrl) {
/* else done by caller later if needed */ /* else done by caller later if needed */
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
...@@ -1949,7 +1952,6 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl) ...@@ -1949,7 +1952,6 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
/* only wait so long for intr */ /* only wait so long for intr */
dd->ipath_sdma_abort_intr_timeout = jiffies + HZ; dd->ipath_sdma_abort_intr_timeout = jiffies + HZ;
dd->ipath_sdma_reset_wait = 200; dd->ipath_sdma_reset_wait = 200;
__set_bit(IPATH_SDMA_DISARMED, &dd->ipath_sdma_status);
if (!test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status)) if (!test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
tasklet_hi_schedule(&dd->ipath_sdma_abort_task); tasklet_hi_schedule(&dd->ipath_sdma_abort_task);
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags); spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
......
...@@ -308,13 +308,15 @@ static void sdma_abort_task(unsigned long opaque) ...@@ -308,13 +308,15 @@ static void sdma_abort_task(unsigned long opaque)
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags); spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
/* /*
* Don't restart sdma here. Wait until link is up to ACTIVE. * Don't restart sdma here (with the exception
* VL15 MADs used to bring the link up use PIO, and multiple * below). Wait until link is up to ACTIVE. VL15 MADs
* link transitions otherwise cause the sdma engine to be * used to bring the link up use PIO, and multiple link
* transitions otherwise cause the sdma engine to be
* stopped and started multiple times. * stopped and started multiple times.
* The disable is done here, including the shadow, so the * The disable is done here, including the shadow,
* state is kept consistent. * so the state is kept consistent.
* See ipath_restart_sdma() for the actual starting of sdma. * See ipath_restart_sdma() for the actual starting
* of sdma.
*/ */
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
dd->ipath_sendctrl &= ~INFINIPATH_S_SDMAENABLE; dd->ipath_sendctrl &= ~INFINIPATH_S_SDMAENABLE;
...@@ -326,6 +328,13 @@ static void sdma_abort_task(unsigned long opaque) ...@@ -326,6 +328,13 @@ static void sdma_abort_task(unsigned long opaque)
/* make sure I see next message */ /* make sure I see next message */
dd->ipath_sdma_abort_jiffies = 0; dd->ipath_sdma_abort_jiffies = 0;
/*
* Not everything that takes SDMA offline is a link
* status change. If the link was up, restart SDMA.
*/
if (dd->ipath_flags & IPATH_LINKACTIVE)
ipath_restart_sdma(dd);
goto done; goto done;
} }
...@@ -427,7 +436,12 @@ int setup_sdma(struct ipath_devdata *dd) ...@@ -427,7 +436,12 @@ int setup_sdma(struct ipath_devdata *dd)
goto done; goto done;
} }
dd->ipath_sdma_status = 0; /*
* Set initial status as if we had been up, then gone down.
* This lets initial start on transition to ACTIVE be the
* same as restart after link flap.
*/
dd->ipath_sdma_status = IPATH_SDMA_ABORT_ABORTED;
dd->ipath_sdma_abort_jiffies = 0; dd->ipath_sdma_abort_jiffies = 0;
dd->ipath_sdma_generation = 0; dd->ipath_sdma_generation = 0;
dd->ipath_sdma_descq_tail = 0; dd->ipath_sdma_descq_tail = 0;
...@@ -618,6 +632,9 @@ void ipath_restart_sdma(struct ipath_devdata *dd) ...@@ -618,6 +632,9 @@ void ipath_restart_sdma(struct ipath_devdata *dd)
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
/* notify upper layers */
ipath_ib_piobufavail(dd->verbs_dev);
bail: bail:
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment