get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 105248,
    "url": "http://patches.dpdk.org/api/patches/105248/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/2bdd398a489d626cf86b62f169bfa366a50f0afa.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": "<2bdd398a489d626cf86b62f169bfa366a50f0afa.1639636621.git.songyl@ramaxel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/2bdd398a489d626cf86b62f169bfa366a50f0afa.1639636621.git.songyl@ramaxel.com",
    "date": "2021-12-18T02:51:36",
    "name": "[v1,09/25] net/spnic: support MAC and link event handling",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "018c45199aa007045a58dc9027af574f78da988c",
    "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/2bdd398a489d626cf86b62f169bfa366a50f0afa.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/105248/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/105248/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 C7D5EA04A4;\n\tSat, 18 Dec 2021 03:53:27 +0100 (CET)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 8157A41199;\n\tSat, 18 Dec 2021 03:52:32 +0100 (CET)",
            "from VLXDG1SPAM1.ramaxel.com (email.unionmem.com [221.4.138.186])\n by mails.dpdk.org (Postfix) with ESMTP id 0DC7841180\n for <dev@dpdk.org>; Sat, 18 Dec 2021 03:52:28 +0100 (CET)",
            "from V12DG1MBS01.ramaxel.local (v12dg1mbs01.ramaxel.local\n [172.26.18.31])\n by VLXDG1SPAM1.ramaxel.com with ESMTPS id 1BI2q0Wo010339\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 09/25] net/spnic: support MAC and link event handling",
        "Date": "Sat, 18 Dec 2021 10:51:36 +0800",
        "Message-ID": "\n <2bdd398a489d626cf86b62f169bfa366a50f0afa.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 1BI2q0Wo010339",
        "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 commit adds interfaces to add/remove MAC addresses\nand registers related ops to struct eth_dev_ops. Furthermore,\nthis commit adds callback to handle link events.\n\nSigned-off-by: Yanling Song <songyl@ramaxel.com>\n---\n drivers/net/spnic/base/meson.build       |   3 +-\n drivers/net/spnic/base/spnic_hw_cfg.c    |  12 +\n drivers/net/spnic/base/spnic_hw_cfg.h    |   2 +\n drivers/net/spnic/base/spnic_nic_cfg.c   | 291 +++++++++++++++++++\n drivers/net/spnic/base/spnic_nic_cfg.h   | 180 ++++++++++++\n drivers/net/spnic/base/spnic_nic_event.c |  27 +-\n drivers/net/spnic/base/spnic_nic_event.h |   9 +-\n drivers/net/spnic/spnic_ethdev.c         | 348 ++++++++++++++++++++++-\n 8 files changed, 861 insertions(+), 11 deletions(-)\n create mode 100644 drivers/net/spnic/base/spnic_nic_cfg.c\n create mode 100644 drivers/net/spnic/base/spnic_nic_cfg.h",
    "diff": "diff --git a/drivers/net/spnic/base/meson.build b/drivers/net/spnic/base/meson.build\nindex 77a56ca41e..f4bb4469ae 100644\n--- a/drivers/net/spnic/base/meson.build\n+++ b/drivers/net/spnic/base/meson.build\n@@ -11,7 +11,8 @@ sources = [\n \t'spnic_cmdq.c',\n \t'spnic_hw_comm.c',\n \t'spnic_wq.c',\n-\t'spnic_hw_cfg.c'\n+\t'spnic_hw_cfg.c',\n+\t'spnic_nic_cfg.c'\n ]\n \n extra_flags = []\ndiff --git a/drivers/net/spnic/base/spnic_hw_cfg.c b/drivers/net/spnic/base/spnic_hw_cfg.c\nindex e8856ce9fe..6505f48273 100644\n--- a/drivers/net/spnic/base/spnic_hw_cfg.c\n+++ b/drivers/net/spnic/base/spnic_hw_cfg.c\n@@ -155,3 +155,15 @@ void spnic_free_capability(void *dev)\n {\n \trte_free(((struct spnic_hwdev *)dev)->cfg_mgmt);\n }\n+\n+u8 spnic_physical_port_id(void *hwdev)\n+{\n+\tstruct spnic_hwdev *dev = hwdev;\n+\n+\tif (!dev) {\n+\t\tPMD_DRV_LOG(INFO, \"Hwdev is NULL for getting physical port id\");\n+\t\treturn 0;\n+\t}\n+\n+\treturn dev->cfg_mgmt->svc_cap.port_id;\n+}\ndiff --git a/drivers/net/spnic/base/spnic_hw_cfg.h b/drivers/net/spnic/base/spnic_hw_cfg.h\nindex 1b1b598726..9ab51f2875 100644\n--- a/drivers/net/spnic/base/spnic_hw_cfg.h\n+++ b/drivers/net/spnic/base/spnic_hw_cfg.h\n@@ -112,6 +112,8 @@ struct spnic_cfg_cmd_dev_cap {\n int spnic_init_capability(void *dev);\n void spnic_free_capability(void *dev);\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 #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\nnew file mode 100644\nindex 0000000000..c47bc330a3\n--- /dev/null\n+++ b/drivers/net/spnic/base/spnic_nic_cfg.c\n@@ -0,0 +1,291 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd\n+ */\n+\n+#include <rte_ether.h>\n+#include \"spnic_compat.h\"\n+#include \"spnic_cmd.h\"\n+#include \"spnic_mgmt.h\"\n+#include \"spnic_hwif.h\"\n+#include \"spnic_mbox.h\"\n+#include \"spnic_hwdev.h\"\n+#include \"spnic_wq.h\"\n+#include \"spnic_cmdq.h\"\n+#include \"spnic_nic_cfg.h\"\n+#include \"spnic_hw_cfg.h\"\n+\n+struct vf_msg_handler {\n+\tu16 cmd;\n+};\n+\n+const struct vf_msg_handler vf_cmd_handler[] = {\n+\t{\n+\t\t.cmd = SPNIC_CMD_VF_REGISTER,\n+\t},\n+\n+\t{\n+\t\t.cmd = SPNIC_CMD_GET_MAC,\n+\t},\n+\n+\t{\n+\t\t.cmd = SPNIC_CMD_SET_MAC,\n+\t},\n+\n+\t{\n+\t\t.cmd = SPNIC_CMD_DEL_MAC,\n+\t},\n+\n+\t{\n+\t\t.cmd = SPNIC_CMD_UPDATE_MAC,\n+\t},\n+\n+\t{\n+\t\t.cmd = SPNIC_CMD_VF_COS,\n+\t},\n+};\n+\n+static const struct vf_msg_handler vf_mag_cmd_handler[] = {\n+\t{\n+\t\t.cmd = MAG_CMD_GET_LINK_STATUS,\n+\t},\n+};\n+\n+static int mag_msg_to_mgmt_sync(void *hwdev, u16 cmd, void *buf_in, u16 in_size,\n+\t\t\t\tvoid *buf_out, u16 *out_size);\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+\tu32 i, cmd_cnt = ARRAY_LEN(vf_cmd_handler);\n+\tbool cmd_to_pf = false;\n+\n+\tif (spnic_func_type(hwdev) == TYPE_VF) {\n+\t\tfor (i = 0; i < cmd_cnt; i++) {\n+\t\t\tif (cmd == vf_cmd_handler[i].cmd)\n+\t\t\t\tcmd_to_pf = true;\n+\t\t}\n+\t}\n+\n+\tif (cmd_to_pf) {\n+\t\treturn spnic_mbox_to_pf(hwdev, SPNIC_MOD_L2NIC, cmd, buf_in,\n+\t\t\t\t\tin_size, buf_out, out_size, 0);\n+\t}\n+\n+\treturn spnic_msg_to_mgmt_sync(hwdev, SPNIC_MOD_L2NIC, cmd, buf_in,\n+\t\t\t\t      in_size, buf_out, out_size, 0);\n+}\n+\n+static int spnic_check_mac_info(u8 status, u16 vlan_id)\n+{\n+\tif ((status && status != SPNIC_MGMT_STATUS_EXIST &&\n+\t     status != SPNIC_PF_SET_VF_ALREADY) ||\n+\t    (vlan_id & CHECK_IPSU_15BIT &&\n+\t     status == SPNIC_MGMT_STATUS_EXIST))\n+\t\treturn -EINVAL;\n+\n+\treturn 0;\n+}\n+\n+#define VLAN_N_VID\t\t4096\n+\n+int spnic_set_mac(void *hwdev, const u8 *mac_addr, u16 vlan_id, u16 func_id)\n+{\n+\tstruct spnic_port_mac_set mac_info;\n+\tu16 out_size = sizeof(mac_info);\n+\tint err;\n+\n+\tif (!hwdev || !mac_addr)\n+\t\treturn -EINVAL;\n+\n+\tmemset(&mac_info, 0, sizeof(mac_info));\n+\n+\tif (vlan_id >= VLAN_N_VID) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid VLAN number: %d\", vlan_id);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmac_info.func_id = func_id;\n+\tmac_info.vlan_id = vlan_id;\n+\tmemmove(mac_info.mac, mac_addr, ETH_ALEN);\n+\n+\terr = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_SET_MAC, &mac_info,\n+\t\t\t\t     sizeof(mac_info), &mac_info, &out_size);\n+\tif (err || !out_size ||\n+\t    spnic_check_mac_info(mac_info.msg_head.status, mac_info.vlan_id)) {\n+\t\tPMD_DRV_LOG(ERR, \"Update MAC failed, err: %d, status: 0x%x, out size: 0x%x\",\n+\t\t\t    err, mac_info.msg_head.status, out_size);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (mac_info.msg_head.status == SPNIC_PF_SET_VF_ALREADY) {\n+\t\tPMD_DRV_LOG(WARNING, \"PF has already set VF mac, Ignore set operation\");\n+\t\treturn SPNIC_PF_SET_VF_ALREADY;\n+\t}\n+\n+\tif (mac_info.msg_head.status == SPNIC_MGMT_STATUS_EXIST) {\n+\t\tPMD_DRV_LOG(WARNING, \"MAC is repeated. Ignore update operation\");\n+\t\treturn 0;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int spnic_del_mac(void *hwdev, const u8 *mac_addr, u16 vlan_id, u16 func_id)\n+{\n+\tstruct spnic_port_mac_set mac_info;\n+\tu16 out_size = sizeof(mac_info);\n+\tint err;\n+\n+\tif (!hwdev || !mac_addr)\n+\t\treturn -EINVAL;\n+\n+\tif (vlan_id >= VLAN_N_VID) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid VLAN number: %d\", vlan_id);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmemset(&mac_info, 0, sizeof(mac_info));\n+\tmac_info.func_id = func_id;\n+\tmac_info.vlan_id = vlan_id;\n+\tmemmove(mac_info.mac, mac_addr, ETH_ALEN);\n+\n+\terr = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_DEL_MAC, &mac_info,\n+\t\t\t\t     sizeof(mac_info), &mac_info, &out_size);\n+\tif (err || !out_size || (mac_info.msg_head.status &&\n+\t    mac_info.msg_head.status != SPNIC_PF_SET_VF_ALREADY)) {\n+\t\tPMD_DRV_LOG(ERR, \"Delete MAC failed, err: %d, status: 0x%x, out size: 0x%x\",\n+\t\t\t    err, mac_info.msg_head.status, out_size);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (mac_info.msg_head.status == SPNIC_PF_SET_VF_ALREADY) {\n+\t\tPMD_DRV_LOG(WARNING, \"PF has already set VF mac, Ignore delete operation\");\n+\t\treturn SPNIC_PF_SET_VF_ALREADY;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int spnic_update_mac(void *hwdev, u8 *old_mac, u8 *new_mac, u16 vlan_id,\n+\t\t     u16 func_id)\n+{\n+\tstruct spnic_port_mac_update mac_info;\n+\tu16 out_size = sizeof(mac_info);\n+\tint err;\n+\n+\tif (!hwdev || !old_mac || !new_mac)\n+\t\treturn -EINVAL;\n+\n+\tif (vlan_id >= VLAN_N_VID) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid VLAN number: %d\", vlan_id);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmemset(&mac_info, 0, sizeof(mac_info));\n+\tmac_info.func_id = func_id;\n+\tmac_info.vlan_id = vlan_id;\n+\tmemcpy(mac_info.old_mac, old_mac, ETH_ALEN);\n+\tmemcpy(mac_info.new_mac, new_mac, ETH_ALEN);\n+\n+\terr = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_UPDATE_MAC, &mac_info,\n+\t\t\t\t     sizeof(mac_info), &mac_info, &out_size);\n+\tif (err || !out_size ||\n+\t    spnic_check_mac_info(mac_info.msg_head.status, mac_info.vlan_id)) {\n+\t\tPMD_DRV_LOG(ERR, \"Update MAC failed, err: %d, status: 0x%x, out size: 0x%x\",\n+\t\t\t    err, mac_info.msg_head.status, out_size);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (mac_info.msg_head.status == SPNIC_PF_SET_VF_ALREADY) {\n+\t\tPMD_DRV_LOG(WARNING, \"PF has already set VF MAC. Ignore update operation\");\n+\t\treturn SPNIC_PF_SET_VF_ALREADY;\n+\t}\n+\n+\tif (mac_info.msg_head.status == SPNIC_MGMT_STATUS_EXIST) {\n+\t\tPMD_DRV_LOG(INFO, \"MAC is repeated. Ignore update operation\");\n+\t\treturn 0;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int spnic_get_default_mac(void *hwdev, u8 *mac_addr, int ether_len)\n+{\n+\tstruct spnic_port_mac_set mac_info;\n+\tu16 out_size = sizeof(mac_info);\n+\tint err;\n+\n+\tif (!hwdev || !mac_addr)\n+\t\treturn -EINVAL;\n+\n+\tmemset(&mac_info, 0, sizeof(mac_info));\n+\tmac_info.func_id = spnic_global_func_id(hwdev);\n+\n+\terr = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_GET_MAC,\n+\t\t\t\t     &mac_info, sizeof(mac_info),\n+\t\t&mac_info, &out_size);\n+\tif (err || !out_size || mac_info.msg_head.status) {\n+\t\tPMD_DRV_LOG(ERR, \"Get MAC failed, err: %d, status: 0x%x, out size: 0x%x\",\n+\t\t\t    err, mac_info.msg_head.status, out_size);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmemmove(mac_addr, mac_info.mac, ether_len);\n+\n+\treturn 0;\n+}\n+\n+int spnic_get_port_info(void *hwdev, struct nic_port_info *port_info)\n+{\n+\tstruct spnic_cmd_port_info port_msg;\n+\tu16 out_size = sizeof(port_msg);\n+\tint err;\n+\n+\tif (!hwdev || !port_info)\n+\t\treturn -EINVAL;\n+\n+\tmemset(&port_msg, 0, sizeof(port_msg));\n+\tport_msg.port_id = spnic_physical_port_id(hwdev);\n+\n+\terr = mag_msg_to_mgmt_sync(hwdev, MAG_CMD_GET_PORT_INFO, &port_msg,\n+\t\t\t\t   sizeof(port_msg), &port_msg, &out_size);\n+\tif (err || !out_size || port_msg.msg_head.status) {\n+\t\tPMD_DRV_LOG(ERR, \"Get port info failed, err: %d, status: 0x%x, out size: 0x%x\",\n+\t\t\t    err, port_msg.msg_head.status, out_size);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tport_info->autoneg_cap = port_msg.autoneg_cap;\n+\tport_info->autoneg_state = port_msg.autoneg_state;\n+\tport_info->duplex = port_msg.duplex;\n+\tport_info->port_type = port_msg.port_type;\n+\tport_info->speed = port_msg.speed;\n+\tport_info->fec = port_msg.fec;\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+{\n+\tu32 i, cmd_cnt = ARRAY_LEN(vf_mag_cmd_handler);\n+\n+\tif (spnic_func_type(hwdev) == TYPE_VF) {\n+\t\tfor (i = 0; i < cmd_cnt; i++) {\n+\t\t\tif (cmd == vf_mag_cmd_handler[i].cmd)\n+\t\t\t\treturn spnic_mbox_to_pf(hwdev, SPNIC_MOD_HILINK,\n+\t\t\t\t\t\t\tcmd, buf_in, in_size,\n+\t\t\t\t\t\t\tbuf_out, out_size, 0);\n+\t\t}\n+\t}\n+\n+\treturn spnic_msg_to_mgmt_sync(hwdev, SPNIC_MOD_HILINK, cmd, buf_in,\n+\t\t\t\t      in_size, buf_out, out_size, 0);\n+}\n+\n+static int mag_msg_to_mgmt_sync(void *hwdev, u16 cmd, void *buf_in, u16 in_size,\n+\t\t\t\tvoid *buf_out, u16 *out_size)\n+{\n+\treturn _mag_msg_to_mgmt_sync(hwdev, cmd, buf_in, in_size, buf_out,\n+\t\t\t\t     out_size);\n+}\ndiff --git a/drivers/net/spnic/base/spnic_nic_cfg.h b/drivers/net/spnic/base/spnic_nic_cfg.h\nnew file mode 100644\nindex 0000000000..669e982876\n--- /dev/null\n+++ b/drivers/net/spnic/base/spnic_nic_cfg.h\n@@ -0,0 +1,180 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd\n+ */\n+\n+#ifndef _SPNIC_NIC_CFG_H_\n+#define _SPNIC_NIC_CFG_H_\n+\n+#ifndef ETH_ALEN\n+#define ETH_ALEN\t\t\t6\n+#endif\n+\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_PF_SET_VF_ALREADY\t\t0x4\n+#define SPNIC_MGMT_STATUS_EXIST\t\t0x6\n+#define CHECK_IPSU_15BIT\t\t0x8000\n+\n+/* Structures for port info */\n+struct nic_port_info {\n+\tu8 port_type;\n+\tu8 autoneg_cap;\n+\tu8 autoneg_state;\n+\tu8 duplex;\n+\tu8 speed;\n+\tu8 fec;\n+};\n+\n+enum spnic_link_status {\n+\tSPNIC_LINK_DOWN = 0,\n+\tSPNIC_LINK_UP\n+};\n+\n+enum nic_media_type {\n+\tMEDIA_UNKNOWN = -1,\n+\tMEDIA_FIBRE = 0,\n+\tMEDIA_COPPER,\n+\tMEDIA_BACKPLANE\n+};\n+\n+enum nic_speed_level {\n+\tLINK_SPEED_10MB = 0,\n+\tLINK_SPEED_100MB,\n+\tLINK_SPEED_1GB,\n+\tLINK_SPEED_10GB,\n+\tLINK_SPEED_25GB,\n+\tLINK_SPEED_40GB,\n+\tLINK_SPEED_100GB,\n+\tLINK_SPEED_LEVELS,\n+};\n+\n+struct spnic_port_mac_set {\n+\tstruct mgmt_msg_head msg_head;\n+\n+\tu16 func_id;\n+\tu16 vlan_id;\n+\tu16 rsvd1;\n+\tu8 mac[ETH_ALEN];\n+};\n+\n+struct spnic_port_mac_update {\n+\tstruct mgmt_msg_head msg_head;\n+\n+\tu16 func_id;\n+\tu16 vlan_id;\n+\tu16 rsvd1;\n+\tu8 old_mac[ETH_ALEN];\n+\tu16 rsvd2;\n+\tu8 new_mac[ETH_ALEN];\n+};\n+\n+struct spnic_cmd_port_info {\n+\tstruct mgmt_msg_head msg_head;\n+\n+\tu8 port_id;\n+\tu8 rsvd1[3];\n+\tu8 port_type;\n+\tu8 autoneg_cap;\n+\tu8 autoneg_state;\n+\tu8 duplex;\n+\tu8 speed;\n+\tu8 fec;\n+\tu16 rsvd2;\n+\tu32 rsvd3[4];\n+};\n+\n+struct spnic_cmd_link_state {\n+\tstruct mgmt_msg_head msg_head;\n+\n+\tu8 port_id;\n+\tu8 state;\n+\tu16 rsvd1;\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+/**\n+ * Update MAC address to hardware\n+ *\n+ * @param[in] hwdev\n+ *   Device pointer to hwdev\n+ * @param[in] old_mac\n+ *   Old MAC addr to delete\n+ * @param[in] new_mac\n+ *   New MAC addr to update\n+ * @param[in] vlan_id\n+ *   Vlan id\n+ * @param func_id\n+ *   Function index\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+int spnic_update_mac(void *hwdev, u8 *old_mac, u8 *new_mac, u16 vlan_id,\n+\t\t     u16 func_id);\n+\n+/**\n+ * Get the default mac address\n+ *\n+ * @param[in] hwdev\n+ *   Device pointer to hwdev\n+ * @param[in] mac_addr\n+ *   Mac address from hardware\n+ * @param[in] ether_len\n+ *   The length of mac address\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+int spnic_get_default_mac(void *hwdev, u8 *mac_addr, int ether_len);\n+\n+/**\n+ * Set mac address\n+ *\n+ * @param[in] hwdev\n+ *   Device pointer to hwdev\n+ * @param[in] mac_addr\n+ *   Mac address from hardware\n+ * @param[in] vlan_id\n+ *   Vlan id\n+ * @param[in] func_id\n+ *   Function index\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+int spnic_set_mac(void *hwdev, const u8 *mac_addr, u16 vlan_id, u16 func_id);\n+\n+/**\n+ * Delete MAC address\n+ *\n+ * @param[in] hwdev\n+ *   Device pointer to hwdev\n+ * @param[in] mac_addr\n+ *   MAC address from hardware\n+ * @param[in] vlan_id\n+ *   Vlan id\n+ * @param[in] func_id\n+ *   Function index\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+int spnic_del_mac(void *hwdev, const u8 *mac_addr, u16 vlan_id, u16 func_id);\n+\n+/**\n+ * Get port info\n+ *\n+ * @param[in] hwdev\n+ *   Device pointer to hwdev\n+ * @param[out] port_info\n+ *   Port info, including autoneg, port type, duplex, speed and fec mode\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+int spnic_get_port_info(void *hwdev, struct nic_port_info *port_info);\n+\n+#endif /* _SPNIC_NIC_CFG_H_ */\ndiff --git a/drivers/net/spnic/base/spnic_nic_event.c b/drivers/net/spnic/base/spnic_nic_event.c\nindex 07ea036d84..1c3621171a 100644\n--- a/drivers/net/spnic/base/spnic_nic_event.c\n+++ b/drivers/net/spnic/base/spnic_nic_event.c\n@@ -9,16 +9,39 @@\n #include \"spnic_hwif.h\"\n #include \"spnic_hwdev.h\"\n #include \"spnic_mgmt.h\"\n+#include \"spnic_nic_cfg.h\"\n #include \"spnic_hwdev.h\"\n #include \"spnic_nic_event.h\"\n \n-static void get_port_info(u8 link_state, struct rte_eth_link *link)\n+void get_port_info(struct spnic_hwdev *hwdev, u8 link_state,\n+\t\t   struct rte_eth_link *link)\n {\n+\tuint32_t port_speed[LINK_SPEED_LEVELS] = {ETH_SPEED_NUM_10M,\n+\t\t\t\t\tETH_SPEED_NUM_100M, ETH_SPEED_NUM_1G,\n+\t\t\t\t\tETH_SPEED_NUM_10G, ETH_SPEED_NUM_25G,\n+\t\t\t\t\tETH_SPEED_NUM_40G, ETH_SPEED_NUM_100G};\n+\tstruct nic_port_info port_info = {0};\n+\tint err;\n+\n \tif (!link_state) {\n \t\tlink->link_status = ETH_LINK_DOWN;\n \t\tlink->link_speed = ETH_SPEED_NUM_NONE;\n \t\tlink->link_duplex = ETH_LINK_HALF_DUPLEX;\n \t\tlink->link_autoneg = ETH_LINK_FIXED;\n+\t} else {\n+\t\tlink->link_status = ETH_LINK_UP;\n+\n+\t\terr = spnic_get_port_info(hwdev, &port_info);\n+\t\tif (err) {\n+\t\t\tlink->link_speed = ETH_SPEED_NUM_NONE;\n+\t\t\tlink->link_duplex = ETH_LINK_FULL_DUPLEX;\n+\t\t\tlink->link_autoneg = ETH_LINK_FIXED;\n+\t\t} else {\n+\t\t\tlink->link_speed = port_speed[port_info.speed %\n+\t\t\t\t\t\tLINK_SPEED_LEVELS];\n+\t\t\tlink->link_duplex = port_info.duplex;\n+\t\t\tlink->link_autoneg = port_info.autoneg_state;\n+\t\t}\n \t}\n }\n \n@@ -51,7 +74,7 @@ static void link_status_event_handler(void *hwdev, void *buf_in,\n \tspnic_link_event_stats(hwdev, link_status->state);\n \n \t/* Link event reported only after set vport enable */\n-\tget_port_info(link_status->state, &link);\n+\tget_port_info(dev, link_status->state, &link);\n \terr = rte_eth_linkstatus_set((struct rte_eth_dev *)(dev->eth_dev),\n \t\t\t\t     &link);\n \tif (!err)\ndiff --git a/drivers/net/spnic/base/spnic_nic_event.h b/drivers/net/spnic/base/spnic_nic_event.h\nindex eb41d76a7d..ac0c072887 100644\n--- a/drivers/net/spnic/base/spnic_nic_event.h\n+++ b/drivers/net/spnic/base/spnic_nic_event.h\n@@ -5,13 +5,8 @@\n #ifndef _SPNIC_NIC_EVENT_H_\n #define _SPNIC_NIC_EVENT_H_\n \n-struct spnic_cmd_link_state {\n-\tstruct mgmt_msg_head msg_head;\n-\n-\tu8 port_id;\n-\tu8 state;\n-\tu16 rsvd1;\n-};\n+void get_port_info(struct spnic_hwdev *hwdev, u8 link_state,\n+\t\t   struct rte_eth_link *link);\n \n void spnic_pf_event_handler(void *hwdev, __rte_unused void *pri_handle,\n \t\t\t    u16 cmd, void *buf_in, u16 in_size,\ndiff --git a/drivers/net/spnic/spnic_ethdev.c b/drivers/net/spnic/spnic_ethdev.c\nindex 228ed0c936..8f71280fa7 100644\n--- a/drivers/net/spnic/spnic_ethdev.c\n+++ b/drivers/net/spnic/spnic_ethdev.c\n@@ -5,14 +5,23 @@\n #include <rte_pci.h>\n #include <rte_bus_pci.h>\n #include <ethdev_pci.h>\n+#include <rte_malloc.h>\n #include <rte_errno.h>\n #include <rte_ether.h>\n \n #include \"base/spnic_compat.h\"\n+#include \"base/spnic_cmd.h\"\n #include \"base/spnic_csr.h\"\n+#include \"base/spnic_wq.h\"\n+#include \"base/spnic_eqs.h\"\n+#include \"base/spnic_mgmt.h\"\n+#include \"base/spnic_cmdq.h\"\n #include \"base/spnic_hwdev.h\"\n #include \"base/spnic_hwif.h\"\n-\n+#include \"base/spnic_hw_cfg.h\"\n+#include \"base/spnic_hw_comm.h\"\n+#include \"base/spnic_nic_cfg.h\"\n+#include \"base/spnic_nic_event.h\"\n #include \"spnic_ethdev.h\"\n \n /* Driver-specific log messages type */\n@@ -21,6 +30,58 @@ 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+\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+ * Deinit mac_vlan table in hardware.\n+ *\n+ * @param[in] eth_dev\n+ *   Pointer to ethernet device structure.\n+ */\n+static void spnic_deinit_mac_addr(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct spnic_nic_dev *nic_dev =\n+\t\t\t\tSPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);\n+\tu16 func_id = 0;\n+\tint err;\n+\tint i;\n+\n+\tfunc_id = spnic_global_func_id(nic_dev->hwdev);\n+\n+\tfor (i = 0; i < SPNIC_MAX_UC_MAC_ADDRS; i++) {\n+\t\tif (rte_is_zero_ether_addr(&eth_dev->data->mac_addrs[i]))\n+\t\t\tcontinue;\n+\n+\t\terr = spnic_del_mac(nic_dev->hwdev,\n+\t\t\t\t    eth_dev->data->mac_addrs[i].addr_bytes,\n+\t\t\t\t    0, func_id);\n+\t\tif (err && err != SPNIC_PF_SET_VF_ALREADY)\n+\t\t\tPMD_DRV_LOG(ERR, \"Delete mac table failed, dev_name: %s\",\n+\t\t\t\t    eth_dev->data->name);\n+\n+\t\tmemset(&eth_dev->data->mac_addrs[i], 0,\n+\t\t       sizeof(struct rte_ether_addr));\n+\t}\n+\n+\t/* Delete multicast mac addrs */\n+\tspnic_delete_mc_addr_list(nic_dev);\n+}\n+\n /**\n  * Close the device.\n  *\n@@ -38,13 +99,247 @@ static int spnic_dev_close(struct rte_eth_dev *eth_dev)\n \t\treturn 0;\n \t}\n \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 \tspnic_free_hwdev(nic_dev->hwdev);\n \n+\teth_dev->dev_ops = NULL;\n+\n \trte_free(nic_dev->hwdev);\n \tnic_dev->hwdev = NULL;\n \n \treturn 0;\n }\n+/**\n+ * Update MAC address\n+ *\n+ * @param[in] dev\n+ *   Pointer to ethernet device structure.\n+ * @param[in] addr\n+ *   Pointer to MAC address\n+ *\n+ * @retval zero: Success\n+ * @retval non-zero: Failure\n+ */\n+static int spnic_set_mac_addr(struct rte_eth_dev *dev,\n+\t\t\t      struct rte_ether_addr *addr)\n+{\n+\tstruct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);\n+\tchar mac_addr[RTE_ETHER_ADDR_FMT_SIZE];\n+\tu16 func_id;\n+\tint err;\n+\n+\tif (!rte_is_valid_assigned_ether_addr(addr)) {\n+\t\trte_ether_format_addr(mac_addr, RTE_ETHER_ADDR_FMT_SIZE, addr);\n+\t\tPMD_DRV_LOG(ERR, \"Set invalid MAC address %s\", mac_addr);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tfunc_id = spnic_global_func_id(nic_dev->hwdev);\n+\terr = spnic_update_mac(nic_dev->hwdev,\n+\t\t\t\tnic_dev->default_addr.addr_bytes,\n+\t\t\t\taddr->addr_bytes, 0, func_id);\n+\tif (err)\n+\t\treturn err;\n+\n+\trte_ether_addr_copy(addr, &nic_dev->default_addr);\n+\trte_ether_format_addr(mac_addr, RTE_ETHER_ADDR_FMT_SIZE,\n+\t\t\t      &nic_dev->default_addr);\n+\n+\tPMD_DRV_LOG(INFO, \"Set new MAC address %s\", mac_addr);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Remove a MAC address.\n+ *\n+ * @param[in] dev\n+ *   Pointer to ethernet device structure.\n+ * @param[in] index\n+ *   MAC address index.\n+ */\n+static void spnic_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)\n+{\n+\tstruct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);\n+\tu16 func_id;\n+\tint err;\n+\n+\tif (index >= SPNIC_MAX_UC_MAC_ADDRS) {\n+\t\tPMD_DRV_LOG(INFO, \"Remove MAC index(%u) is out of range\",\n+\t\t\t    index);\n+\t\treturn;\n+\t}\n+\n+\tfunc_id = spnic_global_func_id(nic_dev->hwdev);\n+\terr = spnic_del_mac(nic_dev->hwdev,\n+\t\t\t     dev->data->mac_addrs[index].addr_bytes,\n+\t\t\t     0, func_id);\n+\tif (err)\n+\t\tPMD_DRV_LOG(ERR, \"Remove MAC index(%u) failed\", index);\n+}\n+\n+/**\n+ * Add a MAC address.\n+ *\n+ * @param[in] dev\n+ *   Pointer to ethernet device structure.\n+ * @param[in] mac_addr\n+ *   MAC address to register.\n+ * @param[in] index\n+ *   MAC address index.\n+ * @param[in] vmdq\n+ *   VMDq pool index to associate address with (unused_).\n+ *\n+ * @retval zero: Success\n+ * @retval non-zero: Failure\n+ */\n+static int spnic_mac_addr_add(struct rte_eth_dev *dev,\n+\t\t\t      struct rte_ether_addr *mac_addr, uint32_t index,\n+\t\t\t      __rte_unused uint32_t vmdq)\n+{\n+\tstruct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);\n+\tunsigned int i;\n+\tu16 func_id;\n+\tint err;\n+\n+\tif (!rte_is_valid_assigned_ether_addr(mac_addr)) {\n+\t\tPMD_DRV_LOG(ERR, \"Add invalid MAC address\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (index >= SPNIC_MAX_UC_MAC_ADDRS) {\n+\t\tPMD_DRV_LOG(ERR, \"Add MAC index(%u) is out of range\", index);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* Make sure this address doesn't already be configured */\n+\tfor (i = 0; i < SPNIC_MAX_UC_MAC_ADDRS; i++) {\n+\t\tif (rte_is_same_ether_addr(mac_addr,\n+\t\t\t&dev->data->mac_addrs[i])) {\n+\t\t\tPMD_DRV_LOG(ERR, \"MAC address is already configured\");\n+\t\t\treturn -EADDRINUSE;\n+\t\t}\n+\t}\n+\n+\tfunc_id = spnic_global_func_id(nic_dev->hwdev);\n+\terr = spnic_set_mac(nic_dev->hwdev, mac_addr->addr_bytes, 0, func_id);\n+\tif (err)\n+\t\treturn err;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Set multicast MAC address\n+ *\n+ * @param[in] dev\n+ *   Pointer to ethernet device structure.\n+ * @param[in] mc_addr_set\n+ *   Pointer to multicast MAC address\n+ * @param[in] nb_mc_addr\n+ *   The number of multicast MAC address to set\n+ *\n+ * @retval zero: Success\n+ * @retval non-zero: Failure\n+ */\n+static int spnic_set_mc_addr_list(struct rte_eth_dev *dev,\n+\t\t\t\t  struct rte_ether_addr *mc_addr_set,\n+\t\t\t\t  uint32_t nb_mc_addr)\n+{\n+\tstruct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);\n+\tchar mac_addr[RTE_ETHER_ADDR_FMT_SIZE];\n+\tu16 func_id;\n+\tint err;\n+\tu32 i;\n+\n+\tfunc_id = spnic_global_func_id(nic_dev->hwdev);\n+\n+\t/* Delete old multi_cast addrs firstly */\n+\tspnic_delete_mc_addr_list(nic_dev);\n+\n+\tif (nb_mc_addr > SPNIC_MAX_MC_MAC_ADDRS)\n+\t\treturn -EINVAL;\n+\n+\tfor (i = 0; i < nb_mc_addr; i++) {\n+\t\tif (!rte_is_multicast_ether_addr(&mc_addr_set[i])) {\n+\t\t\trte_ether_format_addr(mac_addr, RTE_ETHER_ADDR_FMT_SIZE,\n+\t\t\t\t\t      &mc_addr_set[i]);\n+\t\t\tPMD_DRV_LOG(ERR, \"Set mc MAC addr failed, addr(%s) invalid\",\n+\t\t\t\t    mac_addr);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < nb_mc_addr; i++) {\n+\t\terr = spnic_set_mac(nic_dev->hwdev, mc_addr_set[i].addr_bytes,\n+\t\t\t\t    0, func_id);\n+\t\tif (err) {\n+\t\t\tspnic_delete_mc_addr_list(nic_dev);\n+\t\t\treturn err;\n+\t\t}\n+\n+\t\trte_ether_addr_copy(&mc_addr_set[i], &nic_dev->mc_list[i]);\n+\t}\n+\n+\treturn 0;\n+}\n+static const struct eth_dev_ops spnic_pmd_ops = {\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+\t.set_mc_addr_list              = spnic_set_mc_addr_list,\n+};\n+\n+static const struct eth_dev_ops spnic_pmd_vf_ops = {\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+\t.set_mc_addr_list              = spnic_set_mc_addr_list,\n+};\n+\n+/**\n+ * Init mac_vlan table in hardwares.\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_init_mac_table(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct spnic_nic_dev *nic_dev =\n+\t\tSPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);\n+\tu8 addr_bytes[RTE_ETHER_ADDR_LEN];\n+\tu16 func_id = 0;\n+\tint err = 0;\n+\n+\terr = spnic_get_default_mac(nic_dev->hwdev, addr_bytes,\n+\t\t\t\t     RTE_ETHER_ADDR_LEN);\n+\tif (err)\n+\t\treturn err;\n+\n+\trte_ether_addr_copy((struct rte_ether_addr *)addr_bytes,\n+\t\t\t    &eth_dev->data->mac_addrs[0]);\n+\tif (rte_is_zero_ether_addr(&eth_dev->data->mac_addrs[0]))\n+\t\trte_eth_random_addr(eth_dev->data->mac_addrs[0].addr_bytes);\n+\n+\tfunc_id = spnic_global_func_id(nic_dev->hwdev);\n+\terr = spnic_set_mac(nic_dev->hwdev,\n+\t\t\t    eth_dev->data->mac_addrs[0].addr_bytes,\n+\t\t\t    0, func_id);\n+\tif (err && err != SPNIC_PF_SET_VF_ALREADY)\n+\t\treturn err;\n+\n+\trte_ether_addr_copy(&eth_dev->data->mac_addrs[0],\n+\t\t\t    &nic_dev->default_addr);\n+\n+\treturn 0;\n+}\n \n static int spnic_func_init(struct rte_eth_dev *eth_dev)\n {\n@@ -63,11 +358,37 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev)\n \t}\n \n \tnic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);\n+\tmemset(nic_dev, 0, sizeof(*nic_dev));\n \tsnprintf(nic_dev->dev_name, sizeof(nic_dev->dev_name),\n \t\t \"spnic-%.4x:%.2x:%.2x.%x\",\n \t\t pci_dev->addr.domain, pci_dev->addr.bus,\n \t\t pci_dev->addr.devid, pci_dev->addr.function);\n \n+\t/* Alloc mac_addrs */\n+\teth_dev->data->mac_addrs = rte_zmalloc(\"spnic_mac\",\n+\t\tSPNIC_MAX_UC_MAC_ADDRS * sizeof(struct rte_ether_addr), 0);\n+\tif (!eth_dev->data->mac_addrs) {\n+\t\tPMD_DRV_LOG(ERR, \"Allocate %zx bytes to store MAC addresses \"\n+\t\t\t    \"failed, dev_name: %s\",\n+\t\t\t    SPNIC_MAX_UC_MAC_ADDRS *\n+\t\t\t    sizeof(struct rte_ether_addr),\n+\t\t\t    eth_dev->data->name);\n+\t\terr = -ENOMEM;\n+\t\tgoto alloc_eth_addr_fail;\n+\t}\n+\n+\tnic_dev->mc_list = rte_zmalloc(\"spnic_mc\",\n+\t\tSPNIC_MAX_MC_MAC_ADDRS * sizeof(struct rte_ether_addr), 0);\n+\tif (!nic_dev->mc_list) {\n+\t\tPMD_DRV_LOG(ERR, \"Allocate %zx bytes to store multicast \"\n+\t\t\t    \"addresses failed, dev_name: %s\",\n+\t\t\t    SPNIC_MAX_MC_MAC_ADDRS *\n+\t\t\t    sizeof(struct rte_ether_addr),\n+\t\t\t    eth_dev->data->name);\n+\t\terr = -ENOMEM;\n+\t\tgoto alloc_mc_list_fail;\n+\t}\n+\n \teth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;\n \t/* Create hardware device */\n \tnic_dev->hwdev = rte_zmalloc(\"spnic_hwdev\", sizeof(*nic_dev->hwdev),\n@@ -90,17 +411,42 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev)\n \t\tgoto init_hwdev_fail;\n \t}\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+\terr = spnic_init_mac_table(eth_dev);\n+\tif (err) {\n+\t\tPMD_DRV_LOG(ERR, \"Init mac table failed, dev_name: %s\",\n+\t\t\t    eth_dev->data->name);\n+\t\tgoto init_mac_table_fail;\n+\t}\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 \tPMD_DRV_LOG(INFO, \"Initialize %s in primary succeed\",\n \t\t    eth_dev->data->name);\n \n \treturn 0;\n \n+init_mac_table_fail:\n+\tspnic_free_hwdev(nic_dev->hwdev);\n+\teth_dev->dev_ops = NULL;\n+\n init_hwdev_fail:\n \trte_free(nic_dev->hwdev);\n \tnic_dev->hwdev = NULL;\n \n alloc_hwdev_mem_fail:\n+\trte_free(nic_dev->mc_list);\n+\tnic_dev->mc_list = NULL;\n+\n+alloc_mc_list_fail:\n+\trte_free(eth_dev->data->mac_addrs);\n+\teth_dev->data->mac_addrs = NULL;\n+\n+alloc_eth_addr_fail:\n \tPMD_DRV_LOG(ERR, \"Initialize %s in primary failed\",\n \t\t    eth_dev->data->name);\n \treturn err;\n",
    "prefixes": [
        "v1",
        "09/25"
    ]
}