Identify the new SP560 NIC through its PCI device ID and select NIC-type
specific operations, and add 400G/800G line rate support.

Signed-off-by: Jiacheng Ye <[email protected]>
---
 doc/guides/nics/hinic3.rst                 |  2 +-
 doc/guides/rel_notes/release_26_11.rst     |  1 +
 drivers/net/hinic3/base/hinic3_csr.h       |  6 ++-
 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 | 62 ++++++++++++++++++++--
 drivers/net/hinic3/hinic3_ethdev.c         |  8 +++
 drivers/net/hinic3/hinic3_ethdev.h         |  6 ++-
 drivers/net/hinic3/hinic3_rx.c             | 19 +++++++
 9 files changed, 104 insertions(+), 8 deletions(-)

diff --git a/doc/guides/nics/hinic3.rst b/doc/guides/nics/hinic3.rst
index d07e8605c0..bc518ce7fc 100644
--- a/doc/guides/nics/hinic3.rst
+++ b/doc/guides/nics/hinic3.rst
@@ -5,7 +5,7 @@ HINIC3 Poll Mode Driver
 =======================
 
 The hinic3 PMD (**librte_net_hinic3**) provides poll mode driver support
-for 25Gbps/100Gbps/200Gbps Huawei SPx series Network Adapters.
+for 25Gbps/100Gbps/200Gbps/400Gbps Huawei SP230, SP560 and SP620 series 
Network Adapters.
 
 
 Features
diff --git a/doc/guides/rel_notes/release_26_11.rst 
b/doc/guides/rel_notes/release_26_11.rst
index 3f106bfe31..fc5d7f74b2 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -121,6 +121,7 @@ New Features
   * Added Class of Service (COS) mask and map support.
   * Updated RSS hash type configuration.
   * Added mailbox message counter reporting through the device private dump 
API.
+  * 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 7cae2419c0..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 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 d8b7dd9bc4..79375bbf91 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 787b4b0739..6939f3d9cb 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;
@@ -175,6 +215,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)
 {
@@ -200,9 +256,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) {
diff --git a/drivers/net/hinic3/hinic3_ethdev.c 
b/drivers/net/hinic3/hinic3_ethdev.c
index f3dc5a15a6..ccc013462e 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -551,6 +551,10 @@ hinic3_get_nic_type(struct rte_pci_device *pci_dev)
        case HINIC3_DEV_ID_SP230:
        case HINIC3_DEV_ID_VF_SP230:
                return NIC_SP230;
+       case HINIC3_DEV_ID_SP560:
+       case HINIC3_DEV_ID_VF_SP560:
+       case HINIC3_DEV_ID_HYPER_VF_SP560:
+               return NIC_SP560;
        default:
                return NIC_UNKNOWN;
        }
@@ -571,6 +575,7 @@ hinic3_cmdq_get_ops(struct hinic3_nic_dev *nic_dev)
        static const struct hinic3_nic_cmdq_ops *cmdq_ops[] = {
                [NIC_SP620]   = &hinic3_stn_cmdq_ops,
                [NIC_SP230]   = &hinic3_htn_cmdq_ops,
+               [NIC_SP560]   = &hinic3_stn_cmdq_ops,
                [NIC_UNKNOWN] = &hinic3_stn_cmdq_ops,
        };
 
@@ -3952,6 +3957,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_ethdev.h 
b/drivers/net/hinic3/hinic3_ethdev.h
index f7d3dfcff6..7ab9b661d5 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -102,7 +102,7 @@ enum nic_feature_cap {
 
 };
 
-#define DEFAULT_DRV_FEATURE            0x3FC3FFF
+#define DEFAULT_DRV_FEATURE            0x0BFC3FFF
 
 TAILQ_HEAD(hinic3_ethertype_filter_list, rte_flow);
 TAILQ_HEAD(hinic3_fdir_rule_filter_list, rte_flow);
@@ -110,7 +110,8 @@ TAILQ_HEAD(hinic3_fdir_rule_filter_list, rte_flow);
 enum nic_type {
        NIC_SP620 = 0,
        NIC_SP230 = 1,
-       NIC_UNKNOWN = 2,
+       NIC_SP560 = 2,
+       NIC_UNKNOWN = 3,
 };
 
 struct hinic3_nic_dev {
@@ -170,6 +171,7 @@ struct hinic3_nic_dev {
 
 #define HINIC3_IS_SP620_NIC(nic_dev) ((nic_dev)->nic_type == NIC_SP620)
 #define HINIC3_IS_SP230_NIC(nic_dev) ((nic_dev)->nic_type == NIC_SP230)
+#define HINIC3_IS_SP560_NIC(nic_dev) ((nic_dev)->nic_type == NIC_SP560)
 
 extern const struct rte_flow_ops hinic3_flow_ops;
 
diff --git a/drivers/net/hinic3/hinic3_rx.c b/drivers/net/hinic3/hinic3_rx.c
index a4846dc695..9627b608f4 100644
--- a/drivers/net/hinic3/hinic3_rx.c
+++ b/drivers/net/hinic3/hinic3_rx.c
@@ -637,6 +637,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

Reply via email to