provide meter ops implementations. Signed-off-by: Junlong Wang --- doc/guides/nics/features/zxdh.ini | 8 + doc/guides/nics/zxdh.rst | 5 + drivers/net/zxdh/meson.build | 1 + drivers/net/zxdh/zxdh_ethdev.c | 81 +- drivers/net/zxdh/zxdh_ethdev.h | 14 +- drivers/net/zxdh/zxdh_ethdev_ops.c | 4 + drivers/net/zxdh/zxdh_ethdev_ops.h | 1 + drivers/net/zxdh/zxdh_msg.c | 196 +++++ drivers/net/zxdh/zxdh_msg.h | 48 ++ drivers/net/zxdh/zxdh_mtr.c | 1223 ++++++++++++++++++++++++++++ drivers/net/zxdh/zxdh_mtr.h | 114 +++ drivers/net/zxdh/zxdh_np.c | 465 +++++++++++ drivers/net/zxdh/zxdh_np.h | 222 +++++ drivers/net/zxdh/zxdh_tables.h | 3 + 14 files changed, 2383 insertions(+), 2 deletions(-) create mode 100644 drivers/net/zxdh/zxdh_mtr.c create mode 100644 drivers/net/zxdh/zxdh_mtr.h diff --git a/doc/guides/nics/features/zxdh.ini b/doc/guides/nics/features/zxdh.ini index 3561e31666..9e31817b5e 100644 --- a/doc/guides/nics/features/zxdh.ini +++ b/doc/guides/nics/features/zxdh.ini @@ -24,4 +24,12 @@ RSS reta update = Y Inner RSS = Y Basic stats = Y Stats per queue = Y +Extended stats = Y MTU update = Y +FW version = Y +Module EEPROM dump = Y +L3 checksum offload = Y +Inner L3 checksum = Y +Inner L4 checksum = Y +LRO = Y +TSO = Y diff --git a/doc/guides/nics/zxdh.rst b/doc/guides/nics/zxdh.rst index 30179c4e6f..26dd527196 100644 --- a/doc/guides/nics/zxdh.rst +++ b/doc/guides/nics/zxdh.rst @@ -36,6 +36,11 @@ Features of the ZXDH PMD are: - Port hardware statistics - MTU update - Jumbo frames +- Inner and Outer Checksum offload +- Hardware LRO +- Hardware TSO for generic IP or UDP tunnel, including VXLAN +- Extended Statistics query +- Ingress meter support Driver compilation and testing diff --git a/drivers/net/zxdh/meson.build b/drivers/net/zxdh/meson.build index 48f8f5e1ee..a48a0d43c2 100644 --- a/drivers/net/zxdh/meson.build +++ b/drivers/net/zxdh/meson.build @@ -23,4 +23,5 @@ sources = files( 'zxdh_tables.c', 'zxdh_rxtx.c', 'zxdh_ethdev_ops.c', + 'zxdh_mtr.c', ) diff --git a/drivers/net/zxdh/zxdh_ethdev.c b/drivers/net/zxdh/zxdh_ethdev.c index 5546b6bfc3..2c24e99a77 100644 --- a/drivers/net/zxdh/zxdh_ethdev.c +++ b/drivers/net/zxdh/zxdh_ethdev.c @@ -24,6 +24,7 @@ const char *ZXDH_PMD_SHARED_DATA_MZ = "zxdh_pmd_shared_data"; rte_spinlock_t zxdh_shared_data_lock = RTE_SPINLOCK_INITIALIZER; struct zxdh_dev_shared_data g_dev_sd[ZXDH_SLOT_MAX]; struct zxdh_net_hdr_dl g_net_hdr_dl[RTE_MAX_ETHPORTS]; +struct zxdh_mtr_res g_mtr_res; #define ZXDH_INVALID_DTBQUE 0xFFFF #define ZXDH_INVALID_SLOT_IDX 0xFFFF @@ -1408,6 +1409,7 @@ static const struct eth_dev_ops zxdh_eth_dev_ops = { .get_module_info = zxdh_dev_get_module_info, .get_module_eeprom = zxdh_dev_get_module_eeprom, .dev_supported_ptypes_get = zxdh_dev_supported_ptypes_get, + .mtr_ops_get = zxdh_meter_ops_get, }; static int32_t @@ -1637,6 +1639,72 @@ zxdh_init_shared_data(void) return ret; } +static void +zxdh_free_sh_res(void) +{ + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + rte_spinlock_lock(&zxdh_shared_data_lock); + if (zxdh_shared_data != NULL && zxdh_shared_data->init_done && + (--zxdh_shared_data->dev_refcnt == 0)) { + rte_mempool_free(zxdh_shared_data->mtr_mp); + rte_mempool_free(zxdh_shared_data->mtr_profile_mp); + rte_mempool_free(zxdh_shared_data->mtr_policy_mp); + } + rte_spinlock_unlock(&zxdh_shared_data_lock); + } +} + +static int +zxdh_init_sh_res(struct zxdh_shared_data *sd) +{ + const char *MZ_ZXDH_MTR_MP = "zxdh_mtr_mempool"; + const char *MZ_ZXDH_MTR_PROFILE_MP = "zxdh_mtr_profile_mempool"; + const char *MZ_ZXDH_MTR_POLICY_MP = "zxdh_mtr_policy_mempool"; + struct rte_mempool *flow_mp = NULL; + struct rte_mempool *mtr_mp = NULL; + struct rte_mempool *mtr_profile_mp = NULL; + struct rte_mempool *mtr_policy_mp = NULL; + + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + mtr_mp = rte_mempool_create(MZ_ZXDH_MTR_MP, ZXDH_MAX_MTR_NUM, + sizeof(struct zxdh_mtr_object), 64, 0, + NULL, NULL, NULL, NULL, SOCKET_ID_ANY, 0); + if (mtr_mp == NULL) { + PMD_DRV_LOG(ERR, "Cannot allocate zxdh mtr mempool"); + goto error; + } + mtr_profile_mp = rte_mempool_create(MZ_ZXDH_MTR_PROFILE_MP, + MAX_MTR_PROFILE_NUM, sizeof(struct zxdh_meter_profile), + 64, 0, NULL, NULL, NULL, + NULL, SOCKET_ID_ANY, 0); + if (mtr_profile_mp == NULL) { + PMD_DRV_LOG(ERR, "Cannot allocate zxdh mtr profile mempool"); + goto error; + } + mtr_policy_mp = rte_mempool_create(MZ_ZXDH_MTR_POLICY_MP, + ZXDH_MAX_POLICY_NUM, sizeof(struct zxdh_meter_policy), + 64, 0, NULL, NULL, NULL, NULL, SOCKET_ID_ANY, 0); + if (mtr_policy_mp == NULL) { + PMD_DRV_LOG(ERR, "Cannot allocate zxdh mtr profile mempool"); + goto error; + } + sd->mtr_mp = mtr_mp; + sd->mtr_profile_mp = mtr_profile_mp; + sd->mtr_policy_mp = mtr_policy_mp; + TAILQ_INIT(&zxdh_shared_data->meter_profile_list); + TAILQ_INIT(&zxdh_shared_data->mtr_list); + TAILQ_INIT(&zxdh_shared_data->mtr_policy_list); + } + return 0; + +error: + rte_mempool_free(mtr_policy_mp); + rte_mempool_free(mtr_profile_mp); + rte_mempool_free(mtr_mp); + rte_mempool_free(flow_mp); + return -rte_errno; +} + static int zxdh_init_once(struct rte_eth_dev *eth_dev) { @@ -1664,8 +1732,16 @@ zxdh_init_once(struct rte_eth_dev *eth_dev) goto out; } /* RTE_PROC_PRIMARY */ - if (!sd->init_done) + if (!sd->init_done) { + /*shared struct and res init */ + ret = zxdh_init_sh_res(sd); + if (ret != 0) + goto out; + rte_spinlock_init(&g_mtr_res.hw_plcr_res_lock); + memset(&g_mtr_res, 0, sizeof(g_mtr_res)); sd->init_done = true; + } + sd->dev_refcnt++; out: @@ -1879,6 +1955,9 @@ zxdh_eth_dev_init(struct rte_eth_dev *eth_dev) zxdh_np_uninit(eth_dev); zxdh_bar_msg_chan_exit(); zxdh_priv_res_free(hw); + zxdh_free_sh_res(); + rte_free(hw->dev_sd); + hw->dev_sd = NULL; rte_free(eth_dev->data->mac_addrs); eth_dev->data->mac_addrs = NULL; return ret; diff --git a/drivers/net/zxdh/zxdh_ethdev.h b/drivers/net/zxdh/zxdh_ethdev.h index 87c3b5f022..6ad714d29a 100644 --- a/drivers/net/zxdh/zxdh_ethdev.h +++ b/drivers/net/zxdh/zxdh_ethdev.h @@ -10,6 +10,8 @@ #include #include +#include "zxdh_mtr.h" + /* ZXDH PCI vendor/device ID. */ #define ZXDH_PCI_VENDOR_ID 0x1cf2 @@ -113,7 +115,10 @@ struct zxdh_hw { uint8_t use_msix; uint8_t duplex; - uint8_t is_pf; + uint8_t is_pf : 1, + rsv : 1, + i_mtr_en : 1, + e_mtr_en : 1; uint8_t msg_chan_init; uint8_t phyport; uint8_t panel_id; @@ -157,6 +162,13 @@ struct zxdh_shared_data { int32_t np_init_done; uint32_t dev_refcnt; struct zxdh_dtb_shared_data *dtb_data; + + struct rte_mempool *mtr_mp; + struct rte_mempool *mtr_profile_mp; + struct rte_mempool *mtr_policy_mp; + struct zxdh_mtr_profile_list meter_profile_list; + struct zxdh_mtr_list mtr_list; + struct zxdh_mtr_policy_list mtr_policy_list; }; struct zxdh_dev_shared_data { diff --git a/drivers/net/zxdh/zxdh_ethdev_ops.c b/drivers/net/zxdh/zxdh_ethdev_ops.c index 3e88860765..512e1cce2e 100644 --- a/drivers/net/zxdh/zxdh_ethdev_ops.c +++ b/drivers/net/zxdh/zxdh_ethdev_ops.c @@ -14,6 +14,7 @@ #include "zxdh_rxtx.h" #include "zxdh_np.h" #include "zxdh_queue.h" +#include "zxdh_mtr.h" #define ZXDH_VLAN_FILTER_GROUPS 64 #define ZXDH_INVALID_LOGIC_QID 0xFFFFU @@ -1624,6 +1625,9 @@ zxdh_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) stats->ierrors = vqm_stats.rx_error + mac_stats.rx_error + np_stats.rx_mtu_drop_pkts; stats->oerrors = vqm_stats.tx_error + mac_stats.tx_error + np_stats.tx_mtu_drop_pkts; + if (hw->i_mtr_en || hw->e_mtr_en) + stats->imissed += np_stats.rx_mtr_drop_pkts; + stats->rx_nombuf = dev->data->rx_mbuf_alloc_failed; for (i = 0; (i < dev->data->nb_rx_queues) && (i < RTE_ETHDEV_QUEUE_STAT_CNTRS); i++) { struct zxdh_virtnet_rx *rxvq = dev->data->rx_queues[i]; diff --git a/drivers/net/zxdh/zxdh_ethdev_ops.h b/drivers/net/zxdh/zxdh_ethdev_ops.h index 08b9e3341b..ead571067c 100644 --- a/drivers/net/zxdh/zxdh_ethdev_ops.h +++ b/drivers/net/zxdh/zxdh_ethdev_ops.h @@ -108,5 +108,6 @@ int zxdh_dev_fw_version_get(struct rte_eth_dev *dev, char *fw_version, int zxdh_dev_get_module_info(struct rte_eth_dev *dev, struct rte_eth_dev_module_info *modinfo); int zxdh_dev_get_module_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *info); +int zxdh_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg); #endif /* ZXDH_ETHDEV_OPS_H */ diff --git a/drivers/net/zxdh/zxdh_msg.c b/drivers/net/zxdh/zxdh_msg.c index 0790cb2291..00a8db4a69 100644 --- a/drivers/net/zxdh/zxdh_msg.c +++ b/drivers/net/zxdh/zxdh_msg.c @@ -10,6 +10,7 @@ #include #include #include +#include "rte_mtr_driver.h" #include "zxdh_ethdev.h" #include "zxdh_logs.h" @@ -1693,6 +1694,12 @@ zxdh_vf_port_attr_set(struct zxdh_hw *pf_hw, uint16_t vport, void *cfg_data, case ZXDH_PORT_LRO_OFFLOAD_FLAG: port_attr.lro_offload = attr_msg->value; break; + case ZXDH_PORT_EGRESS_METER_EN_OFF_FLAG: + port_attr.egress_meter_enable = attr_msg->value; + break; + case ZXDH_PORT_INGRESS_METER_EN_OFF_FLAG: + port_attr.ingress_meter_mode = attr_msg->value; + break; default: PMD_DRV_LOG(ERR, "unsupport attr 0x%x set", attr_msg->mode); return -1; @@ -1846,6 +1853,190 @@ zxdh_vf_np_stats_update(struct zxdh_hw *pf_hw, uint16_t vport, return 0; } +static int +zxdh_vf_mtr_hw_stats_get(struct zxdh_hw *pf_hw __rte_unused, + uint16_t vport, void *cfg_data, + struct zxdh_msg_reply_body *res_info, + uint16_t *res_len) +{ + struct zxdh_mtr_stats_query *zxdh_mtr_stats_query = + (struct zxdh_mtr_stats_query *)cfg_data; + union zxdh_virport_num v_port = {.vport = vport}; + int ret = 0; + + uint32_t stat_baseaddr = zxdh_mtr_stats_query->direction == + ZXDH_EGRESS ? + ZXDH_MTR_STATS_EGRESS_BASE : ZXDH_MTR_STATS_INGRESS_BASE; + uint32_t idx = zxdh_vport_to_vfid(v_port) + stat_baseaddr; + + if (!res_len || !res_info) { + PMD_DRV_LOG(ERR, "get stat invalid in params"); + return -1; + } + res_info->flag = ZXDH_REPS_FAIL; + ret = zxdh_np_dtb_stats_get(pf_hw->dev_id, pf_hw->dev_sd->dtb_sd.queueid, + 1, idx, (uint32_t *)&res_info->hw_mtr_stats); + if (ret) { + PMD_DRV_LOG(ERR, "get dir %d stats failed", zxdh_mtr_stats_query->direction); + return ret; + } + res_info->flag = ZXDH_REPS_SUCC; + *res_len = sizeof(struct zxdh_hw_mtr_stats); + return 0; +} + +static int +zxdh_vf_mtr_hw_profile_add(struct zxdh_hw *pf_hw __rte_unused, + uint16_t vport, + void *cfg_data, + struct zxdh_msg_reply_body *res_info, + uint16_t *res_len) +{ + if (!cfg_data || !res_len || !res_info) { + PMD_DRV_LOG(ERR, " get profileid invalid inparams"); + return -1; + } + struct rte_mtr_error error = {0}; + int ret = 0; + uint64_t profile_id = HW_PROFILE_MAX; + + struct zxdh_plcr_profile_add *zxdh_plcr_profile_add = + (struct zxdh_plcr_profile_add *)cfg_data; + + res_info->flag = ZXDH_REPS_FAIL; + *res_len = sizeof(struct zxdh_mtr_profile_info); + ret = zxdh_hw_profile_alloc_direct(pf_hw->eth_dev, + zxdh_plcr_profile_add->car_type, + &profile_id, &error); + + if (ret) { + PMD_DRV_LOG(ERR, "pf 0x%x for vf 0x%x alloc hw profile failed", + pf_hw->vport.vport, + vport + ); + return -1; + } + zxdh_hw_profile_ref(profile_id); + res_info->mtr_profile_info.profile_id = profile_id; + res_info->flag = ZXDH_REPS_SUCC; + + return 0; +} + +static int +zxdh_vf_mtr_hw_profile_del(struct zxdh_hw *pf_hw, + uint16_t vport, + void *cfg_data, + struct zxdh_msg_reply_body *res_info, + uint16_t *res_len) +{ + if (!cfg_data || !res_len || !res_info) { + PMD_DRV_LOG(ERR, " del profileid invalid inparams"); + return -1; + } + + res_info->flag = ZXDH_REPS_FAIL; + *res_len = 0; + struct zxdh_plcr_profile_free *mtr_profile_free = (struct zxdh_plcr_profile_free *)cfg_data; + uint64_t profile_id = mtr_profile_free->profile_id; + struct rte_mtr_error error = {0}; + int ret; + + if (profile_id >= HW_PROFILE_MAX) { + PMD_DRV_LOG(ERR, " del profileid invalid inparams"); + return -rte_mtr_error_set(&error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, NULL, + "Meter offload del profile failed profilie id invalid "); + } + + ret = zxdh_hw_profile_unref(pf_hw->eth_dev, mtr_profile_free->car_type, profile_id, &error); + if (ret) { + PMD_DRV_LOG(ERR, + " del hw vport %d profile %d failed. code:%d", + vport, + mtr_profile_free->profile_id, + ret + ); + return -rte_mtr_error_set(&error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, NULL, + "Meter offload del profile failed "); + } + res_info->flag = ZXDH_REPS_SUCC; + return 0; +} + +static int +zxdh_vf_mtr_hw_plcrflow_cfg(struct zxdh_hw *pf_hw, + uint16_t vport, + void *cfg_data, + struct zxdh_msg_reply_body *res_info, + uint16_t *res_len) +{ + int ret = 0; + + if (!cfg_data || !res_info || !res_len) { + PMD_DRV_LOG(ERR, " (vport %d) flow bind failed invalid inparams", vport); + return -1; + } + struct rte_mtr_error error = {0}; + struct zxdh_plcr_flow_cfg *zxdh_plcr_flow_cfg = (struct zxdh_plcr_flow_cfg *)cfg_data; + + res_info->flag = ZXDH_REPS_FAIL; + *res_len = 0; + ret = zxdh_np_stat_car_queue_cfg_set(pf_hw->dev_id, + zxdh_plcr_flow_cfg->car_type, + zxdh_plcr_flow_cfg->flow_id, + zxdh_plcr_flow_cfg->drop_flag, + zxdh_plcr_flow_cfg->plcr_en, + (uint64_t)zxdh_plcr_flow_cfg->profile_id); + if (ret) { + PMD_DRV_LOG(ERR, + " dpp_stat_car_queue_cfg_set failed flowid %d profile id %d. code:%d", + zxdh_plcr_flow_cfg->flow_id, + zxdh_plcr_flow_cfg->profile_id, + ret + ); + return -rte_mtr_error_set(&error, ENOTSUP, + RTE_MTR_ERROR_TYPE_MTR_PARAMS, + NULL, "Failed to bind plcr flow."); + } + res_info->flag = ZXDH_REPS_SUCC; + return 0; +} + +static int +zxdh_vf_mtr_hw_profile_cfg(struct zxdh_hw *pf_hw __rte_unused, + uint16_t vport, + void *cfg_data, + struct zxdh_msg_reply_body *res_info, + uint16_t *res_len) +{ + int ret = 0; + + if (!cfg_data || !res_info || !res_len) { + PMD_DRV_LOG(ERR, " cfg profile invalid inparams"); + return -1; + } + res_info->flag = ZXDH_REPS_FAIL; + *res_len = 0; + struct rte_mtr_error error = {0}; + struct zxdh_plcr_profile_cfg *zxdh_plcr_profile_cfg = + (struct zxdh_plcr_profile_cfg *)cfg_data; + union zxdh_offload_profile_cfg *plcr_param = &zxdh_plcr_profile_cfg->plcr_param; + + ret = zxdh_np_car_profile_cfg_set(vport, + zxdh_plcr_profile_cfg->car_type, + zxdh_plcr_profile_cfg->packet_mode, + zxdh_plcr_profile_cfg->hw_profile_id, + plcr_param); + if (ret) { + PMD_DRV_LOG(ERR, "(vport %d)config hw profilefailed", vport); + return -rte_mtr_error_set(&error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL, "Meter offload cfg profile failed"); + } + res_info->flag = ZXDH_REPS_SUCC; + return 0; +} + zxdh_msg_process_callback zxdh_proc_cb[] = { [ZXDH_NULL] = NULL, [ZXDH_VF_PORT_INIT] = zxdh_vf_port_init, @@ -1863,6 +2054,11 @@ zxdh_msg_process_callback zxdh_proc_cb[] = { [ZXDH_VLAN_OFFLOAD] = zxdh_vf_set_vlan_offload, [ZXDH_PORT_ATTRS_SET] = zxdh_vf_port_attr_set, [ZXDH_GET_NP_STATS] = zxdh_vf_np_stats_update, + [ZXDH_PORT_METER_STAT_GET] = zxdh_vf_mtr_hw_stats_get, + [ZXDH_PLCR_CAR_PROFILE_ID_ADD] = zxdh_vf_mtr_hw_profile_add, + [ZXDH_PLCR_CAR_PROFILE_ID_DELETE] = zxdh_vf_mtr_hw_profile_del, + [ZXDH_PLCR_CAR_QUEUE_CFG_SET] = zxdh_vf_mtr_hw_plcrflow_cfg, + [ZXDH_PLCR_CAR_PROFILE_CFG_SET] = zxdh_vf_mtr_hw_profile_cfg, }; static inline int diff --git a/drivers/net/zxdh/zxdh_msg.h b/drivers/net/zxdh/zxdh_msg.h index b3e202c026..2606f36d21 100644 --- a/drivers/net/zxdh/zxdh_msg.h +++ b/drivers/net/zxdh/zxdh_msg.h @@ -10,6 +10,7 @@ #include #include "zxdh_ethdev_ops.h" +#include "zxdh_mtr.h" #define ZXDH_BAR0_INDEX 0 #define ZXDH_CTRLCH_OFFSET (0x2000) @@ -230,6 +231,11 @@ enum zxdh_msg_type { ZXDH_PORT_PROMISC_SET = 26, ZXDH_GET_NP_STATS = 31, + ZXDH_PLCR_CAR_PROFILE_ID_ADD = 36, + ZXDH_PLCR_CAR_PROFILE_ID_DELETE = 37, + ZXDH_PLCR_CAR_PROFILE_CFG_SET, + ZXDH_PLCR_CAR_QUEUE_CFG_SET = 40, + ZXDH_PORT_METER_STAT_GET = 42, ZXDH_MSG_TYPE_END, }; @@ -373,6 +379,10 @@ struct __rte_packed_begin zxdh_rss_hf { uint32_t rss_hf; } __rte_packed_end; +struct zxdh_mtr_profile_info { + uint64_t profile_id; +}; + struct __rte_packed_begin zxdh_msg_reply_body { enum zxdh_reps_flag flag; union __rte_packed_begin { @@ -386,6 +396,8 @@ struct __rte_packed_begin zxdh_msg_reply_body { struct zxdh_np_stats_updata_msg np_stats_query; struct zxdh_flash_msg flash_msg; struct zxdh_mac_module_eeprom_msg module_eeprom_msg; + struct zxdh_mtr_profile_info mtr_profile_info; + struct zxdh_mtr_stats hw_mtr_stats; } __rte_packed_end; } __rte_packed_end; @@ -443,6 +455,37 @@ struct zxdh_rss_enable { uint8_t enable; }; +struct __rte_packed_begin zxdh_plcr_profile_add { + uint8_t car_type;/* 0 :carA ; 1:carB ;2 carC*/ +} __rte_packed_end; + +struct __rte_packed_begin zxdh_mtr_stats_query { + uint8_t direction; + uint8_t is_clr; +} __rte_packed_end; + +struct __rte_packed_begin zxdh_plcr_profile_cfg { + uint8_t car_type; /* 0 :carA ; 1:carB ;2 carC*/ + uint8_t packet_mode; /*0 bps 1 pps */ + uint16_t hw_profile_id; + union zxdh_offload_profile_cfg plcr_param; +} __rte_packed_end; + +struct __rte_packed_begin zxdh_plcr_flow_cfg { + uint8_t car_type; /* 0:carA; 1:carB; 2:carC */ + uint8_t drop_flag; /* default */ + uint8_t plcr_en; /* 1:bind, 0:unbind */ + uint8_t rsv; + uint16_t flow_id; + uint16_t profile_id; +} __rte_packed_end; + +struct __rte_packed_begin zxdh_plcr_profile_free { + uint8_t car_type; + uint8_t rsv; + uint16_t profile_id; +} __rte_packed_end; + struct __rte_packed_begin zxdh_agent_msg_head { enum zxdh_agent_msg_type msg_type; uint8_t panel_id; @@ -473,6 +516,11 @@ struct __rte_packed_begin zxdh_msg_info { struct zxdh_rss_hf rss_hf; struct zxdh_np_stats_updata_msg np_stats_query; struct zxdh_mac_module_eeprom_msg module_eeprom_msg; + struct zxdh_plcr_profile_add zxdh_plcr_profile_add; + struct zxdh_plcr_profile_free zxdh_plcr_profile_free; + struct zxdh_plcr_profile_cfg zxdh_plcr_profile_cfg; + struct zxdh_plcr_flow_cfg zxdh_plcr_flow_cfg; + struct zxdh_mtr_stats_query zxdh_mtr_stats_query; } __rte_packed_end data; } __rte_packed_end; diff --git a/drivers/net/zxdh/zxdh_mtr.c b/drivers/net/zxdh/zxdh_mtr.c new file mode 100644 index 0000000000..09e601d336 --- /dev/null +++ b/drivers/net/zxdh/zxdh_mtr.c @@ -0,0 +1,1223 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 ZTE Corporation + */ + +#include +#include +#include +#include + +#include "zxdh_logs.h" +#include "zxdh_mtr.h" +#include "zxdh_msg.h" +#include "zxdh_ethdev.h" +#include "zxdh_tables.h" + +#define ZXDH_SHARE_FLOW_MAX 2048 +#define ZXDH_HW_PROFILE_MAX 512 +#define ZXDH_MAX_MTR_PROFILE_NUM ZXDH_HW_PROFILE_MAX +#define ZXDH_PORT_MTR_FID_BASE 8192 + +/* Maximum value of srTCM metering parameters, unit_step: 64kb + * 61K~400000000(400G) bps, uint 64Kbps CBS/EBS/PBS max bucket depth 128MB + * PPS: 1pps~600Mpps + */ +#define ZXDH_SRTCM_CIR_MIN_BPS (61 * (1ULL << 10)) +#define ZXDH_SRTCM_CIR_MAX_BPS (400 * (1ULL << 30)) +#define ZXDH_SRTCM_EBS_MAX_B (128 * (1ULL << 20)) +#define ZXDH_SRTCM_CBS_MAX_B (128 * (1ULL << 20)) +#define ZXDH_TRTCM_PBS_MAX_B (128 * (1ULL << 20)) +#define ZXDH_TRTCM_PIR_MAX_BPS (400 * (1ULL << 30)) +#define ZXDH_TRTCM_PIR_MIN_BPS (61 * (1ULL << 10)) + +#define ZXDH_SRTCM_CIR_MIN_PPS (1) +#define ZXDH_SRTCM_CIR_MAX_PPS (200 * (1ULL << 20)) +#define ZXDH_SRTCM_CBS_MAX_P (8192) +#define ZXDH_SRTCM_EBS_MAX_P (8192) +#define ZXDH_TRTCM_PBS_MAX_P (8192) +#define ZXDH_TRTCM_PIR_MIN_PPS (1) +#define ZXDH_TRTCM_PIR_MAX_PPS (200 * (1ULL << 20)) + +#define ZXDH_MP_ALLOC_OBJ_FUNC(mp, obj) rte_mempool_get(mp, (void **)&(obj)) +#define ZXDH_MP_FREE_OBJ_FUNC(mp, obj) rte_mempool_put(mp, obj) + +#define ZXDH_VFUNC_ACTIVE_BIT 11 +#define ZXDH_VFUNC_NUM_MASK 0xff +#define ZXDH_GET_OWNER_PF_VPORT(vport) \ + (((vport) & ~(ZXDH_VFUNC_NUM_MASK)) & (~(1 << ZXDH_VFUNC_ACTIVE_BIT))) + +enum ZXDH_PLCR_CD { + ZXDH_PLCR_CD_SRTCM = 0, + ZXDH_PLCR_CD_TRTCM, + ZXDH_PLCR_CD_MEF101, +}; +enum ZXDH_PLCR_CM { + ZXDH_PLCR_CM_BLIND = 0, + ZXDH_PLCR_CM_AWARE, +}; +enum ZXDH_PLCR_CF { + ZXDH_PLCR_CF_UNOVERFLOW = 0, + ZXDH_PLCR_CF_OVERFLOW, +}; + +int +zxdh_hw_profile_ref(uint16_t hw_profile_id) +{ + if (hw_profile_id >= HW_PROFILE_MAX) + return -1; + + rte_spinlock_lock(&g_mtr_res.hw_plcr_res_lock); + g_mtr_res.hw_profile_refcnt[hw_profile_id]++; + rte_spinlock_unlock(&g_mtr_res.hw_plcr_res_lock); + return 0; +} + +static struct zxdh_meter_policy +*zxdh_mtr_policy_find_by_id(struct zxdh_mtr_policy_list *mtr_policy_list, + uint16_t policy_id, uint16_t dpdk_portid) +{ + struct zxdh_meter_policy *mtr_policy = NULL; + + TAILQ_FOREACH(mtr_policy, mtr_policy_list, next) { + if (policy_id == mtr_policy->policy_id && + dpdk_portid == mtr_policy->dpdk_port_id) + return mtr_policy; + } + return NULL; +} + +static int +zxdh_policy_validate_actions(const struct rte_flow_action *actions[RTE_COLORS], + struct rte_mtr_error *error) +{ + if (!actions[RTE_COLOR_RED] || actions[RTE_COLOR_RED]->type != RTE_FLOW_ACTION_TYPE_DROP) + return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, + "Red color only supports drop action."); + return 0; +} + +static int +mtr_hw_stats_get(struct zxdh_hw *hw, uint8_t direction, struct zxdh_hw_mtr_stats *hw_mtr_stats) +{ + union zxdh_virport_num v_port = hw->vport; + uint32_t stat_baseaddr = (direction == ZXDH_EGRESS) + ? ZXDH_MTR_STATS_EGRESS_BASE + : ZXDH_MTR_STATS_INGRESS_BASE; + uint32_t idx = zxdh_vport_to_vfid(v_port) + stat_baseaddr; + struct zxdh_dtb_shared_data *dtb_sd = &hw->dev_sd->dtb_sd; + + int ret = zxdh_np_dtb_stats_get(hw->dev_id, + dtb_sd->queueid, ZXDH_STAT_128_MODE, + idx, (uint32_t *)hw_mtr_stats); + + if (ret) { + PMD_DRV_LOG(ERR, "get vport 0x%x (vfid 0x%x) dir %u stats failed", + v_port.vport, + hw->vfid, + direction); + return ret; + } + PMD_DRV_LOG(INFO, "get vport 0x%x (vfid 0x%x) dir %u stats", + v_port.vport, + hw->vfid, + direction); + return 0; +} + +static int +zxdh_mtr_stats_get(struct rte_eth_dev *dev, int dir, struct zxdh_mtr_stats *mtr_stats) +{ + struct zxdh_hw_mtr_stats hw_mtr_stat = {0}; + struct zxdh_hw *hw = dev->data->dev_private; + int ret = mtr_hw_stats_get(hw, dir, &hw_mtr_stat); + + if (ret) { + PMD_DRV_LOG(ERR, "port %u dir %u get mtr stats failed", hw->vport.vport, dir); + return ret; + } + mtr_stats->n_bytes_dropped = + (uint64_t)(rte_le_to_cpu_32(hw_mtr_stat.n_bytes_dropped_hi)) << 32 | + rte_le_to_cpu_32(hw_mtr_stat.n_bytes_dropped_lo); + mtr_stats->n_pkts_dropped = + (uint64_t)(rte_le_to_cpu_32(hw_mtr_stat.n_pkts_dropped_hi)) << 32 | + rte_le_to_cpu_32(hw_mtr_stat.n_pkts_dropped_lo); + + return 0; +} + +static int +zxdh_meter_cap_get(struct rte_eth_dev *dev __rte_unused, + struct rte_mtr_capabilities *cap, + struct rte_mtr_error *error __rte_unused) +{ + struct rte_mtr_capabilities capa = { + .n_max = ZXDH_MAX_MTR_NUM, + .n_shared_max = ZXDH_SHARE_FLOW_MAX, + .meter_srtcm_rfc2697_n_max = ZXDH_MAX_MTR_PROFILE_NUM, + .meter_trtcm_rfc2698_n_max = ZXDH_MAX_MTR_PROFILE_NUM, + .color_aware_srtcm_rfc2697_supported = 1, + .color_aware_trtcm_rfc2698_supported = 1, + .meter_rate_max = ZXDH_SRTCM_CIR_MAX_BPS, + .meter_policy_n_max = ZXDH_MAX_POLICY_NUM, + .srtcm_rfc2697_byte_mode_supported = 1, + .srtcm_rfc2697_packet_mode_supported = 1, + .trtcm_rfc2698_byte_mode_supported = 1, + .trtcm_rfc2698_packet_mode_supported = 1, + .stats_mask = RTE_MTR_STATS_N_PKTS_DROPPED | RTE_MTR_STATS_N_BYTES_DROPPED, + }; + + memcpy(cap, &capa, sizeof(capa)); + return 0; +} + +static int +zxdh_mtr_profile_validate(uint32_t meter_profile_id, + struct rte_mtr_meter_profile *profile, + struct rte_mtr_error *error) +{ + uint64_t cir_min, cir_max, cbs_max, ebs_max, pir_min, pir_max, pbs_max; + + if (profile == NULL || meter_profile_id >= ZXDH_MAX_MTR_PROFILE_NUM) { + return -rte_mtr_error_set(error, EINVAL, RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL, + "Meter profile param id invaild or null"); + } + + if (profile->packet_mode == 0) { + cir_min = ZXDH_SRTCM_CIR_MIN_BPS / 8; + cir_max = ZXDH_SRTCM_CIR_MAX_BPS / 8; + cbs_max = ZXDH_SRTCM_CBS_MAX_B; + ebs_max = ZXDH_SRTCM_EBS_MAX_B; + pir_min = ZXDH_TRTCM_PIR_MIN_BPS / 8; + pir_max = ZXDH_TRTCM_PIR_MAX_BPS / 8; + pbs_max = ZXDH_TRTCM_PBS_MAX_B; + } else { + cir_min = ZXDH_SRTCM_CIR_MIN_PPS; + cir_max = ZXDH_SRTCM_CIR_MAX_PPS; + cbs_max = ZXDH_SRTCM_CBS_MAX_P; + ebs_max = ZXDH_SRTCM_EBS_MAX_P; + pir_min = ZXDH_TRTCM_PIR_MIN_PPS; + pir_max = ZXDH_TRTCM_PIR_MAX_PPS; + pbs_max = ZXDH_TRTCM_PBS_MAX_P; + } + if (profile->alg == RTE_MTR_SRTCM_RFC2697) { + if (profile->srtcm_rfc2697.cir >= cir_min && + profile->srtcm_rfc2697.cir < cir_max && + profile->srtcm_rfc2697.cbs < cbs_max && + profile->srtcm_rfc2697.cbs > 0 && + profile->srtcm_rfc2697.ebs > 0 && + profile->srtcm_rfc2697.ebs < ebs_max) { + goto check_exist; + } else { + return -rte_mtr_error_set + (error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_PROFILE, + NULL, + "Invalid metering parameters"); + } + } else if (profile->alg == RTE_MTR_TRTCM_RFC2698) { + if (profile->trtcm_rfc2698.cir >= cir_min && + profile->trtcm_rfc2698.cir < cir_max && + profile->trtcm_rfc2698.cbs < cbs_max && + profile->trtcm_rfc2698.cbs > 0 && + profile->trtcm_rfc2698.pir >= pir_min && + profile->trtcm_rfc2698.pir < pir_max && + profile->trtcm_rfc2698.cir < profile->trtcm_rfc2698.pir && + profile->trtcm_rfc2698.pbs > 0 && + profile->trtcm_rfc2698.pbs < pbs_max) + goto check_exist; + else + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_PROFILE, + NULL, + "Invalid metering parameters"); + } else { + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_PROFILE, + NULL, + "algorithm not supported"); + } + +check_exist: + return 0; +} + +static struct zxdh_meter_profile +*zxdh_mtr_profile_find_by_id(struct zxdh_mtr_profile_list *mpl, + uint32_t meter_profile_id, uint16_t dpdk_portid) +{ + struct zxdh_meter_profile *mp = NULL; + + TAILQ_FOREACH(mp, mpl, next) { + if (meter_profile_id == mp->meter_profile_id && mp->dpdk_port_id == dpdk_portid) + return mp; + } + return NULL; +} + +static struct zxdh_meter_profile +*zxdh_mtr_profile_res_alloc(struct rte_mempool *mtr_profile_mp) +{ + struct zxdh_meter_profile *meter_profile = NULL; + + if (ZXDH_MP_ALLOC_OBJ_FUNC(mtr_profile_mp, meter_profile) != 0) + return NULL; + + return meter_profile; +} + +static struct zxdh_meter_policy +*zxdh_mtr_policy_res_alloc(struct rte_mempool *mtr_policy_mp) +{ + struct zxdh_meter_policy *policy = NULL; + + rte_mempool_get(mtr_policy_mp, (void **)&policy); + PMD_DRV_LOG(INFO, "policy %p", policy); + return policy; +} + +static int +zxdh_hw_profile_free_direct(struct rte_eth_dev *dev, ZXDH_PROFILE_TYPE car_type, + uint16_t hw_profile_id, struct rte_mtr_error *error) +{ + struct zxdh_hw *hw = dev->data->dev_private; + uint16_t vport = hw->vport.vport; + int ret = zxdh_np_car_profile_id_delete(vport, car_type, + (uint64_t)hw_profile_id); + if (ret) { + PMD_DRV_LOG(ERR, "port %u free hw profile %u failed", vport, hw_profile_id); + return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, NULL, + "Meter free profile failed"); + } + + return 0; +} + +int +zxdh_hw_profile_alloc_direct(struct rte_eth_dev *dev, ZXDH_PROFILE_TYPE car_type, + uint64_t *hw_profile_id, struct rte_mtr_error *error) +{ + uint64_t profile_id = HW_PROFILE_MAX; + struct zxdh_hw *hw = dev->data->dev_private; + uint16_t vport = hw->vport.vport; + int ret = zxdh_np_car_profile_id_add(vport, car_type, &profile_id); + + if (ret) { + PMD_DRV_LOG(ERR, "port %u alloc hw profile failed", vport); + return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, NULL, + "Meter offload alloc profile failed"); + } + *hw_profile_id = profile_id; + if (*hw_profile_id == ZXDH_HW_PROFILE_MAX) { + return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, NULL, + "Meter offload alloc profile id invalid"); + } + + return 0; +} + +static uint16_t +zxdh_hw_profile_free(struct rte_eth_dev *dev, uint8_t car_type, + uint16_t hw_profile_id, struct rte_mtr_error *error) +{ + struct zxdh_hw *hw = dev->data->dev_private; + int ret = 0; + + if (hw->is_pf) { + ret = zxdh_hw_profile_free_direct(dev, car_type, (uint64_t)hw_profile_id, error); + } else { + struct zxdh_msg_info msg_info = {0}; + struct zxdh_msg_reply_info reply_info = {0}; + struct zxdh_plcr_profile_free *zxdh_plcr_profile_free = + &msg_info.data.zxdh_plcr_profile_free; + + zxdh_plcr_profile_free->profile_id = hw_profile_id; + zxdh_plcr_profile_free->car_type = car_type; + zxdh_msg_head_build(hw, ZXDH_PLCR_CAR_PROFILE_ID_DELETE, &msg_info); + ret = zxdh_vf_send_msg_to_pf(dev, &msg_info, + ZXDH_MSG_HEAD_LEN + sizeof(struct zxdh_plcr_profile_free), + &reply_info, sizeof(struct zxdh_msg_reply_info)); + + if (ret) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, NULL, + "Meter free profile failed "); + } + + return ret; +} + +static int +zxdh_hw_profile_alloc(struct rte_eth_dev *dev, uint64_t *hw_profile_id, + struct rte_mtr_error *error) +{ + struct zxdh_hw *hw = dev->data->dev_private; + int ret = 0; + + if (hw->is_pf) { + ret = zxdh_hw_profile_alloc_direct(dev, CAR_A, hw_profile_id, error); + } else { + struct zxdh_msg_info msg_info = {0}; + struct zxdh_msg_reply_info reply_info = {0}; + struct zxdh_plcr_profile_add *zxdh_plcr_profile_add = + &msg_info.data.zxdh_plcr_profile_add; + + zxdh_plcr_profile_add->car_type = CAR_A; + zxdh_msg_head_build(hw, ZXDH_PLCR_CAR_PROFILE_ID_ADD, &msg_info); + ret = zxdh_vf_send_msg_to_pf(dev, &msg_info, + ZXDH_MSG_HEAD_LEN + sizeof(struct zxdh_plcr_profile_add), + &reply_info, sizeof(struct zxdh_msg_reply_info)); + + if (ret) { + PMD_DRV_LOG(ERR, + "Failed to send msg: port 0x%x msg type ZXDH_PLCR_CAR_PROFILE_ID_ADD ", + hw->vport.vport); + + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, NULL, + "Meter offload alloc profile id msg failed "); + } + *hw_profile_id = reply_info.reply_body.mtr_profile_info.profile_id; + if (*hw_profile_id == ZXDH_HW_PROFILE_MAX) { + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, NULL, + "Meter offload alloc profile id invalid "); + } + } + + return ret; +} + +int +zxdh_hw_profile_unref(struct rte_eth_dev *dev, + uint8_t car_type, + uint16_t hw_profile_id, + struct rte_mtr_error *error) +{ + if (hw_profile_id >= ZXDH_HW_PROFILE_MAX) + return -1; + + rte_spinlock_lock(&g_mtr_res.hw_plcr_res_lock); + if (g_mtr_res.hw_profile_refcnt[hw_profile_id] == 0) { + PMD_DRV_LOG(ERR, "del hw profile id %d but ref 0", hw_profile_id); + rte_spinlock_unlock(&g_mtr_res.hw_plcr_res_lock); + return -1; + } + if (--g_mtr_res.hw_profile_refcnt[hw_profile_id] == 0) { + PMD_DRV_LOG(INFO, "del hw profile id %d ", hw_profile_id); + zxdh_hw_profile_free(dev, car_type, hw_profile_id, error); + } + rte_spinlock_unlock(&g_mtr_res.hw_plcr_res_lock); + return 0; +} + +static int +zxdh_mtr_hw_counter_query(struct rte_eth_dev *dev, + bool clear, + bool dir, + struct zxdh_mtr_stats *mtr_stats, + struct rte_mtr_error *error) +{ + struct zxdh_hw *hw = dev->data->dev_private; + int ret = 0; + + if (hw->is_pf) { + ret = zxdh_mtr_stats_get(dev, dir, mtr_stats); + if (ret) { + PMD_DRV_LOG(ERR, + "ZXDH_PORT_METER_STAT_GET port %u dir %d failed", + hw->vport.vport, + dir); + + return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_STATS, NULL, "Failed to bind plcr flow."); + } + } else { /* send msg to pf */ + struct zxdh_msg_info msg_info = {0}; + struct zxdh_msg_reply_info reply_info = {0}; + struct zxdh_mtr_stats_query *zxdh_mtr_stats_query = + &msg_info.data.zxdh_mtr_stats_query; + + zxdh_mtr_stats_query->direction = dir; + zxdh_mtr_stats_query->is_clr = !!clear; + zxdh_msg_head_build(hw, ZXDH_PORT_METER_STAT_GET, &msg_info); + ret = zxdh_vf_send_msg_to_pf(dev, + &msg_info, + sizeof(msg_info), + &reply_info, + sizeof(struct zxdh_msg_reply_info)); + + if (ret) { + PMD_DRV_LOG(ERR, + "Failed to send msg: port 0x%x msg type ZXDH_PORT_METER_STAT_GET", + hw->vport.vport); + return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_STATS, NULL, "Meter offload alloc profile failed"); + } + struct zxdh_mtr_stats *hw_mtr_stats = &reply_info.reply_body.hw_mtr_stats; + + mtr_stats->n_bytes_dropped = hw_mtr_stats->n_bytes_dropped; + mtr_stats->n_pkts_dropped = hw_mtr_stats->n_pkts_dropped; + } + + return ret; +} + + +static void +zxdh_mtr_profile_res_free(struct rte_eth_dev *dev, + struct rte_mempool *mtr_profile_mp, + struct zxdh_meter_profile *meter_profile, + struct rte_mtr_error *error) +{ + if (meter_profile->ref_cnt == 0) { + ZXDH_MP_FREE_OBJ_FUNC(mtr_profile_mp, meter_profile); + return; + } + if (meter_profile->ref_cnt == 1) { + meter_profile->ref_cnt--; + zxdh_hw_profile_unref(dev, CAR_A, meter_profile->hw_profile_id, error); + + TAILQ_REMOVE(&zxdh_shared_data->meter_profile_list, meter_profile, next); + ZXDH_MP_FREE_OBJ_FUNC(mtr_profile_mp, meter_profile); + } else { + PMD_DRV_LOG(INFO, + "profile %d ref %d is busy", + meter_profile->meter_profile_id, + meter_profile->ref_cnt); + } +} + +static uint16_t +zxdh_check_hw_profile_exist(struct zxdh_mtr_profile_list *mpl, + struct rte_mtr_meter_profile *profile, + uint16_t hw_profile_owner_vport) +{ + struct zxdh_meter_profile *mp; + + TAILQ_FOREACH(mp, mpl, next) { + if ((memcmp(profile, &mp->profile, sizeof(struct rte_mtr_meter_profile)) == 0) && + hw_profile_owner_vport == mp->hw_profile_owner_vport) { + return mp->hw_profile_id; + } + } + return ZXDH_HW_PROFILE_MAX; +} + +static void +zxdh_plcr_param_build(struct rte_mtr_meter_profile *profile, + void *plcr_param, uint16_t profile_id) +{ + if (profile->packet_mode == 0) { + ZXDH_STAT_CAR_PROFILE_CFG_T *p_car_byte_profile_cfg = + (ZXDH_STAT_CAR_PROFILE_CFG_T *)plcr_param; + + p_car_byte_profile_cfg->profile_id = profile_id; + p_car_byte_profile_cfg->pkt_sign = profile->packet_mode; + p_car_byte_profile_cfg->cf = ZXDH_PLCR_CF_UNOVERFLOW; + p_car_byte_profile_cfg->cm = ZXDH_PLCR_CM_BLIND; + if (profile->alg == RTE_MTR_SRTCM_RFC2697) { + p_car_byte_profile_cfg->cd = ZXDH_PLCR_CD_SRTCM; + p_car_byte_profile_cfg->cir = profile->srtcm_rfc2697.cir * 8 / 1000; + p_car_byte_profile_cfg->cbs = profile->srtcm_rfc2697.cbs; + p_car_byte_profile_cfg->ebs = profile->srtcm_rfc2697.ebs; + } else { + p_car_byte_profile_cfg->cd = ZXDH_PLCR_CD_TRTCM; + p_car_byte_profile_cfg->cir = profile->trtcm_rfc2698.cir * 8 / 1000; + p_car_byte_profile_cfg->cbs = profile->trtcm_rfc2698.cbs; + p_car_byte_profile_cfg->eir = (profile->trtcm_rfc2698.pir - + profile->trtcm_rfc2698.cir) * 8 / 1000; + p_car_byte_profile_cfg->ebs = + profile->trtcm_rfc2698.pbs - profile->trtcm_rfc2698.cbs; + } + } else { + ZXDH_STAT_CAR_PKT_PROFILE_CFG_T *p_car_pkt_profile_cfg = + (ZXDH_STAT_CAR_PKT_PROFILE_CFG_T *)plcr_param; + + p_car_pkt_profile_cfg->profile_id = profile_id; + p_car_pkt_profile_cfg->pkt_sign = profile->packet_mode; + + if (profile->alg == RTE_MTR_SRTCM_RFC2697) { + p_car_pkt_profile_cfg->cir = profile->srtcm_rfc2697.cir; + p_car_pkt_profile_cfg->cbs = profile->srtcm_rfc2697.cbs; + } else { + p_car_pkt_profile_cfg->cir = profile->trtcm_rfc2698.cir; + p_car_pkt_profile_cfg->cbs = profile->trtcm_rfc2698.cbs; + } + } +} + +static int +zxdh_hw_profile_config_direct(struct rte_eth_dev *dev __rte_unused, + ZXDH_PROFILE_TYPE car_type, + uint16_t hw_profile_id, + struct zxdh_meter_profile *mp, + struct rte_mtr_error *error) +{ + int ret = zxdh_np_car_profile_cfg_set(mp->hw_profile_owner_vport, + car_type, mp->profile.packet_mode, + (uint32_t)hw_profile_id, &mp->plcr_param); + if (ret) { + PMD_DRV_LOG(ERR, " config hw profile %u failed", hw_profile_id); + return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL, + "Meter offload cfg profile failed"); + } + + return 0; +} + +static int zxdh_hw_profile_config(struct rte_eth_dev *dev, uint16_t hw_profile_id, + struct zxdh_meter_profile *mp, struct rte_mtr_error *error) +{ + struct zxdh_hw *hw = dev->data->dev_private; + int ret = 0; + + if (hw->is_pf) { + ret = zxdh_hw_profile_config_direct(dev, CAR_A, hw_profile_id, mp, error); + } else { + struct zxdh_msg_info msg_info = {0}; + struct zxdh_msg_reply_info reply_info = {0}; + struct zxdh_plcr_profile_cfg *zxdh_plcr_profile_cfg = + &msg_info.data.zxdh_plcr_profile_cfg; + + zxdh_plcr_profile_cfg->car_type = CAR_A; + zxdh_plcr_profile_cfg->packet_mode = mp->profile.packet_mode; + zxdh_plcr_profile_cfg->hw_profile_id = hw_profile_id; + rte_memcpy(&zxdh_plcr_profile_cfg->plcr_param, + &mp->plcr_param, + sizeof(zxdh_plcr_profile_cfg->plcr_param)); + + zxdh_msg_head_build(hw, ZXDH_PLCR_CAR_PROFILE_CFG_SET, &msg_info); + ret = zxdh_vf_send_msg_to_pf(dev, + &msg_info, + ZXDH_MSG_HEAD_LEN + sizeof(struct zxdh_plcr_profile_cfg), + &reply_info, + sizeof(struct zxdh_msg_reply_info)); + + if (ret) { + PMD_DRV_LOG(ERR, + "Failed msg: port 0x%x msg type ZXDH_PLCR_CAR_PROFILE_CFG_SET ", + hw->vport.vport); + + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL, + "Meter offload cfg profile failed "); + } + } + + return ret; +} + +static int +zxdh_mtr_profile_offload(struct rte_eth_dev *dev, struct zxdh_meter_profile *mp, + struct rte_mtr_meter_profile *profile, struct rte_mtr_error *error) +{ + struct zxdh_hw *hw = dev->data->dev_private; + uint16_t hw_profile_owner_vport = ZXDH_GET_OWNER_PF_VPORT(hw->vport.vport); + + mp->hw_profile_owner_vport = hw_profile_owner_vport; + uint64_t hw_profile_id = + zxdh_check_hw_profile_exist(&zxdh_shared_data->meter_profile_list, + profile, + hw_profile_owner_vport); + + if (hw_profile_id == ZXDH_HW_PROFILE_MAX) { + uint32_t ret = zxdh_hw_profile_alloc(dev, &hw_profile_id, error); + + if (ret) { + PMD_DRV_LOG(ERR, "hw_profile alloc fail"); + return ret; + } + + zxdh_plcr_param_build(profile, &mp->plcr_param, hw_profile_id); + ret = zxdh_hw_profile_config(dev, hw_profile_id, mp, error); + if (ret) { + PMD_DRV_LOG(ERR, "zxdh_hw_profile_config fail"); + hw_profile_id = ZXDH_HW_PROFILE_MAX; + return ret; + } + } + zxdh_hw_profile_ref(hw_profile_id); + mp->hw_profile_id = hw_profile_id; + + return 0; +} + +static int +zxdh_meter_profile_add(struct rte_eth_dev *dev, + uint32_t meter_profile_id, + struct rte_mtr_meter_profile *profile, + struct rte_mtr_error *error) +{ + struct zxdh_meter_profile *mp; + int ret; + + ret = zxdh_mtr_profile_validate(meter_profile_id, profile, error); + if (ret) + return -rte_mtr_error_set(error, ENOMEM, + RTE_MTR_ERROR_TYPE_METER_PROFILE, + NULL, "meter profile validate failed"); + mp = zxdh_mtr_profile_find_by_id(&zxdh_shared_data->meter_profile_list, + meter_profile_id, + dev->data->port_id); + + if (mp) + return -rte_mtr_error_set(error, EEXIST, + RTE_MTR_ERROR_TYPE_METER_PROFILE, + NULL, + "meter profile is exists"); + + mp = zxdh_mtr_profile_res_alloc(zxdh_shared_data->mtr_profile_mp); + if (mp == NULL) + return -rte_mtr_error_set(error, ENOMEM, + RTE_MTR_ERROR_TYPE_METER_PROFILE, + NULL, "Meter profile res memory alloc failed."); + + memset(mp, 0, sizeof(struct zxdh_meter_profile)); + + mp->meter_profile_id = meter_profile_id; + mp->dpdk_port_id = dev->data->port_id; + mp->hw_profile_id = UINT16_MAX; + rte_memcpy(&mp->profile, profile, sizeof(struct rte_mtr_meter_profile)); + + ret = zxdh_mtr_profile_offload(dev, mp, profile, error); + if (ret) { + PMD_DRV_LOG(ERR, + " port %d profile id %d offload failed ", + dev->data->port_id, + meter_profile_id); + goto error; + } + + TAILQ_INSERT_TAIL(&zxdh_shared_data->meter_profile_list, mp, next); + PMD_DRV_LOG(DEBUG, + "add profile id %d mp %p mp->ref_cnt %d", + meter_profile_id, + mp, + mp->ref_cnt); + + mp->ref_cnt++; + + return 0; +error: + zxdh_mtr_profile_res_free(dev, zxdh_shared_data->mtr_profile_mp, mp, error); + return ret; +} + +static int +zxdh_meter_profile_delete(struct rte_eth_dev *dev, + uint32_t meter_profile_id, + struct rte_mtr_error *error) +{ + struct zxdh_meter_profile *mp; + + mp = zxdh_mtr_profile_find_by_id(&zxdh_shared_data->meter_profile_list, + meter_profile_id, + dev->data->port_id); + + if (mp == NULL) { + PMD_DRV_LOG(ERR, "del profile id %d unfind ", meter_profile_id); + return -rte_mtr_error_set(error, ENOENT, + RTE_MTR_ERROR_TYPE_METER_PROFILE, + &meter_profile_id, + "Meter profile id is not exists."); + } + zxdh_mtr_profile_res_free(dev, zxdh_shared_data->mtr_profile_mp, mp, error); + + return 0; +} + +static int +zxdh_meter_policy_add(struct rte_eth_dev *dev, + uint32_t policy_id, + struct rte_mtr_meter_policy_params *policy, + struct rte_mtr_error *error) +{ + int ret = 0; + struct zxdh_meter_policy *mtr_policy = NULL; + + if (policy_id >= ZXDH_MAX_POLICY_NUM) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_POLICY_ID, + NULL, "policy ID is invalid. "); + mtr_policy = zxdh_mtr_policy_find_by_id(&zxdh_shared_data->mtr_policy_list, + policy_id, + dev->data->port_id); + + if (mtr_policy) + return -rte_mtr_error_set(error, EEXIST, + RTE_MTR_ERROR_TYPE_METER_POLICY_ID, + NULL, "policy ID exists. "); + ret = zxdh_policy_validate_actions(policy->actions, error); + if (ret) { + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_POLICY, + NULL, " only supports def action."); + } + + mtr_policy = zxdh_mtr_policy_res_alloc(zxdh_shared_data->mtr_policy_mp); + if (mtr_policy == NULL) { + return -rte_mtr_error_set(error, ENOMEM, + RTE_MTR_ERROR_TYPE_METER_POLICY_ID, + NULL, "Meter policy res memory alloc failed."); + } + /* Fill profile info. */ + memset(mtr_policy, 0, sizeof(struct zxdh_meter_policy)); + mtr_policy->policy_id = policy_id; + mtr_policy->dpdk_port_id = dev->data->port_id; + rte_memcpy(&mtr_policy->policy, policy, sizeof(struct rte_mtr_meter_policy_params)); + /* Add to list. */ + TAILQ_INSERT_TAIL(&zxdh_shared_data->mtr_policy_list, mtr_policy, next); + mtr_policy->ref_cnt++; + PMD_DRV_LOG(INFO, "allic policy id %d ok %p ", mtr_policy->policy_id, mtr_policy); + return 0; +} + +static int +zxdh_meter_policy_delete(struct rte_eth_dev *dev, + uint32_t policy_id, + struct rte_mtr_error *error) +{ + struct zxdh_meter_policy *mtr_policy = NULL; + + if (policy_id >= ZXDH_MAX_POLICY_NUM) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_POLICY_ID, + NULL, "policy ID is invalid. "); + mtr_policy = zxdh_mtr_policy_find_by_id(&zxdh_shared_data->mtr_policy_list, + policy_id, dev->data->port_id); + + if (mtr_policy && mtr_policy->ref_cnt == 1) { + TAILQ_REMOVE(&zxdh_shared_data->mtr_policy_list, mtr_policy, next); + MP_FREE_OBJ_FUNC(zxdh_shared_data->mtr_policy_mp, mtr_policy); + } else { + if (mtr_policy) { + PMD_DRV_LOG(INFO, + " policy id %d ref %d is busy ", + mtr_policy->policy_id, + mtr_policy->ref_cnt); + } else { + PMD_DRV_LOG(ERR, " policy id %d is not exist ", policy_id); + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_POLICY_ID, + NULL, "policy ID is not exist. "); + } + } + return 0; +} + +static int +zxdh_meter_validate(uint32_t meter_id, + struct rte_mtr_params *params, + struct rte_mtr_error *error) +{ + /* Meter params must not be NULL. */ + if (params == NULL) + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_MTR_PARAMS, + NULL, "Meter object params null."); + /* Previous meter color is not supported. */ + if (params->use_prev_mtr_color) + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_MTR_PARAMS, + NULL, + "Previous meter color not supported."); + if (meter_id > ZXDH_MAX_MTR_NUM / 2) { + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_MTR_PARAMS, + NULL, + " meter id exceed 1024 unsupport "); + } + return 0; +} + +static int +zxdh_check_port_mtr_bind(struct rte_eth_dev *dev, uint32_t dir) +{ + struct zxdh_mtr_object *mtr_obj = NULL; + + TAILQ_FOREACH(mtr_obj, &zxdh_shared_data->mtr_list, next) { + if (mtr_obj->direction != dir) + continue; + if (mtr_obj->port_id == dev->data->port_id) { + PMD_DRV_LOG(INFO, + "port %d dir %d already bind meter %d", + dev->data->port_id, + dir, + mtr_obj->meter_id); + return -1; + } + } + + return 0; +} + +static struct zxdh_mtr_object +*zxdh_mtr_obj_alloc(struct rte_mempool *mtr_mp) +{ + struct zxdh_mtr_object *mtr_obj = NULL; + + if (ZXDH_MP_ALLOC_OBJ_FUNC(mtr_mp, mtr_obj) != 0) + return NULL; + + return mtr_obj; +} + +static uint32_t dir_to_mtr_mode[] = { + ZXDH_PORT_EGRESS_METER_EN_OFF_FLAG, + ZXDH_PORT_INGRESS_METER_EN_OFF_FLAG +}; + +static int +zxdh_set_mtr_enable(struct rte_eth_dev *dev, uint8_t dir, bool enable, struct rte_mtr_error *error) +{ + struct zxdh_hw *priv = dev->data->dev_private; + struct zxdh_port_attr_table port_attr = {0}; + int ret = 0; + + if (priv->is_pf) { + ret = zxdh_get_port_attr(priv, priv->vport.vport, &port_attr); + port_attr.ingress_meter_enable = enable; + ret = zxdh_set_port_attr(priv, priv->vport.vport, &port_attr); + if (ret) { + PMD_DRV_LOG(ERR, "%s set port attr failed", __func__); + return -ret; + } + } else { + struct zxdh_msg_info msg_info = {0}; + struct zxdh_port_attr_set_msg *attr_msg = &msg_info.data.port_attr_msg; + + attr_msg->mode = dir_to_mtr_mode[dir]; + attr_msg->value = enable; + zxdh_msg_head_build(priv, ZXDH_PORT_ATTRS_SET, &msg_info); + ret = zxdh_vf_send_msg_to_pf(dev, &msg_info, + sizeof(struct zxdh_msg_head) + sizeof(struct zxdh_port_attr_set_msg), + NULL, 0); + } + if (ret) { + PMD_DRV_LOG(ERR, " port %d mtr enable failed", priv->port_id); + return -rte_mtr_error_set(error, EEXIST, + RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, + "Meter enable failed."); + } + if (dir == ZXDH_INGRESS) + priv->i_mtr_en = !!enable; + else + priv->e_mtr_en = !!enable; + + return ret; +} + +static void +zxdh_meter_build_actions(struct zxdh_meter_action *mtr_action, + struct rte_mtr_params *params) +{ + mtr_action->stats_mask = params->stats_mask; + mtr_action->action[RTE_COLOR_RED] = ZXDH_MTR_POLICER_ACTION_DROP; +} + +static int +zxdh_hw_plcrflow_config(struct rte_eth_dev *dev, uint16_t hw_flow_id, + struct zxdh_mtr_object *mtr, struct rte_mtr_error *error) +{ + struct zxdh_hw *hw = dev->data->dev_private; + int ret = 0; + + if (hw->is_pf) { + uint64_t hw_profile_id = (uint64_t)mtr->profile->hw_profile_id; + + ret = zxdh_np_stat_car_queue_cfg_set(hw->dev_id, CAR_A, + hw_flow_id, 1, mtr->enable, hw_profile_id); + + if (ret) { + PMD_DRV_LOG(ERR, "dpp_stat_car_queue_cfg_set failed flowid %d profile id %d", + hw_flow_id, mtr->profile->hw_profile_id); + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_MTR_PARAMS, + NULL, "Failed to bind plcr flow."); + ; + } + } else { + struct zxdh_msg_info msg_info = {0}; + struct zxdh_msg_reply_info reply_info = {0}; + struct zxdh_plcr_flow_cfg *zxdh_plcr_flow_cfg = &msg_info.data.zxdh_plcr_flow_cfg; + + zxdh_plcr_flow_cfg->car_type = CAR_A; + zxdh_plcr_flow_cfg->flow_id = hw_flow_id; + zxdh_plcr_flow_cfg->drop_flag = 1; + zxdh_plcr_flow_cfg->plcr_en = mtr->enable; + zxdh_plcr_flow_cfg->profile_id = mtr->profile->hw_profile_id; + zxdh_msg_head_build(hw, ZXDH_PLCR_CAR_QUEUE_CFG_SET, &msg_info); + ret = zxdh_vf_send_msg_to_pf(dev, &msg_info, + ZXDH_MSG_HEAD_LEN + sizeof(struct zxdh_plcr_flow_cfg), + &reply_info, + sizeof(struct zxdh_msg_reply_info)); + if (ret) { + PMD_DRV_LOG(ERR, + "Failed msg: port 0x%x msg type ZXDH_PLCR_CAR_QUEUE_CFG_SET ", + hw->vport.vport); + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_MTR_PARAMS, + NULL, "Failed to bind plcr flow."); + } + } + + return ret; +} + +static void +zxdh_mtr_obj_free(struct rte_eth_dev *dev, struct zxdh_mtr_object *mtr_obj) +{ + struct zxdh_mtr_list *mtr_list = &zxdh_shared_data->mtr_list; + struct rte_mempool *mtr_mp = zxdh_shared_data->mtr_mp; + + PMD_DRV_LOG(INFO, "free port %d dir %d meter %d mtr refcnt:%d ....", + dev->data->port_id, mtr_obj->direction, mtr_obj->meter_id, mtr_obj->mtr_ref_cnt); + + if (mtr_obj->policy) + mtr_obj->policy->ref_cnt--; + + if (mtr_obj->profile) + mtr_obj->profile->ref_cnt--; + + PMD_DRV_LOG(INFO, + "free port %d dir %d meter %d profile refcnt:%d ", + dev->data->port_id, + mtr_obj->direction, + mtr_obj->meter_id, + mtr_obj->profile ? mtr_obj->profile->ref_cnt : 0); + + if (--mtr_obj->mtr_ref_cnt == 0) { + PMD_DRV_LOG(INFO, "rm mtr %p refcnt:%d ....", mtr_obj, mtr_obj->mtr_ref_cnt); + TAILQ_REMOVE(mtr_list, mtr_obj, next); + MP_FREE_OBJ_FUNC(mtr_mp, mtr_obj); + } +} + +static int +zxdh_mtr_flow_offlad(struct rte_eth_dev *dev, + struct zxdh_mtr_object *mtr, + struct rte_mtr_error *error) +{ + uint16_t hw_flow_id; + + hw_flow_id = mtr->vfid * 2 + ZXDH_PORT_MTR_FID_BASE + mtr->direction; + return zxdh_hw_plcrflow_config(dev, hw_flow_id, mtr, error); +} + +static struct zxdh_mtr_object * +zxdh_mtr_find(uint32_t meter_id, uint16_t dpdk_portid) +{ + struct zxdh_mtr_list *mtr_list = &zxdh_shared_data->mtr_list; + struct zxdh_mtr_object *mtr = NULL; + + TAILQ_FOREACH(mtr, mtr_list, next) { + PMD_DRV_LOG(INFO, + "mtrlist head %p mtr %p mtr->meterid %d to find mtrid %d", + TAILQ_FIRST(mtr_list), + mtr, + mtr->meter_id, + meter_id + ); + + if (meter_id == mtr->meter_id && dpdk_portid == mtr->port_id) + return mtr; + } + return NULL; +} + +static int +zxdh_meter_create(struct rte_eth_dev *dev, uint32_t meter_id, + struct rte_mtr_params *params, int shared, + struct rte_mtr_error *error) +{ + struct zxdh_hw *priv = dev->data->dev_private; + struct zxdh_mtr_list *mtr_list = &zxdh_shared_data->mtr_list; + struct zxdh_mtr_object *mtr; + struct zxdh_meter_profile *mtr_profile; + struct zxdh_meter_policy *mtr_policy; + uint8_t dir = 0; + int ret; + + if (shared) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, + "Meter share is not supported"); + + ret = zxdh_meter_validate(meter_id, params, error); + if (ret) + return ret; + + if (zxdh_check_port_mtr_bind(dev, dir)) + return -rte_mtr_error_set(error, EEXIST, + RTE_MTR_ERROR_TYPE_MTR_ID, NULL, + "Meter object already bind to dev."); + + mtr_profile = zxdh_mtr_profile_find_by_id(&zxdh_shared_data->meter_profile_list, + params->meter_profile_id, + dev->data->port_id + ); + + if (mtr_profile == NULL) + return -rte_mtr_error_set(error, EEXIST, + RTE_MTR_ERROR_TYPE_METER_PROFILE, ¶ms->meter_profile_id, + "Meter profile object is not exists."); + mtr_profile->ref_cnt++; + mtr_policy = zxdh_mtr_policy_find_by_id(&zxdh_shared_data->mtr_policy_list, + params->meter_policy_id, + dev->data->port_id); + + if (mtr_policy == NULL) { + ret = -rte_mtr_error_set(error, EEXIST, + RTE_MTR_ERROR_TYPE_METER_PROFILE, ¶ms->meter_policy_id, + "Meter policy object is not exists."); + mtr_profile->ref_cnt--; + return ret; + } + mtr_policy->ref_cnt++; + + mtr = zxdh_mtr_obj_alloc(zxdh_shared_data->mtr_mp); + if (mtr == NULL) { + ret = -rte_mtr_error_set(error, ENOMEM, + RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, + "Memory alloc failed for meter."); + mtr_policy->ref_cnt--; + mtr_profile->ref_cnt--; + return ret; + } + memset(mtr, 0, sizeof(struct zxdh_mtr_object)); + + mtr->meter_id = meter_id; + mtr->profile = mtr_profile; + + zxdh_meter_build_actions(&mtr->mtr_action, params); + TAILQ_INSERT_TAIL(mtr_list, mtr, next); + mtr->enable = !!params->meter_enable; + mtr->shared = !!shared; + mtr->mtr_ref_cnt++; + mtr->vfid = priv->vfid; + mtr->port_id = dev->data->port_id; + mtr->policy = mtr_policy; + mtr->direction = !!dir; + if (params->meter_enable) { + ret = zxdh_mtr_flow_offlad(dev, mtr, error); + if (ret) + goto error; + } + ret = zxdh_set_mtr_enable(dev, mtr->direction, 1, error); + if (ret) + goto error; + return ret; +error: + zxdh_mtr_obj_free(dev, mtr); + return ret; +} + +static int +zxdh_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id, + struct rte_mtr_error *error) +{ + struct zxdh_mtr_object *mtr; + + mtr = zxdh_mtr_find(meter_id, dev->data->port_id); + if (mtr == NULL) + return -rte_mtr_error_set(error, EEXIST, + RTE_MTR_ERROR_TYPE_MTR_ID, + NULL, "Meter object id not valid."); + mtr->enable = 0; + zxdh_set_mtr_enable(dev, mtr->direction, 0, error); + + if (zxdh_mtr_flow_offlad(dev, mtr, error)) + return -1; + + zxdh_mtr_obj_free(dev, mtr); + return 0; +} + +void +zxdh_mtr_policy_res_free(struct rte_mempool *mtr_policy_mp, struct zxdh_meter_policy *policy) +{ + PMD_DRV_LOG(INFO, "to free policy %d ref %d ", policy->policy_id, policy->ref_cnt); + + if (--policy->ref_cnt == 0) { + TAILQ_REMOVE(&zxdh_shared_data->mtr_policy_list, policy, next); + MP_FREE_OBJ_FUNC(mtr_policy_mp, policy); + } +} + +static int +zxdh_mtr_stats_read(struct rte_eth_dev *dev, + uint32_t mtr_id, + struct rte_mtr_stats *stats, + uint64_t *stats_mask, + int clear, + struct rte_mtr_error *error) +{ + struct zxdh_mtr_stats mtr_stat = {0}; + struct zxdh_mtr_object *mtr = NULL; + int ret = 0; + /* Meter object must exist. */ + mtr = zxdh_mtr_find(mtr_id, dev->data->port_id); + if (mtr == NULL) + return -rte_mtr_error_set(error, ENOENT, + RTE_MTR_ERROR_TYPE_MTR_ID, + NULL, "Meter object id not valid."); + *stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED | RTE_MTR_STATS_N_PKTS_DROPPED; + memset(&mtr_stat, 0, sizeof(mtr_stat)); + ret = zxdh_mtr_hw_counter_query(dev, clear, mtr->direction, &mtr_stat, error); + if (ret) + goto error; + stats->n_bytes_dropped = mtr_stat.n_bytes_dropped; + stats->n_pkts_dropped = mtr_stat.n_pkts_dropped; + + return 0; +error: + return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL, + "Failed to read meter drop counters."); +} + +static const struct rte_mtr_ops zxdh_mtr_ops = { + .capabilities_get = zxdh_meter_cap_get, + .meter_profile_add = zxdh_meter_profile_add, + .meter_profile_delete = zxdh_meter_profile_delete, + .create = zxdh_meter_create, + .destroy = zxdh_meter_destroy, + .stats_read = zxdh_mtr_stats_read, + .meter_policy_add = zxdh_meter_policy_add, + .meter_policy_delete = zxdh_meter_policy_delete, +}; + +int +zxdh_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg) +{ + *(const struct rte_mtr_ops **)arg = &zxdh_mtr_ops; + return 0; +} + +void +zxdh_mtr_release(struct rte_eth_dev *dev __rte_unused) +{ + struct zxdh_hw *priv = dev->data->dev_private; + struct zxdh_meter_profile *profile; + struct rte_mtr_error error = {0}; + struct zxdh_mtr_object *mtr_obj; + + RTE_TAILQ_FOREACH(mtr_obj, &zxdh_shared_data->mtr_list, next) { + if (mtr_obj->port_id == priv->port_id) + zxdh_mtr_obj_free(dev, mtr_obj); + } + + + RTE_TAILQ_FOREACH(profile, &zxdh_shared_data->meter_profile_list, next) { + if (profile->dpdk_port_id == priv->port_id) + zxdh_mtr_profile_res_free(dev, + zxdh_shared_data->mtr_profile_mp, + profile, + &error + ); + } + + struct zxdh_meter_policy *policy; + + RTE_TAILQ_FOREACH(policy, &zxdh_shared_data->mtr_policy_list, next) { + if (policy->dpdk_port_id == priv->port_id) + zxdh_mtr_policy_res_free(zxdh_shared_data->mtr_policy_mp, policy); + } +} diff --git a/drivers/net/zxdh/zxdh_mtr.h b/drivers/net/zxdh/zxdh_mtr.h new file mode 100644 index 0000000000..51ddc0840b --- /dev/null +++ b/drivers/net/zxdh/zxdh_mtr.h @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 ZTE Corporation + */ + +#ifndef ZXDH_MTR_H +#define ZXDH_MTR_H + +#include +#include +#include +#include + +#include "zxdh_np.h" + +#define HW_PROFILE_MAX 512 +#define ZXDH_MAX_MTR_NUM 2048 +#define ZXDH_MAX_POLICY_NUM ZXDH_MAX_MTR_NUM +#define MAX_MTR_PROFILE_NUM HW_PROFILE_MAX +#define ZXDH_INGRESS 1 +#define ZXDH_EGRESS 2 + +#define MP_FREE_OBJ_FUNC(mp, obj) rte_mempool_put(mp, obj) + +struct zxdh_mtr_res { + rte_spinlock_t hw_plcr_res_lock; + uint32_t hw_profile_refcnt[HW_PROFILE_MAX]; + struct rte_mtr_meter_profile profile[HW_PROFILE_MAX]; +}; + +extern struct zxdh_mtr_res g_mtr_res; +extern struct zxdh_shared_data *zxdh_shared_data; + +enum rte_mtr_policer_action { + ZXDH_MTR_POLICER_ACTION_COLOR_GREEN = 0, + ZXDH_MTR_POLICER_ACTION_COLOR_YELLOW, + ZXDH_MTR_POLICER_ACTION_COLOR_RED, + ZXDH_MTR_POLICER_ACTION_DROP, +}; + +union zxdh_offload_profile_cfg { + ZXDH_STAT_CAR_PKT_PROFILE_CFG_T p_car_pkt_profile_cfg; + ZXDH_STAT_CAR_PROFILE_CFG_T p_car_byte_profile_cfg; +}; + +/* meter profile structure. */ +struct zxdh_meter_profile { + TAILQ_ENTRY(zxdh_meter_profile) next; /* Pointer to the next flow meter structure. */ + uint16_t dpdk_port_id; + uint16_t hw_profile_owner_vport; + uint16_t meter_profile_id; /* software Profile id. */ + uint16_t hw_profile_id; /* hardware Profile id. */ + struct rte_mtr_meter_profile profile; /* Profile detail. */ + union zxdh_offload_profile_cfg plcr_param; + uint32_t ref_cnt; /* used count. */ +}; +TAILQ_HEAD(zxdh_mtr_profile_list, zxdh_meter_profile); + +struct zxdh_meter_policy { + TAILQ_ENTRY(zxdh_meter_policy) next; + uint16_t policy_id; + uint16_t ref_cnt; + uint16_t dpdk_port_id; + uint16_t rsv; + struct rte_mtr_meter_policy_params policy; +}; +TAILQ_HEAD(zxdh_mtr_policy_list, zxdh_meter_policy); + +struct zxdh_meter_action { + enum rte_mtr_policer_action action[RTE_COLORS]; + uint64_t stats_mask; +}; + +struct zxdh_mtr_object { + TAILQ_ENTRY(zxdh_mtr_object) next; + uint8_t direction:1, /* 0:ingress, 1:egress */ + shared:1, + enable:1, + rsv:5; + uint8_t rsv8; + uint16_t port_id; + uint16_t vfid; + uint16_t meter_id; + uint16_t mtr_ref_cnt; + uint16_t rsv16; + struct zxdh_meter_profile *profile; + struct zxdh_meter_policy *policy; + struct zxdh_meter_action mtr_action; +}; +TAILQ_HEAD(zxdh_mtr_list, zxdh_mtr_object); + +struct zxdh_mtr_stats { + uint64_t n_pkts_dropped; + uint64_t n_bytes_dropped; +}; + +struct zxdh_hw_mtr_stats { + uint32_t n_pkts_dropped_hi; + uint32_t n_pkts_dropped_lo; + uint32_t n_bytes_dropped_hi; + uint32_t n_bytes_dropped_lo; +}; + +int zxdh_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg); +void zxdh_mtr_release(struct rte_eth_dev *dev __rte_unused); +void zxdh_mtr_policy_res_free(struct rte_mempool *mtr_policy_mp, struct zxdh_meter_policy *policy); +int zxdh_hw_profile_unref(struct rte_eth_dev *dev, + uint8_t car_type, + uint16_t hw_profile_id, + struct rte_mtr_error *error); +int zxdh_hw_profile_alloc_direct(struct rte_eth_dev *dev, ZXDH_PROFILE_TYPE car_type, + uint64_t *hw_profile_id, struct rte_mtr_error *error); +int zxdh_hw_profile_ref(uint16_t hw_profile_id); + +#endif /* ZXDH_MTR_H */ diff --git a/drivers/net/zxdh/zxdh_np.c b/drivers/net/zxdh/zxdh_np.c index 015372bedc..926880fd4e 100644 --- a/drivers/net/zxdh/zxdh_np.c +++ b/drivers/net/zxdh/zxdh_np.c @@ -11,6 +11,7 @@ #include #include +#include "zxdh_msg.h" #include "zxdh_np.h" #include "zxdh_logs.h" @@ -142,6 +143,46 @@ do {\ #define ZXDH_DTB_QUEUE_INIT_FLAG_GET(DEV_ID, QUEUE_ID) \ (p_dpp_dtb_mgr[(DEV_ID)]->queue_info[(QUEUE_ID)].init_flag) +ZXDH_FIELD_T g_stat_car0_cara_queue_ram0_159_0_reg[] = { + {"cara_drop", ZXDH_FIELD_FLAG_RW, 147, 1, 0x0, 0x0}, + {"cara_plcr_en", ZXDH_FIELD_FLAG_RW, 146, 1, 0x0, 0x0}, + {"cara_profile_id", ZXDH_FIELD_FLAG_RW, 145, 9, 0x0, 0x0}, + {"cara_tq_h", ZXDH_FIELD_FLAG_RO, 136, 13, 0x0, 0x0}, + {"cara_tq_l", ZXDH_FIELD_FLAG_RO, 123, 32, 0x0, 0x0}, + {"cara_ted", ZXDH_FIELD_FLAG_RO, 91, 19, 0x0, 0x0}, + {"cara_tcd", ZXDH_FIELD_FLAG_RO, 72, 19, 0x0, 0x0}, + {"cara_tei", ZXDH_FIELD_FLAG_RO, 53, 27, 0x0, 0x0}, + {"cara_tci", ZXDH_FIELD_FLAG_RO, 26, 27, 0x0, 0x0}, +}; + +ZXDH_FIELD_T g_stat_car0_carb_queue_ram0_159_0_reg[] = { + {"carb_drop", ZXDH_FIELD_FLAG_RW, 147, 1, 0x0, 0x0}, + {"carb_plcr_en", ZXDH_FIELD_FLAG_RW, 146, 1, 0x0, 0x0}, + {"carb_profile_id", ZXDH_FIELD_FLAG_RW, 145, 9, 0x0, 0x0}, + {"carb_tq_h", ZXDH_FIELD_FLAG_RO, 136, 13, 0x0, 0x0}, + {"carb_tq_l", ZXDH_FIELD_FLAG_RO, 123, 32, 0x0, 0x0}, + {"carb_ted", ZXDH_FIELD_FLAG_RO, 91, 19, 0x0, 0x0}, + {"carb_tcd", ZXDH_FIELD_FLAG_RO, 72, 19, 0x0, 0x0}, + {"carb_tei", ZXDH_FIELD_FLAG_RO, 53, 27, 0x0, 0x0}, + {"carb_tci", ZXDH_FIELD_FLAG_RO, 26, 27, 0x0, 0x0}, +}; + +ZXDH_FIELD_T g_stat_car0_carc_queue_ram0_159_0_reg[] = { + {"carc_drop", ZXDH_FIELD_FLAG_RW, 147, 1, 0x0, 0x0}, + {"carc_plcr_en", ZXDH_FIELD_FLAG_RW, 146, 1, 0x0, 0x0}, + {"carc_profile_id", ZXDH_FIELD_FLAG_RW, 145, 9, 0x0, 0x0}, + {"carc_tq_h", ZXDH_FIELD_FLAG_RO, 136, 13, 0x0, 0x0}, + {"carc_tq_l", ZXDH_FIELD_FLAG_RO, 123, 32, 0x0, 0x0}, + {"carc_ted", ZXDH_FIELD_FLAG_RO, 91, 19, 0x0, 0x0}, + {"carc_tcd", ZXDH_FIELD_FLAG_RO, 72, 19, 0x0, 0x0}, + {"carc_tei", ZXDH_FIELD_FLAG_RO, 53, 27, 0x0, 0x0}, + {"carc_tci", ZXDH_FIELD_FLAG_RO, 26, 27, 0x0, 0x0}, +}; + +ZXDH_FIELD_T g_nppu_pktrx_cfg_pktrx_glbal_cfg_0_reg[] = { + {"pktrx_glbal_cfg_0", ZXDH_FIELD_FLAG_RW, 31, 32, 0x0, 0x0}, +}; + static uint32_t zxdh_np_comm_is_big_endian(void) { @@ -2321,3 +2362,427 @@ zxdh_np_stat_ppu_cnt_get_ex(uint32_t dev_id, return rc; } + +static uint32_t +zxdh_np_agent_channel_sync_send(ZXDH_AGENT_CHANNEL_MSG_T *p_msg, + uint32_t *p_data, + uint32_t rep_len) +{ + uint32_t ret = 0; + uint32_t vport = 0; + struct zxdh_pci_bar_msg in = {0}; + struct zxdh_msg_recviver_mem result = {0}; + uint32_t *recv_buffer = NULL; + uint8_t *reply_ptr = NULL; + uint16_t reply_msg_len = 0; + uint64_t agent_addr = 0; + + if (ZXDH_IS_PF(vport)) + in.src = ZXDH_MSG_CHAN_END_PF; + else + in.src = ZXDH_MSG_CHAN_END_VF; + + in.virt_addr = agent_addr; + in.payload_addr = p_msg->msg; + in.payload_len = p_msg->msg_len; + in.dst = ZXDH_MSG_CHAN_END_RISC; + in.module_id = ZXDH_BAR_MDOULE_NPSDK; + + recv_buffer = (uint32_t *)rte_zmalloc(NULL, rep_len + ZXDH_CHANNEL_REPS_LEN, 0); + if (recv_buffer == NULL) { + PMD_DRV_LOG(ERR, "%s point null!", __func__); + return ZXDH_PAR_CHK_POINT_NULL; + } + + result.buffer_len = rep_len + ZXDH_CHANNEL_REPS_LEN; + result.recv_buffer = recv_buffer; + + ret = zxdh_bar_chan_sync_msg_send(&in, &result); + if (ret == ZXDH_BAR_MSG_OK) { + reply_ptr = (uint8_t *)(result.recv_buffer); + if (*reply_ptr == 0XFF) { + reply_msg_len = *(uint16_t *)(reply_ptr + 1); + rte_memcpy(p_data, reply_ptr + 4, + ((reply_msg_len > rep_len) ? rep_len : reply_msg_len)); + } else { + PMD_DRV_LOG(ERR, "Message not replied"); + } + } else { + PMD_DRV_LOG(ERR, "Error[0x%x], %s failed!", ret, __func__); + } + + rte_free(recv_buffer); + return ret; +} + +static uint32_t +zxdh_np_agent_channel_plcr_sync_send(ZXDH_AGENT_CHANNEL_PLCR_MSG_T *p_msg, + uint32_t *p_data, uint32_t rep_len) +{ + uint32_t ret = 0; + ZXDH_AGENT_CHANNEL_MSG_T agent_msg = {0}; + + agent_msg.msg = (void *)p_msg; + agent_msg.msg_len = sizeof(ZXDH_AGENT_CHANNEL_PLCR_MSG_T); + + ret = zxdh_np_agent_channel_sync_send(&agent_msg, p_data, rep_len); + if (ret != 0) { + PMD_DRV_LOG(ERR, "%s: agent_channel_sync_send failed.", __func__); + return 1; + } + + return 0; +} + +static uint32_t +zxdh_np_agent_channel_plcr_profileid_request(uint32_t vport, + uint32_t car_type, uint32_t *p_profileid) +{ + uint32_t ret = 0; + uint32_t resp_buffer[2] = {0}; + + ZXDH_AGENT_CHANNEL_PLCR_MSG_T msgcfg = {0}; + + msgcfg.dev_id = 0; + msgcfg.type = ZXDH_PLCR_MSG; + msgcfg.oper = ZXDH_PROFILEID_REQUEST; + msgcfg.vport = vport; + msgcfg.car_type = car_type; + msgcfg.profile_id = 0xFFFF; + + ret = zxdh_np_agent_channel_plcr_sync_send(&msgcfg, + resp_buffer, sizeof(resp_buffer)); + if (ret != 0) { + PMD_DRV_LOG(ERR, "%s: agent_channel_plcr_sync_send failed.", __func__); + return 1; + } + + rte_memcpy(p_profileid, resp_buffer, sizeof(uint32_t) * ZXDH_SCHE_RSP_LEN); + + return ret; +} + +static uint32_t +zxdh_np_agent_channel_plcr_car_rate(uint32_t car_type, + uint32_t pkt_sign, + uint32_t profile_id __rte_unused, + void *p_car_profile_cfg) +{ + uint32_t ret = 0; + uint32_t resp_buffer[2] = {0}; + uint32_t resp_len = 8; + uint32_t i = 0; + ZXDH_AGENT_CHANNEL_MSG_T agent_msg = {0}; + ZXDH_AGENT_CAR_PKT_PROFILE_MSG_T msgpktcfg = {0}; + ZXDH_AGENT_CAR_PROFILE_MSG_T msgcfg = {0}; + ZXDH_STAT_CAR_PROFILE_CFG_T *p_stat_car_profile_cfg = NULL; + ZXDH_STAT_CAR_PKT_PROFILE_CFG_T *p_stat_pkt_car_profile_cfg = NULL; + + if (car_type == ZXDH_STAT_CAR_A_TYPE && pkt_sign == 1) { + p_stat_pkt_car_profile_cfg = (ZXDH_STAT_CAR_PKT_PROFILE_CFG_T *)p_car_profile_cfg; + msgpktcfg.dev_id = 0; + msgpktcfg.type = ZXDH_PLCR_CAR_PKT_RATE; + msgpktcfg.car_level = car_type; + msgpktcfg.cir = p_stat_pkt_car_profile_cfg->cir; + msgpktcfg.cbs = p_stat_pkt_car_profile_cfg->cbs; + msgpktcfg.profile_id = p_stat_pkt_car_profile_cfg->profile_id; + msgpktcfg.pkt_sign = p_stat_pkt_car_profile_cfg->pkt_sign; + for (i = 0; i < ZXDH_CAR_PRI_MAX; i++) + msgpktcfg.pri[i] = p_stat_pkt_car_profile_cfg->pri[i]; + + agent_msg.msg = (void *)&msgpktcfg; + agent_msg.msg_len = sizeof(ZXDH_AGENT_CAR_PKT_PROFILE_MSG_T); + + ret = zxdh_np_agent_channel_sync_send(&agent_msg, resp_buffer, resp_len); + if (ret != 0) { + PMD_DRV_LOG(ERR, "%s: stat_car_a_type failed.", __func__); + return 1; + } + + ret = *(uint8_t *)resp_buffer; + } else { + p_stat_car_profile_cfg = (ZXDH_STAT_CAR_PROFILE_CFG_T *)p_car_profile_cfg; + msgcfg.dev_id = 0; + msgcfg.type = ZXDH_PLCR_CAR_RATE; + msgcfg.car_level = car_type; + msgcfg.cir = p_stat_car_profile_cfg->cir; + msgcfg.cbs = p_stat_car_profile_cfg->cbs; + msgcfg.profile_id = p_stat_car_profile_cfg->profile_id; + msgcfg.pkt_sign = p_stat_car_profile_cfg->pkt_sign; + msgcfg.cd = p_stat_car_profile_cfg->cd; + msgcfg.cf = p_stat_car_profile_cfg->cf; + msgcfg.cm = p_stat_car_profile_cfg->cm; + msgcfg.cir = p_stat_car_profile_cfg->cir; + msgcfg.cbs = p_stat_car_profile_cfg->cbs; + msgcfg.eir = p_stat_car_profile_cfg->eir; + msgcfg.ebs = p_stat_car_profile_cfg->ebs; + msgcfg.random_disc_e = p_stat_car_profile_cfg->random_disc_e; + msgcfg.random_disc_c = p_stat_car_profile_cfg->random_disc_c; + for (i = 0; i < ZXDH_CAR_PRI_MAX; i++) { + msgcfg.c_pri[i] = p_stat_car_profile_cfg->c_pri[i]; + msgcfg.e_green_pri[i] = p_stat_car_profile_cfg->e_green_pri[i]; + msgcfg.e_yellow_pri[i] = p_stat_car_profile_cfg->e_yellow_pri[i]; + } + + agent_msg.msg = (void *)&msgcfg; + agent_msg.msg_len = sizeof(ZXDH_AGENT_CAR_PROFILE_MSG_T); + + ret = zxdh_np_agent_channel_sync_send(&agent_msg, resp_buffer, resp_len); + if (ret != 0) { + PMD_DRV_LOG(ERR, "%s: stat_car_b_type failed.", __func__); + return 1; + } + + ret = *(uint8_t *)resp_buffer; + } + + return ret; +} + +static uint32_t +zxdh_np_agent_channel_plcr_profileid_release(uint32_t vport, + uint32_t car_type __rte_unused, + uint32_t profileid) +{ + uint32_t ret = 0; + uint32_t resp_buffer[2] = {0}; + + ZXDH_AGENT_CHANNEL_PLCR_MSG_T msgcfg = {0}; + + msgcfg.dev_id = 0; + msgcfg.type = ZXDH_PLCR_MSG; + msgcfg.oper = ZXDH_PROFILEID_RELEASE; + msgcfg.vport = vport; + msgcfg.profile_id = profileid; + + ret = zxdh_np_agent_channel_plcr_sync_send(&msgcfg, + resp_buffer, sizeof(resp_buffer)); + if (ret != 0) { + PMD_DRV_LOG(ERR, "%s: agent_channel_plcr_sync_send failed.", __func__); + return 1; + } + + ret = *(uint8_t *)resp_buffer; + + return ret; +} + +static uint32_t +zxdh_np_stat_cara_queue_cfg_set(uint32_t dev_id, + uint32_t flow_id, + uint32_t drop_flag, + uint32_t plcr_en, + uint32_t profile_id) +{ + uint32_t rc = 0; + + ZXDH_STAT_CAR0_CARA_QUEUE_RAM0_159_0_T queue_cfg = {0}; + + queue_cfg.cara_drop = drop_flag; + queue_cfg.cara_plcr_en = plcr_en; + queue_cfg.cara_profile_id = profile_id; + + rc = zxdh_np_reg_write(dev_id, + ZXDH_STAT_CAR0_CARA_QUEUE_RAM0, + 0, + flow_id, + &queue_cfg); + ZXDH_COMM_CHECK_DEV_RC(dev_id, rc, "zxdh_np_reg_write"); + + return rc; +} + +static uint32_t +zxdh_np_stat_carb_queue_cfg_set(uint32_t dev_id, + uint32_t flow_id, + uint32_t drop_flag, + uint32_t plcr_en, + uint32_t profile_id) +{ + uint32_t rc = 0; + + ZXDH_STAT_CAR0_CARB_QUEUE_RAM0_159_0_T queue_cfg = {0}; + + queue_cfg.carb_drop = drop_flag; + queue_cfg.carb_plcr_en = plcr_en; + queue_cfg.carb_profile_id = profile_id; + + rc = zxdh_np_reg_write(dev_id, + ZXDH_STAT_CAR0_CARB_QUEUE_RAM0, + 0, + flow_id, + &queue_cfg); + ZXDH_COMM_CHECK_DEV_RC(dev_id, rc, "zxdh_np_reg_write"); + + return rc; +} + +static uint32_t +zxdh_np_stat_carc_queue_cfg_set(uint32_t dev_id, + uint32_t flow_id, + uint32_t drop_flag, + uint32_t plcr_en, + uint32_t profile_id) +{ + uint32_t rc = 0; + + ZXDH_STAT_CAR0_CARC_QUEUE_RAM0_159_0_T queue_cfg = {0}; + + queue_cfg.carc_drop = drop_flag; + queue_cfg.carc_plcr_en = plcr_en; + queue_cfg.carc_profile_id = profile_id; + + rc = zxdh_np_reg_write(dev_id, + ZXDH_STAT_CAR0_CARC_QUEUE_RAM0, + 0, + flow_id, + &queue_cfg); + ZXDH_COMM_CHECK_DEV_RC(dev_id, rc, "zxdh_np_reg_write"); + + return rc; +} + +uint32_t +zxdh_np_car_profile_id_add(uint32_t vport_id, + uint32_t flags, + uint64_t *p_profile_id) +{ + uint32_t ret = 0; + uint32_t *profile_id = NULL; + uint32_t profile_id_h = 0; + uint32_t profile_id_l = 0; + uint64_t temp_profile_id = 0; + + profile_id = (uint32_t *)rte_zmalloc(NULL, ZXDH_G_PROFILE_ID_LEN, 0); + if (profile_id == NULL) { + PMD_DRV_LOG(ERR, "%s: profile_id point null!", __func__); + return ZXDH_PAR_CHK_POINT_NULL; + } + + ret = zxdh_np_agent_channel_plcr_profileid_request(vport_id, flags, profile_id); + + profile_id_h = *(profile_id + 1); + profile_id_l = *profile_id; + rte_free(profile_id); + + temp_profile_id = (((uint64_t)profile_id_l) << 32) | ((uint64_t)profile_id_h); + if (0 != (uint32_t)(temp_profile_id >> 56)) { + PMD_DRV_LOG(ERR, "%s: profile_id is overflow!", __func__); + return 1; + } + + *p_profile_id = temp_profile_id; + + return ret; +} + +uint32_t +zxdh_np_car_profile_cfg_set(uint32_t vport_id __rte_unused, + uint32_t car_type, + uint32_t pkt_sign, + uint32_t profile_id, + void *p_car_profile_cfg) +{ + uint32_t ret = 0; + + ret = zxdh_np_agent_channel_plcr_car_rate(car_type, + pkt_sign, profile_id, p_car_profile_cfg); + if (ret != 0) { + PMD_DRV_LOG(ERR, "%s: plcr_car_rate set failed!", __func__); + return 1; + } + + return ret; +} + +uint32_t +zxdh_np_car_profile_id_delete(uint32_t vport_id, + uint32_t flags, uint64_t profile_id) +{ + uint32_t ret = 0; + uint32_t profileid = 0; + + profileid = profile_id & 0xFFFF; + + ret = zxdh_np_agent_channel_plcr_profileid_release(vport_id, flags, profileid); + if (ret != 0) { + PMD_DRV_LOG(ERR, "%s: plcr profiled id release failed!", __func__); + return 1; + } + + return 0; +} + +uint32_t +zxdh_np_stat_car_queue_cfg_set(uint32_t dev_id, + uint32_t car_type, + uint32_t flow_id, + uint32_t drop_flag, + uint32_t plcr_en, + uint32_t profile_id) +{ + uint32_t rc = 0; + + if (car_type == ZXDH_STAT_CAR_A_TYPE) { + if (flow_id > ZXDH_CAR_A_FLOW_ID_MAX) { + PMD_DRV_LOG(ERR, "%s: stat car a type flow_id invalid!", __func__); + return ZXDH_PAR_CHK_INVALID_INDEX; + } + + if (profile_id > ZXDH_CAR_A_PROFILE_ID_MAX) { + PMD_DRV_LOG(ERR, "%s: stat car a type profile_id invalid!", __func__); + return ZXDH_PAR_CHK_INVALID_INDEX; + } + } else if (car_type == ZXDH_STAT_CAR_B_TYPE) { + if (flow_id > ZXDH_CAR_B_FLOW_ID_MAX) { + PMD_DRV_LOG(ERR, "%s: stat car b type flow_id invalid!", __func__); + return ZXDH_PAR_CHK_INVALID_INDEX; + } + + if (profile_id > ZXDH_CAR_B_PROFILE_ID_MAX) { + PMD_DRV_LOG(ERR, "%s: stat car b type profile_id invalid!", __func__); + return ZXDH_PAR_CHK_INVALID_INDEX; + } + } else { + if (flow_id > ZXDH_CAR_C_FLOW_ID_MAX) { + PMD_DRV_LOG(ERR, "%s: stat car c type flow_id invalid!", __func__); + return ZXDH_PAR_CHK_INVALID_INDEX; + } + + if (profile_id > ZXDH_CAR_C_PROFILE_ID_MAX) { + PMD_DRV_LOG(ERR, "%s: stat car c type profile_id invalid!", __func__); + return ZXDH_PAR_CHK_INVALID_INDEX; + } + } + + switch (car_type) { + case ZXDH_STAT_CAR_A_TYPE: + rc = zxdh_np_stat_cara_queue_cfg_set(dev_id, + flow_id, + drop_flag, + plcr_en, + profile_id); + ZXDH_COMM_CHECK_DEV_RC(dev_id, rc, "stat_cara_queue_cfg_set"); + break; + + case ZXDH_STAT_CAR_B_TYPE: + rc = zxdh_np_stat_carb_queue_cfg_set(dev_id, + flow_id, + drop_flag, + plcr_en, + profile_id); + ZXDH_COMM_CHECK_DEV_RC(dev_id, rc, "stat_carb_queue_cfg_set"); + break; + + case ZXDH_STAT_CAR_C_TYPE: + rc = zxdh_np_stat_carc_queue_cfg_set(dev_id, + flow_id, + drop_flag, + plcr_en, + profile_id); + ZXDH_COMM_CHECK_DEV_RC(dev_id, rc, "stat_carc_queue_cfg_set"); + break; + } + + return rc; +} diff --git a/drivers/net/zxdh/zxdh_np.h b/drivers/net/zxdh/zxdh_np.h index d793189657..63ebd12c18 100644 --- a/drivers/net/zxdh/zxdh_np.h +++ b/drivers/net/zxdh/zxdh_np.h @@ -147,6 +147,43 @@ #define ZXDH_RC_DTB_SEARCH_VPORT_QUEUE_ZERO (ZXDH_RC_DTB_BASE | 0x17) #define ZXDH_RC_DTB_QUEUE_NOT_ENABLE (ZXDH_RC_DTB_BASE | 0x18) +#define ZXDH_SCHE_RSP_LEN (2) +#define ZXDH_G_PROFILE_ID_LEN (8) + +#define ZXDH_CAR_A_FLOW_ID_MAX (0x7fff) +#define ZXDH_CAR_B_FLOW_ID_MAX (0xfff) +#define ZXDH_CAR_C_FLOW_ID_MAX (0x3ff) +#define ZXDH_CAR_A_PROFILE_ID_MAX (0x1ff) +#define ZXDH_CAR_B_PROFILE_ID_MAX (0x7f) +#define ZXDH_CAR_C_PROFILE_ID_MAX (0x1f) + +#define ZXDH_SYS_NP_BASE_ADDR0 (0x00000000) +#define ZXDH_SYS_NP_BASE_ADDR1 (0x02000000) + +#define ZXDH_FIELD_FLAG_RO (1 << 0) +#define ZXDH_FIELD_FLAG_RW (1 << 1) + +#define ZXDH_VF_ACTIVE(VPORT) (((VPORT) & 0x0800) >> 11) +#define ZXDH_EPID_BY(VPORT) (((VPORT) & 0x7000) >> 12) +#define ZXDH_FUNC_NUM(VPORT) (((VPORT) & 0x0700) >> 8) +#define ZXDH_VFUNC_NUM(VPORT) (((VPORT) & 0x00FF)) +#define ZXDH_IS_PF(VPORT) (!ZXDH_VF_ACTIVE(VPORT)) + +#define ZXDH_CHANNEL_REPS_LEN (4) + +typedef enum zxdh_module_base_addr_e { + ZXDH_MODULE_SE_SMMU0_BASE_ADDR = 0x00000000, + ZXDH_MODULE_DTB_ENQ_BASE_ADDR = 0x00000000, + ZXDH_MODULE_NPPU_PKTRX_CFG_BASE_ADDR = 0x00000800, +} ZXDH_MODULE_BASE_ADDR_E; + +typedef enum zxdh_sys_base_addr_e { + ZXDH_SYS_NPPU_BASE_ADDR = (ZXDH_SYS_NP_BASE_ADDR0 + 0x00000000), + ZXDH_SYS_SE_SMMU0_BASE_ADDR = (ZXDH_SYS_NP_BASE_ADDR0 + 0x00300000), + ZXDH_SYS_DTB_BASE_ADDR = (ZXDH_SYS_NP_BASE_ADDR1 + 0x00000000), + ZXDH_SYS_MAX_BASE_ADDR = 0x20000000, +} ZXDH_SYS_BASE_ADDR_E; + typedef enum zxdh_module_init_e { ZXDH_MODULE_INIT_NPPU = 0, ZXDH_MODULE_INIT_PPU, @@ -173,6 +210,10 @@ typedef enum zxdh_reg_info_e { ZXDH_DTB_CFG_QUEUE_DTB_LEN = 2, ZXDH_DTB_INFO_QUEUE_BUF_SPACE = 3, ZXDH_DTB_CFG_EPID_V_FUNC_NUM = 4, + ZXDH_STAT_CAR0_CARA_QUEUE_RAM0 = 9, + ZXDH_STAT_CAR0_CARB_QUEUE_RAM0 = 10, + ZXDH_STAT_CAR0_CARC_QUEUE_RAM0 = 11, + ZXDH_NPPU_PKTRX_CFG_GLBAL_CFG_0R = 12, ZXDH_REG_ENUM_MAX_VALUE } ZXDH_REG_INFO_E; @@ -597,6 +638,170 @@ typedef enum zxdh_se_opr_mode_e { ZXDH_SE_OPR_WR = 1, } ZXDH_SE_OPR_MODE_E; +typedef enum zxdh_stat_car_type_e { + ZXDH_STAT_CAR_A_TYPE = 0, + ZXDH_STAT_CAR_B_TYPE, + ZXDH_STAT_CAR_C_TYPE, + ZXDH_STAT_CAR_MAX_TYPE +} ZXDH_STAT_CAR_TYPE_E; + +typedef enum zxdh_car_priority_e { + ZXDH_CAR_PRI0 = 0, + ZXDH_CAR_PRI1 = 1, + ZXDH_CAR_PRI2 = 2, + ZXDH_CAR_PRI3 = 3, + ZXDH_CAR_PRI4 = 4, + ZXDH_CAR_PRI5 = 5, + ZXDH_CAR_PRI6 = 6, + ZXDH_CAR_PRI7 = 7, + ZXDH_CAR_PRI_MAX +} ZXDH_CAR_PRIORITY_E; + +typedef struct zxdh_stat_car_pkt_profile_cfg_t { + uint32_t profile_id; + uint32_t pkt_sign; + uint32_t cir; + uint32_t cbs; + uint32_t pri[ZXDH_CAR_PRI_MAX]; +} ZXDH_STAT_CAR_PKT_PROFILE_CFG_T; + +typedef struct zxdh_stat_car_profile_cfg_t { + uint32_t profile_id; + uint32_t pkt_sign; + uint32_t cd; + uint32_t cf; + uint32_t cm; + uint32_t cir; + uint32_t cbs; + uint32_t eir; + uint32_t ebs; + uint32_t random_disc_e; + uint32_t random_disc_c; + uint32_t c_pri[ZXDH_CAR_PRI_MAX]; + uint32_t e_green_pri[ZXDH_CAR_PRI_MAX]; + uint32_t e_yellow_pri[ZXDH_CAR_PRI_MAX]; +} ZXDH_STAT_CAR_PROFILE_CFG_T; + +typedef struct zxdh_stat_car0_cara_queue_ram0_159_0_t { + uint32_t cara_drop; + uint32_t cara_plcr_en; + uint32_t cara_profile_id; + uint32_t cara_tq_h; + uint32_t cara_tq_l; + uint32_t cara_ted; + uint32_t cara_tcd; + uint32_t cara_tei; + uint32_t cara_tci; +} ZXDH_STAT_CAR0_CARA_QUEUE_RAM0_159_0_T; + +typedef struct dpp_agent_car_profile_msg { + uint8_t dev_id; + uint8_t type; + uint8_t rsv; + uint8_t rsv1; + uint32_t car_level; + uint32_t profile_id; + uint32_t pkt_sign; + uint32_t cd; + uint32_t cf; + uint32_t cm; + uint32_t cir; + uint32_t cbs; + uint32_t eir; + uint32_t ebs; + uint32_t random_disc_e; + uint32_t random_disc_c; + uint32_t c_pri[ZXDH_CAR_PRI_MAX]; + uint32_t e_green_pri[ZXDH_CAR_PRI_MAX]; + uint32_t e_yellow_pri[ZXDH_CAR_PRI_MAX]; +} ZXDH_AGENT_CAR_PROFILE_MSG_T; + +typedef struct dpp_agent_car_pkt_profile_msg { + uint8_t dev_id; + uint8_t type; + uint8_t rsv; + uint8_t rsv1; + uint32_t car_level; + uint32_t profile_id; + uint32_t pkt_sign; + uint32_t cir; + uint32_t cbs; + uint32_t pri[ZXDH_CAR_PRI_MAX]; +} ZXDH_AGENT_CAR_PKT_PROFILE_MSG_T; + +typedef struct zxdh_agent_channel_msg_t { + uint32_t msg_len; + void *msg; +} ZXDH_AGENT_CHANNEL_MSG_T; + +typedef struct zxdh_agent_channel_plcr_msg { + uint8_t dev_id; + uint8_t type; + uint8_t oper; + uint8_t rsv; + uint32_t vport; + uint32_t car_type; + uint32_t profile_id; +} ZXDH_AGENT_CHANNEL_PLCR_MSG_T; + +typedef struct dpp_stat_car0_carc_queue_ram0_159_0_t { + uint32_t carc_drop; + uint32_t carc_plcr_en; + uint32_t carc_profile_id; + uint32_t carc_tq_h; + uint32_t carc_tq_l; + uint32_t carc_ted; + uint32_t carc_tcd; + uint32_t carc_tei; + uint32_t carc_tci; +} ZXDH_STAT_CAR0_CARC_QUEUE_RAM0_159_0_T; + +typedef struct zxdh_stat_car0_carb_queue_ram0_159_0_t { + uint32_t carb_drop; + uint32_t carb_plcr_en; + uint32_t carb_profile_id; + uint32_t carb_tq_h; + uint32_t carb_tq_l; + uint32_t carb_ted; + uint32_t carb_tcd; + uint32_t carb_tei; + uint32_t carb_tci; +} ZXDH_STAT_CAR0_CARB_QUEUE_RAM0_159_0_T; + +typedef enum zxdh_np_agent_msg_type_e { + ZXDH_REG_MSG = 0, + ZXDH_DTB_MSG, + ZXDH_TM_MSG, + ZXDH_PLCR_MSG, + ZXDH_PKTRX_IND_REG_RW_MSG, + ZXDH_PCIE_BAR_MSG, + ZXDH_RESET_MSG, + ZXDH_PXE_MSG, + ZXDH_TM_FLOW_SHAPE, + ZXDH_TM_TD, + ZXDH_TM_SE_SHAPE, + ZXDH_TM_PP_SHAPE, + ZXDH_PLCR_CAR_RATE, + ZXDH_PLCR_CAR_PKT_RATE, + ZXDH_PPU_THASH_RSK, + ZXDH_ACL_MSG, + ZXDH_STAT_MSG, + ZXDH_RES_MSG, + ZXDH_MSG_MAX +} MSG_TYPE_E; + +typedef enum zxdh_msg_plcr_oper { + ZXDH_PROFILEID_REQUEST = 0, + ZXDH_PROFILEID_RELEASE = 1, +} ZXDH_MSG_PLCR_OPER_E; + +typedef enum zxdh_profile_type { + CAR_A = 0, + CAR_B = 1, + CAR_C = 2, + CAR_MAX +} ZXDH_PROFILE_TYPE; + int zxdh_np_host_init(uint32_t dev_id, ZXDH_DEV_INIT_CTRL_T *p_dev_init_ctrl); int zxdh_np_online_uninit(uint32_t dev_id, char *port_name, uint32_t queue_id); int zxdh_np_dtb_table_entry_write(uint32_t dev_id, uint32_t queue_id, @@ -615,5 +820,22 @@ uint32_t zxdh_np_stat_ppu_cnt_get_ex(uint32_t dev_id, uint32_t index, uint32_t clr_mode, uint32_t *p_data); +uint32_t +zxdh_np_car_profile_id_add(uint32_t vport_id, + uint32_t flags, + uint64_t *p_profile_id); +uint32_t zxdh_np_car_profile_cfg_set(__rte_unused uint32_t vport_id, + uint32_t car_type, + uint32_t pkt_sign, + uint32_t profile_id, + void *p_car_profile_cfg); +uint32_t zxdh_np_car_profile_id_delete(uint32_t vport_id, + uint32_t flags, uint64_t profile_id); +uint32_t zxdh_np_stat_car_queue_cfg_set(uint32_t dev_id, + uint32_t car_type, + uint32_t flow_id, + uint32_t drop_flag, + uint32_t plcr_en, + uint32_t profile_id); #endif /* ZXDH_NP_H */ diff --git a/drivers/net/zxdh/zxdh_tables.h b/drivers/net/zxdh/zxdh_tables.h index 542cee5e49..37be4cf71e 100644 --- a/drivers/net/zxdh/zxdh_tables.h +++ b/drivers/net/zxdh/zxdh_tables.h @@ -64,6 +64,9 @@ #define ZXDH_FLOW_STATS_INGRESS_BASE 0xADC1 +#define ZXDH_MTR_STATS_EGRESS_BASE 0x7481 +#define ZXDH_MTR_STATS_INGRESS_BASE 0x7C81 + extern struct zxdh_dtb_shared_data g_dtb_data; struct zxdh_port_vlan_table { -- 2.27.0