Commit a72d2b2c authored by Jesse Brandeburg's avatar Jesse Brandeburg Committed by David S. Miller

e1000e: fix loss of multicast packets

e1000e (and e1000, igb, ixgbe, ixgb) all do a series of operations each
time a multicast address is added.  The flow goes something like

1) stack adds one multicast address
2) stack passes whole current list of unicast and multicast addresses to
   driver
3) driver clears entire list in hardware
4) driver programs each multicast address using iomem in a loop

This was causing multicast packets to be lost during the reprogramming
process.

reference with test program:
http://kerneltrap.org/mailarchive/linux-netdev/2009/3/14/5160514/thread

Thanks to Dave Boutcher for his report and test program.

This driver fix prepares an array all at once in memory and programs it in
one shot to the hardware, not requiring an "erase" cycle.  It would still
be possible for packets to be dropped while the receiver is off during
reprogramming.
Signed-off-by: default avatarJesse Brandeburg <jesse.brandeburg@intel.com>
CC: Dave Boutcher <daveboutcher@gmail.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 12d04a3c
...@@ -158,41 +158,6 @@ void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index) ...@@ -158,41 +158,6 @@ void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((index << 1) + 1), rar_high); E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((index << 1) + 1), rar_high);
} }
/**
* e1000_mta_set - Set multicast filter table address
* @hw: pointer to the HW structure
* @hash_value: determines the MTA register and bit to set
*
* The multicast table address is a register array of 32-bit registers.
* The hash_value is used to determine what register the bit is in, the
* current value is read, the new bit is OR'd in and the new value is
* written back into the register.
**/
static void e1000_mta_set(struct e1000_hw *hw, u32 hash_value)
{
u32 hash_bit, hash_reg, mta;
/*
* The MTA is a register array of 32-bit registers. It is
* treated like an array of (32*mta_reg_count) bits. We want to
* set bit BitArray[hash_value]. So we figure out what register
* the bit is in, read it, OR in the new bit, then write
* back the new value. The (hw->mac.mta_reg_count - 1) serves as a
* mask to bits 31:5 of the hash value which gives us the
* register we're modifying. The hash bit within that register
* is determined by the lower 5 bits of the hash value.
*/
hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
hash_bit = hash_value & 0x1F;
mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg);
mta |= (1 << hash_bit);
E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta);
e1e_flush();
}
/** /**
* e1000_hash_mc_addr - Generate a multicast hash value * e1000_hash_mc_addr - Generate a multicast hash value
* @hw: pointer to the HW structure * @hw: pointer to the HW structure
...@@ -281,8 +246,13 @@ void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw, ...@@ -281,8 +246,13 @@ void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
u8 *mc_addr_list, u32 mc_addr_count, u8 *mc_addr_list, u32 mc_addr_count,
u32 rar_used_count, u32 rar_count) u32 rar_used_count, u32 rar_count)
{ {
u32 hash_value;
u32 i; u32 i;
u32 *mcarray = kzalloc(hw->mac.mta_reg_count * sizeof(u32), GFP_ATOMIC);
if (!mcarray) {
printk(KERN_ERR "multicast array memory allocation failed\n");
return;
}
/* /*
* Load the first set of multicast addresses into the exact * Load the first set of multicast addresses into the exact
...@@ -302,20 +272,24 @@ void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw, ...@@ -302,20 +272,24 @@ void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
} }
} }
/* Clear the old settings from the MTA */
hw_dbg(hw, "Clearing MTA\n");
for (i = 0; i < hw->mac.mta_reg_count; i++) {
E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
e1e_flush();
}
/* Load any remaining multicast addresses into the hash table. */ /* Load any remaining multicast addresses into the hash table. */
for (; mc_addr_count > 0; mc_addr_count--) { for (; mc_addr_count > 0; mc_addr_count--) {
u32 hash_value, hash_reg, hash_bit, mta;
hash_value = e1000_hash_mc_addr(hw, mc_addr_list); hash_value = e1000_hash_mc_addr(hw, mc_addr_list);
hw_dbg(hw, "Hash value = 0x%03X\n", hash_value); hw_dbg(hw, "Hash value = 0x%03X\n", hash_value);
e1000_mta_set(hw, hash_value); hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
hash_bit = hash_value & 0x1F;
mta = (1 << hash_bit);
mcarray[hash_reg] |= mta;
mc_addr_list += ETH_ALEN; mc_addr_list += ETH_ALEN;
} }
/* write the hash table completely */
for (i = 0; i < hw->mac.mta_reg_count; i++)
E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, mcarray[i]);
e1e_flush();
kfree(mcarray);
} }
/** /**
......
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