ixgbe: update set_rx_mode to fix issues w/ macvlan
authorAlexander Duyck <alexander.h.duyck@intel.com>
Tue, 15 Jun 2010 09:25:48 +0000 (09:25 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 15 Jun 2010 21:23:35 +0000 (14:23 -0700)
This change corrects issues where macvlan was not correctly triggering
promiscuous mode on ixgbe due to the filters not being correctly set.  It
also corrects the fact that VF rar filters were being overwritten when the
PF was reset.

CC: Shirley Ma <xma@us.ibm.com>
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Emil Tantilov <emil.s.tantilov@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_sriov.c

index 9270089eb282c2763bb91071bd31eb1248de00b2..9e15eb93860eb4686ad79ca5058de708ff2bda72 100644 (file)
@@ -110,7 +110,6 @@ struct vf_data_storage {
        u16 vlans_enabled;
        bool clear_to_send;
        bool pf_set_mac;
-       int rar;
        u16 pf_vlan; /* When set, guest VLAN config not allowed. */
        u16 pf_qos;
 };
index 9cca737e48855db0956fb58237cf5c277c8e9044..ebc4b04fdef21b865f1f2aaf012ea6a03fd276d0 100644 (file)
@@ -2991,6 +2991,48 @@ static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
        }
 }
 
+/**
+ * ixgbe_write_uc_addr_list - write unicast addresses to RAR table
+ * @netdev: network interface device structure
+ *
+ * Writes unicast address list to the RAR table.
+ * Returns: -ENOMEM on failure/insufficient address space
+ *                0 on no addresses written
+ *                X on writing X addresses to the RAR table
+ **/
+static int ixgbe_write_uc_addr_list(struct net_device *netdev)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+       unsigned int vfn = adapter->num_vfs;
+       unsigned int rar_entries = hw->mac.num_rar_entries - (vfn + 1);
+       int count = 0;
+
+       /* return ENOMEM indicating insufficient memory for addresses */
+       if (netdev_uc_count(netdev) > rar_entries)
+               return -ENOMEM;
+
+       if (!netdev_uc_empty(netdev) && rar_entries) {
+               struct netdev_hw_addr *ha;
+               /* return error if we do not support writing to RAR table */
+               if (!hw->mac.ops.set_rar)
+                       return -ENOMEM;
+
+               netdev_for_each_uc_addr(ha, netdev) {
+                       if (!rar_entries)
+                               break;
+                       hw->mac.ops.set_rar(hw, rar_entries--, ha->addr,
+                                           vfn, IXGBE_RAH_AV);
+                       count++;
+               }
+       }
+       /* write the addresses in reverse order to avoid write combining */
+       for (; rar_entries > 0 ; rar_entries--)
+               hw->mac.ops.clear_rar(hw, rar_entries);
+
+       return count;
+}
+
 /**
  * ixgbe_set_rx_mode - Unicast, Multicast and Promiscuous mode set
  * @netdev: network interface device structure
@@ -3004,38 +3046,58 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
-       u32 fctrl;
+       u32 fctrl, vmolr = IXGBE_VMOLR_BAM | IXGBE_VMOLR_AUPE;
+       int count;
 
        /* Check for Promiscuous and All Multicast modes */
 
        fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
 
+       /* clear the bits we are changing the status of */
+       fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+
        if (netdev->flags & IFF_PROMISC) {
                hw->addr_ctrl.user_set_promisc = true;
                fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+               vmolr |= (IXGBE_VMOLR_ROPE | IXGBE_VMOLR_MPE);
                /* don't hardware filter vlans in promisc mode */
                ixgbe_vlan_filter_disable(adapter);
        } else {
                if (netdev->flags & IFF_ALLMULTI) {
                        fctrl |= IXGBE_FCTRL_MPE;
-                       fctrl &= ~IXGBE_FCTRL_UPE;
-               } else if (!hw->addr_ctrl.uc_set_promisc) {
-                       fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+                       vmolr |= IXGBE_VMOLR_MPE;
+               } else {
+                       /*
+                        * Write addresses to the MTA, if the attempt fails
+                        * then we should just turn on promiscous mode so
+                        * that we can at least receive multicast traffic
+                        */
+                       hw->mac.ops.update_mc_addr_list(hw, netdev);
+                       vmolr |= IXGBE_VMOLR_ROMPE;
                }
                ixgbe_vlan_filter_enable(adapter);
                hw->addr_ctrl.user_set_promisc = false;
+               /*
+                * Write addresses to available RAR registers, if there is not
+                * sufficient space to store all the addresses then enable
+                * unicast promiscous mode
+                */
+               count = ixgbe_write_uc_addr_list(netdev);
+               if (count < 0) {
+                       fctrl |= IXGBE_FCTRL_UPE;
+                       vmolr |= IXGBE_VMOLR_ROPE;
+               }
        }
 
-       IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
-
-       /* reprogram secondary unicast list */
-       hw->mac.ops.update_uc_addr_list(hw, netdev);
-
-       /* reprogram multicast list */
-       hw->mac.ops.update_mc_addr_list(hw, netdev);
-
-       if (adapter->num_vfs)
+       if (adapter->num_vfs) {
                ixgbe_restore_vf_multicasts(adapter);
+               vmolr |= IXGBE_READ_REG(hw, IXGBE_VMOLR(adapter->num_vfs)) &
+                        ~(IXGBE_VMOLR_MPE | IXGBE_VMOLR_ROMPE |
+                          IXGBE_VMOLR_ROPE);
+               IXGBE_WRITE_REG(hw, IXGBE_VMOLR(adapter->num_vfs), vmolr);
+       }
+
+       IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
 }
 
 static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter)
index 66f6e62b8cb0a2782eb155220a7f1ae8b42ef4ca..6e6dee04ff61704c636402885e8b1a4df81c5cfb 100644 (file)
@@ -137,6 +137,7 @@ static void ixgbe_set_vmvir(struct ixgbe_adapter *adapter, u32 vid, u32 vf)
 inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
 {
        struct ixgbe_hw *hw = &adapter->hw;
+       int rar_entry = hw->mac.num_rar_entries - (vf + 1);
 
        /* reset offloads to defaults */
        if (adapter->vfinfo[vf].pf_vlan) {
@@ -158,26 +159,17 @@ inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
        /* Flush and reset the mta with the new values */
        ixgbe_set_rx_mode(adapter->netdev);
 
-       if (adapter->vfinfo[vf].rar > 0) {
-               adapter->hw.mac.ops.clear_rar(&adapter->hw,
-                                             adapter->vfinfo[vf].rar);
-               adapter->vfinfo[vf].rar = -1;
-       }
+       hw->mac.ops.clear_rar(hw, rar_entry);
 }
 
 int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
                           int vf, unsigned char *mac_addr)
 {
        struct ixgbe_hw *hw = &adapter->hw;
-
-       adapter->vfinfo[vf].rar = hw->mac.ops.set_rar(hw, vf + 1, mac_addr,
-                                                     vf, IXGBE_RAH_AV);
-       if (adapter->vfinfo[vf].rar < 0) {
-               e_err("Could not set MAC Filter for VF %d\n", vf);
-               return -1;
-       }
+       int rar_entry = hw->mac.num_rar_entries - (vf + 1);
 
        memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr, 6);
+       hw->mac.ops.set_rar(hw, rar_entry, mac_addr, vf, IXGBE_RAH_AV);
 
        return 0;
 }