IPoIB: Handle P_Key table reordering
[deliverable/linux.git] / drivers / infiniband / ulp / ipoib / ipoib_ib.c
index 68d72c6f7ffbf40be9156b214ac79df8614bf4fc..e3b0937011d122df60b7a38e3a5410c565733327 100644 (file)
@@ -448,6 +448,13 @@ int ipoib_ib_dev_open(struct net_device *dev)
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        int ret;
 
+       if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &priv->pkey_index)) {
+               ipoib_warn(priv, "P_Key 0x%04x not found\n", priv->pkey);
+               clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
+               return -1;
+       }
+       set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
+
        ret = ipoib_init_qp(dev);
        if (ret) {
                ipoib_warn(priv, "ipoib_init_qp returned %d\n", ret);
@@ -457,14 +464,14 @@ int ipoib_ib_dev_open(struct net_device *dev)
        ret = ipoib_ib_post_receives(dev);
        if (ret) {
                ipoib_warn(priv, "ipoib_ib_post_receives returned %d\n", ret);
-               ipoib_ib_dev_stop(dev);
+               ipoib_ib_dev_stop(dev, 1);
                return -1;
        }
 
        ret = ipoib_cm_dev_open(dev);
        if (ret) {
                ipoib_warn(priv, "ipoib_ib_post_receives returned %d\n", ret);
-               ipoib_ib_dev_stop(dev);
+               ipoib_ib_dev_stop(dev, 1);
                return -1;
        }
 
@@ -516,7 +523,7 @@ int ipoib_ib_dev_down(struct net_device *dev, int flush)
        if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) {
                mutex_lock(&pkey_mutex);
                set_bit(IPOIB_PKEY_STOP, &priv->flags);
-               cancel_delayed_work(&priv->pkey_task);
+               cancel_delayed_work(&priv->pkey_poll_task);
                mutex_unlock(&pkey_mutex);
                if (flush)
                        flush_workqueue(ipoib_workqueue);
@@ -543,7 +550,7 @@ static int recvs_pending(struct net_device *dev)
        return pending;
 }
 
-int ipoib_ib_dev_stop(struct net_device *dev)
+int ipoib_ib_dev_stop(struct net_device *dev, int flush)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ib_qp_attr qp_attr;
@@ -629,7 +636,8 @@ timeout:
        /* Wait for all AHs to be reaped */
        set_bit(IPOIB_STOP_REAPER, &priv->flags);
        cancel_delayed_work(&priv->ah_reap_task);
-       flush_workqueue(ipoib_workqueue);
+       if (flush)
+               flush_workqueue(ipoib_workqueue);
 
        begin = jiffies;
 
@@ -673,13 +681,24 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
        return 0;
 }
 
-void ipoib_ib_dev_flush(struct work_struct *work)
+static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, int pkey_event)
 {
-       struct ipoib_dev_priv *cpriv, *priv =
-               container_of(work, struct ipoib_dev_priv, flush_task);
+       struct ipoib_dev_priv *cpriv;
        struct net_device *dev = priv->dev;
+       u16 new_index;
+
+       mutex_lock(&priv->vlan_mutex);
 
-       if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags) ) {
+       /*
+        * Flush any child interfaces too -- they might be up even if
+        * the parent is down.
+        */
+       list_for_each_entry(cpriv, &priv->child_intfs, list)
+               __ipoib_ib_dev_flush(cpriv, pkey_event);
+
+       mutex_unlock(&priv->vlan_mutex);
+
+       if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) {
                ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n");
                return;
        }
@@ -689,10 +708,32 @@ void ipoib_ib_dev_flush(struct work_struct *work)
                return;
        }
 
+       if (pkey_event) {
+               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_pkey_dev_delay_open(dev);
+                       return;
+               }
+               set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
+
+               /* restart QP only if P_Key index is changed */
+               if (new_index == priv->pkey_index) {
+                       ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n");
+                       return;
+               }
+               priv->pkey_index = new_index;
+       }
+
        ipoib_dbg(priv, "flushing\n");
 
        ipoib_ib_dev_down(dev, 0);
 
+       if (pkey_event) {
+               ipoib_ib_dev_stop(dev, 0);
+               ipoib_ib_dev_open(dev);
+       }
+
        /*
         * The device could have been brought down between the start and when
         * we get here, don't bring it back up if it's not configured up
@@ -701,14 +742,24 @@ void ipoib_ib_dev_flush(struct work_struct *work)
                ipoib_ib_dev_up(dev);
                ipoib_mcast_restart_task(&priv->restart_task);
        }
+}
 
-       mutex_lock(&priv->vlan_mutex);
+void ipoib_ib_dev_flush(struct work_struct *work)
+{
+       struct ipoib_dev_priv *priv =
+               container_of(work, struct ipoib_dev_priv, flush_task);
 
-       /* Flush any child interfaces too */
-       list_for_each_entry(cpriv, &priv->child_intfs, list)
-               ipoib_ib_dev_flush(&cpriv->flush_task);
+       ipoib_dbg(priv, "Flushing %s\n", priv->dev->name);
+       __ipoib_ib_dev_flush(priv, 0);
+}
 
-       mutex_unlock(&priv->vlan_mutex);
+void ipoib_pkey_event(struct work_struct *work)
+{
+       struct ipoib_dev_priv *priv =
+               container_of(work, struct ipoib_dev_priv, pkey_event_task);
+
+       ipoib_dbg(priv, "Flushing %s and restarting its QP\n", priv->dev->name);
+       __ipoib_ib_dev_flush(priv, 1);
 }
 
 void ipoib_ib_dev_cleanup(struct net_device *dev)
@@ -736,7 +787,7 @@ void ipoib_ib_dev_cleanup(struct net_device *dev)
 void ipoib_pkey_poll(struct work_struct *work)
 {
        struct ipoib_dev_priv *priv =
-               container_of(work, struct ipoib_dev_priv, pkey_task.work);
+               container_of(work, struct ipoib_dev_priv, pkey_poll_task.work);
        struct net_device *dev = priv->dev;
 
        ipoib_pkey_dev_check_presence(dev);
@@ -747,7 +798,7 @@ void ipoib_pkey_poll(struct work_struct *work)
                mutex_lock(&pkey_mutex);
                if (!test_bit(IPOIB_PKEY_STOP, &priv->flags))
                        queue_delayed_work(ipoib_workqueue,
-                                          &priv->pkey_task,
+                                          &priv->pkey_poll_task,
                                           HZ);
                mutex_unlock(&pkey_mutex);
        }
@@ -766,7 +817,7 @@ int ipoib_pkey_dev_delay_open(struct net_device *dev)
                mutex_lock(&pkey_mutex);
                clear_bit(IPOIB_PKEY_STOP, &priv->flags);
                queue_delayed_work(ipoib_workqueue,
-                                  &priv->pkey_task,
+                                  &priv->pkey_poll_task,
                                   HZ);
                mutex_unlock(&pkey_mutex);
                return 1;
This page took 0.031797 seconds and 5 git commands to generate.