e1000e: fix loss of multicast packets
[safe/jmp/linux-2.6] / drivers / net / e1000e / lib.c
index ac2f34e..18a4f59 100644 (file)
@@ -159,41 +159,6 @@ void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
 }
 
 /**
- *  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
  *  @hw: pointer to the HW structure
  *  @mc_addr: pointer to a multicast address
@@ -281,8 +246,13 @@ void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
                                        u8 *mc_addr_list, u32 mc_addr_count,
                                        u32 rar_used_count, u32 rar_count)
 {
-       u32 hash_value;
        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
@@ -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. */
        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);
                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;
        }
+
+       /* 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);
 }
 
 /**