]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/bonding/bond_main.c
Merge branch 'pm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[karo-tx-linux.git] / drivers / net / bonding / bond_main.c
index 7f8756825b8abf62f924d569b3e923c7f955c413..435984ad8b2f1a8bedd54ba49eb4269f3991bd3a 100644 (file)
@@ -428,27 +428,34 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
  * @bond_dev: bonding net device that got called
  * @vid: vlan id being added
  */
-static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid)
+static int bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave;
+       struct slave *slave, *stop_at;
        int i, res;
 
        bond_for_each_slave(bond, slave, i) {
-               struct net_device *slave_dev = slave->dev;
-               const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
-
-               if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) &&
-                   slave_ops->ndo_vlan_rx_add_vid) {
-                       slave_ops->ndo_vlan_rx_add_vid(slave_dev, vid);
-               }
+               res = vlan_vid_add(slave->dev, vid);
+               if (res)
+                       goto unwind;
        }
 
        res = bond_add_vlan(bond, vid);
        if (res) {
                pr_err("%s: Error: Failed to add vlan id %d\n",
                       bond_dev->name, vid);
+               return res;
        }
+
+       return 0;
+
+unwind:
+       /* unwind from head to the slave that failed */
+       stop_at = slave;
+       bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at)
+               vlan_vid_del(slave->dev, vid);
+
+       return res;
 }
 
 /**
@@ -456,56 +463,48 @@ static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid)
  * @bond_dev: bonding net device that got called
  * @vid: vlan id being removed
  */
-static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid)
+static int bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
        int i, res;
 
-       bond_for_each_slave(bond, slave, i) {
-               struct net_device *slave_dev = slave->dev;
-               const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
-
-               if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) &&
-                   slave_ops->ndo_vlan_rx_kill_vid) {
-                       slave_ops->ndo_vlan_rx_kill_vid(slave_dev, vid);
-               }
-       }
+       bond_for_each_slave(bond, slave, i)
+               vlan_vid_del(slave->dev, vid);
 
        res = bond_del_vlan(bond, vid);
        if (res) {
                pr_err("%s: Error: Failed to remove vlan id %d\n",
                       bond_dev->name, vid);
+               return res;
        }
+
+       return 0;
 }
 
 static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev)
 {
        struct vlan_entry *vlan;
-       const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
-
-       if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||
-           !(slave_ops->ndo_vlan_rx_add_vid))
-               return;
+       int res;
 
-       list_for_each_entry(vlan, &bond->vlan_list, vlan_list)
-               slave_ops->ndo_vlan_rx_add_vid(slave_dev, vlan->vlan_id);
+       list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
+               res = vlan_vid_add(slave_dev, vlan->vlan_id);
+               if (res)
+                       pr_warning("%s: Failed to add vlan id %d to device %s\n",
+                                  bond->dev->name, vlan->vlan_id,
+                                  slave_dev->name);
+       }
 }
 
 static void bond_del_vlans_from_slave(struct bonding *bond,
                                      struct net_device *slave_dev)
 {
-       const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
        struct vlan_entry *vlan;
 
-       if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||
-           !(slave_ops->ndo_vlan_rx_kill_vid))
-               return;
-
        list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
                if (!vlan->vlan_id)
                        continue;
-               slave_ops->ndo_vlan_rx_kill_vid(slave_dev, vlan->vlan_id);
+               vlan_vid_del(slave_dev, vlan->vlan_id);
        }
 }
 
@@ -1325,11 +1324,12 @@ static int bond_sethwaddr(struct net_device *bond_dev,
        return 0;
 }
 
-static u32 bond_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t bond_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct slave *slave;
        struct bonding *bond = netdev_priv(dev);
-       u32 mask;
+       netdev_features_t mask;
        int i;
 
        read_lock(&bond->lock);
@@ -1363,7 +1363,7 @@ static void bond_compute_features(struct bonding *bond)
 {
        struct slave *slave;
        struct net_device *bond_dev = bond->dev;
-       u32 vlan_features = BOND_VLAN_FEATURES;
+       netdev_features_t vlan_features = BOND_VLAN_FEATURES;
        unsigned short max_hard_header_len = ETH_HLEN;
        int i;
 
@@ -1822,7 +1822,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                                 "but new slave device does not support netpoll.\n",
                                 bond_dev->name);
                        res = -EBUSY;
-                       goto err_close;
+                       goto err_detach;
                }
        }
 #endif
@@ -1831,7 +1831,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        res = bond_create_slave_symlinks(bond_dev, slave_dev);
        if (res)
-               goto err_close;
+               goto err_detach;
 
        res = netdev_rx_handler_register(slave_dev, bond_handle_frame,
                                         new_slave);
@@ -1852,6 +1852,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 err_dest_symlinks:
        bond_destroy_slave_symlinks(bond_dev, slave_dev);
 
+err_detach:
+       write_lock_bh(&bond->lock);
+       bond_detach_slave(bond, new_slave);
+       write_unlock_bh(&bond->lock);
+
 err_close:
        dev_close(slave_dev);
 
@@ -1897,7 +1902,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave, *oldcurrent;
        struct sockaddr addr;
-       u32 old_features = bond_dev->features;
+       netdev_features_t old_features = bond_dev->features;
 
        /* slave is not a slave or master is not master of this slave */
        if (!(slave_dev->flags & IFF_SLAVE) ||
@@ -4339,7 +4344,7 @@ static void bond_setup(struct net_device *bond_dev)
                                NETIF_F_HW_VLAN_RX |
                                NETIF_F_HW_VLAN_FILTER;
 
-       bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM);
+       bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM);
        bond_dev->features |= bond_dev->hw_features;
 }