|
@@ -932,12 +932,47 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Takes whatever value which is in pkey index 0 and updates priv->pkey
|
|
|
+ * returns 0 if the pkey value was changed.
|
|
|
+ */
|
|
|
+static inline int update_parent_pkey(struct ipoib_dev_priv *priv)
|
|
|
+{
|
|
|
+ int result;
|
|
|
+ u16 prev_pkey;
|
|
|
+
|
|
|
+ prev_pkey = priv->pkey;
|
|
|
+ result = ib_query_pkey(priv->ca, priv->port, 0, &priv->pkey);
|
|
|
+ if (result) {
|
|
|
+ ipoib_warn(priv, "ib_query_pkey port %d failed (ret = %d)\n",
|
|
|
+ priv->port, result);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ priv->pkey |= 0x8000;
|
|
|
+
|
|
|
+ if (prev_pkey != priv->pkey) {
|
|
|
+ ipoib_dbg(priv, "pkey changed from 0x%x to 0x%x\n",
|
|
|
+ prev_pkey, priv->pkey);
|
|
|
+ /*
|
|
|
+ * Update the pkey in the broadcast address, while making sure to set
|
|
|
+ * the full membership bit, so that we join the right broadcast group.
|
|
|
+ */
|
|
|
+ priv->dev->broadcast[8] = priv->pkey >> 8;
|
|
|
+ priv->dev->broadcast[9] = priv->pkey & 0xff;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
|
|
|
enum ipoib_flush_level level)
|
|
|
{
|
|
|
struct ipoib_dev_priv *cpriv;
|
|
|
struct net_device *dev = priv->dev;
|
|
|
u16 new_index;
|
|
|
+ int result;
|
|
|
|
|
|
mutex_lock(&priv->vlan_mutex);
|
|
|
|
|
@@ -951,6 +986,10 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
|
|
|
mutex_unlock(&priv->vlan_mutex);
|
|
|
|
|
|
if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) {
|
|
|
+ /* for non-child devices must check/update the pkey value here */
|
|
|
+ if (level == IPOIB_FLUSH_HEAVY &&
|
|
|
+ !test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags))
|
|
|
+ update_parent_pkey(priv);
|
|
|
ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n");
|
|
|
return;
|
|
|
}
|
|
@@ -961,21 +1000,32 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
|
|
|
}
|
|
|
|
|
|
if (level == IPOIB_FLUSH_HEAVY) {
|
|
|
- if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) {
|
|
|
- clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
|
|
|
- ipoib_ib_dev_down(dev, 0);
|
|
|
- ipoib_ib_dev_stop(dev, 0);
|
|
|
- if (ipoib_pkey_dev_delay_open(dev))
|
|
|
+ /* child devices chase their origin pkey value, while non-child
|
|
|
+ * (parent) devices should always takes what present in pkey index 0
|
|
|
+ */
|
|
|
+ if (test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
|
|
|
+ if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) {
|
|
|
+ clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
|
|
|
+ ipoib_ib_dev_down(dev, 0);
|
|
|
+ ipoib_ib_dev_stop(dev, 0);
|
|
|
+ if (ipoib_pkey_dev_delay_open(dev))
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ /* restart QP only if P_Key index is changed */
|
|
|
+ if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) &&
|
|
|
+ new_index == priv->pkey_index) {
|
|
|
+ ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n");
|
|
|
return;
|
|
|
+ }
|
|
|
+ priv->pkey_index = new_index;
|
|
|
+ } else {
|
|
|
+ result = update_parent_pkey(priv);
|
|
|
+ /* restart QP only if P_Key value changed */
|
|
|
+ if (result) {
|
|
|
+ ipoib_dbg(priv, "Not flushing - P_Key value not changed.\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- /* restart QP only if P_Key index is changed */
|
|
|
- if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) &&
|
|
|
- new_index == priv->pkey_index) {
|
|
|
- ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n");
|
|
|
- return;
|
|
|
- }
|
|
|
- priv->pkey_index = new_index;
|
|
|
}
|
|
|
|
|
|
if (level == IPOIB_FLUSH_LIGHT) {
|