net/ixgbe/base: separate PHY ops init from PHY init
[dpdk.git] / drivers / net / ixgbe / base / ixgbe_x550.c
index c8873ee..19a554d 100644 (file)
@@ -41,6 +41,7 @@ POSSIBILITY OF SUCH DAMAGE.
 STATIC s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed);
 STATIC s32 ixgbe_acquire_swfw_sync_X550a(struct ixgbe_hw *, u32 mask);
 STATIC void ixgbe_release_swfw_sync_X550a(struct ixgbe_hw *, u32 mask);
+STATIC s32 ixgbe_read_mng_if_sel_x550em(struct ixgbe_hw *hw);
 
 /**
  *  ixgbe_init_ops_X550 - Inits func ptrs and MAC type
@@ -428,18 +429,15 @@ STATIC s32 ixgbe_write_phy_reg_mdi_22(struct ixgbe_hw *hw, u32 reg_addr,
  */
 STATIC s32 ixgbe_identify_phy_x550em(struct ixgbe_hw *hw)
 {
+       hw->mac.ops.set_lan_id(hw);
+
+       ixgbe_read_mng_if_sel_x550em(hw);
+
        switch (hw->device_id) {
        case IXGBE_DEV_ID_X550EM_A_SFP:
-               hw->phy.ops.read_reg = ixgbe_read_phy_reg_x550a;
-               hw->phy.ops.write_reg = ixgbe_write_phy_reg_x550a;
-               if (hw->bus.lan_id)
-                       hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM;
-               else
-                       hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM;
                return ixgbe_identify_module_generic(hw);
        case IXGBE_DEV_ID_X550EM_X_SFP:
                /* set up for CS4227 usage */
-               hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
                ixgbe_setup_mux_ctl(hw);
                ixgbe_check_cs4227(hw);
                /* Fallthrough */
@@ -456,9 +454,6 @@ STATIC s32 ixgbe_identify_phy_x550em(struct ixgbe_hw *hw)
                hw->phy.type = ixgbe_phy_x550em_kr;
                break;
        case IXGBE_DEV_ID_X550EM_A_10G_T:
-               hw->phy.ops.read_reg = ixgbe_read_phy_reg_x550a;
-               hw->phy.ops.write_reg = ixgbe_write_phy_reg_x550a;
-       /* Fallthrough to ixgbe_identify_phy_generic */
        case IXGBE_DEV_ID_X550EM_A_1G_T:
        case IXGBE_DEV_ID_X550EM_A_1G_T_L:
        case IXGBE_DEV_ID_X550EM_X_1G_T:
@@ -676,6 +671,12 @@ s32 ixgbe_init_ops_X550EM_a(struct ixgbe_hw *hw)
                break;
        }
 
+       if ((hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T) ||
+               (hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T_L)) {
+               mac->ops.fc_autoneg = ixgbe_fc_autoneg_sgmii_x550em_a;
+               mac->ops.setup_fc = ixgbe_setup_fc_sgmii_x550em_a;
+       }
+
        return ret_val;
 }
 
@@ -1709,72 +1710,6 @@ STATIC s32 ixgbe_setup_sgmii_m88(struct ixgbe_hw *hw, ixgbe_link_speed speed,
        return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait);
 }
 
-/**
- * ixgbe_check_link_m88 - Poll PHY for link
- * @hw: pointer to hardware structure
- * @speed: pointer to link speed
- * @link_up: true when link is up
- * @link_up_wait: bool indicating whether to wait for link
- *
- * Check that both the MAC and PHY have link.
- */
-static s32
-ixgbe_check_link_m88(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
-                    bool *link_up, bool link_up_wait)
-{
-       u16 reg;
-       s32 rc;
-       u32 i;
-
-       rc = ixgbe_check_mac_link_generic(hw, speed, link_up, link_up_wait);
-       if (rc || !*link_up)
-               return rc;
-
-       rc = hw->phy.ops.read_reg(hw, IXGBE_M88E1500_PHY_SPEC_STATUS, 0, &reg);
-
-       /* MAC link is up, so check external PHY link */
-       *link_up = !!(reg & IXGBE_M88E1500_PHY_SPEC_STATUS_LINK);
-
-       if (link_up_wait) {
-               for (i = 0; i < IXGBE_AUTO_NEG_TIME; i++) {
-                       if (!rc &&
-                           (reg & IXGBE_M88E1500_PHY_SPEC_STATUS_LINK)) {
-                               *link_up = true;
-                               break;
-                       }
-                       *link_up = false;
-                       msec_delay(100);
-                       rc = hw->phy.ops.read_reg(hw,
-                                                IXGBE_M88E1500_PHY_SPEC_STATUS,
-                                                0, &reg);
-               }
-       }
-
-#define M88_SPEED(x) (IXGBE_M88E1500_PHY_SPEC_STATUS_RESOLVED  | \
-                     IXGBE_M88E1500_PHY_SPEC_STATUS_DUPLEX     | \
-                     ((IXGBE_M88E1500_PHY_SPEC_STATUS_SPEED_##x) <<\
-                       IXGBE_M88E1500_PHY_SPEC_STATUS_SPEED_SHIFT))
-
-       reg &= M88_SPEED(MASK);
-       switch (reg) {
-       case M88_SPEED(10):
-               *speed = IXGBE_LINK_SPEED_10_FULL;
-               break;
-       case M88_SPEED(100):
-               *speed = IXGBE_LINK_SPEED_100_FULL;
-               break;
-       case M88_SPEED(1000):
-               *speed = IXGBE_LINK_SPEED_1GB_FULL;
-               break;
-       default:
-               *speed = IXGBE_LINK_SPEED_UNKNOWN;
-               break;
-       }
-#undef M88_SPEED
-
-       return rc;
-}
-
 /**
  *  ixgbe_init_mac_link_ops_X550em - init mac link function pointers
  *  @hw: pointer to hardware structure
@@ -1805,10 +1740,14 @@ void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
                                ixgbe_setup_mac_link_sfp_x550em;
                break;
        case ixgbe_media_type_copper:
-               if (hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T ||
-                   hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T_L) {
-                       mac->ops.setup_link = ixgbe_setup_sgmii_m88;
-                       mac->ops.check_link = ixgbe_check_link_m88;
+               if (hw->mac.type == ixgbe_mac_X550EM_a) {
+                       if (hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T ||
+                           hw->device_id == IXGBE_DEV_ID_X550EM_A_1G_T_L) {
+                               mac->ops.setup_link = ixgbe_setup_sgmii_m88;
+                       } else {
+                               mac->ops.setup_link =
+                                                 ixgbe_setup_mac_link_t_X550em;
+                       }
                } else {
                        mac->ops.setup_link = ixgbe_setup_mac_link_t_X550em;
                        mac->ops.check_link = ixgbe_check_link_t_X550em;
@@ -2182,27 +2121,15 @@ STATIC s32 ixgbe_setup_m88(struct ixgbe_hw *hw)
        rc = hw->phy.ops.read_reg_mdi(hw, IXGBE_M88E1500_COPPER_AN, 0, &reg);
        if (rc)
                goto out;
-       reg &= ~IXGBE_M88E1500_COPPER_AN_AS_PAUSE;
-       reg &= ~IXGBE_M88E1500_COPPER_AN_PAUSE;
        reg &= ~IXGBE_M88E1500_COPPER_AN_T4;
        reg &= ~IXGBE_M88E1500_COPPER_AN_100TX_FD;
        reg &= ~IXGBE_M88E1500_COPPER_AN_100TX_HD;
        reg &= ~IXGBE_M88E1500_COPPER_AN_10TX_FD;
        reg &= ~IXGBE_M88E1500_COPPER_AN_10TX_HD;
-       switch (hw->fc.current_mode) {
-       case ixgbe_fc_full:
-               reg |= IXGBE_M88E1500_COPPER_AN_PAUSE;
-               break;
-       case ixgbe_fc_rx_pause:
-               reg |= IXGBE_M88E1500_COPPER_AN_PAUSE;
-               reg |= IXGBE_M88E1500_COPPER_AN_AS_PAUSE;
-               break;
-       case ixgbe_fc_tx_pause:
-               reg |= IXGBE_M88E1500_COPPER_AN_AS_PAUSE;
-               break;
-       default:
-               break;
-       }
+
+       /* Flow control auto negotiation configuration was moved from here to
+        * the function ixgbe_setup_fc_sgmii_x550em_a()
+        */
 
        if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
                reg |= IXGBE_M88E1500_COPPER_AN_100TX_FD;
@@ -2351,6 +2278,12 @@ STATIC s32 ixgbe_reset_phy_m88(struct ixgbe_hw *hw)
 
        hw->mac.ops.release_swfw_sync(hw, mask);
 
+       /* In case of first reset set advertised speeds to default value */
+       if (!hw->phy.autoneg_advertised)
+               hw->phy.autoneg_advertised = IXGBE_LINK_SPEED_1GB_FULL |
+                                            IXGBE_LINK_SPEED_100_FULL |
+                                            IXGBE_LINK_SPEED_10_FULL;
+
        return ixgbe_setup_m88(hw);
 
 out:
@@ -2401,10 +2334,6 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
 
        DEBUGFUNC("ixgbe_init_phy_ops_X550em");
 
-       hw->mac.ops.set_lan_id(hw);
-
-       ixgbe_read_mng_if_sel_x550em(hw);
-
        if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) {
                phy->phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
                ixgbe_setup_mux_ctl(hw);
@@ -2416,6 +2345,26 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
        case IXGBE_DEV_ID_X550EM_A_1G_T_L:
                phy->ops.read_reg_mdi = ixgbe_read_phy_reg_mdi_22;
                phy->ops.write_reg_mdi = ixgbe_write_phy_reg_mdi_22;
+               hw->phy.ops.read_reg = ixgbe_read_phy_reg_x550a;
+               hw->phy.ops.write_reg = ixgbe_write_phy_reg_x550a;
+               if (hw->bus.lan_id)
+                       hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM;
+               else
+                       hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM;
+
+               break;
+       case IXGBE_DEV_ID_X550EM_A_10G_T:
+       case IXGBE_DEV_ID_X550EM_A_SFP:
+               hw->phy.ops.read_reg = ixgbe_read_phy_reg_x550a;
+               hw->phy.ops.write_reg = ixgbe_write_phy_reg_x550a;
+               if (hw->bus.lan_id)
+                       hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM;
+               else
+                       hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM;
+               break;
+       case IXGBE_DEV_ID_X550EM_X_SFP:
+               /* set up for CS4227 usage */
+               hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
                break;
        default:
                break;
@@ -4121,6 +4070,152 @@ out:
        }
 }
 
+/**
+ *  ixgbe_fc_autoneg_sgmii_x550em_a - Enable flow control IEEE clause 37
+ *  @hw: pointer to hardware structure
+ *
+ *  Enable flow control according to IEEE clause 37.
+ **/
+void ixgbe_fc_autoneg_sgmii_x550em_a(struct ixgbe_hw *hw)
+{
+       s32 status = IXGBE_ERR_FC_NOT_NEGOTIATED;
+       u16 reg, pcs_an_lp, pcs_an;
+       ixgbe_link_speed speed;
+       bool link_up;
+
+       /* AN should have completed when the cable was plugged in.
+        * Look for reasons to bail out.  Bail out if:
+        * - FC autoneg is disabled, or if
+        * - link is not up.
+        */
+       if (hw->fc.disable_fc_autoneg) {
+               ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED,
+                            "Flow control autoneg is disabled");
+               goto out;
+       }
+
+       hw->mac.ops.check_link(hw, &speed, &link_up, false);
+       if (!link_up) {
+               ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, "The link is down");
+               goto out;
+       }
+
+       /* Check if auto-negotiation has completed */
+       status = hw->phy.ops.read_reg(hw, IXGBE_M88E1500_COPPER_STATUS,
+                                       IXGBE_MDIO_ZERO_DEV_TYPE, &reg);
+       if (status != IXGBE_SUCCESS ||
+           (reg & IXGBE_M88E1500_COPPER_STATUS_AN_DONE) == 0) {
+               DEBUGOUT("Auto-Negotiation did not complete\n");
+               status = IXGBE_ERR_FC_NOT_NEGOTIATED;
+               goto out;
+       }
+
+       /* Get the advertized flow control */
+       status = hw->phy.ops.read_reg(hw, IXGBE_M88E1500_COPPER_AN,
+                                       IXGBE_MDIO_ZERO_DEV_TYPE, &pcs_an);
+       if (status != IXGBE_SUCCESS)
+               goto out;
+
+       /* Get link partner's flow control */
+       status = hw->phy.ops.read_reg(hw,
+                       IXGBE_M88E1500_COPPER_AN_LP_ABILITY,
+                                       IXGBE_MDIO_ZERO_DEV_TYPE, &pcs_an_lp);
+       if (status != IXGBE_SUCCESS)
+               goto out;
+
+       /* Negotiate the flow control */
+       status = ixgbe_negotiate_fc(hw, (u32)pcs_an, (u32)pcs_an_lp,
+                                   IXGBE_M88E1500_COPPER_AN_PAUSE,
+                                   IXGBE_M88E1500_COPPER_AN_AS_PAUSE,
+                                   IXGBE_M88E1500_COPPER_AN_LP_PAUSE,
+                                   IXGBE_M88E1500_COPPER_AN_LP_AS_PAUSE);
+
+out:
+       if (status == IXGBE_SUCCESS) {
+               hw->fc.fc_was_autonegged = true;
+       } else {
+               hw->fc.fc_was_autonegged = false;
+               hw->fc.current_mode = hw->fc.requested_mode;
+       }
+}
+
+/**
+ *  ixgbe_setup_fc_sgmii_x550em_a - Set up flow control
+ *  @hw: pointer to hardware structure
+ *
+ *  Called at init time to set up flow control.
+ **/
+s32 ixgbe_setup_fc_sgmii_x550em_a(struct ixgbe_hw *hw)
+{
+       u16 reg;
+       s32 rc;
+
+       /* Validate the requested mode */
+       if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
+               ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED,
+                             "ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
+               return IXGBE_ERR_INVALID_LINK_SETTINGS;
+       }
+
+       if (hw->fc.requested_mode == ixgbe_fc_default)
+               hw->fc.requested_mode = ixgbe_fc_full;
+
+       /* Read contents of the Auto-Negotiation register, page 0 reg 4 */
+       rc = hw->phy.ops.read_reg(hw, IXGBE_M88E1500_COPPER_AN,
+                                       IXGBE_MDIO_ZERO_DEV_TYPE, &reg);
+       if (rc)
+               goto out;
+
+       /* Disable all the settings related to Flow control Auto-negotiation */
+       reg &= ~IXGBE_M88E1500_COPPER_AN_AS_PAUSE;
+       reg &= ~IXGBE_M88E1500_COPPER_AN_PAUSE;
+
+       /* Configure the Asymmetric and symmetric pause according to the user
+        * requested mode.
+        */
+       switch (hw->fc.requested_mode) {
+       case ixgbe_fc_full:
+               reg |= IXGBE_M88E1500_COPPER_AN_PAUSE;
+               reg |= IXGBE_M88E1500_COPPER_AN_AS_PAUSE;
+               break;
+       case ixgbe_fc_rx_pause:
+               reg |= IXGBE_M88E1500_COPPER_AN_PAUSE;
+               reg |= IXGBE_M88E1500_COPPER_AN_AS_PAUSE;
+               break;
+       case ixgbe_fc_tx_pause:
+               reg |= IXGBE_M88E1500_COPPER_AN_AS_PAUSE;
+               break;
+       default:
+               break;
+       }
+
+       /* Write back to the Auto-Negotiation register with newly configured
+        * fields
+        */
+       hw->phy.ops.write_reg(hw, IXGBE_M88E1500_COPPER_AN,
+                                       IXGBE_MDIO_ZERO_DEV_TYPE, reg);
+
+       /* In this section of the code we restart Auto-negotiation */
+
+       /* Read the CONTROL register, Page 0 reg 0 */
+       rc = hw->phy.ops.read_reg(hw, IXGBE_M88E1500_COPPER_CTRL,
+                                       IXGBE_MDIO_ZERO_DEV_TYPE, &reg);
+       if (rc)
+               goto out;
+
+       /* Set the bit to restart Auto-Neg. The bit to enable Auto-neg is ON
+        * by default
+        */
+       reg |= IXGBE_M88E1500_COPPER_CTRL_RESTART_AN;
+
+       /* write the new values to the register to restart Auto-Negotiation */
+       hw->phy.ops.write_reg(hw, IXGBE_M88E1500_COPPER_CTRL,
+                                       IXGBE_MDIO_ZERO_DEV_TYPE, reg);
+
+out:
+       return rc;
+}
+
 /**
  *  ixgbe_setup_fc_backplane_x550em_a - Set up flow control
  *  @hw: pointer to hardware structure
@@ -4439,7 +4534,6 @@ STATIC s32 ixgbe_acquire_swfw_sync_X550a(struct ixgbe_hw *hw, u32 mask)
                        ixgbe_release_swfw_sync_X540(hw, hmask);
                if (status != IXGBE_ERR_TOKEN_RETRY)
                        return status;
-               msec_delay(FW_PHY_TOKEN_DELAY);
        }
 
        return status;