get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/105250/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 105250,
    "url": "http://patches.dpdk.org/api/patches/105250/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/6015a42cf3bd56b453f47a284423877c0f490ab7.1639636621.git.songyl@ramaxel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<6015a42cf3bd56b453f47a284423877c0f490ab7.1639636621.git.songyl@ramaxel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/6015a42cf3bd56b453f47a284423877c0f490ab7.1639636621.git.songyl@ramaxel.com",
    "date": "2021-12-18T02:51:37",
    "name": "[v1,10/25] net/spnic: add function info initialization",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "321a639bb2185112e2b447594a7f6a3fcebf271e",
    "submitter": {
        "id": 2455,
        "url": "http://patches.dpdk.org/api/people/2455/?format=api",
        "name": "Yanling Song",
        "email": "songyl@ramaxel.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/6015a42cf3bd56b453f47a284423877c0f490ab7.1639636621.git.songyl@ramaxel.com/mbox/",
    "series": [
        {
            "id": 20973,
            "url": "http://patches.dpdk.org/api/series/20973/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=20973",
            "date": "2021-12-18T02:51:28",
            "name": "Net/SPNIC: support SPNIC into DPDK 22.03",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/20973/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/105250/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/105250/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id D1B15A04A4;\n\tSat, 18 Dec 2021 03:53:45 +0100 (CET)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id E251D411E1;\n\tSat, 18 Dec 2021 03:52:36 +0100 (CET)",
            "from VLXDG1SPAM1.ramaxel.com (email.ramaxel.com [221.4.138.186])\n by mails.dpdk.org (Postfix) with ESMTP id 8973441181\n for <dev@dpdk.org>; Sat, 18 Dec 2021 03:52:34 +0100 (CET)",
            "from V12DG1MBS01.ramaxel.local (v12dg1mbs01.ramaxel.local\n [172.26.18.31])\n by VLXDG1SPAM1.ramaxel.com with ESMTPS id 1BI2q0pK010340\n (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL);\n Sat, 18 Dec 2021 10:52:00 +0800 (GMT-8)\n (envelope-from songyl@ramaxel.com)",
            "from localhost.localdomain (10.64.9.47) by V12DG1MBS01.ramaxel.local\n (172.26.18.31) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2308.14; Sat, 18\n Dec 2021 10:51:59 +0800"
        ],
        "From": "Yanling Song <songyl@ramaxel.com>",
        "To": "<dev@dpdk.org>",
        "CC": "<songyl@ramaxel.com>, <yanling.song@linux.dev>, <yanggan@ramaxel.com>,\n <ferruh.yigit@intel.com>",
        "Subject": "[PATCH v1 10/25] net/spnic: add function info initialization",
        "Date": "Sat, 18 Dec 2021 10:51:37 +0800",
        "Message-ID": "\n <6015a42cf3bd56b453f47a284423877c0f490ab7.1639636621.git.songyl@ramaxel.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<cover.1639636621.git.songyl@ramaxel.com>",
        "References": "<cover.1639636621.git.songyl@ramaxel.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[10.64.9.47]",
        "X-ClientProxiedBy": "V12DG1MBS01.ramaxel.local (172.26.18.31) To\n V12DG1MBS01.ramaxel.local (172.26.18.31)",
        "X-DNSRBL": "",
        "X-MAIL": "VLXDG1SPAM1.ramaxel.com 1BI2q0pK010340",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org"
    },
    "content": "This patch mainly implements function info initialization\nincluding mtu, link state, port state, port info and cos\nas well as the definition of the corresponding data structure.\n\nSigned-off-by: Yanling Song <songyl@ramaxel.com>\n---\n drivers/net/spnic/base/spnic_hw_cfg.c  |  43 +++\n drivers/net/spnic/base/spnic_hw_cfg.h  |   6 +\n drivers/net/spnic/base/spnic_nic_cfg.c | 221 ++++++++++++++\n drivers/net/spnic/base/spnic_nic_cfg.h | 213 ++++++++++++++\n drivers/net/spnic/spnic_ethdev.c       | 382 ++++++++++++++++++++++++-\n drivers/net/spnic/spnic_ethdev.h       |  22 +-\n 6 files changed, 876 insertions(+), 11 deletions(-)",
    "diff": "diff --git a/drivers/net/spnic/base/spnic_hw_cfg.c b/drivers/net/spnic/base/spnic_hw_cfg.c\nindex 6505f48273..49e16ee89c 100644\n--- a/drivers/net/spnic/base/spnic_hw_cfg.c\n+++ b/drivers/net/spnic/base/spnic_hw_cfg.c\n@@ -156,6 +156,49 @@ void spnic_free_capability(void *dev)\n \trte_free(((struct spnic_hwdev *)dev)->cfg_mgmt);\n }\n \n+/* *\n+ * @brief spnic_support_nic - function support nic\n+ * @param hwdev: device pointer to hwdev\n+ * @retval true: function support nic\n+ * @retval false: function not support nic\n+ */\n+bool spnic_support_nic(void *hwdev)\n+{\n+\tstruct spnic_hwdev *dev = (struct spnic_hwdev *)hwdev;\n+\n+\tif (!hwdev)\n+\t\treturn false;\n+\n+\tif (!IS_NIC_TYPE(dev))\n+\t\treturn false;\n+\n+\treturn true;\n+}\n+\n+u16 spnic_func_max_sqs(void *hwdev)\n+{\n+\tstruct spnic_hwdev *dev = hwdev;\n+\n+\tif (!dev) {\n+\t\tPMD_DRV_LOG(INFO, \"Hwdev is NULL for getting max_sqs\");\n+\t\treturn 0;\n+\t}\n+\n+\treturn dev->cfg_mgmt->svc_cap.nic_cap.max_sqs;\n+}\n+\n+u16 spnic_func_max_rqs(void *hwdev)\n+{\n+\tstruct spnic_hwdev *dev = hwdev;\n+\n+\tif (!dev) {\n+\t\tPMD_DRV_LOG(INFO, \"Hwdev is NULL for getting max_rqs\");\n+\t\treturn 0;\n+\t}\n+\n+\treturn dev->cfg_mgmt->svc_cap.nic_cap.max_rqs;\n+}\n+\n u8 spnic_physical_port_id(void *hwdev)\n {\n \tstruct spnic_hwdev *dev = hwdev;\ndiff --git a/drivers/net/spnic/base/spnic_hw_cfg.h b/drivers/net/spnic/base/spnic_hw_cfg.h\nindex 9ab51f2875..5019f38ec2 100644\n--- a/drivers/net/spnic/base/spnic_hw_cfg.h\n+++ b/drivers/net/spnic/base/spnic_hw_cfg.h\n@@ -112,8 +112,14 @@ struct spnic_cfg_cmd_dev_cap {\n int spnic_init_capability(void *dev);\n void spnic_free_capability(void *dev);\n \n+u16 spnic_func_max_sqs(void *hwdev);\n+u16 spnic_func_max_rqs(void *hwdev);\n+\n u8 spnic_physical_port_id(void *hwdev);\n \n int cfg_mbx_vf_proc_msg(void *hwdev, void *pri_handle, u16 cmd, void *buf_in,\n \t\t\tu16 in_size, void *buf_out, u16 *out_size);\n+\n+bool spnic_support_nic(void *hwdev);\n+\n #endif /* _SPNIC_HW_CFG_H_ */\ndiff --git a/drivers/net/spnic/base/spnic_nic_cfg.c b/drivers/net/spnic/base/spnic_nic_cfg.c\nindex c47bc330a3..886aaea384 100644\n--- a/drivers/net/spnic/base/spnic_nic_cfg.c\n+++ b/drivers/net/spnic/base/spnic_nic_cfg.c\n@@ -265,6 +265,227 @@ int spnic_get_port_info(void *hwdev, struct nic_port_info *port_info)\n \treturn 0;\n }\n \n+\n+int spnic_get_link_state(void *hwdev, u8 *link_state)\n+{\n+\tstruct spnic_cmd_link_state get_link;\n+\tu16 out_size = sizeof(get_link);\n+\tint err;\n+\n+\tif (!hwdev || !link_state)\n+\t\treturn -EINVAL;\n+\n+\tmemset(&get_link, 0, sizeof(get_link));\n+\tget_link.port_id = spnic_physical_port_id(hwdev);\n+\terr = mag_msg_to_mgmt_sync(hwdev, MAG_CMD_GET_LINK_STATUS, &get_link,\n+\t\t\t\t   sizeof(get_link), &get_link, &out_size);\n+\tif (err || !out_size || get_link.msg_head.status) {\n+\t\tPMD_DRV_LOG(ERR, \"Get link state failed, err: %d, status: 0x%x, out size: 0x%x\",\n+\t\t\t    err, get_link.msg_head.status, out_size);\n+\t\treturn -EIO;\n+\t}\n+\n+\t*link_state = get_link.state;\n+\n+\treturn 0;\n+}\n+\n+int spnic_set_vport_enable(void *hwdev, bool enable)\n+{\n+\tstruct spnic_vport_state en_state;\n+\tu16 out_size = sizeof(en_state);\n+\tint err;\n+\n+\tif (!hwdev)\n+\t\treturn -EINVAL;\n+\n+\tmemset(&en_state, 0, sizeof(en_state));\n+\ten_state.func_id = spnic_global_func_id(hwdev);\n+\ten_state.state = enable ? 1 : 0;\n+\n+\terr = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_SET_VPORT_ENABLE, &en_state,\n+\t\t\t\t     sizeof(en_state), &en_state, &out_size);\n+\tif (err || !out_size || en_state.msg_head.status) {\n+\t\tPMD_DRV_LOG(ERR, \"Set vport state failed, err: %d, status: 0x%x, out size: 0x%x\",\n+\t\t\t    err, en_state.msg_head.status, out_size);\n+\t\treturn -EIO;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int spnic_set_port_enable(void *hwdev, bool enable)\n+{\n+\tstruct mag_cmd_set_port_enable en_state;\n+\tu16 out_size = sizeof(en_state);\n+\tint err;\n+\n+\tif (!hwdev)\n+\t\treturn -EINVAL;\n+\n+\tif (spnic_func_type(hwdev) == TYPE_VF)\n+\t\treturn 0;\n+\n+\tmemset(&en_state, 0, sizeof(en_state));\n+\ten_state.function_id = spnic_global_func_id(hwdev);\n+\ten_state.state = enable ? MAG_CMD_TX_ENABLE | MAG_CMD_RX_ENABLE :\n+\t\t\t\tMAG_CMD_PORT_DISABLE;\n+\n+\terr = mag_msg_to_mgmt_sync(hwdev, MAG_CMD_SET_PORT_ENABLE, &en_state,\n+\t\t\t\t     sizeof(en_state), &en_state, &out_size);\n+\tif (err || !out_size || en_state.head.status) {\n+\t\tPMD_DRV_LOG(ERR, \"Set port state failed, err: %d, status: 0x%x, out size: 0x%x\",\n+\t\t\t    err, en_state.head.status, out_size);\n+\t\treturn -EIO;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int spnic_set_function_table(void *hwdev, u32 cfg_bitmap,\n+\t\t\t\t     struct spnic_func_tbl_cfg *cfg)\n+{\n+\tstruct spnic_cmd_set_func_tbl cmd_func_tbl;\n+\tu16 out_size = sizeof(cmd_func_tbl);\n+\tint err;\n+\n+\tmemset(&cmd_func_tbl, 0, sizeof(cmd_func_tbl));\n+\tcmd_func_tbl.func_id = spnic_global_func_id(hwdev);\n+\tcmd_func_tbl.cfg_bitmap = cfg_bitmap;\n+\tcmd_func_tbl.tbl_cfg = *cfg;\n+\n+\terr = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_SET_FUNC_TBL,\n+\t\t\t\t     &cmd_func_tbl, sizeof(cmd_func_tbl),\n+\t\t\t\t     &cmd_func_tbl, &out_size);\n+\tif (err || cmd_func_tbl.msg_head.status || !out_size) {\n+\t\tPMD_DRV_LOG(ERR, \"Set func table failed, bitmap: 0x%x, err: %d, \"\n+\t\t\t    \"status: 0x%x, out size: 0x%x\\n\", cfg_bitmap, err,\n+\t\t\t    cmd_func_tbl.msg_head.status, out_size);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int spnic_init_function_table(void *hwdev, u16 rx_buff_len)\n+{\n+\tstruct spnic_func_tbl_cfg func_tbl_cfg;\n+\tu32 cfg_bitmap = BIT(FUNC_CFG_INIT) | BIT(FUNC_CFG_MTU) |\n+\t\t\t BIT(FUNC_CFG_RX_BUF_SIZE);\n+\n+\tmemset(&func_tbl_cfg, 0, sizeof(func_tbl_cfg));\n+\tfunc_tbl_cfg.mtu = 0x3FFF; /* Default, max mtu */\n+\tfunc_tbl_cfg.rx_wqe_buf_size = rx_buff_len;\n+\n+\treturn spnic_set_function_table(hwdev, cfg_bitmap, &func_tbl_cfg);\n+}\n+\n+int spnic_set_port_mtu(void *hwdev, u16 new_mtu)\n+{\n+\tstruct spnic_func_tbl_cfg func_tbl_cfg;\n+\n+\tif (!hwdev)\n+\t\treturn -EINVAL;\n+\n+\tif (new_mtu < SPNIC_MIN_MTU_SIZE) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid mtu size: %ubytes, mtu size < %ubytes\",\n+\t\t\t    new_mtu, SPNIC_MIN_MTU_SIZE);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (new_mtu > SPNIC_MAX_JUMBO_FRAME_SIZE) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid mtu size: %ubytes, mtu size > %ubytes\",\n+\t\t\t    new_mtu, SPNIC_MAX_JUMBO_FRAME_SIZE);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmemset(&func_tbl_cfg, 0, sizeof(func_tbl_cfg));\n+\tfunc_tbl_cfg.mtu = new_mtu;\n+\n+\treturn spnic_set_function_table(hwdev, BIT(FUNC_CFG_MTU),\n+\t\t\t\t\t&func_tbl_cfg);\n+}\n+\n+static int spnic_vf_func_init(void *hwdev)\n+{\n+\tstruct spnic_cmd_register_vf register_info;\n+\tu16 out_size = sizeof(register_info);\n+\tint err;\n+\n+\tif (spnic_func_type(hwdev) != TYPE_VF)\n+\t\treturn 0;\n+\n+\tmemset(&register_info, 0, sizeof(register_info));\n+\tregister_info.op_register = 1;\n+\terr = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_VF_REGISTER,\n+\t\t\t\t     &register_info, sizeof(register_info),\n+\t\t\t\t     &register_info, &out_size);\n+\tif (err || register_info.msg_head.status || !out_size) {\n+\t\tPMD_DRV_LOG(ERR, \"Register VF failed, err: %d, status: 0x%x, out size: 0x%x\",\n+\t\t\t    err, register_info.msg_head.status, out_size);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int spnic_vf_func_free(void *hwdev)\n+{\n+\tstruct spnic_cmd_register_vf unregister;\n+\tu16 out_size = sizeof(unregister);\n+\tint err;\n+\n+\tif (spnic_func_type(hwdev) != TYPE_VF)\n+\t\treturn 0;\n+\n+\tmemset(&unregister, 0, sizeof(unregister));\n+\tunregister.op_register = 0;\n+\terr = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_VF_REGISTER,\n+\t\t\t\t     &unregister, sizeof(unregister),\n+\t\t\t\t     &unregister, &out_size);\n+\tif (err || unregister.msg_head.status || !out_size) {\n+\t\tPMD_DRV_LOG(ERR, \"Unregister VF failed, err: %d, status: 0x%x, out size: 0x%x\",\n+\t\t\t    err, unregister.msg_head.status, out_size);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int spnic_init_nic_hwdev(void *hwdev)\n+{\n+\treturn spnic_vf_func_init(hwdev);\n+}\n+\n+void spnic_free_nic_hwdev(void *hwdev)\n+{\n+\tif (!hwdev)\n+\t\treturn;\n+\n+\tspnic_vf_func_free(hwdev);\n+}\n+\n+int spnic_vf_get_default_cos(void *hwdev, u8 *cos_id)\n+{\n+\tstruct spnic_cmd_vf_dcb_state vf_dcb;\n+\tu16 out_size = sizeof(vf_dcb);\n+\tint err;\n+\n+\tmemset(&vf_dcb, 0, sizeof(vf_dcb));\n+\n+\terr = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_VF_COS, &vf_dcb,\n+\t\t\t\t     sizeof(vf_dcb), &vf_dcb, &out_size);\n+\tif (err || !out_size || vf_dcb.msg_head.status) {\n+\t\tPMD_DRV_LOG(ERR, \"Get VF default cos failed, err: %d, status: 0x%x, out size: 0x%x\",\n+\t\t\t    err, vf_dcb.msg_head.status, out_size);\n+\t\treturn -EIO;\n+\t}\n+\n+\t*cos_id = vf_dcb.state.default_cos;\n+\n+\treturn 0;\n+}\n+\n static int _mag_msg_to_mgmt_sync(void *hwdev, u16 cmd, void *buf_in,\n \t\t\t\t u16 in_size, void *buf_out, u16 *out_size)\n {\ndiff --git a/drivers/net/spnic/base/spnic_nic_cfg.h b/drivers/net/spnic/base/spnic_nic_cfg.h\nindex 669e982876..98cad645d2 100644\n--- a/drivers/net/spnic/base/spnic_nic_cfg.h\n+++ b/drivers/net/spnic/base/spnic_nic_cfg.h\n@@ -12,6 +12,26 @@\n #define OS_VF_ID_TO_HW(os_vf_id) ((os_vf_id) + 1)\n #define HW_VF_ID_TO_OS(hw_vf_id) ((hw_vf_id) - 1)\n \n+#define SPNIC_DCB_UP_MAX\t\t0x8\n+\n+#define SPNIC_MAX_NUM_RQ\t\t256\n+\n+#define SPNIC_MAX_MTU_SIZE\t\t9600\n+#define SPNIC_MIN_MTU_SIZE\t\t384\n+\n+#define SPNIC_COS_NUM_MAX\t\t8\n+\n+#define SPNIC_VLAN_TAG_SIZE\t\t4\n+#define SPNIC_ETH_OVERHEAD \\\n+\t(RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN + SPNIC_VLAN_TAG_SIZE * 2)\n+\n+#define SPNIC_MIN_FRAME_SIZE (SPNIC_MIN_MTU_SIZE + SPNIC_ETH_OVERHEAD)\n+#define SPNIC_MAX_JUMBO_FRAME_SIZE (SPNIC_MAX_MTU_SIZE + SPNIC_ETH_OVERHEAD)\n+\n+#define SPNIC_MTU_TO_PKTLEN(mtu)\t((mtu) + SPNIC_ETH_OVERHEAD)\n+\n+#define SPNIC_PKTLEN_TO_MTU(pktlen)\t((pktlen) - SPNIC_ETH_OVERHEAD)\n+\n #define SPNIC_PF_SET_VF_ALREADY\t\t0x4\n #define SPNIC_MGMT_STATUS_EXIST\t\t0x6\n #define CHECK_IPSU_15BIT\t\t0x8000\n@@ -92,6 +112,114 @@ struct spnic_cmd_link_state {\n \tu16 rsvd1;\n };\n \n+struct nic_pause_config {\n+\tu8 auto_neg;\n+\tu8 rx_pause;\n+\tu8 tx_pause;\n+};\n+\n+struct spnic_cmd_pause_config {\n+\tstruct mgmt_msg_head msg_head;\n+\n+\tu8 port_id;\n+\tu8 opcode;\n+\tu16 rsvd1;\n+\tu8 auto_neg;\n+\tu8 rx_pause;\n+\tu8 tx_pause;\n+\tu8 rsvd2[5];\n+};\n+\n+struct spnic_vport_state {\n+\tstruct mgmt_msg_head msg_head;\n+\n+\tu16 func_id;\n+\tu16 rsvd1;\n+\tu8 state;  /* 0--disable, 1--enable */\n+\tu8 rsvd2[3];\n+};\n+\n+#define MAG_CMD_PORT_DISABLE  0x0\n+#define MAG_CMD_TX_ENABLE     0x1\n+#define MAG_CMD_RX_ENABLE     0x2\n+/* the physical port is disable only when all pf of the port are set to down,\n+ * if any pf is enable, the port is enable\n+ */\n+struct mag_cmd_set_port_enable {\n+\tstruct mgmt_msg_head head;\n+\n+\tu16 function_id;\n+\tu16 rsvd0;\n+\n+\tu8 state;  /* bitmap bit0:tx_en bit1:rx_en */\n+\tu8 rsvd1[3];\n+};\n+\n+struct mag_cmd_get_port_enable {\n+\tstruct mgmt_msg_head head;\n+\n+\tu8 port;\n+\tu8 state; /* bitmap bit0:tx_en bit1:rx_en */\n+\tu8 rsvd0[2];\n+};\n+\n+struct spnic_cmd_clear_qp_resource {\n+\tstruct mgmt_msg_head msg_head;\n+\n+\tu16 func_id;\n+\tu16 rsvd1;\n+};\n+\n+\n+enum spnic_func_tbl_cfg_bitmap {\n+\tFUNC_CFG_INIT,\n+\tFUNC_CFG_RX_BUF_SIZE,\n+\tFUNC_CFG_MTU,\n+};\n+\n+struct spnic_func_tbl_cfg {\n+\tu16 rx_wqe_buf_size;\n+\tu16 mtu;\n+\tu32 rsvd[9];\n+};\n+\n+struct spnic_cmd_set_func_tbl {\n+\tstruct mgmt_msg_head msg_head;\n+\n+\tu16 func_id;\n+\tu16 rsvd;\n+\n+\tu32 cfg_bitmap;\n+\tstruct spnic_func_tbl_cfg tbl_cfg;\n+};\n+\n+enum {\n+\tSPNIC_IFLA_VF_LINK_STATE_AUTO,\t/* Link state of the uplink */\n+\tSPNIC_IFLA_VF_LINK_STATE_ENABLE, /* Link always up */\n+\tSPNIC_IFLA_VF_LINK_STATE_DISABLE, /* Link always down */\n+};\n+\n+struct spnic_dcb_state {\n+\tu8 dcb_on;\n+\tu8 default_cos;\n+\tu16 rsvd1;\n+\tu8 up_cos[SPNIC_DCB_UP_MAX];\n+\tu32 rsvd2[7];\n+};\n+\n+struct spnic_cmd_vf_dcb_state {\n+\tstruct mgmt_msg_head msg_head;\n+\n+\tstruct spnic_dcb_state state;\n+};\n+\n+struct spnic_cmd_register_vf {\n+\tstruct mgmt_msg_head msg_head;\n+\n+\tu8 op_register; /* 0 - unregister, 1 - register */\n+\tu8 rsvd[39];\n+};\n+\n int l2nic_msg_to_mgmt_sync(void *hwdev, u16 cmd, void *buf_in, u16 in_size,\n \t\t\t   void *buf_out, u16 *out_size);\n \n@@ -164,6 +292,77 @@ int spnic_set_mac(void *hwdev, const u8 *mac_addr, u16 vlan_id, u16 func_id);\n  */\n int spnic_del_mac(void *hwdev, const u8 *mac_addr, u16 vlan_id, u16 func_id);\n \n+/**\n+ * Set function mtu\n+ *\n+ * @param[in] hwdev\n+ *   Device pointer to hwdev\n+ * @param[in] new_mtu\n+ *   MTU value\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+int spnic_set_port_mtu(void *hwdev, u16 new_mtu);\n+\n+/**\n+ * Set function valid status\n+ *\n+ * @param[in] hwdev\n+ *   Device pointer to hwdev\n+ * @param[in] enable\n+ *   0-disable, 1-enable\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+int spnic_set_vport_enable(void *hwdev, bool enable);\n+\n+/**\n+ * Set port status\n+ *\n+ * @param[in] hwdev\n+ *   Device pointer to hwdev\n+ * @param[in] enable\n+ *   0-disable, 1-enable\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+int spnic_set_port_enable(void *hwdev, bool enable);\n+\n+/**\n+ * Get link state\n+ *\n+ * @param[in] hwdev\n+ *   Device pointer to hwdev\n+ * @param[out] link_state\n+ *   Link state, 0-link down, 1-link up\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+int spnic_get_link_state(void *hwdev, u8 *link_state);\n+\n+/**\n+ * Init nic hwdev\n+ *\n+ * @param[in] hwdev\n+ *   Device pointer to hwdev\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+int spnic_init_nic_hwdev(void *hwdev);\n+\n+/**\n+ * Free nic hwdev\n+ *\n+ * @param[in] hwdev\n+ *   Device pointer to hwdev\n+ */\n+void spnic_free_nic_hwdev(void *hwdev);\n+\n /**\n  * Get port info\n  *\n@@ -177,4 +376,18 @@ int spnic_del_mac(void *hwdev, const u8 *mac_addr, u16 vlan_id, u16 func_id);\n  */\n int spnic_get_port_info(void *hwdev, struct nic_port_info *port_info);\n \n+int spnic_init_function_table(void *hwdev, u16 rx_buff_len);\n+\n+/**\n+ * Get VF function default cos\n+ *\n+ * @param[in] hwdev\n+ *   Device pointer to hwdev\n+ * @param[out] cos_id\n+ *   Cos id\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+int spnic_vf_get_default_cos(void *hwdev, u8 *cos_id);\n #endif /* _SPNIC_NIC_CFG_H_ */\ndiff --git a/drivers/net/spnic/spnic_ethdev.c b/drivers/net/spnic/spnic_ethdev.c\nindex 8f71280fa7..7f73e70df1 100644\n--- a/drivers/net/spnic/spnic_ethdev.c\n+++ b/drivers/net/spnic/spnic_ethdev.c\n@@ -30,23 +30,106 @@ int spnic_logtype;\n #define SPNIC_MAX_UC_MAC_ADDRS\t\t128\n #define SPNIC_MAX_MC_MAC_ADDRS\t\t128\n \n-static void spnic_delete_mc_addr_list(struct spnic_nic_dev *nic_dev)\n+/**\n+ * Deinit mac_vlan table in hardware.\n+ *\n+ * @param[in] eth_dev\n+ *   Pointer to ethernet device structure.\n+ */\n+\n+/**\n+ * Set ethernet device link state up.\n+ *\n+ * @param[in] dev\n+ *   Pointer to ethernet device structure.\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure.\n+ */\n+static int spnic_dev_set_link_up(struct rte_eth_dev *dev)\n {\n-\tu16 func_id;\n-\tu32 i;\n+\tstruct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);\n+\tint err;\n \n-\tfunc_id = spnic_global_func_id(nic_dev->hwdev);\n+\t/* Link status follow phy port status, mpu will open pma */\n+\terr = spnic_set_port_enable(nic_dev->hwdev, true);\n+\tif (err)\n+\t\tPMD_DRV_LOG(ERR, \"Set MAC link up failed, dev_name: %s, port_id: %d\",\n+\t\t\t    nic_dev->dev_name, dev->data->port_id);\n \n-\tfor (i = 0; i < SPNIC_MAX_MC_MAC_ADDRS; i++) {\n-\t\tif (rte_is_zero_ether_addr(&nic_dev->mc_list[i]))\n+\treturn err;\n+}\n+\n+/**\n+ * Set ethernet device link state down.\n+ *\n+ * @param[in] dev\n+ *   Pointer to ethernet device structure.\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure.\n+ */\n+static int spnic_dev_set_link_down(struct rte_eth_dev *dev)\n+{\n+\tstruct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);\n+\tint err;\n+\n+\t/* Link status follow phy port status, mpu will close pma */\n+\terr = spnic_set_port_enable(nic_dev->hwdev, false);\n+\tif (err)\n+\t\tPMD_DRV_LOG(ERR, \"Set MAC link down failed, dev_name: %s, port_id: %d\",\n+\t\t\t    nic_dev->dev_name, dev->data->port_id);\n+\n+\treturn err;\n+}\n+\n+/**\n+ * Get device physical link information.\n+ *\n+ * @param[in] dev\n+ *   Pointer to ethernet device structure.\n+ * @param[in] wait_to_complete\n+ *   Wait for request completion.\n+ *\n+ * @retval 0 : Link status changed\n+ * @retval -1 : Link status not changed.\n+ */\n+static int spnic_link_update(struct rte_eth_dev *dev, int wait_to_complete)\n+{\n+#define CHECK_INTERVAL 10  /* 10ms */\n+#define MAX_REPEAT_TIME 100  /* 1s (100 * 10ms) in total */\n+\tstruct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);\n+\tstruct rte_eth_link link;\n+\tu8 link_state;\n+\tunsigned int rep_cnt = MAX_REPEAT_TIME;\n+\tint ret;\n+\n+\tmemset(&link, 0, sizeof(link));\n+\tdo {\n+\t\t/* Get link status information from hardware */\n+\t\tret = spnic_get_link_state(nic_dev->hwdev, &link_state);\n+\t\tif (ret) {\n+\t\t\tlink.link_status = ETH_LINK_DOWN;\n+\t\t\tlink.link_speed = ETH_SPEED_NUM_NONE;\n+\t\t\tlink.link_duplex = ETH_LINK_HALF_DUPLEX;\n+\t\t\tlink.link_autoneg = ETH_LINK_FIXED;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tget_port_info(nic_dev->hwdev, link_state, &link);\n+\n+\t\tif (!wait_to_complete || link.link_status)\n \t\t\tbreak;\n \n-\t\tspnic_del_mac(nic_dev->hwdev, nic_dev->mc_list[i].addr_bytes,\n-\t\t\t      0, func_id);\n-\t\tmemset(&nic_dev->mc_list[i], 0, sizeof(struct rte_ether_addr));\n-\t}\n+\t\trte_delay_ms(CHECK_INTERVAL);\n+\t} while (rep_cnt--);\n+\n+out:\n+\treturn rte_eth_linkstatus_set(dev, &link);\n }\n \n+static void spnic_delete_mc_addr_list(struct spnic_nic_dev *nic_dev);\n+\n /**\n  * Deinit mac_vlan table in hardware.\n  *\n@@ -82,6 +165,122 @@ static void spnic_deinit_mac_addr(struct rte_eth_dev *eth_dev)\n \tspnic_delete_mc_addr_list(nic_dev);\n }\n \n+static int spnic_init_sw_rxtxqs(struct spnic_nic_dev *nic_dev)\n+{\n+\tu32 txq_size;\n+\tu32 rxq_size;\n+\n+\t/* Allocate software txq array */\n+\ttxq_size = nic_dev->max_sqs * sizeof(*nic_dev->txqs);\n+\tnic_dev->txqs = rte_zmalloc(\"spnic_txqs\", txq_size,\n+\t\t\t\t    RTE_CACHE_LINE_SIZE);\n+\tif (!nic_dev->txqs) {\n+\t\tPMD_DRV_LOG(ERR, \"Allocate txqs failed\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\t/* Allocate software rxq array */\n+\trxq_size = nic_dev->max_rqs * sizeof(*nic_dev->rxqs);\n+\tnic_dev->rxqs = rte_zmalloc(\"spnic_rxqs\", rxq_size,\n+\t\t\t\t    RTE_CACHE_LINE_SIZE);\n+\tif (!nic_dev->rxqs) {\n+\t\t/* Free txqs */\n+\t\trte_free(nic_dev->txqs);\n+\t\tnic_dev->txqs = NULL;\n+\n+\t\tPMD_DRV_LOG(ERR, \"Allocate rxqs failed\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void spnic_deinit_sw_rxtxqs(struct spnic_nic_dev *nic_dev)\n+{\n+\trte_free(nic_dev->txqs);\n+\tnic_dev->txqs = NULL;\n+\n+\trte_free(nic_dev->rxqs);\n+\tnic_dev->rxqs = NULL;\n+}\n+\n+/**\n+ * Start the device.\n+ *\n+ * Initialize function table, rxq and txq context, config rx offload, and enable\n+ * vport and port to prepare receiving packets.\n+ *\n+ * @param[in] eth_dev\n+ *   Pointer to ethernet device structure.\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+static int spnic_dev_start(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct spnic_nic_dev *nic_dev;\n+\tint err;\n+\n+\tnic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);\n+\n+\terr = spnic_init_function_table(nic_dev->hwdev, nic_dev->rx_buff_len);\n+\tif (err) {\n+\t\tPMD_DRV_LOG(ERR, \"Init function table failed, dev_name: %s\",\n+\t\t\t    eth_dev->data->name);\n+\t\tgoto init_func_tbl_fail;\n+\t}\n+\n+\t/* Set default mtu */\n+\terr = spnic_set_port_mtu(nic_dev->hwdev, nic_dev->mtu_size);\n+\tif (err) {\n+\t\tPMD_DRV_LOG(ERR, \"Set mtu_size[%d] failed, dev_name: %s\",\n+\t\t\t    nic_dev->mtu_size, eth_dev->data->name);\n+\t\tgoto set_mtu_fail;\n+\t}\n+\n+\n+\t/* Update eth_dev link status */\n+\tif (eth_dev->data->dev_conf.intr_conf.lsc != 0)\n+\t\t(void)spnic_link_update(eth_dev, 0);\n+\n+\trte_bit_relaxed_set32(SPNIC_DEV_START, &nic_dev->dev_status);\n+\n+\treturn 0;\n+\n+set_mtu_fail:\n+init_func_tbl_fail:\n+\n+\treturn err;\n+}\n+\n+/**\n+ * Stop the device.\n+ *\n+ * Stop phy port and vport, flush pending io request, clean context configure\n+ * and free io resourece.\n+ *\n+ * @param[in] dev\n+ *   Pointer to ethernet device structure.\n+ */\n+static int spnic_dev_stop(struct rte_eth_dev *dev)\n+{\n+\tstruct spnic_nic_dev *nic_dev;\n+\tstruct rte_eth_link link;\n+\n+\tnic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);\n+\tif (!rte_bit_relaxed_test_and_clear32(SPNIC_DEV_START, &nic_dev->dev_status)) {\n+\t\tPMD_DRV_LOG(INFO, \"Device %s already stopped\",\n+\t\t\t    nic_dev->dev_name);\n+\t\treturn 0;\n+\t}\n+\n+\t/* Clear recorded link status */\n+\tmemset(&link, 0, sizeof(link));\n+\t(void)rte_eth_linkstatus_set(dev, &link);\n+\n+\treturn 0;\n+}\n+\n /**\n  * Close the device.\n  *\n@@ -99,11 +298,19 @@ static int spnic_dev_close(struct rte_eth_dev *eth_dev)\n \t\treturn 0;\n \t}\n \n+\tspnic_dev_stop(eth_dev);\n+\n+\tspnic_deinit_sw_rxtxqs(nic_dev);\n \tspnic_deinit_mac_addr(eth_dev);\n \trte_free(nic_dev->mc_list);\n \n \trte_bit_relaxed_clear32(SPNIC_DEV_INTR_EN, &nic_dev->dev_status);\n \n+\n+\t/* Destroy rx mode mutex */\n+\tspnic_mutex_destroy(&nic_dev->rx_mode_mutex);\n+\n+\tspnic_free_nic_hwdev(nic_dev->hwdev);\n \tspnic_free_hwdev(nic_dev->hwdev);\n \n \teth_dev->dev_ops = NULL;\n@@ -113,6 +320,34 @@ static int spnic_dev_close(struct rte_eth_dev *eth_dev)\n \n \treturn 0;\n }\n+\n+static int spnic_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)\n+{\n+\tstruct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);\n+\tint err = 0;\n+\n+\tPMD_DRV_LOG(INFO, \"Set port mtu, port_id: %d, mtu: %d, max_pkt_len: %d\",\n+\t\t    dev->data->port_id, mtu, SPNIC_MTU_TO_PKTLEN(mtu));\n+\n+\tif (mtu < SPNIC_MIN_MTU_SIZE || mtu > SPNIC_MAX_MTU_SIZE) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid mtu: %d, must between %d and %d\",\n+\t\t\t    mtu, SPNIC_MIN_MTU_SIZE, SPNIC_MAX_MTU_SIZE);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\terr = spnic_set_port_mtu(nic_dev->hwdev, mtu);\n+\tif (err) {\n+\t\tPMD_DRV_LOG(ERR, \"Set port mtu failed, err: %d\", err);\n+\t\treturn err;\n+\t}\n+\n+\t/* Update max frame size */\n+\tdev->data->dev_conf.rxmode.mtu = SPNIC_MTU_TO_PKTLEN(mtu);\n+\tnic_dev->mtu_size = mtu;\n+\n+\treturn err;\n+}\n+\n /**\n  * Update MAC address\n  *\n@@ -233,6 +468,23 @@ static int spnic_mac_addr_add(struct rte_eth_dev *dev,\n \treturn 0;\n }\n \n+static void spnic_delete_mc_addr_list(struct spnic_nic_dev *nic_dev)\n+{\n+\tu16 func_id;\n+\tu32 i;\n+\n+\tfunc_id = spnic_global_func_id(nic_dev->hwdev);\n+\n+\tfor (i = 0; i < SPNIC_MAX_MC_MAC_ADDRS; i++) {\n+\t\tif (rte_is_zero_ether_addr(&nic_dev->mc_list[i]))\n+\t\t\tbreak;\n+\n+\t\tspnic_del_mac(nic_dev->hwdev, nic_dev->mc_list[i].addr_bytes,\n+\t\t\t      0, func_id);\n+\t\tmemset(&nic_dev->mc_list[i], 0, sizeof(struct rte_ether_addr));\n+\t}\n+}\n+\n /**\n  * Set multicast MAC address\n  *\n@@ -287,7 +539,15 @@ static int spnic_set_mc_addr_list(struct rte_eth_dev *dev,\n \n \treturn 0;\n }\n+\n static const struct eth_dev_ops spnic_pmd_ops = {\n+\t.dev_set_link_up               = spnic_dev_set_link_up,\n+\t.dev_set_link_down             = spnic_dev_set_link_down,\n+\t.link_update                   = spnic_link_update,\n+\t.dev_start                     = spnic_dev_start,\n+\t.dev_stop                      = spnic_dev_stop,\n+\t.dev_close                     = spnic_dev_close,\n+\t.mtu_set                       = spnic_dev_set_mtu,\n \t.mac_addr_set                  = spnic_set_mac_addr,\n \t.mac_addr_remove               = spnic_mac_addr_remove,\n \t.mac_addr_add                  = spnic_mac_addr_add,\n@@ -295,6 +555,11 @@ static const struct eth_dev_ops spnic_pmd_ops = {\n };\n \n static const struct eth_dev_ops spnic_pmd_vf_ops = {\n+\t.link_update                   = spnic_link_update,\n+\t.dev_start                     = spnic_dev_start,\n+\t.dev_stop                      = spnic_dev_stop,\n+\t.dev_close                     = spnic_dev_close,\n+\t.mtu_set                       = spnic_dev_set_mtu,\n \t.mac_addr_set                  = spnic_set_mac_addr,\n \t.mac_addr_remove               = spnic_mac_addr_remove,\n \t.mac_addr_add                  = spnic_mac_addr_add,\n@@ -341,6 +606,66 @@ static int spnic_init_mac_table(struct rte_eth_dev *eth_dev)\n \treturn 0;\n }\n \n+static int spnic_pf_get_default_cos(struct spnic_hwdev *hwdev, u8 *cos_id)\n+{\n+\tu8 default_cos = 0;\n+\tu8 valid_cos_bitmap;\n+\tu8 i;\n+\n+\tvalid_cos_bitmap = hwdev->cfg_mgmt->svc_cap.cos_valid_bitmap;\n+\tif (!valid_cos_bitmap) {\n+\t\tPMD_DRV_LOG(ERR, \"PF has none cos to support\\n\");\n+\t\treturn -EFAULT;\n+\t}\n+\n+\tfor (i = 0; i < SPNIC_COS_NUM_MAX; i++) {\n+\t\tif (valid_cos_bitmap & BIT(i))\n+\t\t\t/* Find max cos id as default cos */\n+\t\t\tdefault_cos = i;\n+\t}\n+\n+\t*cos_id = default_cos;\n+\n+\treturn 0;\n+}\n+\n+static int spnic_init_default_cos(struct spnic_nic_dev *nic_dev)\n+{\n+\tu8 cos_id = 0;\n+\tint err;\n+\n+\tif (!SPNIC_IS_VF(nic_dev->hwdev)) {\n+\t\terr = spnic_pf_get_default_cos(nic_dev->hwdev, &cos_id);\n+\t\tif (err) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Get PF default cos failed, err: %d\",\n+\t\t\t\t    err);\n+\t\t\treturn err;\n+\t\t}\n+\t} else {\n+\t\terr = spnic_vf_get_default_cos(nic_dev->hwdev, &cos_id);\n+\t\tif (err) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Get VF default cos failed, err: %d\",\n+\t\t\t\t    err);\n+\t\t\treturn err;\n+\t\t}\n+\t}\n+\n+\tnic_dev->default_cos = cos_id;\n+\tPMD_DRV_LOG(INFO, \"Default cos %d\", nic_dev->default_cos);\n+\treturn 0;\n+}\n+\n+static int spnic_set_default_hw_feature(struct spnic_nic_dev *nic_dev)\n+{\n+\tint err;\n+\n+\terr = spnic_init_default_cos(nic_dev);\n+\tif (err)\n+\t\treturn err;\n+\n+\treturn 0;\n+}\n+\n static int spnic_func_init(struct rte_eth_dev *eth_dev)\n {\n \tstruct spnic_nic_dev *nic_dev = NULL;\n@@ -411,10 +736,28 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev)\n \t\tgoto init_hwdev_fail;\n \t}\n \n+\tnic_dev->max_sqs = spnic_func_max_sqs(nic_dev->hwdev);\n+\tnic_dev->max_rqs = spnic_func_max_rqs(nic_dev->hwdev);\n+\n \tif (SPNIC_FUNC_TYPE(nic_dev->hwdev) == TYPE_VF)\n \t\teth_dev->dev_ops = &spnic_pmd_vf_ops;\n \telse\n \t\teth_dev->dev_ops = &spnic_pmd_ops;\n+\n+\terr = spnic_init_nic_hwdev(nic_dev->hwdev);\n+\tif (err) {\n+\t\tPMD_DRV_LOG(ERR, \"Init nic hwdev failed, dev_name: %s\",\n+\t\t\t    eth_dev->data->name);\n+\t\tgoto init_nic_hwdev_fail;\n+\t}\n+\n+\terr = spnic_init_sw_rxtxqs(nic_dev);\n+\tif (err) {\n+\t\tPMD_DRV_LOG(ERR, \"Init sw rxqs or txqs failed, dev_name: %s\",\n+\t\t\t    eth_dev->data->name);\n+\t\tgoto init_sw_rxtxqs_fail;\n+\t}\n+\n \terr = spnic_init_mac_table(eth_dev);\n \tif (err) {\n \t\tPMD_DRV_LOG(ERR, \"Init mac table failed, dev_name: %s\",\n@@ -422,6 +765,16 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev)\n \t\tgoto init_mac_table_fail;\n \t}\n \n+\t/* Set hardware feature to default status */\n+\terr = spnic_set_default_hw_feature(nic_dev);\n+\tif (err) {\n+\t\tPMD_DRV_LOG(ERR, \"Set hw default features failed, dev_name: %s\",\n+\t\t\t    eth_dev->data->name);\n+\t\tgoto set_default_feature_fail;\n+\t}\n+\n+\tspnic_mutex_init(&nic_dev->rx_mode_mutex, NULL);\n+\n \trte_bit_relaxed_set32(SPNIC_DEV_INTR_EN, &nic_dev->dev_status);\n \n \trte_bit_relaxed_set32(SPNIC_DEV_INIT, &nic_dev->dev_status);\n@@ -430,7 +783,16 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev)\n \n \treturn 0;\n \n+set_default_feature_fail:\n+\tspnic_deinit_mac_addr(eth_dev);\n+\n init_mac_table_fail:\n+\tspnic_deinit_sw_rxtxqs(nic_dev);\n+\n+init_sw_rxtxqs_fail:\n+\tspnic_free_nic_hwdev(nic_dev->hwdev);\n+\n+init_nic_hwdev_fail:\n \tspnic_free_hwdev(nic_dev->hwdev);\n \teth_dev->dev_ops = NULL;\n \ndiff --git a/drivers/net/spnic/spnic_ethdev.h b/drivers/net/spnic/spnic_ethdev.h\nindex 654234aaa4..321db389dc 100644\n--- a/drivers/net/spnic/spnic_ethdev.h\n+++ b/drivers/net/spnic/spnic_ethdev.h\n@@ -4,6 +4,7 @@\n \n #ifndef _SPNIC_ETHDEV_H_\n #define _SPNIC_ETHDEV_H_\n+#define SPNIC_DEV_NAME_LEN\t\t32\n \n #define SPNIC_UINT32_BIT_SIZE\t\t(CHAR_BIT * sizeof(uint32_t))\n #define SPNIC_VFTA_SIZE\t\t\t(4096 / SPNIC_UINT32_BIT_SIZE)\n@@ -16,7 +17,25 @@ enum spnic_dev_status {\n \tSPNIC_DEV_INTR_EN\n };\n \n-#define SPNIC_DEV_NAME_LEN\t\t32\n+enum nic_feature_cap {\n+\tNIC_F_CSUM = BIT(0),\n+\tNIC_F_SCTP_CRC = BIT(1),\n+\tNIC_F_TSO = BIT(2),\n+\tNIC_F_LRO = BIT(3),\n+\tNIC_F_UFO = BIT(4),\n+\tNIC_F_RSS = BIT(5),\n+\tNIC_F_RX_VLAN_FILTER = BIT(6),\n+\tNIC_F_RX_VLAN_STRIP = BIT(7),\n+\tNIC_F_TX_VLAN_INSERT = BIT(8),\n+\tNIC_F_VXLAN_OFFLOAD = BIT(9),\n+\tNIC_F_IPSEC_OFFLOAD = BIT(10),\n+\tNIC_F_FDIR = BIT(11),\n+\tNIC_F_PROMISC = BIT(12),\n+\tNIC_F_ALLMULTI = BIT(13),\n+};\n+\n+#define DEFAULT_DRV_FEATURE\t\t0x3FFF\n+\n struct spnic_nic_dev {\n \tstruct spnic_hwdev *hwdev; /* Hardware device */\n \n@@ -53,6 +72,7 @@ struct spnic_nic_dev {\n \tstruct rte_ether_addr *mc_list;\n \n \tchar dev_name[SPNIC_DEV_NAME_LEN];\n+\tu64 feature_cap;\n \tu32 vfta[SPNIC_VFTA_SIZE]; /* VLAN bitmap */\n };\n \n",
    "prefixes": [
        "v1",
        "10/25"
    ]
}