Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / drivers / net / bonding / bond_main.c
index 7db40de..d0aade0 100644 (file)
@@ -428,14 +428,15 @@ 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 int 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,
+                               __be16 proto, u16 vid)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave, *stop_at;
        int i, res;
 
        bond_for_each_slave(bond, slave, i) {
-               res = vlan_vid_add(slave->dev, vid);
+               res = vlan_vid_add(slave->dev, proto, vid);
                if (res)
                        goto unwind;
        }
@@ -453,7 +454,7 @@ 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);
+               vlan_vid_del(slave->dev, proto, vid);
 
        return res;
 }
@@ -463,14 +464,15 @@ unwind:
  * @bond_dev: bonding net device that got called
  * @vid: vlan id being removed
  */
-static int 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,
+                                __be16 proto, u16 vid)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
        int i, res;
 
        bond_for_each_slave(bond, slave, i)
-               vlan_vid_del(slave->dev, vid);
+               vlan_vid_del(slave->dev, proto, vid);
 
        res = bond_del_vlan(bond, vid);
        if (res) {
@@ -488,7 +490,8 @@ static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *sla
        int res;
 
        list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-               res = vlan_vid_add(slave_dev, vlan->vlan_id);
+               res = vlan_vid_add(slave_dev, htons(ETH_P_8021Q),
+                                  vlan->vlan_id);
                if (res)
                        pr_warning("%s: Failed to add vlan id %d to device %s\n",
                                   bond->dev->name, vlan->vlan_id,
@@ -504,7 +507,7 @@ static void bond_del_vlans_from_slave(struct bonding *bond,
        list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
                if (!vlan->vlan_id)
                        continue;
-               vlan_vid_del(slave_dev, vlan->vlan_id);
+               vlan_vid_del(slave_dev, htons(ETH_P_8021Q), vlan->vlan_id);
        }
 }
 
@@ -779,7 +782,7 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
 
        /* rejoin all groups on vlan devices */
        list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-               vlan_dev = __vlan_find_dev_deep(bond_dev,
+               vlan_dev = __vlan_find_dev_deep(bond_dev, htons(ETH_P_8021Q),
                                                vlan->vlan_id);
                if (vlan_dev)
                        __bond_resend_igmp_join_requests(vlan_dev);
@@ -796,9 +799,8 @@ static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
 {
        struct bonding *bond = container_of(work, struct bonding,
                                            mcast_work.work);
-       rcu_read_lock();
+
        bond_resend_igmp_join_requests(bond);
-       rcu_read_unlock();
 }
 
 /*
@@ -2534,7 +2536,8 @@ static int bond_has_this_ip(struct bonding *bond, __be32 ip)
 
        list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
                rcu_read_lock();
-               vlan_dev = __vlan_find_dev_deep(bond->dev, vlan->vlan_id);
+               vlan_dev = __vlan_find_dev_deep(bond->dev, htons(ETH_P_8021Q),
+                                               vlan->vlan_id);
                rcu_read_unlock();
                if (vlan_dev && ip == bond_confirm_addr(vlan_dev, 0, ip))
                        return 1;
@@ -2563,7 +2566,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_
                return;
        }
        if (vlan_id) {
-               skb = vlan_put_tag(skb, vlan_id);
+               skb = vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_id);
                if (!skb) {
                        pr_err("failed to insert VLAN tag\n");
                        return;
@@ -2625,6 +2628,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
                list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
                        rcu_read_lock();
                        vlan_dev = __vlan_find_dev_deep(bond->dev,
+                                                       htons(ETH_P_8021Q),
                                                        vlan->vlan_id);
                        rcu_read_unlock();
                        if (vlan_dev == rt->dst.dev) {
@@ -4260,6 +4264,37 @@ void bond_set_mode_ops(struct bonding *bond, int mode)
        }
 }
 
+static int bond_ethtool_get_settings(struct net_device *bond_dev,
+                                    struct ethtool_cmd *ecmd)
+{
+       struct bonding *bond = netdev_priv(bond_dev);
+       struct slave *slave;
+       int i;
+       unsigned long speed = 0;
+
+       ecmd->duplex = DUPLEX_UNKNOWN;
+       ecmd->port = PORT_OTHER;
+
+       /* Since SLAVE_IS_OK returns false for all inactive or down slaves, we
+        * do not need to check mode.  Though link speed might not represent
+        * the true receive or transmit bandwidth (not all modes are symmetric)
+        * this is an accurate maximum.
+        */
+       read_lock(&bond->lock);
+       bond_for_each_slave(bond, slave, i) {
+               if (SLAVE_IS_OK(slave)) {
+                       if (slave->speed != SPEED_UNKNOWN)
+                               speed += slave->speed;
+                       if (ecmd->duplex == DUPLEX_UNKNOWN &&
+                           slave->duplex != DUPLEX_UNKNOWN)
+                               ecmd->duplex = slave->duplex;
+               }
+       }
+       ethtool_cmd_speed_set(ecmd, speed ? : SPEED_UNKNOWN);
+       read_unlock(&bond->lock);
+       return 0;
+}
+
 static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
                                     struct ethtool_drvinfo *drvinfo)
 {
@@ -4271,6 +4306,7 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
 
 static const struct ethtool_ops bond_ethtool_ops = {
        .get_drvinfo            = bond_ethtool_get_drvinfo,
+       .get_settings           = bond_ethtool_get_settings,
        .get_link               = ethtool_op_get_link,
 };
 
@@ -4361,9 +4397,9 @@ static void bond_setup(struct net_device *bond_dev)
         */
 
        bond_dev->hw_features = BOND_VLAN_FEATURES |
-                               NETIF_F_HW_VLAN_TX |
-                               NETIF_F_HW_VLAN_RX |
-                               NETIF_F_HW_VLAN_FILTER;
+                               NETIF_F_HW_VLAN_CTAG_TX |
+                               NETIF_F_HW_VLAN_CTAG_RX |
+                               NETIF_F_HW_VLAN_CTAG_FILTER;
 
        bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM);
        bond_dev->features |= bond_dev->hw_features;