From: Kalesh AP Date: Wed, 9 Jun 2021 02:45:15 +0000 (+0530) Subject: net/bnxt: dump SFP module info X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=6253a23491a4ad7dd38d89737ad72229b1dc8c1f;p=dpdk.git net/bnxt: dump SFP module info Add support to fetch the SFP EEPROM settings from the firmware. For SFP+ modules we will display 0xA0 page for status and 0xA2 page for other information. For QSFP modules we will show the 0xA0 page. Also identify the module types for QSFP28, QSFP, QSFP+ apart from the SFP modules and return an error for 10GBase-T PHY. Signed-off-by: Kalesh AP Reviewed-by: Somnath Kotur Reviewed-by: Ajit Khaparde Reviewed-by: Venkat Duvvuru --- diff --git a/doc/guides/nics/features/bnxt.ini b/doc/guides/nics/features/bnxt.ini index 75d189ebf6..60cc8bfa15 100644 --- a/doc/guides/nics/features/bnxt.ini +++ b/doc/guides/nics/features/bnxt.ini @@ -42,6 +42,7 @@ Extended stats = Y Stats per queue = Y FW version = Y EEPROM dump = Y +Module EEPROM dump = Y LED = Y Multiprocess aware = Y FreeBSD = Y diff --git a/drivers/net/bnxt/bnxt.h b/drivers/net/bnxt/bnxt.h index 376f3173e8..702ecac629 100644 --- a/drivers/net/bnxt/bnxt.h +++ b/drivers/net/bnxt/bnxt.h @@ -292,6 +292,7 @@ struct bnxt_link_info { uint16_t auto_pam4_link_speeds; uint16_t support_pam4_auto_speeds; uint8_t req_signal_mode; + uint8_t module_status; }; #define BNXT_COS_QUEUE_COUNT 8 @@ -970,6 +971,20 @@ struct bnxt_vf_rep_tx_queue { struct bnxt_representor *bp; }; +#define I2C_DEV_ADDR_A0 0xa0 +#define I2C_DEV_ADDR_A2 0xa2 +#define SFF_DIAG_SUPPORT_OFFSET 0x5c +#define SFF_MODULE_ID_SFP 0x3 +#define SFF_MODULE_ID_QSFP 0xc +#define SFF_MODULE_ID_QSFP_PLUS 0xd +#define SFF_MODULE_ID_QSFP28 0x11 +#define SFF8636_FLATMEM_OFFSET 0x2 +#define SFF8636_FLATMEM_MASK 0x4 +#define SFF8636_OPT_PAGES_OFFSET 0xc3 +#define SFF8636_PAGE1_MASK 0x40 +#define SFF8636_PAGE2_MASK 0x80 +#define BNXT_MAX_PHY_I2C_RESP_SIZE 64 + int bnxt_mtu_set_op(struct rte_eth_dev *eth_dev, uint16_t new_mtu); int bnxt_link_update(struct rte_eth_dev *eth_dev, int wait_to_complete, bool exp_link_status); diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c index d859ef5034..1579d797ce 100644 --- a/drivers/net/bnxt/bnxt_ethdev.c +++ b/drivers/net/bnxt/bnxt_ethdev.c @@ -3858,6 +3858,149 @@ bnxt_set_eeprom_op(struct rte_eth_dev *dev, in_eeprom->data, in_eeprom->length); } +static int bnxt_get_module_info(struct rte_eth_dev *dev, + struct rte_eth_dev_module_info *modinfo) +{ + uint8_t module_info[SFF_DIAG_SUPPORT_OFFSET + 1]; + struct bnxt *bp = dev->data->dev_private; + int rc; + + /* No point in going further if phy status indicates + * module is not inserted or if it is powered down or + * if it is of type 10GBase-T + */ + if (bp->link_info->module_status > + HWRM_PORT_PHY_QCFG_OUTPUT_MODULE_STATUS_WARNINGMSG) { + PMD_DRV_LOG(NOTICE, "Port %u : Module is not inserted or is powered down\n", + dev->data->port_id); + return -ENOTSUP; + } + + /* This feature is not supported in older firmware versions */ + if (bp->hwrm_spec_code < 0x10202) { + PMD_DRV_LOG(NOTICE, "Port %u : Feature is not supported in older firmware\n", + dev->data->port_id); + return -ENOTSUP; + } + + rc = bnxt_hwrm_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, + SFF_DIAG_SUPPORT_OFFSET + 1, + module_info); + + if (rc) + return rc; + + switch (module_info[0]) { + case SFF_MODULE_ID_SFP: + modinfo->type = RTE_ETH_MODULE_SFF_8472; + modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8472_LEN; + if (module_info[SFF_DIAG_SUPPORT_OFFSET] == 0) + modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8436_LEN; + break; + case SFF_MODULE_ID_QSFP: + case SFF_MODULE_ID_QSFP_PLUS: + modinfo->type = RTE_ETH_MODULE_SFF_8436; + modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8436_LEN; + break; + case SFF_MODULE_ID_QSFP28: + modinfo->type = RTE_ETH_MODULE_SFF_8636; + modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8636_MAX_LEN; + if (module_info[SFF8636_FLATMEM_OFFSET] & SFF8636_FLATMEM_MASK) + modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8636_LEN; + break; + default: + PMD_DRV_LOG(NOTICE, "Port %u : Unsupported module\n", dev->data->port_id); + return -ENOTSUP; + } + + PMD_DRV_LOG(INFO, "Port %u : modinfo->type = %d modinfo->eeprom_len = %d\n", + dev->data->port_id, modinfo->type, modinfo->eeprom_len); + + return 0; +} + +static int bnxt_get_module_eeprom(struct rte_eth_dev *dev, + struct rte_dev_eeprom_info *info) +{ + uint8_t pg_addr[5] = { I2C_DEV_ADDR_A0, I2C_DEV_ADDR_A0 }; + uint32_t offset = info->offset, length = info->length; + uint8_t module_info[SFF_DIAG_SUPPORT_OFFSET + 1]; + struct bnxt *bp = dev->data->dev_private; + uint8_t *data = info->data; + uint8_t page = offset >> 7; + uint8_t max_pages = 2; + uint8_t opt_pages; + int rc; + + rc = bnxt_hwrm_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, + SFF_DIAG_SUPPORT_OFFSET + 1, + module_info); + if (rc) + return rc; + + switch (module_info[0]) { + case SFF_MODULE_ID_SFP: + module_info[SFF_DIAG_SUPPORT_OFFSET] = 0; + if (module_info[SFF_DIAG_SUPPORT_OFFSET]) { + pg_addr[2] = I2C_DEV_ADDR_A2; + pg_addr[3] = I2C_DEV_ADDR_A2; + max_pages = 4; + } + break; + case SFF_MODULE_ID_QSFP28: + rc = bnxt_hwrm_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, + SFF8636_OPT_PAGES_OFFSET, + 1, &opt_pages); + if (rc) + return rc; + + if (opt_pages & SFF8636_PAGE1_MASK) { + pg_addr[2] = I2C_DEV_ADDR_A0; + max_pages = 3; + } + if (opt_pages & SFF8636_PAGE2_MASK) { + pg_addr[3] = I2C_DEV_ADDR_A0; + max_pages = 4; + } + if (~module_info[SFF8636_FLATMEM_OFFSET] & SFF8636_FLATMEM_MASK) { + pg_addr[4] = I2C_DEV_ADDR_A0; + max_pages = 5; + } + break; + default: + break; + } + + memset(data, 0, length); + + offset &= 0xff; + while (length && page < max_pages) { + uint8_t raw_page = page ? page - 1 : 0; + uint16_t chunk; + + if (pg_addr[page] == I2C_DEV_ADDR_A2) + raw_page = 0; + else if (page) + offset |= 0x80; + chunk = RTE_MIN(length, 256 - offset); + + if (pg_addr[page]) { + rc = bnxt_hwrm_read_sfp_module_eeprom_info(bp, pg_addr[page], + raw_page, offset, + chunk, data); + if (rc) + return rc; + } + + data += chunk; + length -= chunk; + offset = 0; + page += 1 + (chunk > 128); + } + + return length ? -EINVAL : 0; +} + /* * Initialization */ @@ -3919,6 +4062,8 @@ static const struct eth_dev_ops bnxt_dev_ops = { .get_eeprom_length = bnxt_get_eeprom_length_op, .get_eeprom = bnxt_get_eeprom_op, .set_eeprom = bnxt_set_eeprom_op, + .get_module_info = bnxt_get_module_info, + .get_module_eeprom = bnxt_get_module_eeprom, .timesync_enable = bnxt_timesync_enable, .timesync_disable = bnxt_timesync_disable, .timesync_read_time = bnxt_timesync_read_time, diff --git a/drivers/net/bnxt/bnxt_hwrm.c b/drivers/net/bnxt/bnxt_hwrm.c index 6eab2342f6..be595487e5 100644 --- a/drivers/net/bnxt/bnxt_hwrm.c +++ b/drivers/net/bnxt/bnxt_hwrm.c @@ -1508,6 +1508,7 @@ static int bnxt_hwrm_port_phy_qcfg(struct bnxt *bp, rte_le_to_cpu_16(resp->support_pam4_speeds); link_info->auto_pam4_link_speeds = rte_le_to_cpu_16(resp->auto_pam4_link_speed_mask); + link_info->module_status = resp->module_status; HWRM_UNLOCK(); PMD_DRV_LOG(DEBUG, "Link Speed:%d,Auto:%d:%x:%x,Support:%x,Force:%x\n", @@ -6162,3 +6163,38 @@ int bnxt_hwrm_poll_ver_get(struct bnxt *bp) return rc; } + +int bnxt_hwrm_read_sfp_module_eeprom_info(struct bnxt *bp, uint16_t i2c_addr, + uint16_t page_number, uint16_t start_addr, + uint16_t data_length, uint8_t *buf) +{ + struct hwrm_port_phy_i2c_read_output *resp = bp->hwrm_cmd_resp_addr; + struct hwrm_port_phy_i2c_read_input req = {0}; + uint32_t enables = HWRM_PORT_PHY_I2C_READ_INPUT_ENABLES_PAGE_OFFSET; + int rc, byte_offset = 0; + + do { + uint16_t xfer_size; + + HWRM_PREP(&req, HWRM_PORT_PHY_I2C_READ, BNXT_USE_CHIMP_MB); + req.i2c_slave_addr = i2c_addr; + req.page_number = rte_cpu_to_le_16(page_number); + req.port_id = rte_cpu_to_le_16(bp->pf->port_id); + + xfer_size = RTE_MIN(data_length, BNXT_MAX_PHY_I2C_RESP_SIZE); + req.page_offset = rte_cpu_to_le_16(start_addr + byte_offset); + req.data_length = xfer_size; + req.enables = rte_cpu_to_le_32(start_addr + byte_offset ? enables : 0); + rc = bnxt_hwrm_send_message(bp, &req, sizeof(req), BNXT_USE_CHIMP_MB); + HWRM_CHECK_RESULT(); + + memcpy(buf + byte_offset, resp->data, xfer_size); + + data_length -= xfer_size; + byte_offset += xfer_size; + + HWRM_UNLOCK(); + } while (data_length > 0); + + return rc; +} diff --git a/drivers/net/bnxt/bnxt_hwrm.h b/drivers/net/bnxt/bnxt_hwrm.h index b60aa0cca8..057f7f94d0 100644 --- a/drivers/net/bnxt/bnxt_hwrm.h +++ b/drivers/net/bnxt/bnxt_hwrm.h @@ -301,4 +301,7 @@ int bnxt_hwrm_poll_ver_get(struct bnxt *bp); int bnxt_hwrm_rx_ring_reset(struct bnxt *bp, int queue_index); int bnxt_hwrm_ring_stats(struct bnxt *bp, uint32_t cid, int idx, struct bnxt_ring_stats *stats, bool rx); +int bnxt_hwrm_read_sfp_module_eeprom_info(struct bnxt *bp, uint16_t i2c_addr, + uint16_t page_number, uint16_t start_addr, + uint16_t data_length, uint8_t *buf); #endif diff --git a/drivers/net/bnxt/hsi_struct_def_dpdk.h b/drivers/net/bnxt/hsi_struct_def_dpdk.h index 1f0b37addf..f715bc6b2b 100644 --- a/drivers/net/bnxt/hsi_struct_def_dpdk.h +++ b/drivers/net/bnxt/hsi_struct_def_dpdk.h @@ -48813,4 +48813,87 @@ struct hcomm_status { } __rte_packed; /* This is the GRC offset where the hcomm_status struct resides. */ #define HCOMM_STATUS_STRUCT_LOC 0x31001F0UL + +/************************** + * hwrm_port_phy_i2c_read * + **************************/ + + +/* hwrm_port_phy_i2c_read_input (size:320b/40B) */ +struct hwrm_port_phy_i2c_read_input { + /* The HWRM command request type. */ + uint16_t req_type; + /* + * The completion ring to send the completion event on. This should + * be the NQ ID returned from the `nq_alloc` HWRM command. + */ + uint16_t cmpl_ring; + /* + * The sequence ID is used by the driver for tracking multiple + * commands. This ID is treated as opaque data by the firmware and + * the value is returned in the `hwrm_resp_hdr` upon completion. + */ + uint16_t seq_id; + /* + * The target ID of the command: + * * 0x0-0xFFF8 - The function ID + * * 0xFFF8-0xFFFC, 0xFFFE - Reserved for internal processors + * * 0xFFFD - Reserved for user-space HWRM interface + * * 0xFFFF - HWRM + */ + uint16_t target_id; + /* + * A physical address pointer pointing to a host buffer that the + * command's response data will be written. This can be either a host + * physical address (HPA) or a guest physical address (GPA) and must + * point to a physically contiguous block of memory. + */ + uint64_t resp_addr; + uint32_t flags; + uint32_t enables; + /* + * This bit must be '1' for the page_offset field to be + * configured. + */ + #define HWRM_PORT_PHY_I2C_READ_INPUT_ENABLES_PAGE_OFFSET 0x1UL + /* Port ID of port. */ + uint16_t port_id; + /* 8-bit I2C slave address. */ + uint8_t i2c_slave_addr; + uint8_t unused_0; + /* The page number that is being accessed over I2C. */ + uint16_t page_number; + /* Offset within the page that is being accessed over I2C. */ + uint16_t page_offset; + /* + * Length of data to read, in bytes starting at the offset + * specified above. If the offset is not specified, then + * the data shall be read from the beginning of the page. + */ + uint8_t data_length; + uint8_t unused_1[7]; +} __rte_packed; + +/* hwrm_port_phy_i2c_read_output (size:640b/80B) */ +struct hwrm_port_phy_i2c_read_output { + /* The specific error status for the command. */ + uint16_t error_code; + /* The HWRM command request type. */ + uint16_t req_type; + /* The sequence ID from the original command. */ + uint16_t seq_id; + /* The length of the response data in number of bytes. */ + uint16_t resp_len; + /* Up to 64B of data. */ + uint32_t data[16]; + uint8_t unused_0[7]; + /* + * This field is used in Output records to indicate that the output + * is completely written to RAM. This field should be read as '1' + * to indicate that the output has been completely written. + * When writing a command completion or response to an internal processor, + * the order of writes has to be such that this field is written last. + */ + uint8_t valid; +} __rte_packed; #endif /* _HSI_STRUCT_DEF_DPDK_H_ */