]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/infiniband/ulp/ipoib/ipoib_vlan.c
IB/ipoib: Add rtnl_link_ops support
[karo-tx-linux.git] / drivers / infiniband / ulp / ipoib / ipoib_vlan.c
index d7e9740c724804afcdf20ba9c54fbe4fe91fdb87..238bbf9b2bea8bba67fdcefc42245037df6da23c 100644 (file)
@@ -49,47 +49,11 @@ static ssize_t show_parent(struct device *d, struct device_attribute *attr,
 }
 static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
 
-int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
+int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv,
+                    u16 pkey, int type)
 {
-       struct ipoib_dev_priv *ppriv, *priv;
-       char intf_name[IFNAMSIZ];
        int result;
 
-       if (!capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-       ppriv = netdev_priv(pdev);
-
-       if (!rtnl_trylock())
-               return restart_syscall();
-       mutex_lock(&ppriv->vlan_mutex);
-
-       /*
-        * First ensure this isn't a duplicate. We check the parent device and
-        * then all of the child interfaces to make sure the Pkey doesn't match.
-        */
-       if (ppriv->pkey == pkey) {
-               result = -ENOTUNIQ;
-               priv = NULL;
-               goto err;
-       }
-
-       list_for_each_entry(priv, &ppriv->child_intfs, list) {
-               if (priv->pkey == pkey) {
-                       result = -ENOTUNIQ;
-                       priv = NULL;
-                       goto err;
-               }
-       }
-
-       snprintf(intf_name, sizeof intf_name, "%s.%04x",
-                ppriv->dev->name, pkey);
-       priv = ipoib_intf_alloc(intf_name);
-       if (!priv) {
-               result = -ENOMEM;
-               goto err;
-       }
-
        priv->max_ib_mtu = ppriv->max_ib_mtu;
        /* MTU will be reset when mcast join happens */
        priv->dev->mtu   = IPOIB_UD_MTU(priv->max_ib_mtu);
@@ -134,14 +98,13 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
        if (device_create_file(&priv->dev->dev, &dev_attr_parent))
                goto sysfs_failed;
 
+       priv->child_type = type;
        list_add_tail(&priv->list, &ppriv->child_intfs);
 
-       mutex_unlock(&ppriv->vlan_mutex);
-       rtnl_unlock();
-
        return 0;
 
 sysfs_failed:
+       result = -ENOMEM;
        ipoib_delete_debug_files(priv->dev);
        unregister_netdevice(priv->dev);
 
@@ -149,11 +112,60 @@ register_failed:
        ipoib_dev_cleanup(priv->dev);
 
 err:
+       return result;
+}
+
+int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
+{
+       struct ipoib_dev_priv *ppriv, *priv;
+       char intf_name[IFNAMSIZ];
+       struct ipoib_dev_priv *tpriv;
+       int result;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       ppriv = netdev_priv(pdev);
+
+       snprintf(intf_name, sizeof intf_name, "%s.%04x",
+                ppriv->dev->name, pkey);
+       priv = ipoib_intf_alloc(intf_name);
+       if (!priv)
+               return -ENOMEM;
+
+       if (!rtnl_trylock())
+               return restart_syscall();
+
+       mutex_lock(&ppriv->vlan_mutex);
+
+       /*
+        * First ensure this isn't a duplicate. We check the parent device and
+        * then all of the legacy child interfaces to make sure the Pkey
+        * doesn't match.
+        */
+       if (ppriv->pkey == pkey) {
+               result = -ENOTUNIQ;
+               goto out;
+       }
+
+       list_for_each_entry(tpriv, &ppriv->child_intfs, list) {
+               if (tpriv->pkey == pkey &&
+                   tpriv->child_type == IPOIB_LEGACY_CHILD) {
+                       result = -ENOTUNIQ;
+                       goto out;
+               }
+       }
+
+       result = __ipoib_vlan_add(ppriv, priv, pkey, IPOIB_LEGACY_CHILD);
+
+out:
        mutex_unlock(&ppriv->vlan_mutex);
-       rtnl_unlock();
-       if (priv)
+
+       if (result)
                free_netdev(priv->dev);
 
+       rtnl_unlock();
+
        return result;
 }
 
@@ -171,9 +183,9 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
                return restart_syscall();
        mutex_lock(&ppriv->vlan_mutex);
        list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
-               if (priv->pkey == pkey) {
+               if (priv->pkey == pkey &&
+                   priv->child_type == IPOIB_LEGACY_CHILD) {
                        unregister_netdevice(priv->dev);
-                       ipoib_dev_cleanup(priv->dev);
                        list_del(&priv->list);
                        dev = priv->dev;
                        break;