Commit 4330e4da authored by Michael Albaugh's avatar Michael Albaugh Committed by Roland Dreier

IB/ipath: Prevent link-recovery code from negating admin disable

The link can be put in LINKDOWN_DISABLE state either locally or via a
MAD.  However, the link-recovery code will take it out of that state as
a side-effect of attempts to clear SerDes/XGXS issues.

We add a flag to indicate "link is down on purpose, leave it alone."
Signed-off-by: default avatarMichael Albaugh <michael.albaugh@qlogic.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent 8c641d4b
...@@ -90,6 +90,7 @@ ...@@ -90,6 +90,7 @@
#define __IPATH_IPATHERR 0x0 /* Ethernet (IPATH) errors on */ #define __IPATH_IPATHERR 0x0 /* Ethernet (IPATH) errors on */
#define __IPATH_IPATHPD 0x0 /* Ethernet (IPATH) packet dump on */ #define __IPATH_IPATHPD 0x0 /* Ethernet (IPATH) packet dump on */
#define __IPATH_IPATHTABLE 0x0 /* Ethernet (IPATH) packet dump on */ #define __IPATH_IPATHTABLE 0x0 /* Ethernet (IPATH) packet dump on */
#define __IPATH_LINKVERBDBG 0x0 /* very verbose linkchange debug */
#endif /* _IPATH_DEBUGGING */ #endif /* _IPATH_DEBUGGING */
......
...@@ -1664,30 +1664,48 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl) ...@@ -1664,30 +1664,48 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
} }
static void ipath_set_ib_lstate(struct ipath_devdata *dd, int linkcmd,
static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which) int linitcmd)
{ {
u64 mod_wd;
static const char *what[4] = { static const char *what[4] = {
[0] = "NOP", [0] = "NOP",
[INFINIPATH_IBCC_LINKCMD_DOWN] = "DOWN", [INFINIPATH_IBCC_LINKCMD_DOWN] = "DOWN",
[INFINIPATH_IBCC_LINKCMD_ARMED] = "ARMED", [INFINIPATH_IBCC_LINKCMD_ARMED] = "ARMED",
[INFINIPATH_IBCC_LINKCMD_ACTIVE] = "ACTIVE" [INFINIPATH_IBCC_LINKCMD_ACTIVE] = "ACTIVE"
}; };
int linkcmd = (which >> INFINIPATH_IBCC_LINKCMD_SHIFT) &
INFINIPATH_IBCC_LINKCMD_MASK;
ipath_cdbg(VERBOSE, "Trying to move unit %u to %s, current ltstate " if (linitcmd == INFINIPATH_IBCC_LINKINITCMD_DISABLE) {
"is %s\n", dd->ipath_unit, /*
what[linkcmd], * If we are told to disable, note that so link-recovery
ipath_ibcstatus_str[ipath_ib_linktrstate(dd, * code does not attempt to bring us back up.
*/
preempt_disable();
dd->ipath_flags |= IPATH_IB_LINK_DISABLED;
preempt_enable();
} else if (linitcmd) {
/*
* Any other linkinitcmd will lead to LINKDOWN and then
* to INIT (if all is well), so clear flag to let
* link-recovery code attempt to bring us back up.
*/
preempt_disable();
dd->ipath_flags &= ~IPATH_IB_LINK_DISABLED;
preempt_enable();
}
mod_wd = (linkcmd << dd->ibcc_lc_shift) |
(linitcmd << INFINIPATH_IBCC_LINKINITCMD_SHIFT);
ipath_cdbg(VERBOSE,
"Moving unit %u to %s (initcmd=0x%x), current ltstate is %s\n",
dd->ipath_unit, what[linkcmd], linitcmd,
ipath_ibcstatus_str[ipath_ib_linktrstate(dd,
ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus))]); ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus))]);
/* flush all queued sends when going to DOWN to be sure that
* they don't block MAD packets */
if (linkcmd == INFINIPATH_IBCC_LINKCMD_DOWN)
ipath_cancel_sends(dd, 1);
ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
dd->ipath_ibcctrl | which); dd->ipath_ibcctrl | mod_wd);
/* read from chip so write is flushed */
(void) ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
} }
int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate) int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate)
...@@ -1697,30 +1715,28 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate) ...@@ -1697,30 +1715,28 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate)
switch (newstate) { switch (newstate) {
case IPATH_IB_LINKDOWN_ONLY: case IPATH_IB_LINKDOWN_ONLY:
ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_DOWN << ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_DOWN, 0);
INFINIPATH_IBCC_LINKCMD_SHIFT);
/* don't wait */ /* don't wait */
ret = 0; ret = 0;
goto bail; goto bail;
case IPATH_IB_LINKDOWN: case IPATH_IB_LINKDOWN:
ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_POLL << ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_DOWN,
INFINIPATH_IBCC_LINKINITCMD_SHIFT); INFINIPATH_IBCC_LINKINITCMD_POLL);
/* don't wait */ /* don't wait */
ret = 0; ret = 0;
goto bail; goto bail;
case IPATH_IB_LINKDOWN_SLEEP: case IPATH_IB_LINKDOWN_SLEEP:
ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_SLEEP << ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_DOWN,
INFINIPATH_IBCC_LINKINITCMD_SHIFT); INFINIPATH_IBCC_LINKINITCMD_SLEEP);
/* don't wait */ /* don't wait */
ret = 0; ret = 0;
goto bail; goto bail;
case IPATH_IB_LINKDOWN_DISABLE: case IPATH_IB_LINKDOWN_DISABLE:
ipath_set_ib_lstate(dd, ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_DOWN,
INFINIPATH_IBCC_LINKINITCMD_DISABLE << INFINIPATH_IBCC_LINKINITCMD_DISABLE);
INFINIPATH_IBCC_LINKINITCMD_SHIFT);
/* don't wait */ /* don't wait */
ret = 0; ret = 0;
goto bail; goto bail;
...@@ -1735,8 +1751,8 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate) ...@@ -1735,8 +1751,8 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate)
ret = -EINVAL; ret = -EINVAL;
goto bail; goto bail;
} }
ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ARMED << ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ARMED, 0);
INFINIPATH_IBCC_LINKCMD_SHIFT);
/* /*
* Since the port can transition to ACTIVE by receiving * Since the port can transition to ACTIVE by receiving
* a non VL 15 packet, wait for either state. * a non VL 15 packet, wait for either state.
...@@ -1753,8 +1769,7 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate) ...@@ -1753,8 +1769,7 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate)
ret = -EINVAL; ret = -EINVAL;
goto bail; goto bail;
} }
ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ACTIVE << ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ACTIVE, 0);
INFINIPATH_IBCC_LINKCMD_SHIFT);
lstate = IPATH_LINKACTIVE; lstate = IPATH_LINKACTIVE;
break; break;
...@@ -2026,8 +2041,7 @@ void ipath_shutdown_device(struct ipath_devdata *dd) ...@@ -2026,8 +2041,7 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
*/ */
udelay(5); udelay(5);
ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_DISABLE << ipath_set_ib_lstate(dd, 0, INFINIPATH_IBCC_LINKINITCMD_DISABLE);
INFINIPATH_IBCC_LINKINITCMD_SHIFT);
ipath_cancel_sends(dd, 0); ipath_cancel_sends(dd, 0);
signal_ib_event(dd, IB_EVENT_PORT_ERR); signal_ib_event(dd, IB_EVENT_PORT_ERR);
......
...@@ -180,10 +180,13 @@ static int bringup_link(struct ipath_devdata *dd) ...@@ -180,10 +180,13 @@ static int bringup_link(struct ipath_devdata *dd)
/* /*
* Want to start out with both LINKCMD and LINKINITCMD in NOP * Want to start out with both LINKCMD and LINKINITCMD in NOP
* (0 and 0). Don't put linkinitcmd in ipath_ibcctrl, want that * (0 and 0). Don't put linkinitcmd in ipath_ibcctrl, want that
* to stay a NOP * to stay a NOP. Flag that we are disabled, for the (unlikely)
* case that some recovery path is trying to bring the link up
* before we are ready.
*/ */
ibc |= INFINIPATH_IBCC_LINKINITCMD_DISABLE << ibc |= INFINIPATH_IBCC_LINKINITCMD_DISABLE <<
INFINIPATH_IBCC_LINKINITCMD_SHIFT; INFINIPATH_IBCC_LINKINITCMD_SHIFT;
dd->ipath_flags |= IPATH_IB_LINK_DISABLED;
ipath_cdbg(VERBOSE, "Writing 0x%llx to ibcctrl\n", ipath_cdbg(VERBOSE, "Writing 0x%llx to ibcctrl\n",
(unsigned long long) ibc); (unsigned long long) ibc);
ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, ibc); ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, ibc);
......
...@@ -309,6 +309,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, ...@@ -309,6 +309,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
lastlstate == INFINIPATH_IBCS_L_STATE_DOWN) { lastlstate == INFINIPATH_IBCS_L_STATE_DOWN) {
/* transitioned to UP */ /* transitioned to UP */
if (dd->ipath_f_ib_updown(dd, 1, ibcs)) { if (dd->ipath_f_ib_updown(dd, 1, ibcs)) {
/* link came up, so we must no longer be disabled */
dd->ipath_flags &= ~IPATH_IB_LINK_DISABLED;
ipath_cdbg(LINKVERB, "LinkUp handled, skipped\n"); ipath_cdbg(LINKVERB, "LinkUp handled, skipped\n");
goto skip_ibchange; /* chip-code handled */ goto skip_ibchange; /* chip-code handled */
} }
......
...@@ -848,6 +848,8 @@ void ipath_hol_event(unsigned long); ...@@ -848,6 +848,8 @@ void ipath_hol_event(unsigned long);
/* Suppress heartbeat, even if turning off loopback */ /* Suppress heartbeat, even if turning off loopback */
#define IPATH_NO_HRTBT 0x1000000 #define IPATH_NO_HRTBT 0x1000000
#define IPATH_HAS_MULT_IB_SPEED 0x8000000 #define IPATH_HAS_MULT_IB_SPEED 0x8000000
/* Linkdown-disable intentionally, Do not attempt to bring up */
#define IPATH_IB_LINK_DISABLED 0x40000000
#define IPATH_IB_FORCE_NOTIFY 0x80000000 /* force notify on next ib change */ #define IPATH_IB_FORCE_NOTIFY 0x80000000 /* force notify on next ib change */
/* Bits in GPIO for the added interrupts */ /* Bits in GPIO for the added interrupts */
......
...@@ -590,6 +590,10 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, ...@@ -590,6 +590,10 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
else else
goto err; goto err;
ipath_set_linkstate(dd, lstate); ipath_set_linkstate(dd, lstate);
if (lstate == IPATH_IB_LINKDOWN_DISABLE) {
ret = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
goto done;
}
ipath_wait_linkstate(dd, IPATH_LINKINIT | IPATH_LINKARMED | ipath_wait_linkstate(dd, IPATH_LINKINIT | IPATH_LINKARMED |
IPATH_LINKACTIVE, 1000); IPATH_LINKACTIVE, 1000);
break; break;
......
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