mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-01 19:34:35 +08:00
igb: Support for SFP modules discovery
This patch adds support for SFP modules media type discovery for SGMII, which will enable driver to detect supported external PHYs, including 100baseFXSFP module. Signed-off-by: Akeem G Abodunrin <akeem.g.abodunrin@intel.com> Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
parent
20a4841228
commit
641ac5c0cd
@ -401,12 +401,82 @@ static s32 igb_init_mac_params_82575(struct e1000_hw *hw)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_set_sfp_media_type_82575 - derives SFP module media type.
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* The media type is chosen based on SFP module.
|
||||
* compatibility flags retrieved from SFP ID EEPROM.
|
||||
**/
|
||||
static s32 igb_set_sfp_media_type_82575(struct e1000_hw *hw)
|
||||
{
|
||||
s32 ret_val = E1000_ERR_CONFIG;
|
||||
u32 ctrl_ext = 0;
|
||||
struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
|
||||
struct e1000_sfp_flags *eth_flags = &dev_spec->eth_flags;
|
||||
u8 tranceiver_type = 0;
|
||||
s32 timeout = 3;
|
||||
|
||||
/* Turn I2C interface ON and power on sfp cage */
|
||||
ctrl_ext = rd32(E1000_CTRL_EXT);
|
||||
ctrl_ext &= ~E1000_CTRL_EXT_SDP3_DATA;
|
||||
wr32(E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_I2C_ENA);
|
||||
|
||||
wrfl();
|
||||
|
||||
/* Read SFP module data */
|
||||
while (timeout) {
|
||||
ret_val = igb_read_sfp_data_byte(hw,
|
||||
E1000_I2CCMD_SFP_DATA_ADDR(E1000_SFF_IDENTIFIER_OFFSET),
|
||||
&tranceiver_type);
|
||||
if (ret_val == 0)
|
||||
break;
|
||||
msleep(100);
|
||||
timeout--;
|
||||
}
|
||||
if (ret_val != 0)
|
||||
goto out;
|
||||
|
||||
ret_val = igb_read_sfp_data_byte(hw,
|
||||
E1000_I2CCMD_SFP_DATA_ADDR(E1000_SFF_ETH_FLAGS_OFFSET),
|
||||
(u8 *)eth_flags);
|
||||
if (ret_val != 0)
|
||||
goto out;
|
||||
|
||||
/* Check if there is some SFP module plugged and powered */
|
||||
if ((tranceiver_type == E1000_SFF_IDENTIFIER_SFP) ||
|
||||
(tranceiver_type == E1000_SFF_IDENTIFIER_SFF)) {
|
||||
dev_spec->module_plugged = true;
|
||||
if (eth_flags->e1000_base_lx || eth_flags->e1000_base_sx) {
|
||||
hw->phy.media_type = e1000_media_type_internal_serdes;
|
||||
} else if (eth_flags->e100_base_fx) {
|
||||
dev_spec->sgmii_active = true;
|
||||
hw->phy.media_type = e1000_media_type_internal_serdes;
|
||||
} else if (eth_flags->e1000_base_t) {
|
||||
dev_spec->sgmii_active = true;
|
||||
hw->phy.media_type = e1000_media_type_copper;
|
||||
} else {
|
||||
hw->phy.media_type = e1000_media_type_unknown;
|
||||
hw_dbg("PHY module has not been recognized\n");
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
hw->phy.media_type = e1000_media_type_unknown;
|
||||
}
|
||||
ret_val = 0;
|
||||
out:
|
||||
/* Restore I2C interface setting */
|
||||
wr32(E1000_CTRL_EXT, ctrl_ext);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static s32 igb_get_invariants_82575(struct e1000_hw *hw)
|
||||
{
|
||||
struct e1000_mac_info *mac = &hw->mac;
|
||||
struct e1000_dev_spec_82575 * dev_spec = &hw->dev_spec._82575;
|
||||
s32 ret_val;
|
||||
u32 ctrl_ext = 0;
|
||||
u32 link_mode = 0;
|
||||
|
||||
switch (hw->device_id) {
|
||||
case E1000_DEV_ID_82575EB_COPPER:
|
||||
@ -470,15 +540,55 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
|
||||
*/
|
||||
hw->phy.media_type = e1000_media_type_copper;
|
||||
dev_spec->sgmii_active = false;
|
||||
dev_spec->module_plugged = false;
|
||||
|
||||
ctrl_ext = rd32(E1000_CTRL_EXT);
|
||||
switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
|
||||
case E1000_CTRL_EXT_LINK_MODE_SGMII:
|
||||
dev_spec->sgmii_active = true;
|
||||
break;
|
||||
|
||||
link_mode = ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK;
|
||||
switch (link_mode) {
|
||||
case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
|
||||
case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
|
||||
hw->phy.media_type = e1000_media_type_internal_serdes;
|
||||
break;
|
||||
case E1000_CTRL_EXT_LINK_MODE_SGMII:
|
||||
/* Get phy control interface type set (MDIO vs. I2C)*/
|
||||
if (igb_sgmii_uses_mdio_82575(hw)) {
|
||||
hw->phy.media_type = e1000_media_type_copper;
|
||||
dev_spec->sgmii_active = true;
|
||||
break;
|
||||
}
|
||||
/* fall through for I2C based SGMII */
|
||||
case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
|
||||
/* read media type from SFP EEPROM */
|
||||
ret_val = igb_set_sfp_media_type_82575(hw);
|
||||
if ((ret_val != 0) ||
|
||||
(hw->phy.media_type == e1000_media_type_unknown)) {
|
||||
/* If media type was not identified then return media
|
||||
* type defined by the CTRL_EXT settings.
|
||||
*/
|
||||
hw->phy.media_type = e1000_media_type_internal_serdes;
|
||||
|
||||
if (link_mode == E1000_CTRL_EXT_LINK_MODE_SGMII) {
|
||||
hw->phy.media_type = e1000_media_type_copper;
|
||||
dev_spec->sgmii_active = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* do not change link mode for 100BaseFX */
|
||||
if (dev_spec->eth_flags.e100_base_fx)
|
||||
break;
|
||||
|
||||
/* change current link mode setting */
|
||||
ctrl_ext &= ~E1000_CTRL_EXT_LINK_MODE_MASK;
|
||||
|
||||
if (hw->phy.media_type == e1000_media_type_copper)
|
||||
ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_SGMII;
|
||||
else
|
||||
ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES;
|
||||
|
||||
wr32(E1000_CTRL_EXT, ctrl_ext);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -61,20 +61,22 @@
|
||||
/* Clear Interrupt timers after IMS clear */
|
||||
/* packet buffer parity error detection enabled */
|
||||
/* descriptor FIFO parity error detection enable */
|
||||
#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */
|
||||
#define E1000_I2CCMD_REG_ADDR_SHIFT 16
|
||||
#define E1000_I2CCMD_PHY_ADDR_SHIFT 24
|
||||
#define E1000_I2CCMD_OPCODE_READ 0x08000000
|
||||
#define E1000_I2CCMD_OPCODE_WRITE 0x00000000
|
||||
#define E1000_I2CCMD_READY 0x20000000
|
||||
#define E1000_I2CCMD_ERROR 0x80000000
|
||||
#define E1000_MAX_SGMII_PHY_REG_ADDR 255
|
||||
#define E1000_I2CCMD_PHY_TIMEOUT 200
|
||||
#define E1000_IVAR_VALID 0x80
|
||||
#define E1000_GPIE_NSICR 0x00000001
|
||||
#define E1000_GPIE_MSIX_MODE 0x00000010
|
||||
#define E1000_GPIE_EIAME 0x40000000
|
||||
#define E1000_GPIE_PBA 0x80000000
|
||||
#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */
|
||||
#define E1000_I2CCMD_REG_ADDR_SHIFT 16
|
||||
#define E1000_I2CCMD_PHY_ADDR_SHIFT 24
|
||||
#define E1000_I2CCMD_OPCODE_READ 0x08000000
|
||||
#define E1000_I2CCMD_OPCODE_WRITE 0x00000000
|
||||
#define E1000_I2CCMD_READY 0x20000000
|
||||
#define E1000_I2CCMD_ERROR 0x80000000
|
||||
#define E1000_I2CCMD_SFP_DATA_ADDR(a) (0x0000 + (a))
|
||||
#define E1000_I2CCMD_SFP_DIAG_ADDR(a) (0x0100 + (a))
|
||||
#define E1000_MAX_SGMII_PHY_REG_ADDR 255
|
||||
#define E1000_I2CCMD_PHY_TIMEOUT 200
|
||||
#define E1000_IVAR_VALID 0x80
|
||||
#define E1000_GPIE_NSICR 0x00000001
|
||||
#define E1000_GPIE_MSIX_MODE 0x00000010
|
||||
#define E1000_GPIE_EIAME 0x40000000
|
||||
#define E1000_GPIE_PBA 0x80000000
|
||||
|
||||
/* Receive Descriptor bit definitions */
|
||||
#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
|
||||
|
@ -528,6 +528,8 @@ struct e1000_dev_spec_82575 {
|
||||
bool global_device_reset;
|
||||
bool eee_disable;
|
||||
bool clear_semaphore_once;
|
||||
struct e1000_sfp_flags eth_flags;
|
||||
bool module_plugged;
|
||||
};
|
||||
|
||||
struct e1000_hw {
|
||||
|
@ -340,6 +340,130 @@ s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_read_sfp_data_byte - Reads SFP module data.
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: byte location offset to be read
|
||||
* @data: read data buffer pointer
|
||||
*
|
||||
* Reads one byte from SFP module data stored
|
||||
* in SFP resided EEPROM memory or SFP diagnostic area.
|
||||
* Function should be called with
|
||||
* E1000_I2CCMD_SFP_DATA_ADDR(<byte offset>) for SFP module database access
|
||||
* E1000_I2CCMD_SFP_DIAG_ADDR(<byte offset>) for SFP diagnostics parameters
|
||||
* access
|
||||
**/
|
||||
s32 igb_read_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 *data)
|
||||
{
|
||||
u32 i = 0;
|
||||
u32 i2ccmd = 0;
|
||||
u32 data_local = 0;
|
||||
|
||||
if (offset > E1000_I2CCMD_SFP_DIAG_ADDR(255)) {
|
||||
hw_dbg("I2CCMD command address exceeds upper limit\n");
|
||||
return -E1000_ERR_PHY;
|
||||
}
|
||||
|
||||
/* Set up Op-code, EEPROM Address,in the I2CCMD
|
||||
* register. The MAC will take care of interfacing with the
|
||||
* EEPROM to retrieve the desired data.
|
||||
*/
|
||||
i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
|
||||
E1000_I2CCMD_OPCODE_READ);
|
||||
|
||||
wr32(E1000_I2CCMD, i2ccmd);
|
||||
|
||||
/* Poll the ready bit to see if the I2C read completed */
|
||||
for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
|
||||
udelay(50);
|
||||
data_local = rd32(E1000_I2CCMD);
|
||||
if (data_local & E1000_I2CCMD_READY)
|
||||
break;
|
||||
}
|
||||
if (!(data_local & E1000_I2CCMD_READY)) {
|
||||
hw_dbg("I2CCMD Read did not complete\n");
|
||||
return -E1000_ERR_PHY;
|
||||
}
|
||||
if (data_local & E1000_I2CCMD_ERROR) {
|
||||
hw_dbg("I2CCMD Error bit set\n");
|
||||
return -E1000_ERR_PHY;
|
||||
}
|
||||
*data = (u8) data_local & 0xFF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_write_sfp_data_byte - Writes SFP module data.
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: byte location offset to write to
|
||||
* @data: data to write
|
||||
*
|
||||
* Writes one byte to SFP module data stored
|
||||
* in SFP resided EEPROM memory or SFP diagnostic area.
|
||||
* Function should be called with
|
||||
* E1000_I2CCMD_SFP_DATA_ADDR(<byte offset>) for SFP module database access
|
||||
* E1000_I2CCMD_SFP_DIAG_ADDR(<byte offset>) for SFP diagnostics parameters
|
||||
* access
|
||||
**/
|
||||
s32 e1000_write_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 data)
|
||||
{
|
||||
u32 i = 0;
|
||||
u32 i2ccmd = 0;
|
||||
u32 data_local = 0;
|
||||
|
||||
if (offset > E1000_I2CCMD_SFP_DIAG_ADDR(255)) {
|
||||
hw_dbg("I2CCMD command address exceeds upper limit\n");
|
||||
return -E1000_ERR_PHY;
|
||||
}
|
||||
/* The programming interface is 16 bits wide
|
||||
* so we need to read the whole word first
|
||||
* then update appropriate byte lane and write
|
||||
* the updated word back.
|
||||
*/
|
||||
/* Set up Op-code, EEPROM Address,in the I2CCMD
|
||||
* register. The MAC will take care of interfacing
|
||||
* with an EEPROM to write the data given.
|
||||
*/
|
||||
i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
|
||||
E1000_I2CCMD_OPCODE_READ);
|
||||
/* Set a command to read single word */
|
||||
wr32(E1000_I2CCMD, i2ccmd);
|
||||
for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
|
||||
udelay(50);
|
||||
/* Poll the ready bit to see if lastly
|
||||
* launched I2C operation completed
|
||||
*/
|
||||
i2ccmd = rd32(E1000_I2CCMD);
|
||||
if (i2ccmd & E1000_I2CCMD_READY) {
|
||||
/* Check if this is READ or WRITE phase */
|
||||
if ((i2ccmd & E1000_I2CCMD_OPCODE_READ) ==
|
||||
E1000_I2CCMD_OPCODE_READ) {
|
||||
/* Write the selected byte
|
||||
* lane and update whole word
|
||||
*/
|
||||
data_local = i2ccmd & 0xFF00;
|
||||
data_local |= data;
|
||||
i2ccmd = ((offset <<
|
||||
E1000_I2CCMD_REG_ADDR_SHIFT) |
|
||||
E1000_I2CCMD_OPCODE_WRITE | data_local);
|
||||
wr32(E1000_I2CCMD, i2ccmd);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(i2ccmd & E1000_I2CCMD_READY)) {
|
||||
hw_dbg("I2CCMD Write did not complete\n");
|
||||
return -E1000_ERR_PHY;
|
||||
}
|
||||
if (i2ccmd & E1000_I2CCMD_ERROR) {
|
||||
hw_dbg("I2CCMD Error bit set\n");
|
||||
return -E1000_ERR_PHY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_read_phy_reg_igp - Read igp PHY register
|
||||
* @hw: pointer to the HW structure
|
||||
|
@ -69,6 +69,8 @@ s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
|
||||
s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
|
||||
s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data);
|
||||
s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data);
|
||||
s32 igb_read_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 *data);
|
||||
s32 e1000_write_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 data);
|
||||
s32 igb_copper_link_setup_82580(struct e1000_hw *hw);
|
||||
s32 igb_get_phy_info_82580(struct e1000_hw *hw);
|
||||
s32 igb_phy_force_speed_duplex_82580(struct e1000_hw *hw);
|
||||
@ -157,4 +159,22 @@ s32 igb_check_polarity_m88(struct e1000_hw *hw);
|
||||
#define GS40G_CS_POWER_DOWN 0x0002
|
||||
#define GS40G_LINE_LB 0x4000
|
||||
|
||||
/* SFP modules ID memory locations */
|
||||
#define E1000_SFF_IDENTIFIER_OFFSET 0x00
|
||||
#define E1000_SFF_IDENTIFIER_SFF 0x02
|
||||
#define E1000_SFF_IDENTIFIER_SFP 0x03
|
||||
|
||||
#define E1000_SFF_ETH_FLAGS_OFFSET 0x06
|
||||
/* Flags for SFP modules compatible with ETH up to 1Gb */
|
||||
struct e1000_sfp_flags {
|
||||
u8 e1000_base_sx:1;
|
||||
u8 e1000_base_lx:1;
|
||||
u8 e1000_base_cx:1;
|
||||
u8 e1000_base_t:1;
|
||||
u8 e100_base_lx:1;
|
||||
u8 e100_base_fx:1;
|
||||
u8 e10_base_bx10:1;
|
||||
u8 e10_base_px:1;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -142,6 +142,8 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
|
||||
{
|
||||
struct igb_adapter *adapter = netdev_priv(netdev);
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
|
||||
struct e1000_sfp_flags *eth_flags = &dev_spec->eth_flags;
|
||||
u32 status;
|
||||
|
||||
if (hw->phy.media_type == e1000_media_type_copper) {
|
||||
@ -181,30 +183,22 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
|
||||
ecmd->phy_address = hw->phy.addr;
|
||||
ecmd->transceiver = XCVR_INTERNAL;
|
||||
} else {
|
||||
ecmd->supported = (SUPPORTED_1000baseT_Full |
|
||||
SUPPORTED_100baseT_Full |
|
||||
SUPPORTED_FIBRE |
|
||||
ecmd->supported = (SUPPORTED_FIBRE |
|
||||
SUPPORTED_Autoneg |
|
||||
SUPPORTED_Pause);
|
||||
if (hw->mac.type == e1000_i354)
|
||||
ecmd->supported |= SUPPORTED_2500baseX_Full;
|
||||
|
||||
ecmd->advertising = ADVERTISED_FIBRE;
|
||||
|
||||
switch (adapter->link_speed) {
|
||||
case SPEED_2500:
|
||||
ecmd->advertising = ADVERTISED_2500baseX_Full;
|
||||
break;
|
||||
case SPEED_1000:
|
||||
ecmd->advertising = ADVERTISED_1000baseT_Full;
|
||||
break;
|
||||
case SPEED_100:
|
||||
ecmd->advertising = ADVERTISED_100baseT_Full;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (hw->mac.type == e1000_i354) {
|
||||
ecmd->supported |= SUPPORTED_2500baseX_Full;
|
||||
ecmd->advertising |= ADVERTISED_2500baseX_Full;
|
||||
}
|
||||
if ((eth_flags->e1000_base_lx) || (eth_flags->e1000_base_sx)) {
|
||||
ecmd->supported |= SUPPORTED_1000baseT_Full;
|
||||
ecmd->advertising |= ADVERTISED_1000baseT_Full;
|
||||
}
|
||||
if (eth_flags->e100_base_fx) {
|
||||
ecmd->supported |= SUPPORTED_100baseT_Full;
|
||||
ecmd->advertising |= ADVERTISED_100baseT_Full;
|
||||
}
|
||||
|
||||
if (hw->mac.autoneg == 1)
|
||||
ecmd->advertising |= ADVERTISED_Autoneg;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user