ixgbe: Add support for SFPs with retimer
authorMark Rustad <mark.d.rustad@intel.com>
Fri, 1 Apr 2016 19:18:35 +0000 (12:18 -0700)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Fri, 8 Apr 2016 00:06:54 +0000 (17:06 -0700)
Add support for SFPs with an external retimer.

Signed-off-by: Mark Rustad <mark.d.rustad@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c

index eb93319337a1a75d5cb3234ca2beb4b0d5413538..93db4bf00dfe68b7d2a00e0d53f030a8b8957b94 100644 (file)
@@ -132,6 +132,7 @@ static const struct pci_device_id ixgbe_pci_tbl[] = {
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_10G_T), board_X550EM_x},
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_SFP), board_X550EM_x},
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SFP_N), board_x550em_a },
+       {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SFP), board_x550em_a },
        /* required last entry */
        {0, }
 };
@@ -2681,6 +2682,7 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter, bool queues,
        case ixgbe_mac_X550EM_x:
        case ixgbe_mac_x550em_a:
                if (adapter->hw.device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
+                   adapter->hw.device_id == IXGBE_DEV_ID_X550EM_A_SFP ||
                    adapter->hw.device_id == IXGBE_DEV_ID_X550EM_A_SFP_N)
                        mask |= IXGBE_EIMS_GPI_SDP0(&adapter->hw);
                if (adapter->hw.phy.type == ixgbe_phy_x550em_ext_t)
index 5abd66c84d005f4d211d20bab2fd42b1a5b2a5c7..cdf4c38008015739e29fb7286b5bf2a1783867c3 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2014 Intel Corporation.
+  Copyright(c) 1999 - 2016 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,
 #define IXGBE_I2C_EEPROM_STATUS_FAIL           0x2
 #define IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS    0x3
 #define IXGBE_CS4227                           0xBE    /* CS4227 address */
+#define IXGBE_CS4227_GLOBAL_ID_LSB             0
+#define IXGBE_CS4227_GLOBAL_ID_MSB             1
 #define IXGBE_CS4227_SCRATCH                   2
+#define IXGBE_CS4223_PHY_ID                    0x7003  /* Quad port */
+#define IXGBE_CS4227_PHY_ID                    0x3003  /* Dual port */
 #define IXGBE_CS4227_RESET_PENDING             0x1357
 #define IXGBE_CS4227_RESET_COMPLETE            0x5AA5
 #define IXGBE_CS4227_RETRIES                   15
index 6b68e8ba1dceb684e4822a628a8d859daa28b4e9..fbbc13224657c1f50be87a1fe71c52f9d8d2da95 100644 (file)
@@ -1311,6 +1311,7 @@ struct ixgbe_thermal_sensor_data {
 
 /* MDIO definitions */
 
+#define IXGBE_MDIO_ZERO_DEV_TYPE               0x0
 #define IXGBE_MDIO_PMA_PMD_DEV_TYPE            0x1
 #define IXGBE_MDIO_PCS_DEV_TYPE                0x3
 #define IXGBE_MDIO_PHY_XS_DEV_TYPE             0x4
@@ -3580,6 +3581,7 @@ struct ixgbe_info {
 #define IXGBE_KRM_PORT_CAR_GEN_CTRL(P) ((P) ? 0x8010 : 0x4010)
 #define IXGBE_KRM_LINK_CTRL_1(P)       ((P) ? 0x820C : 0x420C)
 #define IXGBE_KRM_AN_CNTL_1(P)         ((P) ? 0x822C : 0x422C)
+#define IXGBE_KRM_AN_CNTL_8(P)         ((P) ? 0x8248 : 0x4248)
 #define IXGBE_KRM_DSP_TXFFE_STATE_4(P) ((P) ? 0x8634 : 0x4634)
 #define IXGBE_KRM_DSP_TXFFE_STATE_5(P) ((P) ? 0x8638 : 0x4638)
 #define IXGBE_KRM_RX_TRN_LINKUP_CTRL(P)        ((P) ? 0x8B00 : 0x4B00)
@@ -3605,6 +3607,9 @@ struct ixgbe_info {
 #define IXGBE_KRM_AN_CNTL_1_SYM_PAUSE                  (1 << 28)
 #define IXGBE_KRM_AN_CNTL_1_ASM_PAUSE                  (1 << 29)
 
+#define IXGBE_KRM_AN_CNTL_8_LINEAR                     BIT(0)
+#define IXGBE_KRM_AN_CNTL_8_LIMITING                   BIT(1)
+
 #define IXGBE_KRM_DSP_TXFFE_STATE_C0_EN                        (1 << 6)
 #define IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN           (1 << 15)
 #define IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN          (1 << 16)
index 0d6cbb0af1a60abb40fdf63674d1415c08e38d89..a9d86b37872cf218f17776124c864e2c04f81992 100644 (file)
@@ -273,6 +273,12 @@ out:
 static s32 ixgbe_identify_phy_x550em(struct ixgbe_hw *hw)
 {
        switch (hw->device_id) {
+       case IXGBE_DEV_ID_X550EM_A_SFP:
+               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;
@@ -1362,6 +1368,117 @@ i2c_err:
        return status;
 }
 
+/**
+ * ixgbe_setup_mac_link_sfp_n - Setup internal PHY for native SFP
+ * @hw: pointer to hardware structure
+ *
+ * Configure the the integrated PHY for native SFP support.
+ */
+static s32
+ixgbe_setup_mac_link_sfp_n(struct ixgbe_hw *hw, ixgbe_link_speed speed,
+                          __always_unused bool autoneg_wait_to_complete)
+{
+       bool setup_linear = false;
+       u32 reg_phy_int;
+       s32 rc;
+
+       /* Check if SFP module is supported and linear */
+       rc = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear);
+
+       /* If no SFP module present, then return success. Return success since
+        * SFP not present error is not excepted in the setup MAC link flow.
+        */
+       if (rc == IXGBE_ERR_SFP_NOT_PRESENT)
+               return 0;
+
+       if (!rc)
+               return rc;
+
+       /* Configure internal PHY for native SFI */
+       rc = hw->mac.ops.read_iosf_sb_reg(hw,
+                                         IXGBE_KRM_AN_CNTL_8(hw->bus.lan_id),
+                                         IXGBE_SB_IOSF_TARGET_KR_PHY,
+                                         &reg_phy_int);
+       if (rc)
+               return rc;
+
+       if (setup_linear) {
+               reg_phy_int &= ~IXGBE_KRM_AN_CNTL_8_LIMITING;
+               reg_phy_int |= IXGBE_KRM_AN_CNTL_8_LINEAR;
+       } else {
+               reg_phy_int |= IXGBE_KRM_AN_CNTL_8_LIMITING;
+               reg_phy_int &= ~IXGBE_KRM_AN_CNTL_8_LINEAR;
+       }
+
+       rc = hw->mac.ops.write_iosf_sb_reg(hw,
+                                          IXGBE_KRM_AN_CNTL_8(hw->bus.lan_id),
+                                          IXGBE_SB_IOSF_TARGET_KR_PHY,
+                                          reg_phy_int);
+       if (rc)
+               return rc;
+
+       /* Setup XFI/SFI internal link */
+       return ixgbe_setup_ixfi_x550em(hw, &speed);
+}
+
+/**
+ * ixgbe_setup_mac_link_sfp_x550a - Setup internal PHY for SFP
+ * @hw: pointer to hardware structure
+ *
+ * Configure the the integrated PHY for SFP support.
+ */
+static s32
+ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, ixgbe_link_speed speed,
+                              __always_unused bool autoneg_wait_to_complete)
+{
+       u32 reg_slice, slice_offset;
+       bool setup_linear = false;
+       u16 reg_phy_ext;
+       s32 rc;
+
+       /* Check if SFP module is supported and linear */
+       rc = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear);
+
+       /* If no SFP module present, then return success. Return success since
+        * SFP not present error is not excepted in the setup MAC link flow.
+        */
+       if (rc == IXGBE_ERR_SFP_NOT_PRESENT)
+               return 0;
+
+       if (!rc)
+               return rc;
+
+       /* Configure internal PHY for KR/KX. */
+       ixgbe_setup_kr_speed_x550em(hw, speed);
+
+       if (!hw->phy.mdio.prtad || hw->phy.mdio.prtad == 0xFFFF)
+               return IXGBE_ERR_PHY_ADDR_INVALID;
+
+       /* Get external PHY device id */
+       rc = hw->phy.ops.read_reg(hw, IXGBE_CS4227_GLOBAL_ID_MSB,
+                                 IXGBE_MDIO_ZERO_DEV_TYPE, &reg_phy_ext);
+       if (rc)
+               return rc;
+
+       /* When configuring quad port CS4223, the MAC instance is part
+        * of the slice offset.
+        */
+       if (reg_phy_ext == IXGBE_CS4223_PHY_ID)
+               slice_offset = (hw->bus.lan_id +
+                               (hw->bus.instance_id << 1)) << 12;
+       else
+               slice_offset = hw->bus.lan_id << 12;
+
+       /* Configure CS4227/CS4223 LINE side to proper mode. */
+       reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + slice_offset;
+       if (setup_linear)
+               reg_phy_ext = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 1;
+       else
+               reg_phy_ext = (IXGBE_CS4227_EDC_MODE_SR << 1) | 1;
+       return hw->phy.ops.write_reg(hw, reg_slice, IXGBE_MDIO_ZERO_DEV_TYPE,
+                                    reg_phy_ext);
+}
+
 /**
  * ixgbe_setup_mac_link_t_X550em - Sets the auto advertised link speed
  * @hw: pointer to hardware structure
@@ -1456,9 +1573,21 @@ static void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
                mac->ops.disable_tx_laser = NULL;
                mac->ops.enable_tx_laser = NULL;
                mac->ops.flap_tx_laser = NULL;
-               mac->ops.setup_mac_link = ixgbe_setup_mac_link_sfp_x550em;
                mac->ops.setup_link = ixgbe_setup_mac_link_multispeed_fiber;
                mac->ops.setup_fc = ixgbe_setup_fc_x550em;
+               switch (hw->device_id) {
+               case IXGBE_DEV_ID_X550EM_A_SFP_N:
+                       mac->ops.setup_mac_link = ixgbe_setup_mac_link_sfp_n;
+                       break;
+               case IXGBE_DEV_ID_X550EM_A_SFP:
+                       mac->ops.setup_mac_link =
+                                               ixgbe_setup_mac_link_sfp_x550a;
+                       break;
+               default:
+                       mac->ops.setup_mac_link =
+                                               ixgbe_setup_mac_link_sfp_x550em;
+                       break;
+               }
                mac->ops.set_rate_select_speed =
                                        ixgbe_set_soft_rate_select_speed;
                break;
@@ -2253,6 +2382,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw)
                media_type = ixgbe_media_type_backplane;
                break;
        case IXGBE_DEV_ID_X550EM_X_SFP:
+       case IXGBE_DEV_ID_X550EM_A_SFP:
        case IXGBE_DEV_ID_X550EM_A_SFP_N:
                media_type = ixgbe_media_type_fiber;
                break;
@@ -2316,6 +2446,7 @@ static void ixgbe_set_mdio_speed(struct ixgbe_hw *hw)
 
        switch (hw->device_id) {
        case IXGBE_DEV_ID_X550EM_X_10G_T:
+       case IXGBE_DEV_ID_X550EM_A_SFP:
                /* Config MDIO clock speed before the first MDIO PHY access */
                hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
                hlreg0 &= ~IXGBE_HLREG0_MDCSPD;