Identify the new SP560 NIC through its PCI device ID and select NIC-type specific operations, and add 400G/800G line rate support. At init, read the receive WQE type from the kernel module parameter to decide whether the SP560 uses the normal or compact CQE data path.
Signed-off-by: Jiacheng Ye <[email protected]> --- doc/guides/rel_notes/release_26_11.rst | 1 + drivers/net/hinic3/base/hinic3_csr.h | 8 +- drivers/net/hinic3/base/hinic3_hwif.c | 4 +- drivers/net/hinic3/base/hinic3_nic_cfg.h | 4 + drivers/net/hinic3/base/hinic3_nic_event.c | 72 +++++++++++-- drivers/net/hinic3/hinic3_ethdev.c | 111 ++++++++++++++++++++- drivers/net/hinic3/hinic3_rx.c | 19 ++++ 7 files changed, 206 insertions(+), 13 deletions(-) diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst index 80530ac25d..2e8e1e082a 100644 --- a/doc/guides/rel_notes/release_26_11.rst +++ b/doc/guides/rel_notes/release_26_11.rst @@ -98,6 +98,7 @@ New Features * Added FEC mode get and set support. * Added Class of Service (COS) mask and map support. * Updated RSS hash type configuration. + * Added support for the SP560 NIC. * **Updated Intel iavf driver.** diff --git a/drivers/net/hinic3/base/hinic3_csr.h b/drivers/net/hinic3/base/hinic3_csr.h index eceb34e9fd..fba2f6838a 100644 --- a/drivers/net/hinic3/base/hinic3_csr.h +++ b/drivers/net/hinic3/base/hinic3_csr.h @@ -8,13 +8,17 @@ #define PCI_VENDOR_ID_HUAWEI 0x19e5 #define HINIC3_DEV_ID_SP620 0x0222 -#define HINIC3_DEV_ID_VF_SP620 0x375F +#define HINIC3_DEV_ID_VF_SP620 0x375f #define HINIC3_DEV_ID_SP230 0x0229 -#define HINIC3_DEV_ID_VF_SP230 0x3750 +#define HINIC3_DEV_ID_VF_SP230 0x022a #define HINIC3_DEV_ID_SP920 0x0224 +#define HINIC3_DEV_ID_SP560 0x0230 +#define HINIC3_DEV_ID_VF_SP560 0x0231 +#define HINIC3_DEV_ID_HYPER_VF_SP560 0x0232 + /* * Bit30/bit31 for bar index flag. * 00: bar0 diff --git a/drivers/net/hinic3/base/hinic3_hwif.c b/drivers/net/hinic3/base/hinic3_hwif.c index c82b223fa0..af1dddabf4 100644 --- a/drivers/net/hinic3/base/hinic3_hwif.c +++ b/drivers/net/hinic3/base/hinic3_hwif.c @@ -141,7 +141,9 @@ static inline bool hinic3_is_vf_dev(const struct rte_pci_device *pdev) { return pdev->id.device_id == HINIC3_DEV_ID_VF_SP620 || - pdev->id.device_id == HINIC3_DEV_ID_VF_SP230; + pdev->id.device_id == HINIC3_DEV_ID_VF_SP230 || + pdev->id.device_id == HINIC3_DEV_ID_VF_SP560 || + pdev->id.device_id == HINIC3_DEV_ID_HYPER_VF_SP560; } uint32_t diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.h b/drivers/net/hinic3/base/hinic3_nic_cfg.h index ef139b25b9..0de8179c19 100644 --- a/drivers/net/hinic3/base/hinic3_nic_cfg.h +++ b/drivers/net/hinic3/base/hinic3_nic_cfg.h @@ -127,6 +127,8 @@ enum nic_speed_level { LINK_SPEED_50GB, LINK_SPEED_100GB, LINK_SPEED_200GB, + LINK_SPEED_400GB, + LINK_SPEED_800GB, LINK_SPEED_LEVELS, }; @@ -181,6 +183,8 @@ enum mag_cmd_port_speed { PORT_SPEED_50GB = 7, PORT_SPEED_100GB = 8, PORT_SPEED_200GB = 9, + PORT_SPEED_400GB = 10, + PORT_SPEED_800GB = 11, PORT_SPEED_UNKNOWN }; diff --git a/drivers/net/hinic3/base/hinic3_nic_event.c b/drivers/net/hinic3/base/hinic3_nic_event.c index 2f2d6aa75b..131acc47dd 100644 --- a/drivers/net/hinic3/base/hinic3_nic_event.c +++ b/drivers/net/hinic3/base/hinic3_nic_event.c @@ -15,6 +15,7 @@ static const char *g_hw_to_char_fec[HILINK_FEC_MAX_TYPE] = { static const char *g_hw_to_speed_info[PORT_SPEED_UNKNOWN] = { "not set", "10MB", "100MB", "1GB", "10GB", "25GB", "40GB", "50GB", "100GB", "200GB", + "400GB", "800GB", }; static const char *g_hw_to_an_state_info[PORT_CFG_AN_OFF + 1] = { "not set", "on", "off", @@ -25,6 +26,37 @@ struct port_type_table { const char *port_type_name; }; +/* + * Hardware cable speed modes. + * + * The firmware reports the cable speed mode as a uint8_t value. Speeds whose raw + * Gbps value cannot be represented in 8 bits (notably 400G and 800G) are + * therefore encoded with indirection codes instead, and must be translated + * back to their real speeds through speed_mode_map[] below. + */ +enum { + HW_CABLE_SPEED_MODE_200G = 200, + HW_CABLE_SPEED_MODE_400G = 201, + HW_CABLE_SPEED_MODE_800G = 202, +}; + +/* Real cable speeds in Gbps, as exposed to the upper layer. */ +enum { + REAL_CABLE_SPEED_400G = 400, + REAL_CABLE_SPEED_800G = 800, +}; + +/* Mapping between a cable speed mode (uint8_t) and its real speed in Gbps. */ +struct speed_mode_map_entry { + uint8_t speed_mode; + uint32_t real_speed; +}; + +static const struct speed_mode_map_entry speed_mode_map[] = { + {HW_CABLE_SPEED_MODE_400G, REAL_CABLE_SPEED_400G}, + {HW_CABLE_SPEED_MODE_800G, REAL_CABLE_SPEED_800G}, +}; + void hinic3_get_link_port_info(struct hinic3_hwdev *hwdev, uint8_t link_state, struct rte_eth_link *link) @@ -35,6 +67,7 @@ hinic3_get_link_port_info(struct hinic3_hwdev *hwdev, uint8_t link_state, RTE_ETH_SPEED_NUM_10G, RTE_ETH_SPEED_NUM_25G, RTE_ETH_SPEED_NUM_40G, RTE_ETH_SPEED_NUM_50G, RTE_ETH_SPEED_NUM_100G, RTE_ETH_SPEED_NUM_200G, + RTE_ETH_SPEED_NUM_400G, RTE_ETH_SPEED_NUM_800G }; struct nic_port_info port_info = {0}; int err; @@ -53,6 +86,13 @@ hinic3_get_link_port_info(struct hinic3_hwdev *hwdev, uint8_t link_state, link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX; link->link_autoneg = RTE_ETH_LINK_FIXED; } else { + if (port_info.speed >= LINK_SPEED_LEVELS) { + PMD_DRV_LOG(WARNING, + "Invalid port speed %u reported by firmware, reset to %u", + port_info.speed, + port_info.speed % LINK_SPEED_LEVELS); + } + link->link_speed = port_speed[port_info.speed % LINK_SPEED_LEVELS]; link->link_duplex = port_info.duplex; @@ -176,6 +216,22 @@ get_port_temperature_power(struct mag_cmd_event_port_info *info, char *str) return 0; } +static uint32_t +get_real_cable_speed(uint8_t speed) +{ + uint32_t i; + + if (speed <= HW_CABLE_SPEED_MODE_200G) + return speed; + for (i = 0; i < RTE_DIM(speed_mode_map); i++) { + if (speed_mode_map[i].speed_mode == speed) + return speed_mode_map[i].real_speed; + } + + PMD_DRV_LOG(ERR, "unsupported cable speed mode: 0x%x", speed); + return speed; +} + static void print_cable_info(struct mag_cmd_event_port_info *port_info) { @@ -201,9 +257,9 @@ print_cable_info(struct mag_cmd_event_port_info *port_info) memcpy(vendor, port_info->vendor_name, sizeof(port_info->vendor_name)); snprintf(str, CAP_INFO_MAX_LEN - 1, - "Vendor: %s, %s, length: %um, max_speed: %uGbps", - vendor, port_type, port_info->cable_length, - port_info->max_speed); + "Vendor: %s, %s, length: %um, max_speed: %uGbps", + vendor, port_type, port_info->cable_length, + get_real_cable_speed(port_info->max_speed)); if (port_info->port_type == LINK_PORT_OPTICAL_MM || port_info->port_type == LINK_PORT_AOC) { @@ -282,9 +338,13 @@ port_info_event_printf(struct hinic3_hwdev *hwdev, struct hinic3_handler_info *h struct mag_cmd_event_port_info *port_info = handler_info->buf_in; ((struct mag_cmd_event_port_info *)(handler_info->buf_out))->head.status = 0; enum hinic3_nic_event_type type = port_info->event_type; - if (type < RTE_ETH_LINK_DOWN || type > RTE_ETH_LINK_UP) { - PMD_DRV_LOG(ERR, "Invalid hilink info report, type: %d", type); - return; + struct hinic3_nic_dev *nic_dev = ((struct hinic3_hwdev *)hwdev)->dev_handle; + + if (HINIC3_IS_SP620_NIC(nic_dev)) { + if (type < RTE_ETH_LINK_DOWN || type > RTE_ETH_LINK_UP) { + PMD_DRV_LOG(ERR, "Invalid hilink info report, type: %d", type); + return; + } } print_port_info(hwdev, port_info, type); diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c index 9adfe7db41..603330846e 100644 --- a/drivers/net/hinic3/hinic3_ethdev.c +++ b/drivers/net/hinic3/hinic3_ethdev.c @@ -472,6 +472,67 @@ hinic3_pf_get_default_cos(struct hinic3_hwdev *hwdev, uint8_t *cos_id) return 0; } +static int +hinic3_parse_sysfs_value(const char *filename, unsigned long *val) +{ + FILE *f; + char buf[BUFSIZ]; + char *end = NULL; + + f = fopen(filename, "r"); + if (f == NULL) { + PMD_DRV_LOG(ERR, "Cannot open sysfs value %s", filename); + return -1; + } + + if (fgets(buf, sizeof(buf), f) == NULL) { + PMD_DRV_LOG(ERR, "Cannot read sysfs value %s", filename); + fclose(f); + return -1; + } + *val = strtoul(buf, &end, 0); + if ((buf[0] == '\0') || end == NULL || (*end != '\n')) { + PMD_DRV_LOG(ERR, "Cannot parse sysfs value %s", filename); + fclose(f); + return -1; + } + fclose(f); + return 0; +} + +/* + * Try to read sysfs parameter from kernel module. + * SP620 NIC uses "hinic3" kernel driver, other NICs (e.g. BP/SP560/SP230) + * use "hinic5" kernel driver. + * The module name could be either "driver_name" or "driver_name_nic". + * Returns 0 on success, -1 on failure. + */ +static int +hinic3_read_module_param(struct hinic3_nic_dev *nic_dev, const char *param_name, + unsigned long *val) +{ + const char *driver_name = HINIC3_IS_SP620_NIC(nic_dev) ? + "hinic3" : "hinic5"; + char path[PATH_MAX]; + int ret; + + snprintf(path, sizeof(path), "/sys/module/%s/parameters/%s", + driver_name, param_name); + ret = hinic3_parse_sysfs_value(path, val); + if (ret == 0) + return 0; + + snprintf(path, sizeof(path), "/sys/module/%s_nic/parameters/%s", + driver_name, param_name); + ret = hinic3_parse_sysfs_value(path, val); + if (ret == 0) + return 0; + + PMD_DRV_LOG(ERR, "Failed to read parameter %s from module %s or %s_nic", + param_name, driver_name, driver_name); + return -1; +} + static void hinic3_get_cos_mask(struct hinic3_hwdev *hwdev, uint8_t *cos_mask) { @@ -539,6 +600,26 @@ hinic3_init_default_cos(struct hinic3_nic_dev *nic_dev) return 0; } +static enum nic_type +hinic3_get_nic_type(struct rte_pci_device *pci_dev) +{ + switch (pci_dev->id.device_id) { + case HINIC3_DEV_ID_SP620: + case HINIC3_DEV_ID_VF_SP620: + case HINIC3_DEV_ID_SP920: /* SP920 is the DPU card of SP620. */ + return NIC_SP620; + case HINIC3_DEV_ID_SP560: + case HINIC3_DEV_ID_VF_SP560: + case HINIC3_DEV_ID_HYPER_VF_SP560: + return NIC_SP560; + case HINIC3_DEV_ID_SP230: + case HINIC3_DEV_ID_VF_SP230: + return NIC_SP230; + default: + return NIC_UNKNOWN; + } +} + /** * Get cmdq ops for the given NIC device. * @@ -551,10 +632,18 @@ hinic3_init_default_cos(struct hinic3_nic_dev *nic_dev) const struct hinic3_nic_cmdq_ops * hinic3_cmdq_get_ops(struct hinic3_nic_dev *nic_dev) { - if (nic_dev->feature_cap & NIC_F_HTN_CMDQ) - return &hinic3_htn_cmdq_ops; - else - return &hinic3_stn_cmdq_ops; + static const struct hinic3_nic_cmdq_ops *cmdq_ops[] = { + [NIC_SP620] = &hinic3_stn_cmdq_ops, + [NIC_SP560] = &hinic3_stn_cmdq_ops, + [NIC_SP230] = &hinic3_htn_cmdq_ops, + [NIC_UNKNOWN] = &hinic3_stn_cmdq_ops, + }; + static const struct hinic3_nic_cmdq_ops *cached_ops; + + if (cached_ops == NULL) + cached_ops = cmdq_ops[nic_dev->nic_type]; + + return cached_ops; } /** @@ -3652,6 +3741,7 @@ hinic3_func_init(struct rte_eth_dev *eth_dev) struct hinic3_tcam_info *tcam_info = NULL; struct hinic3_nic_dev *nic_dev = NULL; struct rte_pci_device *pci_dev = NULL; + unsigned long compact_cqe = 0; int err; pci_dev = RTE_CLASS_TO_BUS_DEVICE(eth_dev, *pci_dev); @@ -3666,6 +3756,7 @@ hinic3_func_init(struct rte_eth_dev *eth_dev) nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev); memset(nic_dev, 0, sizeof(*nic_dev)); + nic_dev->nic_type = hinic3_get_nic_type(pci_dev); snprintf(nic_dev->dev_name, sizeof(nic_dev->dev_name), "dbdf-%.4x:%.2x:%.2x.%x", pci_dev->addr.domain, pci_dev->addr.bus, pci_dev->addr.devid, @@ -3750,6 +3841,15 @@ hinic3_func_init(struct rte_eth_dev *eth_dev) hinic3_nic_tx_rx_ops_init(nic_dev); + /* Read wqe type from kernel parameter. */ + if (hinic3_read_module_param(nic_dev, "rq_wqe_type", &compact_cqe) != 0) { + err = -EINVAL; + goto get_cap_fail; + } + + if (compact_cqe == 1) + nic_dev->feature_cap &= ~(NIC_F_RX_SW_COMPACT_CQE | NIC_F_RX_HW_COMPACT_CQE); + err = hinic3_init_sw_rxtxqs(nic_dev); if (err) { PMD_DRV_LOG(ERR, "Init sw rxqs or txqs failed, dev_name: %s", @@ -3899,6 +3999,9 @@ static const struct rte_pci_id pci_id_hinic3_map[] = { {RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HINIC3_DEV_ID_VF_SP230)}, {RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HINIC3_DEV_ID_SP920)}, + {RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HINIC3_DEV_ID_SP560)}, + {RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HINIC3_DEV_ID_VF_SP560)}, + {RTE_PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, HINIC3_DEV_ID_HYPER_VF_SP560)}, {.vendor_id = 0}, }; diff --git a/drivers/net/hinic3/hinic3_rx.c b/drivers/net/hinic3/hinic3_rx.c index 57e50590cd..493855b431 100644 --- a/drivers/net/hinic3/hinic3_rx.c +++ b/drivers/net/hinic3/hinic3_rx.c @@ -634,6 +634,25 @@ hinic3_poll_integrated_cqe_rq_empty(struct hinic3_rxq *rxq) rq_ci.dw1.value = hinic3_hw_cpu32(val); hw_ci = rq_ci.dw1.bs.hw_ci; + if (HINIC3_IS_SP560_NIC(rxq->nic_dev)) { + uint16_t sw_pi = hinic3_get_rq_local_pi(rxq); + uint64_t end; + + end = cycles + msecs_to_cycles(HINIC3_FLUSH_QUEUE_TIMEOUT); + do { + val = rte_read32(&rxq->rq_ci->dw1.value); + rq_ci.dw1.value = hinic3_hw_cpu32(val); + hw_ci = rq_ci.dw1.bs.hw_ci; + if (sw_pi == hw_ci) + break; + + rte_delay_us(1); + } while (time_before(cycles, end)); + + if (sw_pi != hw_ci) + return -EFAULT; + } + while (sw_ci != hw_ci) { rx_info = &rxq->rx_info[sw_ci]; rte_pktmbuf_free(rx_info->mbuf); -- 2.33.0

