From 52569256583a4018e6f15295db324d20314f8664 Mon Sep 17 00:00:00 2001 From: Steve Yang Date: Thu, 20 Jan 2022 02:59:30 +0000 Subject: [PATCH] net/ice: support module EEPROM Add new callbacks for eth_dev_ops of ice to get the information and data of plugin module EEPROM. Signed-off-by: Steve Yang Acked-by: Qi Zhang --- drivers/net/ice/ice_ethdev.c | 160 +++++++++++++++++++++++++++++++++++ drivers/net/ice/ice_ethdev.h | 25 ++++++ 2 files changed, 185 insertions(+) diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c index c9fd3de2bd..6d85e421cf 100644 --- a/drivers/net/ice/ice_ethdev.c +++ b/drivers/net/ice/ice_ethdev.c @@ -139,6 +139,10 @@ static int ice_vlan_pvid_set(struct rte_eth_dev *dev, static int ice_get_eeprom_length(struct rte_eth_dev *dev); static int ice_get_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *eeprom); +static int ice_get_module_info(struct rte_eth_dev *dev, + struct rte_eth_dev_module_info *modinfo); +static int ice_get_module_eeprom(struct rte_eth_dev *dev, + struct rte_dev_eeprom_info *info); static int ice_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats); static int ice_stats_reset(struct rte_eth_dev *dev); @@ -238,6 +242,8 @@ static const struct eth_dev_ops ice_eth_dev_ops = { .tx_burst_mode_get = ice_tx_burst_mode_get, .get_eeprom_length = ice_get_eeprom_length, .get_eeprom = ice_get_eeprom, + .get_module_info = ice_get_module_info, + .get_module_eeprom = ice_get_module_eeprom, .stats_get = ice_stats_get, .stats_reset = ice_stats_reset, .xstats_get = ice_xstats_get, @@ -4934,6 +4940,160 @@ ice_get_eeprom(struct rte_eth_dev *dev, return 0; } +static int +ice_get_module_info(struct rte_eth_dev *dev, + struct rte_eth_dev_module_info *modinfo) +{ + struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + enum ice_status status; + u8 sff8472_comp = 0; + u8 sff8472_swap = 0; + u8 sff8636_rev = 0; + u8 value = 0; + + status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR, 0x00, 0x00, + 0, &value, 1, 0, NULL); + if (status) + return -EIO; + + switch (value) { + case ICE_MODULE_TYPE_SFP: + status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR, + ICE_MODULE_SFF_8472_COMP, 0x00, 0, + &sff8472_comp, 1, 0, NULL); + if (status) + return -EIO; + status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR, + ICE_MODULE_SFF_8472_SWAP, 0x00, 0, + &sff8472_swap, 1, 0, NULL); + if (status) + return -EIO; + + if (sff8472_swap & ICE_MODULE_SFF_ADDR_MODE) { + modinfo->type = ICE_MODULE_SFF_8079; + modinfo->eeprom_len = ICE_MODULE_SFF_8079_LEN; + } else if (sff8472_comp && + (sff8472_swap & ICE_MODULE_SFF_DIAG_CAPAB)) { + modinfo->type = ICE_MODULE_SFF_8472; + modinfo->eeprom_len = ICE_MODULE_SFF_8472_LEN; + } else { + modinfo->type = ICE_MODULE_SFF_8079; + modinfo->eeprom_len = ICE_MODULE_SFF_8079_LEN; + } + break; + case ICE_MODULE_TYPE_QSFP_PLUS: + case ICE_MODULE_TYPE_QSFP28: + status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR, + ICE_MODULE_REVISION_ADDR, 0x00, 0, + &sff8636_rev, 1, 0, NULL); + if (status) + return -EIO; + /* Check revision compliance */ + if (sff8636_rev > 0x02) { + /* Module is SFF-8636 compliant */ + modinfo->type = ICE_MODULE_SFF_8636; + modinfo->eeprom_len = ICE_MODULE_QSFP_MAX_LEN; + } else { + modinfo->type = ICE_MODULE_SFF_8436; + modinfo->eeprom_len = ICE_MODULE_QSFP_MAX_LEN; + } + break; + default: + PMD_DRV_LOG(WARNING, "SFF Module Type not recognized.\n"); + return -EINVAL; + } + return 0; +} + +static int +ice_get_module_eeprom(struct rte_eth_dev *dev, + struct rte_dev_eeprom_info *info) +{ + struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private); +#define SFF_READ_BLOCK_SIZE 8 +#define I2C_BUSY_TRY_TIMES 4 +#define I2C_USLEEP_MIN_TIME 1500 +#define I2C_USLEEP_MAX_TIME 2500 + uint8_t value[SFF_READ_BLOCK_SIZE] = {0}; + uint8_t addr = ICE_I2C_EEPROM_DEV_ADDR; + uint8_t *data = info->data; + enum ice_status status; + bool is_sfp = false; + uint32_t i, j; + uint32_t offset = 0; + uint8_t page = 0; + + if (!info || !info->length || !data) + return -EINVAL; + + status = ice_aq_sff_eeprom(hw, 0, addr, offset, page, 0, value, 1, 0, + NULL); + if (status) + return -EIO; + + if (value[0] == ICE_MODULE_TYPE_SFP) + is_sfp = true; + + memset(data, 0, info->length); + for (i = 0; i < info->length; i += SFF_READ_BLOCK_SIZE) { + offset = i + info->offset; + page = 0; + + /* Check if we need to access the other memory page */ + if (is_sfp) { + if (offset >= ICE_MODULE_SFF_8079_LEN) { + offset -= ICE_MODULE_SFF_8079_LEN; + addr = ICE_I2C_EEPROM_DEV_ADDR2; + } + } else { + while (offset >= ICE_MODULE_SFF_8436_LEN) { + /* Compute memory page number and offset. */ + offset -= ICE_MODULE_SFF_8436_LEN / 2; + page++; + } + } + + /* Bit 2 of eeprom address 0x02 declares upper + * pages are disabled on QSFP modules. + * SFP modules only ever use page 0. + */ + if (page == 0 || !(data[0x2] & 0x4)) { + /* If i2c bus is busy due to slow page change or + * link management access, call can fail. + * This is normal. So we retry this a few times. + */ + for (j = 0; j < I2C_BUSY_TRY_TIMES; j++) { + status = ice_aq_sff_eeprom(hw, 0, addr, offset, + page, !is_sfp, value, + SFF_READ_BLOCK_SIZE, + 0, NULL); + PMD_DRV_LOG(DEBUG, "SFF %02X %02X %02X %X = " + "%02X%02X%02X%02X." + "%02X%02X%02X%02X (%X)\n", + addr, offset, page, is_sfp, + value[0], value[1], + value[2], value[3], + value[4], value[5], + value[6], value[7], + status); + if (status) { + usleep_range(I2C_USLEEP_MIN_TIME, + I2C_USLEEP_MAX_TIME); + memset(value, 0, SFF_READ_BLOCK_SIZE); + continue; + } + break; + } + + /* Make sure we have enough room for the new block */ + if ((i + SFF_READ_BLOCK_SIZE) < info->length) + memcpy(data + i, value, SFF_READ_BLOCK_SIZE); + } + } + + return 0; +} + static void ice_stat_update_32(struct ice_hw *hw, uint32_t reg, diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h index 1242177b42..3ed580d438 100644 --- a/drivers/net/ice/ice_ethdev.h +++ b/drivers/net/ice/ice_ethdev.h @@ -143,6 +143,31 @@ /* Max number of flexible descriptor rxdid */ #define ICE_FLEX_DESC_RXDID_MAX_NUM 64 +#define ICE_I2C_EEPROM_DEV_ADDR 0xA0 +#define ICE_I2C_EEPROM_DEV_ADDR2 0xA2 +#define ICE_MODULE_TYPE_SFP 0x03 +#define ICE_MODULE_TYPE_QSFP_PLUS 0x0D +#define ICE_MODULE_TYPE_QSFP28 0x11 +#define ICE_MODULE_SFF_ADDR_MODE 0x04 +#define ICE_MODULE_SFF_DIAG_CAPAB 0x40 +#define ICE_MODULE_REVISION_ADDR 0x01 +#define ICE_MODULE_SFF_8472_COMP 0x5E +#define ICE_MODULE_SFF_8472_SWAP 0x5C +#define ICE_MODULE_QSFP_MAX_LEN 640 + +/* EEPROM Standards for plug in modules */ +#define ICE_MODULE_SFF_8079 0x1 +#define ICE_MODULE_SFF_8079_LEN 256 +#define ICE_MODULE_SFF_8472 0x2 +#define ICE_MODULE_SFF_8472_LEN 512 +#define ICE_MODULE_SFF_8636 0x3 +#define ICE_MODULE_SFF_8636_LEN 256 +#define ICE_MODULE_SFF_8636_MAX_LEN 640 +#define ICE_MODULE_SFF_8436 0x4 +#define ICE_MODULE_SFF_8436_LEN 256 +#define ICE_MODULE_SFF_8436_MAX_LEN 640 + + /* Per-channel register definitions */ #define GLTSYN_AUX_OUT(_chan, _idx) (GLTSYN_AUX_OUT_0(_idx) + ((_chan) * 8)) #define GLTSYN_CLKO(_chan, _idx) (GLTSYN_CLKO_0(_idx) + ((_chan) * 8)) -- 2.20.1