From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 8777CA04DC; Mon, 19 Oct 2020 10:59:27 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 573C3C94A; Mon, 19 Oct 2020 10:53:19 +0200 (CEST) Received: from smtpbgbr2.qq.com (smtpbgbr2.qq.com [54.207.22.56]) by dpdk.org (Postfix) with ESMTP id A3388C84C for ; Mon, 19 Oct 2020 10:52:55 +0200 (CEST) X-QQ-mid: bizesmtp6t1603097560tphh3lojx Received: from localhost.localdomain.com (unknown [183.129.236.74]) by esmtp6.qq.com (ESMTP) with id ; Mon, 19 Oct 2020 16:52:40 +0800 (CST) X-QQ-SSF: 01400000002000C0C000B00A0000000 X-QQ-FEAT: Me8y4DzRu2SYL7qGmCuUBZBHH2qxECPZcK8OKY0I3UwrhUsUjvdnhX4F0uCXY eTFKSd2U1MQiQ2U5m7ugEp7yw7FzUZ+vI41Iv4rGR8y8ZzV8qWVfFhwA+geolKwvPaQ1ldl MOyud4d6EE/9Ykjf+k26b6y8bGsKq+p7qzSlGdHnq7KLzAXFzfv990zJ5YaMqJu7q6+HXq3 0W49Ko4OOYCXe1u24BlgbJSJUIBtfz7D5azagOauViWTfaEjQXtKJUcsjY+45Rj4v0Z3W2+ lnr+d46N8HZ5nry3azubdyOewdEGNTNiFzZxUDq1Gcu40B7m6YBjdIQAqjMvmVHIIdC6MxS fwp/ERbWDfbjXDbmFqdfXlUO0MRzQ== X-QQ-GoodBg: 2 From: Jiawen Wu To: dev@dpdk.org Cc: Jiawen Wu Date: Mon, 19 Oct 2020 16:53:27 +0800 Message-Id: <20201019085415.82207-11-jiawenwu@trustnetic.com> X-Mailer: git-send-email 2.18.4 In-Reply-To: <20201019085415.82207-1-jiawenwu@trustnetic.com> References: <20201019085415.82207-1-jiawenwu@trustnetic.com> X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:trustnetic.com:qybgforeign:qybgforeign5 X-QQ-Bgrelay: 1 Subject: [dpdk-dev] [PATCH v4 10/58] net/txgbe: add module identify X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add sfp anf qsfp module identify, i2c start and stop. Signed-off-by: Jiawen Wu --- drivers/net/txgbe/base/txgbe_eeprom.h | 1 + drivers/net/txgbe/base/txgbe_hw.c | 4 + drivers/net/txgbe/base/txgbe_phy.c | 588 +++++++++++++++++++++++++- drivers/net/txgbe/base/txgbe_phy.h | 12 + drivers/net/txgbe/base/txgbe_type.h | 1 + 5 files changed, 603 insertions(+), 3 deletions(-) diff --git a/drivers/net/txgbe/base/txgbe_eeprom.h b/drivers/net/txgbe/base/txgbe_eeprom.h index 137fb1c30..25d03421c 100644 --- a/drivers/net/txgbe/base/txgbe_eeprom.h +++ b/drivers/net/txgbe/base/txgbe_eeprom.h @@ -23,6 +23,7 @@ #define TXGBE_EEPROM_VERSION_H 0x1E #define TXGBE_ISCSI_BOOT_CONFIG 0x07 +#define TXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 s32 txgbe_init_eeprom_params(struct txgbe_hw *hw); s32 txgbe_calc_eeprom_checksum(struct txgbe_hw *hw); diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c index a067192fa..d2d12a929 100644 --- a/drivers/net/txgbe/base/txgbe_hw.c +++ b/drivers/net/txgbe/base/txgbe_hw.c @@ -291,6 +291,10 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) /* PHY */ phy->identify = txgbe_identify_phy; phy->init = txgbe_init_phy_raptor; + phy->read_i2c_byte = txgbe_read_i2c_byte; + phy->write_i2c_byte = txgbe_write_i2c_byte; + phy->read_i2c_eeprom = txgbe_read_i2c_eeprom; + phy->write_i2c_eeprom = txgbe_write_i2c_eeprom; /* MAC */ mac->init_hw = txgbe_init_hw; diff --git a/drivers/net/txgbe/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c index 2ed497c48..b36bffcac 100644 --- a/drivers/net/txgbe/base/txgbe_phy.c +++ b/drivers/net/txgbe/base/txgbe_phy.c @@ -7,6 +7,9 @@ #include "txgbe_mng.h" #include "txgbe_phy.h" +static void txgbe_i2c_start(struct txgbe_hw *hw); +static void txgbe_i2c_stop(struct txgbe_hw *hw); + /** * txgbe_identify_extphy - Identify a single address for a PHY * @hw: pointer to hardware structure @@ -234,8 +237,204 @@ s32 txgbe_identify_module(struct txgbe_hw *hw) **/ s32 txgbe_identify_sfp_module(struct txgbe_hw *hw) { - RTE_SET_USED(hw); - return 0; + s32 err = TXGBE_ERR_PHY_ADDR_INVALID; + u32 vendor_oui = 0; + enum txgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; + u8 identifier = 0; + u8 comp_codes_1g = 0; + u8 comp_codes_10g = 0; + u8 oui_bytes[3] = {0, 0, 0}; + u8 cable_tech = 0; + u8 cable_spec = 0; + u16 enforce_sfp = 0; + + DEBUGFUNC("txgbe_identify_sfp_module"); + + if (hw->phy.media_type != txgbe_media_type_fiber) { + hw->phy.sfp_type = txgbe_sfp_type_not_present; + return TXGBE_ERR_SFP_NOT_PRESENT; + } + + err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_IDENTIFIER, + &identifier); + if (err != 0) { +ERR_I2C: + hw->phy.sfp_type = txgbe_sfp_type_not_present; + if (hw->phy.type != txgbe_phy_nl) { + hw->phy.id = 0; + hw->phy.type = txgbe_phy_unknown; + } + return TXGBE_ERR_SFP_NOT_PRESENT; + } + + if (identifier != TXGBE_SFF_IDENTIFIER_SFP) { + hw->phy.type = txgbe_phy_sfp_unsupported; + return TXGBE_ERR_SFP_NOT_SUPPORTED; + } + + err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_1GBE_COMP_CODES, + &comp_codes_1g); + if (err != 0) + goto ERR_I2C; + + err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_10GBE_COMP_CODES, + &comp_codes_10g); + if (err != 0) + goto ERR_I2C; + + err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_CABLE_TECHNOLOGY, + &cable_tech); + if (err != 0) + goto ERR_I2C; + + /* ID Module + * ========= + * 0 SFP_DA_CU + * 1 SFP_SR + * 2 SFP_LR + * 3 SFP_DA_CORE0 - chip-specific + * 4 SFP_DA_CORE1 - chip-specific + * 5 SFP_SR/LR_CORE0 - chip-specific + * 6 SFP_SR/LR_CORE1 - chip-specific + * 7 SFP_act_lmt_DA_CORE0 - chip-specific + * 8 SFP_act_lmt_DA_CORE1 - chip-specific + * 9 SFP_1g_cu_CORE0 - chip-specific + * 10 SFP_1g_cu_CORE1 - chip-specific + * 11 SFP_1g_sx_CORE0 - chip-specific + * 12 SFP_1g_sx_CORE1 - chip-specific + */ + if (cable_tech & TXGBE_SFF_CABLE_DA_PASSIVE) { + if (hw->bus.lan_id == 0) + hw->phy.sfp_type = txgbe_sfp_type_da_cu_core0; + else + hw->phy.sfp_type = txgbe_sfp_type_da_cu_core1; + } else if (cable_tech & TXGBE_SFF_CABLE_DA_ACTIVE) { + err = hw->phy.read_i2c_eeprom(hw, + TXGBE_SFF_CABLE_SPEC_COMP, &cable_spec); + if (err != 0) + goto ERR_I2C; + if (cable_spec & TXGBE_SFF_DA_SPEC_ACTIVE_LIMITING) { + hw->phy.sfp_type = (hw->bus.lan_id == 0 + ? txgbe_sfp_type_da_act_lmt_core0 + : txgbe_sfp_type_da_act_lmt_core1); + } else { + hw->phy.sfp_type = txgbe_sfp_type_unknown; + } + } else if (comp_codes_10g & + (TXGBE_SFF_10GBASESR_CAPABLE | + TXGBE_SFF_10GBASELR_CAPABLE)) { + hw->phy.sfp_type = (hw->bus.lan_id == 0 + ? txgbe_sfp_type_srlr_core0 + : txgbe_sfp_type_srlr_core1); + } else if (comp_codes_1g & TXGBE_SFF_1GBASET_CAPABLE) { + hw->phy.sfp_type = (hw->bus.lan_id == 0 + ? txgbe_sfp_type_1g_cu_core0 + : txgbe_sfp_type_1g_cu_core1); + } else if (comp_codes_1g & TXGBE_SFF_1GBASESX_CAPABLE) { + hw->phy.sfp_type = (hw->bus.lan_id == 0 + ? txgbe_sfp_type_1g_sx_core0 + : txgbe_sfp_type_1g_sx_core1); + } else if (comp_codes_1g & TXGBE_SFF_1GBASELX_CAPABLE) { + hw->phy.sfp_type = (hw->bus.lan_id == 0 + ? txgbe_sfp_type_1g_lx_core0 + : txgbe_sfp_type_1g_lx_core1); + } else { + hw->phy.sfp_type = txgbe_sfp_type_unknown; + } + + if (hw->phy.sfp_type != stored_sfp_type) + hw->phy.sfp_setup_needed = true; + + /* Determine if the SFP+ PHY is dual speed or not. */ + hw->phy.multispeed_fiber = false; + if (((comp_codes_1g & TXGBE_SFF_1GBASESX_CAPABLE) && + (comp_codes_10g & TXGBE_SFF_10GBASESR_CAPABLE)) || + ((comp_codes_1g & TXGBE_SFF_1GBASELX_CAPABLE) && + (comp_codes_10g & TXGBE_SFF_10GBASELR_CAPABLE))) + hw->phy.multispeed_fiber = true; + + /* Determine PHY vendor */ + if (hw->phy.type != txgbe_phy_nl) { + hw->phy.id = identifier; + err = hw->phy.read_i2c_eeprom(hw, + TXGBE_SFF_VENDOR_OUI_BYTE0, &oui_bytes[0]); + if (err != 0) + goto ERR_I2C; + + err = hw->phy.read_i2c_eeprom(hw, + TXGBE_SFF_VENDOR_OUI_BYTE1, &oui_bytes[1]); + if (err != 0) + goto ERR_I2C; + + err = hw->phy.read_i2c_eeprom(hw, + TXGBE_SFF_VENDOR_OUI_BYTE2, &oui_bytes[2]); + if (err != 0) + goto ERR_I2C; + + vendor_oui = ((u32)oui_bytes[0] << 24) | + ((u32)oui_bytes[1] << 16) | + ((u32)oui_bytes[2] << 8); + switch (vendor_oui) { + case TXGBE_SFF_VENDOR_OUI_TYCO: + if (cable_tech & TXGBE_SFF_CABLE_DA_PASSIVE) + hw->phy.type = txgbe_phy_sfp_tyco_passive; + break; + case TXGBE_SFF_VENDOR_OUI_FTL: + if (cable_tech & TXGBE_SFF_CABLE_DA_ACTIVE) + hw->phy.type = txgbe_phy_sfp_ftl_active; + else + hw->phy.type = txgbe_phy_sfp_ftl; + break; + case TXGBE_SFF_VENDOR_OUI_AVAGO: + hw->phy.type = txgbe_phy_sfp_avago; + break; + case TXGBE_SFF_VENDOR_OUI_INTEL: + hw->phy.type = txgbe_phy_sfp_intel; + break; + default: + if (cable_tech & TXGBE_SFF_CABLE_DA_PASSIVE) + hw->phy.type = txgbe_phy_sfp_unknown_passive; + else if (cable_tech & TXGBE_SFF_CABLE_DA_ACTIVE) + hw->phy.type = txgbe_phy_sfp_unknown_active; + else + hw->phy.type = txgbe_phy_sfp_unknown; + break; + } + } + + /* Allow any DA cable vendor */ + if (cable_tech & (TXGBE_SFF_CABLE_DA_PASSIVE | + TXGBE_SFF_CABLE_DA_ACTIVE)) { + return 0; + } + + /* Verify supported 1G SFP modules */ + if (comp_codes_10g == 0 && + !(hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core1 || + hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core0 || + hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core0 || + hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core1 || + hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core0 || + hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core1)) { + hw->phy.type = txgbe_phy_sfp_unsupported; + return TXGBE_ERR_SFP_NOT_SUPPORTED; + } + + hw->mac.get_device_caps(hw, &enforce_sfp); + if (!(enforce_sfp & TXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) && + !hw->allow_unsupported_sfp && + !(hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core0 || + hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core1 || + hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core0 || + hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core1 || + hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core0 || + hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core1)) { + DEBUGOUT("SFP+ module not supported\n"); + hw->phy.type = txgbe_phy_sfp_unsupported; + return TXGBE_ERR_SFP_NOT_SUPPORTED; + } + + return err; } /** @@ -246,7 +445,390 @@ s32 txgbe_identify_sfp_module(struct txgbe_hw *hw) **/ s32 txgbe_identify_qsfp_module(struct txgbe_hw *hw) { - RTE_SET_USED(hw); + s32 err = TXGBE_ERR_PHY_ADDR_INVALID; + u32 vendor_oui = 0; + enum txgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; + u8 identifier = 0; + u8 comp_codes_1g = 0; + u8 comp_codes_10g = 0; + u8 oui_bytes[3] = {0, 0, 0}; + u16 enforce_sfp = 0; + u8 connector = 0; + u8 cable_length = 0; + u8 device_tech = 0; + bool active_cable = false; + + DEBUGFUNC("txgbe_identify_qsfp_module"); + + if (hw->phy.media_type != txgbe_media_type_fiber_qsfp) { + hw->phy.sfp_type = txgbe_sfp_type_not_present; + err = TXGBE_ERR_SFP_NOT_PRESENT; + goto out; + } + + err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_IDENTIFIER, + &identifier); +ERR_I2C: + if (err != 0) { + hw->phy.sfp_type = txgbe_sfp_type_not_present; + hw->phy.id = 0; + hw->phy.type = txgbe_phy_unknown; + return TXGBE_ERR_SFP_NOT_PRESENT; + } + if (identifier != TXGBE_SFF_IDENTIFIER_QSFP_PLUS) { + hw->phy.type = txgbe_phy_sfp_unsupported; + err = TXGBE_ERR_SFP_NOT_SUPPORTED; + goto out; + } + + hw->phy.id = identifier; + + err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_QSFP_10GBE_COMP, + &comp_codes_10g); + + if (err != 0) + goto ERR_I2C; + + err = hw->phy.read_i2c_eeprom(hw, TXGBE_SFF_QSFP_1GBE_COMP, + &comp_codes_1g); + + if (err != 0) + goto ERR_I2C; + + if (comp_codes_10g & TXGBE_SFF_QSFP_DA_PASSIVE_CABLE) { + hw->phy.type = txgbe_phy_qsfp_unknown_passive; + if (hw->bus.lan_id == 0) + hw->phy.sfp_type = txgbe_sfp_type_da_cu_core0; + else + hw->phy.sfp_type = txgbe_sfp_type_da_cu_core1; + } else if (comp_codes_10g & (TXGBE_SFF_10GBASESR_CAPABLE | + TXGBE_SFF_10GBASELR_CAPABLE)) { + if (hw->bus.lan_id == 0) + hw->phy.sfp_type = txgbe_sfp_type_srlr_core0; + else + hw->phy.sfp_type = txgbe_sfp_type_srlr_core1; + } else { + if (comp_codes_10g & TXGBE_SFF_QSFP_DA_ACTIVE_CABLE) + active_cable = true; + + if (!active_cable) { + hw->phy.read_i2c_eeprom(hw, + TXGBE_SFF_QSFP_CONNECTOR, + &connector); + + hw->phy.read_i2c_eeprom(hw, + TXGBE_SFF_QSFP_CABLE_LENGTH, + &cable_length); + + hw->phy.read_i2c_eeprom(hw, + TXGBE_SFF_QSFP_DEVICE_TECH, + &device_tech); + + if (connector == + TXGBE_SFF_QSFP_CONNECTOR_NOT_SEPARABLE && + cable_length > 0 && + ((device_tech >> 4) == + TXGBE_SFF_QSFP_TRANSMITTER_850NM_VCSEL)) + active_cable = true; + } + + if (active_cable) { + hw->phy.type = txgbe_phy_qsfp_unknown_active; + if (hw->bus.lan_id == 0) + hw->phy.sfp_type = + txgbe_sfp_type_da_act_lmt_core0; + else + hw->phy.sfp_type = + txgbe_sfp_type_da_act_lmt_core1; + } else { + /* unsupported module type */ + hw->phy.type = txgbe_phy_sfp_unsupported; + err = TXGBE_ERR_SFP_NOT_SUPPORTED; + goto out; + } + } + + if (hw->phy.sfp_type != stored_sfp_type) + hw->phy.sfp_setup_needed = true; + + /* Determine if the QSFP+ PHY is dual speed or not. */ + hw->phy.multispeed_fiber = false; + if (((comp_codes_1g & TXGBE_SFF_1GBASESX_CAPABLE) && + (comp_codes_10g & TXGBE_SFF_10GBASESR_CAPABLE)) || + ((comp_codes_1g & TXGBE_SFF_1GBASELX_CAPABLE) && + (comp_codes_10g & TXGBE_SFF_10GBASELR_CAPABLE))) + hw->phy.multispeed_fiber = true; + + /* Determine PHY vendor for optical modules */ + if (comp_codes_10g & (TXGBE_SFF_10GBASESR_CAPABLE | + TXGBE_SFF_10GBASELR_CAPABLE)) { + err = hw->phy.read_i2c_eeprom(hw, + TXGBE_SFF_QSFP_VENDOR_OUI_BYTE0, + &oui_bytes[0]); + + if (err != 0) + goto ERR_I2C; + + err = hw->phy.read_i2c_eeprom(hw, + TXGBE_SFF_QSFP_VENDOR_OUI_BYTE1, + &oui_bytes[1]); + + if (err != 0) + goto ERR_I2C; + + err = hw->phy.read_i2c_eeprom(hw, + TXGBE_SFF_QSFP_VENDOR_OUI_BYTE2, + &oui_bytes[2]); + + if (err != 0) + goto ERR_I2C; + + vendor_oui = + ((oui_bytes[0] << 24) | + (oui_bytes[1] << 16) | + (oui_bytes[2] << 8)); + + if (vendor_oui == TXGBE_SFF_VENDOR_OUI_INTEL) + hw->phy.type = txgbe_phy_qsfp_intel; + else + hw->phy.type = txgbe_phy_qsfp_unknown; + + hw->mac.get_device_caps(hw, &enforce_sfp); + if (!(enforce_sfp & TXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) { + /* Make sure we're a supported PHY type */ + if (hw->phy.type == txgbe_phy_qsfp_intel) { + err = 0; + } else { + if (hw->allow_unsupported_sfp) { + DEBUGOUT("WARNING: Wangxun (R) Network Connections are quality tested using Wangxun (R) Ethernet Optics. " + "Using untested modules is not supported and may cause unstable operation or damage to the module or the adapter. " + "Wangxun Corporation is not responsible for any harm caused by using untested modules.\n"); + err = 0; + } else { + DEBUGOUT("QSFP module not supported\n"); + hw->phy.type = + txgbe_phy_sfp_unsupported; + err = TXGBE_ERR_SFP_NOT_SUPPORTED; + } + } + } else { + err = 0; + } + } + +out: + return err; +} + +/** + * txgbe_read_i2c_eeprom - Reads 8 bit EEPROM word over I2C interface + * @hw: pointer to hardware structure + * @byte_offset: EEPROM byte offset to read + * @eeprom_data: value read + * + * Performs byte read operation to SFP module's EEPROM over I2C interface. + **/ +s32 txgbe_read_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset, + u8 *eeprom_data) +{ + DEBUGFUNC("txgbe_read_i2c_eeprom"); + + return hw->phy.read_i2c_byte(hw, byte_offset, + TXGBE_I2C_EEPROM_DEV_ADDR, + eeprom_data); +} + +/** + * txgbe_write_i2c_eeprom - Writes 8 bit EEPROM word over I2C interface + * @hw: pointer to hardware structure + * @byte_offset: EEPROM byte offset to write + * @eeprom_data: value to write + * + * Performs byte write operation to SFP module's EEPROM over I2C interface. + **/ +s32 txgbe_write_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset, + u8 eeprom_data) +{ + DEBUGFUNC("txgbe_write_i2c_eeprom"); + + return hw->phy.write_i2c_byte(hw, byte_offset, + TXGBE_I2C_EEPROM_DEV_ADDR, + eeprom_data); +} + +/** + * txgbe_read_i2c_byte_unlocked - Reads 8 bit word over I2C + * @hw: pointer to hardware structure + * @byte_offset: byte offset to read + * @dev_addr: address to read from + * @data: value read + * + * Performs byte read operation to SFP module's EEPROM over I2C interface at + * a specified device address. + **/ +s32 txgbe_read_i2c_byte_unlocked(struct txgbe_hw *hw, u8 byte_offset, + u8 dev_addr, u8 *data) +{ + UNREFERENCED_PARAMETER(dev_addr); + + DEBUGFUNC("txgbe_read_i2c_byte"); + + txgbe_i2c_start(hw); + + /* wait tx empty */ + if (!po32m(hw, TXGBE_I2CICR, TXGBE_I2CICR_TXEMPTY, + TXGBE_I2CICR_TXEMPTY, NULL, 100, 100)) { + return -TERR_TIMEOUT; + } + + /* read data */ + wr32(hw, TXGBE_I2CDATA, + byte_offset | TXGBE_I2CDATA_STOP); + wr32(hw, TXGBE_I2CDATA, TXGBE_I2CDATA_READ); + + /* wait for read complete */ + if (!po32m(hw, TXGBE_I2CICR, TXGBE_I2CICR_RXFULL, + TXGBE_I2CICR_RXFULL, NULL, 100, 100)) { + return -TERR_TIMEOUT; + } + + txgbe_i2c_stop(hw); + + *data = 0xFF & rd32(hw, TXGBE_I2CDATA); + + return 0; +} + +/** + * txgbe_read_i2c_byte - Reads 8 bit word over I2C + * @hw: pointer to hardware structure + * @byte_offset: byte offset to read + * @dev_addr: address to read from + * @data: value read + * + * Performs byte read operation to SFP module's EEPROM over I2C interface at + * a specified device address. + **/ +s32 txgbe_read_i2c_byte(struct txgbe_hw *hw, u8 byte_offset, + u8 dev_addr, u8 *data) +{ + u32 swfw_mask = hw->phy.phy_semaphore_mask; + int err = 0; + + if (hw->mac.acquire_swfw_sync(hw, swfw_mask)) + return TXGBE_ERR_SWFW_SYNC; + err = txgbe_read_i2c_byte_unlocked(hw, byte_offset, dev_addr, data); + hw->mac.release_swfw_sync(hw, swfw_mask); + return err; +} + +/** + * txgbe_write_i2c_byte_unlocked - Writes 8 bit word over I2C + * @hw: pointer to hardware structure + * @byte_offset: byte offset to write + * @dev_addr: address to write to + * @data: value to write + * + * Performs byte write operation to SFP module's EEPROM over I2C interface at + * a specified device address. + **/ +s32 txgbe_write_i2c_byte_unlocked(struct txgbe_hw *hw, u8 byte_offset, + u8 dev_addr, u8 data) +{ + UNREFERENCED_PARAMETER(dev_addr); + + DEBUGFUNC("txgbe_write_i2c_byte"); + + txgbe_i2c_start(hw); + + /* wait tx empty */ + if (!po32m(hw, TXGBE_I2CICR, TXGBE_I2CICR_TXEMPTY, + TXGBE_I2CICR_TXEMPTY, NULL, 100, 100)) { + return -TERR_TIMEOUT; + } + + wr32(hw, TXGBE_I2CDATA, byte_offset | TXGBE_I2CDATA_STOP); + wr32(hw, TXGBE_I2CDATA, data | TXGBE_I2CDATA_WRITE); + + /* wait for write complete */ + if (!po32m(hw, TXGBE_I2CICR, TXGBE_I2CICR_RXFULL, + TXGBE_I2CICR_RXFULL, NULL, 100, 100)) { + return -TERR_TIMEOUT; + } + txgbe_i2c_stop(hw); + return 0; } +/** + * txgbe_write_i2c_byte - Writes 8 bit word over I2C + * @hw: pointer to hardware structure + * @byte_offset: byte offset to write + * @dev_addr: address to write to + * @data: value to write + * + * Performs byte write operation to SFP module's EEPROM over I2C interface at + * a specified device address. + **/ +s32 txgbe_write_i2c_byte(struct txgbe_hw *hw, u8 byte_offset, + u8 dev_addr, u8 data) +{ + u32 swfw_mask = hw->phy.phy_semaphore_mask; + int err = 0; + + if (hw->mac.acquire_swfw_sync(hw, swfw_mask)) + return TXGBE_ERR_SWFW_SYNC; + err = txgbe_write_i2c_byte_unlocked(hw, byte_offset, dev_addr, data); + hw->mac.release_swfw_sync(hw, swfw_mask); + + return err; +} + +/** + * txgbe_i2c_start - Sets I2C start condition + * @hw: pointer to hardware structure + * + * Sets I2C start condition (High -> Low on SDA while SCL is High) + **/ +static void txgbe_i2c_start(struct txgbe_hw *hw) +{ + DEBUGFUNC("txgbe_i2c_start"); + + wr32(hw, TXGBE_I2CENA, 0); + + wr32(hw, TXGBE_I2CCON, + (TXGBE_I2CCON_MENA | + TXGBE_I2CCON_SPEED(1) | + TXGBE_I2CCON_RESTART | + TXGBE_I2CCON_SDIA)); + wr32(hw, TXGBE_I2CTAR, TXGBE_I2C_SLAVEADDR); + wr32(hw, TXGBE_I2CSSSCLHCNT, 600); + wr32(hw, TXGBE_I2CSSSCLLCNT, 600); + wr32(hw, TXGBE_I2CRXTL, 0); /* 1byte for rx full signal */ + wr32(hw, TXGBE_I2CTXTL, 4); + wr32(hw, TXGBE_I2CSCLTMOUT, 0xFFFFFF); + wr32(hw, TXGBE_I2CSDATMOUT, 0xFFFFFF); + + wr32(hw, TXGBE_I2CICM, 0); + wr32(hw, TXGBE_I2CENA, 1); +} + +/** + * txgbe_i2c_stop - Sets I2C stop condition + * @hw: pointer to hardware structure + * + * Sets I2C stop condition (Low -> High on SDA while SCL is High) + **/ +static void txgbe_i2c_stop(struct txgbe_hw *hw) +{ + DEBUGFUNC("txgbe_i2c_stop"); + + /* wait for completion */ + if (!po32m(hw, TXGBE_I2CSTAT, TXGBE_I2CSTAT_MST, + 0, NULL, 100, 100)) { + DEBUGFUNC("i2c stop timeout."); + } + + wr32(hw, TXGBE_I2CENA, 0); +} + diff --git a/drivers/net/txgbe/base/txgbe_phy.h b/drivers/net/txgbe/base/txgbe_phy.h index 544ab064e..3c3f2914a 100644 --- a/drivers/net/txgbe/base/txgbe_phy.h +++ b/drivers/net/txgbe/base/txgbe_phy.h @@ -332,5 +332,17 @@ s32 txgbe_identify_phy(struct txgbe_hw *hw); s32 txgbe_identify_module(struct txgbe_hw *hw); s32 txgbe_identify_sfp_module(struct txgbe_hw *hw); s32 txgbe_identify_qsfp_module(struct txgbe_hw *hw); +s32 txgbe_read_i2c_byte(struct txgbe_hw *hw, u8 byte_offset, + u8 dev_addr, u8 *data); +s32 txgbe_read_i2c_byte_unlocked(struct txgbe_hw *hw, u8 byte_offset, + u8 dev_addr, u8 *data); +s32 txgbe_write_i2c_byte(struct txgbe_hw *hw, u8 byte_offset, + u8 dev_addr, u8 data); +s32 txgbe_write_i2c_byte_unlocked(struct txgbe_hw *hw, u8 byte_offset, + u8 dev_addr, u8 data); +s32 txgbe_read_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset, + u8 *eeprom_data); +s32 txgbe_write_i2c_eeprom(struct txgbe_hw *hw, u8 byte_offset, + u8 eeprom_data); #endif /* _TXGBE_PHY_H_ */ diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h index b8e85063a..438734f8c 100644 --- a/drivers/net/txgbe/base/txgbe_type.h +++ b/drivers/net/txgbe/base/txgbe_type.h @@ -358,6 +358,7 @@ struct txgbe_phy_info { u32 media_type; u32 phy_semaphore_mask; bool reset_disable; + bool multispeed_fiber; bool qsfp_shared_i2c_bus; u32 nw_mng_if_sel; }; -- 2.18.4