This patch mainly implements function info initialization
including mtu, link state, port state, port info and cos
as well as the definition of the corresponding data structure.

Signed-off-by: Yanling Song <son...@ramaxel.com>
---
 drivers/net/spnic/base/spnic_hw_cfg.c  |  43 +++
 drivers/net/spnic/base/spnic_hw_cfg.h  |   6 +
 drivers/net/spnic/base/spnic_nic_cfg.c | 221 ++++++++++++++
 drivers/net/spnic/base/spnic_nic_cfg.h | 213 ++++++++++++++
 drivers/net/spnic/spnic_ethdev.c       | 382 ++++++++++++++++++++++++-
 drivers/net/spnic/spnic_ethdev.h       |  22 +-
 6 files changed, 876 insertions(+), 11 deletions(-)

diff --git a/drivers/net/spnic/base/spnic_hw_cfg.c 
b/drivers/net/spnic/base/spnic_hw_cfg.c
index 6505f48273..49e16ee89c 100644
--- a/drivers/net/spnic/base/spnic_hw_cfg.c
+++ b/drivers/net/spnic/base/spnic_hw_cfg.c
@@ -156,6 +156,49 @@ void spnic_free_capability(void *dev)
        rte_free(((struct spnic_hwdev *)dev)->cfg_mgmt);
 }
 
+/* *
+ * @brief spnic_support_nic - function support nic
+ * @param hwdev: device pointer to hwdev
+ * @retval true: function support nic
+ * @retval false: function not support nic
+ */
+bool spnic_support_nic(void *hwdev)
+{
+       struct spnic_hwdev *dev = (struct spnic_hwdev *)hwdev;
+
+       if (!hwdev)
+               return false;
+
+       if (!IS_NIC_TYPE(dev))
+               return false;
+
+       return true;
+}
+
+u16 spnic_func_max_sqs(void *hwdev)
+{
+       struct spnic_hwdev *dev = hwdev;
+
+       if (!dev) {
+               PMD_DRV_LOG(INFO, "Hwdev is NULL for getting max_sqs");
+               return 0;
+       }
+
+       return dev->cfg_mgmt->svc_cap.nic_cap.max_sqs;
+}
+
+u16 spnic_func_max_rqs(void *hwdev)
+{
+       struct spnic_hwdev *dev = hwdev;
+
+       if (!dev) {
+               PMD_DRV_LOG(INFO, "Hwdev is NULL for getting max_rqs");
+               return 0;
+       }
+
+       return dev->cfg_mgmt->svc_cap.nic_cap.max_rqs;
+}
+
 u8 spnic_physical_port_id(void *hwdev)
 {
        struct spnic_hwdev *dev = hwdev;
diff --git a/drivers/net/spnic/base/spnic_hw_cfg.h 
b/drivers/net/spnic/base/spnic_hw_cfg.h
index 9ab51f2875..5019f38ec2 100644
--- a/drivers/net/spnic/base/spnic_hw_cfg.h
+++ b/drivers/net/spnic/base/spnic_hw_cfg.h
@@ -112,8 +112,14 @@ struct spnic_cfg_cmd_dev_cap {
 int spnic_init_capability(void *dev);
 void spnic_free_capability(void *dev);
 
+u16 spnic_func_max_sqs(void *hwdev);
+u16 spnic_func_max_rqs(void *hwdev);
+
 u8 spnic_physical_port_id(void *hwdev);
 
 int cfg_mbx_vf_proc_msg(void *hwdev, void *pri_handle, u16 cmd, void *buf_in,
                        u16 in_size, void *buf_out, u16 *out_size);
+
+bool spnic_support_nic(void *hwdev);
+
 #endif /* _SPNIC_HW_CFG_H_ */
diff --git a/drivers/net/spnic/base/spnic_nic_cfg.c 
b/drivers/net/spnic/base/spnic_nic_cfg.c
index c47bc330a3..886aaea384 100644
--- a/drivers/net/spnic/base/spnic_nic_cfg.c
+++ b/drivers/net/spnic/base/spnic_nic_cfg.c
@@ -265,6 +265,227 @@ int spnic_get_port_info(void *hwdev, struct nic_port_info 
*port_info)
        return 0;
 }
 
+
+int spnic_get_link_state(void *hwdev, u8 *link_state)
+{
+       struct spnic_cmd_link_state get_link;
+       u16 out_size = sizeof(get_link);
+       int err;
+
+       if (!hwdev || !link_state)
+               return -EINVAL;
+
+       memset(&get_link, 0, sizeof(get_link));
+       get_link.port_id = spnic_physical_port_id(hwdev);
+       err = mag_msg_to_mgmt_sync(hwdev, MAG_CMD_GET_LINK_STATUS, &get_link,
+                                  sizeof(get_link), &get_link, &out_size);
+       if (err || !out_size || get_link.msg_head.status) {
+               PMD_DRV_LOG(ERR, "Get link state failed, err: %d, status: 0x%x, 
out size: 0x%x",
+                           err, get_link.msg_head.status, out_size);
+               return -EIO;
+       }
+
+       *link_state = get_link.state;
+
+       return 0;
+}
+
+int spnic_set_vport_enable(void *hwdev, bool enable)
+{
+       struct spnic_vport_state en_state;
+       u16 out_size = sizeof(en_state);
+       int err;
+
+       if (!hwdev)
+               return -EINVAL;
+
+       memset(&en_state, 0, sizeof(en_state));
+       en_state.func_id = spnic_global_func_id(hwdev);
+       en_state.state = enable ? 1 : 0;
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_SET_VPORT_ENABLE, 
&en_state,
+                                    sizeof(en_state), &en_state, &out_size);
+       if (err || !out_size || en_state.msg_head.status) {
+               PMD_DRV_LOG(ERR, "Set vport state failed, err: %d, status: 
0x%x, out size: 0x%x",
+                           err, en_state.msg_head.status, out_size);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int spnic_set_port_enable(void *hwdev, bool enable)
+{
+       struct mag_cmd_set_port_enable en_state;
+       u16 out_size = sizeof(en_state);
+       int err;
+
+       if (!hwdev)
+               return -EINVAL;
+
+       if (spnic_func_type(hwdev) == TYPE_VF)
+               return 0;
+
+       memset(&en_state, 0, sizeof(en_state));
+       en_state.function_id = spnic_global_func_id(hwdev);
+       en_state.state = enable ? MAG_CMD_TX_ENABLE | MAG_CMD_RX_ENABLE :
+                               MAG_CMD_PORT_DISABLE;
+
+       err = mag_msg_to_mgmt_sync(hwdev, MAG_CMD_SET_PORT_ENABLE, &en_state,
+                                    sizeof(en_state), &en_state, &out_size);
+       if (err || !out_size || en_state.head.status) {
+               PMD_DRV_LOG(ERR, "Set port state failed, err: %d, status: 0x%x, 
out size: 0x%x",
+                           err, en_state.head.status, out_size);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int spnic_set_function_table(void *hwdev, u32 cfg_bitmap,
+                                    struct spnic_func_tbl_cfg *cfg)
+{
+       struct spnic_cmd_set_func_tbl cmd_func_tbl;
+       u16 out_size = sizeof(cmd_func_tbl);
+       int err;
+
+       memset(&cmd_func_tbl, 0, sizeof(cmd_func_tbl));
+       cmd_func_tbl.func_id = spnic_global_func_id(hwdev);
+       cmd_func_tbl.cfg_bitmap = cfg_bitmap;
+       cmd_func_tbl.tbl_cfg = *cfg;
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_SET_FUNC_TBL,
+                                    &cmd_func_tbl, sizeof(cmd_func_tbl),
+                                    &cmd_func_tbl, &out_size);
+       if (err || cmd_func_tbl.msg_head.status || !out_size) {
+               PMD_DRV_LOG(ERR, "Set func table failed, bitmap: 0x%x, err: %d, 
"
+                           "status: 0x%x, out size: 0x%x\n", cfg_bitmap, err,
+                           cmd_func_tbl.msg_head.status, out_size);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+int spnic_init_function_table(void *hwdev, u16 rx_buff_len)
+{
+       struct spnic_func_tbl_cfg func_tbl_cfg;
+       u32 cfg_bitmap = BIT(FUNC_CFG_INIT) | BIT(FUNC_CFG_MTU) |
+                        BIT(FUNC_CFG_RX_BUF_SIZE);
+
+       memset(&func_tbl_cfg, 0, sizeof(func_tbl_cfg));
+       func_tbl_cfg.mtu = 0x3FFF; /* Default, max mtu */
+       func_tbl_cfg.rx_wqe_buf_size = rx_buff_len;
+
+       return spnic_set_function_table(hwdev, cfg_bitmap, &func_tbl_cfg);
+}
+
+int spnic_set_port_mtu(void *hwdev, u16 new_mtu)
+{
+       struct spnic_func_tbl_cfg func_tbl_cfg;
+
+       if (!hwdev)
+               return -EINVAL;
+
+       if (new_mtu < SPNIC_MIN_MTU_SIZE) {
+               PMD_DRV_LOG(ERR, "Invalid mtu size: %ubytes, mtu size < 
%ubytes",
+                           new_mtu, SPNIC_MIN_MTU_SIZE);
+               return -EINVAL;
+       }
+
+       if (new_mtu > SPNIC_MAX_JUMBO_FRAME_SIZE) {
+               PMD_DRV_LOG(ERR, "Invalid mtu size: %ubytes, mtu size > 
%ubytes",
+                           new_mtu, SPNIC_MAX_JUMBO_FRAME_SIZE);
+               return -EINVAL;
+       }
+
+       memset(&func_tbl_cfg, 0, sizeof(func_tbl_cfg));
+       func_tbl_cfg.mtu = new_mtu;
+
+       return spnic_set_function_table(hwdev, BIT(FUNC_CFG_MTU),
+                                       &func_tbl_cfg);
+}
+
+static int spnic_vf_func_init(void *hwdev)
+{
+       struct spnic_cmd_register_vf register_info;
+       u16 out_size = sizeof(register_info);
+       int err;
+
+       if (spnic_func_type(hwdev) != TYPE_VF)
+               return 0;
+
+       memset(&register_info, 0, sizeof(register_info));
+       register_info.op_register = 1;
+       err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_VF_REGISTER,
+                                    &register_info, sizeof(register_info),
+                                    &register_info, &out_size);
+       if (err || register_info.msg_head.status || !out_size) {
+               PMD_DRV_LOG(ERR, "Register VF failed, err: %d, status: 0x%x, 
out size: 0x%x",
+                           err, register_info.msg_head.status, out_size);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+static int spnic_vf_func_free(void *hwdev)
+{
+       struct spnic_cmd_register_vf unregister;
+       u16 out_size = sizeof(unregister);
+       int err;
+
+       if (spnic_func_type(hwdev) != TYPE_VF)
+               return 0;
+
+       memset(&unregister, 0, sizeof(unregister));
+       unregister.op_register = 0;
+       err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_VF_REGISTER,
+                                    &unregister, sizeof(unregister),
+                                    &unregister, &out_size);
+       if (err || unregister.msg_head.status || !out_size) {
+               PMD_DRV_LOG(ERR, "Unregister VF failed, err: %d, status: 0x%x, 
out size: 0x%x",
+                           err, unregister.msg_head.status, out_size);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+int spnic_init_nic_hwdev(void *hwdev)
+{
+       return spnic_vf_func_init(hwdev);
+}
+
+void spnic_free_nic_hwdev(void *hwdev)
+{
+       if (!hwdev)
+               return;
+
+       spnic_vf_func_free(hwdev);
+}
+
+int spnic_vf_get_default_cos(void *hwdev, u8 *cos_id)
+{
+       struct spnic_cmd_vf_dcb_state vf_dcb;
+       u16 out_size = sizeof(vf_dcb);
+       int err;
+
+       memset(&vf_dcb, 0, sizeof(vf_dcb));
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_VF_COS, &vf_dcb,
+                                    sizeof(vf_dcb), &vf_dcb, &out_size);
+       if (err || !out_size || vf_dcb.msg_head.status) {
+               PMD_DRV_LOG(ERR, "Get VF default cos failed, err: %d, status: 
0x%x, out size: 0x%x",
+                           err, vf_dcb.msg_head.status, out_size);
+               return -EIO;
+       }
+
+       *cos_id = vf_dcb.state.default_cos;
+
+       return 0;
+}
+
 static int _mag_msg_to_mgmt_sync(void *hwdev, u16 cmd, void *buf_in,
                                 u16 in_size, void *buf_out, u16 *out_size)
 {
diff --git a/drivers/net/spnic/base/spnic_nic_cfg.h 
b/drivers/net/spnic/base/spnic_nic_cfg.h
index a10a310530..0af4588c1a 100644
--- a/drivers/net/spnic/base/spnic_nic_cfg.h
+++ b/drivers/net/spnic/base/spnic_nic_cfg.h
@@ -12,6 +12,26 @@
 #define OS_VF_ID_TO_HW(os_vf_id) ((os_vf_id) + 1)
 #define HW_VF_ID_TO_OS(hw_vf_id) ((hw_vf_id) - 1)
 
+#define SPNIC_DCB_UP_MAX               0x8
+
+#define SPNIC_MAX_NUM_RQ               256
+
+#define SPNIC_MAX_MTU_SIZE             9600
+#define SPNIC_MIN_MTU_SIZE             384
+
+#define SPNIC_COS_NUM_MAX              8
+
+#define SPNIC_VLAN_TAG_SIZE            4
+#define SPNIC_ETH_OVERHEAD \
+       (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN + SPNIC_VLAN_TAG_SIZE * 2)
+
+#define SPNIC_MIN_FRAME_SIZE (SPNIC_MIN_MTU_SIZE + SPNIC_ETH_OVERHEAD)
+#define SPNIC_MAX_JUMBO_FRAME_SIZE (SPNIC_MAX_MTU_SIZE + SPNIC_ETH_OVERHEAD)
+
+#define SPNIC_MTU_TO_PKTLEN(mtu)       ((mtu) + SPNIC_ETH_OVERHEAD)
+
+#define SPNIC_PKTLEN_TO_MTU(pktlen)    ((pktlen) - SPNIC_ETH_OVERHEAD)
+
 #define SPNIC_PF_SET_VF_ALREADY                0x4
 #define SPNIC_MGMT_STATUS_EXIST                0x6
 #define CHECK_IPSU_15BIT               0x8000
@@ -92,6 +112,114 @@ struct spnic_cmd_link_state {
        u16 rsvd1;
 };
 
+struct nic_pause_config {
+       u8 auto_neg;
+       u8 rx_pause;
+       u8 tx_pause;
+};
+
+struct spnic_cmd_pause_config {
+       struct mgmt_msg_head msg_head;
+
+       u8 port_id;
+       u8 opcode;
+       u16 rsvd1;
+       u8 auto_neg;
+       u8 rx_pause;
+       u8 tx_pause;
+       u8 rsvd2[5];
+};
+
+struct spnic_vport_state {
+       struct mgmt_msg_head msg_head;
+
+       u16 func_id;
+       u16 rsvd1;
+       u8 state;  /* 0--disable, 1--enable */
+       u8 rsvd2[3];
+};
+
+#define MAG_CMD_PORT_DISABLE  0x0
+#define MAG_CMD_TX_ENABLE     0x1
+#define MAG_CMD_RX_ENABLE     0x2
+/* the physical port is disable only when all pf of the port are set to down,
+ * if any pf is enable, the port is enable
+ */
+struct mag_cmd_set_port_enable {
+       struct mgmt_msg_head head;
+
+       u16 function_id;
+       u16 rsvd0;
+
+       u8 state;  /* bitmap bit0:tx_en bit1:rx_en */
+       u8 rsvd1[3];
+};
+
+struct mag_cmd_get_port_enable {
+       struct mgmt_msg_head head;
+
+       u8 port;
+       u8 state; /* bitmap bit0:tx_en bit1:rx_en */
+       u8 rsvd0[2];
+};
+
+struct spnic_cmd_clear_qp_resource {
+       struct mgmt_msg_head msg_head;
+
+       u16 func_id;
+       u16 rsvd1;
+};
+
+
+enum spnic_func_tbl_cfg_bitmap {
+       FUNC_CFG_INIT,
+       FUNC_CFG_RX_BUF_SIZE,
+       FUNC_CFG_MTU,
+};
+
+struct spnic_func_tbl_cfg {
+       u16 rx_wqe_buf_size;
+       u16 mtu;
+       u32 rsvd[9];
+};
+
+struct spnic_cmd_set_func_tbl {
+       struct mgmt_msg_head msg_head;
+
+       u16 func_id;
+       u16 rsvd;
+
+       u32 cfg_bitmap;
+       struct spnic_func_tbl_cfg tbl_cfg;
+};
+
+enum {
+       SPNIC_IFLA_VF_LINK_STATE_AUTO,  /* Link state of the uplink */
+       SPNIC_IFLA_VF_LINK_STATE_ENABLE, /* Link always up */
+       SPNIC_IFLA_VF_LINK_STATE_DISABLE, /* Link always down */
+};
+
+struct spnic_dcb_state {
+       u8 dcb_on;
+       u8 default_cos;
+       u16 rsvd1;
+       u8 up_cos[SPNIC_DCB_UP_MAX];
+       u32 rsvd2[7];
+};
+
+struct spnic_cmd_vf_dcb_state {
+       struct mgmt_msg_head msg_head;
+
+       struct spnic_dcb_state state;
+};
+
+struct spnic_cmd_register_vf {
+       struct mgmt_msg_head msg_head;
+
+       u8 op_register; /* 0 - unregister, 1 - register */
+       u8 rsvd[39];
+};
+
 int l2nic_msg_to_mgmt_sync(void *hwdev, u16 cmd, void *buf_in, u16 in_size,
                           void *buf_out, u16 *out_size);
 
@@ -164,6 +292,77 @@ int spnic_set_mac(void *hwdev, const u8 *mac_addr, u16 
vlan_id, u16 func_id);
  */
 int spnic_del_mac(void *hwdev, const u8 *mac_addr, u16 vlan_id, u16 func_id);
 
+/**
+ * Set function mtu
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[in] new_mtu
+ *   MTU value
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_set_port_mtu(void *hwdev, u16 new_mtu);
+
+/**
+ * Set function valid status
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[in] enable
+ *   0-disable, 1-enable
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_set_vport_enable(void *hwdev, bool enable);
+
+/**
+ * Set port status
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[in] enable
+ *   0-disable, 1-enable
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_set_port_enable(void *hwdev, bool enable);
+
+/**
+ * Get link state
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[out] link_state
+ *   Link state, 0-link down, 1-link up
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_get_link_state(void *hwdev, u8 *link_state);
+
+/**
+ * Init nic hwdev
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_init_nic_hwdev(void *hwdev);
+
+/**
+ * Free nic hwdev
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ */
+void spnic_free_nic_hwdev(void *hwdev);
+
 /**
  * Get port info
  *
@@ -177,4 +376,18 @@ int spnic_del_mac(void *hwdev, const u8 *mac_addr, u16 
vlan_id, u16 func_id);
  */
 int spnic_get_port_info(void *hwdev, struct nic_port_info *port_info);
 
+int spnic_init_function_table(void *hwdev, u16 rx_buff_len);
+
+/**
+ * Get VF function default cos
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[out] cos_id
+ *   Cos id
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_vf_get_default_cos(void *hwdev, u8 *cos_id);
 #endif /* _SPNIC_NIC_CFG_H_ */
diff --git a/drivers/net/spnic/spnic_ethdev.c b/drivers/net/spnic/spnic_ethdev.c
index 8f71280fa7..7f73e70df1 100644
--- a/drivers/net/spnic/spnic_ethdev.c
+++ b/drivers/net/spnic/spnic_ethdev.c
@@ -30,23 +30,106 @@ int spnic_logtype;
 #define SPNIC_MAX_UC_MAC_ADDRS         128
 #define SPNIC_MAX_MC_MAC_ADDRS         128
 
-static void spnic_delete_mc_addr_list(struct spnic_nic_dev *nic_dev)
+/**
+ * Deinit mac_vlan table in hardware.
+ *
+ * @param[in] eth_dev
+ *   Pointer to ethernet device structure.
+ */
+
+/**
+ * Set ethernet device link state up.
+ *
+ * @param[in] dev
+ *   Pointer to ethernet device structure.
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure.
+ */
+static int spnic_dev_set_link_up(struct rte_eth_dev *dev)
 {
-       u16 func_id;
-       u32 i;
+       struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+       int err;
 
-       func_id = spnic_global_func_id(nic_dev->hwdev);
+       /* Link status follow phy port status, mpu will open pma */
+       err = spnic_set_port_enable(nic_dev->hwdev, true);
+       if (err)
+               PMD_DRV_LOG(ERR, "Set MAC link up failed, dev_name: %s, 
port_id: %d",
+                           nic_dev->dev_name, dev->data->port_id);
 
-       for (i = 0; i < SPNIC_MAX_MC_MAC_ADDRS; i++) {
-               if (rte_is_zero_ether_addr(&nic_dev->mc_list[i]))
+       return err;
+}
+
+/**
+ * Set ethernet device link state down.
+ *
+ * @param[in] dev
+ *   Pointer to ethernet device structure.
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure.
+ */
+static int spnic_dev_set_link_down(struct rte_eth_dev *dev)
+{
+       struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+       int err;
+
+       /* Link status follow phy port status, mpu will close pma */
+       err = spnic_set_port_enable(nic_dev->hwdev, false);
+       if (err)
+               PMD_DRV_LOG(ERR, "Set MAC link down failed, dev_name: %s, 
port_id: %d",
+                           nic_dev->dev_name, dev->data->port_id);
+
+       return err;
+}
+
+/**
+ * Get device physical link information.
+ *
+ * @param[in] dev
+ *   Pointer to ethernet device structure.
+ * @param[in] wait_to_complete
+ *   Wait for request completion.
+ *
+ * @retval 0 : Link status changed
+ * @retval -1 : Link status not changed.
+ */
+static int spnic_link_update(struct rte_eth_dev *dev, int wait_to_complete)
+{
+#define CHECK_INTERVAL 10  /* 10ms */
+#define MAX_REPEAT_TIME 100  /* 1s (100 * 10ms) in total */
+       struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+       struct rte_eth_link link;
+       u8 link_state;
+       unsigned int rep_cnt = MAX_REPEAT_TIME;
+       int ret;
+
+       memset(&link, 0, sizeof(link));
+       do {
+               /* Get link status information from hardware */
+               ret = spnic_get_link_state(nic_dev->hwdev, &link_state);
+               if (ret) {
+                       link.link_status = ETH_LINK_DOWN;
+                       link.link_speed = ETH_SPEED_NUM_NONE;
+                       link.link_duplex = ETH_LINK_HALF_DUPLEX;
+                       link.link_autoneg = ETH_LINK_FIXED;
+                       goto out;
+               }
+
+               get_port_info(nic_dev->hwdev, link_state, &link);
+
+               if (!wait_to_complete || link.link_status)
                        break;
 
-               spnic_del_mac(nic_dev->hwdev, nic_dev->mc_list[i].addr_bytes,
-                             0, func_id);
-               memset(&nic_dev->mc_list[i], 0, sizeof(struct rte_ether_addr));
-       }
+               rte_delay_ms(CHECK_INTERVAL);
+       } while (rep_cnt--);
+
+out:
+       return rte_eth_linkstatus_set(dev, &link);
 }
 
+static void spnic_delete_mc_addr_list(struct spnic_nic_dev *nic_dev);
+
 /**
  * Deinit mac_vlan table in hardware.
  *
@@ -82,6 +165,122 @@ static void spnic_deinit_mac_addr(struct rte_eth_dev 
*eth_dev)
        spnic_delete_mc_addr_list(nic_dev);
 }
 
+static int spnic_init_sw_rxtxqs(struct spnic_nic_dev *nic_dev)
+{
+       u32 txq_size;
+       u32 rxq_size;
+
+       /* Allocate software txq array */
+       txq_size = nic_dev->max_sqs * sizeof(*nic_dev->txqs);
+       nic_dev->txqs = rte_zmalloc("spnic_txqs", txq_size,
+                                   RTE_CACHE_LINE_SIZE);
+       if (!nic_dev->txqs) {
+               PMD_DRV_LOG(ERR, "Allocate txqs failed");
+               return -ENOMEM;
+       }
+
+       /* Allocate software rxq array */
+       rxq_size = nic_dev->max_rqs * sizeof(*nic_dev->rxqs);
+       nic_dev->rxqs = rte_zmalloc("spnic_rxqs", rxq_size,
+                                   RTE_CACHE_LINE_SIZE);
+       if (!nic_dev->rxqs) {
+               /* Free txqs */
+               rte_free(nic_dev->txqs);
+               nic_dev->txqs = NULL;
+
+               PMD_DRV_LOG(ERR, "Allocate rxqs failed");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void spnic_deinit_sw_rxtxqs(struct spnic_nic_dev *nic_dev)
+{
+       rte_free(nic_dev->txqs);
+       nic_dev->txqs = NULL;
+
+       rte_free(nic_dev->rxqs);
+       nic_dev->rxqs = NULL;
+}
+
+/**
+ * Start the device.
+ *
+ * Initialize function table, rxq and txq context, config rx offload, and 
enable
+ * vport and port to prepare receiving packets.
+ *
+ * @param[in] eth_dev
+ *   Pointer to ethernet device structure.
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+static int spnic_dev_start(struct rte_eth_dev *eth_dev)
+{
+       struct spnic_nic_dev *nic_dev;
+       int err;
+
+       nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);
+
+       err = spnic_init_function_table(nic_dev->hwdev, nic_dev->rx_buff_len);
+       if (err) {
+               PMD_DRV_LOG(ERR, "Init function table failed, dev_name: %s",
+                           eth_dev->data->name);
+               goto init_func_tbl_fail;
+       }
+
+       /* Set default mtu */
+       err = spnic_set_port_mtu(nic_dev->hwdev, nic_dev->mtu_size);
+       if (err) {
+               PMD_DRV_LOG(ERR, "Set mtu_size[%d] failed, dev_name: %s",
+                           nic_dev->mtu_size, eth_dev->data->name);
+               goto set_mtu_fail;
+       }
+
+
+       /* Update eth_dev link status */
+       if (eth_dev->data->dev_conf.intr_conf.lsc != 0)
+               (void)spnic_link_update(eth_dev, 0);
+
+       rte_bit_relaxed_set32(SPNIC_DEV_START, &nic_dev->dev_status);
+
+       return 0;
+
+set_mtu_fail:
+init_func_tbl_fail:
+
+       return err;
+}
+
+/**
+ * Stop the device.
+ *
+ * Stop phy port and vport, flush pending io request, clean context configure
+ * and free io resourece.
+ *
+ * @param[in] dev
+ *   Pointer to ethernet device structure.
+ */
+static int spnic_dev_stop(struct rte_eth_dev *dev)
+{
+       struct spnic_nic_dev *nic_dev;
+       struct rte_eth_link link;
+
+       nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+       if (!rte_bit_relaxed_test_and_clear32(SPNIC_DEV_START, 
&nic_dev->dev_status)) {
+               PMD_DRV_LOG(INFO, "Device %s already stopped",
+                           nic_dev->dev_name);
+               return 0;
+       }
+
+       /* Clear recorded link status */
+       memset(&link, 0, sizeof(link));
+       (void)rte_eth_linkstatus_set(dev, &link);
+
+       return 0;
+}
+
 /**
  * Close the device.
  *
@@ -99,11 +298,19 @@ static int spnic_dev_close(struct rte_eth_dev *eth_dev)
                return 0;
        }
 
+       spnic_dev_stop(eth_dev);
+
+       spnic_deinit_sw_rxtxqs(nic_dev);
        spnic_deinit_mac_addr(eth_dev);
        rte_free(nic_dev->mc_list);
 
        rte_bit_relaxed_clear32(SPNIC_DEV_INTR_EN, &nic_dev->dev_status);
 
+
+       /* Destroy rx mode mutex */
+       spnic_mutex_destroy(&nic_dev->rx_mode_mutex);
+
+       spnic_free_nic_hwdev(nic_dev->hwdev);
        spnic_free_hwdev(nic_dev->hwdev);
 
        eth_dev->dev_ops = NULL;
@@ -113,6 +320,34 @@ static int spnic_dev_close(struct rte_eth_dev *eth_dev)
 
        return 0;
 }
+
+static int spnic_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)
+{
+       struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+       int err = 0;
+
+       PMD_DRV_LOG(INFO, "Set port mtu, port_id: %d, mtu: %d, max_pkt_len: %d",
+                   dev->data->port_id, mtu, SPNIC_MTU_TO_PKTLEN(mtu));
+
+       if (mtu < SPNIC_MIN_MTU_SIZE || mtu > SPNIC_MAX_MTU_SIZE) {
+               PMD_DRV_LOG(ERR, "Invalid mtu: %d, must between %d and %d",
+                           mtu, SPNIC_MIN_MTU_SIZE, SPNIC_MAX_MTU_SIZE);
+               return -EINVAL;
+       }
+
+       err = spnic_set_port_mtu(nic_dev->hwdev, mtu);
+       if (err) {
+               PMD_DRV_LOG(ERR, "Set port mtu failed, err: %d", err);
+               return err;
+       }
+
+       /* Update max frame size */
+       dev->data->dev_conf.rxmode.mtu = SPNIC_MTU_TO_PKTLEN(mtu);
+       nic_dev->mtu_size = mtu;
+
+       return err;
+}
+
 /**
  * Update MAC address
  *
@@ -233,6 +468,23 @@ static int spnic_mac_addr_add(struct rte_eth_dev *dev,
        return 0;
 }
 
+static void spnic_delete_mc_addr_list(struct spnic_nic_dev *nic_dev)
+{
+       u16 func_id;
+       u32 i;
+
+       func_id = spnic_global_func_id(nic_dev->hwdev);
+
+       for (i = 0; i < SPNIC_MAX_MC_MAC_ADDRS; i++) {
+               if (rte_is_zero_ether_addr(&nic_dev->mc_list[i]))
+                       break;
+
+               spnic_del_mac(nic_dev->hwdev, nic_dev->mc_list[i].addr_bytes,
+                             0, func_id);
+               memset(&nic_dev->mc_list[i], 0, sizeof(struct rte_ether_addr));
+       }
+}
+
 /**
  * Set multicast MAC address
  *
@@ -287,7 +539,15 @@ static int spnic_set_mc_addr_list(struct rte_eth_dev *dev,
 
        return 0;
 }
+
 static const struct eth_dev_ops spnic_pmd_ops = {
+       .dev_set_link_up               = spnic_dev_set_link_up,
+       .dev_set_link_down             = spnic_dev_set_link_down,
+       .link_update                   = spnic_link_update,
+       .dev_start                     = spnic_dev_start,
+       .dev_stop                      = spnic_dev_stop,
+       .dev_close                     = spnic_dev_close,
+       .mtu_set                       = spnic_dev_set_mtu,
        .mac_addr_set                  = spnic_set_mac_addr,
        .mac_addr_remove               = spnic_mac_addr_remove,
        .mac_addr_add                  = spnic_mac_addr_add,
@@ -295,6 +555,11 @@ static const struct eth_dev_ops spnic_pmd_ops = {
 };
 
 static const struct eth_dev_ops spnic_pmd_vf_ops = {
+       .link_update                   = spnic_link_update,
+       .dev_start                     = spnic_dev_start,
+       .dev_stop                      = spnic_dev_stop,
+       .dev_close                     = spnic_dev_close,
+       .mtu_set                       = spnic_dev_set_mtu,
        .mac_addr_set                  = spnic_set_mac_addr,
        .mac_addr_remove               = spnic_mac_addr_remove,
        .mac_addr_add                  = spnic_mac_addr_add,
@@ -341,6 +606,66 @@ static int spnic_init_mac_table(struct rte_eth_dev 
*eth_dev)
        return 0;
 }
 
+static int spnic_pf_get_default_cos(struct spnic_hwdev *hwdev, u8 *cos_id)
+{
+       u8 default_cos = 0;
+       u8 valid_cos_bitmap;
+       u8 i;
+
+       valid_cos_bitmap = hwdev->cfg_mgmt->svc_cap.cos_valid_bitmap;
+       if (!valid_cos_bitmap) {
+               PMD_DRV_LOG(ERR, "PF has none cos to support\n");
+               return -EFAULT;
+       }
+
+       for (i = 0; i < SPNIC_COS_NUM_MAX; i++) {
+               if (valid_cos_bitmap & BIT(i))
+                       /* Find max cos id as default cos */
+                       default_cos = i;
+       }
+
+       *cos_id = default_cos;
+
+       return 0;
+}
+
+static int spnic_init_default_cos(struct spnic_nic_dev *nic_dev)
+{
+       u8 cos_id = 0;
+       int err;
+
+       if (!SPNIC_IS_VF(nic_dev->hwdev)) {
+               err = spnic_pf_get_default_cos(nic_dev->hwdev, &cos_id);
+               if (err) {
+                       PMD_DRV_LOG(ERR, "Get PF default cos failed, err: %d",
+                                   err);
+                       return err;
+               }
+       } else {
+               err = spnic_vf_get_default_cos(nic_dev->hwdev, &cos_id);
+               if (err) {
+                       PMD_DRV_LOG(ERR, "Get VF default cos failed, err: %d",
+                                   err);
+                       return err;
+               }
+       }
+
+       nic_dev->default_cos = cos_id;
+       PMD_DRV_LOG(INFO, "Default cos %d", nic_dev->default_cos);
+       return 0;
+}
+
+static int spnic_set_default_hw_feature(struct spnic_nic_dev *nic_dev)
+{
+       int err;
+
+       err = spnic_init_default_cos(nic_dev);
+       if (err)
+               return err;
+
+       return 0;
+}
+
 static int spnic_func_init(struct rte_eth_dev *eth_dev)
 {
        struct spnic_nic_dev *nic_dev = NULL;
@@ -411,10 +736,28 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev)
                goto init_hwdev_fail;
        }
 
+       nic_dev->max_sqs = spnic_func_max_sqs(nic_dev->hwdev);
+       nic_dev->max_rqs = spnic_func_max_rqs(nic_dev->hwdev);
+
        if (SPNIC_FUNC_TYPE(nic_dev->hwdev) == TYPE_VF)
                eth_dev->dev_ops = &spnic_pmd_vf_ops;
        else
                eth_dev->dev_ops = &spnic_pmd_ops;
+
+       err = spnic_init_nic_hwdev(nic_dev->hwdev);
+       if (err) {
+               PMD_DRV_LOG(ERR, "Init nic hwdev failed, dev_name: %s",
+                           eth_dev->data->name);
+               goto init_nic_hwdev_fail;
+       }
+
+       err = spnic_init_sw_rxtxqs(nic_dev);
+       if (err) {
+               PMD_DRV_LOG(ERR, "Init sw rxqs or txqs failed, dev_name: %s",
+                           eth_dev->data->name);
+               goto init_sw_rxtxqs_fail;
+       }
+
        err = spnic_init_mac_table(eth_dev);
        if (err) {
                PMD_DRV_LOG(ERR, "Init mac table failed, dev_name: %s",
@@ -422,6 +765,16 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev)
                goto init_mac_table_fail;
        }
 
+       /* Set hardware feature to default status */
+       err = spnic_set_default_hw_feature(nic_dev);
+       if (err) {
+               PMD_DRV_LOG(ERR, "Set hw default features failed, dev_name: %s",
+                           eth_dev->data->name);
+               goto set_default_feature_fail;
+       }
+
+       spnic_mutex_init(&nic_dev->rx_mode_mutex, NULL);
+
        rte_bit_relaxed_set32(SPNIC_DEV_INTR_EN, &nic_dev->dev_status);
 
        rte_bit_relaxed_set32(SPNIC_DEV_INIT, &nic_dev->dev_status);
@@ -430,7 +783,16 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev)
 
        return 0;
 
+set_default_feature_fail:
+       spnic_deinit_mac_addr(eth_dev);
+
 init_mac_table_fail:
+       spnic_deinit_sw_rxtxqs(nic_dev);
+
+init_sw_rxtxqs_fail:
+       spnic_free_nic_hwdev(nic_dev->hwdev);
+
+init_nic_hwdev_fail:
        spnic_free_hwdev(nic_dev->hwdev);
        eth_dev->dev_ops = NULL;
 
diff --git a/drivers/net/spnic/spnic_ethdev.h b/drivers/net/spnic/spnic_ethdev.h
index 654234aaa4..321db389dc 100644
--- a/drivers/net/spnic/spnic_ethdev.h
+++ b/drivers/net/spnic/spnic_ethdev.h
@@ -4,6 +4,7 @@
 
 #ifndef _SPNIC_ETHDEV_H_
 #define _SPNIC_ETHDEV_H_
+#define SPNIC_DEV_NAME_LEN             32
 
 #define SPNIC_UINT32_BIT_SIZE          (CHAR_BIT * sizeof(uint32_t))
 #define SPNIC_VFTA_SIZE                        (4096 / SPNIC_UINT32_BIT_SIZE)
@@ -16,7 +17,25 @@ enum spnic_dev_status {
        SPNIC_DEV_INTR_EN
 };
 
-#define SPNIC_DEV_NAME_LEN             32
+enum nic_feature_cap {
+       NIC_F_CSUM = BIT(0),
+       NIC_F_SCTP_CRC = BIT(1),
+       NIC_F_TSO = BIT(2),
+       NIC_F_LRO = BIT(3),
+       NIC_F_UFO = BIT(4),
+       NIC_F_RSS = BIT(5),
+       NIC_F_RX_VLAN_FILTER = BIT(6),
+       NIC_F_RX_VLAN_STRIP = BIT(7),
+       NIC_F_TX_VLAN_INSERT = BIT(8),
+       NIC_F_VXLAN_OFFLOAD = BIT(9),
+       NIC_F_IPSEC_OFFLOAD = BIT(10),
+       NIC_F_FDIR = BIT(11),
+       NIC_F_PROMISC = BIT(12),
+       NIC_F_ALLMULTI = BIT(13),
+};
+
+#define DEFAULT_DRV_FEATURE            0x3FFF
+
 struct spnic_nic_dev {
        struct spnic_hwdev *hwdev; /* Hardware device */
 
@@ -53,6 +72,7 @@ struct spnic_nic_dev {
        struct rte_ether_addr *mc_list;
 
        char dev_name[SPNIC_DEV_NAME_LEN];
+       u64 feature_cap;
        u32 vfta[SPNIC_VFTA_SIZE]; /* VLAN bitmap */
 };
 
-- 
2.32.0

Reply via email to