Commit ff41f8dc authored by Alexander Duyck's avatar Alexander Duyck Committed by David S. Miller

igb: add support for set_rx_mode netdevice operation

This patch adds support for the set_rx_mode netdevice operation so that igb
can better support multiple unicast addresses.
Signed-off-by: default avatarAlexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 55f9d678
...@@ -94,7 +94,7 @@ static void igb_clean_all_tx_rings(struct igb_adapter *); ...@@ -94,7 +94,7 @@ static void igb_clean_all_tx_rings(struct igb_adapter *);
static void igb_clean_all_rx_rings(struct igb_adapter *); static void igb_clean_all_rx_rings(struct igb_adapter *);
static void igb_clean_tx_ring(struct igb_ring *); static void igb_clean_tx_ring(struct igb_ring *);
static void igb_clean_rx_ring(struct igb_ring *); static void igb_clean_rx_ring(struct igb_ring *);
static void igb_set_multi(struct net_device *); static void igb_set_rx_mode(struct net_device *);
static void igb_update_phy_info(unsigned long); static void igb_update_phy_info(unsigned long);
static void igb_watchdog(unsigned long); static void igb_watchdog(unsigned long);
static void igb_watchdog_task(struct work_struct *); static void igb_watchdog_task(struct work_struct *);
...@@ -928,7 +928,7 @@ static void igb_configure(struct igb_adapter *adapter) ...@@ -928,7 +928,7 @@ static void igb_configure(struct igb_adapter *adapter)
int i; int i;
igb_get_hw_control(adapter); igb_get_hw_control(adapter);
igb_set_multi(netdev); igb_set_rx_mode(netdev);
igb_restore_vlan(adapter); igb_restore_vlan(adapter);
...@@ -1169,7 +1169,8 @@ static const struct net_device_ops igb_netdev_ops = { ...@@ -1169,7 +1169,8 @@ static const struct net_device_ops igb_netdev_ops = {
.ndo_stop = igb_close, .ndo_stop = igb_close,
.ndo_start_xmit = igb_xmit_frame_adv, .ndo_start_xmit = igb_xmit_frame_adv,
.ndo_get_stats = igb_get_stats, .ndo_get_stats = igb_get_stats,
.ndo_set_multicast_list = igb_set_multi, .ndo_set_rx_mode = igb_set_rx_mode,
.ndo_set_multicast_list = igb_set_rx_mode,
.ndo_set_mac_address = igb_set_mac, .ndo_set_mac_address = igb_set_mac,
.ndo_change_mtu = igb_change_mtu, .ndo_change_mtu = igb_change_mtu,
.ndo_do_ioctl = igb_ioctl, .ndo_do_ioctl = igb_ioctl,
...@@ -2519,48 +2520,70 @@ static int igb_set_mac(struct net_device *netdev, void *p) ...@@ -2519,48 +2520,70 @@ static int igb_set_mac(struct net_device *netdev, void *p)
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len); memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len);
hw->mac.ops.rar_set(hw, hw->mac.addr, 0); igb_rar_set(hw, hw->mac.addr, 0);
igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0); igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0);
return 0; return 0;
} }
/** /**
* igb_set_multi - Multicast and Promiscuous mode set * igb_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set
* @netdev: network interface device structure * @netdev: network interface device structure
* *
* The set_multi entry point is called whenever the multicast address * The set_rx_mode entry point is called whenever the unicast or multicast
* list or the network interface flags are updated. This routine is * address lists or the network interface flags are updated. This routine is
* responsible for configuring the hardware for proper multicast, * responsible for configuring the hardware for proper unicast, multicast,
* promiscuous mode, and all-multi behavior. * promiscuous mode, and all-multi behavior.
**/ **/
static void igb_set_multi(struct net_device *netdev) static void igb_set_rx_mode(struct net_device *netdev)
{ {
struct igb_adapter *adapter = netdev_priv(netdev); struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
struct dev_mc_list *mc_ptr; unsigned int rar_entries = hw->mac.rar_entry_count -
(adapter->vfs_allocated_count + 1);
struct dev_mc_list *mc_ptr = netdev->mc_list;
u8 *mta_list = NULL; u8 *mta_list = NULL;
u32 rctl; u32 rctl;
int i; int i;
/* Check for Promiscuous and All Multicast modes */ /* Check for Promiscuous and All Multicast modes */
rctl = rd32(E1000_RCTL); rctl = rd32(E1000_RCTL);
if (netdev->flags & IFF_PROMISC) { if (netdev->flags & IFF_PROMISC) {
rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
rctl &= ~E1000_RCTL_VFE; rctl &= ~E1000_RCTL_VFE;
} else { } else {
if (netdev->flags & IFF_ALLMULTI) { if (netdev->flags & IFF_ALLMULTI)
rctl |= E1000_RCTL_MPE; rctl |= E1000_RCTL_MPE;
else
rctl &= ~E1000_RCTL_MPE;
if (netdev->uc.count > rar_entries)
rctl |= E1000_RCTL_UPE;
else
rctl &= ~E1000_RCTL_UPE; rctl &= ~E1000_RCTL_UPE;
} else
rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
rctl |= E1000_RCTL_VFE; rctl |= E1000_RCTL_VFE;
} }
wr32(E1000_RCTL, rctl); wr32(E1000_RCTL, rctl);
if (netdev->uc.count && rar_entries) {
struct netdev_hw_addr *ha;
list_for_each_entry(ha, &netdev->uc.list, list) {
if (!rar_entries)
break;
igb_rar_set(hw, ha->addr, rar_entries);
igb_set_rah_pool(hw, adapter->vfs_allocated_count,
rar_entries);
rar_entries--;
}
}
/* write the addresses in reverse order to avoid write combining */
for (; rar_entries > 0 ; rar_entries--) {
wr32(E1000_RAH(rar_entries), 0);
wr32(E1000_RAL(rar_entries), 0);
}
wrfl();
if (!netdev->mc_count) { if (!netdev->mc_count) {
/* nothing to program, so clear mc list */ /* nothing to program, so clear mc list */
igb_update_mc_addr_list(hw, NULL, 0); igb_update_mc_addr_list(hw, NULL, 0);
...@@ -2576,8 +2599,6 @@ static void igb_set_multi(struct net_device *netdev) ...@@ -2576,8 +2599,6 @@ static void igb_set_multi(struct net_device *netdev)
} }
/* The shared function expects a packed array of only addresses. */ /* The shared function expects a packed array of only addresses. */
mc_ptr = netdev->mc_list;
for (i = 0; i < netdev->mc_count; i++) { for (i = 0; i < netdev->mc_count; i++) {
if (!mc_ptr) if (!mc_ptr)
break; break;
...@@ -3938,7 +3959,7 @@ static int igb_set_vf_multicasts(struct igb_adapter *adapter, ...@@ -3938,7 +3959,7 @@ static int igb_set_vf_multicasts(struct igb_adapter *adapter,
vf_data->vf_mc_hashes[i] = hash_list[i];; vf_data->vf_mc_hashes[i] = hash_list[i];;
/* Flush and reset the mta with the new values */ /* Flush and reset the mta with the new values */
igb_set_multi(adapter->netdev); igb_set_rx_mode(adapter->netdev);
return 0; return 0;
} }
...@@ -4072,13 +4093,14 @@ static inline void igb_vf_reset_event(struct igb_adapter *adapter, u32 vf) ...@@ -4072,13 +4093,14 @@ static inline void igb_vf_reset_event(struct igb_adapter *adapter, u32 vf)
adapter->vf_data[vf].num_vf_mc_hashes = 0; adapter->vf_data[vf].num_vf_mc_hashes = 0;
/* Flush and reset the mta with the new values */ /* Flush and reset the mta with the new values */
igb_set_multi(adapter->netdev); igb_set_rx_mode(adapter->netdev);
} }
static inline void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf) static inline void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf)
{ {
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses; unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses;
int rar_entry = hw->mac.rar_entry_count - (vf + 1);
u32 reg, msgbuf[3]; u32 reg, msgbuf[3];
u8 *addr = (u8 *)(&msgbuf[1]); u8 *addr = (u8 *)(&msgbuf[1]);
...@@ -4086,8 +4108,8 @@ static inline void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf) ...@@ -4086,8 +4108,8 @@ static inline void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf)
igb_vf_reset_event(adapter, vf); igb_vf_reset_event(adapter, vf);
/* set vf mac address */ /* set vf mac address */
igb_rar_set(hw, vf_mac, vf + 1); igb_rar_set(hw, vf_mac, rar_entry);
igb_set_rah_pool(hw, vf, vf + 1); igb_set_rah_pool(hw, vf, rar_entry);
/* enable transmit and receive for vf */ /* enable transmit and receive for vf */
reg = rd32(E1000_VFTE); reg = rd32(E1000_VFTE);
...@@ -5228,7 +5250,7 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake) ...@@ -5228,7 +5250,7 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake)
if (wufc) { if (wufc) {
igb_setup_rctl(adapter); igb_setup_rctl(adapter);
igb_set_multi(netdev); igb_set_rx_mode(netdev);
/* turn on all-multi mode if wake on multicast is enabled */ /* turn on all-multi mode if wake on multicast is enabled */
if (wufc & E1000_WUFC_MC) { if (wufc & E1000_WUFC_MC) {
...@@ -5482,12 +5504,13 @@ static int igb_set_vf_mac(struct igb_adapter *adapter, ...@@ -5482,12 +5504,13 @@ static int igb_set_vf_mac(struct igb_adapter *adapter,
int vf, unsigned char *mac_addr) int vf, unsigned char *mac_addr)
{ {
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
int rar_entry = vf + 1; /* VF MAC addresses start at entry 1 */ /* VF MAC addresses start at end of receive addresses and moves
* torwards the first, as a result a collision should not be possible */
igb_rar_set(hw, mac_addr, rar_entry); int rar_entry = hw->mac.rar_entry_count - (vf + 1);
memcpy(adapter->vf_data[vf].vf_mac_addresses, mac_addr, ETH_ALEN); memcpy(adapter->vf_data[vf].vf_mac_addresses, mac_addr, ETH_ALEN);
igb_rar_set(hw, mac_addr, rar_entry);
igb_set_rah_pool(hw, vf, rar_entry); igb_set_rah_pool(hw, vf, rar_entry);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment