diff options
author | Ralph Campbell <ralph.campbell@qlogic.com> | 2007-12-14 04:53:56 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2008-03-11 16:58:22 -0400 |
commit | 140277e9a710202608914b5b731948d2769399bc (patch) | |
tree | d30fa34b17ec1f42508c5d046926ed7a717126c4 | |
parent | baadac8b10c5ac15ce3d26b68fa266c8889b163f (diff) |
IB/ipath: Fix IB compliance problems with link state vs physical state
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>
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_common.h | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_driver.c | 28 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_kernel.h | 1 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_mad.c | 7 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_registers.h | 2 |
5 files changed, 18 insertions, 22 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h index 414621095540..591901aab6b7 100644 --- a/drivers/infiniband/hw/ipath/ipath_common.h +++ b/drivers/infiniband/hw/ipath/ipath_common.h | |||
@@ -75,7 +75,7 @@ | |||
75 | #define IPATH_IB_LINKDOWN 0 | 75 | #define IPATH_IB_LINKDOWN 0 |
76 | #define IPATH_IB_LINKARM 1 | 76 | #define IPATH_IB_LINKARM 1 |
77 | #define IPATH_IB_LINKACTIVE 2 | 77 | #define IPATH_IB_LINKACTIVE 2 |
78 | #define IPATH_IB_LINKINIT 3 | 78 | #define IPATH_IB_LINKDOWN_ONLY 3 |
79 | #define IPATH_IB_LINKDOWN_SLEEP 4 | 79 | #define IPATH_IB_LINKDOWN_SLEEP 4 |
80 | #define IPATH_IB_LINKDOWN_DISABLE 5 | 80 | #define IPATH_IB_LINKDOWN_DISABLE 5 |
81 | #define IPATH_IB_LINK_LOOPBACK 6 /* enable local loopback */ | 81 | #define IPATH_IB_LINK_LOOPBACK 6 /* enable local loopback */ |
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index d5ff6ca2db30..ca4d0acc6786 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c | |||
@@ -851,8 +851,7 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first, | |||
851 | * -ETIMEDOUT state can have multiple states set, for any of several | 851 | * -ETIMEDOUT state can have multiple states set, for any of several |
852 | * transitions. | 852 | * transitions. |
853 | */ | 853 | */ |
854 | static int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, | 854 | int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, int msecs) |
855 | int msecs) | ||
856 | { | 855 | { |
857 | dd->ipath_state_wanted = state; | 856 | dd->ipath_state_wanted = state; |
858 | wait_event_interruptible_timeout(ipath_state_wait, | 857 | wait_event_interruptible_timeout(ipath_state_wait, |
@@ -1656,8 +1655,8 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl) | |||
1656 | static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which) | 1655 | static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which) |
1657 | { | 1656 | { |
1658 | static const char *what[4] = { | 1657 | static const char *what[4] = { |
1659 | [0] = "DOWN", | 1658 | [0] = "NOP", |
1660 | [INFINIPATH_IBCC_LINKCMD_INIT] = "INIT", | 1659 | [INFINIPATH_IBCC_LINKCMD_DOWN] = "DOWN", |
1661 | [INFINIPATH_IBCC_LINKCMD_ARMED] = "ARMED", | 1660 | [INFINIPATH_IBCC_LINKCMD_ARMED] = "ARMED", |
1662 | [INFINIPATH_IBCC_LINKCMD_ACTIVE] = "ACTIVE" | 1661 | [INFINIPATH_IBCC_LINKCMD_ACTIVE] = "ACTIVE" |
1663 | }; | 1662 | }; |
@@ -1672,9 +1671,9 @@ static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which) | |||
1672 | (dd, dd->ipath_kregs->kr_ibcstatus) >> | 1671 | (dd, dd->ipath_kregs->kr_ibcstatus) >> |
1673 | INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) & | 1672 | INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) & |
1674 | INFINIPATH_IBCS_LINKTRAININGSTATE_MASK]); | 1673 | INFINIPATH_IBCS_LINKTRAININGSTATE_MASK]); |
1675 | /* flush all queued sends when going to DOWN or INIT, to be sure that | 1674 | /* flush all queued sends when going to DOWN to be sure that |
1676 | * they don't block MAD packets */ | 1675 | * they don't block MAD packets */ |
1677 | if (!linkcmd || linkcmd == INFINIPATH_IBCC_LINKCMD_INIT) | 1676 | if (linkcmd == INFINIPATH_IBCC_LINKCMD_DOWN) |
1678 | ipath_cancel_sends(dd, 1); | 1677 | ipath_cancel_sends(dd, 1); |
1679 | 1678 | ||
1680 | ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, | 1679 | ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, |
@@ -1687,6 +1686,13 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate) | |||
1687 | int ret; | 1686 | int ret; |
1688 | 1687 | ||
1689 | switch (newstate) { | 1688 | switch (newstate) { |
1689 | case IPATH_IB_LINKDOWN_ONLY: | ||
1690 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_DOWN << | ||
1691 | INFINIPATH_IBCC_LINKCMD_SHIFT); | ||
1692 | /* don't wait */ | ||
1693 | ret = 0; | ||
1694 | goto bail; | ||
1695 | |||
1690 | case IPATH_IB_LINKDOWN: | 1696 | case IPATH_IB_LINKDOWN: |
1691 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_POLL << | 1697 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_POLL << |
1692 | INFINIPATH_IBCC_LINKINITCMD_SHIFT); | 1698 | INFINIPATH_IBCC_LINKINITCMD_SHIFT); |
@@ -1709,16 +1715,6 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate) | |||
1709 | ret = 0; | 1715 | ret = 0; |
1710 | goto bail; | 1716 | goto bail; |
1711 | 1717 | ||
1712 | case IPATH_IB_LINKINIT: | ||
1713 | if (dd->ipath_flags & IPATH_LINKINIT) { | ||
1714 | ret = 0; | ||
1715 | goto bail; | ||
1716 | } | ||
1717 | ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_INIT << | ||
1718 | INFINIPATH_IBCC_LINKCMD_SHIFT); | ||
1719 | lstate = IPATH_LINKINIT; | ||
1720 | break; | ||
1721 | |||
1722 | case IPATH_IB_LINKARM: | 1718 | case IPATH_IB_LINKARM: |
1723 | if (dd->ipath_flags & IPATH_LINKARMED) { | 1719 | if (dd->ipath_flags & IPATH_LINKARMED) { |
1724 | ret = 0; | 1720 | ret = 0; |
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 4cc0f95ea877..ecf3f7ff7717 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h | |||
@@ -767,6 +767,7 @@ void ipath_kreceive(struct ipath_portdata *); | |||
767 | int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned); | 767 | int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned); |
768 | int ipath_reset_device(int); | 768 | int ipath_reset_device(int); |
769 | void ipath_get_faststats(unsigned long); | 769 | void ipath_get_faststats(unsigned long); |
770 | int ipath_wait_linkstate(struct ipath_devdata *, u32, int); | ||
770 | int ipath_set_linkstate(struct ipath_devdata *, u8); | 771 | int ipath_set_linkstate(struct ipath_devdata *, u8); |
771 | int ipath_set_mtu(struct ipath_devdata *, u16); | 772 | int ipath_set_mtu(struct ipath_devdata *, u16); |
772 | int ipath_set_lid(struct ipath_devdata *, u32, u8); | 773 | int ipath_set_lid(struct ipath_devdata *, u32, u8); |
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index d98d5f103700..b34b91d3723a 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c | |||
@@ -555,10 +555,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, | |||
555 | /* FALLTHROUGH */ | 555 | /* FALLTHROUGH */ |
556 | case IB_PORT_DOWN: | 556 | case IB_PORT_DOWN: |
557 | if (lstate == 0) | 557 | if (lstate == 0) |
558 | if (get_linkdowndefaultstate(dd)) | 558 | lstate = IPATH_IB_LINKDOWN_ONLY; |
559 | lstate = IPATH_IB_LINKDOWN_SLEEP; | ||
560 | else | ||
561 | lstate = IPATH_IB_LINKDOWN; | ||
562 | else if (lstate == 1) | 559 | else if (lstate == 1) |
563 | lstate = IPATH_IB_LINKDOWN_SLEEP; | 560 | lstate = IPATH_IB_LINKDOWN_SLEEP; |
564 | else if (lstate == 2) | 561 | else if (lstate == 2) |
@@ -568,6 +565,8 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, | |||
568 | else | 565 | else |
569 | goto err; | 566 | goto err; |
570 | ipath_set_linkstate(dd, lstate); | 567 | ipath_set_linkstate(dd, lstate); |
568 | ipath_wait_linkstate(dd, IPATH_LINKINIT | IPATH_LINKARMED | | ||
569 | IPATH_LINKACTIVE, 1000); | ||
571 | break; | 570 | break; |
572 | case IB_PORT_ARMED: | 571 | case IB_PORT_ARMED: |
573 | ipath_set_linkstate(dd, IPATH_IB_LINKARM); | 572 | ipath_set_linkstate(dd, IPATH_IB_LINKARM); |
diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h index 6d2a17f9c1da..92ad73a7fff0 100644 --- a/drivers/infiniband/hw/ipath/ipath_registers.h +++ b/drivers/infiniband/hw/ipath/ipath_registers.h | |||
@@ -185,7 +185,7 @@ | |||
185 | #define INFINIPATH_IBCC_LINKINITCMD_SLEEP 3 | 185 | #define INFINIPATH_IBCC_LINKINITCMD_SLEEP 3 |
186 | #define INFINIPATH_IBCC_LINKINITCMD_SHIFT 16 | 186 | #define INFINIPATH_IBCC_LINKINITCMD_SHIFT 16 |
187 | #define INFINIPATH_IBCC_LINKCMD_MASK 0x3ULL | 187 | #define INFINIPATH_IBCC_LINKCMD_MASK 0x3ULL |
188 | #define INFINIPATH_IBCC_LINKCMD_INIT 1 /* move to 0x11 */ | 188 | #define INFINIPATH_IBCC_LINKCMD_DOWN 1 /* move to 0x11 */ |
189 | #define INFINIPATH_IBCC_LINKCMD_ARMED 2 /* move to 0x21 */ | 189 | #define INFINIPATH_IBCC_LINKCMD_ARMED 2 /* move to 0x21 */ |
190 | #define INFINIPATH_IBCC_LINKCMD_ACTIVE 3 /* move to 0x31 */ | 190 | #define INFINIPATH_IBCC_LINKCMD_ACTIVE 3 /* move to 0x31 */ |
191 | #define INFINIPATH_IBCC_LINKCMD_SHIFT 18 | 191 | #define INFINIPATH_IBCC_LINKCMD_SHIFT 18 |