]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/net/e1000e/es2lan.c
e1000e: guard against buffer overflow in cable length tables
[net-next-2.6.git] / drivers / net / e1000e / es2lan.c
index ae5d73689353acf48a1146392f6a1fe50bd06a13..3f435c16608dd3ddcf05f0b589b4a529a4efe1b4 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
+  Copyright(c) 1999 - 2009 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
  * 80003ES2LAN Gigabit Ethernet Controller (Serdes)
  */
 
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-
 #include "e1000.h"
 
 #define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL      0x00
  */
 static const u16 e1000_gg82563_cable_length_table[] =
         { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF };
+#define GG82563_CABLE_LENGTH_TABLE_SIZE \
+               ARRAY_SIZE(e1000_gg82563_cable_length_table)
 
 static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw);
 static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
@@ -121,8 +118,6 @@ static s32  e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
 /**
  *  e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs.
  *  @hw: pointer to the HW structure
- *
- *  This is a function pointer entry point called by the api module.
  **/
 static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw)
 {
@@ -152,8 +147,6 @@ static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw)
 /**
  *  e1000_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs.
  *  @hw: pointer to the HW structure
- *
- *  This is a function pointer entry point called by the api module.
  **/
 static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw)
 {
@@ -200,8 +193,6 @@ static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw)
 /**
  *  e1000_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs.
  *  @hw: pointer to the HW structure
- *
- *  This is a function pointer entry point called by the api module.
  **/
 static s32 e1000_init_mac_params_80003es2lan(struct e1000_adapter *adapter)
 {
@@ -224,7 +215,8 @@ static s32 e1000_init_mac_params_80003es2lan(struct e1000_adapter *adapter)
        /* Set rar entry count */
        mac->rar_entry_count = E1000_RAR_ENTRIES;
        /* Set if manageability features are enabled. */
-       mac->arc_subsystem_valid = (er32(FWSM) & E1000_FWSM_MODE_MASK) ? 1 : 0;
+       mac->arc_subsystem_valid = (er32(FWSM) & E1000_FWSM_MODE_MASK)
+                        ? true : false;
 
        /* check for link */
        switch (hw->phy.media_type) {
@@ -272,8 +264,7 @@ static s32 e1000_get_variants_80003es2lan(struct e1000_adapter *adapter)
  *  e1000_acquire_phy_80003es2lan - Acquire rights to access PHY
  *  @hw: pointer to the HW structure
  *
- *  A wrapper to acquire access rights to the correct PHY.  This is a
- *  function pointer entry point called by the api module.
+ *  A wrapper to acquire access rights to the correct PHY.
  **/
 static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw)
 {
@@ -287,8 +278,7 @@ static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw)
  *  e1000_release_phy_80003es2lan - Release rights to access PHY
  *  @hw: pointer to the HW structure
  *
- *  A wrapper to release access rights to the correct PHY.  This is a
- *  function pointer entry point called by the api module.
+ *  A wrapper to release access rights to the correct PHY.
  **/
 static void e1000_release_phy_80003es2lan(struct e1000_hw *hw)
 {
@@ -333,8 +323,7 @@ static void e1000_release_mac_csr_80003es2lan(struct e1000_hw *hw)
  *  e1000_acquire_nvm_80003es2lan - Acquire rights to access NVM
  *  @hw: pointer to the HW structure
  *
- *  Acquire the semaphore to access the EEPROM.  This is a function
- *  pointer entry point called by the api module.
+ *  Acquire the semaphore to access the EEPROM.
  **/
 static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw)
 {
@@ -356,8 +345,7 @@ static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw)
  *  e1000_release_nvm_80003es2lan - Relinquish rights to access NVM
  *  @hw: pointer to the HW structure
  *
- *  Release the semaphore used to access the EEPROM.  This is a
- *  function pointer entry point called by the api module.
+ *  Release the semaphore used to access the EEPROM.
  **/
 static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw)
 {
@@ -399,8 +387,7 @@ static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
        }
 
        if (i == timeout) {
-               hw_dbg(hw,
-                      "Driver can't access resource, SW_FW_SYNC timeout.\n");
+               e_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n");
                return -E1000_ERR_SWFW_SYNC;
        }
 
@@ -440,8 +427,7 @@ static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
  *  @offset: offset of the register to read
  *  @data: pointer to the data returned from the operation
  *
- *  Read the GG82563 PHY register.  This is a function pointer entry
- *  point called by the api module.
+ *  Read the GG82563 PHY register.
  **/
 static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
                                                  u32 offset, u16 *data)
@@ -505,8 +491,7 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
  *  @offset: offset of the register to read
  *  @data: value to write to the register
  *
- *  Write to the GG82563 PHY register.  This is a function pointer entry
- *  point called by the api module.
+ *  Write to the GG82563 PHY register.
  **/
 static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
                                                   u32 offset, u16 data)
@@ -571,8 +556,7 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
  *  @words: number of words to write
  *  @data: buffer of data to write to the NVM
  *
- *  Write "words" of data to the ESB2 NVM.  This is a function
- *  pointer entry point called by the api module.
+ *  Write "words" of data to the ESB2 NVM.
  **/
 static s32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset,
                                       u16 words, u16 *data)
@@ -602,7 +586,7 @@ static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw)
                timeout--;
        }
        if (!timeout) {
-               hw_dbg(hw, "MNG configuration cycle has not completed.\n");
+               e_dbg("MNG configuration cycle has not completed.\n");
                return -E1000_ERR_RESET;
        }
 
@@ -635,7 +619,7 @@ static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
        if (ret_val)
                return ret_val;
 
-       hw_dbg(hw, "GG82563 PSCR: %X\n", phy_data);
+       e_dbg("GG82563 PSCR: %X\n", phy_data);
 
        ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
        if (ret_val)
@@ -653,7 +637,7 @@ static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
        udelay(1);
 
        if (hw->phy.autoneg_wait_to_complete) {
-               hw_dbg(hw, "Waiting for forced speed/duplex link "
+               e_dbg("Waiting for forced speed/duplex link "
                         "on GG82563 phy.\n");
 
                ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
@@ -712,21 +696,27 @@ static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
 static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw)
 {
        struct e1000_phy_info *phy = &hw->phy;
-       s32 ret_val;
-       u16 phy_data;
-       u16 index;
+       s32 ret_val = 0;
+       u16 phy_data, index;
 
        ret_val = e1e_rphy(hw, GG82563_PHY_DSP_DISTANCE, &phy_data);
        if (ret_val)
-               return ret_val;
+               goto out;
 
        index = phy_data & GG82563_DSPD_CABLE_LENGTH;
+
+       if (index >= GG82563_CABLE_LENGTH_TABLE_SIZE - 5) {
+               ret_val = -E1000_ERR_PHY;
+               goto out;
+       }
+
        phy->min_cable_length = e1000_gg82563_cable_length_table[index];
-       phy->max_cable_length = e1000_gg82563_cable_length_table[index+5];
+       phy->max_cable_length = e1000_gg82563_cable_length_table[index + 5];
 
        phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
 
-       return 0;
+out:
+       return ret_val;
 }
 
 /**
@@ -736,7 +726,6 @@ static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw)
  *  @duplex: pointer to duplex buffer
  *
  *  Retrieve the current speed and duplex configuration.
- *  This is a function pointer entry point called by the api module.
  **/
 static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed,
                                              u16 *duplex)
@@ -762,12 +751,10 @@ static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed,
  *  @hw: pointer to the HW structure
  *
  *  Perform a global reset to the ESB2 controller.
- *  This is a function pointer entry point called by the api module.
  **/
 static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
 {
-       u32 ctrl;
-       u32 icr;
+       u32 ctrl, icr;
        s32 ret_val;
 
        /*
@@ -776,9 +763,9 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
         */
        ret_val = e1000e_disable_pcie_master(hw);
        if (ret_val)
-               hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+               e_dbg("PCI-E Master disable polling has failed.\n");
 
-       hw_dbg(hw, "Masking off all interrupts\n");
+       e_dbg("Masking off all interrupts\n");
        ew32(IMC, 0xffffffff);
 
        ew32(RCTL, 0);
@@ -790,7 +777,7 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
        ctrl = er32(CTRL);
 
        ret_val = e1000_acquire_phy_80003es2lan(hw);
-       hw_dbg(hw, "Issuing a global reset to MAC\n");
+       e_dbg("Issuing a global reset to MAC\n");
        ew32(CTRL, ctrl | E1000_CTRL_RST);
        e1000_release_phy_80003es2lan(hw);
 
@@ -811,7 +798,6 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
  *  @hw: pointer to the HW structure
  *
  *  Initialize the hw bits, LED, VFTA, MTA, link and hw counters.
- *  This is a function pointer entry point called by the api module.
  **/
 static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
 {
@@ -824,20 +810,19 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
 
        /* Initialize identification LED */
        ret_val = e1000e_id_led_init(hw);
-       if (ret_val) {
-               hw_dbg(hw, "Error initializing identification LED\n");
-               return ret_val;
-       }
+       if (ret_val)
+               e_dbg("Error initializing identification LED\n");
+               /* This is not fatal and we should not stop init due to this */
 
        /* Disabling VLAN filtering */
-       hw_dbg(hw, "Initializing the IEEE VLAN\n");
-       e1000e_clear_vfta(hw);
+       e_dbg("Initializing the IEEE VLAN\n");
+       mac->ops.clear_vfta(hw);
 
        /* Setup the receive address. */
        e1000e_init_rx_addrs(hw, mac->rar_entry_count);
 
        /* Zero out the Multicast HASH table */
-       hw_dbg(hw, "Zeroing the MTA\n");
+       e_dbg("Zeroing the MTA\n");
        for (i = 0; i < mac->mta_reg_count; i++)
                E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
 
@@ -994,7 +979,7 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
        /* SW Reset the PHY so all changes take effect */
        ret_val = e1000e_commit_phy(hw);
        if (ret_val) {
-               hw_dbg(hw, "Error Resetting the PHY\n");
+               e_dbg("Error Resetting the PHY\n");
                return ret_val;
        }
 
@@ -1325,44 +1310,42 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
  **/
 static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
 {
-       u32 temp;
-
        e1000e_clear_hw_cntrs_base(hw);
 
-       temp = er32(PRC64);
-       temp = er32(PRC127);
-       temp = er32(PRC255);
-       temp = er32(PRC511);
-       temp = er32(PRC1023);
-       temp = er32(PRC1522);
-       temp = er32(PTC64);
-       temp = er32(PTC127);
-       temp = er32(PTC255);
-       temp = er32(PTC511);
-       temp = er32(PTC1023);
-       temp = er32(PTC1522);
-
-       temp = er32(ALGNERRC);
-       temp = er32(RXERRC);
-       temp = er32(TNCRS);
-       temp = er32(CEXTERR);
-       temp = er32(TSCTC);
-       temp = er32(TSCTFC);
-
-       temp = er32(MGTPRC);
-       temp = er32(MGTPDC);
-       temp = er32(MGTPTC);
-
-       temp = er32(IAC);
-       temp = er32(ICRXOC);
-
-       temp = er32(ICRXPTC);
-       temp = er32(ICRXATC);
-       temp = er32(ICTXPTC);
-       temp = er32(ICTXATC);
-       temp = er32(ICTXQEC);
-       temp = er32(ICTXQMTC);
-       temp = er32(ICRXDMTC);
+       er32(PRC64);
+       er32(PRC127);
+       er32(PRC255);
+       er32(PRC511);
+       er32(PRC1023);
+       er32(PRC1522);
+       er32(PTC64);
+       er32(PTC127);
+       er32(PTC255);
+       er32(PTC511);
+       er32(PTC1023);
+       er32(PTC1522);
+
+       er32(ALGNERRC);
+       er32(RXERRC);
+       er32(TNCRS);
+       er32(CEXTERR);
+       er32(TSCTC);
+       er32(TSCTFC);
+
+       er32(MGTPRC);
+       er32(MGTPDC);
+       er32(MGTPTC);
+
+       er32(IAC);
+       er32(ICRXOC);
+
+       er32(ICRXPTC);
+       er32(ICRXATC);
+       er32(ICTXPTC);
+       er32(ICTXATC);
+       er32(ICTXQEC);
+       er32(ICTXQMTC);
+       er32(ICRXDMTC);
 }
 
 static struct e1000_mac_operations es2_mac_ops = {
@@ -1376,6 +1359,8 @@ static struct e1000_mac_operations es2_mac_ops = {
        .led_on                 = e1000e_led_on_generic,
        .led_off                = e1000e_led_off_generic,
        .update_mc_addr_list    = e1000e_update_mc_addr_list_generic,
+       .write_vfta             = e1000_write_vfta_generic,
+       .clear_vfta             = e1000_clear_vfta_generic,
        .reset_hw               = e1000_reset_hw_80003es2lan,
        .init_hw                = e1000_init_hw_80003es2lan,
        .setup_link             = e1000e_setup_link,
@@ -1384,30 +1369,30 @@ static struct e1000_mac_operations es2_mac_ops = {
 };
 
 static struct e1000_phy_operations es2_phy_ops = {
-       .acquire_phy            = e1000_acquire_phy_80003es2lan,
+       .acquire                = e1000_acquire_phy_80003es2lan,
        .check_reset_block      = e1000e_check_reset_block_generic,
-       .commit_phy             = e1000e_phy_sw_reset,
+       .commit                 = e1000e_phy_sw_reset,
        .force_speed_duplex     = e1000_phy_force_speed_duplex_80003es2lan,
        .get_cfg_done           = e1000_get_cfg_done_80003es2lan,
        .get_cable_length       = e1000_get_cable_length_80003es2lan,
-       .get_phy_info           = e1000e_get_phy_info_m88,
-       .read_phy_reg           = e1000_read_phy_reg_gg82563_80003es2lan,
-       .release_phy            = e1000_release_phy_80003es2lan,
-       .reset_phy              = e1000e_phy_hw_reset_generic,
+       .get_info               = e1000e_get_phy_info_m88,
+       .read_reg               = e1000_read_phy_reg_gg82563_80003es2lan,
+       .release                = e1000_release_phy_80003es2lan,
+       .reset                  = e1000e_phy_hw_reset_generic,
        .set_d0_lplu_state      = NULL,
        .set_d3_lplu_state      = e1000e_set_d3_lplu_state,
-       .write_phy_reg          = e1000_write_phy_reg_gg82563_80003es2lan,
+       .write_reg              = e1000_write_phy_reg_gg82563_80003es2lan,
        .cfg_on_link_up         = e1000_cfg_on_link_up_80003es2lan,
 };
 
 static struct e1000_nvm_operations es2_nvm_ops = {
-       .acquire_nvm            = e1000_acquire_nvm_80003es2lan,
-       .read_nvm               = e1000e_read_nvm_eerd,
-       .release_nvm            = e1000_release_nvm_80003es2lan,
-       .update_nvm             = e1000e_update_nvm_checksum_generic,
+       .acquire                = e1000_acquire_nvm_80003es2lan,
+       .read                   = e1000e_read_nvm_eerd,
+       .release                = e1000_release_nvm_80003es2lan,
+       .update                 = e1000e_update_nvm_checksum_generic,
        .valid_led_default      = e1000e_valid_led_default,
-       .validate_nvm           = e1000e_validate_nvm_checksum_generic,
-       .write_nvm              = e1000_write_nvm_80003es2lan,
+       .validate               = e1000e_validate_nvm_checksum_generic,
+       .write                  = e1000_write_nvm_80003es2lan,
 };
 
 struct e1000_info e1000_es2_info = {