From 859a437b422bee3d8e924a88184a68f4fbd8ed6d Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 14 Dec 2021 10:48:10 +0000 Subject: [PATCH] Implement support for selecting SGMII or SerDes mode depending on the plugged-in SFP transceiver and for reading out transceiver information via ifconfig(8). To read from the SFP, we need to let the card issue I2C transfers. Additionally we need I2C to read/write to the PHY when MDIO is not available. Depending on the SFP's supported media types we can decide which mode to use. This fixes hardware-initialization and link-up problems with some em(4) Fiber NIC and SFP combinations. Tested by dlg@ and been in snaps for quite a while ok dlg@ jmatthew@ --- sys/dev/pci/if_em.c | 42 +++++- sys/dev/pci/if_em.h | 3 +- sys/dev/pci/if_em_hw.c | 334 +++++++++++++++++++++++++++++++++++++++-- sys/dev/pci/if_em_hw.h | 42 +++++- 4 files changed, 406 insertions(+), 15 deletions(-) diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c index 759da7a3ba3..18050b9c8a9 100644 --- a/sys/dev/pci/if_em.c +++ b/sys/dev/pci/if_em.c @@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ -/* $OpenBSD: if_em.c,v 1.358 2021/01/24 10:21:43 jsg Exp $ */ +/* $OpenBSD: if_em.c,v 1.359 2021/12/14 10:48:10 patrick Exp $ */ /* $FreeBSD: if_em.c,v 1.46 2004/09/29 18:28:28 mlaier Exp $ */ #include @@ -296,6 +296,7 @@ u_int32_t em_fill_descriptors(u_int64_t address, u_int32_t length, void em_flush_tx_ring(struct em_queue *); void em_flush_rx_ring(struct em_queue *); void em_flush_desc_rings(struct em_softc *); +int em_get_sffpage(struct em_softc *, struct if_sffpage *); #ifndef SMALL_KERNEL /* MSIX/Multiqueue functions */ @@ -409,6 +410,8 @@ em_attach(struct device *parent, struct device *self, void *aux) timeout_set(&sc->timer_handle, em_local_timer, sc); timeout_set(&sc->tx_fifo_timer_handle, em_82547_move_tail, sc); + rw_init(&sc->sfflock, "emsff"); + /* Determine hardware revision */ em_identify_hardware(sc); @@ -764,6 +767,15 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) NULL, EM_MCLBYTES, &sc->queues->rx.sc_rx_ring); break; + case SIOCGIFSFFPAGE: + error = rw_enter(&sc->sfflock, RW_WRITE|RW_INTR); + if (error != 0) + break; + + error = em_get_sffpage(sc, (struct if_sffpage *)data); + rw_exit(&sc->sfflock); + break; + default: error = ether_ioctl(ifp, &sc->sc_ac, command, data); } @@ -4028,3 +4040,31 @@ em_allocate_desc_rings(struct em_softc *sc) return (0); } + +int +em_get_sffpage(struct em_softc *sc, struct if_sffpage *sff) +{ + struct em_hw *hw = &sc->hw; + size_t i; + int off; + + if (hw->mac_type != em_82575 && hw->mac_type != em_82580 && + hw->mac_type != em_82576 && + hw->mac_type != em_i210 && hw->mac_type != em_i350) + return (ENODEV); + + if (sff->sff_addr == IFSFF_ADDR_EEPROM) + off = E1000_I2CCMD_SFP_DATA_ADDR(0); + else if (sff->sff_addr == IFSFF_ADDR_DDM) + off = E1000_I2CCMD_SFP_DIAG_ADDR(0); + else + return (EIO); + + for (i = 0; i < sizeof(sff->sff_data); i++) { + if (em_read_sfp_data_byte(hw, off + i, + &sff->sff_data[i]) != E1000_SUCCESS) + return (EIO); + } + + return (0); +} diff --git a/sys/dev/pci/if_em.h b/sys/dev/pci/if_em.h index f9aa5997506..dc8a985fe4a 100644 --- a/sys/dev/pci/if_em.h +++ b/sys/dev/pci/if_em.h @@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ /* $FreeBSD: if_em.h,v 1.26 2004/09/01 23:22:41 pdeuskar Exp $ */ -/* $OpenBSD: if_em.h,v 1.78 2020/07/13 10:35:55 dlg Exp $ */ +/* $OpenBSD: if_em.h,v 1.79 2021/12/14 10:48:10 patrick Exp $ */ #ifndef _EM_H_DEFINED_ #define _EM_H_DEFINED_ @@ -405,6 +405,7 @@ struct em_softc { u_int32_t tx_abs_int_delay; u_int32_t rx_int_delay; u_int32_t rx_abs_int_delay; + struct rwlock sfflock; u_int sc_tx_slots; u_int sc_rx_slots; diff --git a/sys/dev/pci/if_em_hw.c b/sys/dev/pci/if_em_hw.c index 34202c596db..4ee98572be7 100644 --- a/sys/dev/pci/if_em_hw.c +++ b/sys/dev/pci/if_em_hw.c @@ -31,7 +31,7 @@ *******************************************************************************/ -/* $OpenBSD: if_em_hw.c,v 1.110 2021/01/24 10:21:43 jsg Exp $ */ +/* $OpenBSD: if_em_hw.c,v 1.111 2021/12/14 10:48:10 patrick Exp $ */ /* * if_em_hw.c Shared functions for accessing and configuring the MAC */ @@ -724,6 +724,75 @@ em_set_mac_type(struct em_hw *hw) return E1000_SUCCESS; } +/** + * em_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 int32_t em_set_sfp_media_type_82575(struct em_hw *hw) +{ + struct sfp_e1000_flags eth_flags; + int32_t ret_val = E1000_ERR_CONFIG; + uint32_t ctrl_ext = 0; + uint8_t tranceiver_type = 0; + int32_t timeout = 3; + + /* Turn I2C interface ON and power on sfp cage */ + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + ctrl_ext &= ~E1000_CTRL_EXT_SDP3_DATA; + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext | E1000_CTRL_I2C_ENA); + + E1000_WRITE_FLUSH(hw); + + /* Read SFP module data */ + while (timeout) { + ret_val = em_read_sfp_data_byte(hw, + E1000_I2CCMD_SFP_DATA_ADDR(E1000_SFF_IDENTIFIER_OFFSET), + &tranceiver_type); + if (ret_val == E1000_SUCCESS) + break; + msec_delay(100); + timeout--; + } + if (ret_val != E1000_SUCCESS) + goto out; + + ret_val = em_read_sfp_data_byte(hw, + E1000_I2CCMD_SFP_DATA_ADDR(E1000_SFF_ETH_FLAGS_OFFSET), + (uint8_t *)ð_flags); + if (ret_val != E1000_SUCCESS) + 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)) { + if (eth_flags.e1000_base_lx || eth_flags.e1000_base_sx) { + hw->media_type = em_media_type_internal_serdes; + } else if (eth_flags.e100_base_fx || eth_flags.e100_base_lx) { + hw->media_type = em_media_type_internal_serdes; + hw->sgmii_active = TRUE; + } else if (eth_flags.e1000_base_t) { + hw->media_type = em_media_type_copper; + hw->sgmii_active = TRUE; + } else { + DEBUGOUT("PHY module has not been recognized\n"); + ret_val = E1000_ERR_CONFIG; + goto out; + } + } else { + ret_val = E1000_ERR_CONFIG; + goto out; + } + ret_val = E1000_SUCCESS; +out: + /* Restore I2C interface setting */ + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + return ret_val; +} + + /***************************************************************************** * Set media type and TBI compatibility. * @@ -732,7 +801,7 @@ em_set_mac_type(struct em_hw *hw) void em_set_media_type(struct em_hw *hw) { - uint32_t status, ctrl_ext; + uint32_t status, ctrl_ext, mdic; DEBUGFUNC("em_set_media_type"); if (hw->mac_type != em_82543) { @@ -744,16 +813,39 @@ em_set_media_type(struct em_hw *hw) hw->mac_type == em_82576 || hw->mac_type == em_i210 || hw->mac_type == em_i350) { hw->media_type = em_media_type_copper; - + hw->sgmii_active = FALSE; + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) { - case E1000_CTRL_EXT_LINK_MODE_SGMII: + case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX: + hw->media_type = em_media_type_internal_serdes; ctrl_ext |= E1000_CTRL_I2C_ENA; break; - case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX: + case E1000_CTRL_EXT_LINK_MODE_SGMII: + mdic = EM_READ_REG(hw, E1000_MDICNFG); + ctrl_ext |= E1000_CTRL_I2C_ENA; + if (mdic & E1000_MDICNFG_EXT_MDIO) { + hw->media_type = em_media_type_copper; + hw->sgmii_active = TRUE; + break; + } + /* FALLTHROUGH */ case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES: - hw->media_type = em_media_type_internal_serdes; ctrl_ext |= E1000_CTRL_I2C_ENA; + if (em_set_sfp_media_type_82575(hw) != 0) { + hw->media_type = em_media_type_internal_serdes; + if ((ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) == + E1000_CTRL_EXT_LINK_MODE_SGMII) { + hw->media_type = em_media_type_copper; + hw->sgmii_active = TRUE; + } + } + + ctrl_ext &= ~E1000_CTRL_EXT_LINK_MODE_MASK; + if (hw->sgmii_active) + ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_SGMII; + else + ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; break; default: ctrl_ext &= ~E1000_CTRL_I2C_ENA; @@ -1976,6 +2068,10 @@ em_power_up_serdes_link_82575(struct em_hw *hw) { uint32_t reg; + if (hw->media_type != em_media_type_internal_serdes && + hw->sgmii_active == FALSE) + return; + /* Enable PCS to turn on link */ reg = E1000_READ_REG(hw, PCS_CFG0); reg |= E1000_PCS_CFG_PCS_EN; @@ -2010,6 +2106,11 @@ em_setup_fiber_serdes_link(struct em_hw *hw) uint32_t signal = 0; int32_t ret_val; DEBUGFUNC("em_setup_fiber_serdes_link"); + + if (hw->media_type != em_media_type_internal_serdes && + hw->sgmii_active == FALSE) + return -E1000_ERR_CONFIG; + /* * On 82571 and 82572 Fiber connections, SerDes loopback mode * persists until explicitly turned off or a power cycle is @@ -5066,6 +5167,14 @@ em_read_phy_reg_ex(struct em_hw *hw, uint32_t reg_addr, uint16_t *phy_data) uint32_t mdic = 0; DEBUGFUNC("em_read_phy_reg_ex"); + /* SGMII active is only set on some specific chips */ + if (hw->sgmii_active && !em_sgmii_uses_mdio_82575(hw)) { + if (reg_addr > E1000_MAX_SGMII_PHY_REG_ADDR) { + DEBUGOUT1("PHY Address %d is out of range\n", reg_addr); + return -E1000_ERR_PARAM; + } + return em_read_phy_reg_i2c(hw, reg_addr, phy_data); + } if (reg_addr > MAX_PHY_REG_ADDRESS) { DEBUGOUT1("PHY Address %d is out of range\n", reg_addr); return -E1000_ERR_PARAM; @@ -5227,6 +5336,14 @@ em_write_phy_reg_ex(struct em_hw *hw, uint32_t reg_addr, uint16_t phy_data) uint32_t mdic = 0; DEBUGFUNC("em_write_phy_reg_ex"); + /* SGMII active is only set on some specific chips */ + if (hw->sgmii_active && !em_sgmii_uses_mdio_82575(hw)) { + if (reg_addr > E1000_MAX_SGMII_PHY_REG_ADDR) { + DEBUGOUT1("PHY Address %d is out of range\n", reg_addr); + return -E1000_ERR_PARAM; + } + return em_write_phy_reg_i2c(hw, reg_addr, phy_data); + } if (reg_addr > MAX_PHY_REG_ADDRESS) { DEBUGOUT1("PHY Address %d is out of range\n", reg_addr); return -E1000_ERR_PARAM; @@ -5337,6 +5454,195 @@ em_write_kmrn_reg(struct em_hw *hw, uint32_t reg_addr, uint16_t data) return E1000_SUCCESS; } +/** + * em_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO + * @hw: pointer to the HW structure + * + * Called to determine if the I2C pins are being used for I2C or as an + * external MDIO interface since the two options are mutually exclusive. + **/ +int em_sgmii_uses_mdio_82575(struct em_hw *hw) +{ + uint32_t reg = 0; + int ext_mdio = 0; + + DEBUGFUNC("em_sgmii_uses_mdio_82575"); + + switch (hw->mac_type) { + case em_82575: + case em_82576: + reg = E1000_READ_REG(hw, MDIC); + ext_mdio = !!(reg & E1000_MDIC_DEST); + break; + case em_82580: + case em_i350: + case em_i210: + reg = E1000_READ_REG(hw, MDICNFG); + ext_mdio = !!(reg & E1000_MDICNFG_EXT_MDIO); + break; + default: + break; + } + return ext_mdio; +} + +/** + * em_read_phy_reg_i2c - Read PHY register using i2c + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the PHY register at offset using the i2c interface and stores the + * retrieved information in data. + **/ +int32_t em_read_phy_reg_i2c(struct em_hw *hw, uint32_t offset, uint16_t *data) +{ + uint32_t i, i2ccmd = 0; + + DEBUGFUNC("em_read_phy_reg_i2c"); + + /* Set up Op-code, Phy Address, and register address in the I2CCMD + * register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) | + (hw->phy_addr << E1000_I2CCMD_PHY_ADDR_SHIFT) | + (E1000_I2CCMD_OPCODE_READ)); + + E1000_WRITE_REG(hw, I2CCMD, i2ccmd); + + /* Poll the ready bit to see if the I2C read completed */ + for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) { + usec_delay(50); + i2ccmd = E1000_READ_REG(hw, I2CCMD); + if (i2ccmd & E1000_I2CCMD_READY) + break; + } + if (!(i2ccmd & E1000_I2CCMD_READY)) { + DEBUGOUT("I2CCMD Read did not complete\n"); + return -E1000_ERR_PHY; + } + if (i2ccmd & E1000_I2CCMD_ERROR) { + DEBUGOUT("I2CCMD Error bit set\n"); + return -E1000_ERR_PHY; + } + + /* Need to byte-swap the 16-bit value. */ + *data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00); + + return E1000_SUCCESS; +} + +/** + * em_write_phy_reg_i2c - Write PHY register using i2c + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Writes the data to PHY register at the offset using the i2c interface. + **/ +int32_t em_write_phy_reg_i2c(struct em_hw *hw, uint32_t offset, uint16_t data) +{ + uint32_t i, i2ccmd = 0; + uint16_t phy_data_swapped; + + DEBUGFUNC("em_write_phy_reg_i2c"); + + /* Prevent overwritting SFP I2C EEPROM which is at A0 address.*/ + if ((hw->phy_addr == 0) || (hw->phy_addr > 7)) { + DEBUGOUT1("PHY I2C Address %d is out of range.\n", + hw->phy_addr); + return -E1000_ERR_CONFIG; + } + + /* Swap the data bytes for the I2C interface */ + phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00); + + /* Set up Op-code, Phy Address, and register address in the I2CCMD + * register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) | + (hw->phy_addr << E1000_I2CCMD_PHY_ADDR_SHIFT) | + E1000_I2CCMD_OPCODE_WRITE | + phy_data_swapped); + + E1000_WRITE_REG(hw, I2CCMD, i2ccmd); + + /* Poll the ready bit to see if the I2C read completed */ + for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) { + usec_delay(50); + i2ccmd = E1000_READ_REG(hw, I2CCMD); + if (i2ccmd & E1000_I2CCMD_READY) + break; + } + if (!(i2ccmd & E1000_I2CCMD_READY)) { + DEBUGOUT("I2CCMD Write did not complete\n"); + return -E1000_ERR_PHY; + } + if (i2ccmd & E1000_I2CCMD_ERROR) { + DEBUGOUT("I2CCMD Error bit set\n"); + return -E1000_ERR_PHY; + } + + return E1000_SUCCESS; +} + +/** + * em_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() for SFP module database access + * E1000_I2CCMD_SFP_DIAG_ADDR() for SFP diagnostics parameters + * access + **/ +int32_t em_read_sfp_data_byte(struct em_hw *hw, uint16_t offset, uint8_t *data) +{ + uint32_t i = 0; + uint32_t i2ccmd = 0; + uint32_t data_local = 0; + + DEBUGFUNC("em_read_sfp_data_byte"); + + if (offset > E1000_I2CCMD_SFP_DIAG_ADDR(255)) { + DEBUGOUT("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); + + E1000_WRITE_REG(hw, I2CCMD, i2ccmd); + + /* Poll the ready bit to see if the I2C read completed */ + for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) { + usec_delay(50); + data_local = E1000_READ_REG(hw, I2CCMD); + if (data_local & E1000_I2CCMD_READY) + break; + } + if (!(data_local & E1000_I2CCMD_READY)) { + DEBUGOUT("I2CCMD Read did not complete\n"); + return -E1000_ERR_PHY; + } + if (data_local & E1000_I2CCMD_ERROR) { + DEBUGOUT("I2CCMD Error bit set\n"); + return -E1000_ERR_PHY; + } + *data = (uint8_t) data_local & 0xFF; + + return E1000_SUCCESS; +} + /****************************************************************************** * Returns the PHY to the power-on reset state * @@ -5713,16 +6019,19 @@ em_match_gig_phy(struct em_hw *hw) hw->phy_id == I210_I_PHY_ID || hw->phy_id == I347AT4_E_PHY_ID || hw->phy_id == I350_I_PHY_ID || + hw->phy_id == M88E1111_I_PHY_ID || hw->phy_id == M88E1112_E_PHY_ID || hw->phy_id == M88E1543_E_PHY_ID || hw->phy_id == M88E1512_E_PHY_ID) { uint32_t mdic; mdic = EM_READ_REG(hw, E1000_MDICNFG); - mdic &= E1000_MDICNFG_PHY_MASK; - hw->phy_addr = mdic >> E1000_MDICNFG_PHY_SHIFT; - DEBUGOUT1("MDICNFG PHY ADDR %d", - mdic >> E1000_MDICNFG_PHY_SHIFT); + if (mdic & E1000_MDICNFG_EXT_MDIO) { + mdic &= E1000_MDICNFG_PHY_MASK; + hw->phy_addr = mdic >> E1000_MDICNFG_PHY_SHIFT; + DEBUGOUT1("MDICNFG PHY ADDR %d", + mdic >> E1000_MDICNFG_PHY_SHIFT); + } match = TRUE; } break; @@ -5858,11 +6167,12 @@ em_detect_gig_phy(struct em_hw *hw) uint32_t ctrl_ext = EM_READ_REG(hw, E1000_CTRL_EXT); EM_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext & ~E1000_CTRL_EXT_SDP3_DATA); - delay(300); + E1000_WRITE_FLUSH(hw); + msec_delay(300); } /* Read the PHY ID Registers to identify which PHY is onboard. */ - for (i = 1; i < 4; i++) { + for (i = 1; i < 8; i++) { /* * hw->phy_addr may be modified down in the call stack, * we can't use it as loop variable. diff --git a/sys/dev/pci/if_em_hw.h b/sys/dev/pci/if_em_hw.h index 443889fd01b..af176c4f05c 100644 --- a/sys/dev/pci/if_em_hw.h +++ b/sys/dev/pci/if_em_hw.h @@ -31,7 +31,7 @@ *******************************************************************************/ -/* $OpenBSD: if_em_hw.h,v 1.84 2021/01/24 10:21:43 jsg Exp $ */ +/* $OpenBSD: if_em_hw.h,v 1.85 2021/12/14 10:48:10 patrick Exp $ */ /* $FreeBSD: if_em_hw.h,v 1.15 2005/05/26 23:32:02 tackerman Exp $ */ /* if_em_hw.h @@ -361,6 +361,10 @@ int32_t em_phy_reset(struct em_hw *hw); int32_t em_phy_get_info(struct em_hw *hw, struct em_phy_info *phy_info); int32_t em_validate_mdi_setting(struct em_hw *hw); void em_phy_powerdown_workaround(struct em_hw *hw); +int em_sgmii_uses_mdio_82575(struct em_hw *); +int32_t em_read_phy_reg_i2c(struct em_hw *, uint32_t, uint16_t *); +int32_t em_write_phy_reg_i2c(struct em_hw *, uint32_t, uint16_t); +int32_t em_read_sfp_data_byte(struct em_hw *, uint16_t, uint8_t *); /* EEPROM Functions */ int32_t em_init_eeprom_params(struct em_hw *hw); @@ -1095,6 +1099,7 @@ struct em_ffvt_entry { #define E1000_FLSWDATA 0x01034 /* FLASH data register */ #define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */ #define E1000_FLOP 0x0103C /* FLASH Opcode Register */ +#define E1000_I2CCMD 0x01028 /* SFPI2C Command Register - RW */ #define E1000_ERT 0x02008 /* Early Rx Threshold - RW */ #define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ #define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ @@ -1492,6 +1497,7 @@ struct em_hw { uint16_t swfw; boolean_t eee_enable; int sw_flag; + boolean_t sgmii_active; }; #define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */ @@ -1528,6 +1534,16 @@ struct em_hw { #define E1000_CTRL_LANPHYPC_VALUE 0x00020000 /* SW value of LANPHYPC */ #define E1000_CTRL_EXT_FORCE_SMBUS 0x00000800 /* Force SMBus mode */ #define E1000_CTRL_EXT_PHYPDEN 0x00100000 +#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_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ #define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ @@ -3790,4 +3806,28 @@ union ich8_hws_flash_regacc { (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\ ~MAX_PHY_REG_ADDRESS))) +/* 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 sfp_e1000_flags { + uint8_t e1000_base_sx:1; + uint8_t e1000_base_lx:1; + uint8_t e1000_base_cx:1; + uint8_t e1000_base_t:1; + uint8_t e100_base_lx:1; + uint8_t e100_base_fx:1; + uint8_t e10_base_bx10:1; + uint8_t e10_base_px:1; +}; + +/* Vendor OUIs: format of OUI is 0x[byte0][byte1][byte2][00] */ +#define E1000_SFF_VENDOR_OUI_TYCO 0x00407600 +#define E1000_SFF_VENDOR_OUI_FTL 0x00906500 +#define E1000_SFF_VENDOR_OUI_AVAGO 0x00176A00 +#define E1000_SFF_VENDOR_OUI_INTEL 0x001B2100 + #endif /* _EM_HW_H_ */ -- 2.20.1