Expose the CIR drop counter through the per-port extended statistics and
select the queue COS from the VF LAG bitmap when a VF runs on an
aggregated link.

The CIR drop counter is only available on SP620, so it is added to the
xstats name list there. For an even queue of a VF that is in the LAG
group, the driver flips the COS so the queue egresses through the peer
port; other queues keep the default COS.

Signed-off-by: Jiacheng Ye <[email protected]>
---
 doc/guides/rel_notes/release_26_11.rst   |  4 ++
 drivers/net/hinic3/base/hinic3_cmd.h     |  2 +
 drivers/net/hinic3/base/hinic3_nic_cfg.c | 62 +++++++++++++++++++
 drivers/net/hinic3/base/hinic3_nic_cfg.h | 45 +++++++++++++-
 drivers/net/hinic3/hinic3_ethdev.c       | 76 +++++++++++++++++++++++-
 drivers/net/hinic3/hinic3_ethdev.h       |  3 +
 6 files changed, 189 insertions(+), 3 deletions(-)

diff --git a/doc/guides/rel_notes/release_26_11.rst 
b/doc/guides/rel_notes/release_26_11.rst
index 8ca8379cc6..e0c0e700a7 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -163,6 +163,10 @@ New Features
   * Advertised ``RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP`` capability,
     as flow rules were already kept across device restart.
 
+* **Updated Huawei hinic3 ethernet driver.**
+
+  * Added CIR drop statistics and VF link aggregation (LAG) support.
+
 * **Updated Intel iavf driver.**
 
   * Runtime Rx/Tx queue setup is now automatically disabled
diff --git a/drivers/net/hinic3/base/hinic3_cmd.h 
b/drivers/net/hinic3/base/hinic3_cmd.h
index f2d5d47522..ecce94690e 100644
--- a/drivers/net/hinic3/base/hinic3_cmd.h
+++ b/drivers/net/hinic3/base/hinic3_cmd.h
@@ -94,6 +94,8 @@ enum hinic3_nic_cmd {
        /* PORT CFG */
        HINIC3_NIC_CMD_CFG_PAUSE_INFO                   = 101,
        HINIC3_NIC_CMD_VF_COS                           = 104,
+       HINIC3_NIC_CMD_GET_CIR_DROP                     = 115,
+       HINIC3_NIC_CMD_CFG_VF_LAG                       = 243,
 };
 
 /* COMM commands between driver to MPU. */
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.c 
b/drivers/net/hinic3/base/hinic3_nic_cfg.c
index fb9b6d4d19..853ca0a41b 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.c
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c
@@ -601,6 +601,33 @@ hinic3_get_pause_info(struct hinic3_hwdev *hwdev, struct 
nic_pause_config *nic_p
        return hinic3_cfg_hw_pause(hwdev, HINIC3_CMD_OP_GET, nic_pause);
 }
 
+int
+hinic3_get_cir_drop(void *hwdev, struct hinic3_cir_drop *stats)
+{
+       struct hinic3_port_stats_info stats_info = { 0 };
+       struct hinic3_cmd_get_dp_info_resp vport_stats = { 0 };
+       uint16_t out_size = sizeof(vport_stats);
+       int err;
+
+       if (!hwdev || !stats)
+               return -EINVAL;
+
+       stats_info.func_id = hinic3_global_func_id(hwdev);
+       err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_L2NIC,
+                                     HINIC3_NIC_CMD_GET_CIR_DROP,
+                                     &stats_info, sizeof(stats_info),
+                                     &vport_stats, &out_size);
+       if (err || !out_size || vport_stats.msg_head.status) {
+               PMD_DRV_LOG(ERR, "Get port stats failed, err: %d, status: 0x%x, 
out size: 0x%x",
+                           err, vport_stats.msg_head.status, out_size);
+               return -EIO;
+       }
+
+       memcpy(stats, vport_stats.value, sizeof(*stats));
+
+       return 0;
+}
+
 int
 hinic3_get_vport_stats(struct hinic3_hwdev *hwdev, struct hinic3_vport_stats 
*stats)
 {
@@ -1725,3 +1752,38 @@ hinic3_set_link_status_follow(struct hinic3_hwdev *hwdev,
 
        return follow.head.status;
 }
+
+bool
+hinic3_cmd_vf_lag(void *hwdev, uint16_t func_id, uint8_t opcode)
+{
+       struct hinic3_vf_lag_cmd vf_lag_info = { 0 };
+       uint16_t out_size = sizeof(struct hinic3_vf_lag_cmd);
+       int err;
+
+       if (!hwdev || func_id >= MAX_FUNCTION_NUM)
+               return false;
+       vf_lag_info.func_id = func_id;
+       vf_lag_info.opcode = opcode;
+       vf_lag_info.en_flag = 0;
+
+       err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_L2NIC,
+                                     HINIC3_NIC_CMD_CFG_VF_LAG,
+                                     &vf_lag_info, sizeof(vf_lag_info),
+                                     &vf_lag_info, &out_size);
+       if (vf_lag_info.msg_head.status == HINIC3_MGMT_CMD_UNSUPPORTED)
+               return false;
+
+       if (err || vf_lag_info.msg_head.status || !out_size) {
+               PMD_DRV_LOG(ERR,
+                           "Get vf_lag failed, err: %d, status: 0x%x, out 
size: 0x%x",
+                           err, vf_lag_info.msg_head.status, out_size);
+               return false;
+       }
+
+       if (opcode == HINIC3_CMD_OPCODE_GET) {
+               return !!(vf_lag_info.vf_lag_bitmap.vf_bit_map[func_id / 
VF_LAG_VF_NUM_PER_GROUP] &
+                         RTE_BIT32(func_id % VF_LAG_VF_NUM_PER_GROUP));
+       }
+
+       return false;
+}
diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.h 
b/drivers/net/hinic3/base/hinic3_nic_cfg.h
index 6d3eb433bd..6fb56fff4f 100644
--- a/drivers/net/hinic3/base/hinic3_nic_cfg.h
+++ b/drivers/net/hinic3/base/hinic3_nic_cfg.h
@@ -17,6 +17,7 @@
 #define HINIC3_DCB_UP_MAX              0x8
 
 #define HINIC3_MAX_NUM_RQ              256
+#define MAX_FUNCTION_NUM               4096
 
 #define HINIC3_MAX_MTU_SIZE            9600
 #define HINIC3_MIN_MTU_SIZE            256
@@ -371,6 +372,18 @@ struct hinic3_port_stats_info {
        uint16_t rsvd1;
 };
 
+#define HINIC3_CMD_MAX_DP_DATA_NUM 50
+struct hinic3_cir_drop {
+       uint64_t rx_discard_phy;
+};
+
+struct hinic3_cmd_get_dp_info_resp {
+       struct mgmt_msg_head msg_head;
+       uint16_t length;
+       uint16_t rsvd;
+       uint64_t value[HINIC3_CMD_MAX_DP_DATA_NUM];
+};
+
 struct hinic3_vport_stats {
        uint64_t tx_unicast_pkts_vport;
        uint64_t tx_unicast_bytes_vport;
@@ -390,6 +403,8 @@ struct hinic3_vport_stats {
        uint64_t rx_discard_vport;
        uint64_t tx_err_vport;
        uint64_t rx_err_vport;
+       uint64_t rx_mtu_err_vport;
+       uint64_t rx_out_of_buffer; /* fw: rx_nowqe */
 };
 
 struct hinic3_cmd_vport_stats {
@@ -398,7 +413,7 @@ struct hinic3_cmd_vport_stats {
        uint32_t stats_size;
        uint32_t rsvd1;
        struct hinic3_vport_stats stats;
-       uint64_t rsvd2[6];
+       uint64_t rsvd2[4];
 };
 
 struct hinic3_phy_port_stats {
@@ -1540,4 +1555,32 @@ int hinic3_set_feature_to_hw(struct hinic3_hwdev *hwdev, 
uint64_t *s_feature, ui
 
 int hinic3_set_link_status_follow(struct hinic3_hwdev *hwdev,
                                  enum hinic3_link_follow_status status);
+
+/* VF LAG definitions */
+#define VF_LAG_VF_NUM_GROUP_NUM 128
+#define VF_LAG_VF_NUM_PER_GROUP 32
+#define HINIC3_CMD_OPCODE_SET 0
+#define HINIC3_CMD_OPCODE_GET 1
+
+typedef struct hinic3_vf_lag_bitmap_s {
+       uint32_t vf_bit_map[VF_LAG_VF_NUM_GROUP_NUM];
+} hinic3_vf_lag_bitmap;
+
+struct hinic3_vf_lag_cmd {
+       struct mgmt_msg_head msg_head;
+
+       uint16_t func_id;
+       uint8_t opcode; /* 0 -> set, 1 -> get */
+       uint8_t en_flag; /* 0 -> disable, 1 -> enable  */
+       uint8_t bond_active_num;
+       uint8_t bond_active_bitmap;
+       uint8_t mac_sync_flag;
+       uint8_t rsvd;
+       hinic3_vf_lag_bitmap vf_lag_bitmap;
+};
+
+int hinic3_get_cir_drop(void *hwdev, struct hinic3_cir_drop *stats);
+
+bool hinic3_cmd_vf_lag(void *hwdev, uint16_t func_id, uint8_t opcode);
+
 #endif /* _HINIC3_NIC_CFG_H_ */
diff --git a/drivers/net/hinic3/hinic3_ethdev.c 
b/drivers/net/hinic3/hinic3_ethdev.c
index 61ea3172fc..46cc19613a 100644
--- a/drivers/net/hinic3/hinic3_ethdev.c
+++ b/drivers/net/hinic3/hinic3_ethdev.c
@@ -80,12 +80,25 @@ struct hinic3_xstats_name_off {
        uint32_t offset;
 };
 
+#define HINIC3_CIR_DROP_STAT(_stat_item)                                   \
+       {                                                                  \
+               .name = #_stat_item,                                       \
+               .offset = offsetof(struct hinic3_cir_drop, _stat_item),    \
+       }
+
 #define HINIC3_FUNC_STAT(_stat_item)                                       \
        {                                                                  \
                .name = #_stat_item,                                       \
                .offset = offsetof(struct hinic3_vport_stats, _stat_item), \
        }
 
+
+static struct hinic3_xstats_name_off hinic3_cir_drop_stats_strings[] = {
+       HINIC3_CIR_DROP_STAT(rx_discard_phy),
+};
+
+#define HINIC3_CIR_DROP_XSTATS_NUM  RTE_DIM(hinic3_cir_drop_stats_strings)
+
 static const struct hinic3_xstats_name_off hinic3_vport_stats_strings[] = {
        HINIC3_FUNC_STAT(tx_unicast_pkts_vport),
        HINIC3_FUNC_STAT(tx_unicast_bytes_vport),
@@ -105,6 +118,8 @@ static const struct hinic3_xstats_name_off 
hinic3_vport_stats_strings[] = {
        HINIC3_FUNC_STAT(rx_discard_vport),
        HINIC3_FUNC_STAT(tx_err_vport),
        HINIC3_FUNC_STAT(rx_err_vport),
+       HINIC3_FUNC_STAT(rx_mtu_err_vport),
+       HINIC3_FUNC_STAT(rx_out_of_buffer),
 };
 
 #define HINIC3_VPORT_XSTATS_NUM RTE_DIM(hinic3_vport_stats_strings)
@@ -284,12 +299,16 @@ static const struct hinic3_xstats_name_off 
hinic3_txq_stats_strings[] = {
 static uint32_t
 hinic3_xstats_calc_num(struct hinic3_nic_dev *nic_dev)
 {
+       uint32_t cir_drop_num = HINIC3_IS_SP620_NIC(nic_dev) ?
+                               HINIC3_CIR_DROP_XSTATS_NUM : 0;
+
        if (HINIC3_IS_VF(nic_dev->hwdev)) {
-               return (HINIC3_VPORT_XSTATS_NUM +
+               return (HINIC3_VPORT_XSTATS_NUM + cir_drop_num +
                        HINIC3_RXQ_XSTATS_NUM * nic_dev->num_rqs +
                        HINIC3_TXQ_XSTATS_NUM * nic_dev->num_sqs);
        } else {
                return (HINIC3_VPORT_XSTATS_NUM + HINIC3_PHYPORT_XSTATS_NUM +
+                       cir_drop_num +
                        HINIC3_RXQ_XSTATS_NUM * nic_dev->num_rqs +
                        HINIC3_TXQ_XSTATS_NUM * nic_dev->num_sqs);
        }
@@ -1271,7 +1290,14 @@ hinic3_tx_queue_setup(struct rte_eth_dev *dev, uint16_t 
qid, uint16_t nb_desc,
        txq->wqebb_size = (uint16_t)RTE_BIT32(txq->wqebb_shift);
        txq->tx_free_thresh = tx_free_thresh;
        txq->owner = 1;
-       txq->cos = nic_dev->default_cos;
+
+       if (!ODD_NUMBER_QUEUE_ID(qid) &&
+               hinic3_cmd_vf_lag(nic_dev->hwdev, 
hinic3_global_func_id(nic_dev->hwdev),
+                                 HINIC3_CMD_OPCODE_GET))
+               txq->cos = SELECT_OTHER_COS_ID(nic_dev->default_cos);
+       else
+               txq->cos = nic_dev->default_cos;
+
        txq->tx_deferred_start = tx_conf->tx_deferred_start;
        txq->tx_wqe_compact_task = HINIC3_SUPPORT_TX_WQE_COMPACT_TASK(nic_dev);
 
@@ -2913,6 +2939,38 @@ hinic3_dev_stats_reset(struct rte_eth_dev *dev)
        return 0;
 }
 
+static uint16_t
+get_port_cir_drop(struct hinic3_nic_dev *nic_dev,
+                 struct rte_eth_xstat *xstats, uint32_t base)
+{
+       struct hinic3_cir_drop port_stats;
+       uint16_t i;
+       int err;
+
+       memset(&port_stats, 0, sizeof(port_stats));
+
+       err = hinic3_get_cir_drop(nic_dev->hwdev, &port_stats);
+       if (err) {
+               PMD_DRV_LOG(ERR, "Failed to get CPB cir drops from fw.");
+
+               for (i = 0; i < RTE_DIM(hinic3_cir_drop_stats_strings); i++) {
+                       xstats[i].value = 0;
+                       xstats[i].id = base + i;
+               }
+
+               return RTE_DIM(hinic3_cir_drop_stats_strings);
+       }
+
+       for (i = 0; i < RTE_DIM(hinic3_cir_drop_stats_strings); i++) {
+               memcpy(&xstats[i].value,
+                      (const char *)&port_stats + 
hinic3_cir_drop_stats_strings[i].offset,
+                      sizeof(uint64_t));
+               xstats[i].id = base + i;
+       }
+
+       return RTE_DIM(hinic3_cir_drop_stats_strings);
+}
+
 /**
  * Get device extended statistics.
  *
@@ -3001,6 +3059,10 @@ hinic3_dev_xstats_get(struct rte_eth_dev *dev, struct 
rte_eth_xstat *xstats,
                count++;
        }
 
+       /* Get stats from cir drop stats structure */
+       if (HINIC3_IS_SP620_NIC(nic_dev))
+               count += get_port_cir_drop(nic_dev, &xstats[count], count);
+
        if (HINIC3_IS_VF(nic_dev->hwdev))
                return count;
 
@@ -3101,6 +3163,16 @@ hinic3_dev_xstats_get_names(struct rte_eth_dev *dev,
                count++;
        }
 
+       /* Get cir drop stats name. */
+       if (HINIC3_IS_SP620_NIC(nic_dev)) {
+               for (i = 0; i < HINIC3_CIR_DROP_XSTATS_NUM; i++) {
+                       strlcpy(xstats_names[count].name,
+                               hinic3_cir_drop_stats_strings[i].name,
+                               sizeof(xstats_names[count].name));
+                       count++;
+               }
+       }
+
        if (HINIC3_IS_VF(nic_dev->hwdev))
                return count;
 
diff --git a/drivers/net/hinic3/hinic3_ethdev.h 
b/drivers/net/hinic3/hinic3_ethdev.h
index f4d8c16640..c3384e5fd0 100644
--- a/drivers/net/hinic3/hinic3_ethdev.h
+++ b/drivers/net/hinic3/hinic3_ethdev.h
@@ -162,6 +162,9 @@ struct hinic3_nic_dev {
 
 };
 
+#define SELECT_OTHER_COS_ID(cos_id) ((cos_id) ^ 4)
+#define ODD_NUMBER_QUEUE_ID(q_id) ((q_id) & 1)
+
 #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)
 
-- 
2.33.0

Reply via email to