e1000e: 82574 intermittently fails to initialize with manageability f/w
authorBruce Allan <bruce.w.allan@intel.com>
Wed, 17 Nov 2010 03:50:14 +0000 (19:50 -0800)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Wed, 17 Nov 2010 03:50:14 +0000 (19:50 -0800)
The driver can fail initializing the hardware when manageability firmware
is performing concurrent MDIO operations because the hardware semaphore
scheme to prevent concurrent operations between software and firmware is
incorrect for 82574/82583.  Instead of using the SWSM register, the driver
should be using the EXTCNF_CTRL register.  A software mutex is also added
to prevent simultaneous software threads from performing similar concurrent
accesses.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Emil Tantilov <emil.s.tantilov@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/e1000e/82571.c

index 235856375ff3f825acefb11b3a56ad208b2132d8..9333921010cc23c7eff6d4a54ee30cbc3dc3fdbf 100644 (file)
@@ -74,6 +74,9 @@ static bool e1000_check_mng_mode_82574(struct e1000_hw *hw);
 static s32 e1000_led_on_82574(struct e1000_hw *hw);
 static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw);
 static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw);
+static s32 e1000_get_hw_semaphore_82574(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_82574(struct e1000_hw *hw);
 
 /**
  *  e1000_init_phy_params_82571 - Init PHY func ptrs.
@@ -107,6 +110,8 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
        case e1000_82574:
        case e1000_82583:
                phy->type                = e1000_phy_bm;
+               phy->ops.acquire = e1000_get_hw_semaphore_82574;
+               phy->ops.release = e1000_put_hw_semaphore_82574;
                break;
        default:
                return -E1000_ERR_PHY;
@@ -200,6 +205,17 @@ static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
                break;
        }
 
+       /* Function Pointers */
+       switch (hw->mac.type) {
+       case e1000_82574:
+       case e1000_82583:
+               nvm->ops.acquire = e1000_get_hw_semaphore_82574;
+               nvm->ops.release = e1000_put_hw_semaphore_82574;
+               break;
+       default:
+               break;
+       }
+
        return 0;
 }
 
@@ -542,6 +558,94 @@ static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw)
        swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
        ew32(SWSM, swsm);
 }
+/**
+ *  e1000_get_hw_semaphore_82573 - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the HW semaphore during reset.
+ *
+ **/
+static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw)
+{
+       u32 extcnf_ctrl;
+       s32 ret_val = 0;
+       s32 i = 0;
+
+       extcnf_ctrl = er32(EXTCNF_CTRL);
+       extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+       do {
+               ew32(EXTCNF_CTRL, extcnf_ctrl);
+               extcnf_ctrl = er32(EXTCNF_CTRL);
+
+               if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+                       break;
+
+               extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+               msleep(2);
+               i++;
+       } while (i < MDIO_OWNERSHIP_TIMEOUT);
+
+       if (i == MDIO_OWNERSHIP_TIMEOUT) {
+               /* Release semaphores */
+               e1000_put_hw_semaphore_82573(hw);
+               e_dbg("Driver can't access the PHY\n");
+               ret_val = -E1000_ERR_PHY;
+               goto out;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_put_hw_semaphore_82573 - Release hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Release hardware semaphore used during reset.
+ *
+ **/
+static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw)
+{
+       u32 extcnf_ctrl;
+
+       extcnf_ctrl = er32(EXTCNF_CTRL);
+       extcnf_ctrl &= ~E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+       ew32(EXTCNF_CTRL, extcnf_ctrl);
+}
+
+static DEFINE_MUTEX(swflag_mutex);
+
+/**
+ *  e1000_get_hw_semaphore_82574 - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the HW semaphore to access the PHY or NVM.
+ *
+ **/
+static s32 e1000_get_hw_semaphore_82574(struct e1000_hw *hw)
+{
+       s32 ret_val;
+
+       mutex_lock(&swflag_mutex);
+       ret_val = e1000_get_hw_semaphore_82573(hw);
+       if (ret_val)
+               mutex_unlock(&swflag_mutex);
+       return ret_val;
+}
+
+/**
+ *  e1000_put_hw_semaphore_82574 - Release hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Release hardware semaphore used to access the PHY or NVM
+ *
+ **/
+static void e1000_put_hw_semaphore_82574(struct e1000_hw *hw)
+{
+       e1000_put_hw_semaphore_82573(hw);
+       mutex_unlock(&swflag_mutex);
+}
 
 /**
  *  e1000_acquire_nvm_82571 - Request for access to the EEPROM
@@ -562,8 +666,6 @@ static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
 
        switch (hw->mac.type) {
        case e1000_82573:
-       case e1000_82574:
-       case e1000_82583:
                break;
        default:
                ret_val = e1000e_acquire_nvm(hw);
@@ -853,9 +955,8 @@ static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active)
  **/
 static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
 {
-       u32 ctrl, extcnf_ctrl, ctrl_ext, icr;
+       u32 ctrl, ctrl_ext, icr;
        s32 ret_val;
-       u16 i = 0;
 
        /*
         * Prevent the PCI-E bus from sticking if there is no TLP connection
@@ -880,33 +981,33 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
         */
        switch (hw->mac.type) {
        case e1000_82573:
+               ret_val = e1000_get_hw_semaphore_82573(hw);
+               break;
        case e1000_82574:
        case e1000_82583:
-               extcnf_ctrl = er32(EXTCNF_CTRL);
-               extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
-
-               do {
-                       ew32(EXTCNF_CTRL, extcnf_ctrl);
-                       extcnf_ctrl = er32(EXTCNF_CTRL);
-
-                       if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
-                               break;
-
-                       extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
-
-                       msleep(2);
-                       i++;
-               } while (i < MDIO_OWNERSHIP_TIMEOUT);
+               ret_val = e1000_get_hw_semaphore_82574(hw);
                break;
        default:
                break;
        }
+       if (ret_val)
+               e_dbg("Cannot acquire MDIO ownership\n");
 
        ctrl = er32(CTRL);
 
        e_dbg("Issuing a global reset to MAC\n");
        ew32(CTRL, ctrl | E1000_CTRL_RST);
 
+       /* Must release MDIO ownership and mutex after MAC reset. */
+       switch (hw->mac.type) {
+       case e1000_82574:
+       case e1000_82583:
+               e1000_put_hw_semaphore_82574(hw);
+               break;
+       default:
+               break;
+       }
+
        if (hw->nvm.type == e1000_nvm_flash_hw) {
                udelay(10);
                ctrl_ext = er32(CTRL_EXT);