IB/ipath: Fix IB compliance problems with link state vs physical state
authorRalph Campbell <ralph.campbell@qlogic.com>
Fri, 14 Dec 2007 09:53:56 +0000 (01:53 -0800)
committerRoland Dreier <rolandd@cisco.com>
Tue, 11 Mar 2008 20:58:22 +0000 (13:58 -0700)
Subnet manager SetPortinfo messages distingush between changing the link
state (DOWN, ARM, ACTIVE) and the link physical state (POLL, SLEEP,
DISABLED).  These are somewhat independent commands and affect when link
width and speed changes take effect.  Without this patch, a link DOWN
physical state NOP command was causing the link width and speed settings
to take effect which should only happen when the link physical state is
goes down (either by a SMP or some link physical error like link errors
exceeding the threshold).

Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/hw/ipath/ipath_common.h
drivers/infiniband/hw/ipath/ipath_driver.c
drivers/infiniband/hw/ipath/ipath_kernel.h
drivers/infiniband/hw/ipath/ipath_mad.c
drivers/infiniband/hw/ipath/ipath_registers.h

index 414621095540e4eb38d18708109bd550a7b7a0c0..591901aab6b75839e9242c0743c8938e14fabd82 100644 (file)
@@ -75,7 +75,7 @@
 #define IPATH_IB_LINKDOWN              0
 #define IPATH_IB_LINKARM               1
 #define IPATH_IB_LINKACTIVE            2
-#define IPATH_IB_LINKINIT              3
+#define IPATH_IB_LINKDOWN_ONLY         3
 #define IPATH_IB_LINKDOWN_SLEEP                4
 #define IPATH_IB_LINKDOWN_DISABLE      5
 #define IPATH_IB_LINK_LOOPBACK 6 /* enable local loopback */
index d5ff6ca2db30aaaba1ecb0265c9527e7c917621f..ca4d0acc6786768177126ca15af89407fbba235a 100644 (file)
@@ -851,8 +851,7 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first,
  * -ETIMEDOUT state can have multiple states set, for any of several
  * transitions.
  */
-static int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state,
-                               int msecs)
+int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, int msecs)
 {
        dd->ipath_state_wanted = state;
        wait_event_interruptible_timeout(ipath_state_wait,
@@ -1656,8 +1655,8 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
 static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which)
 {
        static const char *what[4] = {
-               [0] = "DOWN",
-               [INFINIPATH_IBCC_LINKCMD_INIT] = "INIT",
+               [0] = "NOP",
+               [INFINIPATH_IBCC_LINKCMD_DOWN] = "DOWN",
                [INFINIPATH_IBCC_LINKCMD_ARMED] = "ARMED",
                [INFINIPATH_IBCC_LINKCMD_ACTIVE] = "ACTIVE"
        };
@@ -1672,9 +1671,9 @@ static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which)
                            (dd, dd->ipath_kregs->kr_ibcstatus) >>
                            INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
                           INFINIPATH_IBCS_LINKTRAININGSTATE_MASK]);
-       /* flush all queued sends when going to DOWN or INIT, to be sure that
+       /* flush all queued sends when going to DOWN to be sure that
         * they don't block MAD packets */
-       if (!linkcmd || linkcmd == INFINIPATH_IBCC_LINKCMD_INIT)
+       if (linkcmd == INFINIPATH_IBCC_LINKCMD_DOWN)
                ipath_cancel_sends(dd, 1);
 
        ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
@@ -1687,6 +1686,13 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate)
        int ret;
 
        switch (newstate) {
+       case IPATH_IB_LINKDOWN_ONLY:
+               ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_DOWN <<
+                                   INFINIPATH_IBCC_LINKCMD_SHIFT);
+               /* don't wait */
+               ret = 0;
+               goto bail;
+
        case IPATH_IB_LINKDOWN:
                ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_POLL <<
                                    INFINIPATH_IBCC_LINKINITCMD_SHIFT);
@@ -1709,16 +1715,6 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate)
                ret = 0;
                goto bail;
 
-       case IPATH_IB_LINKINIT:
-               if (dd->ipath_flags & IPATH_LINKINIT) {
-                       ret = 0;
-                       goto bail;
-               }
-               ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_INIT <<
-                                   INFINIPATH_IBCC_LINKCMD_SHIFT);
-               lstate = IPATH_LINKINIT;
-               break;
-
        case IPATH_IB_LINKARM:
                if (dd->ipath_flags & IPATH_LINKARMED) {
                        ret = 0;
index 4cc0f95ea8777ee7aaf040e1089fe48d9d7cba66..ecf3f7ff77177837012af805c673b81b6b3a9bd9 100644 (file)
@@ -767,6 +767,7 @@ void ipath_kreceive(struct ipath_portdata *);
 int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned);
 int ipath_reset_device(int);
 void ipath_get_faststats(unsigned long);
+int ipath_wait_linkstate(struct ipath_devdata *, u32, int);
 int ipath_set_linkstate(struct ipath_devdata *, u8);
 int ipath_set_mtu(struct ipath_devdata *, u16);
 int ipath_set_lid(struct ipath_devdata *, u32, u8);
index d98d5f103700faab9fd94373f18604d61c214115..b34b91d3723a58f4a2e58f0d6233ed3e264f9338 100644 (file)
@@ -555,10 +555,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
                /* FALLTHROUGH */
        case IB_PORT_DOWN:
                if (lstate == 0)
-                       if (get_linkdowndefaultstate(dd))
-                               lstate = IPATH_IB_LINKDOWN_SLEEP;
-                       else
-                               lstate = IPATH_IB_LINKDOWN;
+                       lstate = IPATH_IB_LINKDOWN_ONLY;
                else if (lstate == 1)
                        lstate = IPATH_IB_LINKDOWN_SLEEP;
                else if (lstate == 2)
@@ -568,6 +565,8 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
                else
                        goto err;
                ipath_set_linkstate(dd, lstate);
+               ipath_wait_linkstate(dd, IPATH_LINKINIT | IPATH_LINKARMED |
+                               IPATH_LINKACTIVE, 1000);
                break;
        case IB_PORT_ARMED:
                ipath_set_linkstate(dd, IPATH_IB_LINKARM);
index 6d2a17f9c1da919193e260160033ad57bf3e05f8..92ad73a7fff0f20f353a1f63e2efe0bd265e0ce3 100644 (file)
 #define INFINIPATH_IBCC_LINKINITCMD_SLEEP 3
 #define INFINIPATH_IBCC_LINKINITCMD_SHIFT 16
 #define INFINIPATH_IBCC_LINKCMD_MASK 0x3ULL
-#define INFINIPATH_IBCC_LINKCMD_INIT 1 /* move to 0x11 */
+#define INFINIPATH_IBCC_LINKCMD_DOWN 1 /* move to 0x11 */
 #define INFINIPATH_IBCC_LINKCMD_ARMED 2        /* move to 0x21 */
 #define INFINIPATH_IBCC_LINKCMD_ACTIVE 3       /* move to 0x31 */
 #define INFINIPATH_IBCC_LINKCMD_SHIFT 18