net/hinic: add TCAM filter switch for flow director
[dpdk.git] / drivers / net / hinic / base / hinic_pmd_niccfg.c
index 7da0a88..67f6bc4 100644 (file)
@@ -10,6 +10,7 @@
 #include "hinic_pmd_mgmt.h"
 #include "hinic_pmd_cmdq.h"
 #include "hinic_pmd_niccfg.h"
+#include "hinic_pmd_mbox.h"
 
 #define l2nic_msg_to_mgmt_sync(hwdev, cmd, buf_in,             \
                               in_size, buf_out, out_size)      \
                        buf_in, in_size,                        \
                        buf_out, out_size, 0)
 
+/**
+ * hinic_init_function_table - Initialize function table.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param rx_buf_sz
+ *   Receive buffer size.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
 int hinic_init_function_table(void *hwdev, u16 rx_buf_sz)
 {
        struct hinic_function_table function_table;
@@ -40,8 +53,8 @@ int hinic_init_function_table(void *hwdev, u16 rx_buf_sz)
                                     &function_table, &out_size, 0);
        if (err || function_table.mgmt_msg_head.status || !out_size) {
                PMD_DRV_LOG(ERR,
-                       "Failed to init func table, ret = %d",
-                       function_table.mgmt_msg_head.status);
+                       "Failed to init func table, err: %d, status: 0x%x, out size: 0x%x",
+                       err, function_table.mgmt_msg_head.status, out_size);
                return -EFAULT;
        }
 
@@ -49,13 +62,17 @@ int hinic_init_function_table(void *hwdev, u16 rx_buf_sz)
 }
 
 /**
- * hinic_get_base_qpn - get global number of queue
- * @hwdev: the hardware interface of a nic device
- * @global_qpn: vat page size
+ * hinic_get_base_qpn - Get global queue number.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param global_qpn
+ *   Global queue number.
+ *
  * @return
- *   0 on success,
+ *   0 on success.
  *   negative error value otherwise.
- **/
+ */
 int hinic_get_base_qpn(void *hwdev, u16 *global_qpn)
 {
        struct hinic_cmd_qpn cmd_qpn;
@@ -77,8 +94,8 @@ int hinic_get_base_qpn(void *hwdev, u16 *global_qpn)
                                     &out_size, 0);
        if (err || !out_size || cmd_qpn.mgmt_msg_head.status) {
                PMD_DRV_LOG(ERR,
-                       "Failed to get base qpn, status(%d)",
-                       cmd_qpn.mgmt_msg_head.status);
+                       "Failed to get base qpn, err: %d, status: 0x%x, out size: 0x%x",
+                       err, cmd_qpn.mgmt_msg_head.status, out_size);
                return -EINVAL;
        }
 
@@ -89,12 +106,18 @@ int hinic_get_base_qpn(void *hwdev, u16 *global_qpn)
 
 /**
  * hinic_set_mac - Init mac_vlan table in NIC.
- * @hwdev: the hardware interface of a nic device
- * @mac_addr: mac address
- * @vlan_id: set 0 for mac_vlan table initialization
- * @func_id: global function id of NIC
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param mac_addr
+ *   MAC address.
+ * @param vlan_id
+ *   Set 0 for mac_vlan table initialization.
+ * @param func_id
+ *   Global function id of NIC.
+ *
  * @return
- *   0 on success and stats is filled,
+ *   0 on success.
  *   negative error value otherwise.
  */
 int hinic_set_mac(void *hwdev, u8 *mac_addr, u16 vlan_id, u16 func_id)
@@ -122,6 +145,7 @@ int hinic_set_mac(void *hwdev, u8 *mac_addr, u16 vlan_id, u16 func_id)
                        err, mac_info.mgmt_msg_head.status, out_size);
                return -EINVAL;
        }
+
        if (mac_info.mgmt_msg_head.status == HINIC_PF_SET_VF_ALREADY) {
                PMD_DRV_LOG(WARNING, "PF has already set vf mac, Ignore set operation.");
                return HINIC_PF_SET_VF_ALREADY;
@@ -132,16 +156,21 @@ int hinic_set_mac(void *hwdev, u8 *mac_addr, u16 vlan_id, u16 func_id)
 
 /**
  * hinic_del_mac - Uninit mac_vlan table in NIC.
- * @hwdev: the hardware interface of a nic device
- * @mac_addr: mac address
- * @vlan_id: set 0 for mac_vlan table initialization
- * @func_id: global function id of NIC
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param mac_addr
+ *   MAC address.
+ * @param vlan_id
+ *   Set 0 for mac_vlan table initialization.
+ * @param func_id
+ *   Global function id of NIC.
+ *
  * @return
- *   0 on success and stats is filled,
+ *   0 on success.
  *   negative error value otherwise.
  */
-int hinic_del_mac(void *hwdev, u8 *mac_addr, u16 vlan_id,
-                 u16 func_id)
+int hinic_del_mac(void *hwdev, u8 *mac_addr, u16 vlan_id, u16 func_id)
 {
        struct hinic_port_mac_set mac_info;
        u16 out_size = sizeof(mac_info);
@@ -179,6 +208,18 @@ int hinic_del_mac(void *hwdev, u8 *mac_addr, u16 vlan_id,
        return 0;
 }
 
+/**
+ * hinic_get_default_mac - Get default mac address from hardware.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param mac_addr
+ *   MAC address.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
 int hinic_get_default_mac(void *hwdev, u8 *mac_addr)
 {
        struct hinic_port_mac_set mac_info;
@@ -208,6 +249,73 @@ int hinic_get_default_mac(void *hwdev, u8 *mac_addr)
        return 0;
 }
 
+/**
+*  hinic_update_mac - Update mac address to hardware.
+*
+* @param hwdev
+*   The hardware interface of a nic device.
+* @param old_mac
+*   Old mac address.
+* @param new_mac
+*   New mac address.
+* @param vlan_id
+*   Set 0 for mac_vlan table initialization.
+* @param func_id
+*   Global function id of NIC.
+*
+* @return
+*   0 on success.
+*   negative error value otherwise.
+*/
+int hinic_update_mac(void *hwdev, u8 *old_mac, u8 *new_mac, u16 vlan_id,
+                    u16 func_id)
+{
+       struct hinic_port_mac_update mac_info;
+       u16 out_size = sizeof(mac_info);
+       int err;
+
+       if (!hwdev || !old_mac || !new_mac) {
+               PMD_DRV_LOG(ERR, "Hwdev, old_mac or new_mac is NULL");
+               return -EINVAL;
+       }
+
+       memset(&mac_info, 0, sizeof(mac_info));
+       mac_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       mac_info.func_id = func_id;
+       mac_info.vlan_id = vlan_id;
+       memcpy(mac_info.old_mac, old_mac, ETH_ALEN);
+       memcpy(mac_info.new_mac, new_mac, ETH_ALEN);
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_UPDATE_MAC,
+                                    &mac_info, sizeof(mac_info),
+                                    &mac_info, &out_size);
+       if (err || !out_size ||
+           (mac_info.mgmt_msg_head.status &&
+            mac_info.mgmt_msg_head.status != HINIC_PF_SET_VF_ALREADY)) {
+               PMD_DRV_LOG(ERR, "Failed to update MAC, err: %d, status: 0x%x, out size: 0x%x",
+                           err, mac_info.mgmt_msg_head.status, out_size);
+               return -EINVAL;
+       }
+       if (mac_info.mgmt_msg_head.status == HINIC_PF_SET_VF_ALREADY) {
+               PMD_DRV_LOG(WARNING, "PF has already set vf mac, Ignore update operation");
+               return HINIC_PF_SET_VF_ALREADY;
+       }
+
+       return 0;
+}
+
+/**
+ * hinic_set_port_mtu -  Set MTU to port.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param new_mtu
+ *   MTU size.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
 int hinic_set_port_mtu(void *hwdev, u32 new_mtu)
 {
        struct hinic_mtu mtu_info;
@@ -236,6 +344,153 @@ int hinic_set_port_mtu(void *hwdev, u32 new_mtu)
        return 0;
 }
 
+/**
+ * hinic_add_remove_vlan - Add or remove vlan id to vlan elb table.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param vlan_id
+ *   Vlan id.
+ * @param func_id
+ *   Global function id of NIC.
+ * @param add
+ *   Add or remove operation.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
+int hinic_add_remove_vlan(void *hwdev, u16 vlan_id, u16 func_id, bool add)
+{
+       struct hinic_vlan_config vlan_info;
+       u16 out_size = sizeof(vlan_info);
+       u8 cmd;
+       int err;
+
+       if (!hwdev) {
+               PMD_DRV_LOG(ERR, "Hwdev is NULL");
+               return -EINVAL;
+       }
+
+       cmd = add ? HINIC_PORT_CMD_ADD_VLAN : HINIC_PORT_CMD_DEL_VLAN;
+
+       memset(&vlan_info, 0, sizeof(vlan_info));
+       vlan_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       vlan_info.func_id = func_id;
+       vlan_info.vlan_id = vlan_id;
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, cmd, &vlan_info, sizeof(vlan_info),
+                                    &vlan_info, &out_size);
+       if (err || !out_size || vlan_info.mgmt_msg_head.status) {
+               PMD_DRV_LOG(ERR,
+                       "Failed to %s vlan, err: %d, status: 0x%x, out size: 0x%x",
+                       add ? "add" : "remove", err,
+                       vlan_info.mgmt_msg_head.status, out_size);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * hinic_config_vlan_filter - Enable or Disable vlan filter.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param vlan_filter_ctrl
+ *   Enable or Disable.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
+int hinic_config_vlan_filter(void *hwdev, u32 vlan_filter_ctrl)
+{
+       struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev;
+       struct hinic_vlan_filter vlan_filter;
+       u16 out_size = sizeof(vlan_filter);
+       int err;
+
+       if (!hwdev)
+               return -EINVAL;
+
+       memset(&vlan_filter, 0, sizeof(vlan_filter));
+       vlan_filter.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       vlan_filter.func_id = hinic_global_func_id(nic_hwdev);
+       vlan_filter.vlan_filter_ctrl = vlan_filter_ctrl;
+
+       err = l2nic_msg_to_mgmt_sync(nic_hwdev, HINIC_PORT_CMD_SET_VLAN_FILTER,
+                                    &vlan_filter, sizeof(vlan_filter),
+                                    &vlan_filter, &out_size);
+       if (vlan_filter.mgmt_msg_head.status == HINIC_MGMT_CMD_UNSUPPORTED) {
+               err = HINIC_MGMT_CMD_UNSUPPORTED;
+       } else if ((err == HINIC_MBOX_VF_CMD_ERROR) &&
+               (HINIC_IS_VF(nic_hwdev))) {
+               err = HINIC_MGMT_CMD_UNSUPPORTED;
+       } else if (err || !out_size || vlan_filter.mgmt_msg_head.status) {
+               PMD_DRV_LOG(ERR,
+                       "Failed to config vlan filter, vlan_filter_ctrl: 0x%x, err: %d, status: 0x%x, out size: 0x%x",
+                       vlan_filter_ctrl, err,
+                       vlan_filter.mgmt_msg_head.status, out_size);
+               err = -EINVAL;
+       }
+
+       return err;
+}
+
+/**
+ * hinic_set_rx_vlan_offload - Enable or Disable vlan offload.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param en
+ *   Enable or Disable.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
+int hinic_set_rx_vlan_offload(void *hwdev, u8 en)
+{
+       struct hinic_vlan_offload vlan_cfg;
+       u16 out_size = sizeof(vlan_cfg);
+       int err;
+
+       if (!hwdev) {
+               PMD_DRV_LOG(ERR, "Hwdev is NULL");
+               return -EINVAL;
+       }
+
+       memset(&vlan_cfg, 0, sizeof(vlan_cfg));
+       vlan_cfg.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       vlan_cfg.func_id = hinic_global_func_id(hwdev);
+       vlan_cfg.vlan_rx_offload = en;
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_RX_VLAN_OFFLOAD,
+                                    &vlan_cfg, sizeof(vlan_cfg),
+                                    &vlan_cfg, &out_size);
+       if (err || !out_size || vlan_cfg.mgmt_msg_head.status) {
+               PMD_DRV_LOG(ERR,
+                       "Failed to set rx vlan offload, err: %d, status: 0x%x, out size: 0x%x",
+                       err, vlan_cfg.mgmt_msg_head.status, out_size);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * hinic_get_link_status - Get link status from hardware.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param link_state
+ *   Link status.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
 int hinic_get_link_status(void *hwdev, u8 *link_state)
 {
        struct hinic_get_link get_link;
@@ -267,10 +522,16 @@ int hinic_get_link_status(void *hwdev, u8 *link_state)
 
 /**
  * hinic_set_vport_enable - Notify firmware that driver is ready or not.
- * @hwdev: the hardware interface of a nic device
- * @enable: 1: driver is ready; 0: driver is not ok.
- * Return: 0 on success and state is filled, negative error value otherwise.
- **/
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param enable
+ *   1: driver is ready; 0: driver is not ok.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
 int hinic_set_vport_enable(void *hwdev, bool enable)
 {
        struct hinic_vport_state en_state;
@@ -300,11 +561,15 @@ int hinic_set_vport_enable(void *hwdev, bool enable)
 }
 
 /**
- * hinic_set_port_enable - open MAG to receive packets.
- * @hwdev: the hardware interface of a nic device
- * @enable: 1: open MAG; 0: close MAG.
+ * hinic_set_port_enable - Open MAG to receive packets.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param enable
+ *   1: open MAG; 0: close MAG.
+ *
  * @return
- *   0 on success and stats is filled,
+ *   0 on success.
  *   negative error value otherwise.
  */
 int hinic_set_port_enable(void *hwdev, bool enable)
@@ -318,6 +583,9 @@ int hinic_set_port_enable(void *hwdev, bool enable)
                return -EINVAL;
        }
 
+       if (HINIC_IS_VF((struct hinic_hwdev *)hwdev))
+               return 0;
+
        memset(&en_state, 0, sizeof(en_state));
        en_state.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
        en_state.state = (enable ? HINIC_PORT_ENABLE : HINIC_PORT_DISABLE);
@@ -356,7 +624,7 @@ int hinic_get_port_info(void *hwdev, struct nic_port_info *port_info)
                PMD_DRV_LOG(ERR,
                        "Failed to get port info, err: %d, status: 0x%x, out size: 0x%x",
                        err, port_msg.mgmt_msg_head.status, out_size);
-               return err;
+               return -EIO;
        }
 
        port_info->autoneg_cap = port_msg.autoneg_cap;
@@ -398,6 +666,35 @@ int hinic_set_pause_config(void *hwdev, struct nic_pause_config nic_pause)
        return 0;
 }
 
+int hinic_get_pause_info(void *hwdev, struct nic_pause_config *nic_pause)
+{
+       struct hinic_pause_config pause_info;
+       u16 out_size = sizeof(pause_info);
+       int err;
+
+       if (!hwdev || !nic_pause)
+               return -EINVAL;
+
+       memset(&pause_info, 0, sizeof(pause_info));
+       pause_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       pause_info.func_id = hinic_global_func_id(hwdev);
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_PAUSE_INFO,
+                                    &pause_info, sizeof(pause_info),
+                                    &pause_info, &out_size);
+       if (err || !out_size || pause_info.mgmt_msg_head.status) {
+               PMD_DRV_LOG(ERR, "Failed to get pause info, err: %d, status: 0x%x, out size: 0x%x\n",
+                       err, pause_info.mgmt_msg_head.status, out_size);
+               return -EINVAL;
+       }
+
+       nic_pause->auto_neg = pause_info.auto_neg;
+       nic_pause->rx_pause = pause_info.rx_pause;
+       nic_pause->tx_pause = pause_info.tx_pause;
+
+       return 0;
+}
+
 int hinic_dcb_set_ets(void *hwdev, u8 *up_tc, u8 *pg_bw,
                      u8 *pgid, u8 *up_bw, u8 *prio)
 {
@@ -417,8 +714,7 @@ int hinic_dcb_set_ets(void *hwdev, u8 *up_tc, u8 *pg_bw,
                pg_bw_t += *(pg_bw + i);
 
                if (*(up_tc + i) > HINIC_DCB_TC_MAX) {
-                       PMD_DRV_LOG(ERR,
-                               "Invalid up %d mapping tc: %d", i,
+                       PMD_DRV_LOG(ERR, "Invalid up %d mapping tc: %d", i,
                                *(up_tc + i));
                        return -EINVAL;
                }
@@ -432,7 +728,7 @@ int hinic_dcb_set_ets(void *hwdev, u8 *up_tc, u8 *pg_bw,
 
        memset(&ets, 0, sizeof(ets));
        ets.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
-       ets.port_id = 0;    /* reserved */
+       ets.port_id = 0;        /* reserved */
        memcpy(ets.up_tc, up_tc, HINIC_DCB_TC_MAX);
        memcpy(ets.pg_bw, pg_bw, HINIC_DCB_UP_MAX);
        memcpy(ets.pgid, pgid, HINIC_DCB_UP_MAX);
@@ -672,12 +968,17 @@ int hinic_rss_get_template_tbl(void *hwdev, u32 tmpl_idx, u8 *temp)
 }
 
 /**
- * hinic_rss_set_hash_engine - Init rss hash function .
- * @hwdev: the hardware interface of a nic device
- * @tmpl_idx: index of rss template from NIC.
- * @type: hash function, such as Toeplitz or XOR.
+ * hinic_rss_set_hash_engine - Init rss hash function.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param tmpl_idx
+ *   Index of rss template from NIC.
+ * @param type
+ *   Hash function, such as Toeplitz or XOR.
+ *
  * @return
- *   0 on success and stats is filled,
+ *   0 on success.
  *   negative error value otherwise.
  */
 int hinic_rss_set_hash_engine(void *hwdev, u8 tmpl_idx, u8 type)
@@ -845,12 +1146,18 @@ int hinic_rss_cfg(void *hwdev, u8 rss_en, u8 tmpl_idx, u8 tc_num, u8 *prio_tc)
 }
 
 /**
- * hinic_rss_template_alloc - get rss template id from the chip,
- *                           all functions share 96 templates.
- * @hwdev: the pointer to the private hardware device object
- * @tmpl_idx: index of rss template from chip.
- * Return: 0 on success and stats is filled, negative error value otherwise.
- **/
+ * hinic_rss_template_alloc - Get rss template id from the chip,
+ * all functions share 96 templates.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param tmpl_idx
+ *   Index of rss template from chip.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
 int hinic_rss_template_alloc(void *hwdev, u8 *tmpl_idx)
 {
        struct hinic_rss_template_mgmt template_mgmt;
@@ -882,11 +1189,17 @@ int hinic_rss_template_alloc(void *hwdev, u8 *tmpl_idx)
 }
 
 /**
- * hinic_rss_template_alloc - free rss template id to the chip
- * @hwdev: the hardware interface of a nic device
- * @tmpl_idx: index of rss template from NIC.
- * Return: 0 on success and stats is filled, negative error value otherwise.
- **/
+ * hinic_rss_template_free - Free rss template id to the chip.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param tmpl_idx
+ *   Index of rss template from chip.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
 int hinic_rss_template_free(void *hwdev, u8 tmpl_idx)
 {
        struct hinic_rss_template_mgmt template_mgmt;
@@ -917,12 +1230,17 @@ int hinic_rss_template_free(void *hwdev, u8 tmpl_idx)
 }
 
 /**
- * hinic_set_rx_vhd_mode - change rx buffer size after initialization,
- * @hwdev: the hardware interface of a nic device
- * @mode: not needed.
- * @rx_buf_sz: receive buffer size.
+ * hinic_set_rx_vhd_mode - Change rx buffer size after initialization.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param vhd_mode
+ *   Not needed.
+ * @param rx_buf_sz
+ *   receive buffer size.
+ *
  * @return
- *   0 on success and stats is filled,
+ *   0 on success.
  *   negative error value otherwise.
  */
 int hinic_set_rx_vhd_mode(void *hwdev, u16 vhd_mode, u16 rx_buf_sz)
@@ -950,7 +1268,6 @@ int hinic_set_rx_vhd_mode(void *hwdev, u16 vhd_mode, u16 rx_buf_sz)
                PMD_DRV_LOG(ERR,
                        "Failed to set vhd mode, err: %d, status: 0x%x, out size: 0x%x",
                        err, vhd_mode_cfg.mgmt_msg_head.status, out_size);
-
                return -EIO;
        }
 
@@ -985,6 +1302,46 @@ int hinic_set_rx_mode(void *hwdev, u32 enable)
        return 0;
 }
 
+/**
+ * hinic_get_mgmt_version - Get mgmt module version from chip.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param fw
+ *   Firmware version.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
+int hinic_get_mgmt_version(void *hwdev, char *fw)
+{
+       struct hinic_version_info fw_ver;
+       u16 out_size = sizeof(fw_ver);
+       int err;
+
+       if (!hwdev || !fw) {
+               PMD_DRV_LOG(ERR, "Hwdev or fw is NULL");
+               return -EINVAL;
+       }
+
+       memset(&fw_ver, 0, sizeof(fw_ver));
+       fw_ver.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_GET_MGMT_VERSION,
+                                    &fw_ver, sizeof(fw_ver), &fw_ver,
+                                    &out_size);
+       if (err || !out_size || fw_ver.mgmt_msg_head.status) {
+               PMD_DRV_LOG(ERR, "Failed to get mgmt version, err: %d, status: 0x%x, out size: 0x%x\n",
+                       err, fw_ver.mgmt_msg_head.status, out_size);
+               return -EINVAL;
+       }
+
+       snprintf(fw, HINIC_MGMT_VERSION_MAX_LEN, "%s", fw_ver.ver);
+
+       return 0;
+}
+
 int hinic_set_rx_csum_offload(void *hwdev, u32 en)
 {
        struct hinic_checksum_offload rx_csum_cfg;
@@ -1065,10 +1422,9 @@ int hinic_set_anti_attack(void *hwdev, bool enable)
        rate.xbs = ANTI_ATTACK_DEFAULT_XBS;
 
        err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_ANTI_ATTACK_RATE,
-                                    &rate, sizeof(rate), &rate,
-                                    &out_size);
+                                    &rate, sizeof(rate), &rate, &out_size);
        if (err || !out_size || rate.mgmt_msg_head.status) {
-               PMD_DRV_LOG(ERR, "can't %s port Anti-Attack rate limit, err: %d, status: 0x%x, out size: 0x%x",
+               PMD_DRV_LOG(ERR, "Can't %s port Anti-Attack rate limit, err: %d, status: 0x%x, out size: 0x%x",
                        (enable ? "enable" : "disable"), err,
                        rate.mgmt_msg_head.status, out_size);
                return -EINVAL;
@@ -1100,6 +1456,54 @@ int hinic_reset_port_link_cfg(void *hwdev)
        return 0;
 }
 
+/**
+ * hinic_vf_func_init - Register VF to PF.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
+int hinic_vf_func_init(struct hinic_hwdev *hwdev)
+{
+       int err, state = 0;
+
+       if (!HINIC_IS_VF(hwdev))
+               return 0;
+
+       err = hinic_mbox_to_pf(hwdev, HINIC_MOD_L2NIC,
+                       HINIC_PORT_CMD_VF_REGISTER, &state, sizeof(state),
+                       NULL, NULL, 0);
+       if (err) {
+               PMD_DRV_LOG(ERR, "Fail to register vf");
+               return err;
+       }
+
+       return 0;
+}
+
+/**
+ * hinic_vf_func_free - Unregister VF from PF.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ */
+void hinic_vf_func_free(struct hinic_hwdev *hwdev)
+{
+       int err;
+
+       if (hinic_func_type(hwdev) != TYPE_VF)
+               return;
+
+       err = hinic_mbox_to_pf(hwdev, HINIC_MOD_L2NIC,
+                               HINIC_PORT_CMD_VF_UNREGISTER, &err, sizeof(err),
+                               NULL, NULL, 0);
+       if (err)
+               PMD_DRV_LOG(ERR, "Fail to unregister VF, err: %d", err);
+}
+
 int hinic_set_fast_recycle_mode(void *hwdev, u8 mode)
 {
        struct hinic_fast_recycled_mode fast_recycled_mode;
@@ -1122,16 +1526,15 @@ int hinic_set_fast_recycle_mode(void *hwdev, u8 mode)
                                     sizeof(fast_recycled_mode),
                                     &fast_recycled_mode, &out_size, 0);
        if (err || fast_recycled_mode.mgmt_msg_head.status || !out_size) {
-               PMD_DRV_LOG(ERR,
-                       "Failed to set recycle mode, ret = %d",
-                       fast_recycled_mode.mgmt_msg_head.status);
-               return -EFAULT;
+               PMD_DRV_LOG(ERR, "Failed to set recycle mode, err: %d, status: 0x%x, out size: 0x%x",
+                       err, fast_recycled_mode.mgmt_msg_head.status, out_size);
+               return -EIO;
        }
 
        return 0;
 }
 
-void hinic_clear_vport_stats(struct hinic_hwdev *hwdev)
+int hinic_clear_vport_stats(struct hinic_hwdev *hwdev)
 {
        struct hinic_clear_vport_stats clear_vport_stats;
        u16 out_size = sizeof(clear_vport_stats);
@@ -1139,7 +1542,7 @@ void hinic_clear_vport_stats(struct hinic_hwdev *hwdev)
 
        if (!hwdev) {
                PMD_DRV_LOG(ERR, "Hwdev is NULL");
-               return;
+               return -EINVAL;
        }
 
        memset(&clear_vport_stats, 0, sizeof(clear_vport_stats));
@@ -1153,10 +1556,13 @@ void hinic_clear_vport_stats(struct hinic_hwdev *hwdev)
        if (err || !out_size || clear_vport_stats.mgmt_msg_head.status) {
                PMD_DRV_LOG(ERR, "Failed to clear vport statistics, err: %d, status: 0x%x, out size: 0x%x",
                        err, clear_vport_stats.mgmt_msg_head.status, out_size);
+               return -EINVAL;
        }
+
+       return 0;
 }
 
-void hinic_clear_phy_port_stats(struct hinic_hwdev *hwdev)
+int hinic_clear_phy_port_stats(struct hinic_hwdev *hwdev)
 {
        struct hinic_clear_port_stats clear_phy_port_stats;
        u16 out_size = sizeof(clear_phy_port_stats);
@@ -1164,7 +1570,7 @@ void hinic_clear_phy_port_stats(struct hinic_hwdev *hwdev)
 
        if (!hwdev) {
                PMD_DRV_LOG(ERR, "Hwdev is NULL");
-               return;
+               return -EINVAL;
        }
 
        memset(&clear_phy_port_stats, 0, sizeof(clear_phy_port_stats));
@@ -1180,7 +1586,10 @@ void hinic_clear_phy_port_stats(struct hinic_hwdev *hwdev)
                PMD_DRV_LOG(ERR, "Failed to clear phy port statistics, err: %d, status: 0x%x, out size: 0x%x",
                        err, clear_phy_port_stats.mgmt_msg_head.status,
                        out_size);
+               return -EINVAL;
        }
+
+       return 0;
 }
 
 int hinic_set_link_status_follow(void *hwdev,
@@ -1193,9 +1602,11 @@ int hinic_set_link_status_follow(void *hwdev,
        if (!hwdev)
                return -EINVAL;
 
+       if (HINIC_IS_VF((struct hinic_hwdev *)hwdev))
+               return 0;
+
        if (status >= HINIC_LINK_FOLLOW_STATUS_MAX) {
-               PMD_DRV_LOG(ERR,
-                       "Invalid link follow status: %d", status);
+               PMD_DRV_LOG(ERR, "Invalid link follow status: %d", status);
                return -EINVAL;
        }
 
@@ -1248,11 +1659,54 @@ int hinic_get_link_mode(void *hwdev, u32 *supported, u32 *advertised)
 }
 
 /**
- * hinic_flush_qp_res - Flush tx && rx chip resources in case of set vport fake
- * failed when device start.
- * @hwdev: the hardware interface of a nic device
- * Return: 0 on success, negative error value otherwise.
- **/
+ * hinic_set_xsfp_tx_status - Enable or disable the fiber in
+ * tx direction when set link up or down.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param enable
+ *   Enable or Disable.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
+int hinic_set_xsfp_tx_status(void *hwdev, bool enable)
+{
+       struct hinic_set_xsfp_status xsfp_status;
+       u16 out_size = sizeof(struct hinic_set_xsfp_status);
+       int err;
+
+       memset(&xsfp_status, 0, sizeof(xsfp_status));
+       xsfp_status.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       xsfp_status.port_id = hinic_global_func_id(hwdev);
+       xsfp_status.xsfp_tx_dis = ((enable == 0) ? 1 : 0);
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_SET_XSFP_STATUS,
+               &xsfp_status, sizeof(struct hinic_set_xsfp_status),
+               &xsfp_status, &out_size);
+       if (err || !out_size || xsfp_status.mgmt_msg_head.status) {
+               PMD_DRV_LOG(ERR,
+                       "Failed to %s port xsfp status, err: %d, status: 0x%x, out size: 0x%x\n",
+                       enable ? "Disable" : "Enable", err,
+                       xsfp_status.mgmt_msg_head.status, out_size);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+/**
+ * hinic_flush_qp_res - Flush tx && rx chip resources in case of set vport
+ * fake failed when device start.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
 int hinic_flush_qp_res(void *hwdev)
 {
        struct hinic_clear_qp_resource qp_res;
@@ -1274,3 +1728,430 @@ int hinic_flush_qp_res(void *hwdev)
 
        return 0;
 }
+
+/**
+ * hinic_vf_get_default_cos - Get default cos of VF.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param cos_id
+ *   Cos value.
+ *
+ * @return
+ *   0 on success.
+ *   negative error value otherwise.
+ */
+int hinic_vf_get_default_cos(struct hinic_hwdev *hwdev, u8 *cos_id)
+{
+       struct hinic_vf_default_cos vf_cos;
+       u16 out_size = sizeof(vf_cos);
+       int err;
+
+       memset(&vf_cos, 0, sizeof(vf_cos));
+       vf_cos.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+
+       err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_L2NIC,
+                                    HINIC_PORT_CMD_GET_VF_COS, &vf_cos,
+                                    sizeof(vf_cos), &vf_cos, &out_size, 0);
+       if (err || !out_size || vf_cos.mgmt_msg_head.status) {
+               PMD_DRV_LOG(ERR, "Get VF default cos failed, err: %d, status: 0x%x, out size: 0x%x",
+                       err, vf_cos.mgmt_msg_head.status, out_size);
+               return -EIO;
+       }
+       *cos_id = vf_cos.state.default_cos;
+
+       return 0;
+}
+
+/**
+ * hinic_set_fdir_filter - Set fdir filter for control path
+ * packet to notify firmware.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param filter_type
+ *   Packet type to filter.
+ * @param qid
+ *   Rx qid to filter.
+ * @param type_enable
+ *   The status of pkt type filter.
+ * @param enable
+ *   Fdir function Enable or Disable.
+ * @return
+ *   0 on success,
+ *   negative error value otherwise.
+ */
+int hinic_set_fdir_filter(void *hwdev, u8 filter_type, u8 qid, u8 type_enable,
+                         bool enable)
+{
+       struct hinic_port_qfilter_info port_filer_cmd;
+       u16 out_size = sizeof(port_filer_cmd);
+       int err;
+
+       if (!hwdev)
+               return -EINVAL;
+
+       memset(&port_filer_cmd, 0, sizeof(port_filer_cmd));
+       port_filer_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       port_filer_cmd.func_id = hinic_global_func_id(hwdev);
+       port_filer_cmd.filter_enable = (u8)enable;
+       port_filer_cmd.filter_type = filter_type;
+       port_filer_cmd.qid = qid;
+       port_filer_cmd.filter_type_enable = type_enable;
+       port_filer_cmd.fdir_flag = 0;
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_Q_FILTER,
+                       &port_filer_cmd, sizeof(port_filer_cmd),
+                       &port_filer_cmd, &out_size);
+       if (err || !out_size || port_filer_cmd.mgmt_msg_head.status) {
+               PMD_DRV_LOG(ERR, "Set port Q filter failed, err: %d, status: 0x%x, out size: 0x%x, type: 0x%x,"
+                       " enable: 0x%x, qid: 0x%x, filter_type_enable: 0x%x\n",
+                       err, port_filer_cmd.mgmt_msg_head.status, out_size,
+                       filter_type, enable, qid, type_enable);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+/**
+ * hinic_set_normal_filter - Set fdir filter for IO path packet.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param qid
+ *   Rx qid to filter.
+ * @param normal_type_enable
+ *   IO path packet function Enable or Disable
+ * @param key
+ *   IO path packet filter key value, such as DIP from pkt.
+ * @param enable
+ *   Fdir function Enable or Disable.
+ * @param flag
+ *   Filter flag, such as dip or others.
+ * @return
+ *   0 on success,
+ *   negative error value otherwise.
+ */
+int hinic_set_normal_filter(void *hwdev, u8 qid, u8 normal_type_enable,
+                               u32 key, bool enable, u8 flag)
+{
+       struct hinic_port_qfilter_info port_filer_cmd;
+       u16 out_size = sizeof(port_filer_cmd);
+       int err;
+
+       if (!hwdev)
+               return -EINVAL;
+
+       memset(&port_filer_cmd, 0, sizeof(port_filer_cmd));
+       port_filer_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       port_filer_cmd.func_id = hinic_global_func_id(hwdev);
+       port_filer_cmd.filter_enable = (u8)enable;
+       port_filer_cmd.qid = qid;
+       port_filer_cmd.normal_type_enable = normal_type_enable;
+       port_filer_cmd.fdir_flag = flag; /* fdir flag: support dip */
+       port_filer_cmd.key = key;
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_Q_FILTER,
+                       &port_filer_cmd, sizeof(port_filer_cmd),
+                       &port_filer_cmd, &out_size);
+       if (err || !out_size || port_filer_cmd.mgmt_msg_head.status) {
+               PMD_DRV_LOG(ERR, "Set normal filter failed, err: %d, status: 0x%x, out size: 0x%x, fdir_flag: 0x%x,"
+                       " enable: 0x%x, qid: 0x%x, normal_type_enable: 0x%x, key:0x%x\n",
+                       err, port_filer_cmd.mgmt_msg_head.status, out_size,
+                       flag, enable, qid, normal_type_enable, key);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+/**
+ * hinic_set_fdir_tcam - Set fdir filter for control packet
+ * by tcam table to notify hardware.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param type_mask
+ *   Index of TCAM.
+ * @param filter_rule
+ *   TCAM rule for control packet, such as lacp or bgp.
+ * @param filter_action
+ *   TCAM action for control packet, such as accept or drop.
+ * @return
+ *   0 on success,
+ *   negative error value otherwise.
+ */
+int hinic_set_fdir_tcam(void *hwdev, u16 type_mask,
+                       struct tag_pa_rule *filter_rule,
+                       struct tag_pa_action *filter_action)
+{
+       struct hinic_fdir_tcam_info port_tcam_cmd;
+       u16 out_size = sizeof(port_tcam_cmd);
+       int err;
+
+       if (!hwdev)
+               return -EINVAL;
+
+       memset(&port_tcam_cmd, 0, sizeof(port_tcam_cmd));
+       port_tcam_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       port_tcam_cmd.tcam_index = type_mask;
+       port_tcam_cmd.flag = TCAM_SET;
+       memcpy((void *)&port_tcam_cmd.filter_rule,
+               (void *)filter_rule, sizeof(struct tag_pa_rule));
+       memcpy((void *)&port_tcam_cmd.filter_action,
+               (void *)filter_action, sizeof(struct tag_pa_action));
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_TCAM_FILTER,
+                       &port_tcam_cmd, sizeof(port_tcam_cmd),
+                       &port_tcam_cmd, &out_size);
+       if (err || !out_size || port_tcam_cmd.mgmt_msg_head.status) {
+               PMD_DRV_LOG(ERR, "Set tcam table failed, err: %d, status: 0x%x, out size: 0x%x",
+                       err, port_tcam_cmd.mgmt_msg_head.status, out_size);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+/**
+ * hinic_clear_fdir_tcam - Clear fdir filter TCAM table for control packet.
+ *
+ * @param hwdev
+ *   The hardware interface of a nic device.
+ * @param type_mask
+ *   Index of TCAM.
+ * @return
+ *   0 on success,
+ *   negative error value otherwise.
+ */
+int hinic_clear_fdir_tcam(void *hwdev, u16 type_mask)
+{
+       struct hinic_fdir_tcam_info port_tcam_cmd;
+       u16 out_size = sizeof(port_tcam_cmd);
+       int err;
+
+       if (!hwdev)
+               return -EINVAL;
+
+       memset(&port_tcam_cmd, 0, sizeof(port_tcam_cmd));
+       port_tcam_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       port_tcam_cmd.tcam_index = type_mask;
+       port_tcam_cmd.flag = TCAM_CLEAR;
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_TCAM_FILTER,
+                       &port_tcam_cmd, sizeof(port_tcam_cmd),
+                       &port_tcam_cmd, &out_size);
+       if (err || !out_size || port_tcam_cmd.mgmt_msg_head.status) {
+               PMD_DRV_LOG(ERR, "Clear tcam table failed, err: %d, status: 0x%x, out size: 0x%x",
+                       err, port_tcam_cmd.mgmt_msg_head.status, out_size);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+int hinic_add_tcam_rule(void *hwdev, struct tag_tcam_cfg_rule *tcam_rule)
+{
+       u16 out_size = sizeof(struct tag_fdir_add_rule_cmd);
+       struct tag_fdir_add_rule_cmd tcam_cmd;
+       int err;
+
+       if (!hwdev) {
+               PMD_DRV_LOG(ERR, "Hwdev is NULL");
+               return -EINVAL;
+       }
+
+       if (tcam_rule->index >= HINIC_MAX_TCAM_RULES_NUM) {
+               PMD_DRV_LOG(ERR, "Tcam rules num to add is invalid");
+               return -EFAULT;
+       }
+
+       memset(&tcam_cmd, 0, sizeof(struct tag_fdir_add_rule_cmd));
+       tcam_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       memcpy((void *)&tcam_cmd.rule, (void *)tcam_rule,
+               sizeof(struct tag_tcam_cfg_rule));
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_UP_TC_ADD_FLOW,
+                               &tcam_cmd, sizeof(tcam_cmd),
+                               &tcam_cmd, &out_size);
+       if (err || tcam_cmd.mgmt_msg_head.status || !out_size) {
+               PMD_DRV_LOG(ERR,
+                       "Add tcam rule failed, err: %d, status: 0x%x, out size: 0x%x",
+                       err, tcam_cmd.mgmt_msg_head.status, out_size);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+int hinic_del_tcam_rule(void *hwdev, u32 index)
+{
+       u16 out_size = sizeof(struct tag_fdir_del_rule_cmd);
+       struct tag_fdir_del_rule_cmd tcam_cmd;
+       int err;
+
+       if (!hwdev) {
+               PMD_DRV_LOG(ERR, "Hwdev is NULL");
+               return -EINVAL;
+       }
+
+       if (index >= HINIC_MAX_TCAM_RULES_NUM) {
+               PMD_DRV_LOG(ERR, "Tcam rules num to del is invalid");
+               return -EFAULT;
+       }
+
+       memset(&tcam_cmd, 0, sizeof(struct tag_fdir_del_rule_cmd));
+       tcam_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       tcam_cmd.index_start = index;
+       tcam_cmd.index_num = 1;
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_UP_TC_DEL_FLOW,
+                               &tcam_cmd, sizeof(tcam_cmd),
+                               &tcam_cmd, &out_size);
+       if (err || tcam_cmd.mgmt_msg_head.status || !out_size) {
+               PMD_DRV_LOG(ERR,
+                       "Del tcam rule failed, err: %d, status: 0x%x, out size: 0x%x",
+                       err, tcam_cmd.mgmt_msg_head.status, out_size);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+static int hinic_mgmt_tcam_block(void *hwdev, u8 alloc_en,
+                               u8 block_type, u16 *index)
+{
+       struct hinic_cmd_ctrl_tcam_block tcam_block_info;
+       u16 out_size = sizeof(struct hinic_cmd_ctrl_tcam_block);
+       struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev;
+       int err;
+
+       if (!hwdev) {
+               PMD_DRV_LOG(ERR, "Hwdev is NULL");
+               return -EINVAL;
+       }
+
+       memset(&tcam_block_info, 0, sizeof(struct hinic_cmd_ctrl_tcam_block));
+       tcam_block_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       tcam_block_info.func_id = hinic_global_func_id(hwdev);
+       tcam_block_info.alloc_en = alloc_en;
+       tcam_block_info.tcam_type = block_type;
+       tcam_block_info.tcam_block_index = *index;
+
+       err = l2nic_msg_to_mgmt_sync(hwdev,
+                               HINIC_PORT_CMD_UP_TC_CTRL_TCAM_BLOCK,
+                               &tcam_block_info, sizeof(tcam_block_info),
+                               &tcam_block_info, &out_size);
+       if (tcam_block_info.mgmt_msg_head.status ==
+               HINIC_MGMT_CMD_UNSUPPORTED) {
+               err = HINIC_MGMT_CMD_UNSUPPORTED;
+               PMD_DRV_LOG(INFO, "Firmware/uP doesn't support alloc or del tcam block");
+               return err;
+       } else if ((err == HINIC_MBOX_VF_CMD_ERROR) &&
+                       (HINIC_IS_VF(nic_hwdev))) {
+               err = HINIC_MGMT_CMD_UNSUPPORTED;
+               PMD_DRV_LOG(INFO, "VF doesn't support alloc and del tcam block.");
+               return err;
+       } else if (err || (!out_size) || tcam_block_info.mgmt_msg_head.status) {
+               PMD_DRV_LOG(ERR,
+                       "Set tcam block failed, err: %d, status: 0x%x, out size: 0x%x",
+                       err, tcam_block_info.mgmt_msg_head.status, out_size);
+               return -EFAULT;
+       }
+
+       if (alloc_en)
+               *index = tcam_block_info.tcam_block_index;
+
+       return 0;
+}
+
+int hinic_alloc_tcam_block(void *hwdev, u8 block_type, u16 *index)
+{
+       return hinic_mgmt_tcam_block(hwdev, HINIC_TCAM_BLOCK_ENABLE,
+                               block_type, index);
+}
+
+int hinic_free_tcam_block(void *hwdev, u8 block_type, u16 *index)
+{
+       return hinic_mgmt_tcam_block(hwdev, HINIC_TCAM_BLOCK_DISABLE,
+                               block_type, index);
+}
+
+int hinic_flush_tcam_rule(void *hwdev)
+{
+       struct hinic_cmd_flush_tcam_rules tcam_flush;
+       u16 out_size = sizeof(struct hinic_cmd_flush_tcam_rules);
+       struct hinic_hwdev *nic_hwdev = (struct hinic_hwdev *)hwdev;
+       int err;
+
+       if (!hwdev) {
+               PMD_DRV_LOG(ERR, "Hwdev is NULL");
+               return -EINVAL;
+       }
+
+       memset(&tcam_flush, 0, sizeof(struct hinic_cmd_flush_tcam_rules));
+       tcam_flush.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       tcam_flush.func_id = hinic_global_func_id(hwdev);
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_UP_TC_FLUSH_TCAM,
+                       &tcam_flush, sizeof(struct hinic_cmd_flush_tcam_rules),
+                       &tcam_flush, &out_size);
+       if (tcam_flush.mgmt_msg_head.status == HINIC_MGMT_CMD_UNSUPPORTED) {
+               err = HINIC_MGMT_CMD_UNSUPPORTED;
+               PMD_DRV_LOG(INFO, "Firmware/uP doesn't support flush tcam fdir");
+       } else if ((err == HINIC_MBOX_VF_CMD_ERROR) &&
+                       (HINIC_IS_VF(nic_hwdev))) {
+               err = HINIC_MGMT_CMD_UNSUPPORTED;
+               PMD_DRV_LOG(INFO, "VF doesn't support flush tcam fdir");
+       } else if (err || (!out_size) || tcam_flush.mgmt_msg_head.status) {
+               PMD_DRV_LOG(ERR,
+                       "Flush tcam fdir rules failed, err: %d, status: 0x%x, out size: 0x%x",
+                       err, tcam_flush.mgmt_msg_head.status, out_size);
+               err = -EFAULT;
+       }
+
+       return err;
+}
+
+int hinic_set_fdir_tcam_rule_filter(void *hwdev, bool enable)
+{
+       struct hinic_port_tcam_info port_tcam_cmd;
+       u16 out_size = sizeof(port_tcam_cmd);
+       int err;
+
+       if (!hwdev)
+               return -EINVAL;
+
+       memset(&port_tcam_cmd, 0, sizeof(port_tcam_cmd));
+       port_tcam_cmd.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       port_tcam_cmd.func_id = hinic_global_func_id(hwdev);
+       port_tcam_cmd.tcam_enable = (u8)enable;
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_UP_TC_ENABLE,
+                       &port_tcam_cmd, sizeof(port_tcam_cmd),
+                       &port_tcam_cmd, &out_size);
+       if ((port_tcam_cmd.mgmt_msg_head.status != HINIC_MGMT_CMD_UNSUPPORTED &&
+               port_tcam_cmd.mgmt_msg_head.status) || err || !out_size) {
+               if (err == HINIC_MBOX_VF_CMD_ERROR &&
+                       HINIC_IS_VF((struct hinic_hwdev *)hwdev)) {
+                       err = HINIC_MGMT_CMD_UNSUPPORTED;
+                       PMD_DRV_LOG(WARNING, "VF doesn't support setting fdir tcam filter");
+                       return err;
+               }
+               PMD_DRV_LOG(ERR, "Set fdir tcam filter failed, err: %d, "
+                       "status: 0x%x, out size: 0x%x, enable: 0x%x",
+                       err, port_tcam_cmd.mgmt_msg_head.status, out_size,
+                       enable);
+               return -EFAULT;
+       }
+
+       if (port_tcam_cmd.mgmt_msg_head.status == HINIC_MGMT_CMD_UNSUPPORTED) {
+               err = HINIC_MGMT_CMD_UNSUPPORTED;
+               PMD_DRV_LOG(WARNING, "Fw doesn't support setting fdir tcam filter");
+       }
+
+       return err;
+}
+
+