|
@@ -301,7 +301,7 @@ static void ixgbe_remove_adapter(struct ixgbe_hw *hw)
|
|
|
ixgbe_service_event_schedule(adapter);
|
|
|
}
|
|
|
|
|
|
-void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
|
|
|
+static void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
|
|
|
{
|
|
|
u32 value;
|
|
|
|
|
@@ -320,6 +320,32 @@ void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
|
|
|
ixgbe_remove_adapter(hw);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * ixgbe_read_reg - Read from device register
|
|
|
+ * @hw: hw specific details
|
|
|
+ * @reg: offset of register to read
|
|
|
+ *
|
|
|
+ * Returns : value read or IXGBE_FAILED_READ_REG if removed
|
|
|
+ *
|
|
|
+ * This function is used to read device registers. It checks for device
|
|
|
+ * removal by confirming any read that returns all ones by checking the
|
|
|
+ * status register value for all ones. This function avoids reading from
|
|
|
+ * the hardware if a removal was previously detected in which case it
|
|
|
+ * returns IXGBE_FAILED_READ_REG (all ones).
|
|
|
+ */
|
|
|
+u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg)
|
|
|
+{
|
|
|
+ u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
|
|
|
+ u32 value;
|
|
|
+
|
|
|
+ if (ixgbe_removed(reg_addr))
|
|
|
+ return IXGBE_FAILED_READ_REG;
|
|
|
+ value = readl(reg_addr + reg);
|
|
|
+ if (unlikely(value == IXGBE_FAILED_READ_REG))
|
|
|
+ ixgbe_check_remove(hw, reg);
|
|
|
+ return value;
|
|
|
+}
|
|
|
+
|
|
|
static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev)
|
|
|
{
|
|
|
u16 value;
|
|
@@ -3741,35 +3767,6 @@ static int ixgbe_vlan_rx_kill_vid(struct net_device *netdev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * ixgbe_vlan_filter_disable - helper to disable hw vlan filtering
|
|
|
- * @adapter: driver data
|
|
|
- */
|
|
|
-static void ixgbe_vlan_filter_disable(struct ixgbe_adapter *adapter)
|
|
|
-{
|
|
|
- struct ixgbe_hw *hw = &adapter->hw;
|
|
|
- u32 vlnctrl;
|
|
|
-
|
|
|
- vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
|
|
|
- vlnctrl &= ~(IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN);
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * ixgbe_vlan_filter_enable - helper to enable hw vlan filtering
|
|
|
- * @adapter: driver data
|
|
|
- */
|
|
|
-static void ixgbe_vlan_filter_enable(struct ixgbe_adapter *adapter)
|
|
|
-{
|
|
|
- struct ixgbe_hw *hw = &adapter->hw;
|
|
|
- u32 vlnctrl;
|
|
|
-
|
|
|
- vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
|
|
|
- vlnctrl |= IXGBE_VLNCTRL_VFE;
|
|
|
- vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* ixgbe_vlan_strip_disable - helper to disable hw vlan stripping
|
|
|
* @adapter: driver data
|
|
@@ -3848,6 +3845,158 @@ static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
|
|
|
ixgbe_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), vid);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * ixgbe_write_mc_addr_list - write multicast addresses to MTA
|
|
|
+ * @netdev: network interface device structure
|
|
|
+ *
|
|
|
+ * Writes multicast address list to the MTA hash table.
|
|
|
+ * Returns: -ENOMEM on failure
|
|
|
+ * 0 on no addresses written
|
|
|
+ * X on writing X addresses to MTA
|
|
|
+ **/
|
|
|
+static int ixgbe_write_mc_addr_list(struct net_device *netdev)
|
|
|
+{
|
|
|
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
|
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
|
|
+
|
|
|
+ if (!netif_running(netdev))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (hw->mac.ops.update_mc_addr_list)
|
|
|
+ hw->mac.ops.update_mc_addr_list(hw, netdev);
|
|
|
+ else
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+#ifdef CONFIG_PCI_IOV
|
|
|
+ ixgbe_restore_vf_multicasts(adapter);
|
|
|
+#endif
|
|
|
+
|
|
|
+ return netdev_mc_count(netdev);
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef CONFIG_PCI_IOV
|
|
|
+void ixgbe_full_sync_mac_table(struct ixgbe_adapter *adapter)
|
|
|
+{
|
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
|
|
+ int i;
|
|
|
+ for (i = 0; i < hw->mac.num_rar_entries; i++) {
|
|
|
+ if (adapter->mac_table[i].state & IXGBE_MAC_STATE_IN_USE)
|
|
|
+ hw->mac.ops.set_rar(hw, i, adapter->mac_table[i].addr,
|
|
|
+ adapter->mac_table[i].queue,
|
|
|
+ IXGBE_RAH_AV);
|
|
|
+ else
|
|
|
+ hw->mac.ops.clear_rar(hw, i);
|
|
|
+
|
|
|
+ adapter->mac_table[i].state &= ~(IXGBE_MAC_STATE_MODIFIED);
|
|
|
+ }
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+static void ixgbe_sync_mac_table(struct ixgbe_adapter *adapter)
|
|
|
+{
|
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
|
|
+ int i;
|
|
|
+ for (i = 0; i < hw->mac.num_rar_entries; i++) {
|
|
|
+ if (adapter->mac_table[i].state & IXGBE_MAC_STATE_MODIFIED) {
|
|
|
+ if (adapter->mac_table[i].state &
|
|
|
+ IXGBE_MAC_STATE_IN_USE)
|
|
|
+ hw->mac.ops.set_rar(hw, i,
|
|
|
+ adapter->mac_table[i].addr,
|
|
|
+ adapter->mac_table[i].queue,
|
|
|
+ IXGBE_RAH_AV);
|
|
|
+ else
|
|
|
+ hw->mac.ops.clear_rar(hw, i);
|
|
|
+
|
|
|
+ adapter->mac_table[i].state &=
|
|
|
+ ~(IXGBE_MAC_STATE_MODIFIED);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void ixgbe_flush_sw_mac_table(struct ixgbe_adapter *adapter)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
|
|
+
|
|
|
+ for (i = 0; i < hw->mac.num_rar_entries; i++) {
|
|
|
+ adapter->mac_table[i].state |= IXGBE_MAC_STATE_MODIFIED;
|
|
|
+ adapter->mac_table[i].state &= ~IXGBE_MAC_STATE_IN_USE;
|
|
|
+ memset(adapter->mac_table[i].addr, 0, ETH_ALEN);
|
|
|
+ adapter->mac_table[i].queue = 0;
|
|
|
+ }
|
|
|
+ ixgbe_sync_mac_table(adapter);
|
|
|
+}
|
|
|
+
|
|
|
+static int ixgbe_available_rars(struct ixgbe_adapter *adapter)
|
|
|
+{
|
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
|
|
+ int i, count = 0;
|
|
|
+
|
|
|
+ for (i = 0; i < hw->mac.num_rar_entries; i++) {
|
|
|
+ if (adapter->mac_table[i].state == 0)
|
|
|
+ count++;
|
|
|
+ }
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+/* this function destroys the first RAR entry */
|
|
|
+static void ixgbe_mac_set_default_filter(struct ixgbe_adapter *adapter,
|
|
|
+ u8 *addr)
|
|
|
+{
|
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
|
|
+
|
|
|
+ memcpy(&adapter->mac_table[0].addr, addr, ETH_ALEN);
|
|
|
+ adapter->mac_table[0].queue = VMDQ_P(0);
|
|
|
+ adapter->mac_table[0].state = (IXGBE_MAC_STATE_DEFAULT |
|
|
|
+ IXGBE_MAC_STATE_IN_USE);
|
|
|
+ hw->mac.ops.set_rar(hw, 0, adapter->mac_table[0].addr,
|
|
|
+ adapter->mac_table[0].queue,
|
|
|
+ IXGBE_RAH_AV);
|
|
|
+}
|
|
|
+
|
|
|
+int ixgbe_add_mac_filter(struct ixgbe_adapter *adapter, u8 *addr, u16 queue)
|
|
|
+{
|
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (is_zero_ether_addr(addr))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ for (i = 0; i < hw->mac.num_rar_entries; i++) {
|
|
|
+ if (adapter->mac_table[i].state & IXGBE_MAC_STATE_IN_USE)
|
|
|
+ continue;
|
|
|
+ adapter->mac_table[i].state |= (IXGBE_MAC_STATE_MODIFIED |
|
|
|
+ IXGBE_MAC_STATE_IN_USE);
|
|
|
+ ether_addr_copy(adapter->mac_table[i].addr, addr);
|
|
|
+ adapter->mac_table[i].queue = queue;
|
|
|
+ ixgbe_sync_mac_table(adapter);
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+ return -ENOMEM;
|
|
|
+}
|
|
|
+
|
|
|
+int ixgbe_del_mac_filter(struct ixgbe_adapter *adapter, u8 *addr, u16 queue)
|
|
|
+{
|
|
|
+ /* search table for addr, if found, set to 0 and sync */
|
|
|
+ int i;
|
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
|
|
+
|
|
|
+ if (is_zero_ether_addr(addr))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ for (i = 0; i < hw->mac.num_rar_entries; i++) {
|
|
|
+ if (ether_addr_equal(addr, adapter->mac_table[i].addr) &&
|
|
|
+ adapter->mac_table[i].queue == queue) {
|
|
|
+ adapter->mac_table[i].state |= IXGBE_MAC_STATE_MODIFIED;
|
|
|
+ adapter->mac_table[i].state &= ~IXGBE_MAC_STATE_IN_USE;
|
|
|
+ memset(adapter->mac_table[i].addr, 0, ETH_ALEN);
|
|
|
+ adapter->mac_table[i].queue = 0;
|
|
|
+ ixgbe_sync_mac_table(adapter);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -ENOMEM;
|
|
|
+}
|
|
|
/**
|
|
|
* ixgbe_write_uc_addr_list - write unicast addresses to RAR table
|
|
|
* @netdev: network interface device structure
|
|
@@ -3857,39 +4006,23 @@ static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
|
|
|
* 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)
|
|
|
+static int ixgbe_write_uc_addr_list(struct net_device *netdev, int vfn)
|
|
|
{
|
|
|
struct ixgbe_adapter *adapter = netdev_priv(netdev);
|
|
|
- struct ixgbe_hw *hw = &adapter->hw;
|
|
|
- unsigned int rar_entries = hw->mac.num_rar_entries - 1;
|
|
|
int count = 0;
|
|
|
|
|
|
- /* In SR-IOV/VMDQ modes significantly less RAR entries are available */
|
|
|
- if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
|
|
|
- rar_entries = IXGBE_MAX_PF_MACVLANS - 1;
|
|
|
-
|
|
|
/* return ENOMEM indicating insufficient memory for addresses */
|
|
|
- if (netdev_uc_count(netdev) > rar_entries)
|
|
|
+ if (netdev_uc_count(netdev) > ixgbe_available_rars(adapter))
|
|
|
return -ENOMEM;
|
|
|
|
|
|
if (!netdev_uc_empty(netdev)) {
|
|
|
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,
|
|
|
- VMDQ_P(0), IXGBE_RAH_AV);
|
|
|
+ ixgbe_del_mac_filter(adapter, ha->addr, vfn);
|
|
|
+ ixgbe_add_mac_filter(adapter, ha->addr, vfn);
|
|
|
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;
|
|
|
}
|
|
|
|
|
@@ -3907,11 +4040,12 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
|
|
|
struct ixgbe_adapter *adapter = netdev_priv(netdev);
|
|
|
struct ixgbe_hw *hw = &adapter->hw;
|
|
|
u32 fctrl, vmolr = IXGBE_VMOLR_BAM | IXGBE_VMOLR_AUPE;
|
|
|
+ u32 vlnctrl;
|
|
|
int count;
|
|
|
|
|
|
/* Check for Promiscuous and All Multicast modes */
|
|
|
-
|
|
|
fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
|
|
|
+ vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
|
|
|
|
|
|
/* set all bits that we expect to always be set */
|
|
|
fctrl &= ~IXGBE_FCTRL_SBP; /* disable store-bad-packets */
|
|
@@ -3921,26 +4055,24 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
|
|
|
|
|
|
/* clear the bits we are changing the status of */
|
|
|
fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
|
|
|
-
|
|
|
+ vlnctrl &= ~(IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN);
|
|
|
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);
|
|
|
+ vmolr |= IXGBE_VMOLR_MPE;
|
|
|
/* Only disable hardware filter vlans in promiscuous mode
|
|
|
* if SR-IOV and VMDQ are disabled - otherwise ensure
|
|
|
* that hardware VLAN filters remain enabled.
|
|
|
*/
|
|
|
if (!(adapter->flags & (IXGBE_FLAG_VMDQ_ENABLED |
|
|
|
IXGBE_FLAG_SRIOV_ENABLED)))
|
|
|
- ixgbe_vlan_filter_disable(adapter);
|
|
|
- else
|
|
|
- ixgbe_vlan_filter_enable(adapter);
|
|
|
+ vlnctrl |= (IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN);
|
|
|
} else {
|
|
|
if (netdev->flags & IFF_ALLMULTI) {
|
|
|
fctrl |= IXGBE_FCTRL_MPE;
|
|
|
vmolr |= IXGBE_VMOLR_MPE;
|
|
|
}
|
|
|
- ixgbe_vlan_filter_enable(adapter);
|
|
|
+ vlnctrl |= IXGBE_VLNCTRL_VFE;
|
|
|
hw->addr_ctrl.user_set_promisc = false;
|
|
|
}
|
|
|
|
|
@@ -3949,7 +4081,7 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
|
|
|
* sufficient space to store all the addresses then enable
|
|
|
* unicast promiscuous mode
|
|
|
*/
|
|
|
- count = ixgbe_write_uc_addr_list(netdev);
|
|
|
+ count = ixgbe_write_uc_addr_list(netdev, VMDQ_P(0));
|
|
|
if (count < 0) {
|
|
|
fctrl |= IXGBE_FCTRL_UPE;
|
|
|
vmolr |= IXGBE_VMOLR_ROPE;
|
|
@@ -3959,11 +4091,13 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
|
|
|
* then we should just turn on promiscuous mode so
|
|
|
* that we can at least receive multicast traffic
|
|
|
*/
|
|
|
- hw->mac.ops.update_mc_addr_list(hw, netdev);
|
|
|
- vmolr |= IXGBE_VMOLR_ROMPE;
|
|
|
-
|
|
|
- if (adapter->num_vfs)
|
|
|
- ixgbe_restore_vf_multicasts(adapter);
|
|
|
+ count = ixgbe_write_mc_addr_list(netdev);
|
|
|
+ if (count < 0) {
|
|
|
+ fctrl |= IXGBE_FCTRL_MPE;
|
|
|
+ vmolr |= IXGBE_VMOLR_MPE;
|
|
|
+ } else if (count) {
|
|
|
+ vmolr |= IXGBE_VMOLR_ROMPE;
|
|
|
+ }
|
|
|
|
|
|
if (hw->mac.type != ixgbe_mac_82598EB) {
|
|
|
vmolr |= IXGBE_READ_REG(hw, IXGBE_VMOLR(VMDQ_P(0))) &
|
|
@@ -3984,6 +4118,7 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
|
|
|
/* NOTE: VLAN filtering is disabled by setting PROMISC */
|
|
|
}
|
|
|
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
|
|
|
IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
|
|
|
|
|
|
if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
|
|
@@ -4100,8 +4235,8 @@ static int ixgbe_hpbthresh(struct ixgbe_adapter *adapter, int pb)
|
|
|
(tc < IXGBE_FCOE_JUMBO_FRAME_SIZE) &&
|
|
|
(pb == ixgbe_fcoe_get_tc(adapter)))
|
|
|
tc = IXGBE_FCOE_JUMBO_FRAME_SIZE;
|
|
|
-
|
|
|
#endif
|
|
|
+
|
|
|
/* Calculate delay value for device */
|
|
|
switch (hw->mac.type) {
|
|
|
case ixgbe_mac_X540:
|
|
@@ -4142,7 +4277,7 @@ static int ixgbe_hpbthresh(struct ixgbe_adapter *adapter, int pb)
|
|
|
* @adapter: board private structure to calculate for
|
|
|
* @pb: packet buffer to calculate
|
|
|
*/
|
|
|
-static int ixgbe_lpbthresh(struct ixgbe_adapter *adapter)
|
|
|
+static int ixgbe_lpbthresh(struct ixgbe_adapter *adapter, int pb)
|
|
|
{
|
|
|
struct ixgbe_hw *hw = &adapter->hw;
|
|
|
struct net_device *dev = adapter->netdev;
|
|
@@ -4152,6 +4287,14 @@ static int ixgbe_lpbthresh(struct ixgbe_adapter *adapter)
|
|
|
/* Calculate max LAN frame size */
|
|
|
tc = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
|
|
|
|
|
|
+#ifdef IXGBE_FCOE
|
|
|
+ /* FCoE traffic class uses FCOE jumbo frames */
|
|
|
+ if ((dev->features & NETIF_F_FCOE_MTU) &&
|
|
|
+ (tc < IXGBE_FCOE_JUMBO_FRAME_SIZE) &&
|
|
|
+ (pb == netdev_get_prio_tc_map(dev, adapter->fcoe.up)))
|
|
|
+ tc = IXGBE_FCOE_JUMBO_FRAME_SIZE;
|
|
|
+#endif
|
|
|
+
|
|
|
/* Calculate delay value for device */
|
|
|
switch (hw->mac.type) {
|
|
|
case ixgbe_mac_X540:
|
|
@@ -4178,15 +4321,17 @@ static void ixgbe_pbthresh_setup(struct ixgbe_adapter *adapter)
|
|
|
if (!num_tc)
|
|
|
num_tc = 1;
|
|
|
|
|
|
- hw->fc.low_water = ixgbe_lpbthresh(adapter);
|
|
|
-
|
|
|
for (i = 0; i < num_tc; i++) {
|
|
|
hw->fc.high_water[i] = ixgbe_hpbthresh(adapter, i);
|
|
|
+ hw->fc.low_water[i] = ixgbe_lpbthresh(adapter, i);
|
|
|
|
|
|
/* Low water marks must not be larger than high water marks */
|
|
|
- if (hw->fc.low_water > hw->fc.high_water[i])
|
|
|
- hw->fc.low_water = 0;
|
|
|
+ if (hw->fc.low_water[i] > hw->fc.high_water[i])
|
|
|
+ hw->fc.low_water[i] = 0;
|
|
|
}
|
|
|
+
|
|
|
+ for (; i < MAX_TRAFFIC_CLASS; i++)
|
|
|
+ hw->fc.high_water[i] = 0;
|
|
|
}
|
|
|
|
|
|
static void ixgbe_configure_pb(struct ixgbe_adapter *adapter)
|
|
@@ -4248,20 +4393,10 @@ static void ixgbe_macvlan_set_rx_mode(struct net_device *dev, unsigned int pool,
|
|
|
vmolr |= IXGBE_VMOLR_ROMPE;
|
|
|
hw->mac.ops.update_mc_addr_list(hw, dev);
|
|
|
}
|
|
|
- ixgbe_write_uc_addr_list(adapter->netdev);
|
|
|
+ ixgbe_write_uc_addr_list(adapter->netdev, pool);
|
|
|
IXGBE_WRITE_REG(hw, IXGBE_VMOLR(pool), vmolr);
|
|
|
}
|
|
|
|
|
|
-static void ixgbe_add_mac_filter(struct ixgbe_adapter *adapter,
|
|
|
- u8 *addr, u16 pool)
|
|
|
-{
|
|
|
- struct ixgbe_hw *hw = &adapter->hw;
|
|
|
- unsigned int entry;
|
|
|
-
|
|
|
- entry = hw->mac.num_rar_entries - pool;
|
|
|
- hw->mac.ops.set_rar(hw, entry, addr, VMDQ_P(pool), IXGBE_RAH_AV);
|
|
|
-}
|
|
|
-
|
|
|
static void ixgbe_fwd_psrtype(struct ixgbe_fwd_adapter *vadapter)
|
|
|
{
|
|
|
struct ixgbe_adapter *adapter = vadapter->real_adapter;
|
|
@@ -4741,7 +4876,9 @@ void ixgbe_up(struct ixgbe_adapter *adapter)
|
|
|
void ixgbe_reset(struct ixgbe_adapter *adapter)
|
|
|
{
|
|
|
struct ixgbe_hw *hw = &adapter->hw;
|
|
|
+ struct net_device *netdev = adapter->netdev;
|
|
|
int err;
|
|
|
+ u8 old_addr[ETH_ALEN];
|
|
|
|
|
|
if (ixgbe_removed(hw->hw_addr))
|
|
|
return;
|
|
@@ -4777,9 +4914,10 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
|
|
|
}
|
|
|
|
|
|
clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
|
|
|
-
|
|
|
- /* reprogram the RAR[0] in case user changed it. */
|
|
|
- hw->mac.ops.set_rar(hw, 0, hw->mac.addr, VMDQ_P(0), IXGBE_RAH_AV);
|
|
|
+ /* do not flush user set addresses */
|
|
|
+ memcpy(old_addr, &adapter->mac_table[0].addr, netdev->addr_len);
|
|
|
+ ixgbe_flush_sw_mac_table(adapter);
|
|
|
+ ixgbe_mac_set_default_filter(adapter, old_addr);
|
|
|
|
|
|
/* update SAN MAC vmdq pool selection */
|
|
|
if (hw->mac.san_mac_rar_index)
|
|
@@ -5025,6 +5163,10 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter)
|
|
|
#endif /* CONFIG_IXGBE_DCB */
|
|
|
#endif /* IXGBE_FCOE */
|
|
|
|
|
|
+ adapter->mac_table = kzalloc(sizeof(struct ixgbe_mac_addr) *
|
|
|
+ hw->mac.num_rar_entries,
|
|
|
+ GFP_ATOMIC);
|
|
|
+
|
|
|
/* Set MAC specific capability flags and exceptions */
|
|
|
switch (hw->mac.type) {
|
|
|
case ixgbe_mac_82598EB:
|
|
@@ -7171,16 +7313,17 @@ static int ixgbe_set_mac(struct net_device *netdev, void *p)
|
|
|
struct ixgbe_adapter *adapter = netdev_priv(netdev);
|
|
|
struct ixgbe_hw *hw = &adapter->hw;
|
|
|
struct sockaddr *addr = p;
|
|
|
+ int ret;
|
|
|
|
|
|
if (!is_valid_ether_addr(addr->sa_data))
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
|
|
+ ixgbe_del_mac_filter(adapter, hw->mac.addr, VMDQ_P(0));
|
|
|
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
|
|
|
memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len);
|
|
|
|
|
|
- hw->mac.ops.set_rar(hw, 0, hw->mac.addr, VMDQ_P(0), IXGBE_RAH_AV);
|
|
|
-
|
|
|
- return 0;
|
|
|
+ ret = ixgbe_add_mac_filter(adapter, hw->mac.addr, VMDQ_P(0));
|
|
|
+ return ret > 0 ? 0 : ret;
|
|
|
}
|
|
|
|
|
|
static int
|
|
@@ -8186,6 +8329,8 @@ skip_sriov:
|
|
|
goto err_sw_init;
|
|
|
}
|
|
|
|
|
|
+ ixgbe_mac_set_default_filter(adapter, hw->mac.perm_addr);
|
|
|
+
|
|
|
setup_timer(&adapter->service_timer, &ixgbe_service_timer,
|
|
|
(unsigned long) adapter);
|
|
|
|
|
@@ -8318,6 +8463,7 @@ err_sw_init:
|
|
|
ixgbe_disable_sriov(adapter);
|
|
|
adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP;
|
|
|
iounmap(adapter->io_addr);
|
|
|
+ kfree(adapter->mac_table);
|
|
|
err_ioremap:
|
|
|
free_netdev(netdev);
|
|
|
err_alloc_etherdev:
|
|
@@ -8391,6 +8537,7 @@ static void ixgbe_remove(struct pci_dev *pdev)
|
|
|
|
|
|
e_dev_info("complete\n");
|
|
|
|
|
|
+ kfree(adapter->mac_table);
|
|
|
free_netdev(netdev);
|
|
|
|
|
|
pci_disable_pcie_error_reporting(pdev);
|