summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2009-11-16 22:21:12 +0100
committerMichael Brown2009-11-16 23:19:39 +0100
commit7467cf5f0942a1e3cbe887272a884dda26c240e4 (patch)
treef5ed248fd41a06170342ae814eb11911a9951b4e
parent[ipoib] Mask out non-QPN bits in the IPoIB destination MAC when sending (diff)
downloadipxe-7467cf5f0942a1e3cbe887272a884dda26c240e4.tar.gz
ipxe-7467cf5f0942a1e3cbe887272a884dda26c240e4.tar.xz
ipxe-7467cf5f0942a1e3cbe887272a884dda26c240e4.zip
[linda] Wait up to 20us for link state to update
Some subnet managers expect the GetResponse from a SetPortInfo MAD to contain the new link state. The transition is not immediate, so we often end up returning the previous link state. This can cause the SM to fail to activate the port. Fix by waiting for up to 20us for the link state transition to take effect.
-rw-r--r--src/drivers/infiniband/linda.c32
-rw-r--r--src/drivers/infiniband/linda.h3
2 files changed, 35 insertions, 0 deletions
diff --git a/src/drivers/infiniband/linda.c b/src/drivers/infiniband/linda.c
index 7893e063..b9a7ba58 100644
--- a/src/drivers/infiniband/linda.c
+++ b/src/drivers/infiniband/linda.c
@@ -239,6 +239,32 @@ static void linda_link_state_changed ( struct ib_device *ibdev ) {
}
/**
+ * Wait for link state change to take effect
+ *
+ * @v linda Linda device
+ * @v new_link_state Expected link state
+ * @ret rc Return status code
+ */
+static int linda_link_state_check ( struct linda *linda,
+ unsigned int new_link_state ) {
+ struct QIB_7220_IBCStatus ibcstatus;
+ unsigned int link_state;
+ unsigned int i;
+
+ for ( i = 0 ; i < LINDA_LINK_STATE_MAX_WAIT_US ; i++ ) {
+ linda_readq ( linda, &ibcstatus, QIB_7220_IBCStatus_offset );
+ link_state = BIT_GET ( &ibcstatus, LinkState );
+ if ( link_state == new_link_state )
+ return 0;
+ udelay ( 1 );
+ }
+
+ DBGC ( linda, "Linda %p timed out waiting for link state %s\n",
+ linda, linda_link_state_text ( link_state ) );
+ return -ETIMEDOUT;
+}
+
+/**
* Set port information
*
* @v ibdev Infiniband device
@@ -260,6 +286,12 @@ static int linda_set_port_info ( struct ib_device *ibdev, union ib_mad *mad ) {
linda_readq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset );
BIT_SET ( &ibcctrl, LinkCmd, link_state );
linda_writeq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset );
+
+ /* Wait for link state change to take effect. Ignore
+ * errors; the current link state will be returned via
+ * the GetResponse MAD.
+ */
+ linda_link_state_check ( linda, link_state );
}
/* Detect and report link state change */
diff --git a/src/drivers/infiniband/linda.h b/src/drivers/infiniband/linda.h
index 66eea28e..3068421b 100644
--- a/src/drivers/infiniband/linda.h
+++ b/src/drivers/infiniband/linda.h
@@ -270,4 +270,7 @@ enum linda_link_state {
LINDA_LINK_STATE_ACT_DEFER = 4,
};
+/** Maximum time to wait for link state changes, in us */
+#define LINDA_LINK_STATE_MAX_WAIT_US 20
+
#endif /* _LINDA_H */