]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/e1000e/ich8lan.c
Merge branch 'x86/unify-cpu-detect' into x86-v28-for-linus-phase4-D
[linux-2.6-omap-h63xx.git] / drivers / net / e1000e / ich8lan.c
index 768485dbb2c6e1ee29e74e122dd295b1495989b0..bcd2bc477af29110636abec9920b3f4a76a244b7 100644 (file)
  * 82566DM Gigabit Network Connection
  * 82566MC Gigabit Network Connection
  * 82566MM Gigabit Network Connection
+ * 82567LM Gigabit Network Connection
+ * 82567LF Gigabit Network Connection
+ * 82567LM-2 Gigabit Network Connection
+ * 82567LF-2 Gigabit Network Connection
+ * 82567V-2 Gigabit Network Connection
+ * 82562GT-3 10/100 Network Connection
  */
 
 #include <linux/netdevice.h>
@@ -52,6 +58,7 @@
 #define ICH_FLASH_HSFCTL               0x0006
 #define ICH_FLASH_FADDR                        0x0008
 #define ICH_FLASH_FDATA0               0x0010
+#define ICH_FLASH_PR0                  0x0074
 
 #define ICH_FLASH_READ_COMMAND_TIMEOUT 500
 #define ICH_FLASH_WRITE_COMMAND_TIMEOUT        500
@@ -144,6 +151,19 @@ union ich8_hws_flash_regacc {
        u16 regval;
 };
 
+/* ICH Flash Protected Region */
+union ich8_flash_protected_range {
+       struct ich8_pr {
+               u32 base:13;     /* 0:12 Protected Range Base */
+               u32 reserved1:2; /* 13:14 Reserved */
+               u32 rpe:1;       /* 15 Read Protection Enable */
+               u32 limit:13;    /* 16:28 Protected Range Limit */
+               u32 reserved2:2; /* 29:30 Reserved */
+               u32 wpe:1;       /* 31 Write Protection Enable */
+       } range;
+       u32 regval;
+};
+
 static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
 static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
 static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
@@ -198,6 +218,19 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
        phy->addr                       = 1;
        phy->reset_delay_us             = 100;
 
+       /*
+        * We may need to do this twice - once for IGP and if that fails,
+        * we'll set BM func pointers and try again
+        */
+       ret_val = e1000e_determine_phy_address(hw);
+       if (ret_val) {
+               hw->phy.ops.write_phy_reg = e1000e_write_phy_reg_bm;
+               hw->phy.ops.read_phy_reg  = e1000e_read_phy_reg_bm;
+               ret_val = e1000e_determine_phy_address(hw);
+               if (ret_val)
+                       return ret_val;
+       }
+
        phy->id = 0;
        while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) &&
               (i++ < 100)) {
@@ -219,6 +252,13 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
                phy->type = e1000_phy_ife;
                phy->autoneg_mask = E1000_ALL_NOT_GIG;
                break;
+       case BME1000_E_PHY_ID:
+               phy->type = e1000_phy_bm;
+               phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+               hw->phy.ops.read_phy_reg = e1000e_read_phy_reg_bm;
+               hw->phy.ops.write_phy_reg = e1000e_write_phy_reg_bm;
+               hw->phy.ops.commit_phy = e1000e_phy_sw_reset;
+               break;
        default:
                return -E1000_ERR_PHY;
                break;
@@ -340,6 +380,9 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
        return 0;
 }
 
+static DEFINE_MUTEX(nvm_mutex);
+static pid_t nvm_owner = -1;
+
 /**
  *  e1000_acquire_swflag_ich8lan - Acquire software control flag
  *  @hw: pointer to the HW structure
@@ -353,6 +396,15 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
        u32 extcnf_ctrl;
        u32 timeout = PHY_CFG_TIMEOUT;
 
+       might_sleep();
+
+       if (!mutex_trylock(&nvm_mutex)) {
+               WARN(1, KERN_ERR "e1000e mutex contention. Owned by pid %d\n",
+                    nvm_owner);
+               mutex_lock(&nvm_mutex);
+       }
+       nvm_owner = current->pid;
+
        while (timeout) {
                extcnf_ctrl = er32(EXTCNF_CTRL);
                extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
@@ -367,6 +419,8 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
 
        if (!timeout) {
                hw_dbg(hw, "FW or HW has locked the resource for too long.\n");
+               nvm_owner = -1;
+               mutex_unlock(&nvm_mutex);
                return -E1000_ERR_CONFIG;
        }
 
@@ -388,6 +442,9 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
        extcnf_ctrl = er32(EXTCNF_CTRL);
        extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
        ew32(EXTCNF_CTRL, extcnf_ctrl);
+
+       nvm_owner = -1;
+       mutex_unlock(&nvm_mutex);
 }
 
 /**
@@ -664,6 +721,7 @@ static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw)
                return e1000_get_phy_info_ife_ich8lan(hw);
                break;
        case e1000_phy_igp_3:
+       case e1000_phy_bm:
                return e1000e_get_phy_info_igp(hw);
                break;
        default:
@@ -728,7 +786,7 @@ static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
        s32 ret_val = 0;
        u16 data;
 
-       if (phy->type != e1000_phy_igp_3)
+       if (phy->type == e1000_phy_ife)
                return ret_val;
 
        phy_ctrl = er32(PHY_CTRL);
@@ -1257,6 +1315,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
         * programming failed.
         */
        if (ret_val) {
+               /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
                hw_dbg(hw, "Flash commit failed.\n");
                e1000_release_swflag_ich8lan(hw);
                return ret_val;
@@ -1346,6 +1405,49 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
        return e1000e_validate_nvm_checksum_generic(hw);
 }
 
+/**
+ *  e1000e_write_protect_nvm_ich8lan - Make the NVM read-only
+ *  @hw: pointer to the HW structure
+ *
+ *  To prevent malicious write/erase of the NVM, set it to be read-only
+ *  so that the hardware ignores all write/erase cycles of the NVM via
+ *  the flash control registers.  The shadow-ram copy of the NVM will
+ *  still be updated, however any updates to this copy will not stick
+ *  across driver reloads.
+ **/
+void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw)
+{
+       union ich8_flash_protected_range pr0;
+       union ich8_hws_flash_status hsfsts;
+       u32 gfpreg;
+       s32 ret_val;
+
+       ret_val = e1000_acquire_swflag_ich8lan(hw);
+       if (ret_val)
+               return;
+
+       gfpreg = er32flash(ICH_FLASH_GFPREG);
+
+       /* Write-protect GbE Sector of NVM */
+       pr0.regval = er32flash(ICH_FLASH_PR0);
+       pr0.range.base = gfpreg & FLASH_GFPREG_BASE_MASK;
+       pr0.range.limit = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK);
+       pr0.range.wpe = true;
+       ew32flash(ICH_FLASH_PR0, pr0.regval);
+
+       /*
+        * Lock down a subset of GbE Flash Control Registers, e.g.
+        * PR0 to prevent the write-protection from being lifted.
+        * Once FLOCKDN is set, the registers protected by it cannot
+        * be written until FLOCKDN is cleared by a hardware reset.
+        */
+       hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+       hsfsts.hsf_status.flockdn = true;
+       ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+
+       e1000_release_swflag_ich8lan(hw);
+}
+
 /**
  *  e1000_write_flash_data_ich8lan - Writes bytes to the NVM
  *  @hw: pointer to the HW structure
@@ -1693,6 +1795,9 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
        ew32(CTRL, (ctrl | E1000_CTRL_RST));
        msleep(20);
 
+       /* release the swflag because it is not reset by hardware reset */
+       e1000_release_swflag_ich8lan(hw);
+
        ret_val = e1000e_get_auto_rd_done(hw);
        if (ret_val) {
                /*
@@ -1918,8 +2023,35 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
                ret_val = e1000e_copper_link_setup_igp(hw);
                if (ret_val)
                        return ret_val;
+       } else if (hw->phy.type == e1000_phy_bm) {
+               ret_val = e1000e_copper_link_setup_m88(hw);
+               if (ret_val)
+                       return ret_val;
        }
 
+       if (hw->phy.type == e1000_phy_ife) {
+               ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &reg_data);
+               if (ret_val)
+                       return ret_val;
+
+               reg_data &= ~IFE_PMC_AUTO_MDIX;
+
+               switch (hw->phy.mdix) {
+               case 1:
+                       reg_data &= ~IFE_PMC_FORCE_MDIX;
+                       break;
+               case 2:
+                       reg_data |= IFE_PMC_FORCE_MDIX;
+                       break;
+               case 0:
+               default:
+                       reg_data |= IFE_PMC_AUTO_MDIX;
+                       break;
+               }
+               ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, reg_data);
+               if (ret_val)
+                       return ret_val;
+       }
        return e1000e_setup_copper_link(hw);
 }
 
@@ -2126,6 +2258,31 @@ void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
                                       reg_data);
 }
 
+/**
+ *  e1000e_disable_gig_wol_ich8lan - disable gig during WoL
+ *  @hw: pointer to the HW structure
+ *
+ *  During S0 to Sx transition, it is possible the link remains at gig
+ *  instead of negotiating to a lower speed.  Before going to Sx, set
+ *  'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
+ *  to a lower speed.
+ *
+ *  Should only be called for ICH9 devices.
+ **/
+void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw)
+{
+       u32 phy_ctrl;
+
+       if (hw->mac.type == e1000_ich9lan) {
+               phy_ctrl = er32(PHY_CTRL);
+               phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
+                           E1000_PHY_CTRL_GBE_DISABLE;
+               ew32(PHY_CTRL, phy_ctrl);
+       }
+
+       return;
+}
+
 /**
  *  e1000_cleanup_led_ich8lan - Restore the default LED operation
  *  @hw: pointer to the HW structure
@@ -2247,6 +2404,7 @@ static struct e1000_nvm_operations ich8_nvm_ops = {
 struct e1000_info e1000_ich8_info = {
        .mac                    = e1000_ich8lan,
        .flags                  = FLAG_HAS_WOL
+                                 | FLAG_IS_ICH
                                  | FLAG_RX_CSUM_ENABLED
                                  | FLAG_HAS_CTRLEXT_ON_LOAD
                                  | FLAG_HAS_AMT
@@ -2262,6 +2420,7 @@ struct e1000_info e1000_ich8_info = {
 struct e1000_info e1000_ich9_info = {
        .mac                    = e1000_ich9lan,
        .flags                  = FLAG_HAS_JUMBO_FRAMES
+                                 | FLAG_IS_ICH
                                  | FLAG_HAS_WOL
                                  | FLAG_RX_CSUM_ENABLED
                                  | FLAG_HAS_CTRLEXT_ON_LOAD