e1000e: use alternate MAC address on ESB2 if available
authorBruce Allan <bruce.w.allan@intel.com>
Wed, 13 Jan 2010 02:04:58 +0000 (02:04 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 14 Jan 2010 04:31:56 +0000 (20:31 -0800)
Similar to 82571/2/3 parts that already do this, if ESB2/80003es2lan parts
have an alternate MAC address provided in the EEPROM use it instead of the
default MAC address.  This patch makes the the actual code that does this
generic so that it can be better used by both MAC families.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/e1000e/82571.c
drivers/net/e1000e/defines.h
drivers/net/e1000e/e1000.h
drivers/net/e1000e/es2lan.c
drivers/net/e1000e/hw.h
drivers/net/e1000e/lib.c
drivers/net/e1000e/netdev.c

index 02d67d047d963854c1c5d8210d14c46d4bbcdf0d..d1a45143c2aa933f813a104a36134e96be87b604 100644 (file)
@@ -922,9 +922,12 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
        ew32(IMC, 0xffffffff);
        icr = er32(ICR);
 
-       if (hw->mac.type == e1000_82571 &&
-               hw->dev_spec.e82571.alt_mac_addr_is_present)
-                       e1000e_set_laa_state_82571(hw, true);
+       /* Install any alternate MAC address into RAR0 */
+       ret_val = e1000_check_alt_mac_addr_generic(hw);
+       if (ret_val)
+               return ret_val;
+
+       e1000e_set_laa_state_82571(hw, true);
 
        /* Reinitialize the 82571 serdes link state machine */
        if (hw->phy.media_type == e1000_media_type_internal_serdes)
@@ -1620,6 +1623,29 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
        return 0;
 }
 
+/**
+ *  e1000_read_mac_addr_82571 - Read device MAC address
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+
+       /*
+        * If there's an alternate MAC address place it in RAR0
+        * so that it will override the Si installed default perm
+        * address.
+        */
+       ret_val = e1000_check_alt_mac_addr_generic(hw);
+       if (ret_val)
+               goto out;
+
+       ret_val = e1000_read_mac_addr_generic(hw);
+
+out:
+       return ret_val;
+}
+
 /**
  * e1000_power_down_phy_copper_82571 - Remove link during PHY power down
  * @hw: pointer to the HW structure
@@ -1706,6 +1732,7 @@ static struct e1000_mac_operations e82571_mac_ops = {
        .setup_link             = e1000_setup_link_82571,
        /* .setup_physical_interface: media type dependent */
        .setup_led              = e1000e_setup_led_generic,
+       .read_mac_addr          = e1000_read_mac_addr_82571,
 };
 
 static struct e1000_phy_operations e82_phy_ops_igp = {
index e02e38221ed47c9ab428a7aec033c16ac97e2584..db05ec35574931538e136e40db65988a43df45b4 100644 (file)
  */
 #define E1000_RAR_ENTRIES     15
 #define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+#define E1000_RAL_MAC_ADDR_LEN 4
+#define E1000_RAH_MAC_ADDR_LEN 2
 
 /* Error Codes */
 #define E1000_ERR_NVM      1
index cebbd9079d5382ac736d02db5dc1184c4a40b447..7c91e4bdd36108dd5ba1e586a8231f35b588f7e5 100644 (file)
@@ -529,6 +529,7 @@ extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw);
 extern s32 e1000e_force_mac_fc(struct e1000_hw *hw);
 extern s32 e1000e_blink_led(struct e1000_hw *hw);
 extern void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
+extern s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw);
 extern void e1000e_reset_adaptive(struct e1000_hw *hw);
 extern void e1000e_update_adaptive(struct e1000_hw *hw);
 
@@ -629,7 +630,15 @@ extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16
 extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
 extern void e1000e_release_nvm(struct e1000_hw *hw);
 extern void e1000e_reload_nvm(struct e1000_hw *hw);
-extern s32 e1000e_read_mac_addr(struct e1000_hw *hw);
+extern s32 e1000_read_mac_addr_generic(struct e1000_hw *hw);
+
+static inline s32 e1000e_read_mac_addr(struct e1000_hw *hw)
+{
+       if (hw->mac.ops.read_mac_addr)
+               return hw->mac.ops.read_mac_addr(hw);
+
+       return e1000_read_mac_addr_generic(hw);
+}
 
 static inline s32 e1000_validate_nvm_checksum(struct e1000_hw *hw)
 {
index e2aa3b7885642375f49ff88c5977647f7f72f399..4bb9d88ad97697502617d6eff9b47db65fdab462 100644 (file)
@@ -814,7 +814,9 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
        ew32(IMC, 0xffffffff);
        icr = er32(ICR);
 
-       return 0;
+       ret_val = e1000_check_alt_mac_addr_generic(hw);
+
+       return ret_val;
 }
 
 /**
@@ -1339,6 +1341,29 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
        return ret_val;
 }
 
+/**
+ *  e1000_read_mac_addr_80003es2lan - Read device MAC address
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+
+       /*
+        * If there's an alternate MAC address place it in RAR0
+        * so that it will override the Si installed default perm
+        * address.
+        */
+       ret_val = e1000_check_alt_mac_addr_generic(hw);
+       if (ret_val)
+               goto out;
+
+       ret_val = e1000_read_mac_addr_generic(hw);
+
+out:
+       return ret_val;
+}
+
 /**
  * e1000_power_down_phy_copper_80003es2lan - Remove link during PHY power down
  * @hw: pointer to the HW structure
@@ -1403,6 +1428,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
 }
 
 static struct e1000_mac_operations es2_mac_ops = {
+       .read_mac_addr          = e1000_read_mac_addr_80003es2lan,
        .id_led_init            = e1000e_id_led_init,
        .check_mng_mode         = e1000e_check_mng_mode_generic,
        /* check_for_link dependent on media type */
index eccf29b75c41ed062551249f6552cdfc373a3d85..127e6a226da19a816bded699f0b33dd939b9dbc9 100644 (file)
@@ -389,6 +389,9 @@ enum e1e_registers {
 
 #define E1000_FUNC_1 1
 
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0   0
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1   3
+
 enum e1000_mac_type {
        e1000_82571,
        e1000_82572,
@@ -756,6 +759,7 @@ struct e1000_mac_operations {
        s32  (*setup_physical_interface)(struct e1000_hw *);
        s32  (*setup_led)(struct e1000_hw *);
        void (*write_vfta)(struct e1000_hw *, u32, u32);
+       s32  (*read_mac_addr)(struct e1000_hw *);
 };
 
 /* Function pointers for the PHY. */
@@ -897,7 +901,6 @@ struct e1000_fc_info {
 
 struct e1000_dev_spec_82571 {
        bool laa_is_present;
-       bool alt_mac_addr_is_present;
        u32 smb_counter;
 };
 
index 2fa9b36a2c5ae3d289e7923751bd7b396076a103..547542428edccb7eacaab031045b204821706086 100644 (file)
@@ -138,6 +138,68 @@ void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
                e1000e_rar_set(hw, mac_addr, i);
 }
 
+/**
+ *  e1000_check_alt_mac_addr_generic - Check for alternate MAC addr
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the nvm for an alternate MAC address.  An alternate MAC address
+ *  can be setup by pre-boot software and must be treated like a permanent
+ *  address and must override the actual permanent MAC address. If an
+ *  alternate MAC address is found it is programmed into RAR0, replacing
+ *  the permanent address that was installed into RAR0 by the Si on reset.
+ *  This function will return SUCCESS unless it encounters an error while
+ *  reading the EEPROM.
+ **/
+s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
+{
+       u32 i;
+       s32 ret_val = 0;
+       u16 offset, nvm_alt_mac_addr_offset, nvm_data;
+       u8 alt_mac_addr[ETH_ALEN];
+
+       ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1,
+                                &nvm_alt_mac_addr_offset);
+       if (ret_val) {
+               e_dbg("NVM Read Error\n");
+               goto out;
+       }
+
+       if (nvm_alt_mac_addr_offset == 0xFFFF) {
+               /* There is no Alternate MAC Address */
+               goto out;
+       }
+
+       if (hw->bus.func == E1000_FUNC_1)
+               nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
+       for (i = 0; i < ETH_ALEN; i += 2) {
+               offset = nvm_alt_mac_addr_offset + (i >> 1);
+               ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data);
+               if (ret_val) {
+                       e_dbg("NVM Read Error\n");
+                       goto out;
+               }
+
+               alt_mac_addr[i] = (u8)(nvm_data & 0xFF);
+               alt_mac_addr[i + 1] = (u8)(nvm_data >> 8);
+       }
+
+       /* if multicast bit is set, the alternate address will not be used */
+       if (alt_mac_addr[0] & 0x01) {
+               e_dbg("Ignoring Alternate Mac Address with MC bit set\n");
+               goto out;
+       }
+
+       /*
+        * We have a valid alternate MAC address, and we want to treat it the
+        * same as the normal permanent MAC address stored by the HW into the
+        * RAR. Do this by mapping this address into RAR0.
+        */
+       e1000e_rar_set(hw, alt_mac_addr, 0);
+
+out:
+       return ret_val;
+}
+
 /**
  *  e1000e_rar_set - Set receive address register
  *  @hw: pointer to the HW structure
@@ -2072,67 +2134,27 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
 }
 
 /**
- *  e1000e_read_mac_addr - Read device MAC address
+ *  e1000_read_mac_addr_generic - Read device MAC address
  *  @hw: pointer to the HW structure
  *
  *  Reads the device MAC address from the EEPROM and stores the value.
  *  Since devices with two ports use the same EEPROM, we increment the
  *  last bit in the MAC address for the second port.
  **/
-s32 e1000e_read_mac_addr(struct e1000_hw *hw)
+s32 e1000_read_mac_addr_generic(struct e1000_hw *hw)
 {
-       s32 ret_val;
-       u16 offset, nvm_data, i;
-       u16 mac_addr_offset = 0;
-
-       if (hw->mac.type == e1000_82571) {
-               /* Check for an alternate MAC address.  An alternate MAC
-                * address can be setup by pre-boot software and must be
-                * treated like a permanent address and must override the
-                * actual permanent MAC address.*/
-               ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1,
-                                        &mac_addr_offset);
-               if (ret_val) {
-                       e_dbg("NVM Read Error\n");
-                       return ret_val;
-               }
-               if (mac_addr_offset == 0xFFFF)
-                       mac_addr_offset = 0;
-
-               if (mac_addr_offset) {
-                       if (hw->bus.func == E1000_FUNC_1)
-                               mac_addr_offset += ETH_ALEN/sizeof(u16);
-
-                       /* make sure we have a valid mac address here
-                       * before using it */
-                       ret_val = e1000_read_nvm(hw, mac_addr_offset, 1,
-                                                &nvm_data);
-                       if (ret_val) {
-                               e_dbg("NVM Read Error\n");
-                               return ret_val;
-                       }
-                       if (nvm_data & 0x0001)
-                               mac_addr_offset = 0;
-               }
+       u32 rar_high;
+       u32 rar_low;
+       u16 i;
 
-               if (mac_addr_offset)
-               hw->dev_spec.e82571.alt_mac_addr_is_present = 1;
-       }
+       rar_high = er32(RAH(0));
+       rar_low = er32(RAL(0));
 
-       for (i = 0; i < ETH_ALEN; i += 2) {
-               offset = mac_addr_offset + (i >> 1);
-               ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data);
-               if (ret_val) {
-                       e_dbg("NVM Read Error\n");
-                       return ret_val;
-               }
-               hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
-               hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
-       }
+       for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
+               hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8));
 
-       /* Flip last bit of mac address if we're on second port */
-       if (!mac_addr_offset && hw->bus.func == E1000_FUNC_1)
-               hw->mac.perm_addr[5] ^= 1;
+       for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
+               hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8));
 
        for (i = 0; i < ETH_ALEN; i++)
                hw->mac.addr[i] = hw->mac.perm_addr[i];
index c3745c9d21aaebcd61276750abe3892a6222cc43..0d5ef4c5c6dbd119d4ad7a01f4c8a1c8e77cbd33 100644 (file)
@@ -5135,7 +5135,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 
        e1000_eeprom_checks(adapter);
 
-       /* copy the MAC address out of the NVM */
+       /* copy the MAC address */
        if (e1000e_read_mac_addr(&adapter->hw))
                e_err("NVM Read Error while reading MAC address\n");