* [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support
@ 2020-03-09 14:14 Haiyue Wang
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
` (9 more replies)
0 siblings, 10 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-09 14:14 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A DCF (Device Config Function) based approach is proposed where a device
bound to the device's VF0 can act as a sole controlling entity to exercise
advance functionality (such as switch, ACL) for rest of the VFs.
The DCF works as a standalone PMD to support this function, which shares the
ice PMD flow control core function and the iavf virtchnl mailbox core module.
This patchset is based on:
[1] https://patchwork.dpdk.org/cover/66417/ update ice base code
And it needs the coming iavf common lib update to compile, the modified
ice flow function to work.
Haiyue Wang (4):
net/iavf: stop the PCI probe in DCF mode
net/ice: export the DDP definition symbols
net/ice: add the DCF framework
doc: add release notes for Intel ice PMD
doc/guides/nics/ice.rst | 47 ++
doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
doc/guides/rel_notes/release_20_05.rst | 5 +
drivers/common/Makefile | 1 +
drivers/net/iavf/iavf_ethdev.c | 41 ++
drivers/net/ice/Makefile | 6 +
drivers/net/ice/ice_dcf.c | 651 +++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 61 +++
drivers/net/ice/ice_dcf_ethdev.c | 319 ++++++++++++
drivers/net/ice/ice_dcf_ethdev.h | 33 ++
drivers/net/ice/ice_dcf_parent.c | 348 +++++++++++++
drivers/net/ice/ice_ethdev.c | 9 +-
drivers/net/ice/ice_ethdev.h | 8 +
drivers/net/ice/meson.build | 8 +-
mk/rte.app.mk | 1 +
15 files changed, 1528 insertions(+), 10 deletions(-)
create mode 100644 doc/guides/nics/img/ice_dcf.png
create mode 100644 drivers/net/ice/ice_dcf.c
create mode 100644 drivers/net/ice/ice_dcf.h
create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
create mode 100644 drivers/net/ice/ice_dcf_parent.c
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode
2020-03-09 14:14 [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support Haiyue Wang
@ 2020-03-09 14:14 ` Haiyue Wang
2020-03-09 15:38 ` Ye Xiaolong
2020-03-23 1:50 ` Wu, Jingjing
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 2/4] net/ice: export the DDP definition symbols Haiyue Wang
` (8 subsequent siblings)
9 siblings, 2 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-09 14:14 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A new DCF PMD will be introduced, which runs on Intel VF hardware, and
it is a pure software design to control the advance functionality (such
as switch, ACL) for rest of the VFs.
So if the DCF (Device Config Function) mode is specified by the devarg
'cap=dcf', then it will stop the PCI probe in the iavf PMD.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/iavf/iavf_ethdev.c | 41 ++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 34913f9c4..8ff26c0e7 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -1416,9 +1416,49 @@ iavf_dev_uninit(struct rte_eth_dev *dev)
return 0;
}
+static int
+handle_dcf_arg(__rte_unused const char *key, const char *value,
+ __rte_unused void *arg)
+{
+ bool *dcf = arg;
+
+ if (arg == NULL || value == NULL)
+ return -EINVAL;
+
+ if (strcmp(value, "dcf") == 0)
+ *dcf = true;
+ else
+ *dcf = false;
+
+ return 0;
+}
+
+static bool
+check_cap_dcf_enable(struct rte_devargs *devargs)
+{
+ struct rte_kvargs *kvlist;
+ bool enable = false;
+
+ if (devargs == NULL)
+ return false;
+
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
+ if (kvlist == NULL)
+ return false;
+
+ rte_kvargs_process(kvlist, "cap", handle_dcf_arg, &enable);
+
+ rte_kvargs_free(kvlist);
+
+ return enable;
+}
+
static int eth_iavf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
struct rte_pci_device *pci_dev)
{
+ if (check_cap_dcf_enable(pci_dev->device.devargs))
+ return 1; /* continue to probe */
+
return rte_eth_dev_pci_generic_probe(pci_dev,
sizeof(struct iavf_adapter), iavf_dev_init);
}
@@ -1439,6 +1479,7 @@ static struct rte_pci_driver rte_iavf_pmd = {
RTE_PMD_REGISTER_PCI(net_iavf, rte_iavf_pmd);
RTE_PMD_REGISTER_PCI_TABLE(net_iavf, pci_id_iavf_map);
RTE_PMD_REGISTER_KMOD_DEP(net_iavf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_iavf, "cap=dcf");
RTE_INIT(iavf_init_log)
{
iavf_logtype_init = rte_log_register("pmd.net.iavf.init");
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v1 2/4] net/ice: export the DDP definition symbols
2020-03-09 14:14 [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support Haiyue Wang
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
@ 2020-03-09 14:14 ` Haiyue Wang
2020-03-09 16:25 ` Ye Xiaolong
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 3/4] net/ice: add the DCF framework Haiyue Wang
` (7 subsequent siblings)
9 siblings, 1 reply; 94+ messages in thread
From: Haiyue Wang @ 2020-03-09 14:14 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A new DCF PMD will be introduced, which runs on Intel VF hardware, and
it is a pure software design to control the advance functionality (such
as switch, ACL) for rest of the VFs.
The DCF (Device Config Function) feature shares the core functions of
the ICE PMD, like it needs to export the DDP definition symbols for the
new DCF PMD use.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/ice/ice_ethdev.c | 9 +--------
drivers/net/ice/ice_ethdev.h | 8 ++++++++
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c
index b42deb0bc..8b9d211b0 100644
--- a/drivers/net/ice/ice_ethdev.c
+++ b/drivers/net/ice/ice_ethdev.c
@@ -67,15 +67,8 @@ static struct proto_xtr_ol_flag ice_proto_xtr_ol_flag_params[] = {
#define ICE_DFLT_OUTER_TAG_TYPE ICE_AQ_VSI_OUTER_TAG_VLAN_9100
-/* DDP package search path */
-#define ICE_PKG_FILE_DEFAULT "/lib/firmware/intel/ice/ddp/ice.pkg"
-#define ICE_PKG_FILE_UPDATES "/lib/firmware/updates/intel/ice/ddp/ice.pkg"
-#define ICE_PKG_FILE_SEARCH_PATH_DEFAULT "/lib/firmware/intel/ice/ddp/"
-#define ICE_PKG_FILE_SEARCH_PATH_UPDATES "/lib/firmware/updates/intel/ice/ddp/"
-
#define ICE_OS_DEFAULT_PKG_NAME "ICE OS Default Package"
#define ICE_COMMS_PKG_NAME "ICE COMMS Package"
-#define ICE_MAX_PKG_FILENAME_SIZE 256
#define ICE_MAX_RES_DESC_NUM 1024
int ice_logtype_init;
@@ -1833,7 +1826,7 @@ ice_pkg_file_search_path(struct rte_pci_device *pci_dev, char *pkg_file)
return 0;
}
-static enum ice_pkg_type
+enum ice_pkg_type
ice_load_pkg_type(struct ice_hw *hw)
{
enum ice_pkg_type package_type;
diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h
index da557a254..7b94a3c3e 100644
--- a/drivers/net/ice/ice_ethdev.h
+++ b/drivers/net/ice/ice_ethdev.h
@@ -42,6 +42,13 @@
#define ICE_MAX_PKT_TYPE 1024
+/* DDP package search path */
+#define ICE_PKG_FILE_DEFAULT "/lib/firmware/intel/ice/ddp/ice.pkg"
+#define ICE_PKG_FILE_UPDATES "/lib/firmware/updates/intel/ice/ddp/ice.pkg"
+#define ICE_PKG_FILE_SEARCH_PATH_DEFAULT "/lib/firmware/intel/ice/ddp/"
+#define ICE_PKG_FILE_SEARCH_PATH_UPDATES "/lib/firmware/updates/intel/ice/ddp/"
+#define ICE_MAX_PKG_FILENAME_SIZE 256
+
/**
* vlan_id is a 12 bit number.
* The VFTA array is actually a 4096 bit array, 128 of 32bit elements.
@@ -457,6 +464,7 @@ struct ice_vsi_vlan_pvid_info {
#define ICE_PF_TO_ETH_DEV(pf) \
(((struct ice_pf *)pf)->adapter->eth_dev)
+enum ice_pkg_type ice_load_pkg_type(struct ice_hw *hw);
struct ice_vsi *
ice_setup_vsi(struct ice_pf *pf, enum ice_vsi_type type);
int
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v1 3/4] net/ice: add the DCF framework
2020-03-09 14:14 [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support Haiyue Wang
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 2/4] net/ice: export the DDP definition symbols Haiyue Wang
@ 2020-03-09 14:14 ` Haiyue Wang
2020-03-10 4:17 ` Ye Xiaolong
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 4/4] doc: add release notes for Intel ice PMD Haiyue Wang
` (6 subsequent siblings)
9 siblings, 1 reply; 94+ messages in thread
From: Haiyue Wang @ 2020-03-09 14:14 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) feature works as a standalone PMD, its
hardware entity is the trusted VF with ID 0, and the software function
is to control the flow setting of other VFs by the mailbox with PF.
It doesn't handle packet Rx/Tx related things. This PMD needs the iAVF
virtchnl to send the ICE PF's AdminQ command.
Also for security, it needs to acquire the DCF capability from PF. The
flow related things will be added later, it shares most of the ICE flow
function. This mainly handles hardware initialization etc.
.-------------.
.-| |
.-| | |
| | | iAVF PMD |
| | | |
| | | |
| | '-------------'
| '-------------'
'-------------'
^ Other VFs
/
/ Flow Distribution
.------------------. /
| |/ DCF cap req .-------------.
| CVL . <---------- | |
| Kernel | ----------> | |
. . DCF cap rsp | DCF PMD |
| | | |
'------------------' <----------- | |
rte_flow '-------------'
VF0
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
doc/guides/nics/ice.rst | 47 +++
doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
drivers/common/Makefile | 1 +
drivers/net/ice/Makefile | 6 +
drivers/net/ice/ice_dcf.c | 651 +++++++++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 61 +++
drivers/net/ice/ice_dcf_ethdev.c | 319 +++++++++++++++
drivers/net/ice/ice_dcf_ethdev.h | 33 ++
drivers/net/ice/ice_dcf_parent.c | 348 +++++++++++++++++
drivers/net/ice/meson.build | 8 +-
mk/rte.app.mk | 1 +
11 files changed, 1473 insertions(+), 2 deletions(-)
create mode 100644 doc/guides/nics/img/ice_dcf.png
create mode 100644 drivers/net/ice/ice_dcf.c
create mode 100644 drivers/net/ice/ice_dcf.h
create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
create mode 100644 drivers/net/ice/ice_dcf_parent.c
diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 8af32dabf..2639ae239 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -240,6 +240,53 @@ report a MDD event and drop the packets.
The APPs based on DPDK should avoid providing such packets.
+Device Config Function (DCF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section demonstrates ICE DCF PMD, which shares the core module with ICE
+PMD and iAVF PMD.
+
+A DCF (Device Config Function) PMD bounds to the device's trusted VF with ID 0,
+it can act as a sole controlling entity to exercise advance functionality (such
+as switch, ACL) for the rest VFs.
+
+The DCF PMD needs to advertise and acquire DCF capability which allows DCF to
+send AdminQ commands that it would like to execute over to the PF and receive
+responses for the same from PF.
+
+.. _figure_ice_dcf:
+
+.. figure:: img/ice_dcf.*
+
+ DCF Communication flow.
+
+#. Create the VFs::
+
+ echo 4 > /sys/bus/pci/devices/0000\:18\:00.0/sriov_numvfs
+
+#. Enable the VF0 trust on::
+
+ ip link set dev enp24s0f0 vf 0 trust on
+
+#. Bind the VF0, and run testpmd with 'cap=dcf' devarg::
+
+ testpmd -l 22-25 -n 4 -w 18:01.0,cap=dcf -- -i
+
+#. Monitor the VF2 interface network traffic::
+
+ tcpdump -e -nn -i enp24s1f2
+
+#. Create one flow to redirect the traffic to VF2 by DCF::
+
+ flow create 0 priority 0 ingress pattern eth / ipv4 src is 192.168.0.2 \
+ dst is 192.168.0.3 / end actions vf id 2 / end
+
+#. Send the packet, and it should be displayed on tcpdump::
+
+ sendp(Ether(src='3c:fd:fe:aa:bb:78', dst='00:00:00:01:02:03')/IP(src=' \
+ 192.168.0.2', dst="192.168.0.3")/TCP(flags='S')/Raw(load='XXXXXXXXXX'), \
+ iface="enp24s0f0", count=10)
+
Sample Application Notes
------------------------
diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
new file mode 100644
index 0000000000000000000000000000000000000000..540823c4a05e9ea9d558d233fea77016d1ae5df3
GIT binary patch
literal 39168
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
literal 0
HcmV?d00001
diff --git a/drivers/common/Makefile b/drivers/common/Makefile
index 96bd7ac6e..df2e840cf 100644
--- a/drivers/common/Makefile
+++ b/drivers/common/Makefile
@@ -31,6 +31,7 @@ DIRS-y += dpaax
endif
IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
ifneq (,$(findstring y,$(IAVF-y)))
DIRS-y += iavf
endif
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index e22c34287..643639a50 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -11,9 +11,11 @@ LIB = librte_pmd_ice.a
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
+LDLIBS += -lrte_net -lrte_common_iavf
EXPORT_MAP := rte_pmd_ice_version.map
@@ -84,6 +86,10 @@ ifeq ($(CC_AVX2_SUPPORT), 1)
endif
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_parent.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+
# install this header file
SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
new file mode 100644
index 000000000..669122331
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.c
@@ -0,0 +1,651 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include "ice_dcf.h"
+
+#define ICE_DCF_AQ_LEN 32
+#define ICE_DCF_AQ_BUF_SZ 4096
+
+#define ICE_DCF_ARQ_MAX_RETRIES 200
+#define ICE_DCF_ARQ_CHECK_TIME 2 /* msecs */
+
+#define ICE_DCF_VF_RES_BUF_SZ \
+ (sizeof(struct virtchnl_vf_resource) + \
+ IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource))
+
+static __rte_always_inline int
+ice_dcf_send_cmd_req_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+ uint8_t *req_msg, uint16_t req_msglen)
+{
+ return iavf_aq_send_msg_to_pf(&hw->avf, op, IAVF_SUCCESS,
+ req_msg, req_msglen, NULL);
+}
+
+static int
+ice_dcf_recv_cmd_rsp_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+ uint8_t *rsp_msgbuf, uint16_t rsp_buflen,
+ uint16_t *rsp_msglen)
+{
+ struct iavf_arq_event_info event;
+ enum virtchnl_ops v_op;
+ int i = 0;
+ int err;
+
+ event.buf_len = rsp_buflen;
+ event.msg_buf = rsp_msgbuf;
+
+ do {
+ err = iavf_clean_arq_element(&hw->avf, &event, NULL);
+ if (err != IAVF_SUCCESS)
+ goto again;
+
+ v_op = rte_le_to_cpu_32(event.desc.cookie_high);
+ if (v_op != op)
+ goto again;
+
+ if (rsp_msglen != NULL)
+ *rsp_msglen = event.msg_len;
+ return rte_le_to_cpu_32(event.desc.cookie_low);
+
+again:
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ return -EIO;
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_clear(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_REMOVE(&hw->vc_cmd_queue, cmd, next);
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline void
+ice_dcf_vc_cmd_set(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ cmd->v_ret = IAVF_ERR_NOT_READY;
+ cmd->rsp_msglen = 0;
+ cmd->pending = 1;
+
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_INSERT_TAIL(&hw->vc_cmd_queue, cmd, next);
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline int
+ice_dcf_vc_cmd_send(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ return iavf_aq_send_msg_to_pf(&hw->avf,
+ cmd->v_op, IAVF_SUCCESS,
+ cmd->req_msg, cmd->req_msglen, NULL);
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
+{
+ struct dcf_virtchnl_cmd *cmd;
+ enum virtchnl_ops v_op;
+ enum iavf_status v_ret;
+ uint16_t aq_op;
+
+ aq_op = rte_le_to_cpu_16(info->desc.opcode);
+ if (unlikely(aq_op != iavf_aqc_opc_send_msg_to_vf)) {
+ PMD_DRV_LOG(ERR,
+ "Request %u is not supported yet", aq_op);
+ return;
+ }
+
+ v_op = rte_le_to_cpu_32(info->desc.cookie_high);
+ if (unlikely(v_op == VIRTCHNL_OP_EVENT)) {
+ if (hw->vc_event_msg_cb != NULL)
+ hw->vc_event_msg_cb(hw,
+ info->msg_buf,
+ info->msg_len);
+ return;
+ }
+
+ v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
+
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_FOREACH(cmd, &hw->vc_cmd_queue, next) {
+ if (cmd->v_op == v_op && cmd->pending) {
+ cmd->v_ret = v_ret;
+ cmd->rsp_msglen = RTE_MIN(info->msg_len,
+ cmd->rsp_buflen);
+ if (likely(cmd->rsp_msglen != 0))
+ rte_memcpy(cmd->rsp_msgbuf, info->msg_buf,
+ cmd->rsp_msglen);
+
+ /* prevent compiler reordering */
+ rte_compiler_barrier();
+ cmd->pending = 0;
+ break;
+ }
+ }
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static void
+ice_dcf_handle_virtchnl_msg(struct ice_dcf_hw *hw)
+{
+ struct iavf_arq_event_info info;
+ uint16_t pending = 1;
+ int ret;
+
+ info.buf_len = ICE_DCF_AQ_BUF_SZ;
+ info.msg_buf = hw->arq_buf;
+
+ while (pending) {
+ ret = iavf_clean_arq_element(&hw->avf, &info, &pending);
+ if (ret != IAVF_SUCCESS)
+ break;
+
+ ice_dcf_aq_cmd_handle(hw, &info);
+ }
+}
+
+static int
+ice_dcf_init_check_api_version(struct ice_dcf_hw *hw)
+{
+#define ICE_CPF_VIRTCHNL_VERSION_MAJOR_START 1
+#define ICE_CPF_VIRTCHNL_VERSION_MINOR_START 1
+ struct virtchnl_version_info version, *pver;
+ int err;
+
+ version.major = VIRTCHNL_VERSION_MAJOR;
+ version.minor = VIRTCHNL_VERSION_MINOR;
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_VERSION,
+ (uint8_t *)&version, sizeof(version));
+ if (err) {
+ PMD_INIT_LOG(ERR, "Fail to send OP_VERSION");
+ return err;
+ }
+
+ pver = &hw->virtchnl_version;
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_VERSION,
+ (uint8_t *)pver, sizeof(*pver), NULL);
+ if (err) {
+ PMD_INIT_LOG(ERR, "Fail to get response of OP_VERSION");
+ return -1;
+ }
+
+ PMD_DRV_LOG(DEBUG,
+ "Peer PF API version: %u.%u", pver->major, pver->minor);
+
+ if (pver->major < ICE_CPF_VIRTCHNL_VERSION_MAJOR_START ||
+ (pver->major == ICE_CPF_VIRTCHNL_VERSION_MAJOR_START &&
+ pver->minor < ICE_CPF_VIRTCHNL_VERSION_MINOR_START)) {
+ PMD_INIT_LOG(ERR,
+ "VIRTCHNL API version should not be lower than (%u.%u)",
+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START,
+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START);
+ return -1;
+ } else if (pver->major > VIRTCHNL_VERSION_MAJOR ||
+ (pver->major == VIRTCHNL_VERSION_MAJOR &&
+ pver->minor > VIRTCHNL_VERSION_MINOR)) {
+ PMD_INIT_LOG(ERR,
+ "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
+ pver->major, pver->minor,
+ VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
+ return -1;
+ }
+
+ PMD_DRV_LOG(DEBUG, "Peer is supported PF host");
+
+ return 0;
+}
+
+static int
+ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
+{
+ uint32_t caps;
+ int err, i;
+
+ caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED | VIRTCHNL_VF_CAP_DCF |
+ VF_BASE_MODE_OFFLOADS;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+ (uint8_t *)&caps, sizeof(caps));
+ if (err) {
+ PMD_DRV_LOG(ERR, "Fail to send msg OP_GET_VF_RESOURCE");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+ (uint8_t *)hw->vf_res,
+ ICE_DCF_VF_RES_BUF_SZ, NULL);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Fail to get response of OP_GET_VF_RESOURCE");
+ return -1;
+ }
+
+ iavf_vf_parse_hw_config(&hw->avf, hw->vf_res);
+
+ hw->vsi_res = NULL;
+ for (i = 0; i < hw->vf_res->num_vsis; i++) {
+ if (hw->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
+ hw->vsi_res = &hw->vf_res->vsi_res[i];
+ }
+
+ if (!hw->vsi_res) {
+ PMD_DRV_LOG(ERR, "no LAN VSI found");
+ return -1;
+ }
+
+ hw->vsi_id = hw->vsi_res->vsi_id;
+ PMD_DRV_LOG(DEBUG, "VSI ID is %u", hw->vsi_id);
+
+ return 0;
+}
+
+static int
+ice_dcf_get_vf_vsi_map(struct ice_dcf_hw *hw)
+{
+ struct virtchnl_dcf_vsi_map *vsi_map;
+ uint16_t len;
+ int err;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
+ NULL, 0);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_GET_VSI_MAP");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
+ hw->arq_buf, ICE_DCF_AQ_BUF_SZ,
+ &len);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Fail to get response of OP_DCF_GET_VSI_MAP");
+ return err;
+ }
+
+ vsi_map = (struct virtchnl_dcf_vsi_map *)hw->arq_buf;
+ if (len < sizeof(*vsi_map) || !vsi_map->num_vfs ||
+ len < sizeof(*vsi_map) +
+ (vsi_map->num_vfs - 1) * sizeof(vsi_map->vf_vsi[0])) {
+ PMD_DRV_LOG(ERR, "invalid vf vsi map response with length %u",
+ len);
+ return -EINVAL;
+ }
+
+ if (hw->num_vfs != 0 && hw->num_vfs != vsi_map->num_vfs) {
+ PMD_DRV_LOG(ERR, "The number VSI map (%u) doesn't match the number of VFs (%u)",
+ vsi_map->num_vfs, hw->num_vfs);
+ return -EINVAL;
+ }
+
+ len = vsi_map->num_vfs * sizeof(vsi_map->vf_vsi[0]);
+ if (!hw->vf_vsi_map) {
+ hw->num_vfs = vsi_map->num_vfs;
+ hw->vf_vsi_map = rte_zmalloc("vf_vsi_ctx", len, 0);
+ }
+
+ if (!hw->vf_vsi_map) {
+ PMD_DRV_LOG(ERR, "Fail to alloc memory for VSI context");
+ return -ENOMEM;
+ }
+
+ if (!memcmp(hw->vf_vsi_map, vsi_map->vf_vsi, len)) {
+ PMD_DRV_LOG(DEBUG, "VF VSI map doesn't change");
+ return 1;
+ }
+
+ rte_memcpy(hw->vf_vsi_map, vsi_map->vf_vsi, len);
+ return 0;
+}
+
+static int
+ice_dcf_mode_disable(struct ice_dcf_hw *hw)
+{
+ int err;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
+ NULL, 0);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_DISABLE");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
+ (uint8_t *)hw->arq_buf,
+ ICE_DCF_AQ_BUF_SZ, NULL);
+ if (err) {
+ PMD_DRV_LOG(ERR,
+ "Fail to get response of OP_DCF_DISABLE %d",
+ err);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
+{
+#define ICE_DCF_RESET_WAIT_CNT 50
+ struct iavf_hw *avf = &hw->avf;
+ int i, reset;
+
+ for (i = 0; i < ICE_DCF_RESET_WAIT_CNT; i++) {
+ reset = IAVF_READ_REG(avf, IAVF_VFGEN_RSTAT) &
+ IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
+ reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
+
+ if (reset == VIRTCHNL_VFR_VFACTIVE ||
+ reset == VIRTCHNL_VFR_COMPLETED)
+ break;
+
+ rte_delay_ms(20);
+ }
+
+ if (i >= ICE_DCF_RESET_WAIT_CNT)
+ return -1;
+
+ return 0;
+}
+
+static inline void
+ice_dcf_enable_irq0(struct ice_dcf_hw *hw)
+{
+ struct iavf_hw *avf = &hw->avf;
+
+ /* Enable admin queue interrupt trigger */
+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1,
+ IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+ IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+ IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+ IAVF_WRITE_FLUSH(avf);
+}
+
+static inline void
+ice_dcf_disable_irq0(struct ice_dcf_hw *hw)
+{
+ struct iavf_hw *avf = &hw->avf;
+
+ /* Disable all interrupt types */
+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1, 0);
+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+ IAVF_WRITE_FLUSH(avf);
+}
+
+static void
+ice_dcf_dev_interrupt_handler(void *param)
+{
+ struct ice_dcf_hw *hw = param;
+
+ ice_dcf_disable_irq0(hw);
+
+ ice_dcf_handle_virtchnl_msg(hw);
+
+ ice_dcf_enable_irq0(hw);
+}
+
+int
+ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+ struct dcf_virtchnl_cmd *cmd)
+{
+ int i = 0;
+ int err;
+
+ if ((cmd->req_msg && !cmd->req_msglen) ||
+ (!cmd->req_msg && cmd->req_msglen) ||
+ (cmd->rsp_msgbuf && !cmd->rsp_buflen) ||
+ (!cmd->rsp_msgbuf && cmd->rsp_buflen))
+ return -EINVAL;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_vc_cmd_set(hw, cmd);
+
+ err = ice_dcf_vc_cmd_send(hw, cmd);
+ if (err) {
+ PMD_DRV_LOG(ERR, "fail to send cmd %d", cmd->v_op);
+ goto ret;
+ }
+
+ do {
+ if (!cmd->pending)
+ break;
+
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ if (cmd->v_ret != IAVF_SUCCESS) {
+ err = -1;
+ PMD_DRV_LOG(ERR,
+ "No response (%d times) or return failure (%d) for cmd %d",
+ i, cmd->v_ret, cmd->v_op);
+ }
+
+ret:
+ ice_dcf_aq_cmd_clear(hw, cmd);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+ return err;
+}
+
+int
+ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
+ void *buf, uint16_t buf_size)
+{
+ struct dcf_virtchnl_cmd desc_cmd, buff_cmd;
+ struct ice_dcf_hw *hw = dcf_hw;
+ int err = 0;
+ int i = 0;
+
+ if ((buf && !buf_size) || (!buf && buf_size) ||
+ buf_size > ICE_DCF_AQ_BUF_SZ)
+ return -EINVAL;
+
+ desc_cmd.v_op = VIRTCHNL_OP_DCF_CMD_DESC;
+ desc_cmd.req_msglen = sizeof(*desc);
+ desc_cmd.req_msg = (uint8_t *)desc;
+ desc_cmd.rsp_buflen = sizeof(*desc);
+ desc_cmd.rsp_msgbuf = (uint8_t *)desc;
+
+ if (buf == NULL)
+ return ice_dcf_execute_virtchnl_cmd(hw, &desc_cmd);
+
+ desc->flags |= rte_cpu_to_le_16(ICE_AQ_FLAG_BUF);
+
+ buff_cmd.v_op = VIRTCHNL_OP_DCF_CMD_BUFF;
+ buff_cmd.req_msglen = buf_size;
+ buff_cmd.req_msg = buf;
+ buff_cmd.rsp_buflen = buf_size;
+ buff_cmd.rsp_msgbuf = buf;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_vc_cmd_set(hw, &desc_cmd);
+ ice_dcf_vc_cmd_set(hw, &buff_cmd);
+
+ if (ice_dcf_vc_cmd_send(hw, &desc_cmd) ||
+ ice_dcf_vc_cmd_send(hw, &buff_cmd)) {
+ err = -1;
+ PMD_DRV_LOG(ERR, "fail to send OP_DCF_CMD_DESC/BUFF");
+ goto ret;
+ }
+
+ do {
+ if ((!desc_cmd.pending && !buff_cmd.pending) ||
+ (!desc_cmd.pending && desc_cmd.v_ret != IAVF_SUCCESS) ||
+ (!buff_cmd.pending && buff_cmd.v_ret != IAVF_SUCCESS))
+ break;
+
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ if (desc_cmd.v_ret != IAVF_SUCCESS || buff_cmd.v_ret != IAVF_SUCCESS) {
+ err = -1;
+ PMD_DRV_LOG(ERR,
+ "No response (%d times) or return failure (desc: %d / buff: %d)",
+ i, desc_cmd.v_ret, buff_cmd.v_ret);
+ }
+
+ret:
+ ice_dcf_aq_cmd_clear(hw, &desc_cmd);
+ ice_dcf_aq_cmd_clear(hw, &buff_cmd);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+
+ return err;
+}
+
+int
+ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw)
+{
+ int err = 0;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_disable_irq0(hw);
+
+ if (ice_dcf_get_vf_resource(hw) || ice_dcf_get_vf_vsi_map(hw))
+ err = -1;
+
+ ice_dcf_enable_irq0(hw);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+
+ return err;
+}
+
+int
+ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ int ret;
+
+ hw->avf.hw_addr = pci_dev->mem_resource[0].addr;
+ hw->avf.back = hw;
+
+ hw->avf.bus.bus_id = pci_dev->addr.bus;
+ hw->avf.bus.device = pci_dev->addr.devid;
+ hw->avf.bus.func = pci_dev->addr.function;
+
+ hw->avf.device_id = pci_dev->id.device_id;
+ hw->avf.vendor_id = pci_dev->id.vendor_id;
+ hw->avf.subsystem_device_id = pci_dev->id.subsystem_device_id;
+ hw->avf.subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+
+ hw->avf.aq.num_arq_entries = ICE_DCF_AQ_LEN;
+ hw->avf.aq.num_asq_entries = ICE_DCF_AQ_LEN;
+ hw->avf.aq.arq_buf_size = ICE_DCF_AQ_BUF_SZ;
+ hw->avf.aq.asq_buf_size = ICE_DCF_AQ_BUF_SZ;
+
+ rte_spinlock_init(&hw->vc_cmd_send_lock);
+ rte_spinlock_init(&hw->vc_cmd_queue_lock);
+ TAILQ_INIT(&hw->vc_cmd_queue);
+
+ hw->arq_buf = rte_zmalloc("arq_buf", ICE_DCF_AQ_BUF_SZ, 0);
+ if (hw->arq_buf == NULL) {
+ PMD_INIT_LOG(ERR, "unable to allocate AdminQ buffer memory");
+ goto err;
+ }
+
+ ret = iavf_set_mac_type(&hw->avf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "set_mac_type failed: %d", ret);
+ goto err;
+ }
+
+ ret = ice_dcf_check_reset_done(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "VF is still resetting");
+ goto err;
+ }
+
+ ret = iavf_init_adminq(&hw->avf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "init_adminq failed: %d", ret);
+ goto err;
+ }
+
+ if (ice_dcf_init_check_api_version(hw)) {
+ PMD_INIT_LOG(ERR, "check_api version failed");
+ goto err_api;
+ }
+
+ hw->vf_res = rte_zmalloc("vf_res", ICE_DCF_VF_RES_BUF_SZ, 0);
+ if (hw->vf_res == NULL) {
+ PMD_INIT_LOG(ERR, "unable to allocate vf_res memory");
+ goto err_api;
+ }
+
+ if (ice_dcf_get_vf_resource(hw)) {
+ PMD_INIT_LOG(ERR, "Failed to get VF resource");
+ goto err_alloc;
+ }
+
+ if (ice_dcf_get_vf_vsi_map(hw) < 0) {
+ PMD_INIT_LOG(ERR, "Failed to get VF VSI map");
+ ice_dcf_mode_disable(hw);
+ goto err_alloc;
+ }
+
+ rte_intr_callback_register(&pci_dev->intr_handle,
+ ice_dcf_dev_interrupt_handler, hw);
+ rte_intr_enable(&pci_dev->intr_handle);
+ ice_dcf_enable_irq0(hw);
+
+ return 0;
+
+err_alloc:
+ rte_free(hw->vf_res);
+err_api:
+ iavf_shutdown_adminq(&hw->avf);
+err:
+ rte_free(hw->arq_buf);
+
+ return -1;
+}
+
+void
+ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
+ ice_dcf_disable_irq0(hw);
+ rte_intr_disable(intr_handle);
+ rte_intr_callback_unregister(intr_handle,
+ ice_dcf_dev_interrupt_handler, hw);
+
+ ice_dcf_mode_disable(hw);
+ iavf_shutdown_adminq(&hw->avf);
+
+ rte_free(hw->arq_buf);
+ rte_free(hw->vf_vsi_map);
+ rte_free(hw->vf_res);
+}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
new file mode 100644
index 000000000..58647d87f
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_H_
+#define _ICE_DCF_H_
+
+#include <rte_ethdev_driver.h>
+
+#include <iavf_prototype.h>
+#include <iavf_adminq_cmd.h>
+#include <iavf_type.h>
+
+#include "base/ice_type.h"
+#include "ice_logs.h"
+
+struct dcf_virtchnl_cmd {
+ TAILQ_ENTRY(dcf_virtchnl_cmd) next;
+
+ enum virtchnl_ops v_op;
+ enum iavf_status v_ret;
+
+ uint16_t req_msglen;
+ uint8_t *req_msg;
+
+ uint16_t rsp_msglen;
+ uint16_t rsp_buflen;
+ uint8_t *rsp_msgbuf;
+
+ volatile int pending;
+};
+
+struct ice_dcf_hw {
+ struct iavf_hw avf;
+
+ rte_spinlock_t vc_cmd_send_lock;
+ rte_spinlock_t vc_cmd_queue_lock;
+ TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+ void (*vc_event_msg_cb)(struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen);
+
+ uint8_t *arq_buf;
+
+ uint16_t num_vfs;
+ uint16_t *vf_vsi_map;
+
+ struct virtchnl_version_info virtchnl_version;
+ struct virtchnl_vf_resource *vf_res; /* VF resource */
+ struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
+ uint16_t vsi_id;
+};
+
+int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+ struct dcf_virtchnl_cmd *cmd);
+int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
+ void *buf, uint16_t buf_size);
+int ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw);
+int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+
+#endif /* _ICE_DCF_H_ */
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
new file mode 100644
index 000000000..f65b962d4
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -0,0 +1,319 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <rte_interrupts.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_pci.h>
+#include <rte_kvargs.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include <iavf_devids.h>
+
+#include "ice_generic_flow.h"
+#include "ice_dcf_ethdev.h"
+
+static uint16_t
+ice_dcf_recv_pkts(__rte_unused void *rx_queue,
+ __rte_unused struct rte_mbuf **bufs,
+ __rte_unused uint16_t nb_pkts)
+{
+ return 0;
+}
+
+static uint16_t
+ice_dcf_xmit_pkts(__rte_unused void *tx_queue,
+ __rte_unused struct rte_mbuf **bufs,
+ __rte_unused uint16_t nb_pkts)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_start(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = ETH_LINK_UP;
+
+ return 0;
+}
+
+static void
+ice_dcf_dev_stop(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+ice_dcf_dev_configure(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_info_get(struct rte_eth_dev *dev,
+ struct rte_eth_dev_info *dev_info)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev_info->max_mac_addrs = 1;
+ dev_info->max_rx_pktlen = (uint32_t)-1;
+ dev_info->max_rx_queues = RTE_DIM(adapter->rxqs);
+ dev_info->max_tx_queues = RTE_DIM(adapter->txqs);
+
+ return 0;
+}
+
+static int
+ice_dcf_stats_get(__rte_unused struct rte_eth_dev *dev,
+ __rte_unused struct rte_eth_stats *igb_stats)
+{
+ return 0;
+}
+
+static int
+ice_dcf_stats_reset(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_disable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_enable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_disable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
+ enum rte_filter_type filter_type,
+ __rte_unused enum rte_filter_op filter_op,
+ __rte_unused void *arg)
+{
+ int ret = 0;
+
+ if (!dev)
+ return -EINVAL;
+
+ switch (filter_type) {
+ default:
+ PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+ filter_type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void
+ice_dcf_dev_close(struct rte_eth_dev *dev)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return;
+
+ dev->dev_ops = NULL;
+ dev->rx_pkt_burst = NULL;
+ dev->tx_pkt_burst = NULL;
+
+ ice_dcf_uninit_parent_adapter(dev);
+ ice_dcf_uninit_hw(dev, &adapter->real_hw);
+}
+
+static void
+ice_dcf_queue_release(__rte_unused void *q)
+{
+}
+
+static int
+ice_dcf_link_update(__rte_unused struct rte_eth_dev *dev,
+ __rte_unused int wait_to_complete)
+{
+ return 0;
+}
+
+static int
+ice_dcf_rx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t rx_queue_id,
+ __rte_unused uint16_t nb_rx_desc,
+ __rte_unused unsigned int socket_id,
+ __rte_unused const struct rte_eth_rxconf *rx_conf,
+ __rte_unused struct rte_mempool *mb_pool)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev->data->rx_queues[rx_queue_id] = &adapter->rxqs[rx_queue_id];
+
+ return 0;
+}
+
+static int
+ice_dcf_tx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t tx_queue_id,
+ __rte_unused uint16_t nb_tx_desc,
+ __rte_unused unsigned int socket_id,
+ __rte_unused const struct rte_eth_txconf *tx_conf)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev->data->tx_queues[tx_queue_id] = &adapter->txqs[tx_queue_id];
+
+ return 0;
+}
+
+static const struct eth_dev_ops ice_dcf_eth_dev_ops = {
+ .dev_start = ice_dcf_dev_start,
+ .dev_stop = ice_dcf_dev_stop,
+ .dev_close = ice_dcf_dev_close,
+ .dev_configure = ice_dcf_dev_configure,
+ .dev_infos_get = ice_dcf_dev_info_get,
+ .rx_queue_setup = ice_dcf_rx_queue_setup,
+ .tx_queue_setup = ice_dcf_tx_queue_setup,
+ .rx_queue_release = ice_dcf_queue_release,
+ .tx_queue_release = ice_dcf_queue_release,
+ .link_update = ice_dcf_link_update,
+ .stats_get = ice_dcf_stats_get,
+ .stats_reset = ice_dcf_stats_reset,
+ .promiscuous_enable = ice_dcf_dev_promiscuous_enable,
+ .promiscuous_disable = ice_dcf_dev_promiscuous_disable,
+ .allmulticast_enable = ice_dcf_dev_allmulticast_enable,
+ .allmulticast_disable = ice_dcf_dev_allmulticast_disable,
+ .filter_ctrl = ice_dcf_dev_filter_ctrl,
+};
+
+static int
+ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+
+ eth_dev->dev_ops = &ice_dcf_eth_dev_ops;
+ eth_dev->rx_pkt_burst = ice_dcf_recv_pkts;
+ eth_dev->tx_pkt_burst = ice_dcf_xmit_pkts;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return 0;
+
+ eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
+ adapter->real_hw.vc_event_msg_cb = ice_dcf_handle_pf_event_msg;
+ if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
+ PMD_DRV_LOG(ERR, "Failed to init DCF hardware");
+ return -1;
+ }
+
+ if (ice_dcf_init_parent_adapter(eth_dev) != 0) {
+ PMD_DRV_LOG(ERR, "Failed to init DCF parent adapter");
+ ice_dcf_uninit_hw(eth_dev, &adapter->real_hw);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+ice_dcf_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+ ice_dcf_dev_close(eth_dev);
+
+ return 0;
+}
+
+static int
+handle_dcf_arg(__rte_unused const char *key, const char *value,
+ __rte_unused void *arg)
+{
+ bool *dcf = arg;
+
+ if (arg == NULL || value == NULL)
+ return -EINVAL;
+
+ if (strcmp(value, "dcf") == 0)
+ *dcf = true;
+ else
+ *dcf = false;
+
+ return 0;
+}
+
+static bool
+check_cap_dcf_enable(struct rte_devargs *devargs)
+{
+ struct rte_kvargs *kvlist;
+ bool enable = false;
+
+ if (devargs == NULL)
+ return false;
+
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
+ if (kvlist == NULL)
+ return false;
+
+ rte_kvargs_process(kvlist, "cap", handle_dcf_arg, &enable);
+
+ rte_kvargs_free(kvlist);
+
+ return enable;
+}
+
+static int eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
+ struct rte_pci_device *pci_dev)
+{
+ if (!check_cap_dcf_enable(pci_dev->device.devargs))
+ return 1; /* continue to probe */
+
+ return rte_eth_dev_pci_generic_probe(pci_dev,
+ sizeof(struct ice_dcf_adapter),
+ ice_dcf_dev_init);
+}
+
+static int eth_ice_dcf_pci_remove(struct rte_pci_device *pci_dev)
+{
+ return rte_eth_dev_pci_generic_remove(pci_dev, ice_dcf_dev_uninit);
+}
+
+static const struct rte_pci_id pci_id_ice_dcf_map[] = {
+ { RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
+ { .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver rte_ice_dcf_pmd = {
+ .id_table = pci_id_ice_dcf_map,
+ .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+ .probe = eth_ice_dcf_pci_probe,
+ .remove = eth_ice_dcf_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_ice_dcf, rte_ice_dcf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_ice_dcf, pci_id_ice_dcf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ice_dcf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_ice_dcf, "cap=dcf");
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
new file mode 100644
index 000000000..e95266599
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_ETHDEV_H_
+#define _ICE_DCF_ETHDEV_H_
+
+#include "base/ice_common.h"
+#include "base/ice_adminq_cmd.h"
+
+#include "ice_ethdev.h"
+#include "ice_dcf.h"
+
+#define ICE_DCF_MAX_RINGS 1
+
+struct ice_dcf_queue {
+ uint64_t dummy;
+};
+
+struct ice_dcf_adapter {
+ struct ice_adapter parent; /* Must be first */
+
+ struct ice_dcf_hw real_hw;
+ struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
+ struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
+};
+
+void ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen);
+int ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev);
+void ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev);
+
+#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
new file mode 100644
index 000000000..bca9cd34a
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_parent.c
@@ -0,0 +1,348 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <rte_alarm.h>
+
+#include "ice_dcf_ethdev.h"
+#include "ice_generic_flow.h"
+
+#define ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL 100000 /* us */
+
+static __rte_always_inline void
+ice_dcf_update_vsi_ctx(struct ice_hw *hw, uint16_t vsi_handle,
+ uint16_t vsi_map)
+{
+ struct ice_vsi_ctx *vsi_ctx;
+
+ if (unlikely(vsi_handle >= ICE_MAX_VSI)) {
+ PMD_DRV_LOG(ERR, "Invalid vsi handle %u", vsi_handle);
+ return;
+ }
+
+ vsi_ctx = hw->vsi_ctx[vsi_handle];
+
+ if (vsi_map & VIRTCHNL_DCF_VF_VSI_VALID) {
+ if (!vsi_ctx)
+ vsi_ctx = ice_malloc(hw, sizeof(*vsi_ctx));
+
+ if (!vsi_ctx) {
+ PMD_DRV_LOG(ERR, "No memory for vsi context %u",
+ vsi_handle);
+ return;
+ }
+
+ vsi_ctx->vsi_num = (vsi_map & VIRTCHNL_DCF_VF_VSI_ID_M) >>
+ VIRTCHNL_DCF_VF_VSI_ID_S;
+ hw->vsi_ctx[vsi_handle] = vsi_ctx;
+
+ PMD_DRV_LOG(DEBUG, "VF%u is assigned with vsi number %u",
+ vsi_handle, vsi_ctx->vsi_num);
+ } else {
+ hw->vsi_ctx[vsi_handle] = NULL;
+
+ if (vsi_ctx)
+ ice_free(hw, vsi_ctx);
+
+ PMD_DRV_LOG(NOTICE, "VF%u is disabled", vsi_handle);
+ }
+}
+
+static void
+ice_dcf_update_vf_vsi_map(struct ice_hw *hw, uint16_t num_vfs,
+ uint16_t *vf_vsi_map)
+{
+ uint16_t vf_id;
+
+ for (vf_id = 0; vf_id < num_vfs; vf_id++)
+ ice_dcf_update_vsi_ctx(hw, vf_id, vf_vsi_map[vf_id]);
+}
+
+static void
+ice_dcf_vsi_update_service_handler(void *param)
+{
+ struct ice_dcf_hw *hw = param;
+
+ if (!ice_dcf_handle_vsi_update_event(hw)) {
+ struct ice_dcf_adapter *dcf_ad =
+ container_of(hw, struct ice_dcf_adapter, real_hw);
+
+ ice_dcf_update_vf_vsi_map(&dcf_ad->parent.hw,
+ hw->num_vfs, hw->vf_vsi_map);
+ }
+}
+
+void
+ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen)
+{
+ struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
+
+ if (msglen < sizeof(struct virtchnl_pf_event)) {
+ PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen);
+ return;
+ }
+
+ switch (pf_msg->event) {
+ case VIRTCHNL_EVENT_RESET_IMPENDING:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
+ rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL * 2,
+ ice_dcf_vsi_update_service_handler, dcf_hw);
+ break;
+ case VIRTCHNL_EVENT_LINK_CHANGE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
+ break;
+ case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
+ break;
+ case VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE event : VF%u with VSI num %u",
+ pf_msg->event_data.vf_vsi_map.vf_id,
+ pf_msg->event_data.vf_vsi_map.vsi_id);
+ rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL,
+ ice_dcf_vsi_update_service_handler, dcf_hw);
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
+ break;
+ }
+}
+
+static int
+ice_dcf_init_parent_hw(struct ice_hw *hw)
+{
+ struct ice_aqc_get_phy_caps_data *pcaps;
+ enum ice_status status;
+
+ status = ice_aq_get_fw_ver(hw, NULL);
+ if (status)
+ return status;
+
+ status = ice_get_caps(hw);
+ if (status)
+ return status;
+
+ hw->port_info = (struct ice_port_info *)
+ ice_malloc(hw, sizeof(*hw->port_info));
+ if (!hw->port_info)
+ return ICE_ERR_NO_MEMORY;
+
+ /* set the back pointer to HW */
+ hw->port_info->hw = hw;
+
+ /* Initialize port_info struct with switch configuration data */
+ status = ice_get_initial_sw_cfg(hw);
+ if (status)
+ goto err_unroll_alloc;
+
+ pcaps = (struct ice_aqc_get_phy_caps_data *)
+ ice_malloc(hw, sizeof(*pcaps));
+ if (!pcaps) {
+ status = ICE_ERR_NO_MEMORY;
+ goto err_unroll_alloc;
+ }
+
+ /* Initialize port_info struct with PHY capabilities */
+ status = ice_aq_get_phy_caps(hw->port_info, false,
+ ICE_AQC_REPORT_TOPO_CAP, pcaps, NULL);
+ ice_free(hw, pcaps);
+ if (status)
+ goto err_unroll_alloc;
+
+ /* Initialize port_info struct with link information */
+ status = ice_aq_get_link_info(hw->port_info, false, NULL, NULL);
+ if (status)
+ goto err_unroll_alloc;
+
+ status = ice_init_fltr_mgmt_struct(hw);
+ if (status)
+ goto err_unroll_alloc;
+
+ status = ice_init_hw_tbls(hw);
+ if (status)
+ goto err_unroll_fltr_mgmt_struct;
+
+ PMD_DRV_LOG(INFO,
+ "firmware %d.%d.%d api %d.%d.%d build 0x%08x",
+ hw->fw_maj_ver, hw->fw_min_ver, hw->fw_patch,
+ hw->api_maj_ver, hw->api_min_ver, hw->api_patch,
+ hw->fw_build);
+
+ return ICE_SUCCESS;
+
+err_unroll_fltr_mgmt_struct:
+ ice_cleanup_fltr_mgmt_struct(hw);
+err_unroll_alloc:
+ ice_free(hw, hw->port_info);
+ hw->port_info = NULL;
+
+ return status;
+}
+
+static void ice_dcf_uninit_parent_hw(struct ice_hw *hw)
+{
+ ice_cleanup_fltr_mgmt_struct(hw);
+
+ ice_free_seg(hw);
+ ice_free_hw_tbls(hw);
+
+ if (hw->port_info) {
+ ice_free(hw, hw->port_info);
+ hw->port_info = NULL;
+ }
+
+ ice_clear_all_vsi_ctx(hw);
+}
+
+static int
+ice_dcf_request_pkg_name(struct ice_hw *hw, char *pkg_name)
+{
+ struct ice_dcf_adapter *dcf_adapter =
+ container_of(hw, struct ice_dcf_adapter, parent.hw);
+
+ /* TODO: check with DSN firstly by iAVF */
+ PMD_DRV_LOG(DEBUG,
+ "DCF VSI_ID = %u",
+ dcf_adapter->real_hw.vsi_id);
+
+ snprintf(pkg_name,
+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_UPDATES);
+ if (!access(pkg_name, 0))
+ return 0;
+
+ snprintf(pkg_name,
+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_DEFAULT);
+ if (!access(pkg_name, 0))
+ return 0;
+
+ return -1;
+}
+
+static int
+ice_dcf_load_pkg(struct ice_hw *hw)
+{
+ char pkg_name[ICE_MAX_PKG_FILENAME_SIZE];
+ uint8_t *pkg_buf;
+ uint32_t buf_len;
+ struct stat st;
+ FILE *fp;
+ int err;
+
+ if (ice_dcf_request_pkg_name(hw, pkg_name)) {
+ PMD_INIT_LOG(ERR, "failed to locate the package file");
+ return -ENOENT;
+ }
+
+ PMD_INIT_LOG(DEBUG, "DDP package name: %s", pkg_name);
+
+ err = stat(pkg_name, &st);
+ if (err) {
+ PMD_INIT_LOG(ERR, "failed to get file status");
+ return err;
+ }
+
+ buf_len = st.st_size;
+ pkg_buf = rte_malloc(NULL, buf_len, 0);
+ if (!pkg_buf) {
+ PMD_INIT_LOG(ERR, "failed to allocate buffer of size %u for package",
+ buf_len);
+ return -1;
+ }
+
+ fp = fopen(pkg_name, "rb");
+ if (!fp) {
+ PMD_INIT_LOG(ERR, "failed to open file: %s", pkg_name);
+ err = -1;
+ goto ret;
+ }
+
+ err = fread(pkg_buf, buf_len, 1, fp);
+ fclose(fp);
+ if (err != 1) {
+ PMD_INIT_LOG(ERR, "failed to read package data");
+ err = -1;
+ goto ret;
+ }
+
+ err = ice_copy_and_init_pkg(hw, pkg_buf, buf_len);
+ if (err)
+ PMD_INIT_LOG(ERR, "ice_copy_and_init_hw failed: %d", err);
+
+ret:
+ rte_free(pkg_buf);
+ return err;
+}
+
+int
+ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+ struct ice_adapter *parent_adapter = &adapter->parent;
+ struct ice_hw *parent_hw = &parent_adapter->hw;
+ struct ice_dcf_hw *hw = &adapter->real_hw;
+ const struct rte_ether_addr *mac;
+ int err;
+
+ parent_adapter->eth_dev = eth_dev;
+ parent_adapter->pf.adapter = parent_adapter;
+ parent_adapter->pf.dev_data = eth_dev->data;
+ parent_hw->back = parent_adapter;
+ parent_hw->mac_type = ICE_MAC_GENERIC;
+ parent_hw->vendor_id = ICE_INTEL_VENDOR_ID;
+
+ ice_init_lock(&parent_hw->adminq.sq_lock);
+ ice_init_lock(&parent_hw->adminq.rq_lock);
+ parent_hw->aq_send_cmd_fn = ice_dcf_send_aq_cmd;
+ parent_hw->aq_send_cmd_param = &adapter->real_hw;
+ parent_hw->dcf_enabled = true;
+
+ err = ice_dcf_init_parent_hw(parent_hw);
+ if (err) {
+ PMD_DRV_LOG(ERR, "failed to init the DCF parent hardware with error %d",
+ err);
+ return err;
+ }
+
+ err = ice_dcf_load_pkg(parent_hw);
+ if (err) {
+ PMD_DRV_LOG(ERR, "failed to load package with error %d",
+ err);
+ goto uninit_hw;
+ }
+ parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
+
+ ice_dcf_update_vf_vsi_map(parent_hw,
+ hw->num_vfs, hw->vf_vsi_map);
+
+ mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
+ if (rte_is_valid_assigned_ether_addr(mac))
+ rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
+ else
+ rte_eth_random_addr(parent_adapter->pf.dev_addr.addr_bytes);
+
+ eth_dev->data->mac_addrs = &parent_adapter->pf.dev_addr;
+
+ return 0;
+
+uninit_hw:
+ ice_dcf_uninit_parent_hw(parent_hw);
+ return err;
+}
+
+void
+ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+ struct ice_adapter *parent_adapter = &adapter->parent;
+ struct ice_hw *parent_hw = &parent_adapter->hw;
+
+ eth_dev->data->mac_addrs = NULL;
+
+ rte_eal_alarm_cancel(ice_dcf_vsi_update_service_handler,
+ &adapter->real_hw);
+
+ ice_dcf_uninit_parent_hw(parent_hw);
+}
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index f9e897bbc..0df8ddc0f 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -15,8 +15,8 @@ sources = files(
'ice_hash.c'
)
-deps += ['hash']
-includes += include_directories('base')
+deps += ['hash', 'net', 'common_iavf']
+includes += include_directories('base', '../../common/iavf')
if arch_subdir == 'x86'
sources += files('ice_rxtx_vec_sse.c')
@@ -37,4 +37,8 @@ if arch_subdir == 'x86'
endif
endif
+sources += files('ice_dcf.c',
+ 'ice_dcf_parent.c',
+ 'ice_dcf_ethdev.c')
+
install_headers('rte_pmd_ice.h')
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index d295ca0a5..f3798a09f 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -185,6 +185,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += -lrte_pmd_i40e
_LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD) += -lrte_pmd_iavf
_LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += -lrte_pmd_ice
IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
ifeq ($(findstring y,$(IAVF-y)),y)
_LDLIBS-y += -lrte_common_iavf
endif
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v1 4/4] doc: add release notes for Intel ice PMD
2020-03-09 14:14 [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support Haiyue Wang
` (2 preceding siblings ...)
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 3/4] net/ice: add the DCF framework Haiyue Wang
@ 2020-03-09 14:14 ` Haiyue Wang
2020-03-09 15:22 ` Ye Xiaolong
2020-03-09 15:36 ` [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support David Marchand
` (5 subsequent siblings)
9 siblings, 1 reply; 94+ messages in thread
From: Haiyue Wang @ 2020-03-09 14:14 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
Add release notes for the new Intel ice feature DCF (Device Config
Function).
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
doc/guides/rel_notes/release_20_05.rst | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 000bbf501..f404ee7fd 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -62,6 +62,11 @@ New Features
* Added support for matching on IPv4 Time To Live and IPv6 Hop Limit.
+* **Updated the Intel ice driver.**
+
+ Updated the Intel ice driver with new features and improvements, including:
+
+ * Added support for DCF (Device Config Function) feature.
Removed Items
-------------
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 4/4] doc: add release notes for Intel ice PMD
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 4/4] doc: add release notes for Intel ice PMD Haiyue Wang
@ 2020-03-09 15:22 ` Ye Xiaolong
2020-03-10 2:16 ` Wang, Haiyue
0 siblings, 1 reply; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-09 15:22 UTC (permalink / raw)
To: Haiyue Wang; +Cc: dev, qi.z.zhang, qiming.yang, beilei.xing, wei.zhao1
Release note doesn't have to be a separate patch, can go with the feature
patch.
Thanks,
Xiaolong
On 03/09, Haiyue Wang wrote:
>Add release notes for the new Intel ice feature DCF (Device Config
>Function).
>
>Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
>---
> doc/guides/rel_notes/release_20_05.rst | 5 +++++
> 1 file changed, 5 insertions(+)
>
>diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
>index 000bbf501..f404ee7fd 100644
>--- a/doc/guides/rel_notes/release_20_05.rst
>+++ b/doc/guides/rel_notes/release_20_05.rst
>@@ -62,6 +62,11 @@ New Features
>
> * Added support for matching on IPv4 Time To Live and IPv6 Hop Limit.
>
>+* **Updated the Intel ice driver.**
>+
>+ Updated the Intel ice driver with new features and improvements, including:
>+
>+ * Added support for DCF (Device Config Function) feature.
>
> Removed Items
> -------------
>--
>2.25.1
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support
2020-03-09 14:14 [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support Haiyue Wang
` (3 preceding siblings ...)
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 4/4] doc: add release notes for Intel ice PMD Haiyue Wang
@ 2020-03-09 15:36 ` David Marchand
2020-03-09 16:20 ` Ye Xiaolong
2020-03-10 14:09 ` Aaron Conole
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 0/7] " Haiyue Wang
` (4 subsequent siblings)
9 siblings, 2 replies; 94+ messages in thread
From: David Marchand @ 2020-03-09 15:36 UTC (permalink / raw)
To: Haiyue Wang
Cc: dev, Xiaolong Ye, Qi Zhang, Qiming Yang, Beilei Xing, Wei Zhao,
Aaron Conole, ci
On Mon, Mar 9, 2020 at 3:22 PM Haiyue Wang <haiyue.wang@intel.com> wrote:
>
> A DCF (Device Config Function) based approach is proposed where a device
> bound to the device's VF0 can act as a sole controlling entity to exercise
> advance functionality (such as switch, ACL) for rest of the VFs.
>
> The DCF works as a standalone PMD to support this function, which shares the
> ice PMD flow control core function and the iavf virtchnl mailbox core module.
>
> This patchset is based on:
> [1] https://patchwork.dpdk.org/cover/66417/ update ice base code
The problem is that the CI(s) won't handle this.
Example for the robot: https://travis-ci.com/ovsrobot/dpdk/builds/152461907
Maybe we could add something as an annotation to the cover letter or
the first patch of a series so that the CI(s) can detect and try to be
intelligent?
--
David Marchand
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
@ 2020-03-09 15:38 ` Ye Xiaolong
2020-03-10 2:19 ` Wang, Haiyue
2020-03-23 1:50 ` Wu, Jingjing
1 sibling, 1 reply; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-09 15:38 UTC (permalink / raw)
To: Haiyue Wang; +Cc: dev, qi.z.zhang, qiming.yang, beilei.xing, wei.zhao1
On 03/09, Haiyue Wang wrote:
>A new DCF PMD will be introduced, which runs on Intel VF hardware, and
>it is a pure software design to control the advance functionality (such
>as switch, ACL) for rest of the VFs.
>
>So if the DCF (Device Config Function) mode is specified by the devarg
>'cap=dcf', then it will stop the PCI probe in the iavf PMD.
>
>Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
>---
> drivers/net/iavf/iavf_ethdev.c | 41 ++++++++++++++++++++++++++++++++++
> 1 file changed, 41 insertions(+)
>
>diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
>index 34913f9c4..8ff26c0e7 100644
>--- a/drivers/net/iavf/iavf_ethdev.c
>+++ b/drivers/net/iavf/iavf_ethdev.c
>@@ -1416,9 +1416,49 @@ iavf_dev_uninit(struct rte_eth_dev *dev)
> return 0;
> }
>
>+static int
>+handle_dcf_arg(__rte_unused const char *key, const char *value,
>+ __rte_unused void *arg)
>+{
>+ bool *dcf = arg;
>+
>+ if (arg == NULL || value == NULL)
>+ return -EINVAL;
>+
>+ if (strcmp(value, "dcf") == 0)
>+ *dcf = true;
>+ else
>+ *dcf = false;
>+
>+ return 0;
>+}
>+
>+static bool
>+check_cap_dcf_enable(struct rte_devargs *devargs)
>+{
>+ struct rte_kvargs *kvlist;
>+ bool enable = false;
>+
>+ if (devargs == NULL)
>+ return false;
>+
>+ kvlist = rte_kvargs_parse(devargs->args, NULL);
>+ if (kvlist == NULL)
>+ return false;
>+
>+ rte_kvargs_process(kvlist, "cap", handle_dcf_arg, &enable);
Need error handling for failure case.
>+
>+ rte_kvargs_free(kvlist);
>+
>+ return enable;
>+}
>+
> static int eth_iavf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
> struct rte_pci_device *pci_dev)
> {
>+ if (check_cap_dcf_enable(pci_dev->device.devargs))
>+ return 1; /* continue to probe */
This comment is confusing...
>+
> return rte_eth_dev_pci_generic_probe(pci_dev,
> sizeof(struct iavf_adapter), iavf_dev_init);
> }
>@@ -1439,6 +1479,7 @@ static struct rte_pci_driver rte_iavf_pmd = {
> RTE_PMD_REGISTER_PCI(net_iavf, rte_iavf_pmd);
> RTE_PMD_REGISTER_PCI_TABLE(net_iavf, pci_id_iavf_map);
> RTE_PMD_REGISTER_KMOD_DEP(net_iavf, "* igb_uio | vfio-pci");
>+RTE_PMD_REGISTER_PARAM_STRING(net_iavf, "cap=dcf");
> RTE_INIT(iavf_init_log)
> {
> iavf_logtype_init = rte_log_register("pmd.net.iavf.init");
>--
>2.25.1
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support
2020-03-09 15:36 ` [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support David Marchand
@ 2020-03-09 16:20 ` Ye Xiaolong
2020-03-09 17:57 ` Thomas Monjalon
2020-03-10 14:09 ` Aaron Conole
1 sibling, 1 reply; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-09 16:20 UTC (permalink / raw)
To: David Marchand
Cc: Haiyue Wang, dev, Qi Zhang, Qiming Yang, Beilei Xing, Wei Zhao,
Aaron Conole, ci, Ferruh Yigit, thomas
Hi, David
On 03/09, David Marchand wrote:
>On Mon, Mar 9, 2020 at 3:22 PM Haiyue Wang <haiyue.wang@intel.com> wrote:
>>
>> A DCF (Device Config Function) based approach is proposed where a device
>> bound to the device's VF0 can act as a sole controlling entity to exercise
>> advance functionality (such as switch, ACL) for rest of the VFs.
>>
>> The DCF works as a standalone PMD to support this function, which shares the
>> ice PMD flow control core function and the iavf virtchnl mailbox core module.
>>
>> This patchset is based on:
>> [1] https://patchwork.dpdk.org/cover/66417/ update ice base code
>
>The problem is that the CI(s) won't handle this.
>Example for the robot: https://travis-ci.com/ovsrobot/dpdk/builds/152461907
>
>Maybe we could add something as an annotation to the cover letter or
>the first patch of a series so that the CI(s) can detect and try to be
>intelligent?
Agree, It'd be helpful if the cover letter of the first patch contains some
base tree info including the base commit and dependency patchset info (if any),
so the CI can determine the correct base on top of which the developer's
patchset applies to avoid any apply issue and potential false positive.
And I know there is one option '--base'' of `git format-patch` which is
dedicated for this kind of usage, it can help create the base tree info block
which can be easily consumed by the CI. Here is the simple intro of it.
Imagine that on top of the public commit P (already in upstream), the developer
applied well-known (on-flight, in the mailing list but not merged yet) patches
X, Y and Z from somebody else or himself, and then built his three-patch series
A, B, C, the commit history would be like:
................................................
---P---X---Y---Z---A---B---C
................................................
With `git format-patch --base=P -3 C`,
where P could be the exact commit sha, or variants e.g. HEAD~6, we can also use
--base=auto for convenience, the base tree information block will be shown at
the end of the first message the command outputs (either the first patch, or
the cover letter), like this:
------------
base-commit: P
prerequisite-patch-id: X
prerequisite-patch-id: Y
prerequisite-patch-id: Z
------------
Here P is the commit sha, and X,Y,Z are the patch ids of the dependency patches.
With this info in place, I think CI should be able to setup the exact base for
the coming patchset, the missing part I can see is the mapping of
(in-flight patch <-> patch id), since we have all the in-flight patches in
patchwork, creating and maintaining such mapping in DB is doable, what do you
think?
Thanks,
Xiaolong
>
>
>--
>David Marchand
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 2/4] net/ice: export the DDP definition symbols
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 2/4] net/ice: export the DDP definition symbols Haiyue Wang
@ 2020-03-09 16:25 ` Ye Xiaolong
0 siblings, 0 replies; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-09 16:25 UTC (permalink / raw)
To: Haiyue Wang; +Cc: dev, qi.z.zhang, qiming.yang, beilei.xing, wei.zhao1
On 03/09, Haiyue Wang wrote:
>A new DCF PMD will be introduced, which runs on Intel VF hardware, and
>it is a pure software design to control the advance functionality (such
>as switch, ACL) for rest of the VFs.
>
>The DCF (Device Config Function) feature shares the core functions of
>the ICE PMD, like it needs to export the DDP definition symbols for the
>new DCF PMD use.
>
>Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
>---
> drivers/net/ice/ice_ethdev.c | 9 +--------
> drivers/net/ice/ice_ethdev.h | 8 ++++++++
> 2 files changed, 9 insertions(+), 8 deletions(-)
>
>diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c
>index b42deb0bc..8b9d211b0 100644
>--- a/drivers/net/ice/ice_ethdev.c
>+++ b/drivers/net/ice/ice_ethdev.c
>@@ -67,15 +67,8 @@ static struct proto_xtr_ol_flag ice_proto_xtr_ol_flag_params[] = {
>
> #define ICE_DFLT_OUTER_TAG_TYPE ICE_AQ_VSI_OUTER_TAG_VLAN_9100
>
>-/* DDP package search path */
>-#define ICE_PKG_FILE_DEFAULT "/lib/firmware/intel/ice/ddp/ice.pkg"
>-#define ICE_PKG_FILE_UPDATES "/lib/firmware/updates/intel/ice/ddp/ice.pkg"
>-#define ICE_PKG_FILE_SEARCH_PATH_DEFAULT "/lib/firmware/intel/ice/ddp/"
>-#define ICE_PKG_FILE_SEARCH_PATH_UPDATES "/lib/firmware/updates/intel/ice/ddp/"
>-
> #define ICE_OS_DEFAULT_PKG_NAME "ICE OS Default Package"
> #define ICE_COMMS_PKG_NAME "ICE COMMS Package"
>-#define ICE_MAX_PKG_FILENAME_SIZE 256
> #define ICE_MAX_RES_DESC_NUM 1024
>
> int ice_logtype_init;
>@@ -1833,7 +1826,7 @@ ice_pkg_file_search_path(struct rte_pci_device *pci_dev, char *pkg_file)
> return 0;
> }
>
>-static enum ice_pkg_type
>+enum ice_pkg_type
> ice_load_pkg_type(struct ice_hw *hw)
> {
> enum ice_pkg_type package_type;
>diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h
>index da557a254..7b94a3c3e 100644
>--- a/drivers/net/ice/ice_ethdev.h
>+++ b/drivers/net/ice/ice_ethdev.h
>@@ -42,6 +42,13 @@
>
> #define ICE_MAX_PKT_TYPE 1024
>
>+/* DDP package search path */
>+#define ICE_PKG_FILE_DEFAULT "/lib/firmware/intel/ice/ddp/ice.pkg"
>+#define ICE_PKG_FILE_UPDATES "/lib/firmware/updates/intel/ice/ddp/ice.pkg"
>+#define ICE_PKG_FILE_SEARCH_PATH_DEFAULT "/lib/firmware/intel/ice/ddp/"
>+#define ICE_PKG_FILE_SEARCH_PATH_UPDATES "/lib/firmware/updates/intel/ice/ddp/"
>+#define ICE_MAX_PKG_FILENAME_SIZE 256
>+
> /**
> * vlan_id is a 12 bit number.
> * The VFTA array is actually a 4096 bit array, 128 of 32bit elements.
>@@ -457,6 +464,7 @@ struct ice_vsi_vlan_pvid_info {
> #define ICE_PF_TO_ETH_DEV(pf) \
> (((struct ice_pf *)pf)->adapter->eth_dev)
>
>+enum ice_pkg_type ice_load_pkg_type(struct ice_hw *hw);
> struct ice_vsi *
> ice_setup_vsi(struct ice_pf *pf, enum ice_vsi_type type);
> int
>--
>2.25.1
>
Acked-by: Xiaolong Ye <xiaolong.ye@intel.com>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support
2020-03-09 16:20 ` Ye Xiaolong
@ 2020-03-09 17:57 ` Thomas Monjalon
2020-03-09 19:34 ` Kevin Traynor
0 siblings, 1 reply; 94+ messages in thread
From: Thomas Monjalon @ 2020-03-09 17:57 UTC (permalink / raw)
To: David Marchand, Ye Xiaolong
Cc: Haiyue Wang, dev, Qi Zhang, Qiming Yang, Beilei Xing, Wei Zhao,
Aaron Conole, ci, Ferruh Yigit
09/03/2020 17:20, Ye Xiaolong:
> Hi, David
>
> On 03/09, David Marchand wrote:
> >On Mon, Mar 9, 2020 at 3:22 PM Haiyue Wang <haiyue.wang@intel.com> wrote:
> >>
> >> A DCF (Device Config Function) based approach is proposed where a device
> >> bound to the device's VF0 can act as a sole controlling entity to exercise
> >> advance functionality (such as switch, ACL) for rest of the VFs.
> >>
> >> The DCF works as a standalone PMD to support this function, which shares the
> >> ice PMD flow control core function and the iavf virtchnl mailbox core module.
> >>
> >> This patchset is based on:
> >> [1] https://patchwork.dpdk.org/cover/66417/ update ice base code
> >
> >The problem is that the CI(s) won't handle this.
> >Example for the robot: https://travis-ci.com/ovsrobot/dpdk/builds/152461907
> >
> >Maybe we could add something as an annotation to the cover letter or
> >the first patch of a series so that the CI(s) can detect and try to be
> >intelligent?
>
> Agree, It'd be helpful if the cover letter of the first patch contains some
> base tree info including the base commit and dependency patchset info (if any),
> so the CI can determine the correct base on top of which the developer's
> patchset applies to avoid any apply issue and potential false positive.
>
> And I know there is one option '--base'' of `git format-patch` which is
> dedicated for this kind of usage, it can help create the base tree info block
> which can be easily consumed by the CI. Here is the simple intro of it.
>
> Imagine that on top of the public commit P (already in upstream), the developer
> applied well-known (on-flight, in the mailing list but not merged yet) patches
> X, Y and Z from somebody else or himself, and then built his three-patch series
> A, B, C, the commit history would be like:
>
> ................................................
> ---P---X---Y---Z---A---B---C
> ................................................
>
> With `git format-patch --base=P -3 C`,
>
> where P could be the exact commit sha, or variants e.g. HEAD~6, we can also use
> --base=auto for convenience, the base tree information block will be shown at
> the end of the first message the command outputs (either the first patch, or
> the cover letter), like this:
>
> ------------
> base-commit: P
> prerequisite-patch-id: X
> prerequisite-patch-id: Y
> prerequisite-patch-id: Z
> ------------
>
> Here P is the commit sha, and X,Y,Z are the patch ids of the dependency patches.
>
>
> With this info in place, I think CI should be able to setup the exact base for
> the coming patchset, the missing part I can see is the mapping of
> (in-flight patch <-> patch id), since we have all the in-flight patches in
> patchwork, creating and maintaining such mapping in DB is doable, what do you
> think?
I think it would simpler to list dependencies as patchwork ids.
Example:
Depends-on: series-42, patch-12345
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support
2020-03-09 17:57 ` Thomas Monjalon
@ 2020-03-09 19:34 ` Kevin Traynor
2020-03-10 2:00 ` Wang, Haiyue
0 siblings, 1 reply; 94+ messages in thread
From: Kevin Traynor @ 2020-03-09 19:34 UTC (permalink / raw)
To: Thomas Monjalon, David Marchand, Ye Xiaolong
Cc: Haiyue Wang, dev, Qi Zhang, Qiming Yang, Beilei Xing, Wei Zhao,
Aaron Conole, ci, Ferruh Yigit
On 09/03/2020 17:57, Thomas Monjalon wrote:
> 09/03/2020 17:20, Ye Xiaolong:
>> Hi, David
>>
>> On 03/09, David Marchand wrote:
>>> On Mon, Mar 9, 2020 at 3:22 PM Haiyue Wang <haiyue.wang@intel.com> wrote:
>>>>
>>>> A DCF (Device Config Function) based approach is proposed where a device
>>>> bound to the device's VF0 can act as a sole controlling entity to exercise
>>>> advance functionality (such as switch, ACL) for rest of the VFs.
>>>>
>>>> The DCF works as a standalone PMD to support this function, which shares the
>>>> ice PMD flow control core function and the iavf virtchnl mailbox core module.
>>>>
>>>> This patchset is based on:
>>>> [1] https://patchwork.dpdk.org/cover/66417/ update ice base code
>>>
>>> The problem is that the CI(s) won't handle this.
>>> Example for the robot: https://travis-ci.com/ovsrobot/dpdk/builds/152461907
>>>
>>> Maybe we could add something as an annotation to the cover letter or
>>> the first patch of a series so that the CI(s) can detect and try to be
>>> intelligent?
>>
>> Agree, It'd be helpful if the cover letter of the first patch contains some
>> base tree info including the base commit and dependency patchset info (if any),
>> so the CI can determine the correct base on top of which the developer's
>> patchset applies to avoid any apply issue and potential false positive.
>>
>> And I know there is one option '--base'' of `git format-patch` which is
>> dedicated for this kind of usage, it can help create the base tree info block
>> which can be easily consumed by the CI. Here is the simple intro of it.
>>
>> Imagine that on top of the public commit P (already in upstream), the developer
>> applied well-known (on-flight, in the mailing list but not merged yet) patches
>> X, Y and Z from somebody else or himself, and then built his three-patch series
>> A, B, C, the commit history would be like:
>>
>> ................................................
>> ---P---X---Y---Z---A---B---C
>> ................................................
>>
>> With `git format-patch --base=P -3 C`,
>>
>> where P could be the exact commit sha, or variants e.g. HEAD~6, we can also use
>> --base=auto for convenience, the base tree information block will be shown at
>> the end of the first message the command outputs (either the first patch, or
>> the cover letter), like this:
>>
>> ------------
>> base-commit: P
>> prerequisite-patch-id: X
>> prerequisite-patch-id: Y
>> prerequisite-patch-id: Z
>> ------------
>>
>> Here P is the commit sha, and X,Y,Z are the patch ids of the dependency patches.
>>
>>
>> With this info in place, I think CI should be able to setup the exact base for
>> the coming patchset, the missing part I can see is the mapping of
>> (in-flight patch <-> patch id), since we have all the in-flight patches in
>> patchwork, creating and maintaining such mapping in DB is doable, what do you
>> think?
>
> I think it would simpler to list dependencies as patchwork ids.
> Example:
> Depends-on: series-42, patch-12345
>
+1. I don't think it should depend on a base-commit. If it doesn't
apply/build/work with the latest upstream code then it's a valid error.
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support
2020-03-09 19:34 ` Kevin Traynor
@ 2020-03-10 2:00 ` Wang, Haiyue
2020-03-10 7:48 ` Thomas Monjalon
0 siblings, 1 reply; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-10 2:00 UTC (permalink / raw)
To: Kevin Traynor, Thomas Monjalon, David Marchand, Ye, Xiaolong
Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei,
Aaron Conole, ci, Yigit, Ferruh
> -----Original Message-----
> From: Kevin Traynor <ktraynor@redhat.com>
> Sent: Tuesday, March 10, 2020 03:34
> To: Thomas Monjalon <thomas@monjalon.net>; David Marchand <david.marchand@redhat.com>; Ye, Xiaolong
> <xiaolong.ye@intel.com>
> Cc: Wang, Haiyue <haiyue.wang@intel.com>; dev <dev@dpdk.org>; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang,
> Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>;
> Aaron Conole <aconole@redhat.com>; ci@dpdk.org; Yigit, Ferruh <ferruh.yigit@intel.com>
> Subject: Re: [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support
>
> On 09/03/2020 17:57, Thomas Monjalon wrote:
> > 09/03/2020 17:20, Ye Xiaolong:
> >> Hi, David
> >>
> >> On 03/09, David Marchand wrote:
> >>> On Mon, Mar 9, 2020 at 3:22 PM Haiyue Wang <haiyue.wang@intel.com> wrote:
> >>>>
> >>>> A DCF (Device Config Function) based approach is proposed where a device
> >>>> bound to the device's VF0 can act as a sole controlling entity to exercise
> >>>> advance functionality (such as switch, ACL) for rest of the VFs.
> >>>>
> >>>> The DCF works as a standalone PMD to support this function, which shares the
> >>>> ice PMD flow control core function and the iavf virtchnl mailbox core module.
> >>>>
> >>>> This patchset is based on:
> >>>> [1] https://patchwork.dpdk.org/cover/66417/ update ice base code
> >>>
> >>> The problem is that the CI(s) won't handle this.
> >>> Example for the robot: https://travis-ci.com/ovsrobot/dpdk/builds/152461907
> >>>
> >>> Maybe we could add something as an annotation to the cover letter or
> >>> the first patch of a series so that the CI(s) can detect and try to be
> >>> intelligent?
> >>
> >> Agree, It'd be helpful if the cover letter of the first patch contains some
> >> base tree info including the base commit and dependency patchset info (if any),
> >> so the CI can determine the correct base on top of which the developer's
> >> patchset applies to avoid any apply issue and potential false positive.
> >>
> >> And I know there is one option '--base'' of `git format-patch` which is
> >> dedicated for this kind of usage, it can help create the base tree info block
> >> which can be easily consumed by the CI. Here is the simple intro of it.
> >>
> >> Imagine that on top of the public commit P (already in upstream), the developer
> >> applied well-known (on-flight, in the mailing list but not merged yet) patches
> >> X, Y and Z from somebody else or himself, and then built his three-patch series
> >> A, B, C, the commit history would be like:
> >>
> >> ................................................
> >> ---P---X---Y---Z---A---B---C
> >> ................................................
> >>
> >> With `git format-patch --base=P -3 C`,
> >>
> >> where P could be the exact commit sha, or variants e.g. HEAD~6, we can also use
> >> --base=auto for convenience, the base tree information block will be shown at
> >> the end of the first message the command outputs (either the first patch, or
> >> the cover letter), like this:
> >>
> >> ------------
> >> base-commit: P
> >> prerequisite-patch-id: X
> >> prerequisite-patch-id: Y
> >> prerequisite-patch-id: Z
> >> ------------
> >>
> >> Here P is the commit sha, and X,Y,Z are the patch ids of the dependency patches.
> >>
> >>
> >> With this info in place, I think CI should be able to setup the exact base for
> >> the coming patchset, the missing part I can see is the mapping of
> >> (in-flight patch <-> patch id), since we have all the in-flight patches in
> >> patchwork, creating and maintaining such mapping in DB is doable, what do you
> >> think?
> >
> > I think it would simpler to list dependencies as patchwork ids.
> > Example:
> > Depends-on: series-42, patch-12345
> >
>
Just list the 'series' ? Since it can download the whole patchset with
the single link format like:
Depends-on: series-8843 --> https://patchwork.dpdk.org/series/8843/mbox/
> +1. I don't think it should depend on a base-commit. If it doesn't
> apply/build/work with the latest upstream code then it's a valid error.
>
> >
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 4/4] doc: add release notes for Intel ice PMD
2020-03-09 15:22 ` Ye Xiaolong
@ 2020-03-10 2:16 ` Wang, Haiyue
0 siblings, 0 replies; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-10 2:16 UTC (permalink / raw)
To: Ye, Xiaolong; +Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei
Got it.
BR,
Haiyue
> -----Original Message-----
> From: Ye, Xiaolong <xiaolong.ye@intel.com>
> Sent: Monday, March 9, 2020 23:22
> To: Wang, Haiyue <haiyue.wang@intel.com>
> Cc: dev@dpdk.org; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>
> Subject: Re: [PATCH v1 4/4] doc: add release notes for Intel ice PMD
>
> Release note doesn't have to be a separate patch, can go with the feature
> patch.
>
> Thanks,
> Xiaolong
>
> On 03/09, Haiyue Wang wrote:
> >Add release notes for the new Intel ice feature DCF (Device Config
> >Function).
> >
> >Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
> >---
> > doc/guides/rel_notes/release_20_05.rst | 5 +++++
> > 1 file changed, 5 insertions(+)
> >
> >diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
> >index 000bbf501..f404ee7fd 100644
> >--- a/doc/guides/rel_notes/release_20_05.rst
> >+++ b/doc/guides/rel_notes/release_20_05.rst
> >@@ -62,6 +62,11 @@ New Features
> >
> > * Added support for matching on IPv4 Time To Live and IPv6 Hop Limit.
> >
> >+* **Updated the Intel ice driver.**
> >+
> >+ Updated the Intel ice driver with new features and improvements, including:
> >+
> >+ * Added support for DCF (Device Config Function) feature.
> >
> > Removed Items
> > -------------
> >--
> >2.25.1
> >
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode
2020-03-09 15:38 ` Ye Xiaolong
@ 2020-03-10 2:19 ` Wang, Haiyue
2020-03-10 3:37 ` Ye Xiaolong
0 siblings, 1 reply; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-10 2:19 UTC (permalink / raw)
To: Ye, Xiaolong; +Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei
> -----Original Message-----
> From: Ye, Xiaolong <xiaolong.ye@intel.com>
> Sent: Monday, March 9, 2020 23:38
> To: Wang, Haiyue <haiyue.wang@intel.com>
> Cc: dev@dpdk.org; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>
> Subject: Re: [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode
>
> On 03/09, Haiyue Wang wrote:
> >A new DCF PMD will be introduced, which runs on Intel VF hardware, and
> >it is a pure software design to control the advance functionality (such
> >as switch, ACL) for rest of the VFs.
> >
> >So if the DCF (Device Config Function) mode is specified by the devarg
> >'cap=dcf', then it will stop the PCI probe in the iavf PMD.
> >
> >Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
> >---
> > drivers/net/iavf/iavf_ethdev.c | 41 ++++++++++++++++++++++++++++++++++
> > 1 file changed, 41 insertions(+)
> >
> >diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
> >index 34913f9c4..8ff26c0e7 100644
> >--- a/drivers/net/iavf/iavf_ethdev.c
> >+++ b/drivers/net/iavf/iavf_ethdev.c
> >@@ -1416,9 +1416,49 @@ iavf_dev_uninit(struct rte_eth_dev *dev)
> > return 0;
> > }
> >
> >+static int
> >+handle_dcf_arg(__rte_unused const char *key, const char *value,
> >+ __rte_unused void *arg)
> >+{
> >+ bool *dcf = arg;
> >+
> >+ if (arg == NULL || value == NULL)
> >+ return -EINVAL;
> >+
> >+ if (strcmp(value, "dcf") == 0)
> >+ *dcf = true;
> >+ else
> >+ *dcf = false;
> >+
> >+ return 0;
> >+}
> >+
> >+static bool
> >+check_cap_dcf_enable(struct rte_devargs *devargs)
> >+{
> >+ struct rte_kvargs *kvlist;
> >+ bool enable = false;
> >+
> >+ if (devargs == NULL)
> >+ return false;
> >+
> >+ kvlist = rte_kvargs_parse(devargs->args, NULL);
> >+ if (kvlist == NULL)
> >+ return false;
> >+
> >+ rte_kvargs_process(kvlist, "cap", handle_dcf_arg, &enable);
>
> Need error handling for failure case.
>
We just need the 'cap=dcf' to check whether it is true, by default
'enable=false' can handle all the cases. ;-)
> >+
> >+ rte_kvargs_free(kvlist);
> >+
> >+ return enable;
> >+}
> >+
> > static int eth_iavf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
> > struct rte_pci_device *pci_dev)
> > {
> >+ if (check_cap_dcf_enable(pci_dev->device.devargs))
> >+ return 1; /* continue to probe */
>
> This comment is confusing...
Yes, it should be like 'stop this driver probe to scan the next one'.
>
> >+
> > return rte_eth_dev_pci_generic_probe(pci_dev,
> > sizeof(struct iavf_adapter), iavf_dev_init);
> > }
> >@@ -1439,6 +1479,7 @@ static struct rte_pci_driver rte_iavf_pmd = {
> > RTE_PMD_REGISTER_PCI(net_iavf, rte_iavf_pmd);
> > RTE_PMD_REGISTER_PCI_TABLE(net_iavf, pci_id_iavf_map);
> > RTE_PMD_REGISTER_KMOD_DEP(net_iavf, "* igb_uio | vfio-pci");
> >+RTE_PMD_REGISTER_PARAM_STRING(net_iavf, "cap=dcf");
> > RTE_INIT(iavf_init_log)
> > {
> > iavf_logtype_init = rte_log_register("pmd.net.iavf.init");
> >--
> >2.25.1
> >
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode
2020-03-10 2:19 ` Wang, Haiyue
@ 2020-03-10 3:37 ` Ye Xiaolong
2020-03-10 4:26 ` Wang, Haiyue
0 siblings, 1 reply; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-10 3:37 UTC (permalink / raw)
To: Wang, Haiyue; +Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei
On 03/10, Wang, Haiyue wrote:
>> -----Original Message-----
>> From: Ye, Xiaolong <xiaolong.ye@intel.com>
>> Sent: Monday, March 9, 2020 23:38
>> To: Wang, Haiyue <haiyue.wang@intel.com>
>> Cc: dev@dpdk.org; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
>> Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>
>> Subject: Re: [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode
>>
>> On 03/09, Haiyue Wang wrote:
>> >A new DCF PMD will be introduced, which runs on Intel VF hardware, and
>> >it is a pure software design to control the advance functionality (such
>> >as switch, ACL) for rest of the VFs.
>> >
>> >So if the DCF (Device Config Function) mode is specified by the devarg
>> >'cap=dcf', then it will stop the PCI probe in the iavf PMD.
>> >
>> >Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
>> >---
>> > drivers/net/iavf/iavf_ethdev.c | 41 ++++++++++++++++++++++++++++++++++
>> > 1 file changed, 41 insertions(+)
>> >
>> >diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
>> >index 34913f9c4..8ff26c0e7 100644
>> >--- a/drivers/net/iavf/iavf_ethdev.c
>> >+++ b/drivers/net/iavf/iavf_ethdev.c
>> >@@ -1416,9 +1416,49 @@ iavf_dev_uninit(struct rte_eth_dev *dev)
>> > return 0;
>> > }
>> >
>> >+static int
>> >+handle_dcf_arg(__rte_unused const char *key, const char *value,
>> >+ __rte_unused void *arg)
>> >+{
>> >+ bool *dcf = arg;
>> >+
>> >+ if (arg == NULL || value == NULL)
>> >+ return -EINVAL;
>> >+
>> >+ if (strcmp(value, "dcf") == 0)
>> >+ *dcf = true;
>> >+ else
>> >+ *dcf = false;
>> >+
>> >+ return 0;
>> >+}
>> >+
>> >+static bool
>> >+check_cap_dcf_enable(struct rte_devargs *devargs)
>> >+{
>> >+ struct rte_kvargs *kvlist;
>> >+ bool enable = false;
>> >+
>> >+ if (devargs == NULL)
>> >+ return false;
>> >+
>> >+ kvlist = rte_kvargs_parse(devargs->args, NULL);
>> >+ if (kvlist == NULL)
>> >+ return false;
>> >+
>> >+ rte_kvargs_process(kvlist, "cap", handle_dcf_arg, &enable);
>>
>> Need error handling for failure case.
>>
>
>We just need the 'cap=dcf' to check whether it is true, by default
>'enable=false' can handle all the cases. ;-)
>
Yes, from function point of view, this could work. But it is still good practice
to check the return value of the function.
Thanks,
Xiaolong
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 3/4] net/ice: add the DCF framework
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 3/4] net/ice: add the DCF framework Haiyue Wang
@ 2020-03-10 4:17 ` Ye Xiaolong
2020-03-10 5:09 ` Wang, Haiyue
0 siblings, 1 reply; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-10 4:17 UTC (permalink / raw)
To: Haiyue Wang; +Cc: dev, qi.z.zhang, qiming.yang, beilei.xing, wei.zhao1
On 03/09, Haiyue Wang wrote:
>The DCF (Device Config Function) feature works as a standalone PMD, its
>hardware entity is the trusted VF with ID 0, and the software function
>is to control the flow setting of other VFs by the mailbox with PF.
>
>It doesn't handle packet Rx/Tx related things. This PMD needs the iAVF
>virtchnl to send the ICE PF's AdminQ command.
>
>Also for security, it needs to acquire the DCF capability from PF. The
>flow related things will be added later, it shares most of the ICE flow
>function. This mainly handles hardware initialization etc.
>
> .-------------.
> .-| |
> .-| | |
> | | | iAVF PMD |
> | | | |
> | | | |
> | | '-------------'
> | '-------------'
> '-------------'
> ^ Other VFs
> /
> / Flow Distribution
> .------------------. /
> | |/ DCF cap req .-------------.
> | CVL . <---------- | |
> | Kernel | ----------> | |
> . . DCF cap rsp | DCF PMD |
> | | | |
> '------------------' <----------- | |
> rte_flow '-------------'
> VF0
It'd be clearer if this diagram keeps `DCF PMD` and `iAVF PMD` at the same
level and `CVL Kernel` at the bottom, what do you think?
>
>Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
>---
> doc/guides/nics/ice.rst | 47 +++
> doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> drivers/common/Makefile | 1 +
> drivers/net/ice/Makefile | 6 +
> drivers/net/ice/ice_dcf.c | 651 +++++++++++++++++++++++++++++++
> drivers/net/ice/ice_dcf.h | 61 +++
> drivers/net/ice/ice_dcf_ethdev.c | 319 +++++++++++++++
> drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> drivers/net/ice/ice_dcf_parent.c | 348 +++++++++++++++++
> drivers/net/ice/meson.build | 8 +-
> mk/rte.app.mk | 1 +
> 11 files changed, 1473 insertions(+), 2 deletions(-)
> create mode 100644 doc/guides/nics/img/ice_dcf.png
> create mode 100644 drivers/net/ice/ice_dcf.c
> create mode 100644 drivers/net/ice/ice_dcf.h
> create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
> create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
> create mode 100644 drivers/net/ice/ice_dcf_parent.c
>
>diff --git a/drivers/common/Makefile b/drivers/common/Makefile
>index 96bd7ac6e..df2e840cf 100644
>--- a/drivers/common/Makefile
>+++ b/drivers/common/Makefile
>@@ -31,6 +31,7 @@ DIRS-y += dpaax
> endif
>
> IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
>+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
> ifneq (,$(findstring y,$(IAVF-y)))
> DIRS-y += iavf
> endif
>diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
>index e22c34287..643639a50 100644
>--- a/drivers/net/ice/Makefile
>+++ b/drivers/net/ice/Makefile
>@@ -11,9 +11,11 @@ LIB = librte_pmd_ice.a
> CFLAGS += -O3
> CFLAGS += $(WERROR_FLAGS)
> CFLAGS += -DALLOW_EXPERIMENTAL_API
>+CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
>
> LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
> LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
>+LDLIBS += -lrte_net -lrte_common_iavf
>
> EXPORT_MAP := rte_pmd_ice_version.map
>
>@@ -84,6 +86,10 @@ ifeq ($(CC_AVX2_SUPPORT), 1)
> endif
> SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
>
>+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
>+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_parent.c
>+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
>+
> # install this header file
> SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
>
>diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
>new file mode 100644
>index 000000000..669122331
>--- /dev/null
>+++ b/drivers/net/ice/ice_dcf.c
>@@ -0,0 +1,651 @@
>+/* SPDX-License-Identifier: BSD-3-Clause
>+ * Copyright(c) 2019 Intel Corporation
Should be 2020?
>+ */
>+
>+#include <sys/queue.h>
>+#include <stdio.h>
>+#include <errno.h>
>+#include <stdint.h>
>+#include <string.h>
>+#include <unistd.h>
>+#include <stdarg.h>
>+#include <inttypes.h>
>+#include <rte_byteorder.h>
>+#include <rte_common.h>
>+
>+#include <rte_pci.h>
>+#include <rte_atomic.h>
>+#include <rte_eal.h>
>+#include <rte_ether.h>
>+#include <rte_ethdev_driver.h>
>+#include <rte_ethdev_pci.h>
>+#include <rte_malloc.h>
>+#include <rte_memzone.h>
>+#include <rte_dev.h>
>+
>+#include "ice_dcf.h"
>+
>+#define ICE_DCF_AQ_LEN 32
>+#define ICE_DCF_AQ_BUF_SZ 4096
>+
>+#define ICE_DCF_ARQ_MAX_RETRIES 200
>+#define ICE_DCF_ARQ_CHECK_TIME 2 /* msecs */
>+
>+#define ICE_DCF_VF_RES_BUF_SZ \
>+ (sizeof(struct virtchnl_vf_resource) + \
>+ IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource))
>+
>+static __rte_always_inline int
>+ice_dcf_send_cmd_req_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
>+ uint8_t *req_msg, uint16_t req_msglen)
>+{
>+ return iavf_aq_send_msg_to_pf(&hw->avf, op, IAVF_SUCCESS,
>+ req_msg, req_msglen, NULL);
>+}
>+
>+static int
>+ice_dcf_recv_cmd_rsp_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
>+ uint8_t *rsp_msgbuf, uint16_t rsp_buflen,
>+ uint16_t *rsp_msglen)
>+{
>+ struct iavf_arq_event_info event;
>+ enum virtchnl_ops v_op;
>+ int i = 0;
>+ int err;
>+
>+ event.buf_len = rsp_buflen;
>+ event.msg_buf = rsp_msgbuf;
>+
>+ do {
>+ err = iavf_clean_arq_element(&hw->avf, &event, NULL);
>+ if (err != IAVF_SUCCESS)
>+ goto again;
>+
>+ v_op = rte_le_to_cpu_32(event.desc.cookie_high);
>+ if (v_op != op)
>+ goto again;
>+
>+ if (rsp_msglen != NULL)
>+ *rsp_msglen = event.msg_len;
>+ return rte_le_to_cpu_32(event.desc.cookie_low);
>+
>+again:
>+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
>+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
>+
>+ return -EIO;
>+}
>+
>+static __rte_always_inline void
>+ice_dcf_aq_cmd_clear(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
>+{
>+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
>+
>+ TAILQ_REMOVE(&hw->vc_cmd_queue, cmd, next);
>+
>+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
>+}
>+
>+static __rte_always_inline void
>+ice_dcf_vc_cmd_set(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
>+{
>+ cmd->v_ret = IAVF_ERR_NOT_READY;
>+ cmd->rsp_msglen = 0;
>+ cmd->pending = 1;
>+
>+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
>+
>+ TAILQ_INSERT_TAIL(&hw->vc_cmd_queue, cmd, next);
>+
>+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
>+}
>+
>+static __rte_always_inline int
>+ice_dcf_vc_cmd_send(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
>+{
>+ return iavf_aq_send_msg_to_pf(&hw->avf,
>+ cmd->v_op, IAVF_SUCCESS,
>+ cmd->req_msg, cmd->req_msglen, NULL);
>+}
>+
>+static __rte_always_inline void
>+ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
>+{
>+ struct dcf_virtchnl_cmd *cmd;
>+ enum virtchnl_ops v_op;
>+ enum iavf_status v_ret;
>+ uint16_t aq_op;
>+
>+ aq_op = rte_le_to_cpu_16(info->desc.opcode);
>+ if (unlikely(aq_op != iavf_aqc_opc_send_msg_to_vf)) {
>+ PMD_DRV_LOG(ERR,
>+ "Request %u is not supported yet", aq_op);
>+ return;
>+ }
>+
>+ v_op = rte_le_to_cpu_32(info->desc.cookie_high);
>+ if (unlikely(v_op == VIRTCHNL_OP_EVENT)) {
>+ if (hw->vc_event_msg_cb != NULL)
>+ hw->vc_event_msg_cb(hw,
>+ info->msg_buf,
>+ info->msg_len);
>+ return;
>+ }
>+
>+ v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
>+
>+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
>+
>+ TAILQ_FOREACH(cmd, &hw->vc_cmd_queue, next) {
>+ if (cmd->v_op == v_op && cmd->pending) {
>+ cmd->v_ret = v_ret;
>+ cmd->rsp_msglen = RTE_MIN(info->msg_len,
>+ cmd->rsp_buflen);
>+ if (likely(cmd->rsp_msglen != 0))
>+ rte_memcpy(cmd->rsp_msgbuf, info->msg_buf,
>+ cmd->rsp_msglen);
>+
>+ /* prevent compiler reordering */
>+ rte_compiler_barrier();
>+ cmd->pending = 0;
>+ break;
>+ }
>+ }
>+
>+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
>+}
>+
>+static void
>+ice_dcf_handle_virtchnl_msg(struct ice_dcf_hw *hw)
>+{
>+ struct iavf_arq_event_info info;
>+ uint16_t pending = 1;
>+ int ret;
>+
>+ info.buf_len = ICE_DCF_AQ_BUF_SZ;
>+ info.msg_buf = hw->arq_buf;
>+
>+ while (pending) {
>+ ret = iavf_clean_arq_element(&hw->avf, &info, &pending);
>+ if (ret != IAVF_SUCCESS)
>+ break;
>+
>+ ice_dcf_aq_cmd_handle(hw, &info);
>+ }
>+}
>+
>+static int
>+ice_dcf_init_check_api_version(struct ice_dcf_hw *hw)
>+{
>+#define ICE_CPF_VIRTCHNL_VERSION_MAJOR_START 1
>+#define ICE_CPF_VIRTCHNL_VERSION_MINOR_START 1
>+ struct virtchnl_version_info version, *pver;
>+ int err;
>+
>+ version.major = VIRTCHNL_VERSION_MAJOR;
>+ version.minor = VIRTCHNL_VERSION_MINOR;
>+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_VERSION,
>+ (uint8_t *)&version, sizeof(version));
>+ if (err) {
>+ PMD_INIT_LOG(ERR, "Fail to send OP_VERSION");
>+ return err;
>+ }
>+
>+ pver = &hw->virtchnl_version;
>+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_VERSION,
>+ (uint8_t *)pver, sizeof(*pver), NULL);
>+ if (err) {
>+ PMD_INIT_LOG(ERR, "Fail to get response of OP_VERSION");
>+ return -1;
>+ }
>+
>+ PMD_DRV_LOG(DEBUG,
>+ "Peer PF API version: %u.%u", pver->major, pver->minor);
PMD_INIT_LOG
>+
>+ if (pver->major < ICE_CPF_VIRTCHNL_VERSION_MAJOR_START ||
>+ (pver->major == ICE_CPF_VIRTCHNL_VERSION_MAJOR_START &&
>+ pver->minor < ICE_CPF_VIRTCHNL_VERSION_MINOR_START)) {
>+ PMD_INIT_LOG(ERR,
>+ "VIRTCHNL API version should not be lower than (%u.%u)",
>+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START,
>+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START);
>+ return -1;
>+ } else if (pver->major > VIRTCHNL_VERSION_MAJOR ||
>+ (pver->major == VIRTCHNL_VERSION_MAJOR &&
>+ pver->minor > VIRTCHNL_VERSION_MINOR)) {
>+ PMD_INIT_LOG(ERR,
>+ "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
>+ pver->major, pver->minor,
>+ VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
>+ return -1;
>+ }
>+
>+ PMD_DRV_LOG(DEBUG, "Peer is supported PF host");
PMD_INIT_LOG
>+
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
>+{
>+ uint32_t caps;
>+ int err, i;
>+
>+ caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
>+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED | VIRTCHNL_VF_CAP_DCF |
>+ VF_BASE_MODE_OFFLOADS;
>+
>+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
>+ (uint8_t *)&caps, sizeof(caps));
>+ if (err) {
>+ PMD_DRV_LOG(ERR, "Fail to send msg OP_GET_VF_RESOURCE");
>+ return err;
>+ }
>+
>+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
>+ (uint8_t *)hw->vf_res,
>+ ICE_DCF_VF_RES_BUF_SZ, NULL);
>+ if (err) {
>+ PMD_DRV_LOG(ERR, "Fail to get response of OP_GET_VF_RESOURCE");
>+ return -1;
>+ }
>+
>+ iavf_vf_parse_hw_config(&hw->avf, hw->vf_res);
>+
>+ hw->vsi_res = NULL;
>+ for (i = 0; i < hw->vf_res->num_vsis; i++) {
>+ if (hw->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
>+ hw->vsi_res = &hw->vf_res->vsi_res[i];
>+ }
>+
>+ if (!hw->vsi_res) {
>+ PMD_DRV_LOG(ERR, "no LAN VSI found");
>+ return -1;
>+ }
>+
>+ hw->vsi_id = hw->vsi_res->vsi_id;
>+ PMD_DRV_LOG(DEBUG, "VSI ID is %u", hw->vsi_id);
>+
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_get_vf_vsi_map(struct ice_dcf_hw *hw)
>+{
>+ struct virtchnl_dcf_vsi_map *vsi_map;
>+ uint16_t len;
>+ int err;
>+
>+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
>+ NULL, 0);
>+ if (err) {
>+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_GET_VSI_MAP");
>+ return err;
>+ }
>+
>+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
>+ hw->arq_buf, ICE_DCF_AQ_BUF_SZ,
>+ &len);
>+ if (err) {
>+ PMD_DRV_LOG(ERR, "Fail to get response of OP_DCF_GET_VSI_MAP");
>+ return err;
>+ }
>+
>+ vsi_map = (struct virtchnl_dcf_vsi_map *)hw->arq_buf;
>+ if (len < sizeof(*vsi_map) || !vsi_map->num_vfs ||
>+ len < sizeof(*vsi_map) +
>+ (vsi_map->num_vfs - 1) * sizeof(vsi_map->vf_vsi[0])) {
>+ PMD_DRV_LOG(ERR, "invalid vf vsi map response with length %u",
>+ len);
>+ return -EINVAL;
>+ }
>+
>+ if (hw->num_vfs != 0 && hw->num_vfs != vsi_map->num_vfs) {
>+ PMD_DRV_LOG(ERR, "The number VSI map (%u) doesn't match the number of VFs (%u)",
>+ vsi_map->num_vfs, hw->num_vfs);
>+ return -EINVAL;
>+ }
>+
>+ len = vsi_map->num_vfs * sizeof(vsi_map->vf_vsi[0]);
>+ if (!hw->vf_vsi_map) {
>+ hw->num_vfs = vsi_map->num_vfs;
>+ hw->vf_vsi_map = rte_zmalloc("vf_vsi_ctx", len, 0);
>+ }
>+
>+ if (!hw->vf_vsi_map) {
>+ PMD_DRV_LOG(ERR, "Fail to alloc memory for VSI context");
>+ return -ENOMEM;
>+ }
>+
>+ if (!memcmp(hw->vf_vsi_map, vsi_map->vf_vsi, len)) {
>+ PMD_DRV_LOG(DEBUG, "VF VSI map doesn't change");
>+ return 1;
>+ }
>+
>+ rte_memcpy(hw->vf_vsi_map, vsi_map->vf_vsi, len);
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_mode_disable(struct ice_dcf_hw *hw)
>+{
>+ int err;
>+
>+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
>+ NULL, 0);
>+ if (err) {
>+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_DISABLE");
>+ return err;
>+ }
>+
>+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
>+ (uint8_t *)hw->arq_buf,
>+ ICE_DCF_AQ_BUF_SZ, NULL);
>+ if (err) {
>+ PMD_DRV_LOG(ERR,
>+ "Fail to get response of OP_DCF_DISABLE %d",
>+ err);
>+ return -1;
>+ }
>+
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
>+{
>+#define ICE_DCF_RESET_WAIT_CNT 50
>+ struct iavf_hw *avf = &hw->avf;
>+ int i, reset;
>+
>+ for (i = 0; i < ICE_DCF_RESET_WAIT_CNT; i++) {
>+ reset = IAVF_READ_REG(avf, IAVF_VFGEN_RSTAT) &
>+ IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
>+ reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
>+
>+ if (reset == VIRTCHNL_VFR_VFACTIVE ||
>+ reset == VIRTCHNL_VFR_COMPLETED)
>+ break;
>+
>+ rte_delay_ms(20);
>+ }
>+
>+ if (i >= ICE_DCF_RESET_WAIT_CNT)
>+ return -1;
>+
>+ return 0;
>+}
>+
>+static inline void
>+ice_dcf_enable_irq0(struct ice_dcf_hw *hw)
>+{
>+ struct iavf_hw *avf = &hw->avf;
>+
>+ /* Enable admin queue interrupt trigger */
>+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1,
>+ IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
>+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
>+ IAVF_VFINT_DYN_CTL01_INTENA_MASK |
>+ IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
>+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
>+
>+ IAVF_WRITE_FLUSH(avf);
>+}
>+
>+static inline void
>+ice_dcf_disable_irq0(struct ice_dcf_hw *hw)
>+{
>+ struct iavf_hw *avf = &hw->avf;
>+
>+ /* Disable all interrupt types */
>+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1, 0);
>+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
>+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
>+
>+ IAVF_WRITE_FLUSH(avf);
>+}
>+
>+static void
>+ice_dcf_dev_interrupt_handler(void *param)
>+{
>+ struct ice_dcf_hw *hw = param;
>+
>+ ice_dcf_disable_irq0(hw);
>+
>+ ice_dcf_handle_virtchnl_msg(hw);
>+
>+ ice_dcf_enable_irq0(hw);
>+}
>+
>+int
>+ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
>+ struct dcf_virtchnl_cmd *cmd)
>+{
>+ int i = 0;
>+ int err;
>+
>+ if ((cmd->req_msg && !cmd->req_msglen) ||
>+ (!cmd->req_msg && cmd->req_msglen) ||
>+ (cmd->rsp_msgbuf && !cmd->rsp_buflen) ||
>+ (!cmd->rsp_msgbuf && cmd->rsp_buflen))
>+ return -EINVAL;
>+
>+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
>+ ice_dcf_vc_cmd_set(hw, cmd);
>+
>+ err = ice_dcf_vc_cmd_send(hw, cmd);
>+ if (err) {
>+ PMD_DRV_LOG(ERR, "fail to send cmd %d", cmd->v_op);
>+ goto ret;
>+ }
>+
>+ do {
>+ if (!cmd->pending)
>+ break;
>+
>+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
>+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
>+
>+ if (cmd->v_ret != IAVF_SUCCESS) {
>+ err = -1;
>+ PMD_DRV_LOG(ERR,
>+ "No response (%d times) or return failure (%d) for cmd %d",
>+ i, cmd->v_ret, cmd->v_op);
>+ }
>+
>+ret:
>+ ice_dcf_aq_cmd_clear(hw, cmd);
>+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
>+ return err;
>+}
>+
>+int
>+ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
>+ void *buf, uint16_t buf_size)
>+{
>+ struct dcf_virtchnl_cmd desc_cmd, buff_cmd;
>+ struct ice_dcf_hw *hw = dcf_hw;
>+ int err = 0;
>+ int i = 0;
>+
>+ if ((buf && !buf_size) || (!buf && buf_size) ||
>+ buf_size > ICE_DCF_AQ_BUF_SZ)
>+ return -EINVAL;
>+
>+ desc_cmd.v_op = VIRTCHNL_OP_DCF_CMD_DESC;
>+ desc_cmd.req_msglen = sizeof(*desc);
>+ desc_cmd.req_msg = (uint8_t *)desc;
>+ desc_cmd.rsp_buflen = sizeof(*desc);
>+ desc_cmd.rsp_msgbuf = (uint8_t *)desc;
>+
>+ if (buf == NULL)
>+ return ice_dcf_execute_virtchnl_cmd(hw, &desc_cmd);
>+
>+ desc->flags |= rte_cpu_to_le_16(ICE_AQ_FLAG_BUF);
>+
>+ buff_cmd.v_op = VIRTCHNL_OP_DCF_CMD_BUFF;
>+ buff_cmd.req_msglen = buf_size;
>+ buff_cmd.req_msg = buf;
>+ buff_cmd.rsp_buflen = buf_size;
>+ buff_cmd.rsp_msgbuf = buf;
>+
>+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
>+ ice_dcf_vc_cmd_set(hw, &desc_cmd);
>+ ice_dcf_vc_cmd_set(hw, &buff_cmd);
>+
>+ if (ice_dcf_vc_cmd_send(hw, &desc_cmd) ||
>+ ice_dcf_vc_cmd_send(hw, &buff_cmd)) {
>+ err = -1;
>+ PMD_DRV_LOG(ERR, "fail to send OP_DCF_CMD_DESC/BUFF");
>+ goto ret;
>+ }
>+
>+ do {
>+ if ((!desc_cmd.pending && !buff_cmd.pending) ||
>+ (!desc_cmd.pending && desc_cmd.v_ret != IAVF_SUCCESS) ||
>+ (!buff_cmd.pending && buff_cmd.v_ret != IAVF_SUCCESS))
>+ break;
>+
>+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
>+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
>+
>+ if (desc_cmd.v_ret != IAVF_SUCCESS || buff_cmd.v_ret != IAVF_SUCCESS) {
>+ err = -1;
>+ PMD_DRV_LOG(ERR,
>+ "No response (%d times) or return failure (desc: %d / buff: %d)",
>+ i, desc_cmd.v_ret, buff_cmd.v_ret);
>+ }
>+
>+ret:
>+ ice_dcf_aq_cmd_clear(hw, &desc_cmd);
>+ ice_dcf_aq_cmd_clear(hw, &buff_cmd);
>+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
>+
>+ return err;
>+}
>+
>+int
>+ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw)
>+{
>+ int err = 0;
>+
>+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
>+ ice_dcf_disable_irq0(hw);
>+
>+ if (ice_dcf_get_vf_resource(hw) || ice_dcf_get_vf_vsi_map(hw))
>+ err = -1;
>+
>+ ice_dcf_enable_irq0(hw);
>+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
>+
>+ return err;
>+}
>+
>+int
>+ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
>+{
>+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
>+ int ret;
>+
>+ hw->avf.hw_addr = pci_dev->mem_resource[0].addr;
>+ hw->avf.back = hw;
>+
>+ hw->avf.bus.bus_id = pci_dev->addr.bus;
>+ hw->avf.bus.device = pci_dev->addr.devid;
>+ hw->avf.bus.func = pci_dev->addr.function;
>+
>+ hw->avf.device_id = pci_dev->id.device_id;
>+ hw->avf.vendor_id = pci_dev->id.vendor_id;
>+ hw->avf.subsystem_device_id = pci_dev->id.subsystem_device_id;
>+ hw->avf.subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
>+
>+ hw->avf.aq.num_arq_entries = ICE_DCF_AQ_LEN;
>+ hw->avf.aq.num_asq_entries = ICE_DCF_AQ_LEN;
>+ hw->avf.aq.arq_buf_size = ICE_DCF_AQ_BUF_SZ;
>+ hw->avf.aq.asq_buf_size = ICE_DCF_AQ_BUF_SZ;
>+
>+ rte_spinlock_init(&hw->vc_cmd_send_lock);
>+ rte_spinlock_init(&hw->vc_cmd_queue_lock);
>+ TAILQ_INIT(&hw->vc_cmd_queue);
>+
>+ hw->arq_buf = rte_zmalloc("arq_buf", ICE_DCF_AQ_BUF_SZ, 0);
>+ if (hw->arq_buf == NULL) {
>+ PMD_INIT_LOG(ERR, "unable to allocate AdminQ buffer memory");
>+ goto err;
>+ }
>+
>+ ret = iavf_set_mac_type(&hw->avf);
>+ if (ret) {
>+ PMD_INIT_LOG(ERR, "set_mac_type failed: %d", ret);
>+ goto err;
>+ }
>+
>+ ret = ice_dcf_check_reset_done(hw);
>+ if (ret) {
>+ PMD_INIT_LOG(ERR, "VF is still resetting");
>+ goto err;
>+ }
>+
>+ ret = iavf_init_adminq(&hw->avf);
>+ if (ret) {
>+ PMD_INIT_LOG(ERR, "init_adminq failed: %d", ret);
>+ goto err;
>+ }
>+
>+ if (ice_dcf_init_check_api_version(hw)) {
>+ PMD_INIT_LOG(ERR, "check_api version failed");
>+ goto err_api;
>+ }
>+
>+ hw->vf_res = rte_zmalloc("vf_res", ICE_DCF_VF_RES_BUF_SZ, 0);
>+ if (hw->vf_res == NULL) {
>+ PMD_INIT_LOG(ERR, "unable to allocate vf_res memory");
>+ goto err_api;
>+ }
>+
>+ if (ice_dcf_get_vf_resource(hw)) {
>+ PMD_INIT_LOG(ERR, "Failed to get VF resource");
>+ goto err_alloc;
>+ }
>+
>+ if (ice_dcf_get_vf_vsi_map(hw) < 0) {
>+ PMD_INIT_LOG(ERR, "Failed to get VF VSI map");
>+ ice_dcf_mode_disable(hw);
>+ goto err_alloc;
>+ }
>+
>+ rte_intr_callback_register(&pci_dev->intr_handle,
>+ ice_dcf_dev_interrupt_handler, hw);
>+ rte_intr_enable(&pci_dev->intr_handle);
>+ ice_dcf_enable_irq0(hw);
>+
>+ return 0;
>+
>+err_alloc:
>+ rte_free(hw->vf_res);
>+err_api:
>+ iavf_shutdown_adminq(&hw->avf);
>+err:
>+ rte_free(hw->arq_buf);
>+
>+ return -1;
>+}
>+
>+void
>+ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
>+{
>+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
>+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
>+
>+ ice_dcf_disable_irq0(hw);
>+ rte_intr_disable(intr_handle);
>+ rte_intr_callback_unregister(intr_handle,
>+ ice_dcf_dev_interrupt_handler, hw);
>+
>+ ice_dcf_mode_disable(hw);
>+ iavf_shutdown_adminq(&hw->avf);
>+
>+ rte_free(hw->arq_buf);
>+ rte_free(hw->vf_vsi_map);
>+ rte_free(hw->vf_res);
>+}
>diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
>new file mode 100644
>index 000000000..58647d87f
>--- /dev/null
>+++ b/drivers/net/ice/ice_dcf.h
>@@ -0,0 +1,61 @@
>+/* SPDX-License-Identifier: BSD-3-Clause
>+ * Copyright(c) 2019 Intel Corporation
>+ */
>+
>+#ifndef _ICE_DCF_H_
>+#define _ICE_DCF_H_
>+
>+#include <rte_ethdev_driver.h>
>+
>+#include <iavf_prototype.h>
>+#include <iavf_adminq_cmd.h>
>+#include <iavf_type.h>
>+
>+#include "base/ice_type.h"
>+#include "ice_logs.h"
>+
>+struct dcf_virtchnl_cmd {
>+ TAILQ_ENTRY(dcf_virtchnl_cmd) next;
>+
>+ enum virtchnl_ops v_op;
>+ enum iavf_status v_ret;
>+
>+ uint16_t req_msglen;
>+ uint8_t *req_msg;
>+
>+ uint16_t rsp_msglen;
>+ uint16_t rsp_buflen;
>+ uint8_t *rsp_msgbuf;
>+
>+ volatile int pending;
>+};
>+
>+struct ice_dcf_hw {
>+ struct iavf_hw avf;
>+
>+ rte_spinlock_t vc_cmd_send_lock;
>+ rte_spinlock_t vc_cmd_queue_lock;
>+ TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
>+ void (*vc_event_msg_cb)(struct ice_dcf_hw *dcf_hw,
>+ uint8_t *msg, uint16_t msglen);
>+
>+ uint8_t *arq_buf;
>+
>+ uint16_t num_vfs;
>+ uint16_t *vf_vsi_map;
>+
>+ struct virtchnl_version_info virtchnl_version;
>+ struct virtchnl_vf_resource *vf_res; /* VF resource */
>+ struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
>+ uint16_t vsi_id;
>+};
>+
>+int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
>+ struct dcf_virtchnl_cmd *cmd);
>+int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
>+ void *buf, uint16_t buf_size);
>+int ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw);
>+int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
>+void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
>+
>+#endif /* _ICE_DCF_H_ */
>diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
>new file mode 100644
>index 000000000..f65b962d4
>--- /dev/null
>+++ b/drivers/net/ice/ice_dcf_ethdev.c
>@@ -0,0 +1,319 @@
>+/* SPDX-License-Identifier: BSD-3-Clause
>+ * Copyright(c) 2019 Intel Corporation
>+ */
>+
>+#include <errno.h>
>+#include <stdbool.h>
>+#include <sys/types.h>
>+#include <sys/ioctl.h>
>+#include <unistd.h>
>+
>+#include <rte_interrupts.h>
>+#include <rte_debug.h>
>+#include <rte_pci.h>
>+#include <rte_atomic.h>
>+#include <rte_eal.h>
>+#include <rte_ether.h>
>+#include <rte_ethdev_pci.h>
>+#include <rte_kvargs.h>
>+#include <rte_malloc.h>
>+#include <rte_memzone.h>
>+#include <rte_dev.h>
>+
>+#include <iavf_devids.h>
>+
>+#include "ice_generic_flow.h"
>+#include "ice_dcf_ethdev.h"
>+
>+static uint16_t
>+ice_dcf_recv_pkts(__rte_unused void *rx_queue,
>+ __rte_unused struct rte_mbuf **bufs,
>+ __rte_unused uint16_t nb_pkts)
>+{
>+ return 0;
>+}
>+
>+static uint16_t
>+ice_dcf_xmit_pkts(__rte_unused void *tx_queue,
>+ __rte_unused struct rte_mbuf **bufs,
>+ __rte_unused uint16_t nb_pkts)
>+{
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_dev_start(struct rte_eth_dev *dev)
>+{
>+ dev->data->dev_link.link_status = ETH_LINK_UP;
>+
>+ return 0;
>+}
>+
>+static void
>+ice_dcf_dev_stop(struct rte_eth_dev *dev)
>+{
>+ dev->data->dev_link.link_status = ETH_LINK_DOWN;
>+}
>+
>+static int
>+ice_dcf_dev_configure(__rte_unused struct rte_eth_dev *dev)
>+{
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_dev_info_get(struct rte_eth_dev *dev,
>+ struct rte_eth_dev_info *dev_info)
>+{
>+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
>+
>+ dev_info->max_mac_addrs = 1;
>+ dev_info->max_rx_pktlen = (uint32_t)-1;
>+ dev_info->max_rx_queues = RTE_DIM(adapter->rxqs);
>+ dev_info->max_tx_queues = RTE_DIM(adapter->txqs);
>+
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_stats_get(__rte_unused struct rte_eth_dev *dev,
>+ __rte_unused struct rte_eth_stats *igb_stats)
>+{
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_stats_reset(__rte_unused struct rte_eth_dev *dev)
>+{
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_dev_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
>+{
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_dev_promiscuous_disable(__rte_unused struct rte_eth_dev *dev)
>+{
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_dev_allmulticast_enable(__rte_unused struct rte_eth_dev *dev)
>+{
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_dev_allmulticast_disable(__rte_unused struct rte_eth_dev *dev)
>+{
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
>+ enum rte_filter_type filter_type,
>+ __rte_unused enum rte_filter_op filter_op,
>+ __rte_unused void *arg)
>+{
legacy filter API will be deprecated, I think we should avoid adding support
in new PMD.
>+ int ret = 0;
>+
>+ if (!dev)
>+ return -EINVAL;
>+
>+ switch (filter_type) {
>+ default:
>+ PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
>+ filter_type);
>+ ret = -EINVAL;
>+ break;
>+ }
>+
>+ return ret;
>+}
>+
>+static void
>+ice_dcf_dev_close(struct rte_eth_dev *dev)
>+{
>+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
>+
>+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
>+ return;
>+
>+ dev->dev_ops = NULL;
>+ dev->rx_pkt_burst = NULL;
>+ dev->tx_pkt_burst = NULL;
>+
>+ ice_dcf_uninit_parent_adapter(dev);
>+ ice_dcf_uninit_hw(dev, &adapter->real_hw);
>+}
>+
>+static void
>+ice_dcf_queue_release(__rte_unused void *q)
>+{
>+}
>+
>+static int
>+ice_dcf_link_update(__rte_unused struct rte_eth_dev *dev,
>+ __rte_unused int wait_to_complete)
>+{
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_rx_queue_setup(struct rte_eth_dev *dev,
>+ uint16_t rx_queue_id,
>+ __rte_unused uint16_t nb_rx_desc,
>+ __rte_unused unsigned int socket_id,
>+ __rte_unused const struct rte_eth_rxconf *rx_conf,
>+ __rte_unused struct rte_mempool *mb_pool)
>+{
>+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
>+
>+ dev->data->rx_queues[rx_queue_id] = &adapter->rxqs[rx_queue_id];
>+
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_tx_queue_setup(struct rte_eth_dev *dev,
>+ uint16_t tx_queue_id,
>+ __rte_unused uint16_t nb_tx_desc,
>+ __rte_unused unsigned int socket_id,
>+ __rte_unused const struct rte_eth_txconf *tx_conf)
>+{
>+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
>+
>+ dev->data->tx_queues[tx_queue_id] = &adapter->txqs[tx_queue_id];
>+
>+ return 0;
>+}
>+
>+static const struct eth_dev_ops ice_dcf_eth_dev_ops = {
>+ .dev_start = ice_dcf_dev_start,
>+ .dev_stop = ice_dcf_dev_stop,
>+ .dev_close = ice_dcf_dev_close,
>+ .dev_configure = ice_dcf_dev_configure,
>+ .dev_infos_get = ice_dcf_dev_info_get,
>+ .rx_queue_setup = ice_dcf_rx_queue_setup,
>+ .tx_queue_setup = ice_dcf_tx_queue_setup,
>+ .rx_queue_release = ice_dcf_queue_release,
>+ .tx_queue_release = ice_dcf_queue_release,
>+ .link_update = ice_dcf_link_update,
>+ .stats_get = ice_dcf_stats_get,
>+ .stats_reset = ice_dcf_stats_reset,
>+ .promiscuous_enable = ice_dcf_dev_promiscuous_enable,
>+ .promiscuous_disable = ice_dcf_dev_promiscuous_disable,
>+ .allmulticast_enable = ice_dcf_dev_allmulticast_enable,
>+ .allmulticast_disable = ice_dcf_dev_allmulticast_disable,
>+ .filter_ctrl = ice_dcf_dev_filter_ctrl,
>+};
>+
>+static int
>+ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
>+{
>+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
>+
>+ eth_dev->dev_ops = &ice_dcf_eth_dev_ops;
>+ eth_dev->rx_pkt_burst = ice_dcf_recv_pkts;
>+ eth_dev->tx_pkt_burst = ice_dcf_xmit_pkts;
>+
>+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
>+ return 0;
>+
>+ eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
>+
>+ adapter->real_hw.vc_event_msg_cb = ice_dcf_handle_pf_event_msg;
>+ if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
>+ PMD_DRV_LOG(ERR, "Failed to init DCF hardware");
Use PMD_INIT_LOG instead.
>+ return -1;
>+ }
>+
>+ if (ice_dcf_init_parent_adapter(eth_dev) != 0) {
>+ PMD_DRV_LOG(ERR, "Failed to init DCF parent adapter");
Use PMD_INIT_LOG instead.
>+ ice_dcf_uninit_hw(eth_dev, &adapter->real_hw);
>+ return -1;
>+ }
>+
>+ return 0;
>+}
>+
>+static int
>+ice_dcf_dev_uninit(struct rte_eth_dev *eth_dev)
>+{
>+ ice_dcf_dev_close(eth_dev);
>+
>+ return 0;
>+}
>+
>+static int
>+handle_dcf_arg(__rte_unused const char *key, const char *value,
>+ __rte_unused void *arg)
>+{
>+ bool *dcf = arg;
>+
>+ if (arg == NULL || value == NULL)
>+ return -EINVAL;
>+
>+ if (strcmp(value, "dcf") == 0)
>+ *dcf = true;
>+ else
>+ *dcf = false;
>+
>+ return 0;
>+}
>+
>+static bool
>+check_cap_dcf_enable(struct rte_devargs *devargs)
>+{
>+ struct rte_kvargs *kvlist;
>+ bool enable = false;
>+
>+ if (devargs == NULL)
>+ return false;
>+
>+ kvlist = rte_kvargs_parse(devargs->args, NULL);
>+ if (kvlist == NULL)
>+ return false;
>+
>+ rte_kvargs_process(kvlist, "cap", handle_dcf_arg, &enable);
Need error handing for failure case.
>+
>+ rte_kvargs_free(kvlist);
>+
>+ return enable;
>+}
>+
>+static int eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
>+ struct rte_pci_device *pci_dev)
>+{
>+ if (!check_cap_dcf_enable(pci_dev->device.devargs))
>+ return 1; /* continue to probe */
I think the code is self explanatory, this straightforward comment is unnecessary.
>+
>+ return rte_eth_dev_pci_generic_probe(pci_dev,
>+ sizeof(struct ice_dcf_adapter),
>+ ice_dcf_dev_init);
>+}
>+
>+static int eth_ice_dcf_pci_remove(struct rte_pci_device *pci_dev)
>+{
>+ return rte_eth_dev_pci_generic_remove(pci_dev, ice_dcf_dev_uninit);
>+}
>+
>+static const struct rte_pci_id pci_id_ice_dcf_map[] = {
>+ { RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
>+ { .vendor_id = 0, /* sentinel */ },
>+};
>+
>+static struct rte_pci_driver rte_ice_dcf_pmd = {
>+ .id_table = pci_id_ice_dcf_map,
>+ .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
>+ .probe = eth_ice_dcf_pci_probe,
>+ .remove = eth_ice_dcf_pci_remove,
>+};
>+
>+RTE_PMD_REGISTER_PCI(net_ice_dcf, rte_ice_dcf_pmd);
>+RTE_PMD_REGISTER_PCI_TABLE(net_ice_dcf, pci_id_ice_dcf_map);
>+RTE_PMD_REGISTER_KMOD_DEP(net_ice_dcf, "* igb_uio | vfio-pci");
>+RTE_PMD_REGISTER_PARAM_STRING(net_ice_dcf, "cap=dcf");
>diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
>new file mode 100644
>index 000000000..e95266599
>--- /dev/null
>+++ b/drivers/net/ice/ice_dcf_ethdev.h
>@@ -0,0 +1,33 @@
>+/* SPDX-License-Identifier: BSD-3-Clause
>+ * Copyright(c) 2019 Intel Corporation
>+ */
>+
>+#ifndef _ICE_DCF_ETHDEV_H_
>+#define _ICE_DCF_ETHDEV_H_
>+
>+#include "base/ice_common.h"
>+#include "base/ice_adminq_cmd.h"
>+
>+#include "ice_ethdev.h"
>+#include "ice_dcf.h"
>+
>+#define ICE_DCF_MAX_RINGS 1
>+
>+struct ice_dcf_queue {
>+ uint64_t dummy;
>+};
>+
>+struct ice_dcf_adapter {
>+ struct ice_adapter parent; /* Must be first */
>+
>+ struct ice_dcf_hw real_hw;
>+ struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
>+ struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
>+};
>+
>+void ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
>+ uint8_t *msg, uint16_t msglen);
>+int ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev);
>+void ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev);
>+
>+#endif /* _ICE_DCF_ETHDEV_H_ */
>diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
>new file mode 100644
>index 000000000..bca9cd34a
>--- /dev/null
>+++ b/drivers/net/ice/ice_dcf_parent.c
>@@ -0,0 +1,348 @@
>+/* SPDX-License-Identifier: BSD-3-Clause
>+ * Copyright(c) 2019 Intel Corporation
>+ */
>+#include <sys/types.h>
>+#include <sys/stat.h>
>+#include <unistd.h>
>+
>+#include <rte_alarm.h>
>+
>+#include "ice_dcf_ethdev.h"
>+#include "ice_generic_flow.h"
>+
>+#define ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL 100000 /* us */
>+
>+static __rte_always_inline void
>+ice_dcf_update_vsi_ctx(struct ice_hw *hw, uint16_t vsi_handle,
>+ uint16_t vsi_map)
>+{
>+ struct ice_vsi_ctx *vsi_ctx;
>+
>+ if (unlikely(vsi_handle >= ICE_MAX_VSI)) {
>+ PMD_DRV_LOG(ERR, "Invalid vsi handle %u", vsi_handle);
>+ return;
>+ }
>+
>+ vsi_ctx = hw->vsi_ctx[vsi_handle];
>+
>+ if (vsi_map & VIRTCHNL_DCF_VF_VSI_VALID) {
>+ if (!vsi_ctx)
>+ vsi_ctx = ice_malloc(hw, sizeof(*vsi_ctx));
>+
>+ if (!vsi_ctx) {
>+ PMD_DRV_LOG(ERR, "No memory for vsi context %u",
>+ vsi_handle);
>+ return;
>+ }
>+
>+ vsi_ctx->vsi_num = (vsi_map & VIRTCHNL_DCF_VF_VSI_ID_M) >>
>+ VIRTCHNL_DCF_VF_VSI_ID_S;
>+ hw->vsi_ctx[vsi_handle] = vsi_ctx;
>+
>+ PMD_DRV_LOG(DEBUG, "VF%u is assigned with vsi number %u",
>+ vsi_handle, vsi_ctx->vsi_num);
>+ } else {
>+ hw->vsi_ctx[vsi_handle] = NULL;
>+
>+ if (vsi_ctx)
>+ ice_free(hw, vsi_ctx);
Doesn't need to check vsi_ctx is NUll or not, ice_free (rte_free) would do it inside.
>+
>+ PMD_DRV_LOG(NOTICE, "VF%u is disabled", vsi_handle);
>+ }
>+}
>+
>+static void
>+ice_dcf_update_vf_vsi_map(struct ice_hw *hw, uint16_t num_vfs,
>+ uint16_t *vf_vsi_map)
>+{
>+ uint16_t vf_id;
>+
>+ for (vf_id = 0; vf_id < num_vfs; vf_id++)
>+ ice_dcf_update_vsi_ctx(hw, vf_id, vf_vsi_map[vf_id]);
>+}
>+
>+static void
>+ice_dcf_vsi_update_service_handler(void *param)
>+{
>+ struct ice_dcf_hw *hw = param;
>+
>+ if (!ice_dcf_handle_vsi_update_event(hw)) {
>+ struct ice_dcf_adapter *dcf_ad =
>+ container_of(hw, struct ice_dcf_adapter, real_hw);
>+
>+ ice_dcf_update_vf_vsi_map(&dcf_ad->parent.hw,
>+ hw->num_vfs, hw->vf_vsi_map);
>+ }
>+}
>+
>+void
>+ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
>+ uint8_t *msg, uint16_t msglen)
>+{
>+ struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
>+
>+ if (msglen < sizeof(struct virtchnl_pf_event)) {
>+ PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen);
>+ return;
>+ }
>+
>+ switch (pf_msg->event) {
>+ case VIRTCHNL_EVENT_RESET_IMPENDING:
>+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
>+ rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL * 2,
>+ ice_dcf_vsi_update_service_handler, dcf_hw);
>+ break;
>+ case VIRTCHNL_EVENT_LINK_CHANGE:
>+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
>+ break;
>+ case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
>+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
>+ break;
>+ case VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE:
>+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE event : VF%u with VSI num %u",
>+ pf_msg->event_data.vf_vsi_map.vf_id,
>+ pf_msg->event_data.vf_vsi_map.vsi_id);
>+ rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL,
>+ ice_dcf_vsi_update_service_handler, dcf_hw);
>+ break;
>+ default:
>+ PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
>+ break;
>+ }
>+}
>+
>+static int
>+ice_dcf_init_parent_hw(struct ice_hw *hw)
>+{
>+ struct ice_aqc_get_phy_caps_data *pcaps;
>+ enum ice_status status;
>+
>+ status = ice_aq_get_fw_ver(hw, NULL);
>+ if (status)
>+ return status;
>+
>+ status = ice_get_caps(hw);
>+ if (status)
>+ return status;
>+
>+ hw->port_info = (struct ice_port_info *)
>+ ice_malloc(hw, sizeof(*hw->port_info));
>+ if (!hw->port_info)
>+ return ICE_ERR_NO_MEMORY;
>+
>+ /* set the back pointer to HW */
>+ hw->port_info->hw = hw;
>+
>+ /* Initialize port_info struct with switch configuration data */
>+ status = ice_get_initial_sw_cfg(hw);
>+ if (status)
>+ goto err_unroll_alloc;
>+
>+ pcaps = (struct ice_aqc_get_phy_caps_data *)
>+ ice_malloc(hw, sizeof(*pcaps));
>+ if (!pcaps) {
>+ status = ICE_ERR_NO_MEMORY;
>+ goto err_unroll_alloc;
>+ }
>+
>+ /* Initialize port_info struct with PHY capabilities */
>+ status = ice_aq_get_phy_caps(hw->port_info, false,
>+ ICE_AQC_REPORT_TOPO_CAP, pcaps, NULL);
>+ ice_free(hw, pcaps);
>+ if (status)
>+ goto err_unroll_alloc;
>+
>+ /* Initialize port_info struct with link information */
>+ status = ice_aq_get_link_info(hw->port_info, false, NULL, NULL);
>+ if (status)
>+ goto err_unroll_alloc;
>+
>+ status = ice_init_fltr_mgmt_struct(hw);
>+ if (status)
>+ goto err_unroll_alloc;
>+
>+ status = ice_init_hw_tbls(hw);
>+ if (status)
>+ goto err_unroll_fltr_mgmt_struct;
>+
>+ PMD_DRV_LOG(INFO,
PMD_INIT_LOG
>+ "firmware %d.%d.%d api %d.%d.%d build 0x%08x",
>+ hw->fw_maj_ver, hw->fw_min_ver, hw->fw_patch,
>+ hw->api_maj_ver, hw->api_min_ver, hw->api_patch,
>+ hw->fw_build);
>+
>+ return ICE_SUCCESS;
>+
>+err_unroll_fltr_mgmt_struct:
>+ ice_cleanup_fltr_mgmt_struct(hw);
>+err_unroll_alloc:
>+ ice_free(hw, hw->port_info);
>+ hw->port_info = NULL;
>+
>+ return status;
>+}
>+
>+static void ice_dcf_uninit_parent_hw(struct ice_hw *hw)
>+{
>+ ice_cleanup_fltr_mgmt_struct(hw);
>+
>+ ice_free_seg(hw);
>+ ice_free_hw_tbls(hw);
>+
>+ if (hw->port_info) {
>+ ice_free(hw, hw->port_info);
Doesn't need to check whether hw->port_info is NULL or not, ice_free (rte_free) would do it inside.
>+ hw->port_info = NULL;
>+ }
>+
>+ ice_clear_all_vsi_ctx(hw);
>+}
>+
>+static int
>+ice_dcf_request_pkg_name(struct ice_hw *hw, char *pkg_name)
>+{
>+ struct ice_dcf_adapter *dcf_adapter =
>+ container_of(hw, struct ice_dcf_adapter, parent.hw);
>+
>+ /* TODO: check with DSN firstly by iAVF */
>+ PMD_DRV_LOG(DEBUG,
>+ "DCF VSI_ID = %u",
>+ dcf_adapter->real_hw.vsi_id);
>+
>+ snprintf(pkg_name,
>+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_UPDATES);
>+ if (!access(pkg_name, 0))
>+ return 0;
>+
>+ snprintf(pkg_name,
>+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_DEFAULT);
>+ if (!access(pkg_name, 0))
>+ return 0;
>+
>+ return -1;
>+}
>+
>+static int
>+ice_dcf_load_pkg(struct ice_hw *hw)
>+{
>+ char pkg_name[ICE_MAX_PKG_FILENAME_SIZE];
>+ uint8_t *pkg_buf;
>+ uint32_t buf_len;
>+ struct stat st;
>+ FILE *fp;
>+ int err;
>+
>+ if (ice_dcf_request_pkg_name(hw, pkg_name)) {
>+ PMD_INIT_LOG(ERR, "failed to locate the package file");
>+ return -ENOENT;
>+ }
>+
>+ PMD_INIT_LOG(DEBUG, "DDP package name: %s", pkg_name);
>+
>+ err = stat(pkg_name, &st);
>+ if (err) {
>+ PMD_INIT_LOG(ERR, "failed to get file status");
>+ return err;
>+ }
>+
>+ buf_len = st.st_size;
>+ pkg_buf = rte_malloc(NULL, buf_len, 0);
>+ if (!pkg_buf) {
>+ PMD_INIT_LOG(ERR, "failed to allocate buffer of size %u for package",
>+ buf_len);
>+ return -1;
>+ }
>+
>+ fp = fopen(pkg_name, "rb");
>+ if (!fp) {
>+ PMD_INIT_LOG(ERR, "failed to open file: %s", pkg_name);
>+ err = -1;
>+ goto ret;
>+ }
>+
>+ err = fread(pkg_buf, buf_len, 1, fp);
>+ fclose(fp);
>+ if (err != 1) {
>+ PMD_INIT_LOG(ERR, "failed to read package data");
>+ err = -1;
>+ goto ret;
>+ }
>+
>+ err = ice_copy_and_init_pkg(hw, pkg_buf, buf_len);
>+ if (err)
>+ PMD_INIT_LOG(ERR, "ice_copy_and_init_hw failed: %d", err);
>+
>+ret:
>+ rte_free(pkg_buf);
>+ return err;
>+}
>+
>+int
>+ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
>+{
>+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
>+ struct ice_adapter *parent_adapter = &adapter->parent;
>+ struct ice_hw *parent_hw = &parent_adapter->hw;
>+ struct ice_dcf_hw *hw = &adapter->real_hw;
>+ const struct rte_ether_addr *mac;
>+ int err;
>+
>+ parent_adapter->eth_dev = eth_dev;
>+ parent_adapter->pf.adapter = parent_adapter;
>+ parent_adapter->pf.dev_data = eth_dev->data;
>+ parent_hw->back = parent_adapter;
>+ parent_hw->mac_type = ICE_MAC_GENERIC;
>+ parent_hw->vendor_id = ICE_INTEL_VENDOR_ID;
>+
>+ ice_init_lock(&parent_hw->adminq.sq_lock);
>+ ice_init_lock(&parent_hw->adminq.rq_lock);
>+ parent_hw->aq_send_cmd_fn = ice_dcf_send_aq_cmd;
>+ parent_hw->aq_send_cmd_param = &adapter->real_hw;
>+ parent_hw->dcf_enabled = true;
>+
>+ err = ice_dcf_init_parent_hw(parent_hw);
>+ if (err) {
>+ PMD_DRV_LOG(ERR, "failed to init the DCF parent hardware with error %d",
PMD_INIT_LOG
>+ err);
>+ return err;
>+ }
>+
>+ err = ice_dcf_load_pkg(parent_hw);
>+ if (err) {
>+ PMD_DRV_LOG(ERR, "failed to load package with error %d",
PMD_INIT_LOG
>+ err);
>+ goto uninit_hw;
>+ }
>+ parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
>+
>+ ice_dcf_update_vf_vsi_map(parent_hw,
>+ hw->num_vfs, hw->vf_vsi_map);
>+
>+ mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
>+ if (rte_is_valid_assigned_ether_addr(mac))
>+ rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
>+ else
>+ rte_eth_random_addr(parent_adapter->pf.dev_addr.addr_bytes);
>+
>+ eth_dev->data->mac_addrs = &parent_adapter->pf.dev_addr;
>+
>+ return 0;
>+
>+uninit_hw:
>+ ice_dcf_uninit_parent_hw(parent_hw);
>+ return err;
>+}
>+
>+void
>+ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
>+{
>+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
>+ struct ice_adapter *parent_adapter = &adapter->parent;
>+ struct ice_hw *parent_hw = &parent_adapter->hw;
>+
>+ eth_dev->data->mac_addrs = NULL;
>+
>+ rte_eal_alarm_cancel(ice_dcf_vsi_update_service_handler,
>+ &adapter->real_hw);
>+
>+ ice_dcf_uninit_parent_hw(parent_hw);
>+}
>diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
>index f9e897bbc..0df8ddc0f 100644
>--- a/drivers/net/ice/meson.build
>+++ b/drivers/net/ice/meson.build
>@@ -15,8 +15,8 @@ sources = files(
> 'ice_hash.c'
> )
>
>-deps += ['hash']
>-includes += include_directories('base')
>+deps += ['hash', 'net', 'common_iavf']
>+includes += include_directories('base', '../../common/iavf')
>
> if arch_subdir == 'x86'
> sources += files('ice_rxtx_vec_sse.c')
>@@ -37,4 +37,8 @@ if arch_subdir == 'x86'
> endif
> endif
>
>+sources += files('ice_dcf.c',
>+ 'ice_dcf_parent.c',
>+ 'ice_dcf_ethdev.c')
>+
> install_headers('rte_pmd_ice.h')
>diff --git a/mk/rte.app.mk b/mk/rte.app.mk
>index d295ca0a5..f3798a09f 100644
>--- a/mk/rte.app.mk
>+++ b/mk/rte.app.mk
>@@ -185,6 +185,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += -lrte_pmd_i40e
> _LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD) += -lrte_pmd_iavf
> _LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += -lrte_pmd_ice
> IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
>+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
> ifeq ($(findstring y,$(IAVF-y)),y)
> _LDLIBS-y += -lrte_common_iavf
> endif
>--
>2.25.1
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode
2020-03-10 3:37 ` Ye Xiaolong
@ 2020-03-10 4:26 ` Wang, Haiyue
0 siblings, 0 replies; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-10 4:26 UTC (permalink / raw)
To: Ye, Xiaolong; +Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei
> -----Original Message-----
> From: Ye, Xiaolong <xiaolong.ye@intel.com>
> Sent: Tuesday, March 10, 2020 11:38
> To: Wang, Haiyue <haiyue.wang@intel.com>
> Cc: dev@dpdk.org; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>
> Subject: Re: [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode
>
> On 03/10, Wang, Haiyue wrote:
> >> -----Original Message-----
> >> From: Ye, Xiaolong <xiaolong.ye@intel.com>
> >> Sent: Monday, March 9, 2020 23:38
> >> To: Wang, Haiyue <haiyue.wang@intel.com>
> >> Cc: dev@dpdk.org; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> >> Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>
> >> Subject: Re: [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode
> >>
> >> On 03/09, Haiyue Wang wrote:
> >> >A new DCF PMD will be introduced, which runs on Intel VF hardware, and
> >> >it is a pure software design to control the advance functionality (such
> >> >as switch, ACL) for rest of the VFs.
> >> >
> >> >So if the DCF (Device Config Function) mode is specified by the devarg
> >> >'cap=dcf', then it will stop the PCI probe in the iavf PMD.
> >> >
> >> >Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
> >> >---
> >> > drivers/net/iavf/iavf_ethdev.c | 41 ++++++++++++++++++++++++++++++++++
> >> > 1 file changed, 41 insertions(+)
> >> >
> >> >diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
> >> >index 34913f9c4..8ff26c0e7 100644
> >> >--- a/drivers/net/iavf/iavf_ethdev.c
> >> >+++ b/drivers/net/iavf/iavf_ethdev.c
> >> >@@ -1416,9 +1416,49 @@ iavf_dev_uninit(struct rte_eth_dev *dev)
> >> > return 0;
> >> > }
> >> >
> >> >+static int
> >> >+handle_dcf_arg(__rte_unused const char *key, const char *value,
> >> >+ __rte_unused void *arg)
> >> >+{
> >> >+ bool *dcf = arg;
> >> >+
> >> >+ if (arg == NULL || value == NULL)
> >> >+ return -EINVAL;
> >> >+
> >> >+ if (strcmp(value, "dcf") == 0)
> >> >+ *dcf = true;
> >> >+ else
> >> >+ *dcf = false;
> >> >+
> >> >+ return 0;
> >> >+}
> >> >+
> >> >+static bool
> >> >+check_cap_dcf_enable(struct rte_devargs *devargs)
> >> >+{
> >> >+ struct rte_kvargs *kvlist;
> >> >+ bool enable = false;
> >> >+
> >> >+ if (devargs == NULL)
> >> >+ return false;
> >> >+
> >> >+ kvlist = rte_kvargs_parse(devargs->args, NULL);
> >> >+ if (kvlist == NULL)
> >> >+ return false;
> >> >+
> >> >+ rte_kvargs_process(kvlist, "cap", handle_dcf_arg, &enable);
> >>
> >> Need error handling for failure case.
> >>
> >
> >We just need the 'cap=dcf' to check whether it is true, by default
> >'enable=false' can handle all the cases. ;-)
> >
>
> Yes, from function point of view, this could work. But it is still good practice
> to check the return value of the function.
>
Make sense, will handle it in v2.
> Thanks,
> Xiaolong
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 3/4] net/ice: add the DCF framework
2020-03-10 4:17 ` Ye Xiaolong
@ 2020-03-10 5:09 ` Wang, Haiyue
2020-03-10 5:23 ` Ye Xiaolong
0 siblings, 1 reply; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-10 5:09 UTC (permalink / raw)
To: Ye, Xiaolong; +Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei
> -----Original Message-----
> From: Ye, Xiaolong <xiaolong.ye@intel.com>
> Sent: Tuesday, March 10, 2020 12:17
> To: Wang, Haiyue <haiyue.wang@intel.com>
> Cc: dev@dpdk.org; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>
> Subject: Re: [PATCH v1 3/4] net/ice: add the DCF framework
>
> On 03/09, Haiyue Wang wrote:
> >The DCF (Device Config Function) feature works as a standalone PMD, its
> >hardware entity is the trusted VF with ID 0, and the software function
> >is to control the flow setting of other VFs by the mailbox with PF.
> >
> >It doesn't handle packet Rx/Tx related things. This PMD needs the iAVF
> >virtchnl to send the ICE PF's AdminQ command.
> >
> >Also for security, it needs to acquire the DCF capability from PF. The
> >flow related things will be added later, it shares most of the ICE flow
> >function. This mainly handles hardware initialization etc.
> >
> > .-------------.
> > .-| |
> > .-| | |
> > | | | iAVF PMD |
> > | | | |
> > | | | |
> > | | '-------------'
> > | '-------------'
> > '-------------'
> > ^ Other VFs
> > /
> > / Flow Distribution
> > .------------------. /
> > | |/ DCF cap req .-------------.
> > | CVL . <---------- | |
> > | Kernel | ----------> | |
> > . . DCF cap rsp | DCF PMD |
> > | | | |
> > '------------------' <----------- | |
> > rte_flow '-------------'
> > VF0
>
> It'd be clearer if this diagram keeps `DCF PMD` and `iAVF PMD` at the same
> level and `CVL Kernel` at the bottom, what do you think?
>
Yes, and will remove this redundant message, since the ice guide has a image for
this, it has rich information. ;-)
> >
> >Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
> >---
> > doc/guides/nics/ice.rst | 47 +++
> > doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> > drivers/common/Makefile | 1 +
> > drivers/net/ice/Makefile | 6 +
> > drivers/net/ice/ice_dcf.c | 651 +++++++++++++++++++++++++++++++
> > drivers/net/ice/ice_dcf.h | 61 +++
> > drivers/net/ice/ice_dcf_ethdev.c | 319 +++++++++++++++
> > drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> > drivers/net/ice/ice_dcf_parent.c | 348 +++++++++++++++++
> > drivers/net/ice/meson.build | 8 +-
> > mk/rte.app.mk | 1 +
> > 11 files changed, 1473 insertions(+), 2 deletions(-)
> > create mode 100644 doc/guides/nics/img/ice_dcf.png
> > create mode 100644 drivers/net/ice/ice_dcf.c
> > create mode 100644 drivers/net/ice/ice_dcf.h
> > create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
> > create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
> > create mode 100644 drivers/net/ice/ice_dcf_parent.c
> >
> >diff --git a/drivers/common/Makefile b/drivers/common/Makefile
> >index 96bd7ac6e..df2e840cf 100644
> >--- a/drivers/common/Makefile
> >+++ b/drivers/common/Makefile
> >@@ -31,6 +31,7 @@ DIRS-y += dpaax
> > endif
> >
> > IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
> >+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
> > ifneq (,$(findstring y,$(IAVF-y)))
> > DIRS-y += iavf
> > endif
> >diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
> >index e22c34287..643639a50 100644
> >--- a/drivers/net/ice/Makefile
> >+++ b/drivers/net/ice/Makefile
> >@@ -11,9 +11,11 @@ LIB = librte_pmd_ice.a
> > CFLAGS += -O3
> > CFLAGS += $(WERROR_FLAGS)
> > CFLAGS += -DALLOW_EXPERIMENTAL_API
> >+CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
> >
> > LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
> > LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
> >+LDLIBS += -lrte_net -lrte_common_iavf
> >
> > EXPORT_MAP := rte_pmd_ice_version.map
> >
> >@@ -84,6 +86,10 @@ ifeq ($(CC_AVX2_SUPPORT), 1)
> > endif
> > SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
> >
> >+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
> >+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_parent.c
> >+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
> >+
> > # install this header file
> > SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
> >
> >diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
> >new file mode 100644
> >index 000000000..669122331
> >--- /dev/null
> >+++ b/drivers/net/ice/ice_dcf.c
> >@@ -0,0 +1,651 @@
> >+/* SPDX-License-Identifier: BSD-3-Clause
> >+ * Copyright(c) 2019 Intel Corporation
>
> Should be 2020?
>
Yes, forget to update.
> >+ */
> >+
> >+#include <sys/queue.h>
> >+#include <stdio.h>
> >+#include <errno.h>
> >+#include <stdint.h>
> >+#include <string.h>
> >+#include <unistd.h>
> >+#include <stdarg.h>
> >+#include <inttypes.h>
> >+#include <rte_byteorder.h>
> >+#include <rte_common.h>
> >+
> >+#include <rte_pci.h>
> >+#include <rte_atomic.h>
> >+#include <rte_eal.h>
> >+#include <rte_ether.h>
> >+#include <rte_ethdev_driver.h>
> >+#include <rte_ethdev_pci.h>
> >+#include <rte_malloc.h>
> >+#include <rte_memzone.h>
> >+#include <rte_dev.h>
> >+
> >+#include "ice_dcf.h"
> >+
> >+#define ICE_DCF_AQ_LEN 32
> >+#define ICE_DCF_AQ_BUF_SZ 4096
> >+
> >+#define ICE_DCF_ARQ_MAX_RETRIES 200
> >+#define ICE_DCF_ARQ_CHECK_TIME 2 /* msecs */
> >+
> >+#define ICE_DCF_VF_RES_BUF_SZ \
> >+ (sizeof(struct virtchnl_vf_resource) + \
> >+ IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource))
> >+
> >+static __rte_always_inline int
> >+ice_dcf_send_cmd_req_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
> >+ uint8_t *req_msg, uint16_t req_msglen)
> >+{
> >+ return iavf_aq_send_msg_to_pf(&hw->avf, op, IAVF_SUCCESS,
> >+ req_msg, req_msglen, NULL);
> >+}
> >+
> >+static int
> >+ice_dcf_recv_cmd_rsp_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
> >+ uint8_t *rsp_msgbuf, uint16_t rsp_buflen,
> >+ uint16_t *rsp_msglen)
> >+{
> >+ struct iavf_arq_event_info event;
> >+ enum virtchnl_ops v_op;
> >+ int i = 0;
> >+ int err;
> >+
> >+ event.buf_len = rsp_buflen;
> >+ event.msg_buf = rsp_msgbuf;
> >+
> >+ do {
> >+ err = iavf_clean_arq_element(&hw->avf, &event, NULL);
> >+ if (err != IAVF_SUCCESS)
> >+ goto again;
> >+
> >+ v_op = rte_le_to_cpu_32(event.desc.cookie_high);
> >+ if (v_op != op)
> >+ goto again;
> >+
> >+ if (rsp_msglen != NULL)
> >+ *rsp_msglen = event.msg_len;
> >+ return rte_le_to_cpu_32(event.desc.cookie_low);
> >+
> >+again:
> >+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
> >+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
> >+
> >+ return -EIO;
> >+}
> >+
> >+static __rte_always_inline void
> >+ice_dcf_aq_cmd_clear(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
> >+{
> >+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
> >+
> >+ TAILQ_REMOVE(&hw->vc_cmd_queue, cmd, next);
> >+
> >+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
> >+}
> >+
> >+static __rte_always_inline void
> >+ice_dcf_vc_cmd_set(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
> >+{
> >+ cmd->v_ret = IAVF_ERR_NOT_READY;
> >+ cmd->rsp_msglen = 0;
> >+ cmd->pending = 1;
> >+
> >+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
> >+
> >+ TAILQ_INSERT_TAIL(&hw->vc_cmd_queue, cmd, next);
> >+
> >+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
> >+}
> >+
> >+static __rte_always_inline int
> >+ice_dcf_vc_cmd_send(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
> >+{
> >+ return iavf_aq_send_msg_to_pf(&hw->avf,
> >+ cmd->v_op, IAVF_SUCCESS,
> >+ cmd->req_msg, cmd->req_msglen, NULL);
> >+}
> >+
> >+static __rte_always_inline void
> >+ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
> >+{
> >+ struct dcf_virtchnl_cmd *cmd;
> >+ enum virtchnl_ops v_op;
> >+ enum iavf_status v_ret;
> >+ uint16_t aq_op;
> >+
> >+ aq_op = rte_le_to_cpu_16(info->desc.opcode);
> >+ if (unlikely(aq_op != iavf_aqc_opc_send_msg_to_vf)) {
> >+ PMD_DRV_LOG(ERR,
> >+ "Request %u is not supported yet", aq_op);
> >+ return;
> >+ }
> >+
> >+ v_op = rte_le_to_cpu_32(info->desc.cookie_high);
> >+ if (unlikely(v_op == VIRTCHNL_OP_EVENT)) {
> >+ if (hw->vc_event_msg_cb != NULL)
> >+ hw->vc_event_msg_cb(hw,
> >+ info->msg_buf,
> >+ info->msg_len);
> >+ return;
> >+ }
> >+
> >+ v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
> >+
> >+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
> >+
> >+ TAILQ_FOREACH(cmd, &hw->vc_cmd_queue, next) {
> >+ if (cmd->v_op == v_op && cmd->pending) {
> >+ cmd->v_ret = v_ret;
> >+ cmd->rsp_msglen = RTE_MIN(info->msg_len,
> >+ cmd->rsp_buflen);
> >+ if (likely(cmd->rsp_msglen != 0))
> >+ rte_memcpy(cmd->rsp_msgbuf, info->msg_buf,
> >+ cmd->rsp_msglen);
> >+
> >+ /* prevent compiler reordering */
> >+ rte_compiler_barrier();
> >+ cmd->pending = 0;
> >+ break;
> >+ }
> >+ }
> >+
> >+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
> >+}
> >+
> >+static void
> >+ice_dcf_handle_virtchnl_msg(struct ice_dcf_hw *hw)
> >+{
> >+ struct iavf_arq_event_info info;
> >+ uint16_t pending = 1;
> >+ int ret;
> >+
> >+ info.buf_len = ICE_DCF_AQ_BUF_SZ;
> >+ info.msg_buf = hw->arq_buf;
> >+
> >+ while (pending) {
> >+ ret = iavf_clean_arq_element(&hw->avf, &info, &pending);
> >+ if (ret != IAVF_SUCCESS)
> >+ break;
> >+
> >+ ice_dcf_aq_cmd_handle(hw, &info);
> >+ }
> >+}
> >+
> >+static int
> >+ice_dcf_init_check_api_version(struct ice_dcf_hw *hw)
> >+{
> >+#define ICE_CPF_VIRTCHNL_VERSION_MAJOR_START 1
> >+#define ICE_CPF_VIRTCHNL_VERSION_MINOR_START 1
> >+ struct virtchnl_version_info version, *pver;
> >+ int err;
> >+
> >+ version.major = VIRTCHNL_VERSION_MAJOR;
> >+ version.minor = VIRTCHNL_VERSION_MINOR;
> >+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_VERSION,
> >+ (uint8_t *)&version, sizeof(version));
> >+ if (err) {
> >+ PMD_INIT_LOG(ERR, "Fail to send OP_VERSION");
> >+ return err;
> >+ }
> >+
> >+ pver = &hw->virtchnl_version;
> >+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_VERSION,
> >+ (uint8_t *)pver, sizeof(*pver), NULL);
> >+ if (err) {
> >+ PMD_INIT_LOG(ERR, "Fail to get response of OP_VERSION");
> >+ return -1;
> >+ }
> >+
> >+ PMD_DRV_LOG(DEBUG,
> >+ "Peer PF API version: %u.%u", pver->major, pver->minor);
>
> PMD_INIT_LOG
>
Fixed in v2
> >+
> >+ if (pver->major < ICE_CPF_VIRTCHNL_VERSION_MAJOR_START ||
> >+ (pver->major == ICE_CPF_VIRTCHNL_VERSION_MAJOR_START &&
> >+ pver->minor < ICE_CPF_VIRTCHNL_VERSION_MINOR_START)) {
> >+ PMD_INIT_LOG(ERR,
> >+ "VIRTCHNL API version should not be lower than (%u.%u)",
> >+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START,
> >+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START);
> >+ return -1;
> >+ } else if (pver->major > VIRTCHNL_VERSION_MAJOR ||
> >+ (pver->major == VIRTCHNL_VERSION_MAJOR &&
> >+ pver->minor > VIRTCHNL_VERSION_MINOR)) {
> >+ PMD_INIT_LOG(ERR,
> >+ "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
> >+ pver->major, pver->minor,
> >+ VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
> >+ return -1;
> >+ }
> >+
> >+ PMD_DRV_LOG(DEBUG, "Peer is supported PF host");
>
> PMD_INIT_LOG
>
Fixed in v2, as below
> >+
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
> >+{
> >+ uint32_t caps;
> >+ int err, i;
> >+
> >+ caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
> >+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED | VIRTCHNL_VF_CAP_DCF |
> >+ VF_BASE_MODE_OFFLOADS;
> >+
> >+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
> >+ (uint8_t *)&caps, sizeof(caps));
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR, "Fail to send msg OP_GET_VF_RESOURCE");
> >+ return err;
> >+ }
> >+
> >+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
> >+ (uint8_t *)hw->vf_res,
> >+ ICE_DCF_VF_RES_BUF_SZ, NULL);
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR, "Fail to get response of OP_GET_VF_RESOURCE");
> >+ return -1;
> >+ }
> >+
> >+ iavf_vf_parse_hw_config(&hw->avf, hw->vf_res);
> >+
> >+ hw->vsi_res = NULL;
> >+ for (i = 0; i < hw->vf_res->num_vsis; i++) {
> >+ if (hw->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
> >+ hw->vsi_res = &hw->vf_res->vsi_res[i];
> >+ }
> >+
> >+ if (!hw->vsi_res) {
> >+ PMD_DRV_LOG(ERR, "no LAN VSI found");
> >+ return -1;
> >+ }
> >+
> >+ hw->vsi_id = hw->vsi_res->vsi_id;
> >+ PMD_DRV_LOG(DEBUG, "VSI ID is %u", hw->vsi_id);
> >+
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_get_vf_vsi_map(struct ice_dcf_hw *hw)
> >+{
> >+ struct virtchnl_dcf_vsi_map *vsi_map;
> >+ uint16_t len;
> >+ int err;
> >+
> >+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
> >+ NULL, 0);
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_GET_VSI_MAP");
> >+ return err;
> >+ }
> >+
> >+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
> >+ hw->arq_buf, ICE_DCF_AQ_BUF_SZ,
> >+ &len);
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR, "Fail to get response of OP_DCF_GET_VSI_MAP");
> >+ return err;
> >+ }
> >+
> >+ vsi_map = (struct virtchnl_dcf_vsi_map *)hw->arq_buf;
> >+ if (len < sizeof(*vsi_map) || !vsi_map->num_vfs ||
> >+ len < sizeof(*vsi_map) +
> >+ (vsi_map->num_vfs - 1) * sizeof(vsi_map->vf_vsi[0])) {
> >+ PMD_DRV_LOG(ERR, "invalid vf vsi map response with length %u",
> >+ len);
> >+ return -EINVAL;
> >+ }
> >+
> >+ if (hw->num_vfs != 0 && hw->num_vfs != vsi_map->num_vfs) {
> >+ PMD_DRV_LOG(ERR, "The number VSI map (%u) doesn't match the number of VFs (%u)",
> >+ vsi_map->num_vfs, hw->num_vfs);
> >+ return -EINVAL;
> >+ }
> >+
> >+ len = vsi_map->num_vfs * sizeof(vsi_map->vf_vsi[0]);
> >+ if (!hw->vf_vsi_map) {
> >+ hw->num_vfs = vsi_map->num_vfs;
> >+ hw->vf_vsi_map = rte_zmalloc("vf_vsi_ctx", len, 0);
> >+ }
> >+
> >+ if (!hw->vf_vsi_map) {
> >+ PMD_DRV_LOG(ERR, "Fail to alloc memory for VSI context");
> >+ return -ENOMEM;
> >+ }
> >+
> >+ if (!memcmp(hw->vf_vsi_map, vsi_map->vf_vsi, len)) {
> >+ PMD_DRV_LOG(DEBUG, "VF VSI map doesn't change");
> >+ return 1;
> >+ }
> >+
> >+ rte_memcpy(hw->vf_vsi_map, vsi_map->vf_vsi, len);
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_mode_disable(struct ice_dcf_hw *hw)
> >+{
> >+ int err;
> >+
> >+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
> >+ NULL, 0);
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_DISABLE");
> >+ return err;
> >+ }
> >+
> >+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
> >+ (uint8_t *)hw->arq_buf,
> >+ ICE_DCF_AQ_BUF_SZ, NULL);
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR,
> >+ "Fail to get response of OP_DCF_DISABLE %d",
> >+ err);
> >+ return -1;
> >+ }
> >+
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
> >+{
> >+#define ICE_DCF_RESET_WAIT_CNT 50
> >+ struct iavf_hw *avf = &hw->avf;
> >+ int i, reset;
> >+
> >+ for (i = 0; i < ICE_DCF_RESET_WAIT_CNT; i++) {
> >+ reset = IAVF_READ_REG(avf, IAVF_VFGEN_RSTAT) &
> >+ IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
> >+ reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
> >+
> >+ if (reset == VIRTCHNL_VFR_VFACTIVE ||
> >+ reset == VIRTCHNL_VFR_COMPLETED)
> >+ break;
> >+
> >+ rte_delay_ms(20);
> >+ }
> >+
> >+ if (i >= ICE_DCF_RESET_WAIT_CNT)
> >+ return -1;
> >+
> >+ return 0;
> >+}
> >+
> >+static inline void
> >+ice_dcf_enable_irq0(struct ice_dcf_hw *hw)
> >+{
> >+ struct iavf_hw *avf = &hw->avf;
> >+
> >+ /* Enable admin queue interrupt trigger */
> >+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1,
> >+ IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
> >+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
> >+ IAVF_VFINT_DYN_CTL01_INTENA_MASK |
> >+ IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
> >+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
> >+
> >+ IAVF_WRITE_FLUSH(avf);
> >+}
> >+
> >+static inline void
> >+ice_dcf_disable_irq0(struct ice_dcf_hw *hw)
> >+{
> >+ struct iavf_hw *avf = &hw->avf;
> >+
> >+ /* Disable all interrupt types */
> >+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1, 0);
> >+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
> >+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
> >+
> >+ IAVF_WRITE_FLUSH(avf);
> >+}
> >+
> >+static void
> >+ice_dcf_dev_interrupt_handler(void *param)
> >+{
> >+ struct ice_dcf_hw *hw = param;
> >+
> >+ ice_dcf_disable_irq0(hw);
> >+
> >+ ice_dcf_handle_virtchnl_msg(hw);
> >+
> >+ ice_dcf_enable_irq0(hw);
> >+}
> >+
> >+int
> >+ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
> >+ struct dcf_virtchnl_cmd *cmd)
> >+{
> >+ int i = 0;
> >+ int err;
> >+
> >+ if ((cmd->req_msg && !cmd->req_msglen) ||
> >+ (!cmd->req_msg && cmd->req_msglen) ||
> >+ (cmd->rsp_msgbuf && !cmd->rsp_buflen) ||
> >+ (!cmd->rsp_msgbuf && cmd->rsp_buflen))
> >+ return -EINVAL;
> >+
> >+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
> >+ ice_dcf_vc_cmd_set(hw, cmd);
> >+
> >+ err = ice_dcf_vc_cmd_send(hw, cmd);
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR, "fail to send cmd %d", cmd->v_op);
> >+ goto ret;
> >+ }
> >+
> >+ do {
> >+ if (!cmd->pending)
> >+ break;
> >+
> >+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
> >+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
> >+
> >+ if (cmd->v_ret != IAVF_SUCCESS) {
> >+ err = -1;
> >+ PMD_DRV_LOG(ERR,
> >+ "No response (%d times) or return failure (%d) for cmd %d",
> >+ i, cmd->v_ret, cmd->v_op);
> >+ }
> >+
> >+ret:
> >+ ice_dcf_aq_cmd_clear(hw, cmd);
> >+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
> >+ return err;
> >+}
> >+
> >+int
> >+ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
> >+ void *buf, uint16_t buf_size)
> >+{
> >+ struct dcf_virtchnl_cmd desc_cmd, buff_cmd;
> >+ struct ice_dcf_hw *hw = dcf_hw;
> >+ int err = 0;
> >+ int i = 0;
> >+
> >+ if ((buf && !buf_size) || (!buf && buf_size) ||
> >+ buf_size > ICE_DCF_AQ_BUF_SZ)
> >+ return -EINVAL;
> >+
> >+ desc_cmd.v_op = VIRTCHNL_OP_DCF_CMD_DESC;
> >+ desc_cmd.req_msglen = sizeof(*desc);
> >+ desc_cmd.req_msg = (uint8_t *)desc;
> >+ desc_cmd.rsp_buflen = sizeof(*desc);
> >+ desc_cmd.rsp_msgbuf = (uint8_t *)desc;
> >+
> >+ if (buf == NULL)
> >+ return ice_dcf_execute_virtchnl_cmd(hw, &desc_cmd);
> >+
> >+ desc->flags |= rte_cpu_to_le_16(ICE_AQ_FLAG_BUF);
> >+
> >+ buff_cmd.v_op = VIRTCHNL_OP_DCF_CMD_BUFF;
> >+ buff_cmd.req_msglen = buf_size;
> >+ buff_cmd.req_msg = buf;
> >+ buff_cmd.rsp_buflen = buf_size;
> >+ buff_cmd.rsp_msgbuf = buf;
> >+
> >+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
> >+ ice_dcf_vc_cmd_set(hw, &desc_cmd);
> >+ ice_dcf_vc_cmd_set(hw, &buff_cmd);
> >+
> >+ if (ice_dcf_vc_cmd_send(hw, &desc_cmd) ||
> >+ ice_dcf_vc_cmd_send(hw, &buff_cmd)) {
> >+ err = -1;
> >+ PMD_DRV_LOG(ERR, "fail to send OP_DCF_CMD_DESC/BUFF");
> >+ goto ret;
> >+ }
> >+
> >+ do {
> >+ if ((!desc_cmd.pending && !buff_cmd.pending) ||
> >+ (!desc_cmd.pending && desc_cmd.v_ret != IAVF_SUCCESS) ||
> >+ (!buff_cmd.pending && buff_cmd.v_ret != IAVF_SUCCESS))
> >+ break;
> >+
> >+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
> >+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
> >+
> >+ if (desc_cmd.v_ret != IAVF_SUCCESS || buff_cmd.v_ret != IAVF_SUCCESS) {
> >+ err = -1;
> >+ PMD_DRV_LOG(ERR,
> >+ "No response (%d times) or return failure (desc: %d / buff: %d)",
> >+ i, desc_cmd.v_ret, buff_cmd.v_ret);
> >+ }
> >+
> >+ret:
> >+ ice_dcf_aq_cmd_clear(hw, &desc_cmd);
> >+ ice_dcf_aq_cmd_clear(hw, &buff_cmd);
> >+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
> >+
> >+ return err;
> >+}
> >+
> >+int
> >+ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw)
> >+{
> >+ int err = 0;
> >+
> >+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
> >+ ice_dcf_disable_irq0(hw);
> >+
> >+ if (ice_dcf_get_vf_resource(hw) || ice_dcf_get_vf_vsi_map(hw))
> >+ err = -1;
> >+
> >+ ice_dcf_enable_irq0(hw);
> >+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
> >+
> >+ return err;
> >+}
> >+
> >+int
> >+ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
> >+{
> >+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
> >+ int ret;
> >+
> >+ hw->avf.hw_addr = pci_dev->mem_resource[0].addr;
> >+ hw->avf.back = hw;
> >+
> >+ hw->avf.bus.bus_id = pci_dev->addr.bus;
> >+ hw->avf.bus.device = pci_dev->addr.devid;
> >+ hw->avf.bus.func = pci_dev->addr.function;
> >+
> >+ hw->avf.device_id = pci_dev->id.device_id;
> >+ hw->avf.vendor_id = pci_dev->id.vendor_id;
> >+ hw->avf.subsystem_device_id = pci_dev->id.subsystem_device_id;
> >+ hw->avf.subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
> >+
> >+ hw->avf.aq.num_arq_entries = ICE_DCF_AQ_LEN;
> >+ hw->avf.aq.num_asq_entries = ICE_DCF_AQ_LEN;
> >+ hw->avf.aq.arq_buf_size = ICE_DCF_AQ_BUF_SZ;
> >+ hw->avf.aq.asq_buf_size = ICE_DCF_AQ_BUF_SZ;
> >+
> >+ rte_spinlock_init(&hw->vc_cmd_send_lock);
> >+ rte_spinlock_init(&hw->vc_cmd_queue_lock);
> >+ TAILQ_INIT(&hw->vc_cmd_queue);
> >+
> >+ hw->arq_buf = rte_zmalloc("arq_buf", ICE_DCF_AQ_BUF_SZ, 0);
> >+ if (hw->arq_buf == NULL) {
> >+ PMD_INIT_LOG(ERR, "unable to allocate AdminQ buffer memory");
> >+ goto err;
> >+ }
> >+
> >+ ret = iavf_set_mac_type(&hw->avf);
> >+ if (ret) {
> >+ PMD_INIT_LOG(ERR, "set_mac_type failed: %d", ret);
> >+ goto err;
> >+ }
> >+
> >+ ret = ice_dcf_check_reset_done(hw);
> >+ if (ret) {
> >+ PMD_INIT_LOG(ERR, "VF is still resetting");
> >+ goto err;
> >+ }
> >+
> >+ ret = iavf_init_adminq(&hw->avf);
> >+ if (ret) {
> >+ PMD_INIT_LOG(ERR, "init_adminq failed: %d", ret);
> >+ goto err;
> >+ }
> >+
> >+ if (ice_dcf_init_check_api_version(hw)) {
> >+ PMD_INIT_LOG(ERR, "check_api version failed");
> >+ goto err_api;
> >+ }
> >+
> >+ hw->vf_res = rte_zmalloc("vf_res", ICE_DCF_VF_RES_BUF_SZ, 0);
> >+ if (hw->vf_res == NULL) {
> >+ PMD_INIT_LOG(ERR, "unable to allocate vf_res memory");
> >+ goto err_api;
> >+ }
> >+
> >+ if (ice_dcf_get_vf_resource(hw)) {
> >+ PMD_INIT_LOG(ERR, "Failed to get VF resource");
> >+ goto err_alloc;
> >+ }
> >+
> >+ if (ice_dcf_get_vf_vsi_map(hw) < 0) {
> >+ PMD_INIT_LOG(ERR, "Failed to get VF VSI map");
> >+ ice_dcf_mode_disable(hw);
> >+ goto err_alloc;
> >+ }
> >+
> >+ rte_intr_callback_register(&pci_dev->intr_handle,
> >+ ice_dcf_dev_interrupt_handler, hw);
> >+ rte_intr_enable(&pci_dev->intr_handle);
> >+ ice_dcf_enable_irq0(hw);
> >+
> >+ return 0;
> >+
> >+err_alloc:
> >+ rte_free(hw->vf_res);
> >+err_api:
> >+ iavf_shutdown_adminq(&hw->avf);
> >+err:
> >+ rte_free(hw->arq_buf);
> >+
> >+ return -1;
> >+}
> >+
> >+void
> >+ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
> >+{
> >+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
> >+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
> >+
> >+ ice_dcf_disable_irq0(hw);
> >+ rte_intr_disable(intr_handle);
> >+ rte_intr_callback_unregister(intr_handle,
> >+ ice_dcf_dev_interrupt_handler, hw);
> >+
> >+ ice_dcf_mode_disable(hw);
> >+ iavf_shutdown_adminq(&hw->avf);
> >+
> >+ rte_free(hw->arq_buf);
> >+ rte_free(hw->vf_vsi_map);
> >+ rte_free(hw->vf_res);
> >+}
> >diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
> >new file mode 100644
> >index 000000000..58647d87f
> >--- /dev/null
> >+++ b/drivers/net/ice/ice_dcf.h
> >@@ -0,0 +1,61 @@
> >+/* SPDX-License-Identifier: BSD-3-Clause
> >+ * Copyright(c) 2019 Intel Corporation
> >+ */
> >+
> >+#ifndef _ICE_DCF_H_
> >+#define _ICE_DCF_H_
> >+
> >+#include <rte_ethdev_driver.h>
> >+
> >+#include <iavf_prototype.h>
> >+#include <iavf_adminq_cmd.h>
> >+#include <iavf_type.h>
> >+
> >+#include "base/ice_type.h"
> >+#include "ice_logs.h"
> >+
> >+struct dcf_virtchnl_cmd {
> >+ TAILQ_ENTRY(dcf_virtchnl_cmd) next;
> >+
> >+ enum virtchnl_ops v_op;
> >+ enum iavf_status v_ret;
> >+
> >+ uint16_t req_msglen;
> >+ uint8_t *req_msg;
> >+
> >+ uint16_t rsp_msglen;
> >+ uint16_t rsp_buflen;
> >+ uint8_t *rsp_msgbuf;
> >+
> >+ volatile int pending;
> >+};
> >+
> >+struct ice_dcf_hw {
> >+ struct iavf_hw avf;
> >+
> >+ rte_spinlock_t vc_cmd_send_lock;
> >+ rte_spinlock_t vc_cmd_queue_lock;
> >+ TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
> >+ void (*vc_event_msg_cb)(struct ice_dcf_hw *dcf_hw,
> >+ uint8_t *msg, uint16_t msglen);
> >+
> >+ uint8_t *arq_buf;
> >+
> >+ uint16_t num_vfs;
> >+ uint16_t *vf_vsi_map;
> >+
> >+ struct virtchnl_version_info virtchnl_version;
> >+ struct virtchnl_vf_resource *vf_res; /* VF resource */
> >+ struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
> >+ uint16_t vsi_id;
> >+};
> >+
> >+int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
> >+ struct dcf_virtchnl_cmd *cmd);
> >+int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
> >+ void *buf, uint16_t buf_size);
> >+int ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw);
> >+int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
> >+void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
> >+
> >+#endif /* _ICE_DCF_H_ */
> >diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
> >new file mode 100644
> >index 000000000..f65b962d4
> >--- /dev/null
> >+++ b/drivers/net/ice/ice_dcf_ethdev.c
> >@@ -0,0 +1,319 @@
> >+/* SPDX-License-Identifier: BSD-3-Clause
> >+ * Copyright(c) 2019 Intel Corporation
> >+ */
> >+
> >+#include <errno.h>
> >+#include <stdbool.h>
> >+#include <sys/types.h>
> >+#include <sys/ioctl.h>
> >+#include <unistd.h>
> >+
> >+#include <rte_interrupts.h>
> >+#include <rte_debug.h>
> >+#include <rte_pci.h>
> >+#include <rte_atomic.h>
> >+#include <rte_eal.h>
> >+#include <rte_ether.h>
> >+#include <rte_ethdev_pci.h>
> >+#include <rte_kvargs.h>
> >+#include <rte_malloc.h>
> >+#include <rte_memzone.h>
> >+#include <rte_dev.h>
> >+
> >+#include <iavf_devids.h>
> >+
> >+#include "ice_generic_flow.h"
> >+#include "ice_dcf_ethdev.h"
> >+
> >+static uint16_t
> >+ice_dcf_recv_pkts(__rte_unused void *rx_queue,
> >+ __rte_unused struct rte_mbuf **bufs,
> >+ __rte_unused uint16_t nb_pkts)
> >+{
> >+ return 0;
> >+}
> >+
> >+static uint16_t
> >+ice_dcf_xmit_pkts(__rte_unused void *tx_queue,
> >+ __rte_unused struct rte_mbuf **bufs,
> >+ __rte_unused uint16_t nb_pkts)
> >+{
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_dev_start(struct rte_eth_dev *dev)
> >+{
> >+ dev->data->dev_link.link_status = ETH_LINK_UP;
> >+
> >+ return 0;
> >+}
> >+
> >+static void
> >+ice_dcf_dev_stop(struct rte_eth_dev *dev)
> >+{
> >+ dev->data->dev_link.link_status = ETH_LINK_DOWN;
> >+}
> >+
> >+static int
> >+ice_dcf_dev_configure(__rte_unused struct rte_eth_dev *dev)
> >+{
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_dev_info_get(struct rte_eth_dev *dev,
> >+ struct rte_eth_dev_info *dev_info)
> >+{
> >+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
> >+
> >+ dev_info->max_mac_addrs = 1;
> >+ dev_info->max_rx_pktlen = (uint32_t)-1;
> >+ dev_info->max_rx_queues = RTE_DIM(adapter->rxqs);
> >+ dev_info->max_tx_queues = RTE_DIM(adapter->txqs);
> >+
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_stats_get(__rte_unused struct rte_eth_dev *dev,
> >+ __rte_unused struct rte_eth_stats *igb_stats)
> >+{
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_stats_reset(__rte_unused struct rte_eth_dev *dev)
> >+{
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_dev_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
> >+{
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_dev_promiscuous_disable(__rte_unused struct rte_eth_dev *dev)
> >+{
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_dev_allmulticast_enable(__rte_unused struct rte_eth_dev *dev)
> >+{
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_dev_allmulticast_disable(__rte_unused struct rte_eth_dev *dev)
> >+{
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
> >+ enum rte_filter_type filter_type,
> >+ __rte_unused enum rte_filter_op filter_op,
> >+ __rte_unused void *arg)
> >+{
>
> legacy filter API will be deprecated, I think we should avoid adding support
> in new PMD.
This is the entry for new filter:
dev->dev_ops->filter_ctrl(dev,
RTE_ETH_FILTER_GENERIC,
RTE_ETH_FILTER_GET,
&ops)
>
> >+ int ret = 0;
> >+
> >+ if (!dev)
> >+ return -EINVAL;
> >+
> >+ switch (filter_type) {
> >+ default:
> >+ PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
> >+ filter_type);
> >+ ret = -EINVAL;
> >+ break;
> >+ }
> >+
> >+ return ret;
> >+}
> >+
> >+static void
> >+ice_dcf_dev_close(struct rte_eth_dev *dev)
> >+{
> >+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
> >+
> >+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
> >+ return;
> >+
> >+ dev->dev_ops = NULL;
> >+ dev->rx_pkt_burst = NULL;
> >+ dev->tx_pkt_burst = NULL;
> >+
> >+ ice_dcf_uninit_parent_adapter(dev);
> >+ ice_dcf_uninit_hw(dev, &adapter->real_hw);
> >+}
> >+
> >+static void
> >+ice_dcf_queue_release(__rte_unused void *q)
> >+{
> >+}
> >+
> >+static int
> >+ice_dcf_link_update(__rte_unused struct rte_eth_dev *dev,
> >+ __rte_unused int wait_to_complete)
> >+{
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_rx_queue_setup(struct rte_eth_dev *dev,
> >+ uint16_t rx_queue_id,
> >+ __rte_unused uint16_t nb_rx_desc,
> >+ __rte_unused unsigned int socket_id,
> >+ __rte_unused const struct rte_eth_rxconf *rx_conf,
> >+ __rte_unused struct rte_mempool *mb_pool)
> >+{
> >+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
> >+
> >+ dev->data->rx_queues[rx_queue_id] = &adapter->rxqs[rx_queue_id];
> >+
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_tx_queue_setup(struct rte_eth_dev *dev,
> >+ uint16_t tx_queue_id,
> >+ __rte_unused uint16_t nb_tx_desc,
> >+ __rte_unused unsigned int socket_id,
> >+ __rte_unused const struct rte_eth_txconf *tx_conf)
> >+{
> >+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
> >+
> >+ dev->data->tx_queues[tx_queue_id] = &adapter->txqs[tx_queue_id];
> >+
> >+ return 0;
> >+}
> >+
> >+static const struct eth_dev_ops ice_dcf_eth_dev_ops = {
> >+ .dev_start = ice_dcf_dev_start,
> >+ .dev_stop = ice_dcf_dev_stop,
> >+ .dev_close = ice_dcf_dev_close,
> >+ .dev_configure = ice_dcf_dev_configure,
> >+ .dev_infos_get = ice_dcf_dev_info_get,
> >+ .rx_queue_setup = ice_dcf_rx_queue_setup,
> >+ .tx_queue_setup = ice_dcf_tx_queue_setup,
> >+ .rx_queue_release = ice_dcf_queue_release,
> >+ .tx_queue_release = ice_dcf_queue_release,
> >+ .link_update = ice_dcf_link_update,
> >+ .stats_get = ice_dcf_stats_get,
> >+ .stats_reset = ice_dcf_stats_reset,
> >+ .promiscuous_enable = ice_dcf_dev_promiscuous_enable,
> >+ .promiscuous_disable = ice_dcf_dev_promiscuous_disable,
> >+ .allmulticast_enable = ice_dcf_dev_allmulticast_enable,
> >+ .allmulticast_disable = ice_dcf_dev_allmulticast_disable,
> >+ .filter_ctrl = ice_dcf_dev_filter_ctrl,
> >+};
> >+
> >+static int
> >+ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
> >+{
> >+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
> >+
> >+ eth_dev->dev_ops = &ice_dcf_eth_dev_ops;
> >+ eth_dev->rx_pkt_burst = ice_dcf_recv_pkts;
> >+ eth_dev->tx_pkt_burst = ice_dcf_xmit_pkts;
> >+
> >+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
> >+ return 0;
> >+
> >+ eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
> >+
> >+ adapter->real_hw.vc_event_msg_cb = ice_dcf_handle_pf_event_msg;
> >+ if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
> >+ PMD_DRV_LOG(ERR, "Failed to init DCF hardware");
>
> Use PMD_INIT_LOG instead.
>
> >+ return -1;
> >+ }
> >+
> >+ if (ice_dcf_init_parent_adapter(eth_dev) != 0) {
> >+ PMD_DRV_LOG(ERR, "Failed to init DCF parent adapter");
>
> Use PMD_INIT_LOG instead.
>
> >+ ice_dcf_uninit_hw(eth_dev, &adapter->real_hw);
> >+ return -1;
> >+ }
> >+
> >+ return 0;
> >+}
> >+
> >+static int
> >+ice_dcf_dev_uninit(struct rte_eth_dev *eth_dev)
> >+{
> >+ ice_dcf_dev_close(eth_dev);
> >+
> >+ return 0;
> >+}
> >+
> >+static int
> >+handle_dcf_arg(__rte_unused const char *key, const char *value,
> >+ __rte_unused void *arg)
> >+{
> >+ bool *dcf = arg;
> >+
> >+ if (arg == NULL || value == NULL)
> >+ return -EINVAL;
> >+
> >+ if (strcmp(value, "dcf") == 0)
> >+ *dcf = true;
> >+ else
> >+ *dcf = false;
> >+
> >+ return 0;
> >+}
> >+
> >+static bool
> >+check_cap_dcf_enable(struct rte_devargs *devargs)
> >+{
> >+ struct rte_kvargs *kvlist;
> >+ bool enable = false;
> >+
> >+ if (devargs == NULL)
> >+ return false;
> >+
> >+ kvlist = rte_kvargs_parse(devargs->args, NULL);
> >+ if (kvlist == NULL)
> >+ return false;
> >+
> >+ rte_kvargs_process(kvlist, "cap", handle_dcf_arg, &enable);
>
> Need error handing for failure case.
Fixed in v2.
> >+
> >+ rte_kvargs_free(kvlist);
> >+
> >+ return enable;
> >+}
> >+
> >+static int eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
> >+ struct rte_pci_device *pci_dev)
> >+{
> >+ if (!check_cap_dcf_enable(pci_dev->device.devargs))
> >+ return 1; /* continue to probe */
>
> I think the code is self explanatory, this straightforward comment is unnecessary.
Make sense, will remove it.
>
> >+
> >+ return rte_eth_dev_pci_generic_probe(pci_dev,
> >+ sizeof(struct ice_dcf_adapter),
> >+ ice_dcf_dev_init);
> >+}
> >+
> >+static int eth_ice_dcf_pci_remove(struct rte_pci_device *pci_dev)
> >+{
> >+ return rte_eth_dev_pci_generic_remove(pci_dev, ice_dcf_dev_uninit);
> >+}
> >+
> >+static const struct rte_pci_id pci_id_ice_dcf_map[] = {
> >+ { RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
> >+ { .vendor_id = 0, /* sentinel */ },
> >+};
> >+
> >+static struct rte_pci_driver rte_ice_dcf_pmd = {
> >+ .id_table = pci_id_ice_dcf_map,
> >+ .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
> >+ .probe = eth_ice_dcf_pci_probe,
> >+ .remove = eth_ice_dcf_pci_remove,
> >+};
> >+
> >+RTE_PMD_REGISTER_PCI(net_ice_dcf, rte_ice_dcf_pmd);
> >+RTE_PMD_REGISTER_PCI_TABLE(net_ice_dcf, pci_id_ice_dcf_map);
> >+RTE_PMD_REGISTER_KMOD_DEP(net_ice_dcf, "* igb_uio | vfio-pci");
> >+RTE_PMD_REGISTER_PARAM_STRING(net_ice_dcf, "cap=dcf");
> >diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
> >new file mode 100644
> >index 000000000..e95266599
> >--- /dev/null
> >+++ b/drivers/net/ice/ice_dcf_ethdev.h
> >@@ -0,0 +1,33 @@
> >+/* SPDX-License-Identifier: BSD-3-Clause
> >+ * Copyright(c) 2019 Intel Corporation
> >+ */
> >+
> >+#ifndef _ICE_DCF_ETHDEV_H_
> >+#define _ICE_DCF_ETHDEV_H_
> >+
> >+#include "base/ice_common.h"
> >+#include "base/ice_adminq_cmd.h"
> >+
> >+#include "ice_ethdev.h"
> >+#include "ice_dcf.h"
> >+
> >+#define ICE_DCF_MAX_RINGS 1
> >+
> >+struct ice_dcf_queue {
> >+ uint64_t dummy;
> >+};
> >+
> >+struct ice_dcf_adapter {
> >+ struct ice_adapter parent; /* Must be first */
> >+
> >+ struct ice_dcf_hw real_hw;
> >+ struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
> >+ struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
> >+};
> >+
> >+void ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
> >+ uint8_t *msg, uint16_t msglen);
> >+int ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev);
> >+void ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev);
> >+
> >+#endif /* _ICE_DCF_ETHDEV_H_ */
> >diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
> >new file mode 100644
> >index 000000000..bca9cd34a
> >--- /dev/null
> >+++ b/drivers/net/ice/ice_dcf_parent.c
> >@@ -0,0 +1,348 @@
> >+/* SPDX-License-Identifier: BSD-3-Clause
> >+ * Copyright(c) 2019 Intel Corporation
> >+ */
> >+#include <sys/types.h>
> >+#include <sys/stat.h>
> >+#include <unistd.h>
> >+
> >+#include <rte_alarm.h>
> >+
> >+#include "ice_dcf_ethdev.h"
> >+#include "ice_generic_flow.h"
> >+
> >+#define ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL 100000 /* us */
> >+
> >+static __rte_always_inline void
> >+ice_dcf_update_vsi_ctx(struct ice_hw *hw, uint16_t vsi_handle,
> >+ uint16_t vsi_map)
> >+{
> >+ struct ice_vsi_ctx *vsi_ctx;
> >+
> >+ if (unlikely(vsi_handle >= ICE_MAX_VSI)) {
> >+ PMD_DRV_LOG(ERR, "Invalid vsi handle %u", vsi_handle);
> >+ return;
> >+ }
> >+
> >+ vsi_ctx = hw->vsi_ctx[vsi_handle];
> >+
> >+ if (vsi_map & VIRTCHNL_DCF_VF_VSI_VALID) {
> >+ if (!vsi_ctx)
> >+ vsi_ctx = ice_malloc(hw, sizeof(*vsi_ctx));
> >+
> >+ if (!vsi_ctx) {
> >+ PMD_DRV_LOG(ERR, "No memory for vsi context %u",
> >+ vsi_handle);
> >+ return;
> >+ }
> >+
> >+ vsi_ctx->vsi_num = (vsi_map & VIRTCHNL_DCF_VF_VSI_ID_M) >>
> >+ VIRTCHNL_DCF_VF_VSI_ID_S;
> >+ hw->vsi_ctx[vsi_handle] = vsi_ctx;
> >+
> >+ PMD_DRV_LOG(DEBUG, "VF%u is assigned with vsi number %u",
> >+ vsi_handle, vsi_ctx->vsi_num);
> >+ } else {
> >+ hw->vsi_ctx[vsi_handle] = NULL;
> >+
> >+ if (vsi_ctx)
> >+ ice_free(hw, vsi_ctx);
>
> Doesn't need to check vsi_ctx is NUll or not, ice_free (rte_free) would do it inside.
>
> >+
> >+ PMD_DRV_LOG(NOTICE, "VF%u is disabled", vsi_handle);
> >+ }
> >+}
> >+
> >+static void
> >+ice_dcf_update_vf_vsi_map(struct ice_hw *hw, uint16_t num_vfs,
> >+ uint16_t *vf_vsi_map)
> >+{
> >+ uint16_t vf_id;
> >+
> >+ for (vf_id = 0; vf_id < num_vfs; vf_id++)
> >+ ice_dcf_update_vsi_ctx(hw, vf_id, vf_vsi_map[vf_id]);
> >+}
> >+
> >+static void
> >+ice_dcf_vsi_update_service_handler(void *param)
> >+{
> >+ struct ice_dcf_hw *hw = param;
> >+
> >+ if (!ice_dcf_handle_vsi_update_event(hw)) {
> >+ struct ice_dcf_adapter *dcf_ad =
> >+ container_of(hw, struct ice_dcf_adapter, real_hw);
> >+
> >+ ice_dcf_update_vf_vsi_map(&dcf_ad->parent.hw,
> >+ hw->num_vfs, hw->vf_vsi_map);
> >+ }
> >+}
> >+
> >+void
> >+ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
> >+ uint8_t *msg, uint16_t msglen)
> >+{
> >+ struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
> >+
> >+ if (msglen < sizeof(struct virtchnl_pf_event)) {
> >+ PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen);
> >+ return;
> >+ }
> >+
> >+ switch (pf_msg->event) {
> >+ case VIRTCHNL_EVENT_RESET_IMPENDING:
> >+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
> >+ rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL * 2,
> >+ ice_dcf_vsi_update_service_handler, dcf_hw);
> >+ break;
> >+ case VIRTCHNL_EVENT_LINK_CHANGE:
> >+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
> >+ break;
> >+ case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
> >+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
> >+ break;
> >+ case VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE:
> >+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE event : VF%u with VSI num %u",
> >+ pf_msg->event_data.vf_vsi_map.vf_id,
> >+ pf_msg->event_data.vf_vsi_map.vsi_id);
> >+ rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL,
> >+ ice_dcf_vsi_update_service_handler, dcf_hw);
> >+ break;
> >+ default:
> >+ PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
> >+ break;
> >+ }
> >+}
> >+
> >+static int
> >+ice_dcf_init_parent_hw(struct ice_hw *hw)
> >+{
> >+ struct ice_aqc_get_phy_caps_data *pcaps;
> >+ enum ice_status status;
> >+
> >+ status = ice_aq_get_fw_ver(hw, NULL);
> >+ if (status)
> >+ return status;
> >+
> >+ status = ice_get_caps(hw);
> >+ if (status)
> >+ return status;
> >+
> >+ hw->port_info = (struct ice_port_info *)
> >+ ice_malloc(hw, sizeof(*hw->port_info));
> >+ if (!hw->port_info)
> >+ return ICE_ERR_NO_MEMORY;
> >+
> >+ /* set the back pointer to HW */
> >+ hw->port_info->hw = hw;
> >+
> >+ /* Initialize port_info struct with switch configuration data */
> >+ status = ice_get_initial_sw_cfg(hw);
> >+ if (status)
> >+ goto err_unroll_alloc;
> >+
> >+ pcaps = (struct ice_aqc_get_phy_caps_data *)
> >+ ice_malloc(hw, sizeof(*pcaps));
> >+ if (!pcaps) {
> >+ status = ICE_ERR_NO_MEMORY;
> >+ goto err_unroll_alloc;
> >+ }
> >+
> >+ /* Initialize port_info struct with PHY capabilities */
> >+ status = ice_aq_get_phy_caps(hw->port_info, false,
> >+ ICE_AQC_REPORT_TOPO_CAP, pcaps, NULL);
> >+ ice_free(hw, pcaps);
> >+ if (status)
> >+ goto err_unroll_alloc;
> >+
> >+ /* Initialize port_info struct with link information */
> >+ status = ice_aq_get_link_info(hw->port_info, false, NULL, NULL);
> >+ if (status)
> >+ goto err_unroll_alloc;
> >+
> >+ status = ice_init_fltr_mgmt_struct(hw);
> >+ if (status)
> >+ goto err_unroll_alloc;
> >+
> >+ status = ice_init_hw_tbls(hw);
> >+ if (status)
> >+ goto err_unroll_fltr_mgmt_struct;
> >+
> >+ PMD_DRV_LOG(INFO,
>
> PMD_INIT_LOG
>
> >+ "firmware %d.%d.%d api %d.%d.%d build 0x%08x",
> >+ hw->fw_maj_ver, hw->fw_min_ver, hw->fw_patch,
> >+ hw->api_maj_ver, hw->api_min_ver, hw->api_patch,
> >+ hw->fw_build);
> >+
> >+ return ICE_SUCCESS;
> >+
> >+err_unroll_fltr_mgmt_struct:
> >+ ice_cleanup_fltr_mgmt_struct(hw);
> >+err_unroll_alloc:
> >+ ice_free(hw, hw->port_info);
> >+ hw->port_info = NULL;
> >+
> >+ return status;
> >+}
> >+
> >+static void ice_dcf_uninit_parent_hw(struct ice_hw *hw)
> >+{
> >+ ice_cleanup_fltr_mgmt_struct(hw);
> >+
> >+ ice_free_seg(hw);
> >+ ice_free_hw_tbls(hw);
> >+
> >+ if (hw->port_info) {
> >+ ice_free(hw, hw->port_info);
>
> Doesn't need to check whether hw->port_info is NULL or not, ice_free (rte_free) would do it inside.
>
> >+ hw->port_info = NULL;
> >+ }
> >+
> >+ ice_clear_all_vsi_ctx(hw);
> >+}
> >+
> >+static int
> >+ice_dcf_request_pkg_name(struct ice_hw *hw, char *pkg_name)
> >+{
> >+ struct ice_dcf_adapter *dcf_adapter =
> >+ container_of(hw, struct ice_dcf_adapter, parent.hw);
> >+
> >+ /* TODO: check with DSN firstly by iAVF */
> >+ PMD_DRV_LOG(DEBUG,
> >+ "DCF VSI_ID = %u",
> >+ dcf_adapter->real_hw.vsi_id);
> >+
> >+ snprintf(pkg_name,
> >+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_UPDATES);
> >+ if (!access(pkg_name, 0))
> >+ return 0;
> >+
> >+ snprintf(pkg_name,
> >+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_DEFAULT);
> >+ if (!access(pkg_name, 0))
> >+ return 0;
> >+
> >+ return -1;
> >+}
> >+
> >+static int
> >+ice_dcf_load_pkg(struct ice_hw *hw)
> >+{
> >+ char pkg_name[ICE_MAX_PKG_FILENAME_SIZE];
> >+ uint8_t *pkg_buf;
> >+ uint32_t buf_len;
> >+ struct stat st;
> >+ FILE *fp;
> >+ int err;
> >+
> >+ if (ice_dcf_request_pkg_name(hw, pkg_name)) {
> >+ PMD_INIT_LOG(ERR, "failed to locate the package file");
> >+ return -ENOENT;
> >+ }
> >+
> >+ PMD_INIT_LOG(DEBUG, "DDP package name: %s", pkg_name);
> >+
> >+ err = stat(pkg_name, &st);
> >+ if (err) {
> >+ PMD_INIT_LOG(ERR, "failed to get file status");
> >+ return err;
> >+ }
> >+
> >+ buf_len = st.st_size;
> >+ pkg_buf = rte_malloc(NULL, buf_len, 0);
> >+ if (!pkg_buf) {
> >+ PMD_INIT_LOG(ERR, "failed to allocate buffer of size %u for package",
> >+ buf_len);
> >+ return -1;
> >+ }
> >+
> >+ fp = fopen(pkg_name, "rb");
> >+ if (!fp) {
> >+ PMD_INIT_LOG(ERR, "failed to open file: %s", pkg_name);
> >+ err = -1;
> >+ goto ret;
> >+ }
> >+
> >+ err = fread(pkg_buf, buf_len, 1, fp);
> >+ fclose(fp);
> >+ if (err != 1) {
> >+ PMD_INIT_LOG(ERR, "failed to read package data");
> >+ err = -1;
> >+ goto ret;
> >+ }
> >+
> >+ err = ice_copy_and_init_pkg(hw, pkg_buf, buf_len);
> >+ if (err)
> >+ PMD_INIT_LOG(ERR, "ice_copy_and_init_hw failed: %d", err);
> >+
> >+ret:
> >+ rte_free(pkg_buf);
> >+ return err;
> >+}
> >+
> >+int
> >+ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
> >+{
> >+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
> >+ struct ice_adapter *parent_adapter = &adapter->parent;
> >+ struct ice_hw *parent_hw = &parent_adapter->hw;
> >+ struct ice_dcf_hw *hw = &adapter->real_hw;
> >+ const struct rte_ether_addr *mac;
> >+ int err;
> >+
> >+ parent_adapter->eth_dev = eth_dev;
> >+ parent_adapter->pf.adapter = parent_adapter;
> >+ parent_adapter->pf.dev_data = eth_dev->data;
> >+ parent_hw->back = parent_adapter;
> >+ parent_hw->mac_type = ICE_MAC_GENERIC;
> >+ parent_hw->vendor_id = ICE_INTEL_VENDOR_ID;
> >+
> >+ ice_init_lock(&parent_hw->adminq.sq_lock);
> >+ ice_init_lock(&parent_hw->adminq.rq_lock);
> >+ parent_hw->aq_send_cmd_fn = ice_dcf_send_aq_cmd;
> >+ parent_hw->aq_send_cmd_param = &adapter->real_hw;
> >+ parent_hw->dcf_enabled = true;
> >+
> >+ err = ice_dcf_init_parent_hw(parent_hw);
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR, "failed to init the DCF parent hardware with error %d",
>
> PMD_INIT_LOG
>
> >+ err);
> >+ return err;
> >+ }
> >+
> >+ err = ice_dcf_load_pkg(parent_hw);
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR, "failed to load package with error %d",
>
> PMD_INIT_LOG
>
> >+ err);
> >+ goto uninit_hw;
> >+ }
> >+ parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
> >+
> >+ ice_dcf_update_vf_vsi_map(parent_hw,
> >+ hw->num_vfs, hw->vf_vsi_map);
> >+
> >+ mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
> >+ if (rte_is_valid_assigned_ether_addr(mac))
> >+ rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
> >+ else
> >+ rte_eth_random_addr(parent_adapter->pf.dev_addr.addr_bytes);
> >+
> >+ eth_dev->data->mac_addrs = &parent_adapter->pf.dev_addr;
> >+
> >+ return 0;
> >+
> >+uninit_hw:
> >+ ice_dcf_uninit_parent_hw(parent_hw);
> >+ return err;
> >+}
> >+
> >+void
> >+ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
> >+{
> >+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
> >+ struct ice_adapter *parent_adapter = &adapter->parent;
> >+ struct ice_hw *parent_hw = &parent_adapter->hw;
> >+
> >+ eth_dev->data->mac_addrs = NULL;
> >+
> >+ rte_eal_alarm_cancel(ice_dcf_vsi_update_service_handler,
> >+ &adapter->real_hw);
> >+
> >+ ice_dcf_uninit_parent_hw(parent_hw);
> >+}
> >diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
> >index f9e897bbc..0df8ddc0f 100644
> >--- a/drivers/net/ice/meson.build
> >+++ b/drivers/net/ice/meson.build
> >@@ -15,8 +15,8 @@ sources = files(
> > 'ice_hash.c'
> > )
> >
> >-deps += ['hash']
> >-includes += include_directories('base')
> >+deps += ['hash', 'net', 'common_iavf']
> >+includes += include_directories('base', '../../common/iavf')
> >
> > if arch_subdir == 'x86'
> > sources += files('ice_rxtx_vec_sse.c')
> >@@ -37,4 +37,8 @@ if arch_subdir == 'x86'
> > endif
> > endif
> >
> >+sources += files('ice_dcf.c',
> >+ 'ice_dcf_parent.c',
> >+ 'ice_dcf_ethdev.c')
> >+
> > install_headers('rte_pmd_ice.h')
> >diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> >index d295ca0a5..f3798a09f 100644
> >--- a/mk/rte.app.mk
> >+++ b/mk/rte.app.mk
> >@@ -185,6 +185,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += -lrte_pmd_i40e
> > _LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD) += -lrte_pmd_iavf
> > _LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += -lrte_pmd_ice
> > IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
> >+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
> > ifeq ($(findstring y,$(IAVF-y)),y)
> > _LDLIBS-y += -lrte_common_iavf
> > endif
> >--
> >2.25.1
> >
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 3/4] net/ice: add the DCF framework
2020-03-10 5:09 ` Wang, Haiyue
@ 2020-03-10 5:23 ` Ye Xiaolong
0 siblings, 0 replies; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-10 5:23 UTC (permalink / raw)
To: Wang, Haiyue; +Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei
On 03/10, Wang, Haiyue wrote:
>> >+static int
>> >+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
>> >+ enum rte_filter_type filter_type,
>> >+ __rte_unused enum rte_filter_op filter_op,
>> >+ __rte_unused void *arg)
>> >+{
>>
>> legacy filter API will be deprecated, I think we should avoid adding support
>> in new PMD.
>
>This is the entry for new filter:
>
>dev->dev_ops->filter_ctrl(dev,
> RTE_ETH_FILTER_GENERIC,
> RTE_ETH_FILTER_GET,
> &ops)
Right, I have some misunderstanding before, the filter API will be deprecated,
but the dev->filter_ctrl ops is still needed.
Thanks,
Xiaolong
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
2020-03-09 14:14 [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support Haiyue Wang
` (4 preceding siblings ...)
2020-03-09 15:36 ` [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support David Marchand
@ 2020-03-10 6:50 ` Haiyue Wang
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
` (7 more replies)
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 " Haiyue Wang
` (3 subsequent siblings)
9 siblings, 8 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-10 6:50 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A DCF (Device Config Function) based approach is proposed where a device
bound to the device's VF0 can act as a sole controlling entity to exercise
advance functionality (such as switch, ACL) for rest of the VFs.
The DCF works as a standalone PMD to support this function, which shares the
ice PMD flow control core function and the iavf virtchnl mailbox core module.
This patchset is based on:
[1] https://patchwork.dpdk.org/cover/66417/ : update ice base code
[2] https://patchwork.dpdk.org/cover/66472/ : iavf share code update
Depends-on: series-8843
Depends-on: series-8855
v2:
1. update the iavf patchset link.
2. split more patches for making this work be more understandable
3. fix the log function usage, devargs checking from v1.
Haiyue Wang (7):
net/iavf: stop the PCI probe in DCF mode
net/ice: add the DCF hardware initialization
net/ice: initiate to acquire the DCF capability
net/ice: handle the AdminQ command by DCF
net/ice: export the DDP definition symbols
net/ice: handle the PF initialization by DCF
net/ice: get the VF hardware index in DCF
doc/guides/nics/ice.rst | 47 ++
doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
doc/guides/rel_notes/release_20_05.rst | 5 +
drivers/common/Makefile | 1 +
drivers/net/iavf/iavf_ethdev.c | 43 ++
drivers/net/ice/Makefile | 6 +
drivers/net/ice/ice_dcf.c | 651 +++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 61 +++
drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
drivers/net/ice/ice_dcf_ethdev.h | 33 ++
drivers/net/ice/ice_dcf_parent.c | 344 +++++++++++++
drivers/net/ice/ice_ethdev.c | 9 +-
drivers/net/ice/ice_ethdev.h | 8 +
drivers/net/ice/meson.build | 8 +-
mk/rte.app.mk | 1 +
15 files changed, 1528 insertions(+), 10 deletions(-)
create mode 100644 doc/guides/nics/img/ice_dcf.png
create mode 100644 drivers/net/ice/ice_dcf.c
create mode 100644 drivers/net/ice/ice_dcf.h
create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
create mode 100644 drivers/net/ice/ice_dcf_parent.c
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v2 1/7] net/iavf: stop the PCI probe in DCF mode
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 0/7] " Haiyue Wang
@ 2020-03-10 6:50 ` Haiyue Wang
2020-03-13 5:27 ` Ye Xiaolong
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
` (6 subsequent siblings)
7 siblings, 1 reply; 94+ messages in thread
From: Haiyue Wang @ 2020-03-10 6:50 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A new DCF PMD will be introduced, which runs on Intel VF hardware, and
it is a pure software design to control the advance functionality (such
as switch, ACL) for rest of the VFs.
So if the DCF (Device Config Function) mode is specified by the devarg
'cap=dcf', then it will stop the PCI probe in the iavf PMD.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/iavf/iavf_ethdev.c | 43 ++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 34913f9c4..c0b95e169 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -1416,9 +1416,51 @@ iavf_dev_uninit(struct rte_eth_dev *dev)
return 0;
}
+static int
+iavf_dcf_cap_check_handler(__rte_unused const char *key,
+ const char *value, __rte_unused void *opaque)
+{
+ if (strcmp(value, "dcf"))
+ return -1;
+
+ return 0;
+}
+
+static int
+iavf_dcf_cap_selected(struct rte_devargs *devargs)
+{
+ struct rte_kvargs *kvlist;
+ const char *key = "cap";
+ int ret = 0;
+
+ if (devargs == NULL)
+ return 0;
+
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
+ if (kvlist == NULL)
+ return 0;
+
+ if (!rte_kvargs_count(kvlist, key))
+ goto exit;
+
+ /* dcf capability selected when there's a key-value pair: cap=dcf */
+ if (rte_kvargs_process(kvlist, key,
+ iavf_dcf_cap_check_handler, NULL) < 0)
+ goto exit;
+
+ ret = 1;
+
+exit:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
static int eth_iavf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
struct rte_pci_device *pci_dev)
{
+ if (iavf_dcf_cap_selected(pci_dev->device.devargs))
+ return 1;
+
return rte_eth_dev_pci_generic_probe(pci_dev,
sizeof(struct iavf_adapter), iavf_dev_init);
}
@@ -1439,6 +1481,7 @@ static struct rte_pci_driver rte_iavf_pmd = {
RTE_PMD_REGISTER_PCI(net_iavf, rte_iavf_pmd);
RTE_PMD_REGISTER_PCI_TABLE(net_iavf, pci_id_iavf_map);
RTE_PMD_REGISTER_KMOD_DEP(net_iavf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_iavf, "cap=dcf");
RTE_INIT(iavf_init_log)
{
iavf_logtype_init = rte_log_register("pmd.net.iavf.init");
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v2 2/7] net/ice: add the DCF hardware initialization
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 0/7] " Haiyue Wang
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
@ 2020-03-10 6:50 ` Haiyue Wang
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 3/7] net/ice: initiate to acquire the DCF capability Haiyue Wang
` (5 subsequent siblings)
7 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-10 6:50 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
Introduce the DCF (Device Config Function) feature in the ice PMD, it
works as a standalone PMD which doesn't handle the packet Rx/Tx related
things. Its hardware entity is the VF.
Add the basic DCF hardware initialization, this is specified by devarg
'cap=dcf'.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
doc/guides/nics/ice.rst | 47 +++
doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
doc/guides/rel_notes/release_20_05.rst | 5 +
drivers/common/Makefile | 1 +
drivers/net/ice/Makefile | 5 +
drivers/net/ice/ice_dcf.c | 474 +++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 52 +++
drivers/net/ice/ice_dcf_ethdev.c | 317 +++++++++++++++++
drivers/net/ice/ice_dcf_ethdev.h | 24 ++
drivers/net/ice/meson.build | 7 +-
mk/rte.app.mk | 1 +
11 files changed, 931 insertions(+), 2 deletions(-)
create mode 100644 doc/guides/nics/img/ice_dcf.png
create mode 100644 drivers/net/ice/ice_dcf.c
create mode 100644 drivers/net/ice/ice_dcf.h
create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 8af32dabf..2639ae239 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -240,6 +240,53 @@ report a MDD event and drop the packets.
The APPs based on DPDK should avoid providing such packets.
+Device Config Function (DCF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section demonstrates ICE DCF PMD, which shares the core module with ICE
+PMD and iAVF PMD.
+
+A DCF (Device Config Function) PMD bounds to the device's trusted VF with ID 0,
+it can act as a sole controlling entity to exercise advance functionality (such
+as switch, ACL) for the rest VFs.
+
+The DCF PMD needs to advertise and acquire DCF capability which allows DCF to
+send AdminQ commands that it would like to execute over to the PF and receive
+responses for the same from PF.
+
+.. _figure_ice_dcf:
+
+.. figure:: img/ice_dcf.*
+
+ DCF Communication flow.
+
+#. Create the VFs::
+
+ echo 4 > /sys/bus/pci/devices/0000\:18\:00.0/sriov_numvfs
+
+#. Enable the VF0 trust on::
+
+ ip link set dev enp24s0f0 vf 0 trust on
+
+#. Bind the VF0, and run testpmd with 'cap=dcf' devarg::
+
+ testpmd -l 22-25 -n 4 -w 18:01.0,cap=dcf -- -i
+
+#. Monitor the VF2 interface network traffic::
+
+ tcpdump -e -nn -i enp24s1f2
+
+#. Create one flow to redirect the traffic to VF2 by DCF::
+
+ flow create 0 priority 0 ingress pattern eth / ipv4 src is 192.168.0.2 \
+ dst is 192.168.0.3 / end actions vf id 2 / end
+
+#. Send the packet, and it should be displayed on tcpdump::
+
+ sendp(Ether(src='3c:fd:fe:aa:bb:78', dst='00:00:00:01:02:03')/IP(src=' \
+ 192.168.0.2', dst="192.168.0.3")/TCP(flags='S')/Raw(load='XXXXXXXXXX'), \
+ iface="enp24s0f0", count=10)
+
Sample Application Notes
------------------------
diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
new file mode 100644
index 0000000000000000000000000000000000000000..540823c4a05e9ea9d558d233fea77016d1ae5df3
GIT binary patch
literal 39168
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
literal 0
HcmV?d00001
diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 000bbf501..f404ee7fd 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -62,6 +62,11 @@ New Features
* Added support for matching on IPv4 Time To Live and IPv6 Hop Limit.
+* **Updated the Intel ice driver.**
+
+ Updated the Intel ice driver with new features and improvements, including:
+
+ * Added support for DCF (Device Config Function) feature.
Removed Items
-------------
diff --git a/drivers/common/Makefile b/drivers/common/Makefile
index 96bd7ac6e..df2e840cf 100644
--- a/drivers/common/Makefile
+++ b/drivers/common/Makefile
@@ -31,6 +31,7 @@ DIRS-y += dpaax
endif
IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
ifneq (,$(findstring y,$(IAVF-y)))
DIRS-y += iavf
endif
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index e22c34287..f493c9ed7 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -11,9 +11,11 @@ LIB = librte_pmd_ice.a
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
+LDLIBS += -lrte_net -lrte_common_iavf
EXPORT_MAP := rte_pmd_ice_version.map
@@ -84,6 +86,9 @@ ifeq ($(CC_AVX2_SUPPORT), 1)
endif
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+
# install this header file
SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
new file mode 100644
index 000000000..efb258a5a
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.c
@@ -0,0 +1,474 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include "ice_dcf.h"
+
+#define ICE_DCF_AQ_LEN 32
+#define ICE_DCF_AQ_BUF_SZ 4096
+
+#define ICE_DCF_ARQ_MAX_RETRIES 200
+#define ICE_DCF_ARQ_CHECK_TIME 2 /* msecs */
+
+#define ICE_DCF_VF_RES_BUF_SZ \
+ (sizeof(struct virtchnl_vf_resource) + \
+ IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource))
+
+static __rte_always_inline int
+ice_dcf_send_cmd_req_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+ uint8_t *req_msg, uint16_t req_msglen)
+{
+ return iavf_aq_send_msg_to_pf(&hw->avf, op, IAVF_SUCCESS,
+ req_msg, req_msglen, NULL);
+}
+
+static int
+ice_dcf_recv_cmd_rsp_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+ uint8_t *rsp_msgbuf, uint16_t rsp_buflen,
+ uint16_t *rsp_msglen)
+{
+ struct iavf_arq_event_info event;
+ enum virtchnl_ops v_op;
+ int i = 0;
+ int err;
+
+ event.buf_len = rsp_buflen;
+ event.msg_buf = rsp_msgbuf;
+
+ do {
+ err = iavf_clean_arq_element(&hw->avf, &event, NULL);
+ if (err != IAVF_SUCCESS)
+ goto again;
+
+ v_op = rte_le_to_cpu_32(event.desc.cookie_high);
+ if (v_op != op)
+ goto again;
+
+ if (rsp_msglen != NULL)
+ *rsp_msglen = event.msg_len;
+ return rte_le_to_cpu_32(event.desc.cookie_low);
+
+again:
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ return -EIO;
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_clear(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_REMOVE(&hw->vc_cmd_queue, cmd, next);
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline void
+ice_dcf_vc_cmd_set(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ cmd->v_ret = IAVF_ERR_NOT_READY;
+ cmd->rsp_msglen = 0;
+ cmd->pending = 1;
+
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_INSERT_TAIL(&hw->vc_cmd_queue, cmd, next);
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline int
+ice_dcf_vc_cmd_send(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ return iavf_aq_send_msg_to_pf(&hw->avf,
+ cmd->v_op, IAVF_SUCCESS,
+ cmd->req_msg, cmd->req_msglen, NULL);
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
+{
+ struct dcf_virtchnl_cmd *cmd;
+ enum virtchnl_ops v_op;
+ enum iavf_status v_ret;
+ uint16_t aq_op;
+
+ aq_op = rte_le_to_cpu_16(info->desc.opcode);
+ if (unlikely(aq_op != iavf_aqc_opc_send_msg_to_vf)) {
+ PMD_DRV_LOG(ERR,
+ "Request %u is not supported yet", aq_op);
+ return;
+ }
+
+ v_op = rte_le_to_cpu_32(info->desc.cookie_high);
+ if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+ return;
+
+ v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
+
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_FOREACH(cmd, &hw->vc_cmd_queue, next) {
+ if (cmd->v_op == v_op && cmd->pending) {
+ cmd->v_ret = v_ret;
+ cmd->rsp_msglen = RTE_MIN(info->msg_len,
+ cmd->rsp_buflen);
+ if (likely(cmd->rsp_msglen != 0))
+ rte_memcpy(cmd->rsp_msgbuf, info->msg_buf,
+ cmd->rsp_msglen);
+
+ /* prevent compiler reordering */
+ rte_compiler_barrier();
+ cmd->pending = 0;
+ break;
+ }
+ }
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static void
+ice_dcf_handle_virtchnl_msg(struct ice_dcf_hw *hw)
+{
+ struct iavf_arq_event_info info;
+ uint16_t pending = 1;
+ int ret;
+
+ info.buf_len = ICE_DCF_AQ_BUF_SZ;
+ info.msg_buf = hw->arq_buf;
+
+ while (pending) {
+ ret = iavf_clean_arq_element(&hw->avf, &info, &pending);
+ if (ret != IAVF_SUCCESS)
+ break;
+
+ ice_dcf_aq_cmd_handle(hw, &info);
+ }
+}
+
+static int
+ice_dcf_init_check_api_version(struct ice_dcf_hw *hw)
+{
+#define ICE_CPF_VIRTCHNL_VERSION_MAJOR_START 1
+#define ICE_CPF_VIRTCHNL_VERSION_MINOR_START 1
+ struct virtchnl_version_info version, *pver;
+ int err;
+
+ version.major = VIRTCHNL_VERSION_MAJOR;
+ version.minor = VIRTCHNL_VERSION_MINOR;
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_VERSION,
+ (uint8_t *)&version, sizeof(version));
+ if (err) {
+ PMD_INIT_LOG(ERR, "Fail to send OP_VERSION");
+ return err;
+ }
+
+ pver = &hw->virtchnl_version;
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_VERSION,
+ (uint8_t *)pver, sizeof(*pver), NULL);
+ if (err) {
+ PMD_INIT_LOG(ERR, "Fail to get response of OP_VERSION");
+ return -1;
+ }
+
+ PMD_INIT_LOG(DEBUG,
+ "Peer PF API version: %u.%u", pver->major, pver->minor);
+
+ if (pver->major < ICE_CPF_VIRTCHNL_VERSION_MAJOR_START ||
+ (pver->major == ICE_CPF_VIRTCHNL_VERSION_MAJOR_START &&
+ pver->minor < ICE_CPF_VIRTCHNL_VERSION_MINOR_START)) {
+ PMD_INIT_LOG(ERR,
+ "VIRTCHNL API version should not be lower than (%u.%u)",
+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START,
+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START);
+ return -1;
+ } else if (pver->major > VIRTCHNL_VERSION_MAJOR ||
+ (pver->major == VIRTCHNL_VERSION_MAJOR &&
+ pver->minor > VIRTCHNL_VERSION_MINOR)) {
+ PMD_INIT_LOG(ERR,
+ "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
+ pver->major, pver->minor,
+ VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
+ return -1;
+ }
+
+ PMD_INIT_LOG(DEBUG, "Peer is supported PF host");
+
+ return 0;
+}
+
+static int
+ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
+{
+ uint32_t caps;
+ int err, i;
+
+ caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+ VF_BASE_MODE_OFFLOADS;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+ (uint8_t *)&caps, sizeof(caps));
+ if (err) {
+ PMD_DRV_LOG(ERR, "Fail to send msg OP_GET_VF_RESOURCE");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+ (uint8_t *)hw->vf_res,
+ ICE_DCF_VF_RES_BUF_SZ, NULL);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Fail to get response of OP_GET_VF_RESOURCE");
+ return -1;
+ }
+
+ iavf_vf_parse_hw_config(&hw->avf, hw->vf_res);
+
+ hw->vsi_res = NULL;
+ for (i = 0; i < hw->vf_res->num_vsis; i++) {
+ if (hw->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
+ hw->vsi_res = &hw->vf_res->vsi_res[i];
+ }
+
+ if (!hw->vsi_res) {
+ PMD_DRV_LOG(ERR, "no LAN VSI found");
+ return -1;
+ }
+
+ hw->vsi_id = hw->vsi_res->vsi_id;
+ PMD_DRV_LOG(DEBUG, "VSI ID is %u", hw->vsi_id);
+
+ return 0;
+}
+
+static int
+ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
+{
+#define ICE_DCF_RESET_WAIT_CNT 50
+ struct iavf_hw *avf = &hw->avf;
+ int i, reset;
+
+ for (i = 0; i < ICE_DCF_RESET_WAIT_CNT; i++) {
+ reset = IAVF_READ_REG(avf, IAVF_VFGEN_RSTAT) &
+ IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
+ reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
+
+ if (reset == VIRTCHNL_VFR_VFACTIVE ||
+ reset == VIRTCHNL_VFR_COMPLETED)
+ break;
+
+ rte_delay_ms(20);
+ }
+
+ if (i >= ICE_DCF_RESET_WAIT_CNT)
+ return -1;
+
+ return 0;
+}
+
+static inline void
+ice_dcf_enable_irq0(struct ice_dcf_hw *hw)
+{
+ struct iavf_hw *avf = &hw->avf;
+
+ /* Enable admin queue interrupt trigger */
+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1,
+ IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+ IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+ IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+ IAVF_WRITE_FLUSH(avf);
+}
+
+static inline void
+ice_dcf_disable_irq0(struct ice_dcf_hw *hw)
+{
+ struct iavf_hw *avf = &hw->avf;
+
+ /* Disable all interrupt types */
+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1, 0);
+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+ IAVF_WRITE_FLUSH(avf);
+}
+
+static void
+ice_dcf_dev_interrupt_handler(void *param)
+{
+ struct ice_dcf_hw *hw = param;
+
+ ice_dcf_disable_irq0(hw);
+
+ ice_dcf_handle_virtchnl_msg(hw);
+
+ ice_dcf_enable_irq0(hw);
+}
+
+int
+ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+ struct dcf_virtchnl_cmd *cmd)
+{
+ int i = 0;
+ int err;
+
+ if ((cmd->req_msg && !cmd->req_msglen) ||
+ (!cmd->req_msg && cmd->req_msglen) ||
+ (cmd->rsp_msgbuf && !cmd->rsp_buflen) ||
+ (!cmd->rsp_msgbuf && cmd->rsp_buflen))
+ return -EINVAL;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_vc_cmd_set(hw, cmd);
+
+ err = ice_dcf_vc_cmd_send(hw, cmd);
+ if (err) {
+ PMD_DRV_LOG(ERR, "fail to send cmd %d", cmd->v_op);
+ goto ret;
+ }
+
+ do {
+ if (!cmd->pending)
+ break;
+
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ if (cmd->v_ret != IAVF_SUCCESS) {
+ err = -1;
+ PMD_DRV_LOG(ERR,
+ "No response (%d times) or return failure (%d) for cmd %d",
+ i, cmd->v_ret, cmd->v_op);
+ }
+
+ret:
+ ice_dcf_aq_cmd_clear(hw, cmd);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+ return err;
+}
+
+int
+ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ int ret;
+
+ hw->avf.hw_addr = pci_dev->mem_resource[0].addr;
+ hw->avf.back = hw;
+
+ hw->avf.bus.bus_id = pci_dev->addr.bus;
+ hw->avf.bus.device = pci_dev->addr.devid;
+ hw->avf.bus.func = pci_dev->addr.function;
+
+ hw->avf.device_id = pci_dev->id.device_id;
+ hw->avf.vendor_id = pci_dev->id.vendor_id;
+ hw->avf.subsystem_device_id = pci_dev->id.subsystem_device_id;
+ hw->avf.subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+
+ hw->avf.aq.num_arq_entries = ICE_DCF_AQ_LEN;
+ hw->avf.aq.num_asq_entries = ICE_DCF_AQ_LEN;
+ hw->avf.aq.arq_buf_size = ICE_DCF_AQ_BUF_SZ;
+ hw->avf.aq.asq_buf_size = ICE_DCF_AQ_BUF_SZ;
+
+ rte_spinlock_init(&hw->vc_cmd_send_lock);
+ rte_spinlock_init(&hw->vc_cmd_queue_lock);
+ TAILQ_INIT(&hw->vc_cmd_queue);
+
+ hw->arq_buf = rte_zmalloc("arq_buf", ICE_DCF_AQ_BUF_SZ, 0);
+ if (hw->arq_buf == NULL) {
+ PMD_INIT_LOG(ERR, "unable to allocate AdminQ buffer memory");
+ goto err;
+ }
+
+ ret = iavf_set_mac_type(&hw->avf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "set_mac_type failed: %d", ret);
+ goto err;
+ }
+
+ ret = ice_dcf_check_reset_done(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "VF is still resetting");
+ goto err;
+ }
+
+ ret = iavf_init_adminq(&hw->avf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "init_adminq failed: %d", ret);
+ goto err;
+ }
+
+ if (ice_dcf_init_check_api_version(hw)) {
+ PMD_INIT_LOG(ERR, "check_api version failed");
+ goto err_api;
+ }
+
+ hw->vf_res = rte_zmalloc("vf_res", ICE_DCF_VF_RES_BUF_SZ, 0);
+ if (hw->vf_res == NULL) {
+ PMD_INIT_LOG(ERR, "unable to allocate vf_res memory");
+ goto err_api;
+ }
+
+ if (ice_dcf_get_vf_resource(hw)) {
+ PMD_INIT_LOG(ERR, "Failed to get VF resource");
+ goto err_alloc;
+ }
+
+ rte_intr_callback_register(&pci_dev->intr_handle,
+ ice_dcf_dev_interrupt_handler, hw);
+ rte_intr_enable(&pci_dev->intr_handle);
+ ice_dcf_enable_irq0(hw);
+
+ return 0;
+
+err_alloc:
+ rte_free(hw->vf_res);
+err_api:
+ iavf_shutdown_adminq(&hw->avf);
+err:
+ rte_free(hw->arq_buf);
+
+ return -1;
+}
+
+void
+ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
+ ice_dcf_disable_irq0(hw);
+ rte_intr_disable(intr_handle);
+ rte_intr_callback_unregister(intr_handle,
+ ice_dcf_dev_interrupt_handler, hw);
+
+ iavf_shutdown_adminq(&hw->avf);
+
+ rte_free(hw->arq_buf);
+ rte_free(hw->vf_res);
+}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
new file mode 100644
index 000000000..f44c09db2
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_H_
+#define _ICE_DCF_H_
+
+#include <rte_ethdev_driver.h>
+
+#include <iavf_prototype.h>
+#include <iavf_adminq_cmd.h>
+#include <iavf_type.h>
+
+#include "ice_logs.h"
+
+struct dcf_virtchnl_cmd {
+ TAILQ_ENTRY(dcf_virtchnl_cmd) next;
+
+ enum virtchnl_ops v_op;
+ enum iavf_status v_ret;
+
+ uint16_t req_msglen;
+ uint8_t *req_msg;
+
+ uint16_t rsp_msglen;
+ uint16_t rsp_buflen;
+ uint8_t *rsp_msgbuf;
+
+ volatile int pending;
+};
+
+struct ice_dcf_hw {
+ struct iavf_hw avf;
+
+ rte_spinlock_t vc_cmd_send_lock;
+ rte_spinlock_t vc_cmd_queue_lock;
+ TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+ uint8_t *arq_buf;
+
+ struct virtchnl_version_info virtchnl_version;
+ struct virtchnl_vf_resource *vf_res; /* VF resource */
+ struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
+ uint16_t vsi_id;
+};
+
+int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+ struct dcf_virtchnl_cmd *cmd);
+
+int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+
+#endif /* _ICE_DCF_H_ */
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
new file mode 100644
index 000000000..23f82a487
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -0,0 +1,317 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <rte_interrupts.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_pci.h>
+#include <rte_kvargs.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include <iavf_devids.h>
+
+#include "ice_generic_flow.h"
+#include "ice_dcf_ethdev.h"
+
+static uint16_t
+ice_dcf_recv_pkts(__rte_unused void *rx_queue,
+ __rte_unused struct rte_mbuf **bufs,
+ __rte_unused uint16_t nb_pkts)
+{
+ return 0;
+}
+
+static uint16_t
+ice_dcf_xmit_pkts(__rte_unused void *tx_queue,
+ __rte_unused struct rte_mbuf **bufs,
+ __rte_unused uint16_t nb_pkts)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_start(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = ETH_LINK_UP;
+
+ return 0;
+}
+
+static void
+ice_dcf_dev_stop(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+ice_dcf_dev_configure(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_info_get(struct rte_eth_dev *dev,
+ struct rte_eth_dev_info *dev_info)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev_info->max_mac_addrs = 1;
+ dev_info->max_rx_pktlen = (uint32_t)-1;
+ dev_info->max_rx_queues = RTE_DIM(adapter->rxqs);
+ dev_info->max_tx_queues = RTE_DIM(adapter->txqs);
+
+ return 0;
+}
+
+static int
+ice_dcf_stats_get(__rte_unused struct rte_eth_dev *dev,
+ __rte_unused struct rte_eth_stats *igb_stats)
+{
+ return 0;
+}
+
+static int
+ice_dcf_stats_reset(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_disable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_enable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_disable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
+ enum rte_filter_type filter_type,
+ __rte_unused enum rte_filter_op filter_op,
+ __rte_unused void *arg)
+{
+ int ret = 0;
+
+ if (!dev)
+ return -EINVAL;
+
+ switch (filter_type) {
+ default:
+ PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+ filter_type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void
+ice_dcf_dev_close(struct rte_eth_dev *dev)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return;
+
+ dev->dev_ops = NULL;
+ dev->rx_pkt_burst = NULL;
+ dev->tx_pkt_burst = NULL;
+ dev->data->mac_addrs = NULL;
+
+ ice_dcf_uninit_hw(dev, &adapter->real_hw);
+}
+
+static void
+ice_dcf_queue_release(__rte_unused void *q)
+{
+}
+
+static int
+ice_dcf_link_update(__rte_unused struct rte_eth_dev *dev,
+ __rte_unused int wait_to_complete)
+{
+ return 0;
+}
+
+static int
+ice_dcf_rx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t rx_queue_id,
+ __rte_unused uint16_t nb_rx_desc,
+ __rte_unused unsigned int socket_id,
+ __rte_unused const struct rte_eth_rxconf *rx_conf,
+ __rte_unused struct rte_mempool *mb_pool)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev->data->rx_queues[rx_queue_id] = &adapter->rxqs[rx_queue_id];
+
+ return 0;
+}
+
+static int
+ice_dcf_tx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t tx_queue_id,
+ __rte_unused uint16_t nb_tx_desc,
+ __rte_unused unsigned int socket_id,
+ __rte_unused const struct rte_eth_txconf *tx_conf)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev->data->tx_queues[tx_queue_id] = &adapter->txqs[tx_queue_id];
+
+ return 0;
+}
+
+static const struct eth_dev_ops ice_dcf_eth_dev_ops = {
+ .dev_start = ice_dcf_dev_start,
+ .dev_stop = ice_dcf_dev_stop,
+ .dev_close = ice_dcf_dev_close,
+ .dev_configure = ice_dcf_dev_configure,
+ .dev_infos_get = ice_dcf_dev_info_get,
+ .rx_queue_setup = ice_dcf_rx_queue_setup,
+ .tx_queue_setup = ice_dcf_tx_queue_setup,
+ .rx_queue_release = ice_dcf_queue_release,
+ .tx_queue_release = ice_dcf_queue_release,
+ .link_update = ice_dcf_link_update,
+ .stats_get = ice_dcf_stats_get,
+ .stats_reset = ice_dcf_stats_reset,
+ .promiscuous_enable = ice_dcf_dev_promiscuous_enable,
+ .promiscuous_disable = ice_dcf_dev_promiscuous_disable,
+ .allmulticast_enable = ice_dcf_dev_allmulticast_enable,
+ .allmulticast_disable = ice_dcf_dev_allmulticast_disable,
+ .filter_ctrl = ice_dcf_dev_filter_ctrl,
+};
+
+static int
+ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+
+ eth_dev->dev_ops = &ice_dcf_eth_dev_ops;
+ eth_dev->rx_pkt_burst = ice_dcf_recv_pkts;
+ eth_dev->tx_pkt_burst = ice_dcf_xmit_pkts;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return 0;
+
+ eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
+ if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
+ PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
+ return -1;
+ }
+
+ rte_eth_random_addr(adapter->mac_addr.addr_bytes);
+ eth_dev->data->mac_addrs = &adapter->mac_addr;
+
+ return 0;
+}
+
+static int
+ice_dcf_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+ ice_dcf_dev_close(eth_dev);
+
+ return 0;
+}
+
+static int
+ice_dcf_cap_check_handler(__rte_unused const char *key,
+ const char *value, __rte_unused void *opaque)
+{
+ if (strcmp(value, "dcf"))
+ return -1;
+
+ return 0;
+}
+
+static int
+ice_dcf_cap_selected(struct rte_devargs *devargs)
+{
+ struct rte_kvargs *kvlist;
+ const char *key = "cap";
+ int ret = 0;
+
+ if (devargs == NULL)
+ return 0;
+
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
+ if (kvlist == NULL)
+ return 0;
+
+ if (!rte_kvargs_count(kvlist, key))
+ goto exit;
+
+ /* dcf capability selected when there's a key-value pair: cap=dcf */
+ if (rte_kvargs_process(kvlist, key,
+ ice_dcf_cap_check_handler, NULL) < 0)
+ goto exit;
+
+ ret = 1;
+
+exit:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
+static int eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
+ struct rte_pci_device *pci_dev)
+{
+ if (!ice_dcf_cap_selected(pci_dev->device.devargs))
+ return 1;
+
+ return rte_eth_dev_pci_generic_probe(pci_dev,
+ sizeof(struct ice_dcf_adapter),
+ ice_dcf_dev_init);
+}
+
+static int eth_ice_dcf_pci_remove(struct rte_pci_device *pci_dev)
+{
+ return rte_eth_dev_pci_generic_remove(pci_dev, ice_dcf_dev_uninit);
+}
+
+static const struct rte_pci_id pci_id_ice_dcf_map[] = {
+ { RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
+ { .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver rte_ice_dcf_pmd = {
+ .id_table = pci_id_ice_dcf_map,
+ .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+ .probe = eth_ice_dcf_pci_probe,
+ .remove = eth_ice_dcf_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_ice_dcf, rte_ice_dcf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_ice_dcf, pci_id_ice_dcf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ice_dcf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_ice_dcf, "cap=dcf");
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
new file mode 100644
index 000000000..0c34a0095
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_ETHDEV_H_
+#define _ICE_DCF_ETHDEV_H_
+
+#include "ice_ethdev.h"
+#include "ice_dcf.h"
+
+#define ICE_DCF_MAX_RINGS 1
+
+struct ice_dcf_queue {
+ uint64_t dummy;
+};
+
+struct ice_dcf_adapter {
+ struct ice_dcf_hw real_hw;
+ struct rte_ether_addr mac_addr;
+ struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
+ struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
+};
+
+#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index f9e897bbc..0ba9668d1 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -15,8 +15,8 @@ sources = files(
'ice_hash.c'
)
-deps += ['hash']
-includes += include_directories('base')
+deps += ['hash', 'net', 'common_iavf']
+includes += include_directories('base', '../../common/iavf')
if arch_subdir == 'x86'
sources += files('ice_rxtx_vec_sse.c')
@@ -37,4 +37,7 @@ if arch_subdir == 'x86'
endif
endif
+sources += files('ice_dcf.c',
+ 'ice_dcf_ethdev.c')
+
install_headers('rte_pmd_ice.h')
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index d295ca0a5..f3798a09f 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -185,6 +185,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += -lrte_pmd_i40e
_LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD) += -lrte_pmd_iavf
_LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += -lrte_pmd_ice
IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
ifeq ($(findstring y,$(IAVF-y)),y)
_LDLIBS-y += -lrte_common_iavf
endif
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v2 3/7] net/ice: initiate to acquire the DCF capability
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 0/7] " Haiyue Wang
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
@ 2020-03-10 6:50 ` Haiyue Wang
2020-03-13 5:51 ` Ye Xiaolong
2020-03-13 6:04 ` Ye Xiaolong
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
` (4 subsequent siblings)
7 siblings, 2 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-10 6:50 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
Since the DCF (Device Config Function) controls the flow setting of
other VFs by the mailbox with PF, for security, it needs to acquire
the DCF capability from PF when starts, and exits to disable it.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/ice/ice_dcf.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index efb258a5a..7a3626939 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -227,7 +227,7 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
int err, i;
caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
- VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED | VIRTCHNL_VF_CAP_DCF |
VF_BASE_MODE_OFFLOADS;
err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
@@ -264,6 +264,31 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
return 0;
}
+static int
+ice_dcf_mode_disable(struct ice_dcf_hw *hw)
+{
+ int err;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
+ NULL, 0);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_DISABLE");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
+ (uint8_t *)hw->arq_buf,
+ ICE_DCF_AQ_BUF_SZ, NULL);
+ if (err) {
+ PMD_DRV_LOG(ERR,
+ "Fail to get response of OP_DCF_DISABLE %d",
+ err);
+ return -1;
+ }
+
+ return 0;
+}
+
static int
ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
{
@@ -467,6 +492,7 @@ ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
rte_intr_callback_unregister(intr_handle,
ice_dcf_dev_interrupt_handler, hw);
+ ice_dcf_mode_disable(hw);
iavf_shutdown_adminq(&hw->avf);
rte_free(hw->arq_buf);
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v2 4/7] net/ice: handle the AdminQ command by DCF
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 0/7] " Haiyue Wang
` (2 preceding siblings ...)
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 3/7] net/ice: initiate to acquire the DCF capability Haiyue Wang
@ 2020-03-10 6:50 ` Haiyue Wang
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 5/7] net/ice: export the DDP definition symbols Haiyue Wang
` (3 subsequent siblings)
7 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-10 6:50 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) splits the AdminQ command into two
parts: one is the descriptor of AdminQ command, the other is the buffer
of AdminQ command (the descriptor has BUF flag set). When both of them
are received by the PF, the PF will handle them as one command.
And also, the filled descriptor and buffer of the response will be sent
back to DCF one by one through the virtchnl from PF.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/ice/ice_dcf.c | 65 +++++++++++++++++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 4 ++-
2 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index 7a3626939..24ed31f35 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -397,6 +397,71 @@ ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
return err;
}
+int
+ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
+ void *buf, uint16_t buf_size)
+{
+ struct dcf_virtchnl_cmd desc_cmd, buff_cmd;
+ struct ice_dcf_hw *hw = dcf_hw;
+ int err = 0;
+ int i = 0;
+
+ if ((buf && !buf_size) || (!buf && buf_size) ||
+ buf_size > ICE_DCF_AQ_BUF_SZ)
+ return -EINVAL;
+
+ desc_cmd.v_op = VIRTCHNL_OP_DCF_CMD_DESC;
+ desc_cmd.req_msglen = sizeof(*desc);
+ desc_cmd.req_msg = (uint8_t *)desc;
+ desc_cmd.rsp_buflen = sizeof(*desc);
+ desc_cmd.rsp_msgbuf = (uint8_t *)desc;
+
+ if (buf == NULL)
+ return ice_dcf_execute_virtchnl_cmd(hw, &desc_cmd);
+
+ desc->flags |= rte_cpu_to_le_16(ICE_AQ_FLAG_BUF);
+
+ buff_cmd.v_op = VIRTCHNL_OP_DCF_CMD_BUFF;
+ buff_cmd.req_msglen = buf_size;
+ buff_cmd.req_msg = buf;
+ buff_cmd.rsp_buflen = buf_size;
+ buff_cmd.rsp_msgbuf = buf;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_vc_cmd_set(hw, &desc_cmd);
+ ice_dcf_vc_cmd_set(hw, &buff_cmd);
+
+ if (ice_dcf_vc_cmd_send(hw, &desc_cmd) ||
+ ice_dcf_vc_cmd_send(hw, &buff_cmd)) {
+ err = -1;
+ PMD_DRV_LOG(ERR, "fail to send OP_DCF_CMD_DESC/BUFF");
+ goto ret;
+ }
+
+ do {
+ if ((!desc_cmd.pending && !buff_cmd.pending) ||
+ (!desc_cmd.pending && desc_cmd.v_ret != IAVF_SUCCESS) ||
+ (!buff_cmd.pending && buff_cmd.v_ret != IAVF_SUCCESS))
+ break;
+
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ if (desc_cmd.v_ret != IAVF_SUCCESS || buff_cmd.v_ret != IAVF_SUCCESS) {
+ err = -1;
+ PMD_DRV_LOG(ERR,
+ "No response (%d times) or return failure (desc: %d / buff: %d)",
+ i, desc_cmd.v_ret, buff_cmd.v_ret);
+ }
+
+ret:
+ ice_dcf_aq_cmd_clear(hw, &desc_cmd);
+ ice_dcf_aq_cmd_clear(hw, &buff_cmd);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+
+ return err;
+}
+
int
ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
{
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index f44c09db2..99bd53b02 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -11,6 +11,7 @@
#include <iavf_adminq_cmd.h>
#include <iavf_type.h>
+#include "base/ice_type.h"
#include "ice_logs.h"
struct dcf_virtchnl_cmd {
@@ -45,7 +46,8 @@ struct ice_dcf_hw {
int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
struct dcf_virtchnl_cmd *cmd);
-
+int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
+ void *buf, uint16_t buf_size);
int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v2 5/7] net/ice: export the DDP definition symbols
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 0/7] " Haiyue Wang
` (3 preceding siblings ...)
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
@ 2020-03-10 6:50 ` Haiyue Wang
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
` (2 subsequent siblings)
7 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-10 6:50 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A new DCF PMD will be introduced, which runs on Intel VF hardware, and
it is a pure software design to control the advance functionality (such
as switch, ACL) for rest of the VFs.
The DCF (Device Config Function) feature shares the core functions of
the ICE PMD, like it needs to export the DDP definition symbols for the
new DCF PMD use.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Xiaolong Ye <xiaolong.ye@intel.com>
---
drivers/net/ice/ice_ethdev.c | 9 +--------
drivers/net/ice/ice_ethdev.h | 8 ++++++++
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c
index b42deb0bc..8b9d211b0 100644
--- a/drivers/net/ice/ice_ethdev.c
+++ b/drivers/net/ice/ice_ethdev.c
@@ -67,15 +67,8 @@ static struct proto_xtr_ol_flag ice_proto_xtr_ol_flag_params[] = {
#define ICE_DFLT_OUTER_TAG_TYPE ICE_AQ_VSI_OUTER_TAG_VLAN_9100
-/* DDP package search path */
-#define ICE_PKG_FILE_DEFAULT "/lib/firmware/intel/ice/ddp/ice.pkg"
-#define ICE_PKG_FILE_UPDATES "/lib/firmware/updates/intel/ice/ddp/ice.pkg"
-#define ICE_PKG_FILE_SEARCH_PATH_DEFAULT "/lib/firmware/intel/ice/ddp/"
-#define ICE_PKG_FILE_SEARCH_PATH_UPDATES "/lib/firmware/updates/intel/ice/ddp/"
-
#define ICE_OS_DEFAULT_PKG_NAME "ICE OS Default Package"
#define ICE_COMMS_PKG_NAME "ICE COMMS Package"
-#define ICE_MAX_PKG_FILENAME_SIZE 256
#define ICE_MAX_RES_DESC_NUM 1024
int ice_logtype_init;
@@ -1833,7 +1826,7 @@ ice_pkg_file_search_path(struct rte_pci_device *pci_dev, char *pkg_file)
return 0;
}
-static enum ice_pkg_type
+enum ice_pkg_type
ice_load_pkg_type(struct ice_hw *hw)
{
enum ice_pkg_type package_type;
diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h
index da557a254..7b94a3c3e 100644
--- a/drivers/net/ice/ice_ethdev.h
+++ b/drivers/net/ice/ice_ethdev.h
@@ -42,6 +42,13 @@
#define ICE_MAX_PKT_TYPE 1024
+/* DDP package search path */
+#define ICE_PKG_FILE_DEFAULT "/lib/firmware/intel/ice/ddp/ice.pkg"
+#define ICE_PKG_FILE_UPDATES "/lib/firmware/updates/intel/ice/ddp/ice.pkg"
+#define ICE_PKG_FILE_SEARCH_PATH_DEFAULT "/lib/firmware/intel/ice/ddp/"
+#define ICE_PKG_FILE_SEARCH_PATH_UPDATES "/lib/firmware/updates/intel/ice/ddp/"
+#define ICE_MAX_PKG_FILENAME_SIZE 256
+
/**
* vlan_id is a 12 bit number.
* The VFTA array is actually a 4096 bit array, 128 of 32bit elements.
@@ -457,6 +464,7 @@ struct ice_vsi_vlan_pvid_info {
#define ICE_PF_TO_ETH_DEV(pf) \
(((struct ice_pf *)pf)->adapter->eth_dev)
+enum ice_pkg_type ice_load_pkg_type(struct ice_hw *hw);
struct ice_vsi *
ice_setup_vsi(struct ice_pf *pf, enum ice_vsi_type type);
int
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v2 6/7] net/ice: handle the PF initialization by DCF
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 0/7] " Haiyue Wang
` (4 preceding siblings ...)
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 5/7] net/ice: export the DDP definition symbols Haiyue Wang
@ 2020-03-10 6:50 ` Haiyue Wang
2020-03-13 7:59 ` Ye Xiaolong
2020-03-13 14:06 ` Ye Xiaolong
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
2020-03-13 16:19 ` [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support Stillwell Jr, Paul M
7 siblings, 2 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-10 6:50 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) works at the user PF level, it can't
access the real PF hardware directly. So it will proxy the PF's AdminQ
command through DCF's mailbox.
And the DCF is mainly used to control the flow setting of other VFs, so
it only needs to initialize some core functions about the flow .
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/ice/Makefile | 1 +
drivers/net/ice/ice_dcf.c | 7 +-
drivers/net/ice/ice_dcf.h | 3 +
drivers/net/ice/ice_dcf_ethdev.c | 10 +-
drivers/net/ice/ice_dcf_ethdev.h | 11 +-
drivers/net/ice/ice_dcf_parent.c | 263 +++++++++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
7 files changed, 292 insertions(+), 6 deletions(-)
create mode 100644 drivers/net/ice/ice_dcf_parent.c
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index f493c9ed7..3ecc72219 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -88,6 +88,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_parent.c
# install this header file
SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index 24ed31f35..480c449f5 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -124,8 +124,13 @@ ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
}
v_op = rte_le_to_cpu_32(info->desc.cookie_high);
- if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+ if (unlikely(v_op == VIRTCHNL_OP_EVENT)) {
+ if (hw->vc_event_msg_cb != NULL)
+ hw->vc_event_msg_cb(hw,
+ info->msg_buf,
+ info->msg_len);
return;
+ }
v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index 99bd53b02..ecd6303a0 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -36,6 +36,9 @@ struct ice_dcf_hw {
rte_spinlock_t vc_cmd_send_lock;
rte_spinlock_t vc_cmd_queue_lock;
TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+ void (*vc_event_msg_cb)(struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen);
+
uint8_t *arq_buf;
struct virtchnl_version_info virtchnl_version;
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
index 23f82a487..af94caeff 100644
--- a/drivers/net/ice/ice_dcf_ethdev.c
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -145,8 +145,8 @@ ice_dcf_dev_close(struct rte_eth_dev *dev)
dev->dev_ops = NULL;
dev->rx_pkt_burst = NULL;
dev->tx_pkt_burst = NULL;
- dev->data->mac_addrs = NULL;
+ ice_dcf_uninit_parent_adapter(dev);
ice_dcf_uninit_hw(dev, &adapter->real_hw);
}
@@ -225,13 +225,17 @@ ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+ adapter->real_hw.vc_event_msg_cb = ice_dcf_handle_pf_event_msg;
if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
return -1;
}
- rte_eth_random_addr(adapter->mac_addr.addr_bytes);
- eth_dev->data->mac_addrs = &adapter->mac_addr;
+ if (ice_dcf_init_parent_adapter(eth_dev) != 0) {
+ PMD_INIT_LOG(ERR, "Failed to init DCF parent adapter");
+ ice_dcf_uninit_hw(eth_dev, &adapter->real_hw);
+ return -1;
+ }
return 0;
}
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
index 0c34a0095..e60e808d8 100644
--- a/drivers/net/ice/ice_dcf_ethdev.h
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -5,6 +5,9 @@
#ifndef _ICE_DCF_ETHDEV_H_
#define _ICE_DCF_ETHDEV_H_
+#include "base/ice_common.h"
+#include "base/ice_adminq_cmd.h"
+
#include "ice_ethdev.h"
#include "ice_dcf.h"
@@ -15,10 +18,16 @@ struct ice_dcf_queue {
};
struct ice_dcf_adapter {
+ struct ice_adapter parent; /* Must be first */
+
struct ice_dcf_hw real_hw;
- struct rte_ether_addr mac_addr;
struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
};
+void ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen);
+int ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev);
+void ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev);
+
#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
new file mode 100644
index 000000000..4c3bb68b1
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_parent.c
@@ -0,0 +1,263 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "ice_dcf_ethdev.h"
+
+void
+ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen)
+{
+ struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
+
+ if (msglen < sizeof(struct virtchnl_pf_event)) {
+ PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen);
+ return;
+ }
+
+ switch (pf_msg->event) {
+ case VIRTCHNL_EVENT_RESET_IMPENDING:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
+ break;
+ case VIRTCHNL_EVENT_LINK_CHANGE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
+ break;
+ case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
+ break;
+ }
+}
+
+static int
+ice_dcf_init_parent_hw(struct ice_hw *hw)
+{
+ struct ice_aqc_get_phy_caps_data *pcaps;
+ enum ice_status status;
+
+ status = ice_aq_get_fw_ver(hw, NULL);
+ if (status)
+ return status;
+
+ status = ice_get_caps(hw);
+ if (status)
+ return status;
+
+ hw->port_info = (struct ice_port_info *)
+ ice_malloc(hw, sizeof(*hw->port_info));
+ if (!hw->port_info)
+ return ICE_ERR_NO_MEMORY;
+
+ /* set the back pointer to HW */
+ hw->port_info->hw = hw;
+
+ /* Initialize port_info struct with switch configuration data */
+ status = ice_get_initial_sw_cfg(hw);
+ if (status)
+ goto err_unroll_alloc;
+
+ pcaps = (struct ice_aqc_get_phy_caps_data *)
+ ice_malloc(hw, sizeof(*pcaps));
+ if (!pcaps) {
+ status = ICE_ERR_NO_MEMORY;
+ goto err_unroll_alloc;
+ }
+
+ /* Initialize port_info struct with PHY capabilities */
+ status = ice_aq_get_phy_caps(hw->port_info, false,
+ ICE_AQC_REPORT_TOPO_CAP, pcaps, NULL);
+ ice_free(hw, pcaps);
+ if (status)
+ goto err_unroll_alloc;
+
+ /* Initialize port_info struct with link information */
+ status = ice_aq_get_link_info(hw->port_info, false, NULL, NULL);
+ if (status)
+ goto err_unroll_alloc;
+
+ status = ice_init_fltr_mgmt_struct(hw);
+ if (status)
+ goto err_unroll_alloc;
+
+ status = ice_init_hw_tbls(hw);
+ if (status)
+ goto err_unroll_fltr_mgmt_struct;
+
+ PMD_INIT_LOG(INFO,
+ "firmware %d.%d.%d api %d.%d.%d build 0x%08x",
+ hw->fw_maj_ver, hw->fw_min_ver, hw->fw_patch,
+ hw->api_maj_ver, hw->api_min_ver, hw->api_patch,
+ hw->fw_build);
+
+ return ICE_SUCCESS;
+
+err_unroll_fltr_mgmt_struct:
+ ice_cleanup_fltr_mgmt_struct(hw);
+err_unroll_alloc:
+ ice_free(hw, hw->port_info);
+ hw->port_info = NULL;
+
+ return status;
+}
+
+static void ice_dcf_uninit_parent_hw(struct ice_hw *hw)
+{
+ ice_cleanup_fltr_mgmt_struct(hw);
+
+ ice_free_seg(hw);
+ ice_free_hw_tbls(hw);
+
+ ice_free(hw, hw->port_info);
+ hw->port_info = NULL;
+
+ ice_clear_all_vsi_ctx(hw);
+}
+
+static int
+ice_dcf_request_pkg_name(struct ice_hw *hw, char *pkg_name)
+{
+ struct ice_dcf_adapter *dcf_adapter =
+ container_of(hw, struct ice_dcf_adapter, parent.hw);
+
+ /* TODO: check with DSN firstly by iAVF */
+ PMD_INIT_LOG(DEBUG,
+ "DCF VSI_ID = %u",
+ dcf_adapter->real_hw.vsi_id);
+
+ snprintf(pkg_name,
+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_UPDATES);
+ if (!access(pkg_name, 0))
+ return 0;
+
+ snprintf(pkg_name,
+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_DEFAULT);
+ if (!access(pkg_name, 0))
+ return 0;
+
+ return -1;
+}
+
+static int
+ice_dcf_load_pkg(struct ice_hw *hw)
+{
+ char pkg_name[ICE_MAX_PKG_FILENAME_SIZE];
+ uint8_t *pkg_buf;
+ uint32_t buf_len;
+ struct stat st;
+ FILE *fp;
+ int err;
+
+ if (ice_dcf_request_pkg_name(hw, pkg_name)) {
+ PMD_INIT_LOG(ERR, "failed to locate the package file");
+ return -ENOENT;
+ }
+
+ PMD_INIT_LOG(DEBUG, "DDP package name: %s", pkg_name);
+
+ err = stat(pkg_name, &st);
+ if (err) {
+ PMD_INIT_LOG(ERR, "failed to get file status");
+ return err;
+ }
+
+ buf_len = st.st_size;
+ pkg_buf = rte_malloc(NULL, buf_len, 0);
+ if (!pkg_buf) {
+ PMD_INIT_LOG(ERR, "failed to allocate buffer of size %u for package",
+ buf_len);
+ return -1;
+ }
+
+ fp = fopen(pkg_name, "rb");
+ if (!fp) {
+ PMD_INIT_LOG(ERR, "failed to open file: %s", pkg_name);
+ err = -1;
+ goto ret;
+ }
+
+ err = fread(pkg_buf, buf_len, 1, fp);
+ fclose(fp);
+ if (err != 1) {
+ PMD_INIT_LOG(ERR, "failed to read package data");
+ err = -1;
+ goto ret;
+ }
+
+ err = ice_copy_and_init_pkg(hw, pkg_buf, buf_len);
+ if (err)
+ PMD_INIT_LOG(ERR, "ice_copy_and_init_hw failed: %d", err);
+
+ret:
+ rte_free(pkg_buf);
+ return err;
+}
+
+int
+ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+ struct ice_adapter *parent_adapter = &adapter->parent;
+ struct ice_hw *parent_hw = &parent_adapter->hw;
+ struct ice_dcf_hw *hw = &adapter->real_hw;
+ const struct rte_ether_addr *mac;
+ int err;
+
+ parent_adapter->eth_dev = eth_dev;
+ parent_adapter->pf.adapter = parent_adapter;
+ parent_adapter->pf.dev_data = eth_dev->data;
+ parent_hw->back = parent_adapter;
+ parent_hw->mac_type = ICE_MAC_GENERIC;
+ parent_hw->vendor_id = ICE_INTEL_VENDOR_ID;
+
+ ice_init_lock(&parent_hw->adminq.sq_lock);
+ ice_init_lock(&parent_hw->adminq.rq_lock);
+ parent_hw->aq_send_cmd_fn = ice_dcf_send_aq_cmd;
+ parent_hw->aq_send_cmd_param = &adapter->real_hw;
+ parent_hw->dcf_enabled = true;
+
+ err = ice_dcf_init_parent_hw(parent_hw);
+ if (err) {
+ PMD_INIT_LOG(ERR, "failed to init the DCF parent hardware with error %d",
+ err);
+ return err;
+ }
+
+ err = ice_dcf_load_pkg(parent_hw);
+ if (err) {
+ PMD_INIT_LOG(ERR, "failed to load package with error %d",
+ err);
+ goto uninit_hw;
+ }
+ parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
+
+ mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
+ if (rte_is_valid_assigned_ether_addr(mac))
+ rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
+ else
+ rte_eth_random_addr(parent_adapter->pf.dev_addr.addr_bytes);
+
+ eth_dev->data->mac_addrs = &parent_adapter->pf.dev_addr;
+
+ return 0;
+
+uninit_hw:
+ ice_dcf_uninit_parent_hw(parent_hw);
+ return err;
+}
+
+void
+ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+ struct ice_adapter *parent_adapter = &adapter->parent;
+ struct ice_hw *parent_hw = &parent_adapter->hw;
+
+ eth_dev->data->mac_addrs = NULL;
+
+ ice_dcf_uninit_parent_hw(parent_hw);
+}
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index 0ba9668d1..7e9037f3b 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -38,6 +38,7 @@ if arch_subdir == 'x86'
endif
sources += files('ice_dcf.c',
- 'ice_dcf_ethdev.c')
+ 'ice_dcf_ethdev.c',
+ 'ice_dcf_parent.c')
install_headers('rte_pmd_ice.h')
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v2 7/7] net/ice: get the VF hardware index in DCF
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 0/7] " Haiyue Wang
` (5 preceding siblings ...)
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
@ 2020-03-10 6:50 ` Haiyue Wang
2020-03-13 7:01 ` Ye Xiaolong
2020-03-13 16:19 ` [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support Stillwell Jr, Paul M
7 siblings, 1 reply; 94+ messages in thread
From: Haiyue Wang @ 2020-03-10 6:50 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) needs the hardware index of the VFs to
control the flow setting. And also if the VF resets, the index may be
changed, so it should handle this in VF reset event.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/ice/ice_dcf.c | 81 +++++++++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 4 ++
drivers/net/ice/ice_dcf_parent.c | 83 +++++++++++++++++++++++++++++++-
3 files changed, 167 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index 480c449f5..1d3c8fa95 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -269,6 +269,63 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
return 0;
}
+static int
+ice_dcf_get_vf_vsi_map(struct ice_dcf_hw *hw)
+{
+ struct virtchnl_dcf_vsi_map *vsi_map;
+ uint16_t len;
+ int err;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
+ NULL, 0);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_GET_VSI_MAP");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
+ hw->arq_buf, ICE_DCF_AQ_BUF_SZ,
+ &len);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Fail to get response of OP_DCF_GET_VSI_MAP");
+ return err;
+ }
+
+ vsi_map = (struct virtchnl_dcf_vsi_map *)hw->arq_buf;
+ if (len < sizeof(*vsi_map) || !vsi_map->num_vfs ||
+ len < sizeof(*vsi_map) +
+ (vsi_map->num_vfs - 1) * sizeof(vsi_map->vf_vsi[0])) {
+ PMD_DRV_LOG(ERR, "invalid vf vsi map response with length %u",
+ len);
+ return -EINVAL;
+ }
+
+ if (hw->num_vfs != 0 && hw->num_vfs != vsi_map->num_vfs) {
+ PMD_DRV_LOG(ERR, "The number VSI map (%u) doesn't match the number of VFs (%u)",
+ vsi_map->num_vfs, hw->num_vfs);
+ return -EINVAL;
+ }
+
+ len = vsi_map->num_vfs * sizeof(vsi_map->vf_vsi[0]);
+ if (!hw->vf_vsi_map) {
+ hw->num_vfs = vsi_map->num_vfs;
+ hw->vf_vsi_map = rte_zmalloc("vf_vsi_ctx", len, 0);
+ }
+
+ if (!hw->vf_vsi_map) {
+ PMD_DRV_LOG(ERR, "Fail to alloc memory for VSI context");
+ return -ENOMEM;
+ }
+
+ if (!memcmp(hw->vf_vsi_map, vsi_map->vf_vsi, len)) {
+ PMD_DRV_LOG(DEBUG, "VF VSI map doesn't change");
+ return 1;
+ }
+
+ rte_memcpy(hw->vf_vsi_map, vsi_map->vf_vsi, len);
+ return 0;
+}
+
static int
ice_dcf_mode_disable(struct ice_dcf_hw *hw)
{
@@ -467,6 +524,23 @@ ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
return err;
}
+int
+ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw)
+{
+ int err = 0;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_disable_irq0(hw);
+
+ if (ice_dcf_get_vf_resource(hw) || ice_dcf_get_vf_vsi_map(hw))
+ err = -1;
+
+ ice_dcf_enable_irq0(hw);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+
+ return err;
+}
+
int
ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
{
@@ -534,6 +608,12 @@ ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
goto err_alloc;
}
+ if (ice_dcf_get_vf_vsi_map(hw) < 0) {
+ PMD_INIT_LOG(ERR, "Failed to get VF VSI map");
+ ice_dcf_mode_disable(hw);
+ goto err_alloc;
+ }
+
rte_intr_callback_register(&pci_dev->intr_handle,
ice_dcf_dev_interrupt_handler, hw);
rte_intr_enable(&pci_dev->intr_handle);
@@ -566,5 +646,6 @@ ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
iavf_shutdown_adminq(&hw->avf);
rte_free(hw->arq_buf);
+ rte_free(hw->vf_vsi_map);
rte_free(hw->vf_res);
}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index ecd6303a0..12bef4a2a 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -41,6 +41,9 @@ struct ice_dcf_hw {
uint8_t *arq_buf;
+ uint16_t num_vfs;
+ uint16_t *vf_vsi_map;
+
struct virtchnl_version_info virtchnl_version;
struct virtchnl_vf_resource *vf_res; /* VF resource */
struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
@@ -51,6 +54,7 @@ int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
struct dcf_virtchnl_cmd *cmd);
int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
void *buf, uint16_t buf_size);
+int ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw);
int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
index 4c3bb68b1..2735221e9 100644
--- a/drivers/net/ice/ice_dcf_parent.c
+++ b/drivers/net/ice/ice_dcf_parent.c
@@ -5,10 +5,76 @@
#include <sys/stat.h>
#include <unistd.h>
+#include <rte_alarm.h>
+
#include "ice_dcf_ethdev.h"
+#define ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL 100000 /* us */
+
+static __rte_always_inline void
+ice_dcf_update_vsi_ctx(struct ice_hw *hw, uint16_t vsi_handle,
+ uint16_t vsi_map)
+{
+ struct ice_vsi_ctx *vsi_ctx;
+
+ if (unlikely(vsi_handle >= ICE_MAX_VSI)) {
+ PMD_DRV_LOG(ERR, "Invalid vsi handle %u", vsi_handle);
+ return;
+ }
+
+ vsi_ctx = hw->vsi_ctx[vsi_handle];
+
+ if (vsi_map & VIRTCHNL_DCF_VF_VSI_VALID) {
+ if (!vsi_ctx)
+ vsi_ctx = ice_malloc(hw, sizeof(*vsi_ctx));
+
+ if (!vsi_ctx) {
+ PMD_DRV_LOG(ERR, "No memory for vsi context %u",
+ vsi_handle);
+ return;
+ }
+
+ vsi_ctx->vsi_num = (vsi_map & VIRTCHNL_DCF_VF_VSI_ID_M) >>
+ VIRTCHNL_DCF_VF_VSI_ID_S;
+ hw->vsi_ctx[vsi_handle] = vsi_ctx;
+
+ PMD_DRV_LOG(DEBUG, "VF%u is assigned with vsi number %u",
+ vsi_handle, vsi_ctx->vsi_num);
+ } else {
+ hw->vsi_ctx[vsi_handle] = NULL;
+
+ ice_free(hw, vsi_ctx);
+
+ PMD_DRV_LOG(NOTICE, "VF%u is disabled", vsi_handle);
+ }
+}
+
+static void
+ice_dcf_update_vf_vsi_map(struct ice_hw *hw, uint16_t num_vfs,
+ uint16_t *vf_vsi_map)
+{
+ uint16_t vf_id;
+
+ for (vf_id = 0; vf_id < num_vfs; vf_id++)
+ ice_dcf_update_vsi_ctx(hw, vf_id, vf_vsi_map[vf_id]);
+}
+
+static void
+ice_dcf_vsi_update_service_handler(void *param)
+{
+ struct ice_dcf_hw *hw = param;
+
+ if (!ice_dcf_handle_vsi_update_event(hw)) {
+ struct ice_dcf_adapter *dcf_ad =
+ container_of(hw, struct ice_dcf_adapter, real_hw);
+
+ ice_dcf_update_vf_vsi_map(&dcf_ad->parent.hw,
+ hw->num_vfs, hw->vf_vsi_map);
+ }
+}
+
void
-ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
+ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
uint8_t *msg, uint16_t msglen)
{
struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
@@ -21,6 +87,8 @@ ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
switch (pf_msg->event) {
case VIRTCHNL_EVENT_RESET_IMPENDING:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
+ rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL * 2,
+ ice_dcf_vsi_update_service_handler, dcf_hw);
break;
case VIRTCHNL_EVENT_LINK_CHANGE:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
@@ -28,6 +96,13 @@ ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
break;
+ case VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE event : VF%u with VSI num %u",
+ pf_msg->event_data.vf_vsi_map.vf_id,
+ pf_msg->event_data.vf_vsi_map.vsi_id);
+ rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL,
+ ice_dcf_vsi_update_service_handler, dcf_hw);
+ break;
default:
PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
break;
@@ -235,6 +310,9 @@ ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
}
parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
+ ice_dcf_update_vf_vsi_map(parent_hw,
+ hw->num_vfs, hw->vf_vsi_map);
+
mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
if (rte_is_valid_assigned_ether_addr(mac))
rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
@@ -259,5 +337,8 @@ ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
eth_dev->data->mac_addrs = NULL;
+ rte_eal_alarm_cancel(ice_dcf_vsi_update_service_handler,
+ &adapter->real_hw);
+
ice_dcf_uninit_parent_hw(parent_hw);
}
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support
2020-03-10 2:00 ` Wang, Haiyue
@ 2020-03-10 7:48 ` Thomas Monjalon
2020-03-10 9:36 ` Ferruh Yigit
0 siblings, 1 reply; 94+ messages in thread
From: Thomas Monjalon @ 2020-03-10 7:48 UTC (permalink / raw)
To: Kevin Traynor, David Marchand, Ye, Xiaolong, Wang, Haiyue
Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei,
Aaron Conole, ci, Yigit, Ferruh
10/03/2020 03:00, Wang, Haiyue:
> > -----Original Message-----
> > From: Kevin Traynor <ktraynor@redhat.com>
> > Sent: Tuesday, March 10, 2020 03:34
> > To: Thomas Monjalon <thomas@monjalon.net>; David Marchand <david.marchand@redhat.com>; Ye, Xiaolong
> > <xiaolong.ye@intel.com>
> > Cc: Wang, Haiyue <haiyue.wang@intel.com>; dev <dev@dpdk.org>; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang,
> > Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>;
> > Aaron Conole <aconole@redhat.com>; ci@dpdk.org; Yigit, Ferruh <ferruh.yigit@intel.com>
> > Subject: Re: [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support
> >
> > On 09/03/2020 17:57, Thomas Monjalon wrote:
> > > 09/03/2020 17:20, Ye Xiaolong:
> > >> Hi, David
> > >>
> > >> On 03/09, David Marchand wrote:
> > >>> On Mon, Mar 9, 2020 at 3:22 PM Haiyue Wang <haiyue.wang@intel.com> wrote:
> > >>>>
> > >>>> A DCF (Device Config Function) based approach is proposed where a device
> > >>>> bound to the device's VF0 can act as a sole controlling entity to exercise
> > >>>> advance functionality (such as switch, ACL) for rest of the VFs.
> > >>>>
> > >>>> The DCF works as a standalone PMD to support this function, which shares the
> > >>>> ice PMD flow control core function and the iavf virtchnl mailbox core module.
> > >>>>
> > >>>> This patchset is based on:
> > >>>> [1] https://patchwork.dpdk.org/cover/66417/ update ice base code
> > >>>
> > >>> The problem is that the CI(s) won't handle this.
> > >>> Example for the robot: https://travis-ci.com/ovsrobot/dpdk/builds/152461907
> > >>>
> > >>> Maybe we could add something as an annotation to the cover letter or
> > >>> the first patch of a series so that the CI(s) can detect and try to be
> > >>> intelligent?
> > >>
> > >> Agree, It'd be helpful if the cover letter of the first patch contains some
> > >> base tree info including the base commit and dependency patchset info (if any),
> > >> so the CI can determine the correct base on top of which the developer's
> > >> patchset applies to avoid any apply issue and potential false positive.
> > >>
> > >> And I know there is one option '--base'' of `git format-patch` which is
> > >> dedicated for this kind of usage, it can help create the base tree info block
> > >> which can be easily consumed by the CI. Here is the simple intro of it.
> > >>
> > >> Imagine that on top of the public commit P (already in upstream), the developer
> > >> applied well-known (on-flight, in the mailing list but not merged yet) patches
> > >> X, Y and Z from somebody else or himself, and then built his three-patch series
> > >> A, B, C, the commit history would be like:
> > >>
> > >> ................................................
> > >> ---P---X---Y---Z---A---B---C
> > >> ................................................
> > >>
> > >> With `git format-patch --base=P -3 C`,
> > >>
> > >> where P could be the exact commit sha, or variants e.g. HEAD~6, we can also use
> > >> --base=auto for convenience, the base tree information block will be shown at
> > >> the end of the first message the command outputs (either the first patch, or
> > >> the cover letter), like this:
> > >>
> > >> ------------
> > >> base-commit: P
> > >> prerequisite-patch-id: X
> > >> prerequisite-patch-id: Y
> > >> prerequisite-patch-id: Z
> > >> ------------
> > >>
> > >> Here P is the commit sha, and X,Y,Z are the patch ids of the dependency patches.
> > >>
> > >>
> > >> With this info in place, I think CI should be able to setup the exact base for
> > >> the coming patchset, the missing part I can see is the mapping of
> > >> (in-flight patch <-> patch id), since we have all the in-flight patches in
> > >> patchwork, creating and maintaining such mapping in DB is doable, what do you
> > >> think?
> > >
> > > I think it would simpler to list dependencies as patchwork ids.
> > > Example:
> > > Depends-on: series-42, patch-12345
> > >
> >
>
> Just list the 'series' ? Since it can download the whole patchset with
> the single link format like:
>
> Depends-on: series-8843 --> https://patchwork.dpdk.org/series/8843/mbox/
Yes, I was proposing both format: series-X and patch-Y (on top of series-X).
But we probably never need to be specific about a single patch.
I think you are right, we can keep only "series-X" syntax,
and allow describing a list of series, ordered and separated with comma.
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support
2020-03-10 7:48 ` Thomas Monjalon
@ 2020-03-10 9:36 ` Ferruh Yigit
2020-03-10 14:11 ` Aaron Conole
0 siblings, 1 reply; 94+ messages in thread
From: Ferruh Yigit @ 2020-03-10 9:36 UTC (permalink / raw)
To: Thomas Monjalon, Kevin Traynor, David Marchand, Ye, Xiaolong,
Wang, Haiyue
Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei,
Aaron Conole, ci
On 3/10/2020 7:48 AM, Thomas Monjalon wrote:
> 10/03/2020 03:00, Wang, Haiyue:
>>> -----Original Message-----
>>> From: Kevin Traynor <ktraynor@redhat.com>
>>> Sent: Tuesday, March 10, 2020 03:34
>>> To: Thomas Monjalon <thomas@monjalon.net>; David Marchand <david.marchand@redhat.com>; Ye, Xiaolong
>>> <xiaolong.ye@intel.com>
>>> Cc: Wang, Haiyue <haiyue.wang@intel.com>; dev <dev@dpdk.org>; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang,
>>> Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>;
>>> Aaron Conole <aconole@redhat.com>; ci@dpdk.org; Yigit, Ferruh <ferruh.yigit@intel.com>
>>> Subject: Re: [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support
>>>
>>> On 09/03/2020 17:57, Thomas Monjalon wrote:
>>>> 09/03/2020 17:20, Ye Xiaolong:
>>>>> Hi, David
>>>>>
>>>>> On 03/09, David Marchand wrote:
>>>>>> On Mon, Mar 9, 2020 at 3:22 PM Haiyue Wang <haiyue.wang@intel.com> wrote:
>>>>>>>
>>>>>>> A DCF (Device Config Function) based approach is proposed where a device
>>>>>>> bound to the device's VF0 can act as a sole controlling entity to exercise
>>>>>>> advance functionality (such as switch, ACL) for rest of the VFs.
>>>>>>>
>>>>>>> The DCF works as a standalone PMD to support this function, which shares the
>>>>>>> ice PMD flow control core function and the iavf virtchnl mailbox core module.
>>>>>>>
>>>>>>> This patchset is based on:
>>>>>>> [1] https://patchwork.dpdk.org/cover/66417/ update ice base code
>>>>>>
>>>>>> The problem is that the CI(s) won't handle this.
>>>>>> Example for the robot: https://travis-ci.com/ovsrobot/dpdk/builds/152461907
>>>>>>
>>>>>> Maybe we could add something as an annotation to the cover letter or
>>>>>> the first patch of a series so that the CI(s) can detect and try to be
>>>>>> intelligent?
>>>>>
>>>>> Agree, It'd be helpful if the cover letter of the first patch contains some
>>>>> base tree info including the base commit and dependency patchset info (if any),
>>>>> so the CI can determine the correct base on top of which the developer's
>>>>> patchset applies to avoid any apply issue and potential false positive.
>>>>>
>>>>> And I know there is one option '--base'' of `git format-patch` which is
>>>>> dedicated for this kind of usage, it can help create the base tree info block
>>>>> which can be easily consumed by the CI. Here is the simple intro of it.
>>>>>
>>>>> Imagine that on top of the public commit P (already in upstream), the developer
>>>>> applied well-known (on-flight, in the mailing list but not merged yet) patches
>>>>> X, Y and Z from somebody else or himself, and then built his three-patch series
>>>>> A, B, C, the commit history would be like:
>>>>>
>>>>> ................................................
>>>>> ---P---X---Y---Z---A---B---C
>>>>> ................................................
>>>>>
>>>>> With `git format-patch --base=P -3 C`,
>>>>>
>>>>> where P could be the exact commit sha, or variants e.g. HEAD~6, we can also use
>>>>> --base=auto for convenience, the base tree information block will be shown at
>>>>> the end of the first message the command outputs (either the first patch, or
>>>>> the cover letter), like this:
>>>>>
>>>>> ------------
>>>>> base-commit: P
>>>>> prerequisite-patch-id: X
>>>>> prerequisite-patch-id: Y
>>>>> prerequisite-patch-id: Z
>>>>> ------------
>>>>>
>>>>> Here P is the commit sha, and X,Y,Z are the patch ids of the dependency patches.
>>>>>
>>>>>
>>>>> With this info in place, I think CI should be able to setup the exact base for
>>>>> the coming patchset, the missing part I can see is the mapping of
>>>>> (in-flight patch <-> patch id), since we have all the in-flight patches in
>>>>> patchwork, creating and maintaining such mapping in DB is doable, what do you
>>>>> think?
>>>>
>>>> I think it would simpler to list dependencies as patchwork ids.
>>>> Example:
>>>> Depends-on: series-42, patch-12345
>>>>
>>>
>>
>> Just list the 'series' ? Since it can download the whole patchset with
>> the single link format like:
>>
>> Depends-on: series-8843 --> https://patchwork.dpdk.org/series/8843/mbox/
>
> Yes, I was proposing both format: series-X and patch-Y (on top of series-X).
> But we probably never need to be specific about a single patch.
> I think you are right, we can keep only "series-X" syntax,
> and allow describing a list of series, ordered and separated with comma.
>
+1 to "Depends-on: series-#####" syntax
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support
2020-03-09 15:36 ` [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support David Marchand
2020-03-09 16:20 ` Ye Xiaolong
@ 2020-03-10 14:09 ` Aaron Conole
1 sibling, 0 replies; 94+ messages in thread
From: Aaron Conole @ 2020-03-10 14:09 UTC (permalink / raw)
To: David Marchand
Cc: Haiyue Wang, dev, Xiaolong Ye, Qi Zhang, Qiming Yang,
Beilei Xing, Wei Zhao, ci
David Marchand <david.marchand@redhat.com> writes:
> On Mon, Mar 9, 2020 at 3:22 PM Haiyue Wang <haiyue.wang@intel.com> wrote:
>>
>> A DCF (Device Config Function) based approach is proposed where a device
>> bound to the device's VF0 can act as a sole controlling entity to exercise
>> advance functionality (such as switch, ACL) for rest of the VFs.
>>
>> The DCF works as a standalone PMD to support this function, which shares the
>> ice PMD flow control core function and the iavf virtchnl mailbox core module.
>>
>> This patchset is based on:
>> [1] https://patchwork.dpdk.org/cover/66417/ update ice base code
>
> The problem is that the CI(s) won't handle this.
> Example for the robot: https://travis-ci.com/ovsrobot/dpdk/builds/152461907
>
> Maybe we could add something as an annotation to the cover letter or
> the first patch of a series so that the CI(s) can detect and try to be
> intelligent?
It's something that's possibly worth doing; I can update the bot to
recognize:
series_XXX
in the cover-letter metadata (IE: between the '[...]'), and
automatically check out the correct branch.
Additionally, if the idea is not to get the patch applied right away
while finalizing on the preceding series, the RFC keyword will prevent
the bot from running.
THAT SAID
In general, I dislike posting series that depend on other series. It
makes review much harder, and if there's a feedback on the preceding
series that requires lots of change, the dependent series may also need
to be re-done completely.
I see there are more replies to this thread - sorry I didn't get to it
yesterday (personal stuff).
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support
2020-03-10 9:36 ` Ferruh Yigit
@ 2020-03-10 14:11 ` Aaron Conole
0 siblings, 0 replies; 94+ messages in thread
From: Aaron Conole @ 2020-03-10 14:11 UTC (permalink / raw)
To: Ferruh Yigit
Cc: Thomas Monjalon, Kevin Traynor, David Marchand, Ye, Xiaolong,
Wang, Haiyue, dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei,
Zhao1, Wei, ci
Ferruh Yigit <ferruh.yigit@intel.com> writes:
> On 3/10/2020 7:48 AM, Thomas Monjalon wrote:
>> 10/03/2020 03:00, Wang, Haiyue:
>>>> -----Original Message-----
>>>> From: Kevin Traynor <ktraynor@redhat.com>
>>>> Sent: Tuesday, March 10, 2020 03:34
>>>> To: Thomas Monjalon <thomas@monjalon.net>; David Marchand
>>>> <david.marchand@redhat.com>; Ye, Xiaolong
>>>> <xiaolong.ye@intel.com>
>>>> Cc: Wang, Haiyue <haiyue.wang@intel.com>; dev <dev@dpdk.org>;
>>>> Zhang, Qi Z <qi.z.zhang@intel.com>; Yang,
>>>> Qiming <qiming.yang@intel.com>; Xing, Beilei
>>>> <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>;
>>>> Aaron Conole <aconole@redhat.com>; ci@dpdk.org; Yigit, Ferruh <ferruh.yigit@intel.com>
>>>> Subject: Re: [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support
>>>>
>>>> On 09/03/2020 17:57, Thomas Monjalon wrote:
>>>>> 09/03/2020 17:20, Ye Xiaolong:
>>>>>> Hi, David
>>>>>>
>>>>>> On 03/09, David Marchand wrote:
>>>>>>> On Mon, Mar 9, 2020 at 3:22 PM Haiyue Wang <haiyue.wang@intel.com> wrote:
>>>>>>>>
>>>>>>>> A DCF (Device Config Function) based approach is proposed where a device
>>>>>>>> bound to the device's VF0 can act as a sole controlling entity to exercise
>>>>>>>> advance functionality (such as switch, ACL) for rest of the VFs.
>>>>>>>>
>>>>>>>> The DCF works as a standalone PMD to support this function, which shares the
>>>>>>>> ice PMD flow control core function and the iavf virtchnl mailbox core module.
>>>>>>>>
>>>>>>>> This patchset is based on:
>>>>>>>> [1] https://patchwork.dpdk.org/cover/66417/ update ice base code
>>>>>>>
>>>>>>> The problem is that the CI(s) won't handle this.
>>>>>>> Example for the robot: https://travis-ci.com/ovsrobot/dpdk/builds/152461907
>>>>>>>
>>>>>>> Maybe we could add something as an annotation to the cover letter or
>>>>>>> the first patch of a series so that the CI(s) can detect and try to be
>>>>>>> intelligent?
>>>>>>
>>>>>> Agree, It'd be helpful if the cover letter of the first patch contains some
>>>>>> base tree info including the base commit and dependency patchset info (if any),
>>>>>> so the CI can determine the correct base on top of which the developer's
>>>>>> patchset applies to avoid any apply issue and potential false positive.
>>>>>>
>>>>>> And I know there is one option '--base'' of `git format-patch` which is
>>>>>> dedicated for this kind of usage, it can help create the base tree info block
>>>>>> which can be easily consumed by the CI. Here is the simple intro of it.
>>>>>>
>>>>>> Imagine that on top of the public commit P (already in upstream), the developer
>>>>>> applied well-known (on-flight, in the mailing list but not merged yet) patches
>>>>>> X, Y and Z from somebody else or himself, and then built his three-patch series
>>>>>> A, B, C, the commit history would be like:
>>>>>>
>>>>>> ................................................
>>>>>> ---P---X---Y---Z---A---B---C
>>>>>> ................................................
>>>>>>
>>>>>> With `git format-patch --base=P -3 C`,
>>>>>>
>>>>>> where P could be the exact commit sha, or variants e.g. HEAD~6, we can also use
>>>>>> --base=auto for convenience, the base tree information block will be shown at
>>>>>> the end of the first message the command outputs (either the first patch, or
>>>>>> the cover letter), like this:
>>>>>>
>>>>>> ------------
>>>>>> base-commit: P
>>>>>> prerequisite-patch-id: X
>>>>>> prerequisite-patch-id: Y
>>>>>> prerequisite-patch-id: Z
>>>>>> ------------
>>>>>>
>>>>>> Here P is the commit sha, and X,Y,Z are the patch ids of the dependency patches.
>>>>>>
>>>>>>
>>>>>> With this info in place, I think CI should be able to setup the exact base for
>>>>>> the coming patchset, the missing part I can see is the mapping of
>>>>>> (in-flight patch <-> patch id), since we have all the in-flight patches in
>>>>>> patchwork, creating and maintaining such mapping in DB is doable, what do you
>>>>>> think?
>>>>>
>>>>> I think it would simpler to list dependencies as patchwork ids.
>>>>> Example:
>>>>> Depends-on: series-42, patch-12345
>>>>>
>>>>
>>>
>>> Just list the 'series' ? Since it can download the whole patchset with
>>> the single link format like:
>>>
>>> Depends-on: series-8843 --> https://patchwork.dpdk.org/series/8843/mbox/
>>
>> Yes, I was proposing both format: series-X and patch-Y (on top of series-X).
>> But we probably never need to be specific about a single patch.
>> I think you are right, we can keep only "series-X" syntax,
>> and allow describing a list of series, ordered and separated with comma.
>>
> +1 to "Depends-on: series-#####" syntax
I can do this - but I actually prefer just putting the series in the
brackets. Metadata tags in the message will be preserved in the commit
history, but the details of which series to start with for checking out
don't really need to be preserved. It's just a way to get the bot to
test, right? Maybe it can help maintainers to script an auto-fetch,
too.
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 1/7] net/iavf: stop the PCI probe in DCF mode
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
@ 2020-03-13 5:27 ` Ye Xiaolong
0 siblings, 0 replies; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-13 5:27 UTC (permalink / raw)
To: Haiyue Wang; +Cc: dev, qi.z.zhang, qiming.yang, beilei.xing, wei.zhao1
On 03/10, Haiyue Wang wrote:
>A new DCF PMD will be introduced, which runs on Intel VF hardware, and
>it is a pure software design to control the advance functionality (such
>as switch, ACL) for rest of the VFs.
>
>So if the DCF (Device Config Function) mode is specified by the devarg
>'cap=dcf', then it will stop the PCI probe in the iavf PMD.
>
>Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
>---
> drivers/net/iavf/iavf_ethdev.c | 43 ++++++++++++++++++++++++++++++++++
> 1 file changed, 43 insertions(+)
>
>diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
>index 34913f9c4..c0b95e169 100644
>--- a/drivers/net/iavf/iavf_ethdev.c
>+++ b/drivers/net/iavf/iavf_ethdev.c
>@@ -1416,9 +1416,51 @@ iavf_dev_uninit(struct rte_eth_dev *dev)
> return 0;
> }
>
>+static int
>+iavf_dcf_cap_check_handler(__rte_unused const char *key,
>+ const char *value, __rte_unused void *opaque)
>+{
>+ if (strcmp(value, "dcf"))
>+ return -1;
>+
>+ return 0;
>+}
>+
>+static int
>+iavf_dcf_cap_selected(struct rte_devargs *devargs)
>+{
>+ struct rte_kvargs *kvlist;
>+ const char *key = "cap";
>+ int ret = 0;
>+
>+ if (devargs == NULL)
>+ return 0;
>+
>+ kvlist = rte_kvargs_parse(devargs->args, NULL);
>+ if (kvlist == NULL)
>+ return 0;
>+
>+ if (!rte_kvargs_count(kvlist, key))
>+ goto exit;
>+
>+ /* dcf capability selected when there's a key-value pair: cap=dcf */
>+ if (rte_kvargs_process(kvlist, key,
>+ iavf_dcf_cap_check_handler, NULL) < 0)
>+ goto exit;
>+
>+ ret = 1;
>+
>+exit:
>+ rte_kvargs_free(kvlist);
>+ return ret;
>+}
>+
> static int eth_iavf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
> struct rte_pci_device *pci_dev)
> {
>+ if (iavf_dcf_cap_selected(pci_dev->device.devargs))
>+ return 1;
>+
> return rte_eth_dev_pci_generic_probe(pci_dev,
> sizeof(struct iavf_adapter), iavf_dev_init);
> }
>@@ -1439,6 +1481,7 @@ static struct rte_pci_driver rte_iavf_pmd = {
> RTE_PMD_REGISTER_PCI(net_iavf, rte_iavf_pmd);
> RTE_PMD_REGISTER_PCI_TABLE(net_iavf, pci_id_iavf_map);
> RTE_PMD_REGISTER_KMOD_DEP(net_iavf, "* igb_uio | vfio-pci");
>+RTE_PMD_REGISTER_PARAM_STRING(net_iavf, "cap=dcf");
> RTE_INIT(iavf_init_log)
> {
> iavf_logtype_init = rte_log_register("pmd.net.iavf.init");
>--
>2.25.1
>
Reviewed-by: Xiaolong Ye <xiaolong.ye@intel.com>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 3/7] net/ice: initiate to acquire the DCF capability
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 3/7] net/ice: initiate to acquire the DCF capability Haiyue Wang
@ 2020-03-13 5:51 ` Ye Xiaolong
2020-03-13 6:19 ` Wang, Haiyue
2020-03-13 6:04 ` Ye Xiaolong
1 sibling, 1 reply; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-13 5:51 UTC (permalink / raw)
To: Haiyue Wang; +Cc: dev, qi.z.zhang, qiming.yang, beilei.xing, wei.zhao1
For the subject, since this patch is about acquire + disable, how about
net/ice: support DCF capability acquire/disable
On 03/10, Haiyue Wang wrote:
>Since the DCF (Device Config Function) controls the flow setting of
>other VFs by the mailbox with PF, for security, it needs to acquire
>the DCF capability from PF when starts, and exits to disable it.
s/exits to disable it/disable it when exits
>
>Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
>---
> drivers/net/ice/ice_dcf.c | 28 +++++++++++++++++++++++++++-
> 1 file changed, 27 insertions(+), 1 deletion(-)
>
>diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
>index efb258a5a..7a3626939 100644
>--- a/drivers/net/ice/ice_dcf.c
>+++ b/drivers/net/ice/ice_dcf.c
>@@ -227,7 +227,7 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
> int err, i;
>
> caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
>- VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
>+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED | VIRTCHNL_VF_CAP_DCF |
> VF_BASE_MODE_OFFLOADS;
>
> err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
>@@ -264,6 +264,31 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
> return 0;
> }
>
>+static int
>+ice_dcf_mode_disable(struct ice_dcf_hw *hw)
>+{
>+ int err;
>+
>+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
>+ NULL, 0);
>+ if (err) {
>+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_DISABLE");
>+ return err;
>+ }
>+
>+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
>+ (uint8_t *)hw->arq_buf,
>+ ICE_DCF_AQ_BUF_SZ, NULL);
>+ if (err) {
>+ PMD_DRV_LOG(ERR,
>+ "Fail to get response of OP_DCF_DISABLE %d",
>+ err);
>+ return -1;
>+ }
>+
>+ return 0;
>+}
>+
> static int
> ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
> {
>@@ -467,6 +492,7 @@ ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
> rte_intr_callback_unregister(intr_handle,
> ice_dcf_dev_interrupt_handler, hw);
>
>+ ice_dcf_mode_disable(hw);
> iavf_shutdown_adminq(&hw->avf);
>
> rte_free(hw->arq_buf);
>--
>2.25.1
>
For the patch,
Reviewed-by: Xiaolong Ye <xiaolong.ye@intel.com>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 3/7] net/ice: initiate to acquire the DCF capability
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 3/7] net/ice: initiate to acquire the DCF capability Haiyue Wang
2020-03-13 5:51 ` Ye Xiaolong
@ 2020-03-13 6:04 ` Ye Xiaolong
2020-03-13 6:10 ` Wang, Haiyue
1 sibling, 1 reply; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-13 6:04 UTC (permalink / raw)
To: Haiyue Wang; +Cc: dev, qi.z.zhang, qiming.yang, beilei.xing, wei.zhao1
On 03/10, Haiyue Wang wrote:
>
>+static int
>+ice_dcf_mode_disable(struct ice_dcf_hw *hw)
>+{
>+ int err;
>+
>+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
>+ NULL, 0);
>+ if (err) {
>+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_DISABLE");
>+ return err;
>+ }
>+
>+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
>+ (uint8_t *)hw->arq_buf,
Unnecessary cast.
>+ ICE_DCF_AQ_BUF_SZ, NULL);
>+ if (err) {
>+ PMD_DRV_LOG(ERR,
>+ "Fail to get response of OP_DCF_DISABLE %d",
>+ err);
>+ return -1;
>+ }
>+
>+ return 0;
>+}
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 3/7] net/ice: initiate to acquire the DCF capability
2020-03-13 6:04 ` Ye Xiaolong
@ 2020-03-13 6:10 ` Wang, Haiyue
0 siblings, 0 replies; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-13 6:10 UTC (permalink / raw)
To: Ye, Xiaolong; +Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei
> -----Original Message-----
> From: Ye, Xiaolong <xiaolong.ye@intel.com>
> Sent: Friday, March 13, 2020 14:04
> To: Wang, Haiyue <haiyue.wang@intel.com>
> Cc: dev@dpdk.org; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>
> Subject: Re: [PATCH v2 3/7] net/ice: initiate to acquire the DCF capability
>
> On 03/10, Haiyue Wang wrote:
>
> >
> >+static int
> >+ice_dcf_mode_disable(struct ice_dcf_hw *hw)
> >+{
> >+ int err;
> >+
> >+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
> >+ NULL, 0);
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_DISABLE");
> >+ return err;
> >+ }
> >+
> >+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
> >+ (uint8_t *)hw->arq_buf,
>
> Unnecessary cast.
will be fixed in next patch.
>
> >+ ICE_DCF_AQ_BUF_SZ, NULL);
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR,
> >+ "Fail to get response of OP_DCF_DISABLE %d",
> >+ err);
> >+ return -1;
> >+ }
> >+
> >+ return 0;
> >+}
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 3/7] net/ice: initiate to acquire the DCF capability
2020-03-13 5:51 ` Ye Xiaolong
@ 2020-03-13 6:19 ` Wang, Haiyue
0 siblings, 0 replies; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-13 6:19 UTC (permalink / raw)
To: Ye, Xiaolong; +Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei
> -----Original Message-----
> From: Ye, Xiaolong <xiaolong.ye@intel.com>
> Sent: Friday, March 13, 2020 13:52
> To: Wang, Haiyue <haiyue.wang@intel.com>
> Cc: dev@dpdk.org; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>
> Subject: Re: [PATCH v2 3/7] net/ice: initiate to acquire the DCF capability
>
> For the subject, since this patch is about acquire + disable, how about
>
> net/ice: support DCF capability acquire/disable
Make sense, will improve the title.
>
> On 03/10, Haiyue Wang wrote:
> >Since the DCF (Device Config Function) controls the flow setting of
> >other VFs by the mailbox with PF, for security, it needs to acquire
> >the DCF capability from PF when starts, and exits to disable it.
>
> s/exits to disable it/disable it when exits
>
OK.
> >
> >Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
> >---
> > drivers/net/ice/ice_dcf.c | 28 +++++++++++++++++++++++++++-
> > 1 file changed, 27 insertions(+), 1 deletion(-)
> >
> >diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
> >index efb258a5a..7a3626939 100644
> >--- a/drivers/net/ice/ice_dcf.c
> >+++ b/drivers/net/ice/ice_dcf.c
> >@@ -227,7 +227,7 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
> > int err, i;
> >
> > caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
> >- VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
> >+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED | VIRTCHNL_VF_CAP_DCF |
> > VF_BASE_MODE_OFFLOADS;
> >
> > err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
> >@@ -264,6 +264,31 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
> > return 0;
> > }
> >
> >+static int
> >+ice_dcf_mode_disable(struct ice_dcf_hw *hw)
> >+{
> >+ int err;
> >+
> >+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
> >+ NULL, 0);
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_DISABLE");
> >+ return err;
> >+ }
> >+
> >+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
> >+ (uint8_t *)hw->arq_buf,
> >+ ICE_DCF_AQ_BUF_SZ, NULL);
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR,
> >+ "Fail to get response of OP_DCF_DISABLE %d",
> >+ err);
> >+ return -1;
> >+ }
> >+
> >+ return 0;
> >+}
> >+
> > static int
> > ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
> > {
> >@@ -467,6 +492,7 @@ ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
> > rte_intr_callback_unregister(intr_handle,
> > ice_dcf_dev_interrupt_handler, hw);
> >
> >+ ice_dcf_mode_disable(hw);
> > iavf_shutdown_adminq(&hw->avf);
> >
> > rte_free(hw->arq_buf);
> >--
> >2.25.1
> >
>
> For the patch,
>
> Reviewed-by: Xiaolong Ye <xiaolong.ye@intel.com>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 7/7] net/ice: get the VF hardware index in DCF
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
@ 2020-03-13 7:01 ` Ye Xiaolong
2020-03-16 5:58 ` Wang, Haiyue
0 siblings, 1 reply; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-13 7:01 UTC (permalink / raw)
To: Haiyue Wang; +Cc: dev, qi.z.zhang, qiming.yang, beilei.xing, wei.zhao1
On 03/10, Haiyue Wang wrote:
>The DCF (Device Config Function) needs the hardware index of the VFs to
>control the flow setting. And also if the VF resets, the index may be
>changed, so it should handle this in VF reset event.
>
>Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
>---
> drivers/net/ice/ice_dcf.c | 81 +++++++++++++++++++++++++++++++
> drivers/net/ice/ice_dcf.h | 4 ++
> drivers/net/ice/ice_dcf_parent.c | 83 +++++++++++++++++++++++++++++++-
> 3 files changed, 167 insertions(+), 1 deletion(-)
>
>diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
>index 480c449f5..1d3c8fa95 100644
>--- a/drivers/net/ice/ice_dcf.c
>+++ b/drivers/net/ice/ice_dcf.c
>@@ -269,6 +269,63 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
> return 0;
> }
>
>+static int
>+ice_dcf_get_vf_vsi_map(struct ice_dcf_hw *hw)
>+{
>+ struct virtchnl_dcf_vsi_map *vsi_map;
>+ uint16_t len;
>+ int err;
>+
>+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
>+ NULL, 0);
>+ if (err) {
>+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_GET_VSI_MAP");
Better to make the err log format consistent, either "Failed to xxx" or "Fail to xxxx",
I prefer to "Failed to xxx".
>+ return err;
>+ }
>+
>+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
>+ hw->arq_buf, ICE_DCF_AQ_BUF_SZ,
>+ &len);
>+ if (err) {
>+ PMD_DRV_LOG(ERR, "Fail to get response of OP_DCF_GET_VSI_MAP");
>+ return err;
>+ }
>+
>+ vsi_map = (struct virtchnl_dcf_vsi_map *)hw->arq_buf;
>+ if (len < sizeof(*vsi_map) || !vsi_map->num_vfs ||
>+ len < sizeof(*vsi_map) +
>+ (vsi_map->num_vfs - 1) * sizeof(vsi_map->vf_vsi[0])) {
Better to use a tmp variable to make the code more readable.
And is the first len < sizeof(*vsi_map) redundant?
>+ PMD_DRV_LOG(ERR, "invalid vf vsi map response with length %u",
>+ len);
>+ return -EINVAL;
>+ }
>+
>+ if (hw->num_vfs != 0 && hw->num_vfs != vsi_map->num_vfs) {
>+ PMD_DRV_LOG(ERR, "The number VSI map (%u) doesn't match the number of VFs (%u)",
>+ vsi_map->num_vfs, hw->num_vfs);
>+ return -EINVAL;
>+ }
>+
>+ len = vsi_map->num_vfs * sizeof(vsi_map->vf_vsi[0]);
>+ if (!hw->vf_vsi_map) {
>+ hw->num_vfs = vsi_map->num_vfs;
>+ hw->vf_vsi_map = rte_zmalloc("vf_vsi_ctx", len, 0);
>+ }
>+
>+ if (!hw->vf_vsi_map) {
>+ PMD_DRV_LOG(ERR, "Fail to alloc memory for VSI context");
>+ return -ENOMEM;
>+ }
I think above two blocks can be combined with one if (!hw->vf_vsi_map).
>+
>+ if (!memcmp(hw->vf_vsi_map, vsi_map->vf_vsi, len)) {
>+ PMD_DRV_LOG(DEBUG, "VF VSI map doesn't change");
>+ return 1;
>+ }
>+
>+ rte_memcpy(hw->vf_vsi_map, vsi_map->vf_vsi, len);
>+ return 0;
>+}
>+
> static int
> ice_dcf_mode_disable(struct ice_dcf_hw *hw)
> {
>@@ -467,6 +524,23 @@ ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
> return err;
> }
>
>+int
>+ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw)
>+{
>+ int err = 0;
>+
>+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
>+ ice_dcf_disable_irq0(hw);
>+
>+ if (ice_dcf_get_vf_resource(hw) || ice_dcf_get_vf_vsi_map(hw))
>+ err = -1;
>+
>+ ice_dcf_enable_irq0(hw);
>+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
>+
>+ return err;
>+}
>+
> int
> ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
> {
>@@ -534,6 +608,12 @@ ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
> goto err_alloc;
> }
>
>+ if (ice_dcf_get_vf_vsi_map(hw) < 0) {
>+ PMD_INIT_LOG(ERR, "Failed to get VF VSI map");
>+ ice_dcf_mode_disable(hw);
>+ goto err_alloc;
>+ }
>+
> rte_intr_callback_register(&pci_dev->intr_handle,
> ice_dcf_dev_interrupt_handler, hw);
> rte_intr_enable(&pci_dev->intr_handle);
>@@ -566,5 +646,6 @@ ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
> iavf_shutdown_adminq(&hw->avf);
>
> rte_free(hw->arq_buf);
>+ rte_free(hw->vf_vsi_map);
> rte_free(hw->vf_res);
> }
>diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
>index ecd6303a0..12bef4a2a 100644
>--- a/drivers/net/ice/ice_dcf.h
>+++ b/drivers/net/ice/ice_dcf.h
>@@ -41,6 +41,9 @@ struct ice_dcf_hw {
>
> uint8_t *arq_buf;
>
>+ uint16_t num_vfs;
>+ uint16_t *vf_vsi_map;
>+
> struct virtchnl_version_info virtchnl_version;
> struct virtchnl_vf_resource *vf_res; /* VF resource */
> struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
>@@ -51,6 +54,7 @@ int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
> struct dcf_virtchnl_cmd *cmd);
> int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
> void *buf, uint16_t buf_size);
>+int ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw);
> int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
> void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
>
>diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
>index 4c3bb68b1..2735221e9 100644
>--- a/drivers/net/ice/ice_dcf_parent.c
>+++ b/drivers/net/ice/ice_dcf_parent.c
>@@ -5,10 +5,76 @@
> #include <sys/stat.h>
> #include <unistd.h>
>
>+#include <rte_alarm.h>
>+
> #include "ice_dcf_ethdev.h"
>
>+#define ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL 100000 /* us */
>+
>+static __rte_always_inline void
>+ice_dcf_update_vsi_ctx(struct ice_hw *hw, uint16_t vsi_handle,
>+ uint16_t vsi_map)
>+{
>+ struct ice_vsi_ctx *vsi_ctx;
>+
>+ if (unlikely(vsi_handle >= ICE_MAX_VSI)) {
>+ PMD_DRV_LOG(ERR, "Invalid vsi handle %u", vsi_handle);
>+ return;
>+ }
>+
>+ vsi_ctx = hw->vsi_ctx[vsi_handle];
>+
>+ if (vsi_map & VIRTCHNL_DCF_VF_VSI_VALID) {
>+ if (!vsi_ctx)
>+ vsi_ctx = ice_malloc(hw, sizeof(*vsi_ctx));
>+
>+ if (!vsi_ctx) {
>+ PMD_DRV_LOG(ERR, "No memory for vsi context %u",
>+ vsi_handle);
>+ return;
>+ }
Above two blocks can be combined.
>+
>+ vsi_ctx->vsi_num = (vsi_map & VIRTCHNL_DCF_VF_VSI_ID_M) >>
>+ VIRTCHNL_DCF_VF_VSI_ID_S;
>+ hw->vsi_ctx[vsi_handle] = vsi_ctx;
>+
>+ PMD_DRV_LOG(DEBUG, "VF%u is assigned with vsi number %u",
>+ vsi_handle, vsi_ctx->vsi_num);
>+ } else {
>+ hw->vsi_ctx[vsi_handle] = NULL;
>+
>+ ice_free(hw, vsi_ctx);
>+
>+ PMD_DRV_LOG(NOTICE, "VF%u is disabled", vsi_handle);
>+ }
>+}
>+
>+static void
>+ice_dcf_update_vf_vsi_map(struct ice_hw *hw, uint16_t num_vfs,
>+ uint16_t *vf_vsi_map)
>+{
>+ uint16_t vf_id;
>+
>+ for (vf_id = 0; vf_id < num_vfs; vf_id++)
>+ ice_dcf_update_vsi_ctx(hw, vf_id, vf_vsi_map[vf_id]);
>+}
>+
>+static void
>+ice_dcf_vsi_update_service_handler(void *param)
>+{
>+ struct ice_dcf_hw *hw = param;
>+
>+ if (!ice_dcf_handle_vsi_update_event(hw)) {
>+ struct ice_dcf_adapter *dcf_ad =
>+ container_of(hw, struct ice_dcf_adapter, real_hw);
>+
>+ ice_dcf_update_vf_vsi_map(&dcf_ad->parent.hw,
>+ hw->num_vfs, hw->vf_vsi_map);
>+ }
>+}
>+
> void
>-ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
>+ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
> uint8_t *msg, uint16_t msglen)
> {
> struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
>@@ -21,6 +87,8 @@ ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
> switch (pf_msg->event) {
> case VIRTCHNL_EVENT_RESET_IMPENDING:
> PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
>+ rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL * 2,
>+ ice_dcf_vsi_update_service_handler, dcf_hw);
Why * 2 for the VIRTCHNL_EVENT_RESET_IMPENDING event?
> break;
> case VIRTCHNL_EVENT_LINK_CHANGE:
> PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
>@@ -28,6 +96,13 @@ ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
> case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
> PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
> break;
>+ case VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE:
>+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE event : VF%u with VSI num %u",
>+ pf_msg->event_data.vf_vsi_map.vf_id,
>+ pf_msg->event_data.vf_vsi_map.vsi_id);
>+ rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL,
>+ ice_dcf_vsi_update_service_handler, dcf_hw);
>+ break;
> default:
> PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
> break;
>@@ -235,6 +310,9 @@ ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
> }
> parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
>
>+ ice_dcf_update_vf_vsi_map(parent_hw,
>+ hw->num_vfs, hw->vf_vsi_map);
>+
No need to split into 2 lines.
> mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
> if (rte_is_valid_assigned_ether_addr(mac))
> rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
>@@ -259,5 +337,8 @@ ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
>
> eth_dev->data->mac_addrs = NULL;
>
>+ rte_eal_alarm_cancel(ice_dcf_vsi_update_service_handler,
>+ &adapter->real_hw);
>+
> ice_dcf_uninit_parent_hw(parent_hw);
> }
>--
>2.25.1
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 6/7] net/ice: handle the PF initialization by DCF
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
@ 2020-03-13 7:59 ` Ye Xiaolong
2020-03-13 8:03 ` Ye Xiaolong
2020-03-16 4:52 ` Wang, Haiyue
2020-03-13 14:06 ` Ye Xiaolong
1 sibling, 2 replies; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-13 7:59 UTC (permalink / raw)
To: Haiyue Wang; +Cc: dev, qi.z.zhang, qiming.yang, beilei.xing, wei.zhao1
On 03/10, Haiyue Wang wrote:
>The DCF (Device Config Function) works at the user PF level, it can't
>access the real PF hardware directly. So it will proxy the PF's AdminQ
>command through DCF's mailbox.
>
>And the DCF is mainly used to control the flow setting of other VFs, so
>it only needs to initialize some core functions about the flow .
>
>Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
>---
> drivers/net/ice/Makefile | 1 +
> drivers/net/ice/ice_dcf.c | 7 +-
> drivers/net/ice/ice_dcf.h | 3 +
> drivers/net/ice/ice_dcf_ethdev.c | 10 +-
> drivers/net/ice/ice_dcf_ethdev.h | 11 +-
> drivers/net/ice/ice_dcf_parent.c | 263 +++++++++++++++++++++++++++++++
> drivers/net/ice/meson.build | 3 +-
> 7 files changed, 292 insertions(+), 6 deletions(-)
> create mode 100644 drivers/net/ice/ice_dcf_parent.c
>
>diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
>index f493c9ed7..3ecc72219 100644
>--- a/drivers/net/ice/Makefile
>+++ b/drivers/net/ice/Makefile
>@@ -88,6 +88,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
>
> SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
> SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
>+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_parent.c
>
> # install this header file
> SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
>diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
>index 24ed31f35..480c449f5 100644
>--- a/drivers/net/ice/ice_dcf.c
>+++ b/drivers/net/ice/ice_dcf.c
>@@ -124,8 +124,13 @@ ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
> }
>
> v_op = rte_le_to_cpu_32(info->desc.cookie_high);
>- if (unlikely(v_op == VIRTCHNL_OP_EVENT))
>+ if (unlikely(v_op == VIRTCHNL_OP_EVENT)) {
Is this unlikely really needed?
>+ if (hw->vc_event_msg_cb != NULL)
>+ hw->vc_event_msg_cb(hw,
>+ info->msg_buf,
>+ info->msg_len);
> return;
>+ }
>
> v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
>
>diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
>index 99bd53b02..ecd6303a0 100644
>--- a/drivers/net/ice/ice_dcf.h
>+++ b/drivers/net/ice/ice_dcf.h
>@@ -36,6 +36,9 @@ struct ice_dcf_hw {
> rte_spinlock_t vc_cmd_send_lock;
> rte_spinlock_t vc_cmd_queue_lock;
> TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
>+ void (*vc_event_msg_cb)(struct ice_dcf_hw *dcf_hw,
>+ uint8_t *msg, uint16_t msglen);
>+
> uint8_t *arq_buf;
>
> struct virtchnl_version_info virtchnl_version;
>diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
>index 23f82a487..af94caeff 100644
>--- a/drivers/net/ice/ice_dcf_ethdev.c
>+++ b/drivers/net/ice/ice_dcf_ethdev.c
>@@ -145,8 +145,8 @@ ice_dcf_dev_close(struct rte_eth_dev *dev)
> dev->dev_ops = NULL;
> dev->rx_pkt_burst = NULL;
> dev->tx_pkt_burst = NULL;
>- dev->data->mac_addrs = NULL;
>
>+ ice_dcf_uninit_parent_adapter(dev);
> ice_dcf_uninit_hw(dev, &adapter->real_hw);
> }
>
>@@ -225,13 +225,17 @@ ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
>
> eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
>
>+ adapter->real_hw.vc_event_msg_cb = ice_dcf_handle_pf_event_msg;
> if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
> PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
> return -1;
> }
>
>- rte_eth_random_addr(adapter->mac_addr.addr_bytes);
>- eth_dev->data->mac_addrs = &adapter->mac_addr;
>+ if (ice_dcf_init_parent_adapter(eth_dev) != 0) {
>+ PMD_INIT_LOG(ERR, "Failed to init DCF parent adapter");
>+ ice_dcf_uninit_hw(eth_dev, &adapter->real_hw);
>+ return -1;
>+ }
>
> return 0;
> }
>diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
>index 0c34a0095..e60e808d8 100644
>--- a/drivers/net/ice/ice_dcf_ethdev.h
>+++ b/drivers/net/ice/ice_dcf_ethdev.h
>@@ -5,6 +5,9 @@
> #ifndef _ICE_DCF_ETHDEV_H_
> #define _ICE_DCF_ETHDEV_H_
>
>+#include "base/ice_common.h"
>+#include "base/ice_adminq_cmd.h"
>+
> #include "ice_ethdev.h"
> #include "ice_dcf.h"
>
>@@ -15,10 +18,16 @@ struct ice_dcf_queue {
> };
>
> struct ice_dcf_adapter {
>+ struct ice_adapter parent; /* Must be first */
>+
> struct ice_dcf_hw real_hw;
>- struct rte_ether_addr mac_addr;
This one isn't needed at the first place.
> struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
> struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
> };
>
>+void ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
>+ uint8_t *msg, uint16_t msglen);
>+int ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev);
>+void ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev);
>+
> #endif /* _ICE_DCF_ETHDEV_H_ */
>diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
>new file mode 100644
>index 000000000..4c3bb68b1
>--- /dev/null
>+++ b/drivers/net/ice/ice_dcf_parent.c
>@@ -0,0 +1,263 @@
>+/* SPDX-License-Identifier: BSD-3-Clause
>+ * Copyright(c) 2020 Intel Corporation
>+ */
>+#include <sys/types.h>
>+#include <sys/stat.h>
>+#include <unistd.h>
>+
>+#include "ice_dcf_ethdev.h"
>+
>+void
>+ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
>+ uint8_t *msg, uint16_t msglen)
>+{
>+ struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
>+
>+ if (msglen < sizeof(struct virtchnl_pf_event)) {
>+ PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen);
>+ return;
>+ }
>+
>+ switch (pf_msg->event) {
>+ case VIRTCHNL_EVENT_RESET_IMPENDING:
>+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
>+ break;
>+ case VIRTCHNL_EVENT_LINK_CHANGE:
>+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
>+ break;
>+ case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
>+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
>+ break;
>+ default:
>+ PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
>+ break;
>+ }
>+}
>+
>+static int
>+ice_dcf_init_parent_hw(struct ice_hw *hw)
>+{
>+ struct ice_aqc_get_phy_caps_data *pcaps;
>+ enum ice_status status;
>+
>+ status = ice_aq_get_fw_ver(hw, NULL);
>+ if (status)
>+ return status;
>+
>+ status = ice_get_caps(hw);
>+ if (status)
>+ return status;
>+
>+ hw->port_info = (struct ice_port_info *)
>+ ice_malloc(hw, sizeof(*hw->port_info));
>+ if (!hw->port_info)
>+ return ICE_ERR_NO_MEMORY;
>+
>+ /* set the back pointer to HW */
>+ hw->port_info->hw = hw;
>+
>+ /* Initialize port_info struct with switch configuration data */
>+ status = ice_get_initial_sw_cfg(hw);
>+ if (status)
>+ goto err_unroll_alloc;
>+
>+ pcaps = (struct ice_aqc_get_phy_caps_data *)
>+ ice_malloc(hw, sizeof(*pcaps));
>+ if (!pcaps) {
>+ status = ICE_ERR_NO_MEMORY;
>+ goto err_unroll_alloc;
>+ }
>+
>+ /* Initialize port_info struct with PHY capabilities */
>+ status = ice_aq_get_phy_caps(hw->port_info, false,
>+ ICE_AQC_REPORT_TOPO_CAP, pcaps, NULL);
>+ ice_free(hw, pcaps);
>+ if (status)
>+ goto err_unroll_alloc;
>+
>+ /* Initialize port_info struct with link information */
>+ status = ice_aq_get_link_info(hw->port_info, false, NULL, NULL);
>+ if (status)
>+ goto err_unroll_alloc;
>+
>+ status = ice_init_fltr_mgmt_struct(hw);
>+ if (status)
>+ goto err_unroll_alloc;
>+
>+ status = ice_init_hw_tbls(hw);
>+ if (status)
>+ goto err_unroll_fltr_mgmt_struct;
>+
>+ PMD_INIT_LOG(INFO,
>+ "firmware %d.%d.%d api %d.%d.%d build 0x%08x",
>+ hw->fw_maj_ver, hw->fw_min_ver, hw->fw_patch,
>+ hw->api_maj_ver, hw->api_min_ver, hw->api_patch,
>+ hw->fw_build);
>+
>+ return ICE_SUCCESS;
>+
>+err_unroll_fltr_mgmt_struct:
>+ ice_cleanup_fltr_mgmt_struct(hw);
>+err_unroll_alloc:
>+ ice_free(hw, hw->port_info);
>+ hw->port_info = NULL;
>+
>+ return status;
>+}
>+
>+static void ice_dcf_uninit_parent_hw(struct ice_hw *hw)
>+{
>+ ice_cleanup_fltr_mgmt_struct(hw);
>+
>+ ice_free_seg(hw);
>+ ice_free_hw_tbls(hw);
>+
>+ ice_free(hw, hw->port_info);
>+ hw->port_info = NULL;
>+
>+ ice_clear_all_vsi_ctx(hw);
>+}
>+
>+static int
>+ice_dcf_request_pkg_name(struct ice_hw *hw, char *pkg_name)
>+{
>+ struct ice_dcf_adapter *dcf_adapter =
>+ container_of(hw, struct ice_dcf_adapter, parent.hw);
>+
>+ /* TODO: check with DSN firstly by iAVF */
>+ PMD_INIT_LOG(DEBUG,
>+ "DCF VSI_ID = %u",
>+ dcf_adapter->real_hw.vsi_id);
>+
>+ snprintf(pkg_name,
>+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_UPDATES);
>+ if (!access(pkg_name, 0))
>+ return 0;
>+
>+ snprintf(pkg_name,
>+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_DEFAULT);
>+ if (!access(pkg_name, 0))
>+ return 0;
>+
>+ return -1;
>+}
>+
>+static int
>+ice_dcf_load_pkg(struct ice_hw *hw)
>+{
>+ char pkg_name[ICE_MAX_PKG_FILENAME_SIZE];
>+ uint8_t *pkg_buf;
>+ uint32_t buf_len;
>+ struct stat st;
>+ FILE *fp;
>+ int err;
>+
>+ if (ice_dcf_request_pkg_name(hw, pkg_name)) {
>+ PMD_INIT_LOG(ERR, "failed to locate the package file");
s/failed/Failed
>+ return -ENOENT;
>+ }
>+
>+ PMD_INIT_LOG(DEBUG, "DDP package name: %s", pkg_name);
>+
>+ err = stat(pkg_name, &st);
>+ if (err) {
>+ PMD_INIT_LOG(ERR, "failed to get file status");
s/failed/Failed
>+ return err;
>+ }
>+
>+ buf_len = st.st_size;
>+ pkg_buf = rte_malloc(NULL, buf_len, 0);
>+ if (!pkg_buf) {
>+ PMD_INIT_LOG(ERR, "failed to allocate buffer of size %u for package",
>+ buf_len);
>+ return -1;
>+ }
>+
>+ fp = fopen(pkg_name, "rb");
>+ if (!fp) {
>+ PMD_INIT_LOG(ERR, "failed to open file: %s", pkg_name);
>+ err = -1;
>+ goto ret;
>+ }
>+
>+ err = fread(pkg_buf, buf_len, 1, fp);
>+ fclose(fp);
>+ if (err != 1) {
>+ PMD_INIT_LOG(ERR, "failed to read package data");
>+ err = -1;
>+ goto ret;
>+ }
>+
>+ err = ice_copy_and_init_pkg(hw, pkg_buf, buf_len);
>+ if (err)
>+ PMD_INIT_LOG(ERR, "ice_copy_and_init_hw failed: %d", err);
>+
>+ret:
>+ rte_free(pkg_buf);
>+ return err;
>+}
>+
>+int
>+ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
>+{
>+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
>+ struct ice_adapter *parent_adapter = &adapter->parent;
>+ struct ice_hw *parent_hw = &parent_adapter->hw;
>+ struct ice_dcf_hw *hw = &adapter->real_hw;
>+ const struct rte_ether_addr *mac;
>+ int err;
>+
>+ parent_adapter->eth_dev = eth_dev;
>+ parent_adapter->pf.adapter = parent_adapter;
>+ parent_adapter->pf.dev_data = eth_dev->data;
>+ parent_hw->back = parent_adapter;
>+ parent_hw->mac_type = ICE_MAC_GENERIC;
>+ parent_hw->vendor_id = ICE_INTEL_VENDOR_ID;
>+
>+ ice_init_lock(&parent_hw->adminq.sq_lock);
>+ ice_init_lock(&parent_hw->adminq.rq_lock);
>+ parent_hw->aq_send_cmd_fn = ice_dcf_send_aq_cmd;
>+ parent_hw->aq_send_cmd_param = &adapter->real_hw;
>+ parent_hw->dcf_enabled = true;
>+
>+ err = ice_dcf_init_parent_hw(parent_hw);
>+ if (err) {
>+ PMD_INIT_LOG(ERR, "failed to init the DCF parent hardware with error %d",
>+ err);
>+ return err;
>+ }
>+
>+ err = ice_dcf_load_pkg(parent_hw);
>+ if (err) {
>+ PMD_INIT_LOG(ERR, "failed to load package with error %d",
>+ err);
>+ goto uninit_hw;
>+ }
>+ parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
>+
>+ mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
>+ if (rte_is_valid_assigned_ether_addr(mac))
>+ rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
>+ else
>+ rte_eth_random_addr(parent_adapter->pf.dev_addr.addr_bytes);
>+
>+ eth_dev->data->mac_addrs = &parent_adapter->pf.dev_addr;
>+
>+ return 0;
>+
>+uninit_hw:
>+ ice_dcf_uninit_parent_hw(parent_hw);
>+ return err;
>+}
>+
>+void
>+ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
>+{
>+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
>+ struct ice_adapter *parent_adapter = &adapter->parent;
>+ struct ice_hw *parent_hw = &parent_adapter->hw;
>+
>+ eth_dev->data->mac_addrs = NULL;
>+
>+ ice_dcf_uninit_parent_hw(parent_hw);
>+}
>diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
>index 0ba9668d1..7e9037f3b 100644
>--- a/drivers/net/ice/meson.build
>+++ b/drivers/net/ice/meson.build
>@@ -38,6 +38,7 @@ if arch_subdir == 'x86'
> endif
>
> sources += files('ice_dcf.c',
>- 'ice_dcf_ethdev.c')
>+ 'ice_dcf_ethdev.c',
>+ 'ice_dcf_parent.c')
>
> install_headers('rte_pmd_ice.h')
>--
>2.25.1
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 6/7] net/ice: handle the PF initialization by DCF
2020-03-13 7:59 ` Ye Xiaolong
@ 2020-03-13 8:03 ` Ye Xiaolong
2020-03-16 4:52 ` Wang, Haiyue
1 sibling, 0 replies; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-13 8:03 UTC (permalink / raw)
To: Haiyue Wang; +Cc: dev, qi.z.zhang, qiming.yang, beilei.xing, wei.zhao1
On 03/13, Ye Xiaolong wrote:
>> struct ice_dcf_adapter {
>>+ struct ice_adapter parent; /* Must be first */
>>+
>> struct ice_dcf_hw real_hw;
>>- struct rte_ether_addr mac_addr;
>
>This one isn't needed at the first place.
My bad, please ignore this comment.
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 6/7] net/ice: handle the PF initialization by DCF
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
2020-03-13 7:59 ` Ye Xiaolong
@ 2020-03-13 14:06 ` Ye Xiaolong
2020-03-13 14:11 ` Wang, Haiyue
1 sibling, 1 reply; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-13 14:06 UTC (permalink / raw)
To: Haiyue Wang; +Cc: dev, qi.z.zhang, qiming.yang, beilei.xing, wei.zhao1
On 03/10, Haiyue Wang wrote:
>The DCF (Device Config Function) works at the user PF level, it can't
>access the real PF hardware directly. So it will proxy the PF's AdminQ
>command through DCF's mailbox.
Proxy is a noun, so this sentence is a little bit confusing.
Do you mean DCF will rely on the mailbox to serve as the proxy to pass the
PF's AdminQ command?
Thanks,
Xiaolong
>
>And the DCF is mainly used to control the flow setting of other VFs, so
>it only needs to initialize some core functions about the flow .
>
>Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
>---
> drivers/net/ice/Makefile | 1 +
> drivers/net/ice/ice_dcf.c | 7 +-
> drivers/net/ice/ice_dcf.h | 3 +
> drivers/net/ice/ice_dcf_ethdev.c | 10 +-
> drivers/net/ice/ice_dcf_ethdev.h | 11 +-
> drivers/net/ice/ice_dcf_parent.c | 263 +++++++++++++++++++++++++++++++
> drivers/net/ice/meson.build | 3 +-
> 7 files changed, 292 insertions(+), 6 deletions(-)
> create mode 100644 drivers/net/ice/ice_dcf_parent.c
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 6/7] net/ice: handle the PF initialization by DCF
2020-03-13 14:06 ` Ye Xiaolong
@ 2020-03-13 14:11 ` Wang, Haiyue
0 siblings, 0 replies; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-13 14:11 UTC (permalink / raw)
To: Ye, Xiaolong; +Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei
> -----Original Message-----
> From: Ye, Xiaolong <xiaolong.ye@intel.com>
> Sent: Friday, March 13, 2020 22:07
> To: Wang, Haiyue <haiyue.wang@intel.com>
> Cc: dev@dpdk.org; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>
> Subject: Re: [PATCH v2 6/7] net/ice: handle the PF initialization by DCF
>
> On 03/10, Haiyue Wang wrote:
> >The DCF (Device Config Function) works at the user PF level, it can't
> >access the real PF hardware directly. So it will proxy the PF's AdminQ
> >command through DCF's mailbox.
>
> Proxy is a noun, so this sentence is a little bit confusing.
> Do you mean DCF will rely on the mailbox to serve as the proxy to pass the
> PF's AdminQ command?
>
Yes, exactly, should be "pass through the PF's ..."
> Thanks,
> Xiaolong
>
> >
> >And the DCF is mainly used to control the flow setting of other VFs, so
> >it only needs to initialize some core functions about the flow .
> >
> >Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
> >---
> > drivers/net/ice/Makefile | 1 +
> > drivers/net/ice/ice_dcf.c | 7 +-
> > drivers/net/ice/ice_dcf.h | 3 +
> > drivers/net/ice/ice_dcf_ethdev.c | 10 +-
> > drivers/net/ice/ice_dcf_ethdev.h | 11 +-
> > drivers/net/ice/ice_dcf_parent.c | 263 +++++++++++++++++++++++++++++++
> > drivers/net/ice/meson.build | 3 +-
> > 7 files changed, 292 insertions(+), 6 deletions(-)
> > create mode 100644 drivers/net/ice/ice_dcf_parent.c
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 0/7] " Haiyue Wang
` (6 preceding siblings ...)
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
@ 2020-03-13 16:19 ` Stillwell Jr, Paul M
2020-03-13 16:25 ` Wang, Haiyue
2020-03-15 1:49 ` Zhang, Qi Z
7 siblings, 2 replies; 94+ messages in thread
From: Stillwell Jr, Paul M @ 2020-03-13 16:19 UTC (permalink / raw)
To: Wang, Haiyue, dev, Ye, Xiaolong, Zhang, Qi Z, Yang, Qiming, Xing, Beilei
Cc: Zhao1, Wei, Wang, Haiyue
I'm confused. Shouldn't the DCF be a separate driver since it is a VF, not part of a PF? You are starting to combine PF/VF code and I'm not sure if that is the correct way to go.
Paul
> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Haiyue Wang
> Sent: Monday, March 9, 2020 11:50 PM
> To: dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z
> <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei
> <beilei.xing@intel.com>
> Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> <haiyue.wang@intel.com>
> Subject: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
>
> A DCF (Device Config Function) based approach is proposed where a device
> bound to the device's VF0 can act as a sole controlling entity to exercise
> advance functionality (such as switch, ACL) for rest of the VFs.
>
> The DCF works as a standalone PMD to support this function, which shares
> the ice PMD flow control core function and the iavf virtchnl mailbox core
> module.
>
> This patchset is based on:
> [1] https://patchwork.dpdk.org/cover/66417/ : update ice base code [2]
> https://patchwork.dpdk.org/cover/66472/ : iavf share code update
>
> Depends-on: series-8843
> Depends-on: series-8855
>
> v2:
> 1. update the iavf patchset link.
> 2. split more patches for making this work be more understandable
> 3. fix the log function usage, devargs checking from v1.
>
> Haiyue Wang (7):
> net/iavf: stop the PCI probe in DCF mode
> net/ice: add the DCF hardware initialization
> net/ice: initiate to acquire the DCF capability
> net/ice: handle the AdminQ command by DCF
> net/ice: export the DDP definition symbols
> net/ice: handle the PF initialization by DCF
> net/ice: get the VF hardware index in DCF
>
> doc/guides/nics/ice.rst | 47 ++
> doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> doc/guides/rel_notes/release_20_05.rst | 5 +
> drivers/common/Makefile | 1 +
> drivers/net/iavf/iavf_ethdev.c | 43 ++
> drivers/net/ice/Makefile | 6 +
> drivers/net/ice/ice_dcf.c | 651 +++++++++++++++++++++++++
> drivers/net/ice/ice_dcf.h | 61 +++
> drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
> drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> drivers/net/ice/ice_dcf_parent.c | 344 +++++++++++++
> drivers/net/ice/ice_ethdev.c | 9 +-
> drivers/net/ice/ice_ethdev.h | 8 +
> drivers/net/ice/meson.build | 8 +-
> mk/rte.app.mk | 1 +
> 15 files changed, 1528 insertions(+), 10 deletions(-) create mode 100644
> doc/guides/nics/img/ice_dcf.png create mode 100644
> drivers/net/ice/ice_dcf.c create mode 100644 drivers/net/ice/ice_dcf.h
> create mode 100644 drivers/net/ice/ice_dcf_ethdev.c create mode 100644
> drivers/net/ice/ice_dcf_ethdev.h create mode 100644
> drivers/net/ice/ice_dcf_parent.c
>
> --
> 2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
2020-03-13 16:19 ` [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support Stillwell Jr, Paul M
@ 2020-03-13 16:25 ` Wang, Haiyue
2020-03-13 16:50 ` Stillwell Jr, Paul M
2020-03-15 1:49 ` Zhang, Qi Z
1 sibling, 1 reply; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-13 16:25 UTC (permalink / raw)
To: Stillwell Jr, Paul M, dev, Ye, Xiaolong, Zhang, Qi Z, Yang,
Qiming, Xing, Beilei
Cc: Zhao1, Wei
Hi Paul,
Yes, it's VF (VF hardware initialization like virtchnl). But the flow setting is the
ice PF AdminQ message, so the DCF shares most of ice PMD flow control.
BR,
Haiyue
> -----Original Message-----
> From: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>
> Sent: Saturday, March 14, 2020 00:19
> To: Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang,
> Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue <haiyue.wang@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
>
> I'm confused. Shouldn't the DCF be a separate driver since it is a VF, not part of a PF? You are
> starting to combine PF/VF code and I'm not sure if that is the correct way to go.
>
> Paul
>
> > -----Original Message-----
> > From: dev <dev-bounces@dpdk.org> On Behalf Of Haiyue Wang
> > Sent: Monday, March 9, 2020 11:50 PM
> > To: dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z
> > <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei
> > <beilei.xing@intel.com>
> > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > <haiyue.wang@intel.com>
> > Subject: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> >
> > A DCF (Device Config Function) based approach is proposed where a device
> > bound to the device's VF0 can act as a sole controlling entity to exercise
> > advance functionality (such as switch, ACL) for rest of the VFs.
> >
> > The DCF works as a standalone PMD to support this function, which shares
> > the ice PMD flow control core function and the iavf virtchnl mailbox core
> > module.
> >
> > This patchset is based on:
> > [1] https://patchwork.dpdk.org/cover/66417/ : update ice base code [2]
> > https://patchwork.dpdk.org/cover/66472/ : iavf share code update
> >
> > Depends-on: series-8843
> > Depends-on: series-8855
> >
> > v2:
> > 1. update the iavf patchset link.
> > 2. split more patches for making this work be more understandable
> > 3. fix the log function usage, devargs checking from v1.
> >
> > Haiyue Wang (7):
> > net/iavf: stop the PCI probe in DCF mode
> > net/ice: add the DCF hardware initialization
> > net/ice: initiate to acquire the DCF capability
> > net/ice: handle the AdminQ command by DCF
> > net/ice: export the DDP definition symbols
> > net/ice: handle the PF initialization by DCF
> > net/ice: get the VF hardware index in DCF
> >
> > doc/guides/nics/ice.rst | 47 ++
> > doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> > doc/guides/rel_notes/release_20_05.rst | 5 +
> > drivers/common/Makefile | 1 +
> > drivers/net/iavf/iavf_ethdev.c | 43 ++
> > drivers/net/ice/Makefile | 6 +
> > drivers/net/ice/ice_dcf.c | 651 +++++++++++++++++++++++++
> > drivers/net/ice/ice_dcf.h | 61 +++
> > drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
> > drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> > drivers/net/ice/ice_dcf_parent.c | 344 +++++++++++++
> > drivers/net/ice/ice_ethdev.c | 9 +-
> > drivers/net/ice/ice_ethdev.h | 8 +
> > drivers/net/ice/meson.build | 8 +-
> > mk/rte.app.mk | 1 +
> > 15 files changed, 1528 insertions(+), 10 deletions(-) create mode 100644
> > doc/guides/nics/img/ice_dcf.png create mode 100644
> > drivers/net/ice/ice_dcf.c create mode 100644 drivers/net/ice/ice_dcf.h
> > create mode 100644 drivers/net/ice/ice_dcf_ethdev.c create mode 100644
> > drivers/net/ice/ice_dcf_ethdev.h create mode 100644
> > drivers/net/ice/ice_dcf_parent.c
> >
> > --
> > 2.25.1
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
2020-03-13 16:25 ` Wang, Haiyue
@ 2020-03-13 16:50 ` Stillwell Jr, Paul M
2020-03-13 17:05 ` Wang, Haiyue
0 siblings, 1 reply; 94+ messages in thread
From: Stillwell Jr, Paul M @ 2020-03-13 16:50 UTC (permalink / raw)
To: Wang, Haiyue, dev, Ye, Xiaolong, Zhang, Qi Z, Yang, Qiming, Xing, Beilei
Cc: Zhao1, Wei
Hi Haiyue,
This statement is confusing to me "But the flow setting is the ice PF AdminQ message, so the DCF shares most of ice PMD flow control." What do you mean by "flow setting"? The way I understand DCF working is that there is a trusted VF (the DCF) that is setting switch rules for other VFs on the same PF. The mechanism for doing that is the DCF sends a virtchnl message to the Linux kernel driver PF to add/delete a switch rule. None of this requires the ice PMD as far as I can tell. This seems like a driver just like the iavf driver; the iavf driver is separate from the ice PMD and it seems like DCF should also be separate.
Paul
> -----Original Message-----
> From: Wang, Haiyue <haiyue.wang@intel.com>
> Sent: Friday, March 13, 2020 9:25 AM
> To: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>; dev@dpdk.org; Ye,
> Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>;
> Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> Cc: Zhao1, Wei <wei.zhao1@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
>
> Hi Paul,
>
> Yes, it's VF (VF hardware initialization like virtchnl). But the flow setting is the
> ice PF AdminQ message, so the DCF shares most of ice PMD flow control.
>
> BR,
> Haiyue
>
> > -----Original Message-----
> > From: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>
> > Sent: Saturday, March 14, 2020 00:19
> > To: Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye, Xiaolong
> > <xiaolong.ye@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang,
> > Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > <haiyue.wang@intel.com>
> > Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> >
> > I'm confused. Shouldn't the DCF be a separate driver since it is a VF,
> > not part of a PF? You are starting to combine PF/VF code and I'm not sure if
> that is the correct way to go.
> >
> > Paul
> >
> > > -----Original Message-----
> > > From: dev <dev-bounces@dpdk.org> On Behalf Of Haiyue Wang
> > > Sent: Monday, March 9, 2020 11:50 PM
> > > To: dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z
> > > <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> > > Beilei <beilei.xing@intel.com>
> > > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > > <haiyue.wang@intel.com>
> > > Subject: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> > >
> > > A DCF (Device Config Function) based approach is proposed where a
> > > device bound to the device's VF0 can act as a sole controlling
> > > entity to exercise advance functionality (such as switch, ACL) for rest of
> the VFs.
> > >
> > > The DCF works as a standalone PMD to support this function, which
> > > shares the ice PMD flow control core function and the iavf virtchnl
> > > mailbox core module.
> > >
> > > This patchset is based on:
> > > [1] https://patchwork.dpdk.org/cover/66417/ : update ice base code
> > > [2] https://patchwork.dpdk.org/cover/66472/ : iavf share code update
> > >
> > > Depends-on: series-8843
> > > Depends-on: series-8855
> > >
> > > v2:
> > > 1. update the iavf patchset link.
> > > 2. split more patches for making this work be more understandable
> > > 3. fix the log function usage, devargs checking from v1.
> > >
> > > Haiyue Wang (7):
> > > net/iavf: stop the PCI probe in DCF mode
> > > net/ice: add the DCF hardware initialization
> > > net/ice: initiate to acquire the DCF capability
> > > net/ice: handle the AdminQ command by DCF
> > > net/ice: export the DDP definition symbols
> > > net/ice: handle the PF initialization by DCF
> > > net/ice: get the VF hardware index in DCF
> > >
> > > doc/guides/nics/ice.rst | 47 ++
> > > doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> > > doc/guides/rel_notes/release_20_05.rst | 5 +
> > > drivers/common/Makefile | 1 +
> > > drivers/net/iavf/iavf_ethdev.c | 43 ++
> > > drivers/net/ice/Makefile | 6 +
> > > drivers/net/ice/ice_dcf.c | 651 +++++++++++++++++++++++++
> > > drivers/net/ice/ice_dcf.h | 61 +++
> > > drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
> > > drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> > > drivers/net/ice/ice_dcf_parent.c | 344 +++++++++++++
> > > drivers/net/ice/ice_ethdev.c | 9 +-
> > > drivers/net/ice/ice_ethdev.h | 8 +
> > > drivers/net/ice/meson.build | 8 +-
> > > mk/rte.app.mk | 1 +
> > > 15 files changed, 1528 insertions(+), 10 deletions(-) create mode
> > > 100644 doc/guides/nics/img/ice_dcf.png create mode 100644
> > > drivers/net/ice/ice_dcf.c create mode 100644
> > > drivers/net/ice/ice_dcf.h create mode 100644
> > > drivers/net/ice/ice_dcf_ethdev.c create mode 100644
> > > drivers/net/ice/ice_dcf_ethdev.h create mode 100644
> > > drivers/net/ice/ice_dcf_parent.c
> > >
> > > --
> > > 2.25.1
> >
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
2020-03-13 16:50 ` Stillwell Jr, Paul M
@ 2020-03-13 17:05 ` Wang, Haiyue
2020-03-13 17:47 ` Stillwell Jr, Paul M
0 siblings, 1 reply; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-13 17:05 UTC (permalink / raw)
To: Stillwell Jr, Paul M, dev, Ye, Xiaolong, Zhang, Qi Z, Yang,
Qiming, Xing, Beilei
Cc: Zhao1, Wei
Hi Paul,
> -----Original Message-----
> From: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>
> Sent: Saturday, March 14, 2020 00:50
> To: Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang,
> Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> Cc: Zhao1, Wei <wei.zhao1@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
>
> Hi Haiyue,
>
> This statement is confusing to me "But the flow setting is the ice PF AdminQ message, so the DCF
> shares most of ice PMD flow control." What do you mean by "flow setting"?
It is DPDP rte_flow API calling.
> The way I understand DCF
> working is that there is a trusted VF (the DCF) that is setting switch rules for other VFs on the same
> PF. The mechanism for doing that is the DCF sends a virtchnl message to the Linux kernel driver PF to
DCF needs: 1). virtchnl message is handles by 'dpdk/drivers/common/iavf/', which is the original iavf base code.
> add/delete a switch rule. None of this requires the ice PMD as far as I can tell. This seems like a
DCF needs: 2). add/delete a switch rule.
rte_flow API --> 'dpdk/drivers/net/ice/ice_switch_filter.c/ice_generic_flow.c' (ice flow framework)
|
`--> 'dpdk/drivers/net/ice/base' ...
So, put it under the ice PMD is the best way.
> driver just like the iavf driver; the iavf driver is separate from the ice PMD and it seems like DCF
> should also be separate.
>
> Paul
>
> > -----Original Message-----
> > From: Wang, Haiyue <haiyue.wang@intel.com>
> > Sent: Friday, March 13, 2020 9:25 AM
> > To: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>; dev@dpdk.org; Ye,
> > Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>;
> > Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> > Cc: Zhao1, Wei <wei.zhao1@intel.com>
> > Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> >
> > Hi Paul,
> >
> > Yes, it's VF (VF hardware initialization like virtchnl). But the flow setting is the
> > ice PF AdminQ message, so the DCF shares most of ice PMD flow control.
> >
> > BR,
> > Haiyue
> >
> > > -----Original Message-----
> > > From: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>
> > > Sent: Saturday, March 14, 2020 00:19
> > > To: Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye, Xiaolong
> > > <xiaolong.ye@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang,
> > > Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> > > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > > <haiyue.wang@intel.com>
> > > Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> > >
> > > I'm confused. Shouldn't the DCF be a separate driver since it is a VF,
> > > not part of a PF? You are starting to combine PF/VF code and I'm not sure if
> > that is the correct way to go.
> > >
> > > Paul
> > >
> > > > -----Original Message-----
> > > > From: dev <dev-bounces@dpdk.org> On Behalf Of Haiyue Wang
> > > > Sent: Monday, March 9, 2020 11:50 PM
> > > > To: dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z
> > > > <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> > > > Beilei <beilei.xing@intel.com>
> > > > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > > > <haiyue.wang@intel.com>
> > > > Subject: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> > > >
> > > > A DCF (Device Config Function) based approach is proposed where a
> > > > device bound to the device's VF0 can act as a sole controlling
> > > > entity to exercise advance functionality (such as switch, ACL) for rest of
> > the VFs.
> > > >
> > > > The DCF works as a standalone PMD to support this function, which
> > > > shares the ice PMD flow control core function and the iavf virtchnl
> > > > mailbox core module.
> > > >
> > > > This patchset is based on:
> > > > [1] https://patchwork.dpdk.org/cover/66417/ : update ice base code
> > > > [2] https://patchwork.dpdk.org/cover/66472/ : iavf share code update
> > > >
> > > > Depends-on: series-8843
> > > > Depends-on: series-8855
> > > >
> > > > v2:
> > > > 1. update the iavf patchset link.
> > > > 2. split more patches for making this work be more understandable
> > > > 3. fix the log function usage, devargs checking from v1.
> > > >
> > > > Haiyue Wang (7):
> > > > net/iavf: stop the PCI probe in DCF mode
> > > > net/ice: add the DCF hardware initialization
> > > > net/ice: initiate to acquire the DCF capability
> > > > net/ice: handle the AdminQ command by DCF
> > > > net/ice: export the DDP definition symbols
> > > > net/ice: handle the PF initialization by DCF
> > > > net/ice: get the VF hardware index in DCF
> > > >
> > > > doc/guides/nics/ice.rst | 47 ++
> > > > doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> > > > doc/guides/rel_notes/release_20_05.rst | 5 +
> > > > drivers/common/Makefile | 1 +
> > > > drivers/net/iavf/iavf_ethdev.c | 43 ++
> > > > drivers/net/ice/Makefile | 6 +
> > > > drivers/net/ice/ice_dcf.c | 651 +++++++++++++++++++++++++
> > > > drivers/net/ice/ice_dcf.h | 61 +++
> > > > drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
> > > > drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> > > > drivers/net/ice/ice_dcf_parent.c | 344 +++++++++++++
> > > > drivers/net/ice/ice_ethdev.c | 9 +-
> > > > drivers/net/ice/ice_ethdev.h | 8 +
> > > > drivers/net/ice/meson.build | 8 +-
> > > > mk/rte.app.mk | 1 +
> > > > 15 files changed, 1528 insertions(+), 10 deletions(-) create mode
> > > > 100644 doc/guides/nics/img/ice_dcf.png create mode 100644
> > > > drivers/net/ice/ice_dcf.c create mode 100644
> > > > drivers/net/ice/ice_dcf.h create mode 100644
> > > > drivers/net/ice/ice_dcf_ethdev.c create mode 100644
> > > > drivers/net/ice/ice_dcf_ethdev.h create mode 100644
> > > > drivers/net/ice/ice_dcf_parent.c
> > > >
> > > > --
> > > > 2.25.1
> > >
> >
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
2020-03-13 17:05 ` Wang, Haiyue
@ 2020-03-13 17:47 ` Stillwell Jr, Paul M
2020-03-14 1:57 ` Wang, Haiyue
0 siblings, 1 reply; 94+ messages in thread
From: Stillwell Jr, Paul M @ 2020-03-13 17:47 UTC (permalink / raw)
To: Wang, Haiyue, dev, Ye, Xiaolong, Zhang, Qi Z, Yang, Qiming, Xing, Beilei
Cc: Zhao1, Wei, Yigit, Ferruh
OK, I looked at the code further and it seems like what you are doing is you are using the iavf PCI device ID instead of the PF device ID when the user says cap=dcf. This doesn't seem like the right thing to do. Why not modify the iavf code to support being the DCF? Or create a new PMD? You are calling iavf functions from within the ice PMD which seems wrong to me.
Paul
> -----Original Message-----
> From: Wang, Haiyue <haiyue.wang@intel.com>
> Sent: Friday, March 13, 2020 10:05 AM
> To: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>; dev@dpdk.org; Ye,
> Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>;
> Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> Cc: Zhao1, Wei <wei.zhao1@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
>
> Hi Paul,
>
> > -----Original Message-----
> > From: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>
> > Sent: Saturday, March 14, 2020 00:50
> > To: Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye, Xiaolong
> > <xiaolong.ye@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang,
> > Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> > Cc: Zhao1, Wei <wei.zhao1@intel.com>
> > Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> >
> > Hi Haiyue,
> >
> > This statement is confusing to me "But the flow setting is the ice PF
> > AdminQ message, so the DCF shares most of ice PMD flow control." What
> do you mean by "flow setting"?
> It is DPDP rte_flow API calling.
>
> > The way I understand DCF
> > working is that there is a trusted VF (the DCF) that is setting switch
> > rules for other VFs on the same PF. The mechanism for doing that is
> > the DCF sends a virtchnl message to the Linux kernel driver PF to
>
> DCF needs: 1). virtchnl message is handles by 'dpdk/drivers/common/iavf/',
> which is the original iavf base code.
>
> > add/delete a switch rule. None of this requires the ice PMD as far as
> > I can tell. This seems like a
>
> DCF needs: 2). add/delete a switch rule.
> rte_flow API -->
> 'dpdk/drivers/net/ice/ice_switch_filter.c/ice_generic_flow.c' (ice flow
> framework)
> |
> `--> 'dpdk/drivers/net/ice/base' ...
>
> So, put it under the ice PMD is the best way.
>
> > driver just like the iavf driver; the iavf driver is separate from the
> > ice PMD and it seems like DCF should also be separate.
> >
> > Paul
> >
> > > -----Original Message-----
> > > From: Wang, Haiyue <haiyue.wang@intel.com>
> > > Sent: Friday, March 13, 2020 9:25 AM
> > > To: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>;
> > > dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z
> > > <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> > > Beilei <beilei.xing@intel.com>
> > > Cc: Zhao1, Wei <wei.zhao1@intel.com>
> > > Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> > >
> > > Hi Paul,
> > >
> > > Yes, it's VF (VF hardware initialization like virtchnl). But the
> > > flow setting is the ice PF AdminQ message, so the DCF shares most of ice
> PMD flow control.
> > >
> > > BR,
> > > Haiyue
> > >
> > > > -----Original Message-----
> > > > From: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>
> > > > Sent: Saturday, March 14, 2020 00:19
> > > > To: Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye,
> > > > Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z
> > > > <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>;
> > > > Xing, Beilei <beilei.xing@intel.com>
> > > > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > > > <haiyue.wang@intel.com>
> > > > Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> > > >
> > > > I'm confused. Shouldn't the DCF be a separate driver since it is a
> > > > VF, not part of a PF? You are starting to combine PF/VF code and
> > > > I'm not sure if
> > > that is the correct way to go.
> > > >
> > > > Paul
> > > >
> > > > > -----Original Message-----
> > > > > From: dev <dev-bounces@dpdk.org> On Behalf Of Haiyue Wang
> > > > > Sent: Monday, March 9, 2020 11:50 PM
> > > > > To: dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang,
> > > > > Qi Z <qi.z.zhang@intel.com>; Yang, Qiming
> > > > > <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> > > > > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > > > > <haiyue.wang@intel.com>
> > > > > Subject: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> > > > >
> > > > > A DCF (Device Config Function) based approach is proposed where
> > > > > a device bound to the device's VF0 can act as a sole controlling
> > > > > entity to exercise advance functionality (such as switch, ACL)
> > > > > for rest of
> > > the VFs.
> > > > >
> > > > > The DCF works as a standalone PMD to support this function,
> > > > > which shares the ice PMD flow control core function and the iavf
> > > > > virtchnl mailbox core module.
> > > > >
> > > > > This patchset is based on:
> > > > > [1] https://patchwork.dpdk.org/cover/66417/ : update ice base
> > > > > code [2] https://patchwork.dpdk.org/cover/66472/ : iavf share
> > > > > code update
> > > > >
> > > > > Depends-on: series-8843
> > > > > Depends-on: series-8855
> > > > >
> > > > > v2:
> > > > > 1. update the iavf patchset link.
> > > > > 2. split more patches for making this work be more understandable
> > > > > 3. fix the log function usage, devargs checking from v1.
> > > > >
> > > > > Haiyue Wang (7):
> > > > > net/iavf: stop the PCI probe in DCF mode
> > > > > net/ice: add the DCF hardware initialization
> > > > > net/ice: initiate to acquire the DCF capability
> > > > > net/ice: handle the AdminQ command by DCF
> > > > > net/ice: export the DDP definition symbols
> > > > > net/ice: handle the PF initialization by DCF
> > > > > net/ice: get the VF hardware index in DCF
> > > > >
> > > > > doc/guides/nics/ice.rst | 47 ++
> > > > > doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> > > > > doc/guides/rel_notes/release_20_05.rst | 5 +
> > > > > drivers/common/Makefile | 1 +
> > > > > drivers/net/iavf/iavf_ethdev.c | 43 ++
> > > > > drivers/net/ice/Makefile | 6 +
> > > > > drivers/net/ice/ice_dcf.c | 651
> +++++++++++++++++++++++++
> > > > > drivers/net/ice/ice_dcf.h | 61 +++
> > > > > drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
> > > > > drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> > > > > drivers/net/ice/ice_dcf_parent.c | 344 +++++++++++++
> > > > > drivers/net/ice/ice_ethdev.c | 9 +-
> > > > > drivers/net/ice/ice_ethdev.h | 8 +
> > > > > drivers/net/ice/meson.build | 8 +-
> > > > > mk/rte.app.mk | 1 +
> > > > > 15 files changed, 1528 insertions(+), 10 deletions(-) create
> > > > > mode
> > > > > 100644 doc/guides/nics/img/ice_dcf.png create mode 100644
> > > > > drivers/net/ice/ice_dcf.c create mode 100644
> > > > > drivers/net/ice/ice_dcf.h create mode 100644
> > > > > drivers/net/ice/ice_dcf_ethdev.c create mode 100644
> > > > > drivers/net/ice/ice_dcf_ethdev.h create mode 100644
> > > > > drivers/net/ice/ice_dcf_parent.c
> > > > >
> > > > > --
> > > > > 2.25.1
> > > >
> > >
> >
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
2020-03-13 17:47 ` Stillwell Jr, Paul M
@ 2020-03-14 1:57 ` Wang, Haiyue
0 siblings, 0 replies; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-14 1:57 UTC (permalink / raw)
To: Stillwell Jr, Paul M, dev, Ye, Xiaolong, Zhang, Qi Z, Yang,
Qiming, Xing, Beilei
Cc: Zhao1, Wei, Yigit, Ferruh
> -----Original Message-----
> From: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>
> Sent: Saturday, March 14, 2020 01:48
> To: Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang,
> Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> Cc: Zhao1, Wei <wei.zhao1@intel.com>; Yigit, Ferruh <ferruh.yigit@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
>
> OK, I looked at the code further and it seems like what you are doing is you are using the iavf PCI
> device ID instead of the PF device ID when the user says cap=dcf. This doesn't seem like the right
> thing to do.
No, how can you get the PF device ID from the VF hardware ? ;-)
> Why not modify the iavf code to support being the DCF? Or create a new PMD? You are
> calling iavf functions from within the ice PMD which seems wrong to me.
No, you still can't get my point about the ice rte_flow framework. Please see Wei's next patch
https://patchwork.dpdk.org/patch/66621/ net/ice: enable switch flow on DCF
>
> Paul
>
> > -----Original Message-----
> > From: Wang, Haiyue <haiyue.wang@intel.com>
> > Sent: Friday, March 13, 2020 10:05 AM
> > To: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>; dev@dpdk.org; Ye,
> > Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>;
> > Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> > Cc: Zhao1, Wei <wei.zhao1@intel.com>
> > Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> >
> > Hi Paul,
> >
> > > -----Original Message-----
> > > From: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>
> > > Sent: Saturday, March 14, 2020 00:50
> > > To: Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye, Xiaolong
> > > <xiaolong.ye@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang,
> > > Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> > > Cc: Zhao1, Wei <wei.zhao1@intel.com>
> > > Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> > >
> > > Hi Haiyue,
> > >
> > > This statement is confusing to me "But the flow setting is the ice PF
> > > AdminQ message, so the DCF shares most of ice PMD flow control." What
> > do you mean by "flow setting"?
> > It is DPDP rte_flow API calling.
> >
> > > The way I understand DCF
> > > working is that there is a trusted VF (the DCF) that is setting switch
> > > rules for other VFs on the same PF. The mechanism for doing that is
> > > the DCF sends a virtchnl message to the Linux kernel driver PF to
> >
> > DCF needs: 1). virtchnl message is handles by 'dpdk/drivers/common/iavf/',
> > which is the original iavf base code.
> >
> > > add/delete a switch rule. None of this requires the ice PMD as far as
> > > I can tell. This seems like a
> >
> > DCF needs: 2). add/delete a switch rule.
> > rte_flow API -->
> > 'dpdk/drivers/net/ice/ice_switch_filter.c/ice_generic_flow.c' (ice flow
> > framework)
> > |
> > `--> 'dpdk/drivers/net/ice/base' ...
> >
> > So, put it under the ice PMD is the best way.
> >
> > > driver just like the iavf driver; the iavf driver is separate from the
> > > ice PMD and it seems like DCF should also be separate.
> > >
> > > Paul
> > >
> > > > -----Original Message-----
> > > > From: Wang, Haiyue <haiyue.wang@intel.com>
> > > > Sent: Friday, March 13, 2020 9:25 AM
> > > > To: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>;
> > > > dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z
> > > > <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> > > > Beilei <beilei.xing@intel.com>
> > > > Cc: Zhao1, Wei <wei.zhao1@intel.com>
> > > > Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> > > >
> > > > Hi Paul,
> > > >
> > > > Yes, it's VF (VF hardware initialization like virtchnl). But the
> > > > flow setting is the ice PF AdminQ message, so the DCF shares most of ice
> > PMD flow control.
> > > >
> > > > BR,
> > > > Haiyue
> > > >
> > > > > -----Original Message-----
> > > > > From: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>
> > > > > Sent: Saturday, March 14, 2020 00:19
> > > > > To: Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye,
> > > > > Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z
> > > > > <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>;
> > > > > Xing, Beilei <beilei.xing@intel.com>
> > > > > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > > > > <haiyue.wang@intel.com>
> > > > > Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> > > > >
> > > > > I'm confused. Shouldn't the DCF be a separate driver since it is a
> > > > > VF, not part of a PF? You are starting to combine PF/VF code and
> > > > > I'm not sure if
> > > > that is the correct way to go.
> > > > >
> > > > > Paul
> > > > >
> > > > > > -----Original Message-----
> > > > > > From: dev <dev-bounces@dpdk.org> On Behalf Of Haiyue Wang
> > > > > > Sent: Monday, March 9, 2020 11:50 PM
> > > > > > To: dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang,
> > > > > > Qi Z <qi.z.zhang@intel.com>; Yang, Qiming
> > > > > > <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> > > > > > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > > > > > <haiyue.wang@intel.com>
> > > > > > Subject: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> > > > > >
> > > > > > A DCF (Device Config Function) based approach is proposed where
> > > > > > a device bound to the device's VF0 can act as a sole controlling
> > > > > > entity to exercise advance functionality (such as switch, ACL)
> > > > > > for rest of
> > > > the VFs.
> > > > > >
> > > > > > The DCF works as a standalone PMD to support this function,
> > > > > > which shares the ice PMD flow control core function and the iavf
> > > > > > virtchnl mailbox core module.
> > > > > >
> > > > > > This patchset is based on:
> > > > > > [1] https://patchwork.dpdk.org/cover/66417/ : update ice base
> > > > > > code [2] https://patchwork.dpdk.org/cover/66472/ : iavf share
> > > > > > code update
> > > > > >
> > > > > > Depends-on: series-8843
> > > > > > Depends-on: series-8855
> > > > > >
> > > > > > v2:
> > > > > > 1. update the iavf patchset link.
> > > > > > 2. split more patches for making this work be more understandable
> > > > > > 3. fix the log function usage, devargs checking from v1.
> > > > > >
> > > > > > Haiyue Wang (7):
> > > > > > net/iavf: stop the PCI probe in DCF mode
> > > > > > net/ice: add the DCF hardware initialization
> > > > > > net/ice: initiate to acquire the DCF capability
> > > > > > net/ice: handle the AdminQ command by DCF
> > > > > > net/ice: export the DDP definition symbols
> > > > > > net/ice: handle the PF initialization by DCF
> > > > > > net/ice: get the VF hardware index in DCF
> > > > > >
> > > > > > doc/guides/nics/ice.rst | 47 ++
> > > > > > doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> > > > > > doc/guides/rel_notes/release_20_05.rst | 5 +
> > > > > > drivers/common/Makefile | 1 +
> > > > > > drivers/net/iavf/iavf_ethdev.c | 43 ++
> > > > > > drivers/net/ice/Makefile | 6 +
> > > > > > drivers/net/ice/ice_dcf.c | 651
> > +++++++++++++++++++++++++
> > > > > > drivers/net/ice/ice_dcf.h | 61 +++
> > > > > > drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
> > > > > > drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> > > > > > drivers/net/ice/ice_dcf_parent.c | 344 +++++++++++++
> > > > > > drivers/net/ice/ice_ethdev.c | 9 +-
> > > > > > drivers/net/ice/ice_ethdev.h | 8 +
> > > > > > drivers/net/ice/meson.build | 8 +-
> > > > > > mk/rte.app.mk | 1 +
> > > > > > 15 files changed, 1528 insertions(+), 10 deletions(-) create
> > > > > > mode
> > > > > > 100644 doc/guides/nics/img/ice_dcf.png create mode 100644
> > > > > > drivers/net/ice/ice_dcf.c create mode 100644
> > > > > > drivers/net/ice/ice_dcf.h create mode 100644
> > > > > > drivers/net/ice/ice_dcf_ethdev.c create mode 100644
> > > > > > drivers/net/ice/ice_dcf_ethdev.h create mode 100644
> > > > > > drivers/net/ice/ice_dcf_parent.c
> > > > > >
> > > > > > --
> > > > > > 2.25.1
> > > > >
> > > >
> > >
> >
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
2020-03-13 16:19 ` [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support Stillwell Jr, Paul M
2020-03-13 16:25 ` Wang, Haiyue
@ 2020-03-15 1:49 ` Zhang, Qi Z
2020-03-16 18:54 ` Stillwell Jr, Paul M
1 sibling, 1 reply; 94+ messages in thread
From: Zhang, Qi Z @ 2020-03-15 1:49 UTC (permalink / raw)
To: Stillwell Jr, Paul M, Wang, Haiyue, dev, Ye, Xiaolong, Yang,
Qiming, Xing, Beilei
Cc: Zhao1, Wei, Wang, Haiyue, Liang, Cunming, Wu, Jingjing
Hi Paul:
> -----Original Message-----
> From: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>
> Sent: Saturday, March 14, 2020 12:19 AM
> To: Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye, Xiaolong
> <xiaolong.ye@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang, Qiming
> <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> <haiyue.wang@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
>
> I'm confused. Shouldn't the DCF be a separate driver since it is a VF, not part
> of a PF? You are starting to combine PF/VF code and I'm not sure if that is
> the correct way to go.
From DPDK's view, DCF is NOT a VF driver, actually it behaves like a PF driver with control path only and it share most exist PF driver's API implementation ,
That's why we combined it with exist PF driver, so when the module driver/net/ice is compiled into a library, it can be probed as a PF driver or DCF base on device ID at runtime.
And the is not special in DPDK, for example, the module in driver/net/i40e can be probed as i40e pf driver or i40e vf driver.
DCF take SR-IOV's mailbox as a message channel to communicate with the backend kernel driver, so iavf virtual channel is reused here, so we also need to link iavf share code.
And I agree, its always better if we can separate 2 different things while decouple all the common code into a share library to avoid duplicate code copy (just like we did on iavf share code)
But in this case, a lot of code refectory is required , so far we just take the simple way, we may improve this in future.
Thanks
Qi
>
> Paul
>
> > -----Original Message-----
> > From: dev <dev-bounces@dpdk.org> On Behalf Of Haiyue Wang
> > Sent: Monday, March 9, 2020 11:50 PM
> > To: dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z
> > <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> > Beilei <beilei.xing@intel.com>
> > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > <haiyue.wang@intel.com>
> > Subject: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> >
> > A DCF (Device Config Function) based approach is proposed where a
> > device bound to the device's VF0 can act as a sole controlling entity
> > to exercise advance functionality (such as switch, ACL) for rest of the VFs.
> >
> > The DCF works as a standalone PMD to support this function, which
> > shares the ice PMD flow control core function and the iavf virtchnl
> > mailbox core module.
> >
> > This patchset is based on:
> > [1] https://patchwork.dpdk.org/cover/66417/ : update ice base code [2]
> > https://patchwork.dpdk.org/cover/66472/ : iavf share code update
> >
> > Depends-on: series-8843
> > Depends-on: series-8855
> >
> > v2:
> > 1. update the iavf patchset link.
> > 2. split more patches for making this work be more understandable
> > 3. fix the log function usage, devargs checking from v1.
> >
> > Haiyue Wang (7):
> > net/iavf: stop the PCI probe in DCF mode
> > net/ice: add the DCF hardware initialization
> > net/ice: initiate to acquire the DCF capability
> > net/ice: handle the AdminQ command by DCF
> > net/ice: export the DDP definition symbols
> > net/ice: handle the PF initialization by DCF
> > net/ice: get the VF hardware index in DCF
> >
> > doc/guides/nics/ice.rst | 47 ++
> > doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> > doc/guides/rel_notes/release_20_05.rst | 5 +
> > drivers/common/Makefile | 1 +
> > drivers/net/iavf/iavf_ethdev.c | 43 ++
> > drivers/net/ice/Makefile | 6 +
> > drivers/net/ice/ice_dcf.c | 651
> +++++++++++++++++++++++++
> > drivers/net/ice/ice_dcf.h | 61 +++
> > drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
> > drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> > drivers/net/ice/ice_dcf_parent.c | 344 +++++++++++++
> > drivers/net/ice/ice_ethdev.c | 9 +-
> > drivers/net/ice/ice_ethdev.h | 8 +
> > drivers/net/ice/meson.build | 8 +-
> > mk/rte.app.mk | 1 +
> > 15 files changed, 1528 insertions(+), 10 deletions(-) create mode
> > 100644 doc/guides/nics/img/ice_dcf.png create mode 100644
> > drivers/net/ice/ice_dcf.c create mode 100644
> > drivers/net/ice/ice_dcf.h create mode 100644
> > drivers/net/ice/ice_dcf_ethdev.c create mode 100644
> > drivers/net/ice/ice_dcf_ethdev.h create mode 100644
> > drivers/net/ice/ice_dcf_parent.c
> >
> > --
> > 2.25.1
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 6/7] net/ice: handle the PF initialization by DCF
2020-03-13 7:59 ` Ye Xiaolong
2020-03-13 8:03 ` Ye Xiaolong
@ 2020-03-16 4:52 ` Wang, Haiyue
1 sibling, 0 replies; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-16 4:52 UTC (permalink / raw)
To: Ye, Xiaolong; +Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei
> -----Original Message-----
> From: Ye, Xiaolong <xiaolong.ye@intel.com>
> Sent: Friday, March 13, 2020 16:00
> To: Wang, Haiyue <haiyue.wang@intel.com>
> Cc: dev@dpdk.org; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>
> Subject: Re: [PATCH v2 6/7] net/ice: handle the PF initialization by DCF
>
> On 03/10, Haiyue Wang wrote:
> >The DCF (Device Config Function) works at the user PF level, it can't
> >access the real PF hardware directly. So it will proxy the PF's AdminQ
> >command through DCF's mailbox.
> >
> >And the DCF is mainly used to control the flow setting of other VFs, so
> >it only needs to initialize some core functions about the flow .
> >
> >Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
> >---
> > drivers/net/ice/Makefile | 1 +
> > drivers/net/ice/ice_dcf.c | 7 +-
> > drivers/net/ice/ice_dcf.h | 3 +
> > drivers/net/ice/ice_dcf_ethdev.c | 10 +-
> > drivers/net/ice/ice_dcf_ethdev.h | 11 +-
> > drivers/net/ice/ice_dcf_parent.c | 263 +++++++++++++++++++++++++++++++
> > drivers/net/ice/meson.build | 3 +-
> > 7 files changed, 292 insertions(+), 6 deletions(-)
> > create mode 100644 drivers/net/ice/ice_dcf_parent.c
> >
> >diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
> >index f493c9ed7..3ecc72219 100644
> >--- a/drivers/net/ice/Makefile
> >+++ b/drivers/net/ice/Makefile
> >@@ -88,6 +88,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
> >
> > SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
> > SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
> >+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_parent.c
> >
> > # install this header file
> > SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
> >diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
> >index 24ed31f35..480c449f5 100644
> >--- a/drivers/net/ice/ice_dcf.c
> >+++ b/drivers/net/ice/ice_dcf.c
> >@@ -124,8 +124,13 @@ ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
> > }
> >
> > v_op = rte_le_to_cpu_32(info->desc.cookie_high);
> >- if (unlikely(v_op == VIRTCHNL_OP_EVENT))
> >+ if (unlikely(v_op == VIRTCHNL_OP_EVENT)) {
>
> Is this unlikely really needed?
>
Looks like 'unlikely' a little abuse. Will remove it in v3 ;-0
> >+ if (hw->vc_event_msg_cb != NULL)
> >+ hw->vc_event_msg_cb(hw,
> >+ info->msg_buf,
> >+ info->msg_len);
> > return;
> >+ }
> >
> > v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
> >
> >diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
> >index 99bd53b02..ecd6303a0 100644
> >--- a/drivers/net/ice/ice_dcf.h
> >+++ b/drivers/net/ice/ice_dcf.h
> >@@ -36,6 +36,9 @@ struct ice_dcf_hw {
> > rte_spinlock_t vc_cmd_send_lock;
> > rte_spinlock_t vc_cmd_queue_lock;
> > TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
> >+ void (*vc_event_msg_cb)(struct ice_dcf_hw *dcf_hw,
> >+ uint8_t *msg, uint16_t msglen);
> >+
> > uint8_t *arq_buf;
> >
> > struct virtchnl_version_info virtchnl_version;
> >diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
> >index 23f82a487..af94caeff 100644
> >--- a/drivers/net/ice/ice_dcf_ethdev.c
> >+++ b/drivers/net/ice/ice_dcf_ethdev.c
> >@@ -145,8 +145,8 @@ ice_dcf_dev_close(struct rte_eth_dev *dev)
> > dev->dev_ops = NULL;
> > dev->rx_pkt_burst = NULL;
> > dev->tx_pkt_burst = NULL;
> >- dev->data->mac_addrs = NULL;
> >
> >+ ice_dcf_uninit_parent_adapter(dev);
> > ice_dcf_uninit_hw(dev, &adapter->real_hw);
> > }
> >
> >@@ -225,13 +225,17 @@ ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
> >
> > eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
> >
> >+ adapter->real_hw.vc_event_msg_cb = ice_dcf_handle_pf_event_msg;
> > if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
> > PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
> > return -1;
> > }
> >
> >- rte_eth_random_addr(adapter->mac_addr.addr_bytes);
> >- eth_dev->data->mac_addrs = &adapter->mac_addr;
> >+ if (ice_dcf_init_parent_adapter(eth_dev) != 0) {
> >+ PMD_INIT_LOG(ERR, "Failed to init DCF parent adapter");
> >+ ice_dcf_uninit_hw(eth_dev, &adapter->real_hw);
> >+ return -1;
> >+ }
> >
> > return 0;
> > }
> >diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
> >index 0c34a0095..e60e808d8 100644
> >--- a/drivers/net/ice/ice_dcf_ethdev.h
> >+++ b/drivers/net/ice/ice_dcf_ethdev.h
> >@@ -5,6 +5,9 @@
> > #ifndef _ICE_DCF_ETHDEV_H_
> > #define _ICE_DCF_ETHDEV_H_
> >
> >+#include "base/ice_common.h"
> >+#include "base/ice_adminq_cmd.h"
> >+
> > #include "ice_ethdev.h"
> > #include "ice_dcf.h"
> >
> >@@ -15,10 +18,16 @@ struct ice_dcf_queue {
> > };
> >
> > struct ice_dcf_adapter {
> >+ struct ice_adapter parent; /* Must be first */
> >+
> > struct ice_dcf_hw real_hw;
> >- struct rte_ether_addr mac_addr;
>
> This one isn't needed at the first place.
>
> > struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
> > struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
> > };
> >
> >+void ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
> >+ uint8_t *msg, uint16_t msglen);
> >+int ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev);
> >+void ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev);
> >+
> > #endif /* _ICE_DCF_ETHDEV_H_ */
> >diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
> >new file mode 100644
> >index 000000000..4c3bb68b1
> >--- /dev/null
> >+++ b/drivers/net/ice/ice_dcf_parent.c
> >@@ -0,0 +1,263 @@
> >+/* SPDX-License-Identifier: BSD-3-Clause
> >+ * Copyright(c) 2020 Intel Corporation
> >+ */
> >+#include <sys/types.h>
> >+#include <sys/stat.h>
> >+#include <unistd.h>
> >+
> >+#include "ice_dcf_ethdev.h"
> >+
> >+void
> >+ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
> >+ uint8_t *msg, uint16_t msglen)
> >+{
> >+ struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
> >+
> >+ if (msglen < sizeof(struct virtchnl_pf_event)) {
> >+ PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen);
> >+ return;
> >+ }
> >+
> >+ switch (pf_msg->event) {
> >+ case VIRTCHNL_EVENT_RESET_IMPENDING:
> >+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
> >+ break;
> >+ case VIRTCHNL_EVENT_LINK_CHANGE:
> >+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
> >+ break;
> >+ case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
> >+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
> >+ break;
> >+ default:
> >+ PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
> >+ break;
> >+ }
> >+}
> >+
> >+static int
> >+ice_dcf_init_parent_hw(struct ice_hw *hw)
> >+{
> >+ struct ice_aqc_get_phy_caps_data *pcaps;
> >+ enum ice_status status;
> >+
> >+ status = ice_aq_get_fw_ver(hw, NULL);
> >+ if (status)
> >+ return status;
> >+
> >+ status = ice_get_caps(hw);
> >+ if (status)
> >+ return status;
> >+
> >+ hw->port_info = (struct ice_port_info *)
> >+ ice_malloc(hw, sizeof(*hw->port_info));
> >+ if (!hw->port_info)
> >+ return ICE_ERR_NO_MEMORY;
> >+
> >+ /* set the back pointer to HW */
> >+ hw->port_info->hw = hw;
> >+
> >+ /* Initialize port_info struct with switch configuration data */
> >+ status = ice_get_initial_sw_cfg(hw);
> >+ if (status)
> >+ goto err_unroll_alloc;
> >+
> >+ pcaps = (struct ice_aqc_get_phy_caps_data *)
> >+ ice_malloc(hw, sizeof(*pcaps));
> >+ if (!pcaps) {
> >+ status = ICE_ERR_NO_MEMORY;
> >+ goto err_unroll_alloc;
> >+ }
> >+
> >+ /* Initialize port_info struct with PHY capabilities */
> >+ status = ice_aq_get_phy_caps(hw->port_info, false,
> >+ ICE_AQC_REPORT_TOPO_CAP, pcaps, NULL);
> >+ ice_free(hw, pcaps);
> >+ if (status)
> >+ goto err_unroll_alloc;
> >+
> >+ /* Initialize port_info struct with link information */
> >+ status = ice_aq_get_link_info(hw->port_info, false, NULL, NULL);
> >+ if (status)
> >+ goto err_unroll_alloc;
> >+
> >+ status = ice_init_fltr_mgmt_struct(hw);
> >+ if (status)
> >+ goto err_unroll_alloc;
> >+
> >+ status = ice_init_hw_tbls(hw);
> >+ if (status)
> >+ goto err_unroll_fltr_mgmt_struct;
> >+
> >+ PMD_INIT_LOG(INFO,
> >+ "firmware %d.%d.%d api %d.%d.%d build 0x%08x",
> >+ hw->fw_maj_ver, hw->fw_min_ver, hw->fw_patch,
> >+ hw->api_maj_ver, hw->api_min_ver, hw->api_patch,
> >+ hw->fw_build);
> >+
> >+ return ICE_SUCCESS;
> >+
> >+err_unroll_fltr_mgmt_struct:
> >+ ice_cleanup_fltr_mgmt_struct(hw);
> >+err_unroll_alloc:
> >+ ice_free(hw, hw->port_info);
> >+ hw->port_info = NULL;
> >+
> >+ return status;
> >+}
> >+
> >+static void ice_dcf_uninit_parent_hw(struct ice_hw *hw)
> >+{
> >+ ice_cleanup_fltr_mgmt_struct(hw);
> >+
> >+ ice_free_seg(hw);
> >+ ice_free_hw_tbls(hw);
> >+
> >+ ice_free(hw, hw->port_info);
> >+ hw->port_info = NULL;
> >+
> >+ ice_clear_all_vsi_ctx(hw);
> >+}
> >+
> >+static int
> >+ice_dcf_request_pkg_name(struct ice_hw *hw, char *pkg_name)
> >+{
> >+ struct ice_dcf_adapter *dcf_adapter =
> >+ container_of(hw, struct ice_dcf_adapter, parent.hw);
> >+
> >+ /* TODO: check with DSN firstly by iAVF */
> >+ PMD_INIT_LOG(DEBUG,
> >+ "DCF VSI_ID = %u",
> >+ dcf_adapter->real_hw.vsi_id);
> >+
> >+ snprintf(pkg_name,
> >+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_UPDATES);
> >+ if (!access(pkg_name, 0))
> >+ return 0;
> >+
> >+ snprintf(pkg_name,
> >+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_DEFAULT);
> >+ if (!access(pkg_name, 0))
> >+ return 0;
> >+
> >+ return -1;
> >+}
> >+
> >+static int
> >+ice_dcf_load_pkg(struct ice_hw *hw)
> >+{
> >+ char pkg_name[ICE_MAX_PKG_FILENAME_SIZE];
> >+ uint8_t *pkg_buf;
> >+ uint32_t buf_len;
> >+ struct stat st;
> >+ FILE *fp;
> >+ int err;
> >+
> >+ if (ice_dcf_request_pkg_name(hw, pkg_name)) {
> >+ PMD_INIT_LOG(ERR, "failed to locate the package file");
>
> s/failed/Failed
>
Fixed in v3.
> >+ return -ENOENT;
> >+ }
> >+
> >+ PMD_INIT_LOG(DEBUG, "DDP package name: %s", pkg_name);
> >+
> >+ err = stat(pkg_name, &st);
> >+ if (err) {
> >+ PMD_INIT_LOG(ERR, "failed to get file status");
>
> s/failed/Failed
>
Fixed in v3.
> >+ return err;
> >+ }
> >+
> >+ buf_len = st.st_size;
> >+ pkg_buf = rte_malloc(NULL, buf_len, 0);
> >+ if (!pkg_buf) {
> >+ PMD_INIT_LOG(ERR, "failed to allocate buffer of size %u for package",
> >+ buf_len);
> >+ return -1;
> >+ }
> >+
> >+ fp = fopen(pkg_name, "rb");
> >+ if (!fp) {
> >+ PMD_INIT_LOG(ERR, "failed to open file: %s", pkg_name);
> >+ err = -1;
> >+ goto ret;
> >+ }
> >+
> >+ err = fread(pkg_buf, buf_len, 1, fp);
> >+ fclose(fp);
> >+ if (err != 1) {
> >+ PMD_INIT_LOG(ERR, "failed to read package data");
> >+ err = -1;
> >+ goto ret;
> >+ }
> >+
> >+ err = ice_copy_and_init_pkg(hw, pkg_buf, buf_len);
> >+ if (err)
> >+ PMD_INIT_LOG(ERR, "ice_copy_and_init_hw failed: %d", err);
> >+
> >+ret:
> >+ rte_free(pkg_buf);
> >+ return err;
> >+}
> >+
> >+int
> >+ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
> >+{
> >+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
> >+ struct ice_adapter *parent_adapter = &adapter->parent;
> >+ struct ice_hw *parent_hw = &parent_adapter->hw;
> >+ struct ice_dcf_hw *hw = &adapter->real_hw;
> >+ const struct rte_ether_addr *mac;
> >+ int err;
> >+
> >+ parent_adapter->eth_dev = eth_dev;
> >+ parent_adapter->pf.adapter = parent_adapter;
> >+ parent_adapter->pf.dev_data = eth_dev->data;
> >+ parent_hw->back = parent_adapter;
> >+ parent_hw->mac_type = ICE_MAC_GENERIC;
> >+ parent_hw->vendor_id = ICE_INTEL_VENDOR_ID;
> >+
> >+ ice_init_lock(&parent_hw->adminq.sq_lock);
> >+ ice_init_lock(&parent_hw->adminq.rq_lock);
> >+ parent_hw->aq_send_cmd_fn = ice_dcf_send_aq_cmd;
> >+ parent_hw->aq_send_cmd_param = &adapter->real_hw;
> >+ parent_hw->dcf_enabled = true;
> >+
> >+ err = ice_dcf_init_parent_hw(parent_hw);
> >+ if (err) {
> >+ PMD_INIT_LOG(ERR, "failed to init the DCF parent hardware with error %d",
> >+ err);
> >+ return err;
> >+ }
> >+
> >+ err = ice_dcf_load_pkg(parent_hw);
> >+ if (err) {
> >+ PMD_INIT_LOG(ERR, "failed to load package with error %d",
> >+ err);
> >+ goto uninit_hw;
> >+ }
> >+ parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
> >+
> >+ mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
> >+ if (rte_is_valid_assigned_ether_addr(mac))
> >+ rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
> >+ else
> >+ rte_eth_random_addr(parent_adapter->pf.dev_addr.addr_bytes);
> >+
> >+ eth_dev->data->mac_addrs = &parent_adapter->pf.dev_addr;
> >+
> >+ return 0;
> >+
> >+uninit_hw:
> >+ ice_dcf_uninit_parent_hw(parent_hw);
> >+ return err;
> >+}
> >+
> >+void
> >+ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
> >+{
> >+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
> >+ struct ice_adapter *parent_adapter = &adapter->parent;
> >+ struct ice_hw *parent_hw = &parent_adapter->hw;
> >+
> >+ eth_dev->data->mac_addrs = NULL;
> >+
> >+ ice_dcf_uninit_parent_hw(parent_hw);
> >+}
> >diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
> >index 0ba9668d1..7e9037f3b 100644
> >--- a/drivers/net/ice/meson.build
> >+++ b/drivers/net/ice/meson.build
> >@@ -38,6 +38,7 @@ if arch_subdir == 'x86'
> > endif
> >
> > sources += files('ice_dcf.c',
> >- 'ice_dcf_ethdev.c')
> >+ 'ice_dcf_ethdev.c',
> >+ 'ice_dcf_parent.c')
> >
> > install_headers('rte_pmd_ice.h')
> >--
> >2.25.1
> >
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v3 0/7] add Intel DCF PMD support
2020-03-09 14:14 [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support Haiyue Wang
` (5 preceding siblings ...)
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 0/7] " Haiyue Wang
@ 2020-03-16 5:52 ` Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
` (6 more replies)
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Haiyue Wang
` (2 subsequent siblings)
9 siblings, 7 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-16 5:52 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A DCF (Device Config Function) based approach is proposed where a device
bound to the device's VF0 can act as a sole controlling entity to exercise
advance functionality (such as switch, ACL) for rest of the VFs.
The DCF works as a standalone PMD to support this function, which shares the
ice PMD flow control core function and the iavf virtchnl mailbox core module.
This patchset is based on:
[1] https://patchwork.dpdk.org/cover/66417/ : update ice base code
[2] https://patchwork.dpdk.org/cover/66472/ : iavf share code update
Depends-on: series-8843
Depends-on: series-8855
v3:
1. Fixed the error log message format.
2. Fixed some memory allocation check.
3. Fixed some code style issue and commmit message description.
v2:
1. update the iavf patchset link.
2. split more patches for making this work be more understandable
3. fix the log function usage, devargs checking from v1.
Haiyue Wang (7):
net/iavf: stop the PCI probe in DCF mode
net/ice: add the DCF hardware initialization
net/ice: acquire and disable the DCF capability
net/ice: handle the AdminQ command by DCF
net/ice: export the DDP definition symbols
net/ice: handle the PF initialization by DCF
net/ice: get the VF hardware index in DCF
doc/guides/nics/ice.rst | 47 ++
doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
doc/guides/rel_notes/release_20_05.rst | 5 +
drivers/common/Makefile | 1 +
drivers/net/iavf/iavf_ethdev.c | 43 ++
drivers/net/ice/Makefile | 6 +
drivers/net/ice/ice_dcf.c | 652 +++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 61 +++
drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
drivers/net/ice/ice_dcf_ethdev.h | 33 ++
drivers/net/ice/ice_dcf_parent.c | 343 +++++++++++++
drivers/net/ice/ice_ethdev.c | 9 +-
drivers/net/ice/ice_ethdev.h | 8 +
drivers/net/ice/meson.build | 8 +-
mk/rte.app.mk | 1 +
15 files changed, 1528 insertions(+), 10 deletions(-)
create mode 100644 doc/guides/nics/img/ice_dcf.png
create mode 100644 drivers/net/ice/ice_dcf.c
create mode 100644 drivers/net/ice/ice_dcf.h
create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
create mode 100644 drivers/net/ice/ice_dcf_parent.c
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v3 1/7] net/iavf: stop the PCI probe in DCF mode
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 " Haiyue Wang
@ 2020-03-16 5:52 ` Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
` (5 subsequent siblings)
6 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-16 5:52 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A new DCF PMD will be introduced, which runs on Intel VF hardware, and
it is a pure software design to control the advance functionality (such
as switch, ACL) for rest of the VFs.
So if the DCF (Device Config Function) mode is specified by the devarg
'cap=dcf', then it will stop the PCI probe in the iavf PMD.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Reviewed-by: Xiaolong Ye <xiaolong.ye@intel.com>
---
drivers/net/iavf/iavf_ethdev.c | 43 ++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 34913f9c4..c0b95e169 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -1416,9 +1416,51 @@ iavf_dev_uninit(struct rte_eth_dev *dev)
return 0;
}
+static int
+iavf_dcf_cap_check_handler(__rte_unused const char *key,
+ const char *value, __rte_unused void *opaque)
+{
+ if (strcmp(value, "dcf"))
+ return -1;
+
+ return 0;
+}
+
+static int
+iavf_dcf_cap_selected(struct rte_devargs *devargs)
+{
+ struct rte_kvargs *kvlist;
+ const char *key = "cap";
+ int ret = 0;
+
+ if (devargs == NULL)
+ return 0;
+
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
+ if (kvlist == NULL)
+ return 0;
+
+ if (!rte_kvargs_count(kvlist, key))
+ goto exit;
+
+ /* dcf capability selected when there's a key-value pair: cap=dcf */
+ if (rte_kvargs_process(kvlist, key,
+ iavf_dcf_cap_check_handler, NULL) < 0)
+ goto exit;
+
+ ret = 1;
+
+exit:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
static int eth_iavf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
struct rte_pci_device *pci_dev)
{
+ if (iavf_dcf_cap_selected(pci_dev->device.devargs))
+ return 1;
+
return rte_eth_dev_pci_generic_probe(pci_dev,
sizeof(struct iavf_adapter), iavf_dev_init);
}
@@ -1439,6 +1481,7 @@ static struct rte_pci_driver rte_iavf_pmd = {
RTE_PMD_REGISTER_PCI(net_iavf, rte_iavf_pmd);
RTE_PMD_REGISTER_PCI_TABLE(net_iavf, pci_id_iavf_map);
RTE_PMD_REGISTER_KMOD_DEP(net_iavf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_iavf, "cap=dcf");
RTE_INIT(iavf_init_log)
{
iavf_logtype_init = rte_log_register("pmd.net.iavf.init");
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v3 2/7] net/ice: add the DCF hardware initialization
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 " Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
@ 2020-03-16 5:52 ` Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 3/7] net/ice: acquire and disable the DCF capability Haiyue Wang
` (4 subsequent siblings)
6 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-16 5:52 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
Introduce the DCF (Device Config Function) feature in the ice PMD, it
works as a standalone PMD which doesn't handle the packet Rx/Tx related
things. Its hardware entity is the VF.
Add the basic DCF hardware initialization, this is specified by devarg
'cap=dcf'.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
doc/guides/nics/ice.rst | 47 +++
doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
doc/guides/rel_notes/release_20_05.rst | 5 +
drivers/common/Makefile | 1 +
drivers/net/ice/Makefile | 5 +
drivers/net/ice/ice_dcf.c | 474 +++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 52 +++
drivers/net/ice/ice_dcf_ethdev.c | 317 +++++++++++++++++
drivers/net/ice/ice_dcf_ethdev.h | 24 ++
drivers/net/ice/meson.build | 7 +-
mk/rte.app.mk | 1 +
11 files changed, 931 insertions(+), 2 deletions(-)
create mode 100644 doc/guides/nics/img/ice_dcf.png
create mode 100644 drivers/net/ice/ice_dcf.c
create mode 100644 drivers/net/ice/ice_dcf.h
create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 8af32dabf..2639ae239 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -240,6 +240,53 @@ report a MDD event and drop the packets.
The APPs based on DPDK should avoid providing such packets.
+Device Config Function (DCF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section demonstrates ICE DCF PMD, which shares the core module with ICE
+PMD and iAVF PMD.
+
+A DCF (Device Config Function) PMD bounds to the device's trusted VF with ID 0,
+it can act as a sole controlling entity to exercise advance functionality (such
+as switch, ACL) for the rest VFs.
+
+The DCF PMD needs to advertise and acquire DCF capability which allows DCF to
+send AdminQ commands that it would like to execute over to the PF and receive
+responses for the same from PF.
+
+.. _figure_ice_dcf:
+
+.. figure:: img/ice_dcf.*
+
+ DCF Communication flow.
+
+#. Create the VFs::
+
+ echo 4 > /sys/bus/pci/devices/0000\:18\:00.0/sriov_numvfs
+
+#. Enable the VF0 trust on::
+
+ ip link set dev enp24s0f0 vf 0 trust on
+
+#. Bind the VF0, and run testpmd with 'cap=dcf' devarg::
+
+ testpmd -l 22-25 -n 4 -w 18:01.0,cap=dcf -- -i
+
+#. Monitor the VF2 interface network traffic::
+
+ tcpdump -e -nn -i enp24s1f2
+
+#. Create one flow to redirect the traffic to VF2 by DCF::
+
+ flow create 0 priority 0 ingress pattern eth / ipv4 src is 192.168.0.2 \
+ dst is 192.168.0.3 / end actions vf id 2 / end
+
+#. Send the packet, and it should be displayed on tcpdump::
+
+ sendp(Ether(src='3c:fd:fe:aa:bb:78', dst='00:00:00:01:02:03')/IP(src=' \
+ 192.168.0.2', dst="192.168.0.3")/TCP(flags='S')/Raw(load='XXXXXXXXXX'), \
+ iface="enp24s0f0", count=10)
+
Sample Application Notes
------------------------
diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
new file mode 100644
index 0000000000000000000000000000000000000000..540823c4a05e9ea9d558d233fea77016d1ae5df3
GIT binary patch
literal 39168
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
literal 0
HcmV?d00001
diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 000bbf501..f404ee7fd 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -62,6 +62,11 @@ New Features
* Added support for matching on IPv4 Time To Live and IPv6 Hop Limit.
+* **Updated the Intel ice driver.**
+
+ Updated the Intel ice driver with new features and improvements, including:
+
+ * Added support for DCF (Device Config Function) feature.
Removed Items
-------------
diff --git a/drivers/common/Makefile b/drivers/common/Makefile
index 96bd7ac6e..df2e840cf 100644
--- a/drivers/common/Makefile
+++ b/drivers/common/Makefile
@@ -31,6 +31,7 @@ DIRS-y += dpaax
endif
IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
ifneq (,$(findstring y,$(IAVF-y)))
DIRS-y += iavf
endif
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index e22c34287..f493c9ed7 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -11,9 +11,11 @@ LIB = librte_pmd_ice.a
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
+LDLIBS += -lrte_net -lrte_common_iavf
EXPORT_MAP := rte_pmd_ice_version.map
@@ -84,6 +86,9 @@ ifeq ($(CC_AVX2_SUPPORT), 1)
endif
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+
# install this header file
SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
new file mode 100644
index 000000000..0a99cceb1
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.c
@@ -0,0 +1,474 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include "ice_dcf.h"
+
+#define ICE_DCF_AQ_LEN 32
+#define ICE_DCF_AQ_BUF_SZ 4096
+
+#define ICE_DCF_ARQ_MAX_RETRIES 200
+#define ICE_DCF_ARQ_CHECK_TIME 2 /* msecs */
+
+#define ICE_DCF_VF_RES_BUF_SZ \
+ (sizeof(struct virtchnl_vf_resource) + \
+ IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource))
+
+static __rte_always_inline int
+ice_dcf_send_cmd_req_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+ uint8_t *req_msg, uint16_t req_msglen)
+{
+ return iavf_aq_send_msg_to_pf(&hw->avf, op, IAVF_SUCCESS,
+ req_msg, req_msglen, NULL);
+}
+
+static int
+ice_dcf_recv_cmd_rsp_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+ uint8_t *rsp_msgbuf, uint16_t rsp_buflen,
+ uint16_t *rsp_msglen)
+{
+ struct iavf_arq_event_info event;
+ enum virtchnl_ops v_op;
+ int i = 0;
+ int err;
+
+ event.buf_len = rsp_buflen;
+ event.msg_buf = rsp_msgbuf;
+
+ do {
+ err = iavf_clean_arq_element(&hw->avf, &event, NULL);
+ if (err != IAVF_SUCCESS)
+ goto again;
+
+ v_op = rte_le_to_cpu_32(event.desc.cookie_high);
+ if (v_op != op)
+ goto again;
+
+ if (rsp_msglen != NULL)
+ *rsp_msglen = event.msg_len;
+ return rte_le_to_cpu_32(event.desc.cookie_low);
+
+again:
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ return -EIO;
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_clear(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_REMOVE(&hw->vc_cmd_queue, cmd, next);
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline void
+ice_dcf_vc_cmd_set(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ cmd->v_ret = IAVF_ERR_NOT_READY;
+ cmd->rsp_msglen = 0;
+ cmd->pending = 1;
+
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_INSERT_TAIL(&hw->vc_cmd_queue, cmd, next);
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline int
+ice_dcf_vc_cmd_send(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ return iavf_aq_send_msg_to_pf(&hw->avf,
+ cmd->v_op, IAVF_SUCCESS,
+ cmd->req_msg, cmd->req_msglen, NULL);
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
+{
+ struct dcf_virtchnl_cmd *cmd;
+ enum virtchnl_ops v_op;
+ enum iavf_status v_ret;
+ uint16_t aq_op;
+
+ aq_op = rte_le_to_cpu_16(info->desc.opcode);
+ if (unlikely(aq_op != iavf_aqc_opc_send_msg_to_vf)) {
+ PMD_DRV_LOG(ERR,
+ "Request %u is not supported yet", aq_op);
+ return;
+ }
+
+ v_op = rte_le_to_cpu_32(info->desc.cookie_high);
+ if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+ return;
+
+ v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
+
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_FOREACH(cmd, &hw->vc_cmd_queue, next) {
+ if (cmd->v_op == v_op && cmd->pending) {
+ cmd->v_ret = v_ret;
+ cmd->rsp_msglen = RTE_MIN(info->msg_len,
+ cmd->rsp_buflen);
+ if (likely(cmd->rsp_msglen != 0))
+ rte_memcpy(cmd->rsp_msgbuf, info->msg_buf,
+ cmd->rsp_msglen);
+
+ /* prevent compiler reordering */
+ rte_compiler_barrier();
+ cmd->pending = 0;
+ break;
+ }
+ }
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static void
+ice_dcf_handle_virtchnl_msg(struct ice_dcf_hw *hw)
+{
+ struct iavf_arq_event_info info;
+ uint16_t pending = 1;
+ int ret;
+
+ info.buf_len = ICE_DCF_AQ_BUF_SZ;
+ info.msg_buf = hw->arq_buf;
+
+ while (pending) {
+ ret = iavf_clean_arq_element(&hw->avf, &info, &pending);
+ if (ret != IAVF_SUCCESS)
+ break;
+
+ ice_dcf_aq_cmd_handle(hw, &info);
+ }
+}
+
+static int
+ice_dcf_init_check_api_version(struct ice_dcf_hw *hw)
+{
+#define ICE_CPF_VIRTCHNL_VERSION_MAJOR_START 1
+#define ICE_CPF_VIRTCHNL_VERSION_MINOR_START 1
+ struct virtchnl_version_info version, *pver;
+ int err;
+
+ version.major = VIRTCHNL_VERSION_MAJOR;
+ version.minor = VIRTCHNL_VERSION_MINOR;
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_VERSION,
+ (uint8_t *)&version, sizeof(version));
+ if (err) {
+ PMD_INIT_LOG(ERR, "Failed to send OP_VERSION");
+ return err;
+ }
+
+ pver = &hw->virtchnl_version;
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_VERSION,
+ (uint8_t *)pver, sizeof(*pver), NULL);
+ if (err) {
+ PMD_INIT_LOG(ERR, "Failed to get response of OP_VERSION");
+ return -1;
+ }
+
+ PMD_INIT_LOG(DEBUG,
+ "Peer PF API version: %u.%u", pver->major, pver->minor);
+
+ if (pver->major < ICE_CPF_VIRTCHNL_VERSION_MAJOR_START ||
+ (pver->major == ICE_CPF_VIRTCHNL_VERSION_MAJOR_START &&
+ pver->minor < ICE_CPF_VIRTCHNL_VERSION_MINOR_START)) {
+ PMD_INIT_LOG(ERR,
+ "VIRTCHNL API version should not be lower than (%u.%u)",
+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START,
+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START);
+ return -1;
+ } else if (pver->major > VIRTCHNL_VERSION_MAJOR ||
+ (pver->major == VIRTCHNL_VERSION_MAJOR &&
+ pver->minor > VIRTCHNL_VERSION_MINOR)) {
+ PMD_INIT_LOG(ERR,
+ "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
+ pver->major, pver->minor,
+ VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
+ return -1;
+ }
+
+ PMD_INIT_LOG(DEBUG, "Peer is supported PF host");
+
+ return 0;
+}
+
+static int
+ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
+{
+ uint32_t caps;
+ int err, i;
+
+ caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+ VF_BASE_MODE_OFFLOADS;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+ (uint8_t *)&caps, sizeof(caps));
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to send msg OP_GET_VF_RESOURCE");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+ (uint8_t *)hw->vf_res,
+ ICE_DCF_VF_RES_BUF_SZ, NULL);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to get response of OP_GET_VF_RESOURCE");
+ return -1;
+ }
+
+ iavf_vf_parse_hw_config(&hw->avf, hw->vf_res);
+
+ hw->vsi_res = NULL;
+ for (i = 0; i < hw->vf_res->num_vsis; i++) {
+ if (hw->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
+ hw->vsi_res = &hw->vf_res->vsi_res[i];
+ }
+
+ if (!hw->vsi_res) {
+ PMD_DRV_LOG(ERR, "no LAN VSI found");
+ return -1;
+ }
+
+ hw->vsi_id = hw->vsi_res->vsi_id;
+ PMD_DRV_LOG(DEBUG, "VSI ID is %u", hw->vsi_id);
+
+ return 0;
+}
+
+static int
+ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
+{
+#define ICE_DCF_RESET_WAIT_CNT 50
+ struct iavf_hw *avf = &hw->avf;
+ int i, reset;
+
+ for (i = 0; i < ICE_DCF_RESET_WAIT_CNT; i++) {
+ reset = IAVF_READ_REG(avf, IAVF_VFGEN_RSTAT) &
+ IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
+ reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
+
+ if (reset == VIRTCHNL_VFR_VFACTIVE ||
+ reset == VIRTCHNL_VFR_COMPLETED)
+ break;
+
+ rte_delay_ms(20);
+ }
+
+ if (i >= ICE_DCF_RESET_WAIT_CNT)
+ return -1;
+
+ return 0;
+}
+
+static inline void
+ice_dcf_enable_irq0(struct ice_dcf_hw *hw)
+{
+ struct iavf_hw *avf = &hw->avf;
+
+ /* Enable admin queue interrupt trigger */
+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1,
+ IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+ IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+ IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+ IAVF_WRITE_FLUSH(avf);
+}
+
+static inline void
+ice_dcf_disable_irq0(struct ice_dcf_hw *hw)
+{
+ struct iavf_hw *avf = &hw->avf;
+
+ /* Disable all interrupt types */
+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1, 0);
+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+ IAVF_WRITE_FLUSH(avf);
+}
+
+static void
+ice_dcf_dev_interrupt_handler(void *param)
+{
+ struct ice_dcf_hw *hw = param;
+
+ ice_dcf_disable_irq0(hw);
+
+ ice_dcf_handle_virtchnl_msg(hw);
+
+ ice_dcf_enable_irq0(hw);
+}
+
+int
+ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+ struct dcf_virtchnl_cmd *cmd)
+{
+ int i = 0;
+ int err;
+
+ if ((cmd->req_msg && !cmd->req_msglen) ||
+ (!cmd->req_msg && cmd->req_msglen) ||
+ (cmd->rsp_msgbuf && !cmd->rsp_buflen) ||
+ (!cmd->rsp_msgbuf && cmd->rsp_buflen))
+ return -EINVAL;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_vc_cmd_set(hw, cmd);
+
+ err = ice_dcf_vc_cmd_send(hw, cmd);
+ if (err) {
+ PMD_DRV_LOG(ERR, "fail to send cmd %d", cmd->v_op);
+ goto ret;
+ }
+
+ do {
+ if (!cmd->pending)
+ break;
+
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ if (cmd->v_ret != IAVF_SUCCESS) {
+ err = -1;
+ PMD_DRV_LOG(ERR,
+ "No response (%d times) or return failure (%d) for cmd %d",
+ i, cmd->v_ret, cmd->v_op);
+ }
+
+ret:
+ ice_dcf_aq_cmd_clear(hw, cmd);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+ return err;
+}
+
+int
+ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ int ret;
+
+ hw->avf.hw_addr = pci_dev->mem_resource[0].addr;
+ hw->avf.back = hw;
+
+ hw->avf.bus.bus_id = pci_dev->addr.bus;
+ hw->avf.bus.device = pci_dev->addr.devid;
+ hw->avf.bus.func = pci_dev->addr.function;
+
+ hw->avf.device_id = pci_dev->id.device_id;
+ hw->avf.vendor_id = pci_dev->id.vendor_id;
+ hw->avf.subsystem_device_id = pci_dev->id.subsystem_device_id;
+ hw->avf.subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+
+ hw->avf.aq.num_arq_entries = ICE_DCF_AQ_LEN;
+ hw->avf.aq.num_asq_entries = ICE_DCF_AQ_LEN;
+ hw->avf.aq.arq_buf_size = ICE_DCF_AQ_BUF_SZ;
+ hw->avf.aq.asq_buf_size = ICE_DCF_AQ_BUF_SZ;
+
+ rte_spinlock_init(&hw->vc_cmd_send_lock);
+ rte_spinlock_init(&hw->vc_cmd_queue_lock);
+ TAILQ_INIT(&hw->vc_cmd_queue);
+
+ hw->arq_buf = rte_zmalloc("arq_buf", ICE_DCF_AQ_BUF_SZ, 0);
+ if (hw->arq_buf == NULL) {
+ PMD_INIT_LOG(ERR, "unable to allocate AdminQ buffer memory");
+ goto err;
+ }
+
+ ret = iavf_set_mac_type(&hw->avf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "set_mac_type failed: %d", ret);
+ goto err;
+ }
+
+ ret = ice_dcf_check_reset_done(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "VF is still resetting");
+ goto err;
+ }
+
+ ret = iavf_init_adminq(&hw->avf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "init_adminq failed: %d", ret);
+ goto err;
+ }
+
+ if (ice_dcf_init_check_api_version(hw)) {
+ PMD_INIT_LOG(ERR, "check_api version failed");
+ goto err_api;
+ }
+
+ hw->vf_res = rte_zmalloc("vf_res", ICE_DCF_VF_RES_BUF_SZ, 0);
+ if (hw->vf_res == NULL) {
+ PMD_INIT_LOG(ERR, "unable to allocate vf_res memory");
+ goto err_api;
+ }
+
+ if (ice_dcf_get_vf_resource(hw)) {
+ PMD_INIT_LOG(ERR, "Failed to get VF resource");
+ goto err_alloc;
+ }
+
+ rte_intr_callback_register(&pci_dev->intr_handle,
+ ice_dcf_dev_interrupt_handler, hw);
+ rte_intr_enable(&pci_dev->intr_handle);
+ ice_dcf_enable_irq0(hw);
+
+ return 0;
+
+err_alloc:
+ rte_free(hw->vf_res);
+err_api:
+ iavf_shutdown_adminq(&hw->avf);
+err:
+ rte_free(hw->arq_buf);
+
+ return -1;
+}
+
+void
+ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
+ ice_dcf_disable_irq0(hw);
+ rte_intr_disable(intr_handle);
+ rte_intr_callback_unregister(intr_handle,
+ ice_dcf_dev_interrupt_handler, hw);
+
+ iavf_shutdown_adminq(&hw->avf);
+
+ rte_free(hw->arq_buf);
+ rte_free(hw->vf_res);
+}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
new file mode 100644
index 000000000..f44c09db2
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_H_
+#define _ICE_DCF_H_
+
+#include <rte_ethdev_driver.h>
+
+#include <iavf_prototype.h>
+#include <iavf_adminq_cmd.h>
+#include <iavf_type.h>
+
+#include "ice_logs.h"
+
+struct dcf_virtchnl_cmd {
+ TAILQ_ENTRY(dcf_virtchnl_cmd) next;
+
+ enum virtchnl_ops v_op;
+ enum iavf_status v_ret;
+
+ uint16_t req_msglen;
+ uint8_t *req_msg;
+
+ uint16_t rsp_msglen;
+ uint16_t rsp_buflen;
+ uint8_t *rsp_msgbuf;
+
+ volatile int pending;
+};
+
+struct ice_dcf_hw {
+ struct iavf_hw avf;
+
+ rte_spinlock_t vc_cmd_send_lock;
+ rte_spinlock_t vc_cmd_queue_lock;
+ TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+ uint8_t *arq_buf;
+
+ struct virtchnl_version_info virtchnl_version;
+ struct virtchnl_vf_resource *vf_res; /* VF resource */
+ struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
+ uint16_t vsi_id;
+};
+
+int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+ struct dcf_virtchnl_cmd *cmd);
+
+int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+
+#endif /* _ICE_DCF_H_ */
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
new file mode 100644
index 000000000..23f82a487
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -0,0 +1,317 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <rte_interrupts.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_pci.h>
+#include <rte_kvargs.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include <iavf_devids.h>
+
+#include "ice_generic_flow.h"
+#include "ice_dcf_ethdev.h"
+
+static uint16_t
+ice_dcf_recv_pkts(__rte_unused void *rx_queue,
+ __rte_unused struct rte_mbuf **bufs,
+ __rte_unused uint16_t nb_pkts)
+{
+ return 0;
+}
+
+static uint16_t
+ice_dcf_xmit_pkts(__rte_unused void *tx_queue,
+ __rte_unused struct rte_mbuf **bufs,
+ __rte_unused uint16_t nb_pkts)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_start(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = ETH_LINK_UP;
+
+ return 0;
+}
+
+static void
+ice_dcf_dev_stop(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+ice_dcf_dev_configure(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_info_get(struct rte_eth_dev *dev,
+ struct rte_eth_dev_info *dev_info)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev_info->max_mac_addrs = 1;
+ dev_info->max_rx_pktlen = (uint32_t)-1;
+ dev_info->max_rx_queues = RTE_DIM(adapter->rxqs);
+ dev_info->max_tx_queues = RTE_DIM(adapter->txqs);
+
+ return 0;
+}
+
+static int
+ice_dcf_stats_get(__rte_unused struct rte_eth_dev *dev,
+ __rte_unused struct rte_eth_stats *igb_stats)
+{
+ return 0;
+}
+
+static int
+ice_dcf_stats_reset(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_disable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_enable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_disable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
+ enum rte_filter_type filter_type,
+ __rte_unused enum rte_filter_op filter_op,
+ __rte_unused void *arg)
+{
+ int ret = 0;
+
+ if (!dev)
+ return -EINVAL;
+
+ switch (filter_type) {
+ default:
+ PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+ filter_type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void
+ice_dcf_dev_close(struct rte_eth_dev *dev)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return;
+
+ dev->dev_ops = NULL;
+ dev->rx_pkt_burst = NULL;
+ dev->tx_pkt_burst = NULL;
+ dev->data->mac_addrs = NULL;
+
+ ice_dcf_uninit_hw(dev, &adapter->real_hw);
+}
+
+static void
+ice_dcf_queue_release(__rte_unused void *q)
+{
+}
+
+static int
+ice_dcf_link_update(__rte_unused struct rte_eth_dev *dev,
+ __rte_unused int wait_to_complete)
+{
+ return 0;
+}
+
+static int
+ice_dcf_rx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t rx_queue_id,
+ __rte_unused uint16_t nb_rx_desc,
+ __rte_unused unsigned int socket_id,
+ __rte_unused const struct rte_eth_rxconf *rx_conf,
+ __rte_unused struct rte_mempool *mb_pool)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev->data->rx_queues[rx_queue_id] = &adapter->rxqs[rx_queue_id];
+
+ return 0;
+}
+
+static int
+ice_dcf_tx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t tx_queue_id,
+ __rte_unused uint16_t nb_tx_desc,
+ __rte_unused unsigned int socket_id,
+ __rte_unused const struct rte_eth_txconf *tx_conf)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev->data->tx_queues[tx_queue_id] = &adapter->txqs[tx_queue_id];
+
+ return 0;
+}
+
+static const struct eth_dev_ops ice_dcf_eth_dev_ops = {
+ .dev_start = ice_dcf_dev_start,
+ .dev_stop = ice_dcf_dev_stop,
+ .dev_close = ice_dcf_dev_close,
+ .dev_configure = ice_dcf_dev_configure,
+ .dev_infos_get = ice_dcf_dev_info_get,
+ .rx_queue_setup = ice_dcf_rx_queue_setup,
+ .tx_queue_setup = ice_dcf_tx_queue_setup,
+ .rx_queue_release = ice_dcf_queue_release,
+ .tx_queue_release = ice_dcf_queue_release,
+ .link_update = ice_dcf_link_update,
+ .stats_get = ice_dcf_stats_get,
+ .stats_reset = ice_dcf_stats_reset,
+ .promiscuous_enable = ice_dcf_dev_promiscuous_enable,
+ .promiscuous_disable = ice_dcf_dev_promiscuous_disable,
+ .allmulticast_enable = ice_dcf_dev_allmulticast_enable,
+ .allmulticast_disable = ice_dcf_dev_allmulticast_disable,
+ .filter_ctrl = ice_dcf_dev_filter_ctrl,
+};
+
+static int
+ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+
+ eth_dev->dev_ops = &ice_dcf_eth_dev_ops;
+ eth_dev->rx_pkt_burst = ice_dcf_recv_pkts;
+ eth_dev->tx_pkt_burst = ice_dcf_xmit_pkts;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return 0;
+
+ eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
+ if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
+ PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
+ return -1;
+ }
+
+ rte_eth_random_addr(adapter->mac_addr.addr_bytes);
+ eth_dev->data->mac_addrs = &adapter->mac_addr;
+
+ return 0;
+}
+
+static int
+ice_dcf_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+ ice_dcf_dev_close(eth_dev);
+
+ return 0;
+}
+
+static int
+ice_dcf_cap_check_handler(__rte_unused const char *key,
+ const char *value, __rte_unused void *opaque)
+{
+ if (strcmp(value, "dcf"))
+ return -1;
+
+ return 0;
+}
+
+static int
+ice_dcf_cap_selected(struct rte_devargs *devargs)
+{
+ struct rte_kvargs *kvlist;
+ const char *key = "cap";
+ int ret = 0;
+
+ if (devargs == NULL)
+ return 0;
+
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
+ if (kvlist == NULL)
+ return 0;
+
+ if (!rte_kvargs_count(kvlist, key))
+ goto exit;
+
+ /* dcf capability selected when there's a key-value pair: cap=dcf */
+ if (rte_kvargs_process(kvlist, key,
+ ice_dcf_cap_check_handler, NULL) < 0)
+ goto exit;
+
+ ret = 1;
+
+exit:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
+static int eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
+ struct rte_pci_device *pci_dev)
+{
+ if (!ice_dcf_cap_selected(pci_dev->device.devargs))
+ return 1;
+
+ return rte_eth_dev_pci_generic_probe(pci_dev,
+ sizeof(struct ice_dcf_adapter),
+ ice_dcf_dev_init);
+}
+
+static int eth_ice_dcf_pci_remove(struct rte_pci_device *pci_dev)
+{
+ return rte_eth_dev_pci_generic_remove(pci_dev, ice_dcf_dev_uninit);
+}
+
+static const struct rte_pci_id pci_id_ice_dcf_map[] = {
+ { RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
+ { .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver rte_ice_dcf_pmd = {
+ .id_table = pci_id_ice_dcf_map,
+ .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+ .probe = eth_ice_dcf_pci_probe,
+ .remove = eth_ice_dcf_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_ice_dcf, rte_ice_dcf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_ice_dcf, pci_id_ice_dcf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ice_dcf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_ice_dcf, "cap=dcf");
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
new file mode 100644
index 000000000..0c34a0095
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_ETHDEV_H_
+#define _ICE_DCF_ETHDEV_H_
+
+#include "ice_ethdev.h"
+#include "ice_dcf.h"
+
+#define ICE_DCF_MAX_RINGS 1
+
+struct ice_dcf_queue {
+ uint64_t dummy;
+};
+
+struct ice_dcf_adapter {
+ struct ice_dcf_hw real_hw;
+ struct rte_ether_addr mac_addr;
+ struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
+ struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
+};
+
+#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index f9e897bbc..0ba9668d1 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -15,8 +15,8 @@ sources = files(
'ice_hash.c'
)
-deps += ['hash']
-includes += include_directories('base')
+deps += ['hash', 'net', 'common_iavf']
+includes += include_directories('base', '../../common/iavf')
if arch_subdir == 'x86'
sources += files('ice_rxtx_vec_sse.c')
@@ -37,4 +37,7 @@ if arch_subdir == 'x86'
endif
endif
+sources += files('ice_dcf.c',
+ 'ice_dcf_ethdev.c')
+
install_headers('rte_pmd_ice.h')
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index d295ca0a5..f3798a09f 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -185,6 +185,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += -lrte_pmd_i40e
_LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD) += -lrte_pmd_iavf
_LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += -lrte_pmd_ice
IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
ifeq ($(findstring y,$(IAVF-y)),y)
_LDLIBS-y += -lrte_common_iavf
endif
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v3 3/7] net/ice: acquire and disable the DCF capability
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 " Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
@ 2020-03-16 5:52 ` Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
` (3 subsequent siblings)
6 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-16 5:52 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
Since the DCF (Device Config Function) controls the flow setting of
other VFs by the mailbox with PF, for security, it needs to acquire
the DCF capability from PF when starts, and disable it when exits.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/ice/ice_dcf.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index 0a99cceb1..ab5bc7424 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -227,7 +227,7 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
int err, i;
caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
- VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED | VIRTCHNL_VF_CAP_DCF |
VF_BASE_MODE_OFFLOADS;
err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
@@ -264,6 +264,30 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
return 0;
}
+static int
+ice_dcf_mode_disable(struct ice_dcf_hw *hw)
+{
+ int err;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
+ NULL, 0);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_DISABLE");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
+ hw->arq_buf, ICE_DCF_AQ_BUF_SZ, NULL);
+ if (err) {
+ PMD_DRV_LOG(ERR,
+ "Fail to get response of OP_DCF_DISABLE %d",
+ err);
+ return -1;
+ }
+
+ return 0;
+}
+
static int
ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
{
@@ -467,6 +491,7 @@ ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
rte_intr_callback_unregister(intr_handle,
ice_dcf_dev_interrupt_handler, hw);
+ ice_dcf_mode_disable(hw);
iavf_shutdown_adminq(&hw->avf);
rte_free(hw->arq_buf);
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v3 4/7] net/ice: handle the AdminQ command by DCF
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 " Haiyue Wang
` (2 preceding siblings ...)
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 3/7] net/ice: acquire and disable the DCF capability Haiyue Wang
@ 2020-03-16 5:52 ` Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 5/7] net/ice: export the DDP definition symbols Haiyue Wang
` (2 subsequent siblings)
6 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-16 5:52 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) splits the AdminQ command into two
parts: one is the descriptor of AdminQ command, the other is the buffer
of AdminQ command (the descriptor has BUF flag set). When both of them
are received by the PF, the PF will handle them as one command.
And also, the filled descriptor and buffer of the response will be sent
back to DCF one by one through the virtchnl from PF.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/ice/ice_dcf.c | 65 +++++++++++++++++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 4 ++-
2 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index ab5bc7424..89bc14774 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -396,6 +396,71 @@ ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
return err;
}
+int
+ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
+ void *buf, uint16_t buf_size)
+{
+ struct dcf_virtchnl_cmd desc_cmd, buff_cmd;
+ struct ice_dcf_hw *hw = dcf_hw;
+ int err = 0;
+ int i = 0;
+
+ if ((buf && !buf_size) || (!buf && buf_size) ||
+ buf_size > ICE_DCF_AQ_BUF_SZ)
+ return -EINVAL;
+
+ desc_cmd.v_op = VIRTCHNL_OP_DCF_CMD_DESC;
+ desc_cmd.req_msglen = sizeof(*desc);
+ desc_cmd.req_msg = (uint8_t *)desc;
+ desc_cmd.rsp_buflen = sizeof(*desc);
+ desc_cmd.rsp_msgbuf = (uint8_t *)desc;
+
+ if (buf == NULL)
+ return ice_dcf_execute_virtchnl_cmd(hw, &desc_cmd);
+
+ desc->flags |= rte_cpu_to_le_16(ICE_AQ_FLAG_BUF);
+
+ buff_cmd.v_op = VIRTCHNL_OP_DCF_CMD_BUFF;
+ buff_cmd.req_msglen = buf_size;
+ buff_cmd.req_msg = buf;
+ buff_cmd.rsp_buflen = buf_size;
+ buff_cmd.rsp_msgbuf = buf;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_vc_cmd_set(hw, &desc_cmd);
+ ice_dcf_vc_cmd_set(hw, &buff_cmd);
+
+ if (ice_dcf_vc_cmd_send(hw, &desc_cmd) ||
+ ice_dcf_vc_cmd_send(hw, &buff_cmd)) {
+ err = -1;
+ PMD_DRV_LOG(ERR, "fail to send OP_DCF_CMD_DESC/BUFF");
+ goto ret;
+ }
+
+ do {
+ if ((!desc_cmd.pending && !buff_cmd.pending) ||
+ (!desc_cmd.pending && desc_cmd.v_ret != IAVF_SUCCESS) ||
+ (!buff_cmd.pending && buff_cmd.v_ret != IAVF_SUCCESS))
+ break;
+
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ if (desc_cmd.v_ret != IAVF_SUCCESS || buff_cmd.v_ret != IAVF_SUCCESS) {
+ err = -1;
+ PMD_DRV_LOG(ERR,
+ "No response (%d times) or return failure (desc: %d / buff: %d)",
+ i, desc_cmd.v_ret, buff_cmd.v_ret);
+ }
+
+ret:
+ ice_dcf_aq_cmd_clear(hw, &desc_cmd);
+ ice_dcf_aq_cmd_clear(hw, &buff_cmd);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+
+ return err;
+}
+
int
ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
{
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index f44c09db2..99bd53b02 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -11,6 +11,7 @@
#include <iavf_adminq_cmd.h>
#include <iavf_type.h>
+#include "base/ice_type.h"
#include "ice_logs.h"
struct dcf_virtchnl_cmd {
@@ -45,7 +46,8 @@ struct ice_dcf_hw {
int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
struct dcf_virtchnl_cmd *cmd);
-
+int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
+ void *buf, uint16_t buf_size);
int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v3 5/7] net/ice: export the DDP definition symbols
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 " Haiyue Wang
` (3 preceding siblings ...)
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
@ 2020-03-16 5:52 ` Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
6 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-16 5:52 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A new DCF PMD will be introduced, which runs on Intel VF hardware, and
it is a pure software design to control the advance functionality (such
as switch, ACL) for rest of the VFs.
The DCF (Device Config Function) feature shares the core functions of
the ICE PMD, like it needs to export the DDP definition symbols for the
new DCF PMD use.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Xiaolong Ye <xiaolong.ye@intel.com>
---
drivers/net/ice/ice_ethdev.c | 9 +--------
drivers/net/ice/ice_ethdev.h | 8 ++++++++
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c
index 3498a5075..3c38472de 100644
--- a/drivers/net/ice/ice_ethdev.c
+++ b/drivers/net/ice/ice_ethdev.c
@@ -67,15 +67,8 @@ static struct proto_xtr_ol_flag ice_proto_xtr_ol_flag_params[] = {
#define ICE_DFLT_OUTER_TAG_TYPE ICE_AQ_VSI_OUTER_TAG_VLAN_9100
-/* DDP package search path */
-#define ICE_PKG_FILE_DEFAULT "/lib/firmware/intel/ice/ddp/ice.pkg"
-#define ICE_PKG_FILE_UPDATES "/lib/firmware/updates/intel/ice/ddp/ice.pkg"
-#define ICE_PKG_FILE_SEARCH_PATH_DEFAULT "/lib/firmware/intel/ice/ddp/"
-#define ICE_PKG_FILE_SEARCH_PATH_UPDATES "/lib/firmware/updates/intel/ice/ddp/"
-
#define ICE_OS_DEFAULT_PKG_NAME "ICE OS Default Package"
#define ICE_COMMS_PKG_NAME "ICE COMMS Package"
-#define ICE_MAX_PKG_FILENAME_SIZE 256
#define ICE_MAX_RES_DESC_NUM 1024
int ice_logtype_init;
@@ -1833,7 +1826,7 @@ ice_pkg_file_search_path(struct rte_pci_device *pci_dev, char *pkg_file)
return 0;
}
-static enum ice_pkg_type
+enum ice_pkg_type
ice_load_pkg_type(struct ice_hw *hw)
{
enum ice_pkg_type package_type;
diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h
index da557a254..7b94a3c3e 100644
--- a/drivers/net/ice/ice_ethdev.h
+++ b/drivers/net/ice/ice_ethdev.h
@@ -42,6 +42,13 @@
#define ICE_MAX_PKT_TYPE 1024
+/* DDP package search path */
+#define ICE_PKG_FILE_DEFAULT "/lib/firmware/intel/ice/ddp/ice.pkg"
+#define ICE_PKG_FILE_UPDATES "/lib/firmware/updates/intel/ice/ddp/ice.pkg"
+#define ICE_PKG_FILE_SEARCH_PATH_DEFAULT "/lib/firmware/intel/ice/ddp/"
+#define ICE_PKG_FILE_SEARCH_PATH_UPDATES "/lib/firmware/updates/intel/ice/ddp/"
+#define ICE_MAX_PKG_FILENAME_SIZE 256
+
/**
* vlan_id is a 12 bit number.
* The VFTA array is actually a 4096 bit array, 128 of 32bit elements.
@@ -457,6 +464,7 @@ struct ice_vsi_vlan_pvid_info {
#define ICE_PF_TO_ETH_DEV(pf) \
(((struct ice_pf *)pf)->adapter->eth_dev)
+enum ice_pkg_type ice_load_pkg_type(struct ice_hw *hw);
struct ice_vsi *
ice_setup_vsi(struct ice_pf *pf, enum ice_vsi_type type);
int
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v3 6/7] net/ice: handle the PF initialization by DCF
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 " Haiyue Wang
` (4 preceding siblings ...)
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 5/7] net/ice: export the DDP definition symbols Haiyue Wang
@ 2020-03-16 5:52 ` Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
6 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-16 5:52 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) works at the user PF level, it can't
access the real PF hardware directly. So it will pass through the PF's
AdminQ command by the DCF's mailbox.
And the DCF is mainly used to control the flow setting of other VFs, so
it only needs to initialize some core functions related to the flow.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/ice/Makefile | 1 +
drivers/net/ice/ice_dcf.c | 7 +-
drivers/net/ice/ice_dcf.h | 3 +
drivers/net/ice/ice_dcf_ethdev.c | 10 +-
drivers/net/ice/ice_dcf_ethdev.h | 11 +-
drivers/net/ice/ice_dcf_parent.c | 263 +++++++++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
7 files changed, 292 insertions(+), 6 deletions(-)
create mode 100644 drivers/net/ice/ice_dcf_parent.c
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index f493c9ed7..3ecc72219 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -88,6 +88,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_parent.c
# install this header file
SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index 89bc14774..f32a7ffdb 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -124,8 +124,13 @@ ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
}
v_op = rte_le_to_cpu_32(info->desc.cookie_high);
- if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+ if (v_op == VIRTCHNL_OP_EVENT) {
+ if (hw->vc_event_msg_cb != NULL)
+ hw->vc_event_msg_cb(hw,
+ info->msg_buf,
+ info->msg_len);
return;
+ }
v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index 99bd53b02..ecd6303a0 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -36,6 +36,9 @@ struct ice_dcf_hw {
rte_spinlock_t vc_cmd_send_lock;
rte_spinlock_t vc_cmd_queue_lock;
TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+ void (*vc_event_msg_cb)(struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen);
+
uint8_t *arq_buf;
struct virtchnl_version_info virtchnl_version;
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
index 23f82a487..af94caeff 100644
--- a/drivers/net/ice/ice_dcf_ethdev.c
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -145,8 +145,8 @@ ice_dcf_dev_close(struct rte_eth_dev *dev)
dev->dev_ops = NULL;
dev->rx_pkt_burst = NULL;
dev->tx_pkt_burst = NULL;
- dev->data->mac_addrs = NULL;
+ ice_dcf_uninit_parent_adapter(dev);
ice_dcf_uninit_hw(dev, &adapter->real_hw);
}
@@ -225,13 +225,17 @@ ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+ adapter->real_hw.vc_event_msg_cb = ice_dcf_handle_pf_event_msg;
if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
return -1;
}
- rte_eth_random_addr(adapter->mac_addr.addr_bytes);
- eth_dev->data->mac_addrs = &adapter->mac_addr;
+ if (ice_dcf_init_parent_adapter(eth_dev) != 0) {
+ PMD_INIT_LOG(ERR, "Failed to init DCF parent adapter");
+ ice_dcf_uninit_hw(eth_dev, &adapter->real_hw);
+ return -1;
+ }
return 0;
}
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
index 0c34a0095..e60e808d8 100644
--- a/drivers/net/ice/ice_dcf_ethdev.h
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -5,6 +5,9 @@
#ifndef _ICE_DCF_ETHDEV_H_
#define _ICE_DCF_ETHDEV_H_
+#include "base/ice_common.h"
+#include "base/ice_adminq_cmd.h"
+
#include "ice_ethdev.h"
#include "ice_dcf.h"
@@ -15,10 +18,16 @@ struct ice_dcf_queue {
};
struct ice_dcf_adapter {
+ struct ice_adapter parent; /* Must be first */
+
struct ice_dcf_hw real_hw;
- struct rte_ether_addr mac_addr;
struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
};
+void ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen);
+int ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev);
+void ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev);
+
#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
new file mode 100644
index 000000000..138838a73
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_parent.c
@@ -0,0 +1,263 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "ice_dcf_ethdev.h"
+
+void
+ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen)
+{
+ struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
+
+ if (msglen < sizeof(struct virtchnl_pf_event)) {
+ PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen);
+ return;
+ }
+
+ switch (pf_msg->event) {
+ case VIRTCHNL_EVENT_RESET_IMPENDING:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
+ break;
+ case VIRTCHNL_EVENT_LINK_CHANGE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
+ break;
+ case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
+ break;
+ }
+}
+
+static int
+ice_dcf_init_parent_hw(struct ice_hw *hw)
+{
+ struct ice_aqc_get_phy_caps_data *pcaps;
+ enum ice_status status;
+
+ status = ice_aq_get_fw_ver(hw, NULL);
+ if (status)
+ return status;
+
+ status = ice_get_caps(hw);
+ if (status)
+ return status;
+
+ hw->port_info = (struct ice_port_info *)
+ ice_malloc(hw, sizeof(*hw->port_info));
+ if (!hw->port_info)
+ return ICE_ERR_NO_MEMORY;
+
+ /* set the back pointer to HW */
+ hw->port_info->hw = hw;
+
+ /* Initialize port_info struct with switch configuration data */
+ status = ice_get_initial_sw_cfg(hw);
+ if (status)
+ goto err_unroll_alloc;
+
+ pcaps = (struct ice_aqc_get_phy_caps_data *)
+ ice_malloc(hw, sizeof(*pcaps));
+ if (!pcaps) {
+ status = ICE_ERR_NO_MEMORY;
+ goto err_unroll_alloc;
+ }
+
+ /* Initialize port_info struct with PHY capabilities */
+ status = ice_aq_get_phy_caps(hw->port_info, false,
+ ICE_AQC_REPORT_TOPO_CAP, pcaps, NULL);
+ ice_free(hw, pcaps);
+ if (status)
+ goto err_unroll_alloc;
+
+ /* Initialize port_info struct with link information */
+ status = ice_aq_get_link_info(hw->port_info, false, NULL, NULL);
+ if (status)
+ goto err_unroll_alloc;
+
+ status = ice_init_fltr_mgmt_struct(hw);
+ if (status)
+ goto err_unroll_alloc;
+
+ status = ice_init_hw_tbls(hw);
+ if (status)
+ goto err_unroll_fltr_mgmt_struct;
+
+ PMD_INIT_LOG(INFO,
+ "firmware %d.%d.%d api %d.%d.%d build 0x%08x",
+ hw->fw_maj_ver, hw->fw_min_ver, hw->fw_patch,
+ hw->api_maj_ver, hw->api_min_ver, hw->api_patch,
+ hw->fw_build);
+
+ return ICE_SUCCESS;
+
+err_unroll_fltr_mgmt_struct:
+ ice_cleanup_fltr_mgmt_struct(hw);
+err_unroll_alloc:
+ ice_free(hw, hw->port_info);
+ hw->port_info = NULL;
+
+ return status;
+}
+
+static void ice_dcf_uninit_parent_hw(struct ice_hw *hw)
+{
+ ice_cleanup_fltr_mgmt_struct(hw);
+
+ ice_free_seg(hw);
+ ice_free_hw_tbls(hw);
+
+ ice_free(hw, hw->port_info);
+ hw->port_info = NULL;
+
+ ice_clear_all_vsi_ctx(hw);
+}
+
+static int
+ice_dcf_request_pkg_name(struct ice_hw *hw, char *pkg_name)
+{
+ struct ice_dcf_adapter *dcf_adapter =
+ container_of(hw, struct ice_dcf_adapter, parent.hw);
+
+ /* TODO: check with DSN firstly by iAVF */
+ PMD_INIT_LOG(DEBUG,
+ "DCF VSI_ID = %u",
+ dcf_adapter->real_hw.vsi_id);
+
+ snprintf(pkg_name,
+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_UPDATES);
+ if (!access(pkg_name, 0))
+ return 0;
+
+ snprintf(pkg_name,
+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_DEFAULT);
+ if (!access(pkg_name, 0))
+ return 0;
+
+ return -1;
+}
+
+static int
+ice_dcf_load_pkg(struct ice_hw *hw)
+{
+ char pkg_name[ICE_MAX_PKG_FILENAME_SIZE];
+ uint8_t *pkg_buf;
+ uint32_t buf_len;
+ struct stat st;
+ FILE *fp;
+ int err;
+
+ if (ice_dcf_request_pkg_name(hw, pkg_name)) {
+ PMD_INIT_LOG(ERR, "Failed to locate the package file");
+ return -ENOENT;
+ }
+
+ PMD_INIT_LOG(DEBUG, "DDP package name: %s", pkg_name);
+
+ err = stat(pkg_name, &st);
+ if (err) {
+ PMD_INIT_LOG(ERR, "Failed to get file status");
+ return err;
+ }
+
+ buf_len = st.st_size;
+ pkg_buf = rte_malloc(NULL, buf_len, 0);
+ if (!pkg_buf) {
+ PMD_INIT_LOG(ERR, "failed to allocate buffer of size %u for package",
+ buf_len);
+ return -1;
+ }
+
+ fp = fopen(pkg_name, "rb");
+ if (!fp) {
+ PMD_INIT_LOG(ERR, "failed to open file: %s", pkg_name);
+ err = -1;
+ goto ret;
+ }
+
+ err = fread(pkg_buf, buf_len, 1, fp);
+ fclose(fp);
+ if (err != 1) {
+ PMD_INIT_LOG(ERR, "failed to read package data");
+ err = -1;
+ goto ret;
+ }
+
+ err = ice_copy_and_init_pkg(hw, pkg_buf, buf_len);
+ if (err)
+ PMD_INIT_LOG(ERR, "ice_copy_and_init_hw failed: %d", err);
+
+ret:
+ rte_free(pkg_buf);
+ return err;
+}
+
+int
+ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+ struct ice_adapter *parent_adapter = &adapter->parent;
+ struct ice_hw *parent_hw = &parent_adapter->hw;
+ struct ice_dcf_hw *hw = &adapter->real_hw;
+ const struct rte_ether_addr *mac;
+ int err;
+
+ parent_adapter->eth_dev = eth_dev;
+ parent_adapter->pf.adapter = parent_adapter;
+ parent_adapter->pf.dev_data = eth_dev->data;
+ parent_hw->back = parent_adapter;
+ parent_hw->mac_type = ICE_MAC_GENERIC;
+ parent_hw->vendor_id = ICE_INTEL_VENDOR_ID;
+
+ ice_init_lock(&parent_hw->adminq.sq_lock);
+ ice_init_lock(&parent_hw->adminq.rq_lock);
+ parent_hw->aq_send_cmd_fn = ice_dcf_send_aq_cmd;
+ parent_hw->aq_send_cmd_param = &adapter->real_hw;
+ parent_hw->dcf_enabled = true;
+
+ err = ice_dcf_init_parent_hw(parent_hw);
+ if (err) {
+ PMD_INIT_LOG(ERR, "failed to init the DCF parent hardware with error %d",
+ err);
+ return err;
+ }
+
+ err = ice_dcf_load_pkg(parent_hw);
+ if (err) {
+ PMD_INIT_LOG(ERR, "failed to load package with error %d",
+ err);
+ goto uninit_hw;
+ }
+ parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
+
+ mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
+ if (rte_is_valid_assigned_ether_addr(mac))
+ rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
+ else
+ rte_eth_random_addr(parent_adapter->pf.dev_addr.addr_bytes);
+
+ eth_dev->data->mac_addrs = &parent_adapter->pf.dev_addr;
+
+ return 0;
+
+uninit_hw:
+ ice_dcf_uninit_parent_hw(parent_hw);
+ return err;
+}
+
+void
+ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+ struct ice_adapter *parent_adapter = &adapter->parent;
+ struct ice_hw *parent_hw = &parent_adapter->hw;
+
+ eth_dev->data->mac_addrs = NULL;
+
+ ice_dcf_uninit_parent_hw(parent_hw);
+}
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index 0ba9668d1..7e9037f3b 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -38,6 +38,7 @@ if arch_subdir == 'x86'
endif
sources += files('ice_dcf.c',
- 'ice_dcf_ethdev.c')
+ 'ice_dcf_ethdev.c',
+ 'ice_dcf_parent.c')
install_headers('rte_pmd_ice.h')
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v3 7/7] net/ice: get the VF hardware index in DCF
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 " Haiyue Wang
` (5 preceding siblings ...)
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
@ 2020-03-16 5:52 ` Haiyue Wang
6 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-16 5:52 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) needs the hardware index of the VFs to
control the flow setting. And also if the VF resets, the index may be
changed, so it should handle this in VF reset event.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/ice/ice_dcf.c | 87 +++++++++++++++++++++++++++++++-
drivers/net/ice/ice_dcf.h | 4 ++
drivers/net/ice/ice_dcf_parent.c | 82 +++++++++++++++++++++++++++++-
3 files changed, 170 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index f32a7ffdb..88c905191 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -269,6 +269,65 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
return 0;
}
+static int
+ice_dcf_get_vf_vsi_map(struct ice_dcf_hw *hw)
+{
+ struct virtchnl_dcf_vsi_map *vsi_map;
+ uint32_t valid_msg_len;
+ uint16_t len;
+ int err;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
+ NULL, 0);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to send msg OP_DCF_GET_VSI_MAP");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
+ hw->arq_buf, ICE_DCF_AQ_BUF_SZ,
+ &len);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to get response of OP_DCF_GET_VSI_MAP");
+ return err;
+ }
+
+ vsi_map = (struct virtchnl_dcf_vsi_map *)hw->arq_buf;
+ valid_msg_len = (vsi_map->num_vfs - 1) * sizeof(vsi_map->vf_vsi[0]) +
+ sizeof(*vsi_map);
+ if (len != valid_msg_len) {
+ PMD_DRV_LOG(ERR, "invalid vf vsi map response with length %u",
+ len);
+ return -EINVAL;
+ }
+
+ if (hw->num_vfs != 0 && hw->num_vfs != vsi_map->num_vfs) {
+ PMD_DRV_LOG(ERR, "The number VSI map (%u) doesn't match the number of VFs (%u)",
+ vsi_map->num_vfs, hw->num_vfs);
+ return -EINVAL;
+ }
+
+ len = vsi_map->num_vfs * sizeof(vsi_map->vf_vsi[0]);
+
+ if (!hw->vf_vsi_map) {
+ hw->vf_vsi_map = rte_zmalloc("vf_vsi_ctx", len, 0);
+ if (!hw->vf_vsi_map) {
+ PMD_DRV_LOG(ERR, "Failed to alloc memory for VSI context");
+ return -ENOMEM;
+ }
+
+ hw->num_vfs = vsi_map->num_vfs;
+ }
+
+ if (!memcmp(hw->vf_vsi_map, vsi_map->vf_vsi, len)) {
+ PMD_DRV_LOG(DEBUG, "VF VSI map doesn't change");
+ return 1;
+ }
+
+ rte_memcpy(hw->vf_vsi_map, vsi_map->vf_vsi, len);
+ return 0;
+}
+
static int
ice_dcf_mode_disable(struct ice_dcf_hw *hw)
{
@@ -277,7 +336,7 @@ ice_dcf_mode_disable(struct ice_dcf_hw *hw)
err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
NULL, 0);
if (err) {
- PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_DISABLE");
+ PMD_DRV_LOG(ERR, "Failed to send msg OP_DCF_DISABLE");
return err;
}
@@ -285,7 +344,7 @@ ice_dcf_mode_disable(struct ice_dcf_hw *hw)
hw->arq_buf, ICE_DCF_AQ_BUF_SZ, NULL);
if (err) {
PMD_DRV_LOG(ERR,
- "Fail to get response of OP_DCF_DISABLE %d",
+ "Failed to get response of OP_DCF_DISABLE %d",
err);
return -1;
}
@@ -466,6 +525,23 @@ ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
return err;
}
+int
+ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw)
+{
+ int err = 0;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_disable_irq0(hw);
+
+ if (ice_dcf_get_vf_resource(hw) || ice_dcf_get_vf_vsi_map(hw))
+ err = -1;
+
+ ice_dcf_enable_irq0(hw);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+
+ return err;
+}
+
int
ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
{
@@ -533,6 +609,12 @@ ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
goto err_alloc;
}
+ if (ice_dcf_get_vf_vsi_map(hw) < 0) {
+ PMD_INIT_LOG(ERR, "Failed to get VF VSI map");
+ ice_dcf_mode_disable(hw);
+ goto err_alloc;
+ }
+
rte_intr_callback_register(&pci_dev->intr_handle,
ice_dcf_dev_interrupt_handler, hw);
rte_intr_enable(&pci_dev->intr_handle);
@@ -565,5 +647,6 @@ ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
iavf_shutdown_adminq(&hw->avf);
rte_free(hw->arq_buf);
+ rte_free(hw->vf_vsi_map);
rte_free(hw->vf_res);
}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index ecd6303a0..12bef4a2a 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -41,6 +41,9 @@ struct ice_dcf_hw {
uint8_t *arq_buf;
+ uint16_t num_vfs;
+ uint16_t *vf_vsi_map;
+
struct virtchnl_version_info virtchnl_version;
struct virtchnl_vf_resource *vf_res; /* VF resource */
struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
@@ -51,6 +54,7 @@ int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
struct dcf_virtchnl_cmd *cmd);
int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
void *buf, uint16_t buf_size);
+int ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw);
int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
index 138838a73..df93509b7 100644
--- a/drivers/net/ice/ice_dcf_parent.c
+++ b/drivers/net/ice/ice_dcf_parent.c
@@ -5,10 +5,76 @@
#include <sys/stat.h>
#include <unistd.h>
+#include <rte_alarm.h>
+
#include "ice_dcf_ethdev.h"
+#define ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL 100000 /* us */
+
+static __rte_always_inline void
+ice_dcf_update_vsi_ctx(struct ice_hw *hw, uint16_t vsi_handle,
+ uint16_t vsi_map)
+{
+ struct ice_vsi_ctx *vsi_ctx;
+
+ if (unlikely(vsi_handle >= ICE_MAX_VSI)) {
+ PMD_DRV_LOG(ERR, "Invalid vsi handle %u", vsi_handle);
+ return;
+ }
+
+ vsi_ctx = hw->vsi_ctx[vsi_handle];
+
+ if (vsi_map & VIRTCHNL_DCF_VF_VSI_VALID) {
+ if (!vsi_ctx) {
+ vsi_ctx = ice_malloc(hw, sizeof(*vsi_ctx));
+ if (!vsi_ctx) {
+ PMD_DRV_LOG(ERR, "No memory for vsi context %u",
+ vsi_handle);
+ return;
+ }
+ }
+
+ vsi_ctx->vsi_num = (vsi_map & VIRTCHNL_DCF_VF_VSI_ID_M) >>
+ VIRTCHNL_DCF_VF_VSI_ID_S;
+ hw->vsi_ctx[vsi_handle] = vsi_ctx;
+
+ PMD_DRV_LOG(DEBUG, "VF%u is assigned with vsi number %u",
+ vsi_handle, vsi_ctx->vsi_num);
+ } else {
+ hw->vsi_ctx[vsi_handle] = NULL;
+
+ ice_free(hw, vsi_ctx);
+
+ PMD_DRV_LOG(NOTICE, "VF%u is disabled", vsi_handle);
+ }
+}
+
+static void
+ice_dcf_update_vf_vsi_map(struct ice_hw *hw, uint16_t num_vfs,
+ uint16_t *vf_vsi_map)
+{
+ uint16_t vf_id;
+
+ for (vf_id = 0; vf_id < num_vfs; vf_id++)
+ ice_dcf_update_vsi_ctx(hw, vf_id, vf_vsi_map[vf_id]);
+}
+
+static void
+ice_dcf_vsi_update_service_handler(void *param)
+{
+ struct ice_dcf_hw *hw = param;
+
+ if (!ice_dcf_handle_vsi_update_event(hw)) {
+ struct ice_dcf_adapter *dcf_ad =
+ container_of(hw, struct ice_dcf_adapter, real_hw);
+
+ ice_dcf_update_vf_vsi_map(&dcf_ad->parent.hw,
+ hw->num_vfs, hw->vf_vsi_map);
+ }
+}
+
void
-ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
+ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
uint8_t *msg, uint16_t msglen)
{
struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
@@ -21,6 +87,8 @@ ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
switch (pf_msg->event) {
case VIRTCHNL_EVENT_RESET_IMPENDING:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
+ rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL,
+ ice_dcf_vsi_update_service_handler, dcf_hw);
break;
case VIRTCHNL_EVENT_LINK_CHANGE:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
@@ -28,6 +96,13 @@ ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
break;
+ case VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE event : VF%u with VSI num %u",
+ pf_msg->event_data.vf_vsi_map.vf_id,
+ pf_msg->event_data.vf_vsi_map.vsi_id);
+ rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL,
+ ice_dcf_vsi_update_service_handler, dcf_hw);
+ break;
default:
PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
break;
@@ -235,6 +310,8 @@ ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
}
parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
+ ice_dcf_update_vf_vsi_map(parent_hw, hw->num_vfs, hw->vf_vsi_map);
+
mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
if (rte_is_valid_assigned_ether_addr(mac))
rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
@@ -259,5 +336,8 @@ ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
eth_dev->data->mac_addrs = NULL;
+ rte_eal_alarm_cancel(ice_dcf_vsi_update_service_handler,
+ &adapter->real_hw);
+
ice_dcf_uninit_parent_hw(parent_hw);
}
--
2.25.1
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 7/7] net/ice: get the VF hardware index in DCF
2020-03-13 7:01 ` Ye Xiaolong
@ 2020-03-16 5:58 ` Wang, Haiyue
0 siblings, 0 replies; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-16 5:58 UTC (permalink / raw)
To: Ye, Xiaolong; +Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei
> -----Original Message-----
> From: Ye, Xiaolong <xiaolong.ye@intel.com>
> Sent: Friday, March 13, 2020 15:01
> To: Wang, Haiyue <haiyue.wang@intel.com>
> Cc: dev@dpdk.org; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>
> Subject: Re: [PATCH v2 7/7] net/ice: get the VF hardware index in DCF
>
> On 03/10, Haiyue Wang wrote:
> >The DCF (Device Config Function) needs the hardware index of the VFs to
> >control the flow setting. And also if the VF resets, the index may be
> >changed, so it should handle this in VF reset event.
> >
> >Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
> >---
> > drivers/net/ice/ice_dcf.c | 81 +++++++++++++++++++++++++++++++
> > drivers/net/ice/ice_dcf.h | 4 ++
> > drivers/net/ice/ice_dcf_parent.c | 83 +++++++++++++++++++++++++++++++-
> > 3 files changed, 167 insertions(+), 1 deletion(-)
> >
> >diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
> >index 480c449f5..1d3c8fa95 100644
> >--- a/drivers/net/ice/ice_dcf.c
> >+++ b/drivers/net/ice/ice_dcf.c
> >@@ -269,6 +269,63 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
> > return 0;
> > }
> >
> >+static int
> >+ice_dcf_get_vf_vsi_map(struct ice_dcf_hw *hw)
> >+{
> >+ struct virtchnl_dcf_vsi_map *vsi_map;
> >+ uint16_t len;
> >+ int err;
> >+
> >+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
> >+ NULL, 0);
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR, "Fail to send msg OP_DCF_GET_VSI_MAP");
>
> Better to make the err log format consistent, either "Failed to xxx" or "Fail to xxxx",
> I prefer to "Failed to xxx".
>
Fixed in v3 with "Failed to xxx".
>
> >+ return err;
> >+ }
> >+
> >+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
> >+ hw->arq_buf, ICE_DCF_AQ_BUF_SZ,
> >+ &len);
> >+ if (err) {
> >+ PMD_DRV_LOG(ERR, "Fail to get response of OP_DCF_GET_VSI_MAP");
> >+ return err;
> >+ }
> >+
> >+ vsi_map = (struct virtchnl_dcf_vsi_map *)hw->arq_buf;
> >+ if (len < sizeof(*vsi_map) || !vsi_map->num_vfs ||
> >+ len < sizeof(*vsi_map) +
> >+ (vsi_map->num_vfs - 1) * sizeof(vsi_map->vf_vsi[0])) {
>
> Better to use a tmp variable to make the code more readable.
> And is the first len < sizeof(*vsi_map) redundant?
Yes, and enhanced this with valid_msg_len for checking the length in v3.
>
> >+ PMD_DRV_LOG(ERR, "invalid vf vsi map response with length %u",
> >+ len);
> >+ return -EINVAL;
> >+ }
> >+
> >+ if (hw->num_vfs != 0 && hw->num_vfs != vsi_map->num_vfs) {
> >+ PMD_DRV_LOG(ERR, "The number VSI map (%u) doesn't match the number of VFs (%u)",
> >+ vsi_map->num_vfs, hw->num_vfs);
> >+ return -EINVAL;
> >+ }
> >+
> >+ len = vsi_map->num_vfs * sizeof(vsi_map->vf_vsi[0]);
> >+ if (!hw->vf_vsi_map) {
> >+ hw->num_vfs = vsi_map->num_vfs;
> >+ hw->vf_vsi_map = rte_zmalloc("vf_vsi_ctx", len, 0);
> >+ }
> >+
> >+ if (!hw->vf_vsi_map) {
> >+ PMD_DRV_LOG(ERR, "Fail to alloc memory for VSI context");
> >+ return -ENOMEM;
> >+ }
>
> I think above two blocks can be combined with one if (!hw->vf_vsi_map).
>
Done in v3.
> >+
> >+ if (!memcmp(hw->vf_vsi_map, vsi_map->vf_vsi, len)) {
> >+ PMD_DRV_LOG(DEBUG, "VF VSI map doesn't change");
> >+ return 1;
> >+ }
> >+
> >+ rte_memcpy(hw->vf_vsi_map, vsi_map->vf_vsi, len);
> >+ return 0;
> >+}
> >+
> > static int
> > ice_dcf_mode_disable(struct ice_dcf_hw *hw)
> > {
> >@@ -467,6 +524,23 @@ ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
> > return err;
> > }
> >
> >+int
> >+ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw)
> >+{
> >+ int err = 0;
> >+
> >+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
> >+ ice_dcf_disable_irq0(hw);
> >+
> >+ if (ice_dcf_get_vf_resource(hw) || ice_dcf_get_vf_vsi_map(hw))
> >+ err = -1;
> >+
> >+ ice_dcf_enable_irq0(hw);
> >+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
> >+
> >+ return err;
> >+}
> >+
> > int
> > ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
> > {
> >@@ -534,6 +608,12 @@ ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
> > goto err_alloc;
> > }
> >
> >+ if (ice_dcf_get_vf_vsi_map(hw) < 0) {
> >+ PMD_INIT_LOG(ERR, "Failed to get VF VSI map");
> >+ ice_dcf_mode_disable(hw);
> >+ goto err_alloc;
> >+ }
> >+
> > rte_intr_callback_register(&pci_dev->intr_handle,
> > ice_dcf_dev_interrupt_handler, hw);
> > rte_intr_enable(&pci_dev->intr_handle);
> >@@ -566,5 +646,6 @@ ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
> > iavf_shutdown_adminq(&hw->avf);
> >
> > rte_free(hw->arq_buf);
> >+ rte_free(hw->vf_vsi_map);
> > rte_free(hw->vf_res);
> > }
> >diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
> >index ecd6303a0..12bef4a2a 100644
> >--- a/drivers/net/ice/ice_dcf.h
> >+++ b/drivers/net/ice/ice_dcf.h
> >@@ -41,6 +41,9 @@ struct ice_dcf_hw {
> >
> > uint8_t *arq_buf;
> >
> >+ uint16_t num_vfs;
> >+ uint16_t *vf_vsi_map;
> >+
> > struct virtchnl_version_info virtchnl_version;
> > struct virtchnl_vf_resource *vf_res; /* VF resource */
> > struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
> >@@ -51,6 +54,7 @@ int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
> > struct dcf_virtchnl_cmd *cmd);
> > int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
> > void *buf, uint16_t buf_size);
> >+int ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw);
> > int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
> > void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
> >
> >diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
> >index 4c3bb68b1..2735221e9 100644
> >--- a/drivers/net/ice/ice_dcf_parent.c
> >+++ b/drivers/net/ice/ice_dcf_parent.c
> >@@ -5,10 +5,76 @@
> > #include <sys/stat.h>
> > #include <unistd.h>
> >
> >+#include <rte_alarm.h>
> >+
> > #include "ice_dcf_ethdev.h"
> >
> >+#define ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL 100000 /* us */
> >+
> >+static __rte_always_inline void
> >+ice_dcf_update_vsi_ctx(struct ice_hw *hw, uint16_t vsi_handle,
> >+ uint16_t vsi_map)
> >+{
> >+ struct ice_vsi_ctx *vsi_ctx;
> >+
> >+ if (unlikely(vsi_handle >= ICE_MAX_VSI)) {
> >+ PMD_DRV_LOG(ERR, "Invalid vsi handle %u", vsi_handle);
> >+ return;
> >+ }
> >+
> >+ vsi_ctx = hw->vsi_ctx[vsi_handle];
> >+
> >+ if (vsi_map & VIRTCHNL_DCF_VF_VSI_VALID) {
> >+ if (!vsi_ctx)
> >+ vsi_ctx = ice_malloc(hw, sizeof(*vsi_ctx));
> >+
> >+ if (!vsi_ctx) {
> >+ PMD_DRV_LOG(ERR, "No memory for vsi context %u",
> >+ vsi_handle);
> >+ return;
> >+ }
>
> Above two blocks can be combined.
Done in v3.
>
> >+
> >+ vsi_ctx->vsi_num = (vsi_map & VIRTCHNL_DCF_VF_VSI_ID_M) >>
> >+ VIRTCHNL_DCF_VF_VSI_ID_S;
> >+ hw->vsi_ctx[vsi_handle] = vsi_ctx;
> >+
> >+ PMD_DRV_LOG(DEBUG, "VF%u is assigned with vsi number %u",
> >+ vsi_handle, vsi_ctx->vsi_num);
> >+ } else {
> >+ hw->vsi_ctx[vsi_handle] = NULL;
> >+
> >+ ice_free(hw, vsi_ctx);
> >+
> >+ PMD_DRV_LOG(NOTICE, "VF%u is disabled", vsi_handle);
> >+ }
> >+}
> >+
> >+static void
> >+ice_dcf_update_vf_vsi_map(struct ice_hw *hw, uint16_t num_vfs,
> >+ uint16_t *vf_vsi_map)
> >+{
> >+ uint16_t vf_id;
> >+
> >+ for (vf_id = 0; vf_id < num_vfs; vf_id++)
> >+ ice_dcf_update_vsi_ctx(hw, vf_id, vf_vsi_map[vf_id]);
> >+}
> >+
> >+static void
> >+ice_dcf_vsi_update_service_handler(void *param)
> >+{
> >+ struct ice_dcf_hw *hw = param;
> >+
> >+ if (!ice_dcf_handle_vsi_update_event(hw)) {
> >+ struct ice_dcf_adapter *dcf_ad =
> >+ container_of(hw, struct ice_dcf_adapter, real_hw);
> >+
> >+ ice_dcf_update_vf_vsi_map(&dcf_ad->parent.hw,
> >+ hw->num_vfs, hw->vf_vsi_map);
> >+ }
> >+}
> >+
> > void
> >-ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
> >+ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
> > uint8_t *msg, uint16_t msglen)
> > {
> > struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
> >@@ -21,6 +87,8 @@ ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
> > switch (pf_msg->event) {
> > case VIRTCHNL_EVENT_RESET_IMPENDING:
> > PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
> >+ rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL * 2,
> >+ ice_dcf_vsi_update_service_handler, dcf_hw);
>
> Why * 2 for the VIRTCHNL_EVENT_RESET_IMPENDING event?
>
Original thought is VF itself reset needs more work (by referring to iavf PMD),
after check, no need *2. Fixed in v3.
> > break;
> > case VIRTCHNL_EVENT_LINK_CHANGE:
> > PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
> >@@ -28,6 +96,13 @@ ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
> > case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
> > PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
> > break;
> >+ case VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE:
> >+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE event : VF%u with VSI num %u",
> >+ pf_msg->event_data.vf_vsi_map.vf_id,
> >+ pf_msg->event_data.vf_vsi_map.vsi_id);
> >+ rte_eal_alarm_set(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL,
> >+ ice_dcf_vsi_update_service_handler, dcf_hw);
> >+ break;
> > default:
> > PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
> > break;
> >@@ -235,6 +310,9 @@ ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
> > }
> > parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
> >
> >+ ice_dcf_update_vf_vsi_map(parent_hw,
> >+ hw->num_vfs, hw->vf_vsi_map);
> >+
>
> No need to split into 2 lines.
Done in v3.
>
> > mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
> > if (rte_is_valid_assigned_ether_addr(mac))
> > rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
> >@@ -259,5 +337,8 @@ ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
> >
> > eth_dev->data->mac_addrs = NULL;
> >
> >+ rte_eal_alarm_cancel(ice_dcf_vsi_update_service_handler,
> >+ &adapter->real_hw);
> >+
> > ice_dcf_uninit_parent_hw(parent_hw);
> > }
> >--
> >2.25.1
> >
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
2020-03-15 1:49 ` Zhang, Qi Z
@ 2020-03-16 18:54 ` Stillwell Jr, Paul M
2020-03-17 2:35 ` Wang, Haiyue
0 siblings, 1 reply; 94+ messages in thread
From: Stillwell Jr, Paul M @ 2020-03-16 18:54 UTC (permalink / raw)
To: Zhang, Qi Z, Wang, Haiyue, dev, Ye, Xiaolong, Yang, Qiming, Xing, Beilei
Cc: Zhao1, Wei, Wang, Haiyue, Liang, Cunming, Wu, Jingjing
See my responses inline.
Paul
> -----Original Message-----
> From: Zhang, Qi Z <qi.z.zhang@intel.com>
> Sent: Saturday, March 14, 2020 6:50 PM
> To: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>; Wang, Haiyue
> <haiyue.wang@intel.com>; dev@dpdk.org; Ye, Xiaolong
> <xiaolong.ye@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> Beilei <beilei.xing@intel.com>
> Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> <haiyue.wang@intel.com>; Liang, Cunming <cunming.liang@intel.com>; Wu,
> Jingjing <jingjing.wu@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
>
> Hi Paul:
>
> > -----Original Message-----
> > From: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>
> > Sent: Saturday, March 14, 2020 12:19 AM
> > To: Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye, Xiaolong
> > <xiaolong.ye@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang,
> > Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > <haiyue.wang@intel.com>
> > Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> >
> > I'm confused. Shouldn't the DCF be a separate driver since it is a VF,
> > not part of a PF? You are starting to combine PF/VF code and I'm not
> > sure if that is the correct way to go.
>
> From DPDK's view, DCF is NOT a VF driver, actually it behaves like a PF driver
> with control path only and it share most exist PF driver's API implementation
It *is* a VF. The only way this will work is if the VF has the trust flag set and then it can become the DCF. You can't set the trust flag on a PF I don't think. That's the only way this will work because the kernel driver code has checks on the admin queue messages to see if the message is from a VF. If it's not a message from a specific VF, then the message will get rejected.
> , That's why we combined it with exist PF driver, so when the module
> driver/net/ice is compiled into a library, it can be probed as a PF driver or DCF
> base on device ID at runtime.
> And the is not special in DPDK, for example, the module in driver/net/i40e
> can be probed as i40e pf driver or i40e vf driver.
> DCF take SR-IOV's mailbox as a message channel to communicate with the
> backend kernel driver, so iavf virtual channel is reused here, so we also need
> to link iavf share code.
>
> And I agree, its always better if we can separate 2 different things while
> decouple all the common code into a share library to avoid duplicate code
> copy (just like we did on iavf share code) But in this case, a lot of code
> refectory is required , so far we just take the simple way, we may improve
> this in future.
>
> Thanks
> Qi
>
> >
> > Paul
> >
> > > -----Original Message-----
> > > From: dev <dev-bounces@dpdk.org> On Behalf Of Haiyue Wang
> > > Sent: Monday, March 9, 2020 11:50 PM
> > > To: dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z
> > > <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> > > Beilei <beilei.xing@intel.com>
> > > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > > <haiyue.wang@intel.com>
> > > Subject: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> > >
> > > A DCF (Device Config Function) based approach is proposed where a
> > > device bound to the device's VF0 can act as a sole controlling
> > > entity to exercise advance functionality (such as switch, ACL) for rest of
> the VFs.
> > >
> > > The DCF works as a standalone PMD to support this function, which
> > > shares the ice PMD flow control core function and the iavf virtchnl
> > > mailbox core module.
> > >
> > > This patchset is based on:
> > > [1] https://patchwork.dpdk.org/cover/66417/ : update ice base code
> > > [2] https://patchwork.dpdk.org/cover/66472/ : iavf share code update
> > >
> > > Depends-on: series-8843
> > > Depends-on: series-8855
> > >
> > > v2:
> > > 1. update the iavf patchset link.
> > > 2. split more patches for making this work be more understandable
> > > 3. fix the log function usage, devargs checking from v1.
> > >
> > > Haiyue Wang (7):
> > > net/iavf: stop the PCI probe in DCF mode
> > > net/ice: add the DCF hardware initialization
> > > net/ice: initiate to acquire the DCF capability
> > > net/ice: handle the AdminQ command by DCF
> > > net/ice: export the DDP definition symbols
> > > net/ice: handle the PF initialization by DCF
> > > net/ice: get the VF hardware index in DCF
> > >
> > > doc/guides/nics/ice.rst | 47 ++
> > > doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> > > doc/guides/rel_notes/release_20_05.rst | 5 +
> > > drivers/common/Makefile | 1 +
> > > drivers/net/iavf/iavf_ethdev.c | 43 ++
> > > drivers/net/ice/Makefile | 6 +
> > > drivers/net/ice/ice_dcf.c | 651
> > +++++++++++++++++++++++++
> > > drivers/net/ice/ice_dcf.h | 61 +++
> > > drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
> > > drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> > > drivers/net/ice/ice_dcf_parent.c | 344 +++++++++++++
> > > drivers/net/ice/ice_ethdev.c | 9 +-
> > > drivers/net/ice/ice_ethdev.h | 8 +
> > > drivers/net/ice/meson.build | 8 +-
> > > mk/rte.app.mk | 1 +
> > > 15 files changed, 1528 insertions(+), 10 deletions(-) create mode
> > > 100644 doc/guides/nics/img/ice_dcf.png create mode 100644
> > > drivers/net/ice/ice_dcf.c create mode 100644
> > > drivers/net/ice/ice_dcf.h create mode 100644
> > > drivers/net/ice/ice_dcf_ethdev.c create mode 100644
> > > drivers/net/ice/ice_dcf_ethdev.h create mode 100644
> > > drivers/net/ice/ice_dcf_parent.c
> > >
> > > --
> > > 2.25.1
> >
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
2020-03-16 18:54 ` Stillwell Jr, Paul M
@ 2020-03-17 2:35 ` Wang, Haiyue
0 siblings, 0 replies; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-17 2:35 UTC (permalink / raw)
To: Stillwell Jr, Paul M, Zhang, Qi Z, dev, Ye, Xiaolong, Yang,
Qiming, Xing, Beilei
Cc: Zhao1, Wei, Liang, Cunming, Wu, Jingjing
> -----Original Message-----
> From: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>
> Sent: Tuesday, March 17, 2020 02:55
> To: Zhang, Qi Z <qi.z.zhang@intel.com>; Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye,
> Xiaolong <xiaolong.ye@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei
> <beilei.xing@intel.com>
> Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue <haiyue.wang@intel.com>; Liang, Cunming
> <cunming.liang@intel.com>; Wu, Jingjing <jingjing.wu@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
>
> See my responses inline.
>
> Paul
>
> > -----Original Message-----
> > From: Zhang, Qi Z <qi.z.zhang@intel.com>
> > Sent: Saturday, March 14, 2020 6:50 PM
> > To: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>; Wang, Haiyue
> > <haiyue.wang@intel.com>; dev@dpdk.org; Ye, Xiaolong
> > <xiaolong.ye@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> > Beilei <beilei.xing@intel.com>
> > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > <haiyue.wang@intel.com>; Liang, Cunming <cunming.liang@intel.com>; Wu,
> > Jingjing <jingjing.wu@intel.com>
> > Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> >
> > Hi Paul:
> >
> > > -----Original Message-----
> > > From: Stillwell Jr, Paul M <paul.m.stillwell.jr@intel.com>
> > > Sent: Saturday, March 14, 2020 12:19 AM
> > > To: Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye, Xiaolong
> > > <xiaolong.ye@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang,
> > > Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> > > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > > <haiyue.wang@intel.com>
> > > Subject: RE: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> > >
> > > I'm confused. Shouldn't the DCF be a separate driver since it is a VF,
> > > not part of a PF? You are starting to combine PF/VF code and I'm not
> > > sure if that is the correct way to go.
> >
> > From DPDK's view, DCF is NOT a VF driver, actually it behaves like a PF driver
> > with control path only and it share most exist PF driver's API implementation
>
> It *is* a VF. The only way this will work is if the VF has the trust flag set and then it can become
> the DCF. You can't set the trust flag on a PF I don't think. That's the only way this will work
> because the kernel driver code has checks on the admin queue messages to see if the message is from a
> VF. If it's not a message from a specific VF, then the message will get rejected.
>
This is absolutely right, and this is added into the guide about how to enable DCF. ;-)
And one important thing is that : VF with DCF capability is only bound to ice/kernel
driver, so we can't add it into the generic iavf VF PMD, since it works on i40e/ice etc.
And the main task about DCF is flow control, the AdminQ is implemented in ice PF PMD, and
it just uses these AdminQ API to runs on VF hardware, not ice PF hardware.
> > , That's why we combined it with exist PF driver, so when the module
> > driver/net/ice is compiled into a library, it can be probed as a PF driver or DCF
> > base on device ID at runtime.
> > And the is not special in DPDK, for example, the module in driver/net/i40e
> > can be probed as i40e pf driver or i40e vf driver.
> > DCF take SR-IOV's mailbox as a message channel to communicate with the
> > backend kernel driver, so iavf virtual channel is reused here, so we also need
> > to link iavf share code.
> >
> > And I agree, its always better if we can separate 2 different things while
> > decouple all the common code into a share library to avoid duplicate code
> > copy (just like we did on iavf share code) But in this case, a lot of code
> > refectory is required , so far we just take the simple way, we may improve
> > this in future.
> >
> > Thanks
> > Qi
> >
> > >
> > > Paul
> > >
> > > > -----Original Message-----
> > > > From: dev <dev-bounces@dpdk.org> On Behalf Of Haiyue Wang
> > > > Sent: Monday, March 9, 2020 11:50 PM
> > > > To: dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z
> > > > <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> > > > Beilei <beilei.xing@intel.com>
> > > > Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> > > > <haiyue.wang@intel.com>
> > > > Subject: [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support
> > > >
> > > > A DCF (Device Config Function) based approach is proposed where a
> > > > device bound to the device's VF0 can act as a sole controlling
> > > > entity to exercise advance functionality (such as switch, ACL) for rest of
> > the VFs.
> > > >
> > > > The DCF works as a standalone PMD to support this function, which
> > > > shares the ice PMD flow control core function and the iavf virtchnl
> > > > mailbox core module.
> > > >
> > > > This patchset is based on:
> > > > [1] https://patchwork.dpdk.org/cover/66417/ : update ice base code
> > > > [2] https://patchwork.dpdk.org/cover/66472/ : iavf share code update
> > > >
> > > > Depends-on: series-8843
> > > > Depends-on: series-8855
> > > >
> > > > v2:
> > > > 1. update the iavf patchset link.
> > > > 2. split more patches for making this work be more understandable
> > > > 3. fix the log function usage, devargs checking from v1.
> > > >
> > > > Haiyue Wang (7):
> > > > net/iavf: stop the PCI probe in DCF mode
> > > > net/ice: add the DCF hardware initialization
> > > > net/ice: initiate to acquire the DCF capability
> > > > net/ice: handle the AdminQ command by DCF
> > > > net/ice: export the DDP definition symbols
> > > > net/ice: handle the PF initialization by DCF
> > > > net/ice: get the VF hardware index in DCF
> > > >
> > > > doc/guides/nics/ice.rst | 47 ++
> > > > doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> > > > doc/guides/rel_notes/release_20_05.rst | 5 +
> > > > drivers/common/Makefile | 1 +
> > > > drivers/net/iavf/iavf_ethdev.c | 43 ++
> > > > drivers/net/ice/Makefile | 6 +
> > > > drivers/net/ice/ice_dcf.c | 651
> > > +++++++++++++++++++++++++
> > > > drivers/net/ice/ice_dcf.h | 61 +++
> > > > drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
> > > > drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> > > > drivers/net/ice/ice_dcf_parent.c | 344 +++++++++++++
> > > > drivers/net/ice/ice_ethdev.c | 9 +-
> > > > drivers/net/ice/ice_ethdev.h | 8 +
> > > > drivers/net/ice/meson.build | 8 +-
> > > > mk/rte.app.mk | 1 +
> > > > 15 files changed, 1528 insertions(+), 10 deletions(-) create mode
> > > > 100644 doc/guides/nics/img/ice_dcf.png create mode 100644
> > > > drivers/net/ice/ice_dcf.c create mode 100644
> > > > drivers/net/ice/ice_dcf.h create mode 100644
> > > > drivers/net/ice/ice_dcf_ethdev.c create mode 100644
> > > > drivers/net/ice/ice_dcf_ethdev.h create mode 100644
> > > > drivers/net/ice/ice_dcf_parent.c
> > > >
> > > > --
> > > > 2.25.1
> > >
> >
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
2020-03-09 15:38 ` Ye Xiaolong
@ 2020-03-23 1:50 ` Wu, Jingjing
2020-03-23 1:55 ` Wang, Haiyue
1 sibling, 1 reply; 94+ messages in thread
From: Wu, Jingjing @ 2020-03-23 1:50 UTC (permalink / raw)
To: Wang, Haiyue, dev, Ye, Xiaolong, Zhang, Qi Z, Yang, Qiming, Xing, Beilei
Cc: Zhao1, Wei, Wang, Haiyue
+static int
+handle_dcf_arg(__rte_unused const char *key, const char *value,
+ __rte_unused void *arg)
__rte_unused is not needed here.
+{
+ bool *dcf = arg;
+
+ if (arg == NULL || value == NULL)
+ return -EINVAL;
+
+ if (strcmp(value, "dcf") == 0)
+ *dcf = true;
+ else
+ *dcf = false;
+
+ return 0;
+}
+
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode
2020-03-23 1:50 ` Wu, Jingjing
@ 2020-03-23 1:55 ` Wang, Haiyue
0 siblings, 0 replies; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-23 1:55 UTC (permalink / raw)
To: Wu, Jingjing, dev, Ye, Xiaolong, Zhang, Qi Z, Yang, Qiming, Xing, Beilei
Cc: Zhao1, Wei
> -----Original Message-----
> From: Wu, Jingjing <jingjing.wu@intel.com>
> Sent: Monday, March 23, 2020 09:51
> To: Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang,
> Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue <haiyue.wang@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode
>
> +static int
> +handle_dcf_arg(__rte_unused const char *key, const char *value,
> + __rte_unused void *arg)
> __rte_unused is not needed here.
Yes, has been rewritten and fixed in v3. ;-)
>
> +{
> + bool *dcf = arg;
> +
> + if (arg == NULL || value == NULL)
> + return -EINVAL;
> +
> + if (strcmp(value, "dcf") == 0)
> + *dcf = true;
> + else
> + *dcf = false;
> +
> + return 0;
> +}
> +
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support
2020-03-09 14:14 [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support Haiyue Wang
` (6 preceding siblings ...)
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 " Haiyue Wang
@ 2020-03-26 3:03 ` Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
` (8 more replies)
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 " Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Haiyue Wang
9 siblings, 9 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 3:03 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A DCF (Device Config Function) based approach is proposed where a device
bound to the device's VF0 can act as a sole controlling entity to exercise
advance functionality (such as switch, ACL) for rest of the VFs.
The DCF works as a standalone PMD to support this function, which shares the
ice PMD flow control core function and the iavf virtchnl mailbox core module.
v4:
Change the alarm handler to thread service, since it will need to do more
work.
v3:
1. Fixed the error log message format.
2. Fixed some memory allocation check.
3. Fixed some code style issue and commmit message description.
v2:
1. update the iavf patchset link.
2. split more patches for making this work be more understandable
3. fix the log function usage, devargs checking from v1.
Haiyue Wang (7):
net/iavf: stop the PCI probe in DCF mode
net/ice: add the DCF hardware initialization
net/ice: acquire and disable the DCF capability
net/ice: handle the AdminQ command by DCF
net/ice: export the DDP definition symbols
net/ice: handle the PF initialization by DCF
net/ice: get the VF hardware index in DCF
doc/guides/nics/ice.rst | 47 ++
doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
doc/guides/rel_notes/release_20_05.rst | 5 +
drivers/common/Makefile | 1 +
drivers/net/iavf/iavf_ethdev.c | 43 ++
drivers/net/ice/Makefile | 6 +
drivers/net/ice/ice_dcf.c | 658 +++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 63 +++
drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
drivers/net/ice/ice_dcf_ethdev.h | 33 ++
drivers/net/ice/ice_dcf_parent.c | 351 +++++++++++++
drivers/net/ice/ice_ethdev.c | 9 +-
drivers/net/ice/ice_ethdev.h | 8 +
drivers/net/ice/meson.build | 8 +-
mk/rte.app.mk | 1 +
15 files changed, 1544 insertions(+), 10 deletions(-)
create mode 100644 doc/guides/nics/img/ice_dcf.png
create mode 100644 drivers/net/ice/ice_dcf.c
create mode 100644 drivers/net/ice/ice_dcf.h
create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
create mode 100644 drivers/net/ice/ice_dcf_parent.c
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v4 1/7] net/iavf: stop the PCI probe in DCF mode
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Haiyue Wang
@ 2020-03-26 3:03 ` Haiyue Wang
2020-03-26 3:28 ` Wu, Jingjing
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
` (7 subsequent siblings)
8 siblings, 1 reply; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 3:03 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A new DCF PMD will be introduced, which runs on Intel VF hardware, and
it is a pure software design to control the advance functionality (such
as switch, ACL) for rest of the VFs.
So if the DCF (Device Config Function) mode is specified by the devarg
'cap=dcf', then it will stop the PCI probe in the iavf PMD.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Reviewed-by: Xiaolong Ye <xiaolong.ye@intel.com>
---
drivers/net/iavf/iavf_ethdev.c | 43 ++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 34913f9c4..c0b95e169 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -1416,9 +1416,51 @@ iavf_dev_uninit(struct rte_eth_dev *dev)
return 0;
}
+static int
+iavf_dcf_cap_check_handler(__rte_unused const char *key,
+ const char *value, __rte_unused void *opaque)
+{
+ if (strcmp(value, "dcf"))
+ return -1;
+
+ return 0;
+}
+
+static int
+iavf_dcf_cap_selected(struct rte_devargs *devargs)
+{
+ struct rte_kvargs *kvlist;
+ const char *key = "cap";
+ int ret = 0;
+
+ if (devargs == NULL)
+ return 0;
+
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
+ if (kvlist == NULL)
+ return 0;
+
+ if (!rte_kvargs_count(kvlist, key))
+ goto exit;
+
+ /* dcf capability selected when there's a key-value pair: cap=dcf */
+ if (rte_kvargs_process(kvlist, key,
+ iavf_dcf_cap_check_handler, NULL) < 0)
+ goto exit;
+
+ ret = 1;
+
+exit:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
static int eth_iavf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
struct rte_pci_device *pci_dev)
{
+ if (iavf_dcf_cap_selected(pci_dev->device.devargs))
+ return 1;
+
return rte_eth_dev_pci_generic_probe(pci_dev,
sizeof(struct iavf_adapter), iavf_dev_init);
}
@@ -1439,6 +1481,7 @@ static struct rte_pci_driver rte_iavf_pmd = {
RTE_PMD_REGISTER_PCI(net_iavf, rte_iavf_pmd);
RTE_PMD_REGISTER_PCI_TABLE(net_iavf, pci_id_iavf_map);
RTE_PMD_REGISTER_KMOD_DEP(net_iavf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_iavf, "cap=dcf");
RTE_INIT(iavf_init_log)
{
iavf_logtype_init = rte_log_register("pmd.net.iavf.init");
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v4 2/7] net/ice: add the DCF hardware initialization
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
@ 2020-03-26 3:03 ` Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 3/7] net/ice: acquire and disable the DCF capability Haiyue Wang
` (6 subsequent siblings)
8 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 3:03 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
Introduce the DCF (Device Config Function) feature in the ice PMD, it
works as a standalone PMD which doesn't handle the packet Rx/Tx related
things. Its hardware entity is the VF.
Add the basic DCF hardware initialization, this is specified by devarg
'cap=dcf'.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
doc/guides/nics/ice.rst | 47 +++
doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
doc/guides/rel_notes/release_20_05.rst | 5 +
drivers/common/Makefile | 1 +
drivers/net/ice/Makefile | 5 +
drivers/net/ice/ice_dcf.c | 474 +++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 52 +++
drivers/net/ice/ice_dcf_ethdev.c | 317 +++++++++++++++++
drivers/net/ice/ice_dcf_ethdev.h | 24 ++
drivers/net/ice/meson.build | 7 +-
mk/rte.app.mk | 1 +
11 files changed, 931 insertions(+), 2 deletions(-)
create mode 100644 doc/guides/nics/img/ice_dcf.png
create mode 100644 drivers/net/ice/ice_dcf.c
create mode 100644 drivers/net/ice/ice_dcf.h
create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 8af32dabf..2639ae239 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -240,6 +240,53 @@ report a MDD event and drop the packets.
The APPs based on DPDK should avoid providing such packets.
+Device Config Function (DCF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section demonstrates ICE DCF PMD, which shares the core module with ICE
+PMD and iAVF PMD.
+
+A DCF (Device Config Function) PMD bounds to the device's trusted VF with ID 0,
+it can act as a sole controlling entity to exercise advance functionality (such
+as switch, ACL) for the rest VFs.
+
+The DCF PMD needs to advertise and acquire DCF capability which allows DCF to
+send AdminQ commands that it would like to execute over to the PF and receive
+responses for the same from PF.
+
+.. _figure_ice_dcf:
+
+.. figure:: img/ice_dcf.*
+
+ DCF Communication flow.
+
+#. Create the VFs::
+
+ echo 4 > /sys/bus/pci/devices/0000\:18\:00.0/sriov_numvfs
+
+#. Enable the VF0 trust on::
+
+ ip link set dev enp24s0f0 vf 0 trust on
+
+#. Bind the VF0, and run testpmd with 'cap=dcf' devarg::
+
+ testpmd -l 22-25 -n 4 -w 18:01.0,cap=dcf -- -i
+
+#. Monitor the VF2 interface network traffic::
+
+ tcpdump -e -nn -i enp24s1f2
+
+#. Create one flow to redirect the traffic to VF2 by DCF::
+
+ flow create 0 priority 0 ingress pattern eth / ipv4 src is 192.168.0.2 \
+ dst is 192.168.0.3 / end actions vf id 2 / end
+
+#. Send the packet, and it should be displayed on tcpdump::
+
+ sendp(Ether(src='3c:fd:fe:aa:bb:78', dst='00:00:00:01:02:03')/IP(src=' \
+ 192.168.0.2', dst="192.168.0.3")/TCP(flags='S')/Raw(load='XXXXXXXXXX'), \
+ iface="enp24s0f0", count=10)
+
Sample Application Notes
------------------------
diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
new file mode 100644
index 0000000000000000000000000000000000000000..540823c4a05e9ea9d558d233fea77016d1ae5df3
GIT binary patch
literal 39168
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
literal 0
HcmV?d00001
diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 000bbf501..f404ee7fd 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -62,6 +62,11 @@ New Features
* Added support for matching on IPv4 Time To Live and IPv6 Hop Limit.
+* **Updated the Intel ice driver.**
+
+ Updated the Intel ice driver with new features and improvements, including:
+
+ * Added support for DCF (Device Config Function) feature.
Removed Items
-------------
diff --git a/drivers/common/Makefile b/drivers/common/Makefile
index 96bd7ac6e..df2e840cf 100644
--- a/drivers/common/Makefile
+++ b/drivers/common/Makefile
@@ -31,6 +31,7 @@ DIRS-y += dpaax
endif
IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
ifneq (,$(findstring y,$(IAVF-y)))
DIRS-y += iavf
endif
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index e22c34287..f493c9ed7 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -11,9 +11,11 @@ LIB = librte_pmd_ice.a
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
+LDLIBS += -lrte_net -lrte_common_iavf
EXPORT_MAP := rte_pmd_ice_version.map
@@ -84,6 +86,9 @@ ifeq ($(CC_AVX2_SUPPORT), 1)
endif
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+
# install this header file
SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
new file mode 100644
index 000000000..0a99cceb1
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.c
@@ -0,0 +1,474 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include "ice_dcf.h"
+
+#define ICE_DCF_AQ_LEN 32
+#define ICE_DCF_AQ_BUF_SZ 4096
+
+#define ICE_DCF_ARQ_MAX_RETRIES 200
+#define ICE_DCF_ARQ_CHECK_TIME 2 /* msecs */
+
+#define ICE_DCF_VF_RES_BUF_SZ \
+ (sizeof(struct virtchnl_vf_resource) + \
+ IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource))
+
+static __rte_always_inline int
+ice_dcf_send_cmd_req_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+ uint8_t *req_msg, uint16_t req_msglen)
+{
+ return iavf_aq_send_msg_to_pf(&hw->avf, op, IAVF_SUCCESS,
+ req_msg, req_msglen, NULL);
+}
+
+static int
+ice_dcf_recv_cmd_rsp_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+ uint8_t *rsp_msgbuf, uint16_t rsp_buflen,
+ uint16_t *rsp_msglen)
+{
+ struct iavf_arq_event_info event;
+ enum virtchnl_ops v_op;
+ int i = 0;
+ int err;
+
+ event.buf_len = rsp_buflen;
+ event.msg_buf = rsp_msgbuf;
+
+ do {
+ err = iavf_clean_arq_element(&hw->avf, &event, NULL);
+ if (err != IAVF_SUCCESS)
+ goto again;
+
+ v_op = rte_le_to_cpu_32(event.desc.cookie_high);
+ if (v_op != op)
+ goto again;
+
+ if (rsp_msglen != NULL)
+ *rsp_msglen = event.msg_len;
+ return rte_le_to_cpu_32(event.desc.cookie_low);
+
+again:
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ return -EIO;
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_clear(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_REMOVE(&hw->vc_cmd_queue, cmd, next);
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline void
+ice_dcf_vc_cmd_set(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ cmd->v_ret = IAVF_ERR_NOT_READY;
+ cmd->rsp_msglen = 0;
+ cmd->pending = 1;
+
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_INSERT_TAIL(&hw->vc_cmd_queue, cmd, next);
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline int
+ice_dcf_vc_cmd_send(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ return iavf_aq_send_msg_to_pf(&hw->avf,
+ cmd->v_op, IAVF_SUCCESS,
+ cmd->req_msg, cmd->req_msglen, NULL);
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
+{
+ struct dcf_virtchnl_cmd *cmd;
+ enum virtchnl_ops v_op;
+ enum iavf_status v_ret;
+ uint16_t aq_op;
+
+ aq_op = rte_le_to_cpu_16(info->desc.opcode);
+ if (unlikely(aq_op != iavf_aqc_opc_send_msg_to_vf)) {
+ PMD_DRV_LOG(ERR,
+ "Request %u is not supported yet", aq_op);
+ return;
+ }
+
+ v_op = rte_le_to_cpu_32(info->desc.cookie_high);
+ if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+ return;
+
+ v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
+
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_FOREACH(cmd, &hw->vc_cmd_queue, next) {
+ if (cmd->v_op == v_op && cmd->pending) {
+ cmd->v_ret = v_ret;
+ cmd->rsp_msglen = RTE_MIN(info->msg_len,
+ cmd->rsp_buflen);
+ if (likely(cmd->rsp_msglen != 0))
+ rte_memcpy(cmd->rsp_msgbuf, info->msg_buf,
+ cmd->rsp_msglen);
+
+ /* prevent compiler reordering */
+ rte_compiler_barrier();
+ cmd->pending = 0;
+ break;
+ }
+ }
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static void
+ice_dcf_handle_virtchnl_msg(struct ice_dcf_hw *hw)
+{
+ struct iavf_arq_event_info info;
+ uint16_t pending = 1;
+ int ret;
+
+ info.buf_len = ICE_DCF_AQ_BUF_SZ;
+ info.msg_buf = hw->arq_buf;
+
+ while (pending) {
+ ret = iavf_clean_arq_element(&hw->avf, &info, &pending);
+ if (ret != IAVF_SUCCESS)
+ break;
+
+ ice_dcf_aq_cmd_handle(hw, &info);
+ }
+}
+
+static int
+ice_dcf_init_check_api_version(struct ice_dcf_hw *hw)
+{
+#define ICE_CPF_VIRTCHNL_VERSION_MAJOR_START 1
+#define ICE_CPF_VIRTCHNL_VERSION_MINOR_START 1
+ struct virtchnl_version_info version, *pver;
+ int err;
+
+ version.major = VIRTCHNL_VERSION_MAJOR;
+ version.minor = VIRTCHNL_VERSION_MINOR;
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_VERSION,
+ (uint8_t *)&version, sizeof(version));
+ if (err) {
+ PMD_INIT_LOG(ERR, "Failed to send OP_VERSION");
+ return err;
+ }
+
+ pver = &hw->virtchnl_version;
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_VERSION,
+ (uint8_t *)pver, sizeof(*pver), NULL);
+ if (err) {
+ PMD_INIT_LOG(ERR, "Failed to get response of OP_VERSION");
+ return -1;
+ }
+
+ PMD_INIT_LOG(DEBUG,
+ "Peer PF API version: %u.%u", pver->major, pver->minor);
+
+ if (pver->major < ICE_CPF_VIRTCHNL_VERSION_MAJOR_START ||
+ (pver->major == ICE_CPF_VIRTCHNL_VERSION_MAJOR_START &&
+ pver->minor < ICE_CPF_VIRTCHNL_VERSION_MINOR_START)) {
+ PMD_INIT_LOG(ERR,
+ "VIRTCHNL API version should not be lower than (%u.%u)",
+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START,
+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START);
+ return -1;
+ } else if (pver->major > VIRTCHNL_VERSION_MAJOR ||
+ (pver->major == VIRTCHNL_VERSION_MAJOR &&
+ pver->minor > VIRTCHNL_VERSION_MINOR)) {
+ PMD_INIT_LOG(ERR,
+ "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
+ pver->major, pver->minor,
+ VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
+ return -1;
+ }
+
+ PMD_INIT_LOG(DEBUG, "Peer is supported PF host");
+
+ return 0;
+}
+
+static int
+ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
+{
+ uint32_t caps;
+ int err, i;
+
+ caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+ VF_BASE_MODE_OFFLOADS;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+ (uint8_t *)&caps, sizeof(caps));
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to send msg OP_GET_VF_RESOURCE");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+ (uint8_t *)hw->vf_res,
+ ICE_DCF_VF_RES_BUF_SZ, NULL);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to get response of OP_GET_VF_RESOURCE");
+ return -1;
+ }
+
+ iavf_vf_parse_hw_config(&hw->avf, hw->vf_res);
+
+ hw->vsi_res = NULL;
+ for (i = 0; i < hw->vf_res->num_vsis; i++) {
+ if (hw->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
+ hw->vsi_res = &hw->vf_res->vsi_res[i];
+ }
+
+ if (!hw->vsi_res) {
+ PMD_DRV_LOG(ERR, "no LAN VSI found");
+ return -1;
+ }
+
+ hw->vsi_id = hw->vsi_res->vsi_id;
+ PMD_DRV_LOG(DEBUG, "VSI ID is %u", hw->vsi_id);
+
+ return 0;
+}
+
+static int
+ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
+{
+#define ICE_DCF_RESET_WAIT_CNT 50
+ struct iavf_hw *avf = &hw->avf;
+ int i, reset;
+
+ for (i = 0; i < ICE_DCF_RESET_WAIT_CNT; i++) {
+ reset = IAVF_READ_REG(avf, IAVF_VFGEN_RSTAT) &
+ IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
+ reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
+
+ if (reset == VIRTCHNL_VFR_VFACTIVE ||
+ reset == VIRTCHNL_VFR_COMPLETED)
+ break;
+
+ rte_delay_ms(20);
+ }
+
+ if (i >= ICE_DCF_RESET_WAIT_CNT)
+ return -1;
+
+ return 0;
+}
+
+static inline void
+ice_dcf_enable_irq0(struct ice_dcf_hw *hw)
+{
+ struct iavf_hw *avf = &hw->avf;
+
+ /* Enable admin queue interrupt trigger */
+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1,
+ IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+ IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+ IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+ IAVF_WRITE_FLUSH(avf);
+}
+
+static inline void
+ice_dcf_disable_irq0(struct ice_dcf_hw *hw)
+{
+ struct iavf_hw *avf = &hw->avf;
+
+ /* Disable all interrupt types */
+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1, 0);
+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+ IAVF_WRITE_FLUSH(avf);
+}
+
+static void
+ice_dcf_dev_interrupt_handler(void *param)
+{
+ struct ice_dcf_hw *hw = param;
+
+ ice_dcf_disable_irq0(hw);
+
+ ice_dcf_handle_virtchnl_msg(hw);
+
+ ice_dcf_enable_irq0(hw);
+}
+
+int
+ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+ struct dcf_virtchnl_cmd *cmd)
+{
+ int i = 0;
+ int err;
+
+ if ((cmd->req_msg && !cmd->req_msglen) ||
+ (!cmd->req_msg && cmd->req_msglen) ||
+ (cmd->rsp_msgbuf && !cmd->rsp_buflen) ||
+ (!cmd->rsp_msgbuf && cmd->rsp_buflen))
+ return -EINVAL;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_vc_cmd_set(hw, cmd);
+
+ err = ice_dcf_vc_cmd_send(hw, cmd);
+ if (err) {
+ PMD_DRV_LOG(ERR, "fail to send cmd %d", cmd->v_op);
+ goto ret;
+ }
+
+ do {
+ if (!cmd->pending)
+ break;
+
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ if (cmd->v_ret != IAVF_SUCCESS) {
+ err = -1;
+ PMD_DRV_LOG(ERR,
+ "No response (%d times) or return failure (%d) for cmd %d",
+ i, cmd->v_ret, cmd->v_op);
+ }
+
+ret:
+ ice_dcf_aq_cmd_clear(hw, cmd);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+ return err;
+}
+
+int
+ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ int ret;
+
+ hw->avf.hw_addr = pci_dev->mem_resource[0].addr;
+ hw->avf.back = hw;
+
+ hw->avf.bus.bus_id = pci_dev->addr.bus;
+ hw->avf.bus.device = pci_dev->addr.devid;
+ hw->avf.bus.func = pci_dev->addr.function;
+
+ hw->avf.device_id = pci_dev->id.device_id;
+ hw->avf.vendor_id = pci_dev->id.vendor_id;
+ hw->avf.subsystem_device_id = pci_dev->id.subsystem_device_id;
+ hw->avf.subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+
+ hw->avf.aq.num_arq_entries = ICE_DCF_AQ_LEN;
+ hw->avf.aq.num_asq_entries = ICE_DCF_AQ_LEN;
+ hw->avf.aq.arq_buf_size = ICE_DCF_AQ_BUF_SZ;
+ hw->avf.aq.asq_buf_size = ICE_DCF_AQ_BUF_SZ;
+
+ rte_spinlock_init(&hw->vc_cmd_send_lock);
+ rte_spinlock_init(&hw->vc_cmd_queue_lock);
+ TAILQ_INIT(&hw->vc_cmd_queue);
+
+ hw->arq_buf = rte_zmalloc("arq_buf", ICE_DCF_AQ_BUF_SZ, 0);
+ if (hw->arq_buf == NULL) {
+ PMD_INIT_LOG(ERR, "unable to allocate AdminQ buffer memory");
+ goto err;
+ }
+
+ ret = iavf_set_mac_type(&hw->avf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "set_mac_type failed: %d", ret);
+ goto err;
+ }
+
+ ret = ice_dcf_check_reset_done(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "VF is still resetting");
+ goto err;
+ }
+
+ ret = iavf_init_adminq(&hw->avf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "init_adminq failed: %d", ret);
+ goto err;
+ }
+
+ if (ice_dcf_init_check_api_version(hw)) {
+ PMD_INIT_LOG(ERR, "check_api version failed");
+ goto err_api;
+ }
+
+ hw->vf_res = rte_zmalloc("vf_res", ICE_DCF_VF_RES_BUF_SZ, 0);
+ if (hw->vf_res == NULL) {
+ PMD_INIT_LOG(ERR, "unable to allocate vf_res memory");
+ goto err_api;
+ }
+
+ if (ice_dcf_get_vf_resource(hw)) {
+ PMD_INIT_LOG(ERR, "Failed to get VF resource");
+ goto err_alloc;
+ }
+
+ rte_intr_callback_register(&pci_dev->intr_handle,
+ ice_dcf_dev_interrupt_handler, hw);
+ rte_intr_enable(&pci_dev->intr_handle);
+ ice_dcf_enable_irq0(hw);
+
+ return 0;
+
+err_alloc:
+ rte_free(hw->vf_res);
+err_api:
+ iavf_shutdown_adminq(&hw->avf);
+err:
+ rte_free(hw->arq_buf);
+
+ return -1;
+}
+
+void
+ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
+ ice_dcf_disable_irq0(hw);
+ rte_intr_disable(intr_handle);
+ rte_intr_callback_unregister(intr_handle,
+ ice_dcf_dev_interrupt_handler, hw);
+
+ iavf_shutdown_adminq(&hw->avf);
+
+ rte_free(hw->arq_buf);
+ rte_free(hw->vf_res);
+}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
new file mode 100644
index 000000000..f44c09db2
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_H_
+#define _ICE_DCF_H_
+
+#include <rte_ethdev_driver.h>
+
+#include <iavf_prototype.h>
+#include <iavf_adminq_cmd.h>
+#include <iavf_type.h>
+
+#include "ice_logs.h"
+
+struct dcf_virtchnl_cmd {
+ TAILQ_ENTRY(dcf_virtchnl_cmd) next;
+
+ enum virtchnl_ops v_op;
+ enum iavf_status v_ret;
+
+ uint16_t req_msglen;
+ uint8_t *req_msg;
+
+ uint16_t rsp_msglen;
+ uint16_t rsp_buflen;
+ uint8_t *rsp_msgbuf;
+
+ volatile int pending;
+};
+
+struct ice_dcf_hw {
+ struct iavf_hw avf;
+
+ rte_spinlock_t vc_cmd_send_lock;
+ rte_spinlock_t vc_cmd_queue_lock;
+ TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+ uint8_t *arq_buf;
+
+ struct virtchnl_version_info virtchnl_version;
+ struct virtchnl_vf_resource *vf_res; /* VF resource */
+ struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
+ uint16_t vsi_id;
+};
+
+int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+ struct dcf_virtchnl_cmd *cmd);
+
+int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+
+#endif /* _ICE_DCF_H_ */
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
new file mode 100644
index 000000000..23f82a487
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -0,0 +1,317 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <rte_interrupts.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_pci.h>
+#include <rte_kvargs.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include <iavf_devids.h>
+
+#include "ice_generic_flow.h"
+#include "ice_dcf_ethdev.h"
+
+static uint16_t
+ice_dcf_recv_pkts(__rte_unused void *rx_queue,
+ __rte_unused struct rte_mbuf **bufs,
+ __rte_unused uint16_t nb_pkts)
+{
+ return 0;
+}
+
+static uint16_t
+ice_dcf_xmit_pkts(__rte_unused void *tx_queue,
+ __rte_unused struct rte_mbuf **bufs,
+ __rte_unused uint16_t nb_pkts)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_start(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = ETH_LINK_UP;
+
+ return 0;
+}
+
+static void
+ice_dcf_dev_stop(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+ice_dcf_dev_configure(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_info_get(struct rte_eth_dev *dev,
+ struct rte_eth_dev_info *dev_info)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev_info->max_mac_addrs = 1;
+ dev_info->max_rx_pktlen = (uint32_t)-1;
+ dev_info->max_rx_queues = RTE_DIM(adapter->rxqs);
+ dev_info->max_tx_queues = RTE_DIM(adapter->txqs);
+
+ return 0;
+}
+
+static int
+ice_dcf_stats_get(__rte_unused struct rte_eth_dev *dev,
+ __rte_unused struct rte_eth_stats *igb_stats)
+{
+ return 0;
+}
+
+static int
+ice_dcf_stats_reset(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_disable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_enable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_disable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
+ enum rte_filter_type filter_type,
+ __rte_unused enum rte_filter_op filter_op,
+ __rte_unused void *arg)
+{
+ int ret = 0;
+
+ if (!dev)
+ return -EINVAL;
+
+ switch (filter_type) {
+ default:
+ PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+ filter_type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void
+ice_dcf_dev_close(struct rte_eth_dev *dev)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return;
+
+ dev->dev_ops = NULL;
+ dev->rx_pkt_burst = NULL;
+ dev->tx_pkt_burst = NULL;
+ dev->data->mac_addrs = NULL;
+
+ ice_dcf_uninit_hw(dev, &adapter->real_hw);
+}
+
+static void
+ice_dcf_queue_release(__rte_unused void *q)
+{
+}
+
+static int
+ice_dcf_link_update(__rte_unused struct rte_eth_dev *dev,
+ __rte_unused int wait_to_complete)
+{
+ return 0;
+}
+
+static int
+ice_dcf_rx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t rx_queue_id,
+ __rte_unused uint16_t nb_rx_desc,
+ __rte_unused unsigned int socket_id,
+ __rte_unused const struct rte_eth_rxconf *rx_conf,
+ __rte_unused struct rte_mempool *mb_pool)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev->data->rx_queues[rx_queue_id] = &adapter->rxqs[rx_queue_id];
+
+ return 0;
+}
+
+static int
+ice_dcf_tx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t tx_queue_id,
+ __rte_unused uint16_t nb_tx_desc,
+ __rte_unused unsigned int socket_id,
+ __rte_unused const struct rte_eth_txconf *tx_conf)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev->data->tx_queues[tx_queue_id] = &adapter->txqs[tx_queue_id];
+
+ return 0;
+}
+
+static const struct eth_dev_ops ice_dcf_eth_dev_ops = {
+ .dev_start = ice_dcf_dev_start,
+ .dev_stop = ice_dcf_dev_stop,
+ .dev_close = ice_dcf_dev_close,
+ .dev_configure = ice_dcf_dev_configure,
+ .dev_infos_get = ice_dcf_dev_info_get,
+ .rx_queue_setup = ice_dcf_rx_queue_setup,
+ .tx_queue_setup = ice_dcf_tx_queue_setup,
+ .rx_queue_release = ice_dcf_queue_release,
+ .tx_queue_release = ice_dcf_queue_release,
+ .link_update = ice_dcf_link_update,
+ .stats_get = ice_dcf_stats_get,
+ .stats_reset = ice_dcf_stats_reset,
+ .promiscuous_enable = ice_dcf_dev_promiscuous_enable,
+ .promiscuous_disable = ice_dcf_dev_promiscuous_disable,
+ .allmulticast_enable = ice_dcf_dev_allmulticast_enable,
+ .allmulticast_disable = ice_dcf_dev_allmulticast_disable,
+ .filter_ctrl = ice_dcf_dev_filter_ctrl,
+};
+
+static int
+ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+
+ eth_dev->dev_ops = &ice_dcf_eth_dev_ops;
+ eth_dev->rx_pkt_burst = ice_dcf_recv_pkts;
+ eth_dev->tx_pkt_burst = ice_dcf_xmit_pkts;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return 0;
+
+ eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
+ if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
+ PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
+ return -1;
+ }
+
+ rte_eth_random_addr(adapter->mac_addr.addr_bytes);
+ eth_dev->data->mac_addrs = &adapter->mac_addr;
+
+ return 0;
+}
+
+static int
+ice_dcf_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+ ice_dcf_dev_close(eth_dev);
+
+ return 0;
+}
+
+static int
+ice_dcf_cap_check_handler(__rte_unused const char *key,
+ const char *value, __rte_unused void *opaque)
+{
+ if (strcmp(value, "dcf"))
+ return -1;
+
+ return 0;
+}
+
+static int
+ice_dcf_cap_selected(struct rte_devargs *devargs)
+{
+ struct rte_kvargs *kvlist;
+ const char *key = "cap";
+ int ret = 0;
+
+ if (devargs == NULL)
+ return 0;
+
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
+ if (kvlist == NULL)
+ return 0;
+
+ if (!rte_kvargs_count(kvlist, key))
+ goto exit;
+
+ /* dcf capability selected when there's a key-value pair: cap=dcf */
+ if (rte_kvargs_process(kvlist, key,
+ ice_dcf_cap_check_handler, NULL) < 0)
+ goto exit;
+
+ ret = 1;
+
+exit:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
+static int eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
+ struct rte_pci_device *pci_dev)
+{
+ if (!ice_dcf_cap_selected(pci_dev->device.devargs))
+ return 1;
+
+ return rte_eth_dev_pci_generic_probe(pci_dev,
+ sizeof(struct ice_dcf_adapter),
+ ice_dcf_dev_init);
+}
+
+static int eth_ice_dcf_pci_remove(struct rte_pci_device *pci_dev)
+{
+ return rte_eth_dev_pci_generic_remove(pci_dev, ice_dcf_dev_uninit);
+}
+
+static const struct rte_pci_id pci_id_ice_dcf_map[] = {
+ { RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
+ { .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver rte_ice_dcf_pmd = {
+ .id_table = pci_id_ice_dcf_map,
+ .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+ .probe = eth_ice_dcf_pci_probe,
+ .remove = eth_ice_dcf_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_ice_dcf, rte_ice_dcf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_ice_dcf, pci_id_ice_dcf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ice_dcf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_ice_dcf, "cap=dcf");
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
new file mode 100644
index 000000000..0c34a0095
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_ETHDEV_H_
+#define _ICE_DCF_ETHDEV_H_
+
+#include "ice_ethdev.h"
+#include "ice_dcf.h"
+
+#define ICE_DCF_MAX_RINGS 1
+
+struct ice_dcf_queue {
+ uint64_t dummy;
+};
+
+struct ice_dcf_adapter {
+ struct ice_dcf_hw real_hw;
+ struct rte_ether_addr mac_addr;
+ struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
+ struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
+};
+
+#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index f9e897bbc..0ba9668d1 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -15,8 +15,8 @@ sources = files(
'ice_hash.c'
)
-deps += ['hash']
-includes += include_directories('base')
+deps += ['hash', 'net', 'common_iavf']
+includes += include_directories('base', '../../common/iavf')
if arch_subdir == 'x86'
sources += files('ice_rxtx_vec_sse.c')
@@ -37,4 +37,7 @@ if arch_subdir == 'x86'
endif
endif
+sources += files('ice_dcf.c',
+ 'ice_dcf_ethdev.c')
+
install_headers('rte_pmd_ice.h')
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index d295ca0a5..f3798a09f 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -185,6 +185,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += -lrte_pmd_i40e
_LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD) += -lrte_pmd_iavf
_LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += -lrte_pmd_ice
IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
ifeq ($(findstring y,$(IAVF-y)),y)
_LDLIBS-y += -lrte_common_iavf
endif
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v4 3/7] net/ice: acquire and disable the DCF capability
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
@ 2020-03-26 3:03 ` Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
` (5 subsequent siblings)
8 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 3:03 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
Since the DCF (Device Config Function) controls the flow setting of
other VFs by the mailbox with PF, for security, it needs to acquire
the DCF capability from PF when starts, and disable it when exits.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/ice/ice_dcf.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index 0a99cceb1..6ea68feb9 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -227,7 +227,7 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
int err, i;
caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
- VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED | VIRTCHNL_VF_CAP_DCF |
VF_BASE_MODE_OFFLOADS;
err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
@@ -264,6 +264,30 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
return 0;
}
+static int
+ice_dcf_mode_disable(struct ice_dcf_hw *hw)
+{
+ int err;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
+ NULL, 0);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to send msg OP_DCF_DISABLE");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
+ hw->arq_buf, ICE_DCF_AQ_BUF_SZ, NULL);
+ if (err) {
+ PMD_DRV_LOG(ERR,
+ "Failed to get response of OP_DCF_DISABLE %d",
+ err);
+ return -1;
+ }
+
+ return 0;
+}
+
static int
ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
{
@@ -467,6 +491,7 @@ ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
rte_intr_callback_unregister(intr_handle,
ice_dcf_dev_interrupt_handler, hw);
+ ice_dcf_mode_disable(hw);
iavf_shutdown_adminq(&hw->avf);
rte_free(hw->arq_buf);
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v4 4/7] net/ice: handle the AdminQ command by DCF
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Haiyue Wang
` (2 preceding siblings ...)
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 3/7] net/ice: acquire and disable the DCF capability Haiyue Wang
@ 2020-03-26 3:03 ` Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 5/7] net/ice: export the DDP definition symbols Haiyue Wang
` (4 subsequent siblings)
8 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 3:03 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) splits the AdminQ command into two
parts: one is the descriptor of AdminQ command, the other is the buffer
of AdminQ command (the descriptor has BUF flag set). When both of them
are received by the PF, the PF will handle them as one command.
And also, the filled descriptor and buffer of the response will be sent
back to DCF one by one through the virtchnl from PF.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/ice/ice_dcf.c | 65 +++++++++++++++++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 4 ++-
2 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index 6ea68feb9..baef5b8dc 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -396,6 +396,71 @@ ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
return err;
}
+int
+ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
+ void *buf, uint16_t buf_size)
+{
+ struct dcf_virtchnl_cmd desc_cmd, buff_cmd;
+ struct ice_dcf_hw *hw = dcf_hw;
+ int err = 0;
+ int i = 0;
+
+ if ((buf && !buf_size) || (!buf && buf_size) ||
+ buf_size > ICE_DCF_AQ_BUF_SZ)
+ return -EINVAL;
+
+ desc_cmd.v_op = VIRTCHNL_OP_DCF_CMD_DESC;
+ desc_cmd.req_msglen = sizeof(*desc);
+ desc_cmd.req_msg = (uint8_t *)desc;
+ desc_cmd.rsp_buflen = sizeof(*desc);
+ desc_cmd.rsp_msgbuf = (uint8_t *)desc;
+
+ if (buf == NULL)
+ return ice_dcf_execute_virtchnl_cmd(hw, &desc_cmd);
+
+ desc->flags |= rte_cpu_to_le_16(ICE_AQ_FLAG_BUF);
+
+ buff_cmd.v_op = VIRTCHNL_OP_DCF_CMD_BUFF;
+ buff_cmd.req_msglen = buf_size;
+ buff_cmd.req_msg = buf;
+ buff_cmd.rsp_buflen = buf_size;
+ buff_cmd.rsp_msgbuf = buf;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_vc_cmd_set(hw, &desc_cmd);
+ ice_dcf_vc_cmd_set(hw, &buff_cmd);
+
+ if (ice_dcf_vc_cmd_send(hw, &desc_cmd) ||
+ ice_dcf_vc_cmd_send(hw, &buff_cmd)) {
+ err = -1;
+ PMD_DRV_LOG(ERR, "fail to send OP_DCF_CMD_DESC/BUFF");
+ goto ret;
+ }
+
+ do {
+ if ((!desc_cmd.pending && !buff_cmd.pending) ||
+ (!desc_cmd.pending && desc_cmd.v_ret != IAVF_SUCCESS) ||
+ (!buff_cmd.pending && buff_cmd.v_ret != IAVF_SUCCESS))
+ break;
+
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ if (desc_cmd.v_ret != IAVF_SUCCESS || buff_cmd.v_ret != IAVF_SUCCESS) {
+ err = -1;
+ PMD_DRV_LOG(ERR,
+ "No response (%d times) or return failure (desc: %d / buff: %d)",
+ i, desc_cmd.v_ret, buff_cmd.v_ret);
+ }
+
+ret:
+ ice_dcf_aq_cmd_clear(hw, &desc_cmd);
+ ice_dcf_aq_cmd_clear(hw, &buff_cmd);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+
+ return err;
+}
+
int
ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
{
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index f44c09db2..99bd53b02 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -11,6 +11,7 @@
#include <iavf_adminq_cmd.h>
#include <iavf_type.h>
+#include "base/ice_type.h"
#include "ice_logs.h"
struct dcf_virtchnl_cmd {
@@ -45,7 +46,8 @@ struct ice_dcf_hw {
int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
struct dcf_virtchnl_cmd *cmd);
-
+int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
+ void *buf, uint16_t buf_size);
int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v4 5/7] net/ice: export the DDP definition symbols
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Haiyue Wang
` (3 preceding siblings ...)
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
@ 2020-03-26 3:03 ` Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
` (3 subsequent siblings)
8 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 3:03 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A new DCF PMD will be introduced, which runs on Intel VF hardware, and
it is a pure software design to control the advance functionality (such
as switch, ACL) for rest of the VFs.
The DCF (Device Config Function) feature shares the core functions of
the ICE PMD, like it needs to export the DDP definition symbols for the
new DCF PMD use.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Xiaolong Ye <xiaolong.ye@intel.com>
---
drivers/net/ice/ice_ethdev.c | 9 +--------
drivers/net/ice/ice_ethdev.h | 8 ++++++++
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c
index 3498a5075..3c38472de 100644
--- a/drivers/net/ice/ice_ethdev.c
+++ b/drivers/net/ice/ice_ethdev.c
@@ -67,15 +67,8 @@ static struct proto_xtr_ol_flag ice_proto_xtr_ol_flag_params[] = {
#define ICE_DFLT_OUTER_TAG_TYPE ICE_AQ_VSI_OUTER_TAG_VLAN_9100
-/* DDP package search path */
-#define ICE_PKG_FILE_DEFAULT "/lib/firmware/intel/ice/ddp/ice.pkg"
-#define ICE_PKG_FILE_UPDATES "/lib/firmware/updates/intel/ice/ddp/ice.pkg"
-#define ICE_PKG_FILE_SEARCH_PATH_DEFAULT "/lib/firmware/intel/ice/ddp/"
-#define ICE_PKG_FILE_SEARCH_PATH_UPDATES "/lib/firmware/updates/intel/ice/ddp/"
-
#define ICE_OS_DEFAULT_PKG_NAME "ICE OS Default Package"
#define ICE_COMMS_PKG_NAME "ICE COMMS Package"
-#define ICE_MAX_PKG_FILENAME_SIZE 256
#define ICE_MAX_RES_DESC_NUM 1024
int ice_logtype_init;
@@ -1833,7 +1826,7 @@ ice_pkg_file_search_path(struct rte_pci_device *pci_dev, char *pkg_file)
return 0;
}
-static enum ice_pkg_type
+enum ice_pkg_type
ice_load_pkg_type(struct ice_hw *hw)
{
enum ice_pkg_type package_type;
diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h
index da557a254..7b94a3c3e 100644
--- a/drivers/net/ice/ice_ethdev.h
+++ b/drivers/net/ice/ice_ethdev.h
@@ -42,6 +42,13 @@
#define ICE_MAX_PKT_TYPE 1024
+/* DDP package search path */
+#define ICE_PKG_FILE_DEFAULT "/lib/firmware/intel/ice/ddp/ice.pkg"
+#define ICE_PKG_FILE_UPDATES "/lib/firmware/updates/intel/ice/ddp/ice.pkg"
+#define ICE_PKG_FILE_SEARCH_PATH_DEFAULT "/lib/firmware/intel/ice/ddp/"
+#define ICE_PKG_FILE_SEARCH_PATH_UPDATES "/lib/firmware/updates/intel/ice/ddp/"
+#define ICE_MAX_PKG_FILENAME_SIZE 256
+
/**
* vlan_id is a 12 bit number.
* The VFTA array is actually a 4096 bit array, 128 of 32bit elements.
@@ -457,6 +464,7 @@ struct ice_vsi_vlan_pvid_info {
#define ICE_PF_TO_ETH_DEV(pf) \
(((struct ice_pf *)pf)->adapter->eth_dev)
+enum ice_pkg_type ice_load_pkg_type(struct ice_hw *hw);
struct ice_vsi *
ice_setup_vsi(struct ice_pf *pf, enum ice_vsi_type type);
int
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v4 6/7] net/ice: handle the PF initialization by DCF
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Haiyue Wang
` (4 preceding siblings ...)
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 5/7] net/ice: export the DDP definition symbols Haiyue Wang
@ 2020-03-26 3:03 ` Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
` (2 subsequent siblings)
8 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 3:03 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) works at the user PF level, it can't
access the real PF hardware directly. So it will pass through the PF's
AdminQ command by the DCF's mailbox.
And the DCF is mainly used to control the flow setting of other VFs, so
it only needs to initialize some core functions related to the flow.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/ice/Makefile | 1 +
drivers/net/ice/ice_dcf.c | 7 +-
drivers/net/ice/ice_dcf.h | 3 +
drivers/net/ice/ice_dcf_ethdev.c | 10 +-
drivers/net/ice/ice_dcf_ethdev.h | 11 +-
drivers/net/ice/ice_dcf_parent.c | 263 +++++++++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
7 files changed, 292 insertions(+), 6 deletions(-)
create mode 100644 drivers/net/ice/ice_dcf_parent.c
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index f493c9ed7..3ecc72219 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -88,6 +88,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_parent.c
# install this header file
SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index baef5b8dc..c799cdf83 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -124,8 +124,13 @@ ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
}
v_op = rte_le_to_cpu_32(info->desc.cookie_high);
- if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+ if (v_op == VIRTCHNL_OP_EVENT) {
+ if (hw->vc_event_msg_cb != NULL)
+ hw->vc_event_msg_cb(hw,
+ info->msg_buf,
+ info->msg_len);
return;
+ }
v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index 99bd53b02..ecd6303a0 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -36,6 +36,9 @@ struct ice_dcf_hw {
rte_spinlock_t vc_cmd_send_lock;
rte_spinlock_t vc_cmd_queue_lock;
TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+ void (*vc_event_msg_cb)(struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen);
+
uint8_t *arq_buf;
struct virtchnl_version_info virtchnl_version;
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
index 23f82a487..af94caeff 100644
--- a/drivers/net/ice/ice_dcf_ethdev.c
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -145,8 +145,8 @@ ice_dcf_dev_close(struct rte_eth_dev *dev)
dev->dev_ops = NULL;
dev->rx_pkt_burst = NULL;
dev->tx_pkt_burst = NULL;
- dev->data->mac_addrs = NULL;
+ ice_dcf_uninit_parent_adapter(dev);
ice_dcf_uninit_hw(dev, &adapter->real_hw);
}
@@ -225,13 +225,17 @@ ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+ adapter->real_hw.vc_event_msg_cb = ice_dcf_handle_pf_event_msg;
if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
return -1;
}
- rte_eth_random_addr(adapter->mac_addr.addr_bytes);
- eth_dev->data->mac_addrs = &adapter->mac_addr;
+ if (ice_dcf_init_parent_adapter(eth_dev) != 0) {
+ PMD_INIT_LOG(ERR, "Failed to init DCF parent adapter");
+ ice_dcf_uninit_hw(eth_dev, &adapter->real_hw);
+ return -1;
+ }
return 0;
}
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
index 0c34a0095..e60e808d8 100644
--- a/drivers/net/ice/ice_dcf_ethdev.h
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -5,6 +5,9 @@
#ifndef _ICE_DCF_ETHDEV_H_
#define _ICE_DCF_ETHDEV_H_
+#include "base/ice_common.h"
+#include "base/ice_adminq_cmd.h"
+
#include "ice_ethdev.h"
#include "ice_dcf.h"
@@ -15,10 +18,16 @@ struct ice_dcf_queue {
};
struct ice_dcf_adapter {
+ struct ice_adapter parent; /* Must be first */
+
struct ice_dcf_hw real_hw;
- struct rte_ether_addr mac_addr;
struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
};
+void ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen);
+int ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev);
+void ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev);
+
#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
new file mode 100644
index 000000000..138838a73
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_parent.c
@@ -0,0 +1,263 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "ice_dcf_ethdev.h"
+
+void
+ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen)
+{
+ struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
+
+ if (msglen < sizeof(struct virtchnl_pf_event)) {
+ PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen);
+ return;
+ }
+
+ switch (pf_msg->event) {
+ case VIRTCHNL_EVENT_RESET_IMPENDING:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
+ break;
+ case VIRTCHNL_EVENT_LINK_CHANGE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
+ break;
+ case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
+ break;
+ }
+}
+
+static int
+ice_dcf_init_parent_hw(struct ice_hw *hw)
+{
+ struct ice_aqc_get_phy_caps_data *pcaps;
+ enum ice_status status;
+
+ status = ice_aq_get_fw_ver(hw, NULL);
+ if (status)
+ return status;
+
+ status = ice_get_caps(hw);
+ if (status)
+ return status;
+
+ hw->port_info = (struct ice_port_info *)
+ ice_malloc(hw, sizeof(*hw->port_info));
+ if (!hw->port_info)
+ return ICE_ERR_NO_MEMORY;
+
+ /* set the back pointer to HW */
+ hw->port_info->hw = hw;
+
+ /* Initialize port_info struct with switch configuration data */
+ status = ice_get_initial_sw_cfg(hw);
+ if (status)
+ goto err_unroll_alloc;
+
+ pcaps = (struct ice_aqc_get_phy_caps_data *)
+ ice_malloc(hw, sizeof(*pcaps));
+ if (!pcaps) {
+ status = ICE_ERR_NO_MEMORY;
+ goto err_unroll_alloc;
+ }
+
+ /* Initialize port_info struct with PHY capabilities */
+ status = ice_aq_get_phy_caps(hw->port_info, false,
+ ICE_AQC_REPORT_TOPO_CAP, pcaps, NULL);
+ ice_free(hw, pcaps);
+ if (status)
+ goto err_unroll_alloc;
+
+ /* Initialize port_info struct with link information */
+ status = ice_aq_get_link_info(hw->port_info, false, NULL, NULL);
+ if (status)
+ goto err_unroll_alloc;
+
+ status = ice_init_fltr_mgmt_struct(hw);
+ if (status)
+ goto err_unroll_alloc;
+
+ status = ice_init_hw_tbls(hw);
+ if (status)
+ goto err_unroll_fltr_mgmt_struct;
+
+ PMD_INIT_LOG(INFO,
+ "firmware %d.%d.%d api %d.%d.%d build 0x%08x",
+ hw->fw_maj_ver, hw->fw_min_ver, hw->fw_patch,
+ hw->api_maj_ver, hw->api_min_ver, hw->api_patch,
+ hw->fw_build);
+
+ return ICE_SUCCESS;
+
+err_unroll_fltr_mgmt_struct:
+ ice_cleanup_fltr_mgmt_struct(hw);
+err_unroll_alloc:
+ ice_free(hw, hw->port_info);
+ hw->port_info = NULL;
+
+ return status;
+}
+
+static void ice_dcf_uninit_parent_hw(struct ice_hw *hw)
+{
+ ice_cleanup_fltr_mgmt_struct(hw);
+
+ ice_free_seg(hw);
+ ice_free_hw_tbls(hw);
+
+ ice_free(hw, hw->port_info);
+ hw->port_info = NULL;
+
+ ice_clear_all_vsi_ctx(hw);
+}
+
+static int
+ice_dcf_request_pkg_name(struct ice_hw *hw, char *pkg_name)
+{
+ struct ice_dcf_adapter *dcf_adapter =
+ container_of(hw, struct ice_dcf_adapter, parent.hw);
+
+ /* TODO: check with DSN firstly by iAVF */
+ PMD_INIT_LOG(DEBUG,
+ "DCF VSI_ID = %u",
+ dcf_adapter->real_hw.vsi_id);
+
+ snprintf(pkg_name,
+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_UPDATES);
+ if (!access(pkg_name, 0))
+ return 0;
+
+ snprintf(pkg_name,
+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_DEFAULT);
+ if (!access(pkg_name, 0))
+ return 0;
+
+ return -1;
+}
+
+static int
+ice_dcf_load_pkg(struct ice_hw *hw)
+{
+ char pkg_name[ICE_MAX_PKG_FILENAME_SIZE];
+ uint8_t *pkg_buf;
+ uint32_t buf_len;
+ struct stat st;
+ FILE *fp;
+ int err;
+
+ if (ice_dcf_request_pkg_name(hw, pkg_name)) {
+ PMD_INIT_LOG(ERR, "Failed to locate the package file");
+ return -ENOENT;
+ }
+
+ PMD_INIT_LOG(DEBUG, "DDP package name: %s", pkg_name);
+
+ err = stat(pkg_name, &st);
+ if (err) {
+ PMD_INIT_LOG(ERR, "Failed to get file status");
+ return err;
+ }
+
+ buf_len = st.st_size;
+ pkg_buf = rte_malloc(NULL, buf_len, 0);
+ if (!pkg_buf) {
+ PMD_INIT_LOG(ERR, "failed to allocate buffer of size %u for package",
+ buf_len);
+ return -1;
+ }
+
+ fp = fopen(pkg_name, "rb");
+ if (!fp) {
+ PMD_INIT_LOG(ERR, "failed to open file: %s", pkg_name);
+ err = -1;
+ goto ret;
+ }
+
+ err = fread(pkg_buf, buf_len, 1, fp);
+ fclose(fp);
+ if (err != 1) {
+ PMD_INIT_LOG(ERR, "failed to read package data");
+ err = -1;
+ goto ret;
+ }
+
+ err = ice_copy_and_init_pkg(hw, pkg_buf, buf_len);
+ if (err)
+ PMD_INIT_LOG(ERR, "ice_copy_and_init_hw failed: %d", err);
+
+ret:
+ rte_free(pkg_buf);
+ return err;
+}
+
+int
+ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+ struct ice_adapter *parent_adapter = &adapter->parent;
+ struct ice_hw *parent_hw = &parent_adapter->hw;
+ struct ice_dcf_hw *hw = &adapter->real_hw;
+ const struct rte_ether_addr *mac;
+ int err;
+
+ parent_adapter->eth_dev = eth_dev;
+ parent_adapter->pf.adapter = parent_adapter;
+ parent_adapter->pf.dev_data = eth_dev->data;
+ parent_hw->back = parent_adapter;
+ parent_hw->mac_type = ICE_MAC_GENERIC;
+ parent_hw->vendor_id = ICE_INTEL_VENDOR_ID;
+
+ ice_init_lock(&parent_hw->adminq.sq_lock);
+ ice_init_lock(&parent_hw->adminq.rq_lock);
+ parent_hw->aq_send_cmd_fn = ice_dcf_send_aq_cmd;
+ parent_hw->aq_send_cmd_param = &adapter->real_hw;
+ parent_hw->dcf_enabled = true;
+
+ err = ice_dcf_init_parent_hw(parent_hw);
+ if (err) {
+ PMD_INIT_LOG(ERR, "failed to init the DCF parent hardware with error %d",
+ err);
+ return err;
+ }
+
+ err = ice_dcf_load_pkg(parent_hw);
+ if (err) {
+ PMD_INIT_LOG(ERR, "failed to load package with error %d",
+ err);
+ goto uninit_hw;
+ }
+ parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
+
+ mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
+ if (rte_is_valid_assigned_ether_addr(mac))
+ rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
+ else
+ rte_eth_random_addr(parent_adapter->pf.dev_addr.addr_bytes);
+
+ eth_dev->data->mac_addrs = &parent_adapter->pf.dev_addr;
+
+ return 0;
+
+uninit_hw:
+ ice_dcf_uninit_parent_hw(parent_hw);
+ return err;
+}
+
+void
+ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+ struct ice_adapter *parent_adapter = &adapter->parent;
+ struct ice_hw *parent_hw = &parent_adapter->hw;
+
+ eth_dev->data->mac_addrs = NULL;
+
+ ice_dcf_uninit_parent_hw(parent_hw);
+}
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index 0ba9668d1..7e9037f3b 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -38,6 +38,7 @@ if arch_subdir == 'x86'
endif
sources += files('ice_dcf.c',
- 'ice_dcf_ethdev.c')
+ 'ice_dcf_ethdev.c',
+ 'ice_dcf_parent.c')
install_headers('rte_pmd_ice.h')
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v4 7/7] net/ice: get the VF hardware index in DCF
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Haiyue Wang
` (5 preceding siblings ...)
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
@ 2020-03-26 3:03 ` Haiyue Wang
2020-03-26 4:11 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Zhang, Qi Z
2020-03-26 5:05 ` Ye Xiaolong
8 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 3:03 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) needs the hardware index of the VFs to
control the flow setting. And also if the VF resets, the index may be
changed, so it should handle this in VF reset event.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
drivers/net/ice/ice_dcf.c | 89 +++++++++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 6 +++
drivers/net/ice/ice_dcf_parent.c | 90 +++++++++++++++++++++++++++++++-
3 files changed, 184 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index c799cdf83..4c30f0e60 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -269,6 +269,65 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
return 0;
}
+static int
+ice_dcf_get_vf_vsi_map(struct ice_dcf_hw *hw)
+{
+ struct virtchnl_dcf_vsi_map *vsi_map;
+ uint32_t valid_msg_len;
+ uint16_t len;
+ int err;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
+ NULL, 0);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to send msg OP_DCF_GET_VSI_MAP");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
+ hw->arq_buf, ICE_DCF_AQ_BUF_SZ,
+ &len);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to get response of OP_DCF_GET_VSI_MAP");
+ return err;
+ }
+
+ vsi_map = (struct virtchnl_dcf_vsi_map *)hw->arq_buf;
+ valid_msg_len = (vsi_map->num_vfs - 1) * sizeof(vsi_map->vf_vsi[0]) +
+ sizeof(*vsi_map);
+ if (len != valid_msg_len) {
+ PMD_DRV_LOG(ERR, "invalid vf vsi map response with length %u",
+ len);
+ return -EINVAL;
+ }
+
+ if (hw->num_vfs != 0 && hw->num_vfs != vsi_map->num_vfs) {
+ PMD_DRV_LOG(ERR, "The number VSI map (%u) doesn't match the number of VFs (%u)",
+ vsi_map->num_vfs, hw->num_vfs);
+ return -EINVAL;
+ }
+
+ len = vsi_map->num_vfs * sizeof(vsi_map->vf_vsi[0]);
+
+ if (!hw->vf_vsi_map) {
+ hw->vf_vsi_map = rte_zmalloc("vf_vsi_ctx", len, 0);
+ if (!hw->vf_vsi_map) {
+ PMD_DRV_LOG(ERR, "Failed to alloc memory for VSI context");
+ return -ENOMEM;
+ }
+
+ hw->num_vfs = vsi_map->num_vfs;
+ }
+
+ if (!memcmp(hw->vf_vsi_map, vsi_map->vf_vsi, len)) {
+ PMD_DRV_LOG(DEBUG, "VF VSI map doesn't change");
+ return 1;
+ }
+
+ rte_memcpy(hw->vf_vsi_map, vsi_map->vf_vsi, len);
+ return 0;
+}
+
static int
ice_dcf_mode_disable(struct ice_dcf_hw *hw)
{
@@ -466,6 +525,28 @@ ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
return err;
}
+int
+ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(hw->eth_dev);
+ int err = 0;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+
+ rte_intr_disable(&pci_dev->intr_handle);
+ ice_dcf_disable_irq0(hw);
+
+ if (ice_dcf_get_vf_resource(hw) || ice_dcf_get_vf_vsi_map(hw))
+ err = -1;
+
+ rte_intr_enable(&pci_dev->intr_handle);
+ ice_dcf_enable_irq0(hw);
+
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+
+ return err;
+}
+
int
ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
{
@@ -533,6 +614,13 @@ ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
goto err_alloc;
}
+ if (ice_dcf_get_vf_vsi_map(hw) < 0) {
+ PMD_INIT_LOG(ERR, "Failed to get VF VSI map");
+ ice_dcf_mode_disable(hw);
+ goto err_alloc;
+ }
+
+ hw->eth_dev = eth_dev;
rte_intr_callback_register(&pci_dev->intr_handle,
ice_dcf_dev_interrupt_handler, hw);
rte_intr_enable(&pci_dev->intr_handle);
@@ -565,5 +653,6 @@ ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
iavf_shutdown_adminq(&hw->avf);
rte_free(hw->arq_buf);
+ rte_free(hw->vf_vsi_map);
rte_free(hw->vf_res);
}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index ecd6303a0..d2e447b48 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -41,16 +41,22 @@ struct ice_dcf_hw {
uint8_t *arq_buf;
+ uint16_t num_vfs;
+ uint16_t *vf_vsi_map;
+
struct virtchnl_version_info virtchnl_version;
struct virtchnl_vf_resource *vf_res; /* VF resource */
struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
uint16_t vsi_id;
+
+ struct rte_eth_dev *eth_dev;
};
int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
struct dcf_virtchnl_cmd *cmd);
int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
void *buf, uint16_t buf_size);
+int ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw);
int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
index 138838a73..ff08292a1 100644
--- a/drivers/net/ice/ice_dcf_parent.c
+++ b/drivers/net/ice/ice_dcf_parent.c
@@ -3,15 +3,92 @@
*/
#include <sys/types.h>
#include <sys/stat.h>
+#include <pthread.h>
#include <unistd.h>
+#include <rte_spinlock.h>
+
#include "ice_dcf_ethdev.h"
+#define ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL 100000 /* us */
+static rte_spinlock_t vsi_update_lock = RTE_SPINLOCK_INITIALIZER;
+
+static __rte_always_inline void
+ice_dcf_update_vsi_ctx(struct ice_hw *hw, uint16_t vsi_handle,
+ uint16_t vsi_map)
+{
+ struct ice_vsi_ctx *vsi_ctx;
+
+ if (unlikely(vsi_handle >= ICE_MAX_VSI)) {
+ PMD_DRV_LOG(ERR, "Invalid vsi handle %u", vsi_handle);
+ return;
+ }
+
+ vsi_ctx = hw->vsi_ctx[vsi_handle];
+
+ if (vsi_map & VIRTCHNL_DCF_VF_VSI_VALID) {
+ if (!vsi_ctx) {
+ vsi_ctx = ice_malloc(hw, sizeof(*vsi_ctx));
+ if (!vsi_ctx) {
+ PMD_DRV_LOG(ERR, "No memory for vsi context %u",
+ vsi_handle);
+ return;
+ }
+ }
+
+ vsi_ctx->vsi_num = (vsi_map & VIRTCHNL_DCF_VF_VSI_ID_M) >>
+ VIRTCHNL_DCF_VF_VSI_ID_S;
+ hw->vsi_ctx[vsi_handle] = vsi_ctx;
+
+ PMD_DRV_LOG(DEBUG, "VF%u is assigned with vsi number %u",
+ vsi_handle, vsi_ctx->vsi_num);
+ } else {
+ hw->vsi_ctx[vsi_handle] = NULL;
+
+ ice_free(hw, vsi_ctx);
+
+ PMD_DRV_LOG(NOTICE, "VF%u is disabled", vsi_handle);
+ }
+}
+
+static void
+ice_dcf_update_vf_vsi_map(struct ice_hw *hw, uint16_t num_vfs,
+ uint16_t *vf_vsi_map)
+{
+ uint16_t vf_id;
+
+ for (vf_id = 0; vf_id < num_vfs; vf_id++)
+ ice_dcf_update_vsi_ctx(hw, vf_id, vf_vsi_map[vf_id]);
+}
+
+static void*
+ice_dcf_vsi_update_service_handler(void *param)
+{
+ struct ice_dcf_hw *hw = param;
+
+ usleep(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL);
+
+ rte_spinlock_lock(&vsi_update_lock);
+
+ if (!ice_dcf_handle_vsi_update_event(hw)) {
+ struct ice_dcf_adapter *dcf_ad =
+ container_of(hw, struct ice_dcf_adapter, real_hw);
+
+ ice_dcf_update_vf_vsi_map(&dcf_ad->parent.hw,
+ hw->num_vfs, hw->vf_vsi_map);
+ }
+
+ rte_spinlock_unlock(&vsi_update_lock);
+
+ return NULL;
+}
+
void
-ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
+ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
uint8_t *msg, uint16_t msglen)
{
struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
+ pthread_t thread;
if (msglen < sizeof(struct virtchnl_pf_event)) {
PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen);
@@ -21,6 +98,8 @@ ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
switch (pf_msg->event) {
case VIRTCHNL_EVENT_RESET_IMPENDING:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
+ pthread_create(&thread, NULL,
+ ice_dcf_vsi_update_service_handler, dcf_hw);
break;
case VIRTCHNL_EVENT_LINK_CHANGE:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
@@ -28,6 +107,13 @@ ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
break;
+ case VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE event : VF%u with VSI num %u",
+ pf_msg->event_data.vf_vsi_map.vf_id,
+ pf_msg->event_data.vf_vsi_map.vsi_id);
+ pthread_create(&thread, NULL,
+ ice_dcf_vsi_update_service_handler, dcf_hw);
+ break;
default:
PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
break;
@@ -235,6 +321,8 @@ ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
}
parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
+ ice_dcf_update_vf_vsi_map(parent_hw, hw->num_vfs, hw->vf_vsi_map);
+
mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
if (rte_is_valid_assigned_ether_addr(mac))
rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v4 1/7] net/iavf: stop the PCI probe in DCF mode
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
@ 2020-03-26 3:28 ` Wu, Jingjing
0 siblings, 0 replies; 94+ messages in thread
From: Wu, Jingjing @ 2020-03-26 3:28 UTC (permalink / raw)
To: Wang, Haiyue, dev, Ye, Xiaolong, Zhang, Qi Z, Yang, Qiming, Xing, Beilei
Cc: Zhao1, Wei, Wang, Haiyue
-----Original Message-----
From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Haiyue Wang
Sent: Thursday, March 26, 2020 11:04 AM
To: dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue <haiyue.wang@intel.com>
Subject: [dpdk-dev] [PATCH v4 1/7] net/iavf: stop the PCI probe in DCF mode
A new DCF PMD will be introduced, which runs on Intel VF hardware, and it is a pure software design to control the advance functionality (such as switch, ACL) for rest of the VFs.
So if the DCF (Device Config Function) mode is specified by the devarg 'cap=dcf', then it will stop the PCI probe in the iavf PMD.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Reviewed-by: Xiaolong Ye <xiaolong.ye@intel.com>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Haiyue Wang
` (6 preceding siblings ...)
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
@ 2020-03-26 4:11 ` Zhang, Qi Z
2020-03-26 5:05 ` Ye Xiaolong
8 siblings, 0 replies; 94+ messages in thread
From: Zhang, Qi Z @ 2020-03-26 4:11 UTC (permalink / raw)
To: Wang, Haiyue, dev, Ye, Xiaolong, Yang, Qiming, Xing, Beilei; +Cc: Zhao1, Wei
> -----Original Message-----
> From: Wang, Haiyue <haiyue.wang@intel.com>
> Sent: Thursday, March 26, 2020 11:04 AM
> To: dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang, Qi Z
> <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing, Beilei
> <beilei.xing@intel.com>
> Cc: Zhao1, Wei <wei.zhao1@intel.com>; Wang, Haiyue
> <haiyue.wang@intel.com>
> Subject: [PATCH v4 0/7] add Intel DCF PMD support
>
> A DCF (Device Config Function) based approach is proposed where a device
> bound to the device's VF0 can act as a sole controlling entity to exercise
> advance functionality (such as switch, ACL) for rest of the VFs.
>
> The DCF works as a standalone PMD to support this function, which shares
> the ice PMD flow control core function and the iavf virtchnl mailbox core
> module.
>
> v4:
> Change the alarm handler to thread service, since it will need to do more
> work.
>
> v3:
> 1. Fixed the error log message format.
> 2. Fixed some memory allocation check.
> 3. Fixed some code style issue and commmit message description.
>
> v2:
> 1. update the iavf patchset link.
> 2. split more patches for making this work be more understandable
> 3. fix the log function usage, devargs checking from v1.
>
> Haiyue Wang (7):
> net/iavf: stop the PCI probe in DCF mode
> net/ice: add the DCF hardware initialization
> net/ice: acquire and disable the DCF capability
> net/ice: handle the AdminQ command by DCF
> net/ice: export the DDP definition symbols
> net/ice: handle the PF initialization by DCF
> net/ice: get the VF hardware index in DCF
>
> doc/guides/nics/ice.rst | 47 ++
> doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> doc/guides/rel_notes/release_20_05.rst | 5 +
> drivers/common/Makefile | 1 +
> drivers/net/iavf/iavf_ethdev.c | 43 ++
> drivers/net/ice/Makefile | 6 +
> drivers/net/ice/ice_dcf.c | 658
> +++++++++++++++++++++++++
> drivers/net/ice/ice_dcf.h | 63 +++
> drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
> drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> drivers/net/ice/ice_dcf_parent.c | 351 +++++++++++++
> drivers/net/ice/ice_ethdev.c | 9 +-
> drivers/net/ice/ice_ethdev.h | 8 +
> drivers/net/ice/meson.build | 8 +-
> mk/rte.app.mk | 1 +
> 15 files changed, 1544 insertions(+), 10 deletions(-) create mode 100644
> doc/guides/nics/img/ice_dcf.png create mode 100644
> drivers/net/ice/ice_dcf.c create mode 100644 drivers/net/ice/ice_dcf.h
> create mode 100644 drivers/net/ice/ice_dcf_ethdev.c create mode 100644
> drivers/net/ice/ice_dcf_ethdev.h create mode 100644
> drivers/net/ice/ice_dcf_parent.c
>
> --
> 2.26.0
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Haiyue Wang
` (7 preceding siblings ...)
2020-03-26 4:11 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Zhang, Qi Z
@ 2020-03-26 5:05 ` Ye Xiaolong
2020-03-26 5:26 ` Wang, Haiyue
8 siblings, 1 reply; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-26 5:05 UTC (permalink / raw)
To: Haiyue Wang; +Cc: dev, qi.z.zhang, qiming.yang, beilei.xing, wei.zhao1
There is build error about this patchset, could you double check?
OS: CENTOS77-64
Target: x86_64-native-linuxapp-gcc+shared
LD librte_pmd_ice.so.20.0.2
CC sfc_ev.o
ice_dcf_parent.o: In function `ice_dcf_handle_pf_event_msg':
ice_dcf_parent.c:(.text+0x556): undefined reference to `pthread_create'
collect2: error: ld returned 1 exit status
make[6]: *** [librte_pmd_ice.so.20.0.2] Error 1
make[5]: *** [ice] Error 2
make[5]: *** Waiting for unfinished jobs....
CC sfc_port.o
CC bnxt_rxtx_vec_sse.o
CC sfc_rx.o
CC nicvf_hw.o
--
CC medford2_nic.o
LD librte_pmd_octeontx2.so.20.0.2
INSTALL-LIB librte_pmd_octeontx2.so.20.0.2
LD librte_pmd_sfc_efx.so.20.0.2
INSTALL-LIB librte_pmd_sfc_efx.so.20.0.2
make[4]: *** [net] Error 2
make[3]: *** [drivers] Error 2
make[2]: *** [all] Error 2
make[1]: *** [pre_install] Error 2
make: *** [install] Error 2
http://mails.dpdk.org/archives/test-report/2020-March/122145.html
On 03/26, Haiyue Wang wrote:
>A DCF (Device Config Function) based approach is proposed where a device
>bound to the device's VF0 can act as a sole controlling entity to exercise
>advance functionality (such as switch, ACL) for rest of the VFs.
>
>The DCF works as a standalone PMD to support this function, which shares the
>ice PMD flow control core function and the iavf virtchnl mailbox core module.
>
>v4:
> Change the alarm handler to thread service, since it will need to do more
> work.
>
>v3:
> 1. Fixed the error log message format.
> 2. Fixed some memory allocation check.
> 3. Fixed some code style issue and commmit message description.
>
>v2:
> 1. update the iavf patchset link.
> 2. split more patches for making this work be more understandable
> 3. fix the log function usage, devargs checking from v1.
>
>Haiyue Wang (7):
> net/iavf: stop the PCI probe in DCF mode
> net/ice: add the DCF hardware initialization
> net/ice: acquire and disable the DCF capability
> net/ice: handle the AdminQ command by DCF
> net/ice: export the DDP definition symbols
> net/ice: handle the PF initialization by DCF
> net/ice: get the VF hardware index in DCF
>
> doc/guides/nics/ice.rst | 47 ++
> doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> doc/guides/rel_notes/release_20_05.rst | 5 +
> drivers/common/Makefile | 1 +
> drivers/net/iavf/iavf_ethdev.c | 43 ++
> drivers/net/ice/Makefile | 6 +
> drivers/net/ice/ice_dcf.c | 658 +++++++++++++++++++++++++
> drivers/net/ice/ice_dcf.h | 63 +++
> drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
> drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> drivers/net/ice/ice_dcf_parent.c | 351 +++++++++++++
> drivers/net/ice/ice_ethdev.c | 9 +-
> drivers/net/ice/ice_ethdev.h | 8 +
> drivers/net/ice/meson.build | 8 +-
> mk/rte.app.mk | 1 +
> 15 files changed, 1544 insertions(+), 10 deletions(-)
> create mode 100644 doc/guides/nics/img/ice_dcf.png
> create mode 100644 drivers/net/ice/ice_dcf.c
> create mode 100644 drivers/net/ice/ice_dcf.h
> create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
> create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
> create mode 100644 drivers/net/ice/ice_dcf_parent.c
>
>--
>2.26.0
>
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support
2020-03-26 5:05 ` Ye Xiaolong
@ 2020-03-26 5:26 ` Wang, Haiyue
0 siblings, 0 replies; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-26 5:26 UTC (permalink / raw)
To: Ye, Xiaolong; +Cc: dev, Zhang, Qi Z, Yang, Qiming, Xing, Beilei, Zhao1, Wei
Hi Xiaolong,
Yes, found the root cause. Will fix it next version.
BR,
Haiyue
> -----Original Message-----
> From: Ye, Xiaolong <xiaolong.ye@intel.com>
> Sent: Thursday, March 26, 2020 13:06
> To: Wang, Haiyue <haiyue.wang@intel.com>
> Cc: dev@dpdk.org; Zhang, Qi Z <qi.z.zhang@intel.com>; Yang, Qiming <qiming.yang@intel.com>; Xing,
> Beilei <beilei.xing@intel.com>; Zhao1, Wei <wei.zhao1@intel.com>
> Subject: Re: [PATCH v4 0/7] add Intel DCF PMD support
>
>
> There is build error about this patchset, could you double check?
>
>
> OS: CENTOS77-64
> Target: x86_64-native-linuxapp-gcc+shared
> LD librte_pmd_ice.so.20.0.2
> CC sfc_ev.o
> ice_dcf_parent.o: In function `ice_dcf_handle_pf_event_msg':
> ice_dcf_parent.c:(.text+0x556): undefined reference to `pthread_create'
> collect2: error: ld returned 1 exit status
> make[6]: *** [librte_pmd_ice.so.20.0.2] Error 1
> make[5]: *** [ice] Error 2
> make[5]: *** Waiting for unfinished jobs....
> CC sfc_port.o
> CC bnxt_rxtx_vec_sse.o
> CC sfc_rx.o
> CC nicvf_hw.o
> --
> CC medford2_nic.o
> LD librte_pmd_octeontx2.so.20.0.2
> INSTALL-LIB librte_pmd_octeontx2.so.20.0.2
> LD librte_pmd_sfc_efx.so.20.0.2
> INSTALL-LIB librte_pmd_sfc_efx.so.20.0.2
> make[4]: *** [net] Error 2
> make[3]: *** [drivers] Error 2
> make[2]: *** [all] Error 2
> make[1]: *** [pre_install] Error 2
> make: *** [install] Error 2
>
> http://mails.dpdk.org/archives/test-report/2020-March/122145.html
>
> On 03/26, Haiyue Wang wrote:
> >A DCF (Device Config Function) based approach is proposed where a device
> >bound to the device's VF0 can act as a sole controlling entity to exercise
> >advance functionality (such as switch, ACL) for rest of the VFs.
> >
> >The DCF works as a standalone PMD to support this function, which shares the
> >ice PMD flow control core function and the iavf virtchnl mailbox core module.
> >
> >v4:
> > Change the alarm handler to thread service, since it will need to do more
> > work.
> >
> >v3:
> > 1. Fixed the error log message format.
> > 2. Fixed some memory allocation check.
> > 3. Fixed some code style issue and commmit message description.
> >
> >v2:
> > 1. update the iavf patchset link.
> > 2. split more patches for making this work be more understandable
> > 3. fix the log function usage, devargs checking from v1.
> >
> >Haiyue Wang (7):
> > net/iavf: stop the PCI probe in DCF mode
> > net/ice: add the DCF hardware initialization
> > net/ice: acquire and disable the DCF capability
> > net/ice: handle the AdminQ command by DCF
> > net/ice: export the DDP definition symbols
> > net/ice: handle the PF initialization by DCF
> > net/ice: get the VF hardware index in DCF
> >
> > doc/guides/nics/ice.rst | 47 ++
> > doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> > doc/guides/rel_notes/release_20_05.rst | 5 +
> > drivers/common/Makefile | 1 +
> > drivers/net/iavf/iavf_ethdev.c | 43 ++
> > drivers/net/ice/Makefile | 6 +
> > drivers/net/ice/ice_dcf.c | 658 +++++++++++++++++++++++++
> > drivers/net/ice/ice_dcf.h | 63 +++
> > drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
> > drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> > drivers/net/ice/ice_dcf_parent.c | 351 +++++++++++++
> > drivers/net/ice/ice_ethdev.c | 9 +-
> > drivers/net/ice/ice_ethdev.h | 8 +
> > drivers/net/ice/meson.build | 8 +-
> > mk/rte.app.mk | 1 +
> > 15 files changed, 1544 insertions(+), 10 deletions(-)
> > create mode 100644 doc/guides/nics/img/ice_dcf.png
> > create mode 100644 drivers/net/ice/ice_dcf.c
> > create mode 100644 drivers/net/ice/ice_dcf.h
> > create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
> > create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
> > create mode 100644 drivers/net/ice/ice_dcf_parent.c
> >
> >--
> >2.26.0
> >
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v5 0/7] add Intel DCF PMD support
2020-03-09 14:14 [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support Haiyue Wang
` (7 preceding siblings ...)
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Haiyue Wang
@ 2020-03-26 7:15 ` Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
` (6 more replies)
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Haiyue Wang
9 siblings, 7 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 7:15 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A DCF (Device Config Function) based approach is proposed where a device
bound to the device's VF0 can act as a sole controlling entity to exercise
advance functionality (such as switch, ACL) for rest of the VFs.
The DCF works as a standalone PMD to support this function, which shares the
ice PMD flow control core function and the iavf virtchnl mailbox core module.
v5:
Fixed the shared module compile errror.
v4:
Change the alarm handler to thread service, since it will need to do more
work.
v3:
1. Fixed the error log message format.
2. Fixed some memory allocation check.
3. Fixed some code style issue and commmit message description.
v2:
1. update the iavf patchset link.
2. split more patches for making this work be more understandable
3. fix the log function usage, devargs checking from v1.
Haiyue Wang (7):
net/iavf: stop the PCI probe in DCF mode
net/ice: add the DCF hardware initialization
net/ice: acquire and disable the DCF capability
net/ice: handle the AdminQ command by DCF
net/ice: export the DDP definition symbols
net/ice: handle the PF initialization by DCF
net/ice: get the VF hardware index in DCF
doc/guides/nics/ice.rst | 47 ++
doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
doc/guides/rel_notes/release_20_05.rst | 5 +
drivers/common/Makefile | 1 +
drivers/net/iavf/iavf_ethdev.c | 43 ++
drivers/net/ice/Makefile | 7 +
drivers/net/ice/ice_dcf.c | 658 +++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 63 +++
drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
drivers/net/ice/ice_dcf_ethdev.h | 33 ++
drivers/net/ice/ice_dcf_parent.c | 351 +++++++++++++
drivers/net/ice/ice_ethdev.c | 9 +-
drivers/net/ice/ice_ethdev.h | 8 +
drivers/net/ice/meson.build | 8 +-
mk/rte.app.mk | 1 +
15 files changed, 1545 insertions(+), 10 deletions(-)
create mode 100644 doc/guides/nics/img/ice_dcf.png
create mode 100644 drivers/net/ice/ice_dcf.c
create mode 100644 drivers/net/ice/ice_dcf.h
create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
create mode 100644 drivers/net/ice/ice_dcf_parent.c
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v5 1/7] net/iavf: stop the PCI probe in DCF mode
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 " Haiyue Wang
@ 2020-03-26 7:15 ` Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
` (5 subsequent siblings)
6 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 7:15 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A new DCF PMD will be introduced, which runs on Intel VF hardware, and
it is a pure software design to control the advance functionality (such
as switch, ACL) for rest of the VFs.
So if the DCF (Device Config Function) mode is specified by the devarg
'cap=dcf', then it will stop the PCI probe in the iavf PMD.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Reviewed-by: Xiaolong Ye <xiaolong.ye@intel.com>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
drivers/net/iavf/iavf_ethdev.c | 43 ++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 34913f9c4..c0b95e169 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -1416,9 +1416,51 @@ iavf_dev_uninit(struct rte_eth_dev *dev)
return 0;
}
+static int
+iavf_dcf_cap_check_handler(__rte_unused const char *key,
+ const char *value, __rte_unused void *opaque)
+{
+ if (strcmp(value, "dcf"))
+ return -1;
+
+ return 0;
+}
+
+static int
+iavf_dcf_cap_selected(struct rte_devargs *devargs)
+{
+ struct rte_kvargs *kvlist;
+ const char *key = "cap";
+ int ret = 0;
+
+ if (devargs == NULL)
+ return 0;
+
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
+ if (kvlist == NULL)
+ return 0;
+
+ if (!rte_kvargs_count(kvlist, key))
+ goto exit;
+
+ /* dcf capability selected when there's a key-value pair: cap=dcf */
+ if (rte_kvargs_process(kvlist, key,
+ iavf_dcf_cap_check_handler, NULL) < 0)
+ goto exit;
+
+ ret = 1;
+
+exit:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
static int eth_iavf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
struct rte_pci_device *pci_dev)
{
+ if (iavf_dcf_cap_selected(pci_dev->device.devargs))
+ return 1;
+
return rte_eth_dev_pci_generic_probe(pci_dev,
sizeof(struct iavf_adapter), iavf_dev_init);
}
@@ -1439,6 +1481,7 @@ static struct rte_pci_driver rte_iavf_pmd = {
RTE_PMD_REGISTER_PCI(net_iavf, rte_iavf_pmd);
RTE_PMD_REGISTER_PCI_TABLE(net_iavf, pci_id_iavf_map);
RTE_PMD_REGISTER_KMOD_DEP(net_iavf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_iavf, "cap=dcf");
RTE_INIT(iavf_init_log)
{
iavf_logtype_init = rte_log_register("pmd.net.iavf.init");
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v5 2/7] net/ice: add the DCF hardware initialization
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 " Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
@ 2020-03-26 7:15 ` Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 3/7] net/ice: acquire and disable the DCF capability Haiyue Wang
` (4 subsequent siblings)
6 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 7:15 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
Introduce the DCF (Device Config Function) feature in the ice PMD, it
works as a standalone PMD which doesn't handle the packet Rx/Tx related
things. Its hardware entity is the VF.
Add the basic DCF hardware initialization, this is specified by devarg
'cap=dcf'.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
doc/guides/nics/ice.rst | 47 +++
doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
doc/guides/rel_notes/release_20_05.rst | 5 +
drivers/common/Makefile | 1 +
drivers/net/ice/Makefile | 5 +
drivers/net/ice/ice_dcf.c | 474 +++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 52 +++
drivers/net/ice/ice_dcf_ethdev.c | 317 +++++++++++++++++
drivers/net/ice/ice_dcf_ethdev.h | 24 ++
drivers/net/ice/meson.build | 7 +-
mk/rte.app.mk | 1 +
11 files changed, 931 insertions(+), 2 deletions(-)
create mode 100644 doc/guides/nics/img/ice_dcf.png
create mode 100644 drivers/net/ice/ice_dcf.c
create mode 100644 drivers/net/ice/ice_dcf.h
create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 8af32dabf..2639ae239 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -240,6 +240,53 @@ report a MDD event and drop the packets.
The APPs based on DPDK should avoid providing such packets.
+Device Config Function (DCF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section demonstrates ICE DCF PMD, which shares the core module with ICE
+PMD and iAVF PMD.
+
+A DCF (Device Config Function) PMD bounds to the device's trusted VF with ID 0,
+it can act as a sole controlling entity to exercise advance functionality (such
+as switch, ACL) for the rest VFs.
+
+The DCF PMD needs to advertise and acquire DCF capability which allows DCF to
+send AdminQ commands that it would like to execute over to the PF and receive
+responses for the same from PF.
+
+.. _figure_ice_dcf:
+
+.. figure:: img/ice_dcf.*
+
+ DCF Communication flow.
+
+#. Create the VFs::
+
+ echo 4 > /sys/bus/pci/devices/0000\:18\:00.0/sriov_numvfs
+
+#. Enable the VF0 trust on::
+
+ ip link set dev enp24s0f0 vf 0 trust on
+
+#. Bind the VF0, and run testpmd with 'cap=dcf' devarg::
+
+ testpmd -l 22-25 -n 4 -w 18:01.0,cap=dcf -- -i
+
+#. Monitor the VF2 interface network traffic::
+
+ tcpdump -e -nn -i enp24s1f2
+
+#. Create one flow to redirect the traffic to VF2 by DCF::
+
+ flow create 0 priority 0 ingress pattern eth / ipv4 src is 192.168.0.2 \
+ dst is 192.168.0.3 / end actions vf id 2 / end
+
+#. Send the packet, and it should be displayed on tcpdump::
+
+ sendp(Ether(src='3c:fd:fe:aa:bb:78', dst='00:00:00:01:02:03')/IP(src=' \
+ 192.168.0.2', dst="192.168.0.3")/TCP(flags='S')/Raw(load='XXXXXXXXXX'), \
+ iface="enp24s0f0", count=10)
+
Sample Application Notes
------------------------
diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
new file mode 100644
index 0000000000000000000000000000000000000000..540823c4a05e9ea9d558d233fea77016d1ae5df3
GIT binary patch
literal 39168
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
literal 0
HcmV?d00001
diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 000bbf501..f404ee7fd 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -62,6 +62,11 @@ New Features
* Added support for matching on IPv4 Time To Live and IPv6 Hop Limit.
+* **Updated the Intel ice driver.**
+
+ Updated the Intel ice driver with new features and improvements, including:
+
+ * Added support for DCF (Device Config Function) feature.
Removed Items
-------------
diff --git a/drivers/common/Makefile b/drivers/common/Makefile
index 96bd7ac6e..df2e840cf 100644
--- a/drivers/common/Makefile
+++ b/drivers/common/Makefile
@@ -31,6 +31,7 @@ DIRS-y += dpaax
endif
IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
ifneq (,$(findstring y,$(IAVF-y)))
DIRS-y += iavf
endif
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index e22c34287..f493c9ed7 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -11,9 +11,11 @@ LIB = librte_pmd_ice.a
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
+LDLIBS += -lrte_net -lrte_common_iavf
EXPORT_MAP := rte_pmd_ice_version.map
@@ -84,6 +86,9 @@ ifeq ($(CC_AVX2_SUPPORT), 1)
endif
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+
# install this header file
SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
new file mode 100644
index 000000000..0a99cceb1
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.c
@@ -0,0 +1,474 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include "ice_dcf.h"
+
+#define ICE_DCF_AQ_LEN 32
+#define ICE_DCF_AQ_BUF_SZ 4096
+
+#define ICE_DCF_ARQ_MAX_RETRIES 200
+#define ICE_DCF_ARQ_CHECK_TIME 2 /* msecs */
+
+#define ICE_DCF_VF_RES_BUF_SZ \
+ (sizeof(struct virtchnl_vf_resource) + \
+ IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource))
+
+static __rte_always_inline int
+ice_dcf_send_cmd_req_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+ uint8_t *req_msg, uint16_t req_msglen)
+{
+ return iavf_aq_send_msg_to_pf(&hw->avf, op, IAVF_SUCCESS,
+ req_msg, req_msglen, NULL);
+}
+
+static int
+ice_dcf_recv_cmd_rsp_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+ uint8_t *rsp_msgbuf, uint16_t rsp_buflen,
+ uint16_t *rsp_msglen)
+{
+ struct iavf_arq_event_info event;
+ enum virtchnl_ops v_op;
+ int i = 0;
+ int err;
+
+ event.buf_len = rsp_buflen;
+ event.msg_buf = rsp_msgbuf;
+
+ do {
+ err = iavf_clean_arq_element(&hw->avf, &event, NULL);
+ if (err != IAVF_SUCCESS)
+ goto again;
+
+ v_op = rte_le_to_cpu_32(event.desc.cookie_high);
+ if (v_op != op)
+ goto again;
+
+ if (rsp_msglen != NULL)
+ *rsp_msglen = event.msg_len;
+ return rte_le_to_cpu_32(event.desc.cookie_low);
+
+again:
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ return -EIO;
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_clear(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_REMOVE(&hw->vc_cmd_queue, cmd, next);
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline void
+ice_dcf_vc_cmd_set(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ cmd->v_ret = IAVF_ERR_NOT_READY;
+ cmd->rsp_msglen = 0;
+ cmd->pending = 1;
+
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_INSERT_TAIL(&hw->vc_cmd_queue, cmd, next);
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline int
+ice_dcf_vc_cmd_send(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ return iavf_aq_send_msg_to_pf(&hw->avf,
+ cmd->v_op, IAVF_SUCCESS,
+ cmd->req_msg, cmd->req_msglen, NULL);
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
+{
+ struct dcf_virtchnl_cmd *cmd;
+ enum virtchnl_ops v_op;
+ enum iavf_status v_ret;
+ uint16_t aq_op;
+
+ aq_op = rte_le_to_cpu_16(info->desc.opcode);
+ if (unlikely(aq_op != iavf_aqc_opc_send_msg_to_vf)) {
+ PMD_DRV_LOG(ERR,
+ "Request %u is not supported yet", aq_op);
+ return;
+ }
+
+ v_op = rte_le_to_cpu_32(info->desc.cookie_high);
+ if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+ return;
+
+ v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
+
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_FOREACH(cmd, &hw->vc_cmd_queue, next) {
+ if (cmd->v_op == v_op && cmd->pending) {
+ cmd->v_ret = v_ret;
+ cmd->rsp_msglen = RTE_MIN(info->msg_len,
+ cmd->rsp_buflen);
+ if (likely(cmd->rsp_msglen != 0))
+ rte_memcpy(cmd->rsp_msgbuf, info->msg_buf,
+ cmd->rsp_msglen);
+
+ /* prevent compiler reordering */
+ rte_compiler_barrier();
+ cmd->pending = 0;
+ break;
+ }
+ }
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static void
+ice_dcf_handle_virtchnl_msg(struct ice_dcf_hw *hw)
+{
+ struct iavf_arq_event_info info;
+ uint16_t pending = 1;
+ int ret;
+
+ info.buf_len = ICE_DCF_AQ_BUF_SZ;
+ info.msg_buf = hw->arq_buf;
+
+ while (pending) {
+ ret = iavf_clean_arq_element(&hw->avf, &info, &pending);
+ if (ret != IAVF_SUCCESS)
+ break;
+
+ ice_dcf_aq_cmd_handle(hw, &info);
+ }
+}
+
+static int
+ice_dcf_init_check_api_version(struct ice_dcf_hw *hw)
+{
+#define ICE_CPF_VIRTCHNL_VERSION_MAJOR_START 1
+#define ICE_CPF_VIRTCHNL_VERSION_MINOR_START 1
+ struct virtchnl_version_info version, *pver;
+ int err;
+
+ version.major = VIRTCHNL_VERSION_MAJOR;
+ version.minor = VIRTCHNL_VERSION_MINOR;
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_VERSION,
+ (uint8_t *)&version, sizeof(version));
+ if (err) {
+ PMD_INIT_LOG(ERR, "Failed to send OP_VERSION");
+ return err;
+ }
+
+ pver = &hw->virtchnl_version;
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_VERSION,
+ (uint8_t *)pver, sizeof(*pver), NULL);
+ if (err) {
+ PMD_INIT_LOG(ERR, "Failed to get response of OP_VERSION");
+ return -1;
+ }
+
+ PMD_INIT_LOG(DEBUG,
+ "Peer PF API version: %u.%u", pver->major, pver->minor);
+
+ if (pver->major < ICE_CPF_VIRTCHNL_VERSION_MAJOR_START ||
+ (pver->major == ICE_CPF_VIRTCHNL_VERSION_MAJOR_START &&
+ pver->minor < ICE_CPF_VIRTCHNL_VERSION_MINOR_START)) {
+ PMD_INIT_LOG(ERR,
+ "VIRTCHNL API version should not be lower than (%u.%u)",
+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START,
+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START);
+ return -1;
+ } else if (pver->major > VIRTCHNL_VERSION_MAJOR ||
+ (pver->major == VIRTCHNL_VERSION_MAJOR &&
+ pver->minor > VIRTCHNL_VERSION_MINOR)) {
+ PMD_INIT_LOG(ERR,
+ "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
+ pver->major, pver->minor,
+ VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
+ return -1;
+ }
+
+ PMD_INIT_LOG(DEBUG, "Peer is supported PF host");
+
+ return 0;
+}
+
+static int
+ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
+{
+ uint32_t caps;
+ int err, i;
+
+ caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+ VF_BASE_MODE_OFFLOADS;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+ (uint8_t *)&caps, sizeof(caps));
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to send msg OP_GET_VF_RESOURCE");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+ (uint8_t *)hw->vf_res,
+ ICE_DCF_VF_RES_BUF_SZ, NULL);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to get response of OP_GET_VF_RESOURCE");
+ return -1;
+ }
+
+ iavf_vf_parse_hw_config(&hw->avf, hw->vf_res);
+
+ hw->vsi_res = NULL;
+ for (i = 0; i < hw->vf_res->num_vsis; i++) {
+ if (hw->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
+ hw->vsi_res = &hw->vf_res->vsi_res[i];
+ }
+
+ if (!hw->vsi_res) {
+ PMD_DRV_LOG(ERR, "no LAN VSI found");
+ return -1;
+ }
+
+ hw->vsi_id = hw->vsi_res->vsi_id;
+ PMD_DRV_LOG(DEBUG, "VSI ID is %u", hw->vsi_id);
+
+ return 0;
+}
+
+static int
+ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
+{
+#define ICE_DCF_RESET_WAIT_CNT 50
+ struct iavf_hw *avf = &hw->avf;
+ int i, reset;
+
+ for (i = 0; i < ICE_DCF_RESET_WAIT_CNT; i++) {
+ reset = IAVF_READ_REG(avf, IAVF_VFGEN_RSTAT) &
+ IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
+ reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
+
+ if (reset == VIRTCHNL_VFR_VFACTIVE ||
+ reset == VIRTCHNL_VFR_COMPLETED)
+ break;
+
+ rte_delay_ms(20);
+ }
+
+ if (i >= ICE_DCF_RESET_WAIT_CNT)
+ return -1;
+
+ return 0;
+}
+
+static inline void
+ice_dcf_enable_irq0(struct ice_dcf_hw *hw)
+{
+ struct iavf_hw *avf = &hw->avf;
+
+ /* Enable admin queue interrupt trigger */
+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1,
+ IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+ IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+ IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+ IAVF_WRITE_FLUSH(avf);
+}
+
+static inline void
+ice_dcf_disable_irq0(struct ice_dcf_hw *hw)
+{
+ struct iavf_hw *avf = &hw->avf;
+
+ /* Disable all interrupt types */
+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1, 0);
+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+ IAVF_WRITE_FLUSH(avf);
+}
+
+static void
+ice_dcf_dev_interrupt_handler(void *param)
+{
+ struct ice_dcf_hw *hw = param;
+
+ ice_dcf_disable_irq0(hw);
+
+ ice_dcf_handle_virtchnl_msg(hw);
+
+ ice_dcf_enable_irq0(hw);
+}
+
+int
+ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+ struct dcf_virtchnl_cmd *cmd)
+{
+ int i = 0;
+ int err;
+
+ if ((cmd->req_msg && !cmd->req_msglen) ||
+ (!cmd->req_msg && cmd->req_msglen) ||
+ (cmd->rsp_msgbuf && !cmd->rsp_buflen) ||
+ (!cmd->rsp_msgbuf && cmd->rsp_buflen))
+ return -EINVAL;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_vc_cmd_set(hw, cmd);
+
+ err = ice_dcf_vc_cmd_send(hw, cmd);
+ if (err) {
+ PMD_DRV_LOG(ERR, "fail to send cmd %d", cmd->v_op);
+ goto ret;
+ }
+
+ do {
+ if (!cmd->pending)
+ break;
+
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ if (cmd->v_ret != IAVF_SUCCESS) {
+ err = -1;
+ PMD_DRV_LOG(ERR,
+ "No response (%d times) or return failure (%d) for cmd %d",
+ i, cmd->v_ret, cmd->v_op);
+ }
+
+ret:
+ ice_dcf_aq_cmd_clear(hw, cmd);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+ return err;
+}
+
+int
+ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ int ret;
+
+ hw->avf.hw_addr = pci_dev->mem_resource[0].addr;
+ hw->avf.back = hw;
+
+ hw->avf.bus.bus_id = pci_dev->addr.bus;
+ hw->avf.bus.device = pci_dev->addr.devid;
+ hw->avf.bus.func = pci_dev->addr.function;
+
+ hw->avf.device_id = pci_dev->id.device_id;
+ hw->avf.vendor_id = pci_dev->id.vendor_id;
+ hw->avf.subsystem_device_id = pci_dev->id.subsystem_device_id;
+ hw->avf.subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+
+ hw->avf.aq.num_arq_entries = ICE_DCF_AQ_LEN;
+ hw->avf.aq.num_asq_entries = ICE_DCF_AQ_LEN;
+ hw->avf.aq.arq_buf_size = ICE_DCF_AQ_BUF_SZ;
+ hw->avf.aq.asq_buf_size = ICE_DCF_AQ_BUF_SZ;
+
+ rte_spinlock_init(&hw->vc_cmd_send_lock);
+ rte_spinlock_init(&hw->vc_cmd_queue_lock);
+ TAILQ_INIT(&hw->vc_cmd_queue);
+
+ hw->arq_buf = rte_zmalloc("arq_buf", ICE_DCF_AQ_BUF_SZ, 0);
+ if (hw->arq_buf == NULL) {
+ PMD_INIT_LOG(ERR, "unable to allocate AdminQ buffer memory");
+ goto err;
+ }
+
+ ret = iavf_set_mac_type(&hw->avf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "set_mac_type failed: %d", ret);
+ goto err;
+ }
+
+ ret = ice_dcf_check_reset_done(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "VF is still resetting");
+ goto err;
+ }
+
+ ret = iavf_init_adminq(&hw->avf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "init_adminq failed: %d", ret);
+ goto err;
+ }
+
+ if (ice_dcf_init_check_api_version(hw)) {
+ PMD_INIT_LOG(ERR, "check_api version failed");
+ goto err_api;
+ }
+
+ hw->vf_res = rte_zmalloc("vf_res", ICE_DCF_VF_RES_BUF_SZ, 0);
+ if (hw->vf_res == NULL) {
+ PMD_INIT_LOG(ERR, "unable to allocate vf_res memory");
+ goto err_api;
+ }
+
+ if (ice_dcf_get_vf_resource(hw)) {
+ PMD_INIT_LOG(ERR, "Failed to get VF resource");
+ goto err_alloc;
+ }
+
+ rte_intr_callback_register(&pci_dev->intr_handle,
+ ice_dcf_dev_interrupt_handler, hw);
+ rte_intr_enable(&pci_dev->intr_handle);
+ ice_dcf_enable_irq0(hw);
+
+ return 0;
+
+err_alloc:
+ rte_free(hw->vf_res);
+err_api:
+ iavf_shutdown_adminq(&hw->avf);
+err:
+ rte_free(hw->arq_buf);
+
+ return -1;
+}
+
+void
+ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
+ ice_dcf_disable_irq0(hw);
+ rte_intr_disable(intr_handle);
+ rte_intr_callback_unregister(intr_handle,
+ ice_dcf_dev_interrupt_handler, hw);
+
+ iavf_shutdown_adminq(&hw->avf);
+
+ rte_free(hw->arq_buf);
+ rte_free(hw->vf_res);
+}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
new file mode 100644
index 000000000..f44c09db2
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_H_
+#define _ICE_DCF_H_
+
+#include <rte_ethdev_driver.h>
+
+#include <iavf_prototype.h>
+#include <iavf_adminq_cmd.h>
+#include <iavf_type.h>
+
+#include "ice_logs.h"
+
+struct dcf_virtchnl_cmd {
+ TAILQ_ENTRY(dcf_virtchnl_cmd) next;
+
+ enum virtchnl_ops v_op;
+ enum iavf_status v_ret;
+
+ uint16_t req_msglen;
+ uint8_t *req_msg;
+
+ uint16_t rsp_msglen;
+ uint16_t rsp_buflen;
+ uint8_t *rsp_msgbuf;
+
+ volatile int pending;
+};
+
+struct ice_dcf_hw {
+ struct iavf_hw avf;
+
+ rte_spinlock_t vc_cmd_send_lock;
+ rte_spinlock_t vc_cmd_queue_lock;
+ TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+ uint8_t *arq_buf;
+
+ struct virtchnl_version_info virtchnl_version;
+ struct virtchnl_vf_resource *vf_res; /* VF resource */
+ struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
+ uint16_t vsi_id;
+};
+
+int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+ struct dcf_virtchnl_cmd *cmd);
+
+int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+
+#endif /* _ICE_DCF_H_ */
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
new file mode 100644
index 000000000..23f82a487
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -0,0 +1,317 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <rte_interrupts.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_pci.h>
+#include <rte_kvargs.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include <iavf_devids.h>
+
+#include "ice_generic_flow.h"
+#include "ice_dcf_ethdev.h"
+
+static uint16_t
+ice_dcf_recv_pkts(__rte_unused void *rx_queue,
+ __rte_unused struct rte_mbuf **bufs,
+ __rte_unused uint16_t nb_pkts)
+{
+ return 0;
+}
+
+static uint16_t
+ice_dcf_xmit_pkts(__rte_unused void *tx_queue,
+ __rte_unused struct rte_mbuf **bufs,
+ __rte_unused uint16_t nb_pkts)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_start(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = ETH_LINK_UP;
+
+ return 0;
+}
+
+static void
+ice_dcf_dev_stop(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+ice_dcf_dev_configure(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_info_get(struct rte_eth_dev *dev,
+ struct rte_eth_dev_info *dev_info)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev_info->max_mac_addrs = 1;
+ dev_info->max_rx_pktlen = (uint32_t)-1;
+ dev_info->max_rx_queues = RTE_DIM(adapter->rxqs);
+ dev_info->max_tx_queues = RTE_DIM(adapter->txqs);
+
+ return 0;
+}
+
+static int
+ice_dcf_stats_get(__rte_unused struct rte_eth_dev *dev,
+ __rte_unused struct rte_eth_stats *igb_stats)
+{
+ return 0;
+}
+
+static int
+ice_dcf_stats_reset(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_disable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_enable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_disable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
+ enum rte_filter_type filter_type,
+ __rte_unused enum rte_filter_op filter_op,
+ __rte_unused void *arg)
+{
+ int ret = 0;
+
+ if (!dev)
+ return -EINVAL;
+
+ switch (filter_type) {
+ default:
+ PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+ filter_type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void
+ice_dcf_dev_close(struct rte_eth_dev *dev)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return;
+
+ dev->dev_ops = NULL;
+ dev->rx_pkt_burst = NULL;
+ dev->tx_pkt_burst = NULL;
+ dev->data->mac_addrs = NULL;
+
+ ice_dcf_uninit_hw(dev, &adapter->real_hw);
+}
+
+static void
+ice_dcf_queue_release(__rte_unused void *q)
+{
+}
+
+static int
+ice_dcf_link_update(__rte_unused struct rte_eth_dev *dev,
+ __rte_unused int wait_to_complete)
+{
+ return 0;
+}
+
+static int
+ice_dcf_rx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t rx_queue_id,
+ __rte_unused uint16_t nb_rx_desc,
+ __rte_unused unsigned int socket_id,
+ __rte_unused const struct rte_eth_rxconf *rx_conf,
+ __rte_unused struct rte_mempool *mb_pool)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev->data->rx_queues[rx_queue_id] = &adapter->rxqs[rx_queue_id];
+
+ return 0;
+}
+
+static int
+ice_dcf_tx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t tx_queue_id,
+ __rte_unused uint16_t nb_tx_desc,
+ __rte_unused unsigned int socket_id,
+ __rte_unused const struct rte_eth_txconf *tx_conf)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev->data->tx_queues[tx_queue_id] = &adapter->txqs[tx_queue_id];
+
+ return 0;
+}
+
+static const struct eth_dev_ops ice_dcf_eth_dev_ops = {
+ .dev_start = ice_dcf_dev_start,
+ .dev_stop = ice_dcf_dev_stop,
+ .dev_close = ice_dcf_dev_close,
+ .dev_configure = ice_dcf_dev_configure,
+ .dev_infos_get = ice_dcf_dev_info_get,
+ .rx_queue_setup = ice_dcf_rx_queue_setup,
+ .tx_queue_setup = ice_dcf_tx_queue_setup,
+ .rx_queue_release = ice_dcf_queue_release,
+ .tx_queue_release = ice_dcf_queue_release,
+ .link_update = ice_dcf_link_update,
+ .stats_get = ice_dcf_stats_get,
+ .stats_reset = ice_dcf_stats_reset,
+ .promiscuous_enable = ice_dcf_dev_promiscuous_enable,
+ .promiscuous_disable = ice_dcf_dev_promiscuous_disable,
+ .allmulticast_enable = ice_dcf_dev_allmulticast_enable,
+ .allmulticast_disable = ice_dcf_dev_allmulticast_disable,
+ .filter_ctrl = ice_dcf_dev_filter_ctrl,
+};
+
+static int
+ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+
+ eth_dev->dev_ops = &ice_dcf_eth_dev_ops;
+ eth_dev->rx_pkt_burst = ice_dcf_recv_pkts;
+ eth_dev->tx_pkt_burst = ice_dcf_xmit_pkts;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return 0;
+
+ eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
+ if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
+ PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
+ return -1;
+ }
+
+ rte_eth_random_addr(adapter->mac_addr.addr_bytes);
+ eth_dev->data->mac_addrs = &adapter->mac_addr;
+
+ return 0;
+}
+
+static int
+ice_dcf_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+ ice_dcf_dev_close(eth_dev);
+
+ return 0;
+}
+
+static int
+ice_dcf_cap_check_handler(__rte_unused const char *key,
+ const char *value, __rte_unused void *opaque)
+{
+ if (strcmp(value, "dcf"))
+ return -1;
+
+ return 0;
+}
+
+static int
+ice_dcf_cap_selected(struct rte_devargs *devargs)
+{
+ struct rte_kvargs *kvlist;
+ const char *key = "cap";
+ int ret = 0;
+
+ if (devargs == NULL)
+ return 0;
+
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
+ if (kvlist == NULL)
+ return 0;
+
+ if (!rte_kvargs_count(kvlist, key))
+ goto exit;
+
+ /* dcf capability selected when there's a key-value pair: cap=dcf */
+ if (rte_kvargs_process(kvlist, key,
+ ice_dcf_cap_check_handler, NULL) < 0)
+ goto exit;
+
+ ret = 1;
+
+exit:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
+static int eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
+ struct rte_pci_device *pci_dev)
+{
+ if (!ice_dcf_cap_selected(pci_dev->device.devargs))
+ return 1;
+
+ return rte_eth_dev_pci_generic_probe(pci_dev,
+ sizeof(struct ice_dcf_adapter),
+ ice_dcf_dev_init);
+}
+
+static int eth_ice_dcf_pci_remove(struct rte_pci_device *pci_dev)
+{
+ return rte_eth_dev_pci_generic_remove(pci_dev, ice_dcf_dev_uninit);
+}
+
+static const struct rte_pci_id pci_id_ice_dcf_map[] = {
+ { RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
+ { .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver rte_ice_dcf_pmd = {
+ .id_table = pci_id_ice_dcf_map,
+ .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+ .probe = eth_ice_dcf_pci_probe,
+ .remove = eth_ice_dcf_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_ice_dcf, rte_ice_dcf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_ice_dcf, pci_id_ice_dcf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ice_dcf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_ice_dcf, "cap=dcf");
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
new file mode 100644
index 000000000..0c34a0095
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_ETHDEV_H_
+#define _ICE_DCF_ETHDEV_H_
+
+#include "ice_ethdev.h"
+#include "ice_dcf.h"
+
+#define ICE_DCF_MAX_RINGS 1
+
+struct ice_dcf_queue {
+ uint64_t dummy;
+};
+
+struct ice_dcf_adapter {
+ struct ice_dcf_hw real_hw;
+ struct rte_ether_addr mac_addr;
+ struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
+ struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
+};
+
+#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index f9e897bbc..0ba9668d1 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -15,8 +15,8 @@ sources = files(
'ice_hash.c'
)
-deps += ['hash']
-includes += include_directories('base')
+deps += ['hash', 'net', 'common_iavf']
+includes += include_directories('base', '../../common/iavf')
if arch_subdir == 'x86'
sources += files('ice_rxtx_vec_sse.c')
@@ -37,4 +37,7 @@ if arch_subdir == 'x86'
endif
endif
+sources += files('ice_dcf.c',
+ 'ice_dcf_ethdev.c')
+
install_headers('rte_pmd_ice.h')
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index d295ca0a5..f3798a09f 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -185,6 +185,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += -lrte_pmd_i40e
_LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD) += -lrte_pmd_iavf
_LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += -lrte_pmd_ice
IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
ifeq ($(findstring y,$(IAVF-y)),y)
_LDLIBS-y += -lrte_common_iavf
endif
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v5 3/7] net/ice: acquire and disable the DCF capability
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 " Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
@ 2020-03-26 7:15 ` Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
` (3 subsequent siblings)
6 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 7:15 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
Since the DCF (Device Config Function) controls the flow setting of
other VFs by the mailbox with PF, for security, it needs to acquire
the DCF capability from PF when starts, and disable it when exits.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
drivers/net/ice/ice_dcf.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index 0a99cceb1..6ea68feb9 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -227,7 +227,7 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
int err, i;
caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
- VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED | VIRTCHNL_VF_CAP_DCF |
VF_BASE_MODE_OFFLOADS;
err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
@@ -264,6 +264,30 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
return 0;
}
+static int
+ice_dcf_mode_disable(struct ice_dcf_hw *hw)
+{
+ int err;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
+ NULL, 0);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to send msg OP_DCF_DISABLE");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
+ hw->arq_buf, ICE_DCF_AQ_BUF_SZ, NULL);
+ if (err) {
+ PMD_DRV_LOG(ERR,
+ "Failed to get response of OP_DCF_DISABLE %d",
+ err);
+ return -1;
+ }
+
+ return 0;
+}
+
static int
ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
{
@@ -467,6 +491,7 @@ ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
rte_intr_callback_unregister(intr_handle,
ice_dcf_dev_interrupt_handler, hw);
+ ice_dcf_mode_disable(hw);
iavf_shutdown_adminq(&hw->avf);
rte_free(hw->arq_buf);
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v5 4/7] net/ice: handle the AdminQ command by DCF
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 " Haiyue Wang
` (2 preceding siblings ...)
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 3/7] net/ice: acquire and disable the DCF capability Haiyue Wang
@ 2020-03-26 7:15 ` Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 5/7] net/ice: export the DDP definition symbols Haiyue Wang
` (2 subsequent siblings)
6 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 7:15 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) splits the AdminQ command into two
parts: one is the descriptor of AdminQ command, the other is the buffer
of AdminQ command (the descriptor has BUF flag set). When both of them
are received by the PF, the PF will handle them as one command.
And also, the filled descriptor and buffer of the response will be sent
back to DCF one by one through the virtchnl from PF.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
drivers/net/ice/ice_dcf.c | 65 +++++++++++++++++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 4 ++-
2 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index 6ea68feb9..baef5b8dc 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -396,6 +396,71 @@ ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
return err;
}
+int
+ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
+ void *buf, uint16_t buf_size)
+{
+ struct dcf_virtchnl_cmd desc_cmd, buff_cmd;
+ struct ice_dcf_hw *hw = dcf_hw;
+ int err = 0;
+ int i = 0;
+
+ if ((buf && !buf_size) || (!buf && buf_size) ||
+ buf_size > ICE_DCF_AQ_BUF_SZ)
+ return -EINVAL;
+
+ desc_cmd.v_op = VIRTCHNL_OP_DCF_CMD_DESC;
+ desc_cmd.req_msglen = sizeof(*desc);
+ desc_cmd.req_msg = (uint8_t *)desc;
+ desc_cmd.rsp_buflen = sizeof(*desc);
+ desc_cmd.rsp_msgbuf = (uint8_t *)desc;
+
+ if (buf == NULL)
+ return ice_dcf_execute_virtchnl_cmd(hw, &desc_cmd);
+
+ desc->flags |= rte_cpu_to_le_16(ICE_AQ_FLAG_BUF);
+
+ buff_cmd.v_op = VIRTCHNL_OP_DCF_CMD_BUFF;
+ buff_cmd.req_msglen = buf_size;
+ buff_cmd.req_msg = buf;
+ buff_cmd.rsp_buflen = buf_size;
+ buff_cmd.rsp_msgbuf = buf;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_vc_cmd_set(hw, &desc_cmd);
+ ice_dcf_vc_cmd_set(hw, &buff_cmd);
+
+ if (ice_dcf_vc_cmd_send(hw, &desc_cmd) ||
+ ice_dcf_vc_cmd_send(hw, &buff_cmd)) {
+ err = -1;
+ PMD_DRV_LOG(ERR, "fail to send OP_DCF_CMD_DESC/BUFF");
+ goto ret;
+ }
+
+ do {
+ if ((!desc_cmd.pending && !buff_cmd.pending) ||
+ (!desc_cmd.pending && desc_cmd.v_ret != IAVF_SUCCESS) ||
+ (!buff_cmd.pending && buff_cmd.v_ret != IAVF_SUCCESS))
+ break;
+
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ if (desc_cmd.v_ret != IAVF_SUCCESS || buff_cmd.v_ret != IAVF_SUCCESS) {
+ err = -1;
+ PMD_DRV_LOG(ERR,
+ "No response (%d times) or return failure (desc: %d / buff: %d)",
+ i, desc_cmd.v_ret, buff_cmd.v_ret);
+ }
+
+ret:
+ ice_dcf_aq_cmd_clear(hw, &desc_cmd);
+ ice_dcf_aq_cmd_clear(hw, &buff_cmd);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+
+ return err;
+}
+
int
ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
{
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index f44c09db2..99bd53b02 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -11,6 +11,7 @@
#include <iavf_adminq_cmd.h>
#include <iavf_type.h>
+#include "base/ice_type.h"
#include "ice_logs.h"
struct dcf_virtchnl_cmd {
@@ -45,7 +46,8 @@ struct ice_dcf_hw {
int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
struct dcf_virtchnl_cmd *cmd);
-
+int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
+ void *buf, uint16_t buf_size);
int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v5 5/7] net/ice: export the DDP definition symbols
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 " Haiyue Wang
` (3 preceding siblings ...)
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
@ 2020-03-26 7:15 ` Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
6 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 7:15 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A new DCF PMD will be introduced, which runs on Intel VF hardware, and
it is a pure software design to control the advance functionality (such
as switch, ACL) for rest of the VFs.
The DCF (Device Config Function) feature shares the core functions of
the ICE PMD, like it needs to export the DDP definition symbols for the
new DCF PMD use.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Xiaolong Ye <xiaolong.ye@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
drivers/net/ice/ice_ethdev.c | 9 +--------
drivers/net/ice/ice_ethdev.h | 8 ++++++++
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c
index 3498a5075..3c38472de 100644
--- a/drivers/net/ice/ice_ethdev.c
+++ b/drivers/net/ice/ice_ethdev.c
@@ -67,15 +67,8 @@ static struct proto_xtr_ol_flag ice_proto_xtr_ol_flag_params[] = {
#define ICE_DFLT_OUTER_TAG_TYPE ICE_AQ_VSI_OUTER_TAG_VLAN_9100
-/* DDP package search path */
-#define ICE_PKG_FILE_DEFAULT "/lib/firmware/intel/ice/ddp/ice.pkg"
-#define ICE_PKG_FILE_UPDATES "/lib/firmware/updates/intel/ice/ddp/ice.pkg"
-#define ICE_PKG_FILE_SEARCH_PATH_DEFAULT "/lib/firmware/intel/ice/ddp/"
-#define ICE_PKG_FILE_SEARCH_PATH_UPDATES "/lib/firmware/updates/intel/ice/ddp/"
-
#define ICE_OS_DEFAULT_PKG_NAME "ICE OS Default Package"
#define ICE_COMMS_PKG_NAME "ICE COMMS Package"
-#define ICE_MAX_PKG_FILENAME_SIZE 256
#define ICE_MAX_RES_DESC_NUM 1024
int ice_logtype_init;
@@ -1833,7 +1826,7 @@ ice_pkg_file_search_path(struct rte_pci_device *pci_dev, char *pkg_file)
return 0;
}
-static enum ice_pkg_type
+enum ice_pkg_type
ice_load_pkg_type(struct ice_hw *hw)
{
enum ice_pkg_type package_type;
diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h
index da557a254..7b94a3c3e 100644
--- a/drivers/net/ice/ice_ethdev.h
+++ b/drivers/net/ice/ice_ethdev.h
@@ -42,6 +42,13 @@
#define ICE_MAX_PKT_TYPE 1024
+/* DDP package search path */
+#define ICE_PKG_FILE_DEFAULT "/lib/firmware/intel/ice/ddp/ice.pkg"
+#define ICE_PKG_FILE_UPDATES "/lib/firmware/updates/intel/ice/ddp/ice.pkg"
+#define ICE_PKG_FILE_SEARCH_PATH_DEFAULT "/lib/firmware/intel/ice/ddp/"
+#define ICE_PKG_FILE_SEARCH_PATH_UPDATES "/lib/firmware/updates/intel/ice/ddp/"
+#define ICE_MAX_PKG_FILENAME_SIZE 256
+
/**
* vlan_id is a 12 bit number.
* The VFTA array is actually a 4096 bit array, 128 of 32bit elements.
@@ -457,6 +464,7 @@ struct ice_vsi_vlan_pvid_info {
#define ICE_PF_TO_ETH_DEV(pf) \
(((struct ice_pf *)pf)->adapter->eth_dev)
+enum ice_pkg_type ice_load_pkg_type(struct ice_hw *hw);
struct ice_vsi *
ice_setup_vsi(struct ice_pf *pf, enum ice_vsi_type type);
int
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v5 6/7] net/ice: handle the PF initialization by DCF
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 " Haiyue Wang
` (4 preceding siblings ...)
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 5/7] net/ice: export the DDP definition symbols Haiyue Wang
@ 2020-03-26 7:15 ` Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
6 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 7:15 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) works at the user PF level, it can't
access the real PF hardware directly. So it will pass through the PF's
AdminQ command by the DCF's mailbox.
And the DCF is mainly used to control the flow setting of other VFs, so
it only needs to initialize some core functions related to the flow.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
drivers/net/ice/Makefile | 1 +
drivers/net/ice/ice_dcf.c | 7 +-
drivers/net/ice/ice_dcf.h | 3 +
drivers/net/ice/ice_dcf_ethdev.c | 10 +-
drivers/net/ice/ice_dcf_ethdev.h | 11 +-
drivers/net/ice/ice_dcf_parent.c | 263 +++++++++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
7 files changed, 292 insertions(+), 6 deletions(-)
create mode 100644 drivers/net/ice/ice_dcf_parent.c
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index f493c9ed7..3ecc72219 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -88,6 +88,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_parent.c
# install this header file
SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index baef5b8dc..c799cdf83 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -124,8 +124,13 @@ ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
}
v_op = rte_le_to_cpu_32(info->desc.cookie_high);
- if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+ if (v_op == VIRTCHNL_OP_EVENT) {
+ if (hw->vc_event_msg_cb != NULL)
+ hw->vc_event_msg_cb(hw,
+ info->msg_buf,
+ info->msg_len);
return;
+ }
v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index 99bd53b02..ecd6303a0 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -36,6 +36,9 @@ struct ice_dcf_hw {
rte_spinlock_t vc_cmd_send_lock;
rte_spinlock_t vc_cmd_queue_lock;
TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+ void (*vc_event_msg_cb)(struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen);
+
uint8_t *arq_buf;
struct virtchnl_version_info virtchnl_version;
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
index 23f82a487..af94caeff 100644
--- a/drivers/net/ice/ice_dcf_ethdev.c
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -145,8 +145,8 @@ ice_dcf_dev_close(struct rte_eth_dev *dev)
dev->dev_ops = NULL;
dev->rx_pkt_burst = NULL;
dev->tx_pkt_burst = NULL;
- dev->data->mac_addrs = NULL;
+ ice_dcf_uninit_parent_adapter(dev);
ice_dcf_uninit_hw(dev, &adapter->real_hw);
}
@@ -225,13 +225,17 @@ ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+ adapter->real_hw.vc_event_msg_cb = ice_dcf_handle_pf_event_msg;
if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
return -1;
}
- rte_eth_random_addr(adapter->mac_addr.addr_bytes);
- eth_dev->data->mac_addrs = &adapter->mac_addr;
+ if (ice_dcf_init_parent_adapter(eth_dev) != 0) {
+ PMD_INIT_LOG(ERR, "Failed to init DCF parent adapter");
+ ice_dcf_uninit_hw(eth_dev, &adapter->real_hw);
+ return -1;
+ }
return 0;
}
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
index 0c34a0095..e60e808d8 100644
--- a/drivers/net/ice/ice_dcf_ethdev.h
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -5,6 +5,9 @@
#ifndef _ICE_DCF_ETHDEV_H_
#define _ICE_DCF_ETHDEV_H_
+#include "base/ice_common.h"
+#include "base/ice_adminq_cmd.h"
+
#include "ice_ethdev.h"
#include "ice_dcf.h"
@@ -15,10 +18,16 @@ struct ice_dcf_queue {
};
struct ice_dcf_adapter {
+ struct ice_adapter parent; /* Must be first */
+
struct ice_dcf_hw real_hw;
- struct rte_ether_addr mac_addr;
struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
};
+void ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen);
+int ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev);
+void ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev);
+
#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
new file mode 100644
index 000000000..138838a73
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_parent.c
@@ -0,0 +1,263 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "ice_dcf_ethdev.h"
+
+void
+ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen)
+{
+ struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
+
+ if (msglen < sizeof(struct virtchnl_pf_event)) {
+ PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen);
+ return;
+ }
+
+ switch (pf_msg->event) {
+ case VIRTCHNL_EVENT_RESET_IMPENDING:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
+ break;
+ case VIRTCHNL_EVENT_LINK_CHANGE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
+ break;
+ case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
+ break;
+ }
+}
+
+static int
+ice_dcf_init_parent_hw(struct ice_hw *hw)
+{
+ struct ice_aqc_get_phy_caps_data *pcaps;
+ enum ice_status status;
+
+ status = ice_aq_get_fw_ver(hw, NULL);
+ if (status)
+ return status;
+
+ status = ice_get_caps(hw);
+ if (status)
+ return status;
+
+ hw->port_info = (struct ice_port_info *)
+ ice_malloc(hw, sizeof(*hw->port_info));
+ if (!hw->port_info)
+ return ICE_ERR_NO_MEMORY;
+
+ /* set the back pointer to HW */
+ hw->port_info->hw = hw;
+
+ /* Initialize port_info struct with switch configuration data */
+ status = ice_get_initial_sw_cfg(hw);
+ if (status)
+ goto err_unroll_alloc;
+
+ pcaps = (struct ice_aqc_get_phy_caps_data *)
+ ice_malloc(hw, sizeof(*pcaps));
+ if (!pcaps) {
+ status = ICE_ERR_NO_MEMORY;
+ goto err_unroll_alloc;
+ }
+
+ /* Initialize port_info struct with PHY capabilities */
+ status = ice_aq_get_phy_caps(hw->port_info, false,
+ ICE_AQC_REPORT_TOPO_CAP, pcaps, NULL);
+ ice_free(hw, pcaps);
+ if (status)
+ goto err_unroll_alloc;
+
+ /* Initialize port_info struct with link information */
+ status = ice_aq_get_link_info(hw->port_info, false, NULL, NULL);
+ if (status)
+ goto err_unroll_alloc;
+
+ status = ice_init_fltr_mgmt_struct(hw);
+ if (status)
+ goto err_unroll_alloc;
+
+ status = ice_init_hw_tbls(hw);
+ if (status)
+ goto err_unroll_fltr_mgmt_struct;
+
+ PMD_INIT_LOG(INFO,
+ "firmware %d.%d.%d api %d.%d.%d build 0x%08x",
+ hw->fw_maj_ver, hw->fw_min_ver, hw->fw_patch,
+ hw->api_maj_ver, hw->api_min_ver, hw->api_patch,
+ hw->fw_build);
+
+ return ICE_SUCCESS;
+
+err_unroll_fltr_mgmt_struct:
+ ice_cleanup_fltr_mgmt_struct(hw);
+err_unroll_alloc:
+ ice_free(hw, hw->port_info);
+ hw->port_info = NULL;
+
+ return status;
+}
+
+static void ice_dcf_uninit_parent_hw(struct ice_hw *hw)
+{
+ ice_cleanup_fltr_mgmt_struct(hw);
+
+ ice_free_seg(hw);
+ ice_free_hw_tbls(hw);
+
+ ice_free(hw, hw->port_info);
+ hw->port_info = NULL;
+
+ ice_clear_all_vsi_ctx(hw);
+}
+
+static int
+ice_dcf_request_pkg_name(struct ice_hw *hw, char *pkg_name)
+{
+ struct ice_dcf_adapter *dcf_adapter =
+ container_of(hw, struct ice_dcf_adapter, parent.hw);
+
+ /* TODO: check with DSN firstly by iAVF */
+ PMD_INIT_LOG(DEBUG,
+ "DCF VSI_ID = %u",
+ dcf_adapter->real_hw.vsi_id);
+
+ snprintf(pkg_name,
+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_UPDATES);
+ if (!access(pkg_name, 0))
+ return 0;
+
+ snprintf(pkg_name,
+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_DEFAULT);
+ if (!access(pkg_name, 0))
+ return 0;
+
+ return -1;
+}
+
+static int
+ice_dcf_load_pkg(struct ice_hw *hw)
+{
+ char pkg_name[ICE_MAX_PKG_FILENAME_SIZE];
+ uint8_t *pkg_buf;
+ uint32_t buf_len;
+ struct stat st;
+ FILE *fp;
+ int err;
+
+ if (ice_dcf_request_pkg_name(hw, pkg_name)) {
+ PMD_INIT_LOG(ERR, "Failed to locate the package file");
+ return -ENOENT;
+ }
+
+ PMD_INIT_LOG(DEBUG, "DDP package name: %s", pkg_name);
+
+ err = stat(pkg_name, &st);
+ if (err) {
+ PMD_INIT_LOG(ERR, "Failed to get file status");
+ return err;
+ }
+
+ buf_len = st.st_size;
+ pkg_buf = rte_malloc(NULL, buf_len, 0);
+ if (!pkg_buf) {
+ PMD_INIT_LOG(ERR, "failed to allocate buffer of size %u for package",
+ buf_len);
+ return -1;
+ }
+
+ fp = fopen(pkg_name, "rb");
+ if (!fp) {
+ PMD_INIT_LOG(ERR, "failed to open file: %s", pkg_name);
+ err = -1;
+ goto ret;
+ }
+
+ err = fread(pkg_buf, buf_len, 1, fp);
+ fclose(fp);
+ if (err != 1) {
+ PMD_INIT_LOG(ERR, "failed to read package data");
+ err = -1;
+ goto ret;
+ }
+
+ err = ice_copy_and_init_pkg(hw, pkg_buf, buf_len);
+ if (err)
+ PMD_INIT_LOG(ERR, "ice_copy_and_init_hw failed: %d", err);
+
+ret:
+ rte_free(pkg_buf);
+ return err;
+}
+
+int
+ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+ struct ice_adapter *parent_adapter = &adapter->parent;
+ struct ice_hw *parent_hw = &parent_adapter->hw;
+ struct ice_dcf_hw *hw = &adapter->real_hw;
+ const struct rte_ether_addr *mac;
+ int err;
+
+ parent_adapter->eth_dev = eth_dev;
+ parent_adapter->pf.adapter = parent_adapter;
+ parent_adapter->pf.dev_data = eth_dev->data;
+ parent_hw->back = parent_adapter;
+ parent_hw->mac_type = ICE_MAC_GENERIC;
+ parent_hw->vendor_id = ICE_INTEL_VENDOR_ID;
+
+ ice_init_lock(&parent_hw->adminq.sq_lock);
+ ice_init_lock(&parent_hw->adminq.rq_lock);
+ parent_hw->aq_send_cmd_fn = ice_dcf_send_aq_cmd;
+ parent_hw->aq_send_cmd_param = &adapter->real_hw;
+ parent_hw->dcf_enabled = true;
+
+ err = ice_dcf_init_parent_hw(parent_hw);
+ if (err) {
+ PMD_INIT_LOG(ERR, "failed to init the DCF parent hardware with error %d",
+ err);
+ return err;
+ }
+
+ err = ice_dcf_load_pkg(parent_hw);
+ if (err) {
+ PMD_INIT_LOG(ERR, "failed to load package with error %d",
+ err);
+ goto uninit_hw;
+ }
+ parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
+
+ mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
+ if (rte_is_valid_assigned_ether_addr(mac))
+ rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
+ else
+ rte_eth_random_addr(parent_adapter->pf.dev_addr.addr_bytes);
+
+ eth_dev->data->mac_addrs = &parent_adapter->pf.dev_addr;
+
+ return 0;
+
+uninit_hw:
+ ice_dcf_uninit_parent_hw(parent_hw);
+ return err;
+}
+
+void
+ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+ struct ice_adapter *parent_adapter = &adapter->parent;
+ struct ice_hw *parent_hw = &parent_adapter->hw;
+
+ eth_dev->data->mac_addrs = NULL;
+
+ ice_dcf_uninit_parent_hw(parent_hw);
+}
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index 0ba9668d1..7e9037f3b 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -38,6 +38,7 @@ if arch_subdir == 'x86'
endif
sources += files('ice_dcf.c',
- 'ice_dcf_ethdev.c')
+ 'ice_dcf_ethdev.c',
+ 'ice_dcf_parent.c')
install_headers('rte_pmd_ice.h')
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v5 7/7] net/ice: get the VF hardware index in DCF
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 " Haiyue Wang
` (5 preceding siblings ...)
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
@ 2020-03-26 7:15 ` Haiyue Wang
6 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-26 7:15 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) needs the hardware index of the VFs to
control the flow setting. And also if the VF resets, the index may be
changed, so it should handle this in VF reset event.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
drivers/net/ice/Makefile | 1 +
drivers/net/ice/ice_dcf.c | 89 +++++++++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 6 +++
drivers/net/ice/ice_dcf_parent.c | 90 +++++++++++++++++++++++++++++++-
4 files changed, 185 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index 3ecc72219..622a853af 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -16,6 +16,7 @@ CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
LDLIBS += -lrte_net -lrte_common_iavf
+LDLIBS += -lpthread
EXPORT_MAP := rte_pmd_ice_version.map
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index c799cdf83..4c30f0e60 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -269,6 +269,65 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
return 0;
}
+static int
+ice_dcf_get_vf_vsi_map(struct ice_dcf_hw *hw)
+{
+ struct virtchnl_dcf_vsi_map *vsi_map;
+ uint32_t valid_msg_len;
+ uint16_t len;
+ int err;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
+ NULL, 0);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to send msg OP_DCF_GET_VSI_MAP");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
+ hw->arq_buf, ICE_DCF_AQ_BUF_SZ,
+ &len);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to get response of OP_DCF_GET_VSI_MAP");
+ return err;
+ }
+
+ vsi_map = (struct virtchnl_dcf_vsi_map *)hw->arq_buf;
+ valid_msg_len = (vsi_map->num_vfs - 1) * sizeof(vsi_map->vf_vsi[0]) +
+ sizeof(*vsi_map);
+ if (len != valid_msg_len) {
+ PMD_DRV_LOG(ERR, "invalid vf vsi map response with length %u",
+ len);
+ return -EINVAL;
+ }
+
+ if (hw->num_vfs != 0 && hw->num_vfs != vsi_map->num_vfs) {
+ PMD_DRV_LOG(ERR, "The number VSI map (%u) doesn't match the number of VFs (%u)",
+ vsi_map->num_vfs, hw->num_vfs);
+ return -EINVAL;
+ }
+
+ len = vsi_map->num_vfs * sizeof(vsi_map->vf_vsi[0]);
+
+ if (!hw->vf_vsi_map) {
+ hw->vf_vsi_map = rte_zmalloc("vf_vsi_ctx", len, 0);
+ if (!hw->vf_vsi_map) {
+ PMD_DRV_LOG(ERR, "Failed to alloc memory for VSI context");
+ return -ENOMEM;
+ }
+
+ hw->num_vfs = vsi_map->num_vfs;
+ }
+
+ if (!memcmp(hw->vf_vsi_map, vsi_map->vf_vsi, len)) {
+ PMD_DRV_LOG(DEBUG, "VF VSI map doesn't change");
+ return 1;
+ }
+
+ rte_memcpy(hw->vf_vsi_map, vsi_map->vf_vsi, len);
+ return 0;
+}
+
static int
ice_dcf_mode_disable(struct ice_dcf_hw *hw)
{
@@ -466,6 +525,28 @@ ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
return err;
}
+int
+ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(hw->eth_dev);
+ int err = 0;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+
+ rte_intr_disable(&pci_dev->intr_handle);
+ ice_dcf_disable_irq0(hw);
+
+ if (ice_dcf_get_vf_resource(hw) || ice_dcf_get_vf_vsi_map(hw))
+ err = -1;
+
+ rte_intr_enable(&pci_dev->intr_handle);
+ ice_dcf_enable_irq0(hw);
+
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+
+ return err;
+}
+
int
ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
{
@@ -533,6 +614,13 @@ ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
goto err_alloc;
}
+ if (ice_dcf_get_vf_vsi_map(hw) < 0) {
+ PMD_INIT_LOG(ERR, "Failed to get VF VSI map");
+ ice_dcf_mode_disable(hw);
+ goto err_alloc;
+ }
+
+ hw->eth_dev = eth_dev;
rte_intr_callback_register(&pci_dev->intr_handle,
ice_dcf_dev_interrupt_handler, hw);
rte_intr_enable(&pci_dev->intr_handle);
@@ -565,5 +653,6 @@ ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
iavf_shutdown_adminq(&hw->avf);
rte_free(hw->arq_buf);
+ rte_free(hw->vf_vsi_map);
rte_free(hw->vf_res);
}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index ecd6303a0..d2e447b48 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -41,16 +41,22 @@ struct ice_dcf_hw {
uint8_t *arq_buf;
+ uint16_t num_vfs;
+ uint16_t *vf_vsi_map;
+
struct virtchnl_version_info virtchnl_version;
struct virtchnl_vf_resource *vf_res; /* VF resource */
struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
uint16_t vsi_id;
+
+ struct rte_eth_dev *eth_dev;
};
int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
struct dcf_virtchnl_cmd *cmd);
int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
void *buf, uint16_t buf_size);
+int ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw);
int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
index 138838a73..ff08292a1 100644
--- a/drivers/net/ice/ice_dcf_parent.c
+++ b/drivers/net/ice/ice_dcf_parent.c
@@ -3,15 +3,92 @@
*/
#include <sys/types.h>
#include <sys/stat.h>
+#include <pthread.h>
#include <unistd.h>
+#include <rte_spinlock.h>
+
#include "ice_dcf_ethdev.h"
+#define ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL 100000 /* us */
+static rte_spinlock_t vsi_update_lock = RTE_SPINLOCK_INITIALIZER;
+
+static __rte_always_inline void
+ice_dcf_update_vsi_ctx(struct ice_hw *hw, uint16_t vsi_handle,
+ uint16_t vsi_map)
+{
+ struct ice_vsi_ctx *vsi_ctx;
+
+ if (unlikely(vsi_handle >= ICE_MAX_VSI)) {
+ PMD_DRV_LOG(ERR, "Invalid vsi handle %u", vsi_handle);
+ return;
+ }
+
+ vsi_ctx = hw->vsi_ctx[vsi_handle];
+
+ if (vsi_map & VIRTCHNL_DCF_VF_VSI_VALID) {
+ if (!vsi_ctx) {
+ vsi_ctx = ice_malloc(hw, sizeof(*vsi_ctx));
+ if (!vsi_ctx) {
+ PMD_DRV_LOG(ERR, "No memory for vsi context %u",
+ vsi_handle);
+ return;
+ }
+ }
+
+ vsi_ctx->vsi_num = (vsi_map & VIRTCHNL_DCF_VF_VSI_ID_M) >>
+ VIRTCHNL_DCF_VF_VSI_ID_S;
+ hw->vsi_ctx[vsi_handle] = vsi_ctx;
+
+ PMD_DRV_LOG(DEBUG, "VF%u is assigned with vsi number %u",
+ vsi_handle, vsi_ctx->vsi_num);
+ } else {
+ hw->vsi_ctx[vsi_handle] = NULL;
+
+ ice_free(hw, vsi_ctx);
+
+ PMD_DRV_LOG(NOTICE, "VF%u is disabled", vsi_handle);
+ }
+}
+
+static void
+ice_dcf_update_vf_vsi_map(struct ice_hw *hw, uint16_t num_vfs,
+ uint16_t *vf_vsi_map)
+{
+ uint16_t vf_id;
+
+ for (vf_id = 0; vf_id < num_vfs; vf_id++)
+ ice_dcf_update_vsi_ctx(hw, vf_id, vf_vsi_map[vf_id]);
+}
+
+static void*
+ice_dcf_vsi_update_service_handler(void *param)
+{
+ struct ice_dcf_hw *hw = param;
+
+ usleep(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL);
+
+ rte_spinlock_lock(&vsi_update_lock);
+
+ if (!ice_dcf_handle_vsi_update_event(hw)) {
+ struct ice_dcf_adapter *dcf_ad =
+ container_of(hw, struct ice_dcf_adapter, real_hw);
+
+ ice_dcf_update_vf_vsi_map(&dcf_ad->parent.hw,
+ hw->num_vfs, hw->vf_vsi_map);
+ }
+
+ rte_spinlock_unlock(&vsi_update_lock);
+
+ return NULL;
+}
+
void
-ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
+ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
uint8_t *msg, uint16_t msglen)
{
struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
+ pthread_t thread;
if (msglen < sizeof(struct virtchnl_pf_event)) {
PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen);
@@ -21,6 +98,8 @@ ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
switch (pf_msg->event) {
case VIRTCHNL_EVENT_RESET_IMPENDING:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
+ pthread_create(&thread, NULL,
+ ice_dcf_vsi_update_service_handler, dcf_hw);
break;
case VIRTCHNL_EVENT_LINK_CHANGE:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
@@ -28,6 +107,13 @@ ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
break;
+ case VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE event : VF%u with VSI num %u",
+ pf_msg->event_data.vf_vsi_map.vf_id,
+ pf_msg->event_data.vf_vsi_map.vsi_id);
+ pthread_create(&thread, NULL,
+ ice_dcf_vsi_update_service_handler, dcf_hw);
+ break;
default:
PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
break;
@@ -235,6 +321,8 @@ ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
}
parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
+ ice_dcf_update_vf_vsi_map(parent_hw, hw->num_vfs, hw->vf_vsi_map);
+
mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
if (rte_is_valid_assigned_ether_addr(mac))
rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support
2020-03-09 14:14 [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support Haiyue Wang
` (8 preceding siblings ...)
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 " Haiyue Wang
@ 2020-03-27 2:56 ` Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
` (7 more replies)
9 siblings, 8 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-27 2:56 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A DCF (Device Config Function) based approach is proposed where a device
bound to the device's VF0 can act as a sole controlling entity to exercise
advance functionality (such as switch, ACL) for rest of the VFs.
The DCF works as a standalone PMD to support this function, which shares the
ice PMD flow control core function and the iavf virtchnl mailbox core module.
v6:
No change, but to resend the same patchset again to trigger ci/Performance-Testing
by using the new code base:
https://lab.dpdk.org/results/dashboard/patchsets/10120/
v5:
Fixed the shared module compile errror.
v4:
Change the alarm handler to thread service, since it will need to do more
work.
v3:
1. Fixed the error log message format.
2. Fixed some memory allocation check.
3. Fixed some code style issue and commmit message description.
v2:
1. update the iavf patchset link.
2. split more patches for making this work be more understandable
3. fix the log function usage, devargs checking from v1.
Haiyue Wang (7):
net/iavf: stop the PCI probe in DCF mode
net/ice: add the DCF hardware initialization
net/ice: acquire and disable the DCF capability
net/ice: handle the AdminQ command by DCF
net/ice: export the DDP definition symbols
net/ice: handle the PF initialization by DCF
net/ice: get the VF hardware index in DCF
doc/guides/nics/ice.rst | 47 ++
doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
doc/guides/rel_notes/release_20_05.rst | 5 +
drivers/common/Makefile | 1 +
drivers/net/iavf/iavf_ethdev.c | 43 ++
drivers/net/ice/Makefile | 7 +
drivers/net/ice/ice_dcf.c | 658 +++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 63 +++
drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
drivers/net/ice/ice_dcf_ethdev.h | 33 ++
drivers/net/ice/ice_dcf_parent.c | 351 +++++++++++++
drivers/net/ice/ice_ethdev.c | 9 +-
drivers/net/ice/ice_ethdev.h | 8 +
drivers/net/ice/meson.build | 8 +-
mk/rte.app.mk | 1 +
15 files changed, 1545 insertions(+), 10 deletions(-)
create mode 100644 doc/guides/nics/img/ice_dcf.png
create mode 100644 drivers/net/ice/ice_dcf.c
create mode 100644 drivers/net/ice/ice_dcf.h
create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
create mode 100644 drivers/net/ice/ice_dcf_parent.c
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v6 1/7] net/iavf: stop the PCI probe in DCF mode
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Haiyue Wang
@ 2020-03-27 2:56 ` Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
` (6 subsequent siblings)
7 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-27 2:56 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A new DCF PMD will be introduced, which runs on Intel VF hardware, and
it is a pure software design to control the advance functionality (such
as switch, ACL) for rest of the VFs.
So if the DCF (Device Config Function) mode is specified by the devarg
'cap=dcf', then it will stop the PCI probe in the iavf PMD.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Reviewed-by: Xiaolong Ye <xiaolong.ye@intel.com>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
drivers/net/iavf/iavf_ethdev.c | 43 ++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 34913f9c4..c0b95e169 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -1416,9 +1416,51 @@ iavf_dev_uninit(struct rte_eth_dev *dev)
return 0;
}
+static int
+iavf_dcf_cap_check_handler(__rte_unused const char *key,
+ const char *value, __rte_unused void *opaque)
+{
+ if (strcmp(value, "dcf"))
+ return -1;
+
+ return 0;
+}
+
+static int
+iavf_dcf_cap_selected(struct rte_devargs *devargs)
+{
+ struct rte_kvargs *kvlist;
+ const char *key = "cap";
+ int ret = 0;
+
+ if (devargs == NULL)
+ return 0;
+
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
+ if (kvlist == NULL)
+ return 0;
+
+ if (!rte_kvargs_count(kvlist, key))
+ goto exit;
+
+ /* dcf capability selected when there's a key-value pair: cap=dcf */
+ if (rte_kvargs_process(kvlist, key,
+ iavf_dcf_cap_check_handler, NULL) < 0)
+ goto exit;
+
+ ret = 1;
+
+exit:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
static int eth_iavf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
struct rte_pci_device *pci_dev)
{
+ if (iavf_dcf_cap_selected(pci_dev->device.devargs))
+ return 1;
+
return rte_eth_dev_pci_generic_probe(pci_dev,
sizeof(struct iavf_adapter), iavf_dev_init);
}
@@ -1439,6 +1481,7 @@ static struct rte_pci_driver rte_iavf_pmd = {
RTE_PMD_REGISTER_PCI(net_iavf, rte_iavf_pmd);
RTE_PMD_REGISTER_PCI_TABLE(net_iavf, pci_id_iavf_map);
RTE_PMD_REGISTER_KMOD_DEP(net_iavf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_iavf, "cap=dcf");
RTE_INIT(iavf_init_log)
{
iavf_logtype_init = rte_log_register("pmd.net.iavf.init");
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v6 2/7] net/ice: add the DCF hardware initialization
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
@ 2020-03-27 2:56 ` Haiyue Wang
2020-03-31 8:50 ` Ferruh Yigit
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 3/7] net/ice: acquire and disable the DCF capability Haiyue Wang
` (5 subsequent siblings)
7 siblings, 1 reply; 94+ messages in thread
From: Haiyue Wang @ 2020-03-27 2:56 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
Introduce the DCF (Device Config Function) feature in the ice PMD, it
works as a standalone PMD which doesn't handle the packet Rx/Tx related
things. Its hardware entity is the VF.
Add the basic DCF hardware initialization, this is specified by devarg
'cap=dcf'.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
doc/guides/nics/ice.rst | 47 +++
doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
doc/guides/rel_notes/release_20_05.rst | 5 +
drivers/common/Makefile | 1 +
drivers/net/ice/Makefile | 5 +
drivers/net/ice/ice_dcf.c | 474 +++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 52 +++
drivers/net/ice/ice_dcf_ethdev.c | 317 +++++++++++++++++
drivers/net/ice/ice_dcf_ethdev.h | 24 ++
drivers/net/ice/meson.build | 7 +-
mk/rte.app.mk | 1 +
11 files changed, 931 insertions(+), 2 deletions(-)
create mode 100644 doc/guides/nics/img/ice_dcf.png
create mode 100644 drivers/net/ice/ice_dcf.c
create mode 100644 drivers/net/ice/ice_dcf.h
create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
diff --git a/doc/guides/nics/ice.rst b/doc/guides/nics/ice.rst
index 8af32dabf..2639ae239 100644
--- a/doc/guides/nics/ice.rst
+++ b/doc/guides/nics/ice.rst
@@ -240,6 +240,53 @@ report a MDD event and drop the packets.
The APPs based on DPDK should avoid providing such packets.
+Device Config Function (DCF)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section demonstrates ICE DCF PMD, which shares the core module with ICE
+PMD and iAVF PMD.
+
+A DCF (Device Config Function) PMD bounds to the device's trusted VF with ID 0,
+it can act as a sole controlling entity to exercise advance functionality (such
+as switch, ACL) for the rest VFs.
+
+The DCF PMD needs to advertise and acquire DCF capability which allows DCF to
+send AdminQ commands that it would like to execute over to the PF and receive
+responses for the same from PF.
+
+.. _figure_ice_dcf:
+
+.. figure:: img/ice_dcf.*
+
+ DCF Communication flow.
+
+#. Create the VFs::
+
+ echo 4 > /sys/bus/pci/devices/0000\:18\:00.0/sriov_numvfs
+
+#. Enable the VF0 trust on::
+
+ ip link set dev enp24s0f0 vf 0 trust on
+
+#. Bind the VF0, and run testpmd with 'cap=dcf' devarg::
+
+ testpmd -l 22-25 -n 4 -w 18:01.0,cap=dcf -- -i
+
+#. Monitor the VF2 interface network traffic::
+
+ tcpdump -e -nn -i enp24s1f2
+
+#. Create one flow to redirect the traffic to VF2 by DCF::
+
+ flow create 0 priority 0 ingress pattern eth / ipv4 src is 192.168.0.2 \
+ dst is 192.168.0.3 / end actions vf id 2 / end
+
+#. Send the packet, and it should be displayed on tcpdump::
+
+ sendp(Ether(src='3c:fd:fe:aa:bb:78', dst='00:00:00:01:02:03')/IP(src=' \
+ 192.168.0.2', dst="192.168.0.3")/TCP(flags='S')/Raw(load='XXXXXXXXXX'), \
+ iface="enp24s0f0", count=10)
+
Sample Application Notes
------------------------
diff --git a/doc/guides/nics/img/ice_dcf.png b/doc/guides/nics/img/ice_dcf.png
new file mode 100644
index 0000000000000000000000000000000000000000..540823c4a05e9ea9d558d233fea77016d1ae5df3
GIT binary patch
literal 39168
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
literal 0
HcmV?d00001
diff --git a/doc/guides/rel_notes/release_20_05.rst b/doc/guides/rel_notes/release_20_05.rst
index 000bbf501..f404ee7fd 100644
--- a/doc/guides/rel_notes/release_20_05.rst
+++ b/doc/guides/rel_notes/release_20_05.rst
@@ -62,6 +62,11 @@ New Features
* Added support for matching on IPv4 Time To Live and IPv6 Hop Limit.
+* **Updated the Intel ice driver.**
+
+ Updated the Intel ice driver with new features and improvements, including:
+
+ * Added support for DCF (Device Config Function) feature.
Removed Items
-------------
diff --git a/drivers/common/Makefile b/drivers/common/Makefile
index 96bd7ac6e..df2e840cf 100644
--- a/drivers/common/Makefile
+++ b/drivers/common/Makefile
@@ -31,6 +31,7 @@ DIRS-y += dpaax
endif
IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
ifneq (,$(findstring y,$(IAVF-y)))
DIRS-y += iavf
endif
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index e22c34287..f493c9ed7 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -11,9 +11,11 @@ LIB = librte_pmd_ice.a
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
CFLAGS += -DALLOW_EXPERIMENTAL_API
+CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
+LDLIBS += -lrte_net -lrte_common_iavf
EXPORT_MAP := rte_pmd_ice_version.map
@@ -84,6 +86,9 @@ ifeq ($(CC_AVX2_SUPPORT), 1)
endif
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+
# install this header file
SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
new file mode 100644
index 000000000..0a99cceb1
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.c
@@ -0,0 +1,474 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include "ice_dcf.h"
+
+#define ICE_DCF_AQ_LEN 32
+#define ICE_DCF_AQ_BUF_SZ 4096
+
+#define ICE_DCF_ARQ_MAX_RETRIES 200
+#define ICE_DCF_ARQ_CHECK_TIME 2 /* msecs */
+
+#define ICE_DCF_VF_RES_BUF_SZ \
+ (sizeof(struct virtchnl_vf_resource) + \
+ IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource))
+
+static __rte_always_inline int
+ice_dcf_send_cmd_req_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+ uint8_t *req_msg, uint16_t req_msglen)
+{
+ return iavf_aq_send_msg_to_pf(&hw->avf, op, IAVF_SUCCESS,
+ req_msg, req_msglen, NULL);
+}
+
+static int
+ice_dcf_recv_cmd_rsp_no_irq(struct ice_dcf_hw *hw, enum virtchnl_ops op,
+ uint8_t *rsp_msgbuf, uint16_t rsp_buflen,
+ uint16_t *rsp_msglen)
+{
+ struct iavf_arq_event_info event;
+ enum virtchnl_ops v_op;
+ int i = 0;
+ int err;
+
+ event.buf_len = rsp_buflen;
+ event.msg_buf = rsp_msgbuf;
+
+ do {
+ err = iavf_clean_arq_element(&hw->avf, &event, NULL);
+ if (err != IAVF_SUCCESS)
+ goto again;
+
+ v_op = rte_le_to_cpu_32(event.desc.cookie_high);
+ if (v_op != op)
+ goto again;
+
+ if (rsp_msglen != NULL)
+ *rsp_msglen = event.msg_len;
+ return rte_le_to_cpu_32(event.desc.cookie_low);
+
+again:
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ return -EIO;
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_clear(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_REMOVE(&hw->vc_cmd_queue, cmd, next);
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline void
+ice_dcf_vc_cmd_set(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ cmd->v_ret = IAVF_ERR_NOT_READY;
+ cmd->rsp_msglen = 0;
+ cmd->pending = 1;
+
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_INSERT_TAIL(&hw->vc_cmd_queue, cmd, next);
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static __rte_always_inline int
+ice_dcf_vc_cmd_send(struct ice_dcf_hw *hw, struct dcf_virtchnl_cmd *cmd)
+{
+ return iavf_aq_send_msg_to_pf(&hw->avf,
+ cmd->v_op, IAVF_SUCCESS,
+ cmd->req_msg, cmd->req_msglen, NULL);
+}
+
+static __rte_always_inline void
+ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
+{
+ struct dcf_virtchnl_cmd *cmd;
+ enum virtchnl_ops v_op;
+ enum iavf_status v_ret;
+ uint16_t aq_op;
+
+ aq_op = rte_le_to_cpu_16(info->desc.opcode);
+ if (unlikely(aq_op != iavf_aqc_opc_send_msg_to_vf)) {
+ PMD_DRV_LOG(ERR,
+ "Request %u is not supported yet", aq_op);
+ return;
+ }
+
+ v_op = rte_le_to_cpu_32(info->desc.cookie_high);
+ if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+ return;
+
+ v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
+
+ rte_spinlock_lock(&hw->vc_cmd_queue_lock);
+
+ TAILQ_FOREACH(cmd, &hw->vc_cmd_queue, next) {
+ if (cmd->v_op == v_op && cmd->pending) {
+ cmd->v_ret = v_ret;
+ cmd->rsp_msglen = RTE_MIN(info->msg_len,
+ cmd->rsp_buflen);
+ if (likely(cmd->rsp_msglen != 0))
+ rte_memcpy(cmd->rsp_msgbuf, info->msg_buf,
+ cmd->rsp_msglen);
+
+ /* prevent compiler reordering */
+ rte_compiler_barrier();
+ cmd->pending = 0;
+ break;
+ }
+ }
+
+ rte_spinlock_unlock(&hw->vc_cmd_queue_lock);
+}
+
+static void
+ice_dcf_handle_virtchnl_msg(struct ice_dcf_hw *hw)
+{
+ struct iavf_arq_event_info info;
+ uint16_t pending = 1;
+ int ret;
+
+ info.buf_len = ICE_DCF_AQ_BUF_SZ;
+ info.msg_buf = hw->arq_buf;
+
+ while (pending) {
+ ret = iavf_clean_arq_element(&hw->avf, &info, &pending);
+ if (ret != IAVF_SUCCESS)
+ break;
+
+ ice_dcf_aq_cmd_handle(hw, &info);
+ }
+}
+
+static int
+ice_dcf_init_check_api_version(struct ice_dcf_hw *hw)
+{
+#define ICE_CPF_VIRTCHNL_VERSION_MAJOR_START 1
+#define ICE_CPF_VIRTCHNL_VERSION_MINOR_START 1
+ struct virtchnl_version_info version, *pver;
+ int err;
+
+ version.major = VIRTCHNL_VERSION_MAJOR;
+ version.minor = VIRTCHNL_VERSION_MINOR;
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_VERSION,
+ (uint8_t *)&version, sizeof(version));
+ if (err) {
+ PMD_INIT_LOG(ERR, "Failed to send OP_VERSION");
+ return err;
+ }
+
+ pver = &hw->virtchnl_version;
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_VERSION,
+ (uint8_t *)pver, sizeof(*pver), NULL);
+ if (err) {
+ PMD_INIT_LOG(ERR, "Failed to get response of OP_VERSION");
+ return -1;
+ }
+
+ PMD_INIT_LOG(DEBUG,
+ "Peer PF API version: %u.%u", pver->major, pver->minor);
+
+ if (pver->major < ICE_CPF_VIRTCHNL_VERSION_MAJOR_START ||
+ (pver->major == ICE_CPF_VIRTCHNL_VERSION_MAJOR_START &&
+ pver->minor < ICE_CPF_VIRTCHNL_VERSION_MINOR_START)) {
+ PMD_INIT_LOG(ERR,
+ "VIRTCHNL API version should not be lower than (%u.%u)",
+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START,
+ ICE_CPF_VIRTCHNL_VERSION_MAJOR_START);
+ return -1;
+ } else if (pver->major > VIRTCHNL_VERSION_MAJOR ||
+ (pver->major == VIRTCHNL_VERSION_MAJOR &&
+ pver->minor > VIRTCHNL_VERSION_MINOR)) {
+ PMD_INIT_LOG(ERR,
+ "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
+ pver->major, pver->minor,
+ VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
+ return -1;
+ }
+
+ PMD_INIT_LOG(DEBUG, "Peer is supported PF host");
+
+ return 0;
+}
+
+static int
+ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
+{
+ uint32_t caps;
+ int err, i;
+
+ caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+ VF_BASE_MODE_OFFLOADS;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+ (uint8_t *)&caps, sizeof(caps));
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to send msg OP_GET_VF_RESOURCE");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
+ (uint8_t *)hw->vf_res,
+ ICE_DCF_VF_RES_BUF_SZ, NULL);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to get response of OP_GET_VF_RESOURCE");
+ return -1;
+ }
+
+ iavf_vf_parse_hw_config(&hw->avf, hw->vf_res);
+
+ hw->vsi_res = NULL;
+ for (i = 0; i < hw->vf_res->num_vsis; i++) {
+ if (hw->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
+ hw->vsi_res = &hw->vf_res->vsi_res[i];
+ }
+
+ if (!hw->vsi_res) {
+ PMD_DRV_LOG(ERR, "no LAN VSI found");
+ return -1;
+ }
+
+ hw->vsi_id = hw->vsi_res->vsi_id;
+ PMD_DRV_LOG(DEBUG, "VSI ID is %u", hw->vsi_id);
+
+ return 0;
+}
+
+static int
+ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
+{
+#define ICE_DCF_RESET_WAIT_CNT 50
+ struct iavf_hw *avf = &hw->avf;
+ int i, reset;
+
+ for (i = 0; i < ICE_DCF_RESET_WAIT_CNT; i++) {
+ reset = IAVF_READ_REG(avf, IAVF_VFGEN_RSTAT) &
+ IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
+ reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
+
+ if (reset == VIRTCHNL_VFR_VFACTIVE ||
+ reset == VIRTCHNL_VFR_COMPLETED)
+ break;
+
+ rte_delay_ms(20);
+ }
+
+ if (i >= ICE_DCF_RESET_WAIT_CNT)
+ return -1;
+
+ return 0;
+}
+
+static inline void
+ice_dcf_enable_irq0(struct ice_dcf_hw *hw)
+{
+ struct iavf_hw *avf = &hw->avf;
+
+ /* Enable admin queue interrupt trigger */
+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1,
+ IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK);
+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+ IAVF_VFINT_DYN_CTL01_INTENA_MASK |
+ IAVF_VFINT_DYN_CTL01_CLEARPBA_MASK |
+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+ IAVF_WRITE_FLUSH(avf);
+}
+
+static inline void
+ice_dcf_disable_irq0(struct ice_dcf_hw *hw)
+{
+ struct iavf_hw *avf = &hw->avf;
+
+ /* Disable all interrupt types */
+ IAVF_WRITE_REG(avf, IAVF_VFINT_ICR0_ENA1, 0);
+ IAVF_WRITE_REG(avf, IAVF_VFINT_DYN_CTL01,
+ IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK);
+
+ IAVF_WRITE_FLUSH(avf);
+}
+
+static void
+ice_dcf_dev_interrupt_handler(void *param)
+{
+ struct ice_dcf_hw *hw = param;
+
+ ice_dcf_disable_irq0(hw);
+
+ ice_dcf_handle_virtchnl_msg(hw);
+
+ ice_dcf_enable_irq0(hw);
+}
+
+int
+ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+ struct dcf_virtchnl_cmd *cmd)
+{
+ int i = 0;
+ int err;
+
+ if ((cmd->req_msg && !cmd->req_msglen) ||
+ (!cmd->req_msg && cmd->req_msglen) ||
+ (cmd->rsp_msgbuf && !cmd->rsp_buflen) ||
+ (!cmd->rsp_msgbuf && cmd->rsp_buflen))
+ return -EINVAL;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_vc_cmd_set(hw, cmd);
+
+ err = ice_dcf_vc_cmd_send(hw, cmd);
+ if (err) {
+ PMD_DRV_LOG(ERR, "fail to send cmd %d", cmd->v_op);
+ goto ret;
+ }
+
+ do {
+ if (!cmd->pending)
+ break;
+
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ if (cmd->v_ret != IAVF_SUCCESS) {
+ err = -1;
+ PMD_DRV_LOG(ERR,
+ "No response (%d times) or return failure (%d) for cmd %d",
+ i, cmd->v_ret, cmd->v_op);
+ }
+
+ret:
+ ice_dcf_aq_cmd_clear(hw, cmd);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+ return err;
+}
+
+int
+ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ int ret;
+
+ hw->avf.hw_addr = pci_dev->mem_resource[0].addr;
+ hw->avf.back = hw;
+
+ hw->avf.bus.bus_id = pci_dev->addr.bus;
+ hw->avf.bus.device = pci_dev->addr.devid;
+ hw->avf.bus.func = pci_dev->addr.function;
+
+ hw->avf.device_id = pci_dev->id.device_id;
+ hw->avf.vendor_id = pci_dev->id.vendor_id;
+ hw->avf.subsystem_device_id = pci_dev->id.subsystem_device_id;
+ hw->avf.subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+
+ hw->avf.aq.num_arq_entries = ICE_DCF_AQ_LEN;
+ hw->avf.aq.num_asq_entries = ICE_DCF_AQ_LEN;
+ hw->avf.aq.arq_buf_size = ICE_DCF_AQ_BUF_SZ;
+ hw->avf.aq.asq_buf_size = ICE_DCF_AQ_BUF_SZ;
+
+ rte_spinlock_init(&hw->vc_cmd_send_lock);
+ rte_spinlock_init(&hw->vc_cmd_queue_lock);
+ TAILQ_INIT(&hw->vc_cmd_queue);
+
+ hw->arq_buf = rte_zmalloc("arq_buf", ICE_DCF_AQ_BUF_SZ, 0);
+ if (hw->arq_buf == NULL) {
+ PMD_INIT_LOG(ERR, "unable to allocate AdminQ buffer memory");
+ goto err;
+ }
+
+ ret = iavf_set_mac_type(&hw->avf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "set_mac_type failed: %d", ret);
+ goto err;
+ }
+
+ ret = ice_dcf_check_reset_done(hw);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "VF is still resetting");
+ goto err;
+ }
+
+ ret = iavf_init_adminq(&hw->avf);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "init_adminq failed: %d", ret);
+ goto err;
+ }
+
+ if (ice_dcf_init_check_api_version(hw)) {
+ PMD_INIT_LOG(ERR, "check_api version failed");
+ goto err_api;
+ }
+
+ hw->vf_res = rte_zmalloc("vf_res", ICE_DCF_VF_RES_BUF_SZ, 0);
+ if (hw->vf_res == NULL) {
+ PMD_INIT_LOG(ERR, "unable to allocate vf_res memory");
+ goto err_api;
+ }
+
+ if (ice_dcf_get_vf_resource(hw)) {
+ PMD_INIT_LOG(ERR, "Failed to get VF resource");
+ goto err_alloc;
+ }
+
+ rte_intr_callback_register(&pci_dev->intr_handle,
+ ice_dcf_dev_interrupt_handler, hw);
+ rte_intr_enable(&pci_dev->intr_handle);
+ ice_dcf_enable_irq0(hw);
+
+ return 0;
+
+err_alloc:
+ rte_free(hw->vf_res);
+err_api:
+ iavf_shutdown_adminq(&hw->avf);
+err:
+ rte_free(hw->arq_buf);
+
+ return -1;
+}
+
+void
+ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
+ ice_dcf_disable_irq0(hw);
+ rte_intr_disable(intr_handle);
+ rte_intr_callback_unregister(intr_handle,
+ ice_dcf_dev_interrupt_handler, hw);
+
+ iavf_shutdown_adminq(&hw->avf);
+
+ rte_free(hw->arq_buf);
+ rte_free(hw->vf_res);
+}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
new file mode 100644
index 000000000..f44c09db2
--- /dev/null
+++ b/drivers/net/ice/ice_dcf.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_H_
+#define _ICE_DCF_H_
+
+#include <rte_ethdev_driver.h>
+
+#include <iavf_prototype.h>
+#include <iavf_adminq_cmd.h>
+#include <iavf_type.h>
+
+#include "ice_logs.h"
+
+struct dcf_virtchnl_cmd {
+ TAILQ_ENTRY(dcf_virtchnl_cmd) next;
+
+ enum virtchnl_ops v_op;
+ enum iavf_status v_ret;
+
+ uint16_t req_msglen;
+ uint8_t *req_msg;
+
+ uint16_t rsp_msglen;
+ uint16_t rsp_buflen;
+ uint8_t *rsp_msgbuf;
+
+ volatile int pending;
+};
+
+struct ice_dcf_hw {
+ struct iavf_hw avf;
+
+ rte_spinlock_t vc_cmd_send_lock;
+ rte_spinlock_t vc_cmd_queue_lock;
+ TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+ uint8_t *arq_buf;
+
+ struct virtchnl_version_info virtchnl_version;
+ struct virtchnl_vf_resource *vf_res; /* VF resource */
+ struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
+ uint16_t vsi_id;
+};
+
+int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
+ struct dcf_virtchnl_cmd *cmd);
+
+int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
+
+#endif /* _ICE_DCF_H_ */
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
new file mode 100644
index 000000000..23f82a487
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -0,0 +1,317 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <rte_interrupts.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_ether.h>
+#include <rte_ethdev_pci.h>
+#include <rte_kvargs.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_dev.h>
+
+#include <iavf_devids.h>
+
+#include "ice_generic_flow.h"
+#include "ice_dcf_ethdev.h"
+
+static uint16_t
+ice_dcf_recv_pkts(__rte_unused void *rx_queue,
+ __rte_unused struct rte_mbuf **bufs,
+ __rte_unused uint16_t nb_pkts)
+{
+ return 0;
+}
+
+static uint16_t
+ice_dcf_xmit_pkts(__rte_unused void *tx_queue,
+ __rte_unused struct rte_mbuf **bufs,
+ __rte_unused uint16_t nb_pkts)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_start(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = ETH_LINK_UP;
+
+ return 0;
+}
+
+static void
+ice_dcf_dev_stop(struct rte_eth_dev *dev)
+{
+ dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+ice_dcf_dev_configure(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_info_get(struct rte_eth_dev *dev,
+ struct rte_eth_dev_info *dev_info)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev_info->max_mac_addrs = 1;
+ dev_info->max_rx_pktlen = (uint32_t)-1;
+ dev_info->max_rx_queues = RTE_DIM(adapter->rxqs);
+ dev_info->max_tx_queues = RTE_DIM(adapter->txqs);
+
+ return 0;
+}
+
+static int
+ice_dcf_stats_get(__rte_unused struct rte_eth_dev *dev,
+ __rte_unused struct rte_eth_stats *igb_stats)
+{
+ return 0;
+}
+
+static int
+ice_dcf_stats_reset(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_enable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_promiscuous_disable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_enable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_allmulticast_disable(__rte_unused struct rte_eth_dev *dev)
+{
+ return 0;
+}
+
+static int
+ice_dcf_dev_filter_ctrl(struct rte_eth_dev *dev,
+ enum rte_filter_type filter_type,
+ __rte_unused enum rte_filter_op filter_op,
+ __rte_unused void *arg)
+{
+ int ret = 0;
+
+ if (!dev)
+ return -EINVAL;
+
+ switch (filter_type) {
+ default:
+ PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+ filter_type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void
+ice_dcf_dev_close(struct rte_eth_dev *dev)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return;
+
+ dev->dev_ops = NULL;
+ dev->rx_pkt_burst = NULL;
+ dev->tx_pkt_burst = NULL;
+ dev->data->mac_addrs = NULL;
+
+ ice_dcf_uninit_hw(dev, &adapter->real_hw);
+}
+
+static void
+ice_dcf_queue_release(__rte_unused void *q)
+{
+}
+
+static int
+ice_dcf_link_update(__rte_unused struct rte_eth_dev *dev,
+ __rte_unused int wait_to_complete)
+{
+ return 0;
+}
+
+static int
+ice_dcf_rx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t rx_queue_id,
+ __rte_unused uint16_t nb_rx_desc,
+ __rte_unused unsigned int socket_id,
+ __rte_unused const struct rte_eth_rxconf *rx_conf,
+ __rte_unused struct rte_mempool *mb_pool)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev->data->rx_queues[rx_queue_id] = &adapter->rxqs[rx_queue_id];
+
+ return 0;
+}
+
+static int
+ice_dcf_tx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t tx_queue_id,
+ __rte_unused uint16_t nb_tx_desc,
+ __rte_unused unsigned int socket_id,
+ __rte_unused const struct rte_eth_txconf *tx_conf)
+{
+ struct ice_dcf_adapter *adapter = dev->data->dev_private;
+
+ dev->data->tx_queues[tx_queue_id] = &adapter->txqs[tx_queue_id];
+
+ return 0;
+}
+
+static const struct eth_dev_ops ice_dcf_eth_dev_ops = {
+ .dev_start = ice_dcf_dev_start,
+ .dev_stop = ice_dcf_dev_stop,
+ .dev_close = ice_dcf_dev_close,
+ .dev_configure = ice_dcf_dev_configure,
+ .dev_infos_get = ice_dcf_dev_info_get,
+ .rx_queue_setup = ice_dcf_rx_queue_setup,
+ .tx_queue_setup = ice_dcf_tx_queue_setup,
+ .rx_queue_release = ice_dcf_queue_release,
+ .tx_queue_release = ice_dcf_queue_release,
+ .link_update = ice_dcf_link_update,
+ .stats_get = ice_dcf_stats_get,
+ .stats_reset = ice_dcf_stats_reset,
+ .promiscuous_enable = ice_dcf_dev_promiscuous_enable,
+ .promiscuous_disable = ice_dcf_dev_promiscuous_disable,
+ .allmulticast_enable = ice_dcf_dev_allmulticast_enable,
+ .allmulticast_disable = ice_dcf_dev_allmulticast_disable,
+ .filter_ctrl = ice_dcf_dev_filter_ctrl,
+};
+
+static int
+ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+
+ eth_dev->dev_ops = &ice_dcf_eth_dev_ops;
+ eth_dev->rx_pkt_burst = ice_dcf_recv_pkts;
+ eth_dev->tx_pkt_burst = ice_dcf_xmit_pkts;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return 0;
+
+ eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
+ if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
+ PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
+ return -1;
+ }
+
+ rte_eth_random_addr(adapter->mac_addr.addr_bytes);
+ eth_dev->data->mac_addrs = &adapter->mac_addr;
+
+ return 0;
+}
+
+static int
+ice_dcf_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+ ice_dcf_dev_close(eth_dev);
+
+ return 0;
+}
+
+static int
+ice_dcf_cap_check_handler(__rte_unused const char *key,
+ const char *value, __rte_unused void *opaque)
+{
+ if (strcmp(value, "dcf"))
+ return -1;
+
+ return 0;
+}
+
+static int
+ice_dcf_cap_selected(struct rte_devargs *devargs)
+{
+ struct rte_kvargs *kvlist;
+ const char *key = "cap";
+ int ret = 0;
+
+ if (devargs == NULL)
+ return 0;
+
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
+ if (kvlist == NULL)
+ return 0;
+
+ if (!rte_kvargs_count(kvlist, key))
+ goto exit;
+
+ /* dcf capability selected when there's a key-value pair: cap=dcf */
+ if (rte_kvargs_process(kvlist, key,
+ ice_dcf_cap_check_handler, NULL) < 0)
+ goto exit;
+
+ ret = 1;
+
+exit:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
+static int eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv,
+ struct rte_pci_device *pci_dev)
+{
+ if (!ice_dcf_cap_selected(pci_dev->device.devargs))
+ return 1;
+
+ return rte_eth_dev_pci_generic_probe(pci_dev,
+ sizeof(struct ice_dcf_adapter),
+ ice_dcf_dev_init);
+}
+
+static int eth_ice_dcf_pci_remove(struct rte_pci_device *pci_dev)
+{
+ return rte_eth_dev_pci_generic_remove(pci_dev, ice_dcf_dev_uninit);
+}
+
+static const struct rte_pci_id pci_id_ice_dcf_map[] = {
+ { RTE_PCI_DEVICE(IAVF_INTEL_VENDOR_ID, IAVF_DEV_ID_ADAPTIVE_VF) },
+ { .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver rte_ice_dcf_pmd = {
+ .id_table = pci_id_ice_dcf_map,
+ .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+ .probe = eth_ice_dcf_pci_probe,
+ .remove = eth_ice_dcf_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_ice_dcf, rte_ice_dcf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_ice_dcf, pci_id_ice_dcf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ice_dcf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_ice_dcf, "cap=dcf");
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
new file mode 100644
index 000000000..0c34a0095
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _ICE_DCF_ETHDEV_H_
+#define _ICE_DCF_ETHDEV_H_
+
+#include "ice_ethdev.h"
+#include "ice_dcf.h"
+
+#define ICE_DCF_MAX_RINGS 1
+
+struct ice_dcf_queue {
+ uint64_t dummy;
+};
+
+struct ice_dcf_adapter {
+ struct ice_dcf_hw real_hw;
+ struct rte_ether_addr mac_addr;
+ struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
+ struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
+};
+
+#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index f9e897bbc..0ba9668d1 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -15,8 +15,8 @@ sources = files(
'ice_hash.c'
)
-deps += ['hash']
-includes += include_directories('base')
+deps += ['hash', 'net', 'common_iavf']
+includes += include_directories('base', '../../common/iavf')
if arch_subdir == 'x86'
sources += files('ice_rxtx_vec_sse.c')
@@ -37,4 +37,7 @@ if arch_subdir == 'x86'
endif
endif
+sources += files('ice_dcf.c',
+ 'ice_dcf_ethdev.c')
+
install_headers('rte_pmd_ice.h')
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index d295ca0a5..f3798a09f 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -185,6 +185,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += -lrte_pmd_i40e
_LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD) += -lrte_pmd_iavf
_LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += -lrte_pmd_ice
IAVF-y := $(CONFIG_RTE_LIBRTE_IAVF_PMD)
+IAVF-y += $(CONFIG_RTE_LIBRTE_ICE_PMD)
ifeq ($(findstring y,$(IAVF-y)),y)
_LDLIBS-y += -lrte_common_iavf
endif
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v6 3/7] net/ice: acquire and disable the DCF capability
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
@ 2020-03-27 2:56 ` Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
` (4 subsequent siblings)
7 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-27 2:56 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
Since the DCF (Device Config Function) controls the flow setting of
other VFs by the mailbox with PF, for security, it needs to acquire
the DCF capability from PF when starts, and disable it when exits.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
drivers/net/ice/ice_dcf.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index 0a99cceb1..6ea68feb9 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -227,7 +227,7 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
int err, i;
caps = VIRTCHNL_VF_OFFLOAD_WB_ON_ITR | VIRTCHNL_VF_OFFLOAD_RX_POLLING |
- VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED | VIRTCHNL_VF_CAP_DCF |
VF_BASE_MODE_OFFLOADS;
err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_GET_VF_RESOURCES,
@@ -264,6 +264,30 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
return 0;
}
+static int
+ice_dcf_mode_disable(struct ice_dcf_hw *hw)
+{
+ int err;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
+ NULL, 0);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to send msg OP_DCF_DISABLE");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_DISABLE,
+ hw->arq_buf, ICE_DCF_AQ_BUF_SZ, NULL);
+ if (err) {
+ PMD_DRV_LOG(ERR,
+ "Failed to get response of OP_DCF_DISABLE %d",
+ err);
+ return -1;
+ }
+
+ return 0;
+}
+
static int
ice_dcf_check_reset_done(struct ice_dcf_hw *hw)
{
@@ -467,6 +491,7 @@ ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
rte_intr_callback_unregister(intr_handle,
ice_dcf_dev_interrupt_handler, hw);
+ ice_dcf_mode_disable(hw);
iavf_shutdown_adminq(&hw->avf);
rte_free(hw->arq_buf);
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v6 4/7] net/ice: handle the AdminQ command by DCF
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Haiyue Wang
` (2 preceding siblings ...)
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 3/7] net/ice: acquire and disable the DCF capability Haiyue Wang
@ 2020-03-27 2:56 ` Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 5/7] net/ice: export the DDP definition symbols Haiyue Wang
` (3 subsequent siblings)
7 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-27 2:56 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) splits the AdminQ command into two
parts: one is the descriptor of AdminQ command, the other is the buffer
of AdminQ command (the descriptor has BUF flag set). When both of them
are received by the PF, the PF will handle them as one command.
And also, the filled descriptor and buffer of the response will be sent
back to DCF one by one through the virtchnl from PF.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
drivers/net/ice/ice_dcf.c | 65 +++++++++++++++++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 4 ++-
2 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index 6ea68feb9..baef5b8dc 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -396,6 +396,71 @@ ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
return err;
}
+int
+ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
+ void *buf, uint16_t buf_size)
+{
+ struct dcf_virtchnl_cmd desc_cmd, buff_cmd;
+ struct ice_dcf_hw *hw = dcf_hw;
+ int err = 0;
+ int i = 0;
+
+ if ((buf && !buf_size) || (!buf && buf_size) ||
+ buf_size > ICE_DCF_AQ_BUF_SZ)
+ return -EINVAL;
+
+ desc_cmd.v_op = VIRTCHNL_OP_DCF_CMD_DESC;
+ desc_cmd.req_msglen = sizeof(*desc);
+ desc_cmd.req_msg = (uint8_t *)desc;
+ desc_cmd.rsp_buflen = sizeof(*desc);
+ desc_cmd.rsp_msgbuf = (uint8_t *)desc;
+
+ if (buf == NULL)
+ return ice_dcf_execute_virtchnl_cmd(hw, &desc_cmd);
+
+ desc->flags |= rte_cpu_to_le_16(ICE_AQ_FLAG_BUF);
+
+ buff_cmd.v_op = VIRTCHNL_OP_DCF_CMD_BUFF;
+ buff_cmd.req_msglen = buf_size;
+ buff_cmd.req_msg = buf;
+ buff_cmd.rsp_buflen = buf_size;
+ buff_cmd.rsp_msgbuf = buf;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+ ice_dcf_vc_cmd_set(hw, &desc_cmd);
+ ice_dcf_vc_cmd_set(hw, &buff_cmd);
+
+ if (ice_dcf_vc_cmd_send(hw, &desc_cmd) ||
+ ice_dcf_vc_cmd_send(hw, &buff_cmd)) {
+ err = -1;
+ PMD_DRV_LOG(ERR, "fail to send OP_DCF_CMD_DESC/BUFF");
+ goto ret;
+ }
+
+ do {
+ if ((!desc_cmd.pending && !buff_cmd.pending) ||
+ (!desc_cmd.pending && desc_cmd.v_ret != IAVF_SUCCESS) ||
+ (!buff_cmd.pending && buff_cmd.v_ret != IAVF_SUCCESS))
+ break;
+
+ rte_delay_ms(ICE_DCF_ARQ_CHECK_TIME);
+ } while (i++ < ICE_DCF_ARQ_MAX_RETRIES);
+
+ if (desc_cmd.v_ret != IAVF_SUCCESS || buff_cmd.v_ret != IAVF_SUCCESS) {
+ err = -1;
+ PMD_DRV_LOG(ERR,
+ "No response (%d times) or return failure (desc: %d / buff: %d)",
+ i, desc_cmd.v_ret, buff_cmd.v_ret);
+ }
+
+ret:
+ ice_dcf_aq_cmd_clear(hw, &desc_cmd);
+ ice_dcf_aq_cmd_clear(hw, &buff_cmd);
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+
+ return err;
+}
+
int
ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
{
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index f44c09db2..99bd53b02 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -11,6 +11,7 @@
#include <iavf_adminq_cmd.h>
#include <iavf_type.h>
+#include "base/ice_type.h"
#include "ice_logs.h"
struct dcf_virtchnl_cmd {
@@ -45,7 +46,8 @@ struct ice_dcf_hw {
int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
struct dcf_virtchnl_cmd *cmd);
-
+int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
+ void *buf, uint16_t buf_size);
int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v6 5/7] net/ice: export the DDP definition symbols
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Haiyue Wang
` (3 preceding siblings ...)
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
@ 2020-03-27 2:56 ` Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
` (2 subsequent siblings)
7 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-27 2:56 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
A new DCF PMD will be introduced, which runs on Intel VF hardware, and
it is a pure software design to control the advance functionality (such
as switch, ACL) for rest of the VFs.
The DCF (Device Config Function) feature shares the core functions of
the ICE PMD, like it needs to export the DDP definition symbols for the
new DCF PMD use.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Xiaolong Ye <xiaolong.ye@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
drivers/net/ice/ice_ethdev.c | 9 +--------
drivers/net/ice/ice_ethdev.h | 8 ++++++++
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c
index 3498a5075..3c38472de 100644
--- a/drivers/net/ice/ice_ethdev.c
+++ b/drivers/net/ice/ice_ethdev.c
@@ -67,15 +67,8 @@ static struct proto_xtr_ol_flag ice_proto_xtr_ol_flag_params[] = {
#define ICE_DFLT_OUTER_TAG_TYPE ICE_AQ_VSI_OUTER_TAG_VLAN_9100
-/* DDP package search path */
-#define ICE_PKG_FILE_DEFAULT "/lib/firmware/intel/ice/ddp/ice.pkg"
-#define ICE_PKG_FILE_UPDATES "/lib/firmware/updates/intel/ice/ddp/ice.pkg"
-#define ICE_PKG_FILE_SEARCH_PATH_DEFAULT "/lib/firmware/intel/ice/ddp/"
-#define ICE_PKG_FILE_SEARCH_PATH_UPDATES "/lib/firmware/updates/intel/ice/ddp/"
-
#define ICE_OS_DEFAULT_PKG_NAME "ICE OS Default Package"
#define ICE_COMMS_PKG_NAME "ICE COMMS Package"
-#define ICE_MAX_PKG_FILENAME_SIZE 256
#define ICE_MAX_RES_DESC_NUM 1024
int ice_logtype_init;
@@ -1833,7 +1826,7 @@ ice_pkg_file_search_path(struct rte_pci_device *pci_dev, char *pkg_file)
return 0;
}
-static enum ice_pkg_type
+enum ice_pkg_type
ice_load_pkg_type(struct ice_hw *hw)
{
enum ice_pkg_type package_type;
diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h
index da557a254..7b94a3c3e 100644
--- a/drivers/net/ice/ice_ethdev.h
+++ b/drivers/net/ice/ice_ethdev.h
@@ -42,6 +42,13 @@
#define ICE_MAX_PKT_TYPE 1024
+/* DDP package search path */
+#define ICE_PKG_FILE_DEFAULT "/lib/firmware/intel/ice/ddp/ice.pkg"
+#define ICE_PKG_FILE_UPDATES "/lib/firmware/updates/intel/ice/ddp/ice.pkg"
+#define ICE_PKG_FILE_SEARCH_PATH_DEFAULT "/lib/firmware/intel/ice/ddp/"
+#define ICE_PKG_FILE_SEARCH_PATH_UPDATES "/lib/firmware/updates/intel/ice/ddp/"
+#define ICE_MAX_PKG_FILENAME_SIZE 256
+
/**
* vlan_id is a 12 bit number.
* The VFTA array is actually a 4096 bit array, 128 of 32bit elements.
@@ -457,6 +464,7 @@ struct ice_vsi_vlan_pvid_info {
#define ICE_PF_TO_ETH_DEV(pf) \
(((struct ice_pf *)pf)->adapter->eth_dev)
+enum ice_pkg_type ice_load_pkg_type(struct ice_hw *hw);
struct ice_vsi *
ice_setup_vsi(struct ice_pf *pf, enum ice_vsi_type type);
int
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v6 6/7] net/ice: handle the PF initialization by DCF
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Haiyue Wang
` (4 preceding siblings ...)
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 5/7] net/ice: export the DDP definition symbols Haiyue Wang
@ 2020-03-27 2:56 ` Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
2020-03-27 15:26 ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Ye Xiaolong
7 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-27 2:56 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) works at the user PF level, it can't
access the real PF hardware directly. So it will pass through the PF's
AdminQ command by the DCF's mailbox.
And the DCF is mainly used to control the flow setting of other VFs, so
it only needs to initialize some core functions related to the flow.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
drivers/net/ice/Makefile | 1 +
drivers/net/ice/ice_dcf.c | 7 +-
drivers/net/ice/ice_dcf.h | 3 +
drivers/net/ice/ice_dcf_ethdev.c | 10 +-
drivers/net/ice/ice_dcf_ethdev.h | 11 +-
drivers/net/ice/ice_dcf_parent.c | 263 +++++++++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
7 files changed, 292 insertions(+), 6 deletions(-)
create mode 100644 drivers/net/ice/ice_dcf_parent.c
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index f493c9ed7..3ecc72219 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -88,6 +88,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf.c
SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcf_parent.c
# install this header file
SYMLINK-$(CONFIG_RTE_LIBRTE_ICE_PMD)-include := rte_pmd_ice.h
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index baef5b8dc..c799cdf83 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -124,8 +124,13 @@ ice_dcf_aq_cmd_handle(struct ice_dcf_hw *hw, struct iavf_arq_event_info *info)
}
v_op = rte_le_to_cpu_32(info->desc.cookie_high);
- if (unlikely(v_op == VIRTCHNL_OP_EVENT))
+ if (v_op == VIRTCHNL_OP_EVENT) {
+ if (hw->vc_event_msg_cb != NULL)
+ hw->vc_event_msg_cb(hw,
+ info->msg_buf,
+ info->msg_len);
return;
+ }
v_ret = rte_le_to_cpu_32(info->desc.cookie_low);
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index 99bd53b02..ecd6303a0 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -36,6 +36,9 @@ struct ice_dcf_hw {
rte_spinlock_t vc_cmd_send_lock;
rte_spinlock_t vc_cmd_queue_lock;
TAILQ_HEAD(, dcf_virtchnl_cmd) vc_cmd_queue;
+ void (*vc_event_msg_cb)(struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen);
+
uint8_t *arq_buf;
struct virtchnl_version_info virtchnl_version;
diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c
index 23f82a487..af94caeff 100644
--- a/drivers/net/ice/ice_dcf_ethdev.c
+++ b/drivers/net/ice/ice_dcf_ethdev.c
@@ -145,8 +145,8 @@ ice_dcf_dev_close(struct rte_eth_dev *dev)
dev->dev_ops = NULL;
dev->rx_pkt_burst = NULL;
dev->tx_pkt_burst = NULL;
- dev->data->mac_addrs = NULL;
+ ice_dcf_uninit_parent_adapter(dev);
ice_dcf_uninit_hw(dev, &adapter->real_hw);
}
@@ -225,13 +225,17 @@ ice_dcf_dev_init(struct rte_eth_dev *eth_dev)
eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+ adapter->real_hw.vc_event_msg_cb = ice_dcf_handle_pf_event_msg;
if (ice_dcf_init_hw(eth_dev, &adapter->real_hw) != 0) {
PMD_INIT_LOG(ERR, "Failed to init DCF hardware");
return -1;
}
- rte_eth_random_addr(adapter->mac_addr.addr_bytes);
- eth_dev->data->mac_addrs = &adapter->mac_addr;
+ if (ice_dcf_init_parent_adapter(eth_dev) != 0) {
+ PMD_INIT_LOG(ERR, "Failed to init DCF parent adapter");
+ ice_dcf_uninit_hw(eth_dev, &adapter->real_hw);
+ return -1;
+ }
return 0;
}
diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h
index 0c34a0095..e60e808d8 100644
--- a/drivers/net/ice/ice_dcf_ethdev.h
+++ b/drivers/net/ice/ice_dcf_ethdev.h
@@ -5,6 +5,9 @@
#ifndef _ICE_DCF_ETHDEV_H_
#define _ICE_DCF_ETHDEV_H_
+#include "base/ice_common.h"
+#include "base/ice_adminq_cmd.h"
+
#include "ice_ethdev.h"
#include "ice_dcf.h"
@@ -15,10 +18,16 @@ struct ice_dcf_queue {
};
struct ice_dcf_adapter {
+ struct ice_adapter parent; /* Must be first */
+
struct ice_dcf_hw real_hw;
- struct rte_ether_addr mac_addr;
struct ice_dcf_queue rxqs[ICE_DCF_MAX_RINGS];
struct ice_dcf_queue txqs[ICE_DCF_MAX_RINGS];
};
+void ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen);
+int ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev);
+void ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev);
+
#endif /* _ICE_DCF_ETHDEV_H_ */
diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
new file mode 100644
index 000000000..138838a73
--- /dev/null
+++ b/drivers/net/ice/ice_dcf_parent.c
@@ -0,0 +1,263 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "ice_dcf_ethdev.h"
+
+void
+ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
+ uint8_t *msg, uint16_t msglen)
+{
+ struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
+
+ if (msglen < sizeof(struct virtchnl_pf_event)) {
+ PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen);
+ return;
+ }
+
+ switch (pf_msg->event) {
+ case VIRTCHNL_EVENT_RESET_IMPENDING:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
+ break;
+ case VIRTCHNL_EVENT_LINK_CHANGE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
+ break;
+ case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
+ break;
+ }
+}
+
+static int
+ice_dcf_init_parent_hw(struct ice_hw *hw)
+{
+ struct ice_aqc_get_phy_caps_data *pcaps;
+ enum ice_status status;
+
+ status = ice_aq_get_fw_ver(hw, NULL);
+ if (status)
+ return status;
+
+ status = ice_get_caps(hw);
+ if (status)
+ return status;
+
+ hw->port_info = (struct ice_port_info *)
+ ice_malloc(hw, sizeof(*hw->port_info));
+ if (!hw->port_info)
+ return ICE_ERR_NO_MEMORY;
+
+ /* set the back pointer to HW */
+ hw->port_info->hw = hw;
+
+ /* Initialize port_info struct with switch configuration data */
+ status = ice_get_initial_sw_cfg(hw);
+ if (status)
+ goto err_unroll_alloc;
+
+ pcaps = (struct ice_aqc_get_phy_caps_data *)
+ ice_malloc(hw, sizeof(*pcaps));
+ if (!pcaps) {
+ status = ICE_ERR_NO_MEMORY;
+ goto err_unroll_alloc;
+ }
+
+ /* Initialize port_info struct with PHY capabilities */
+ status = ice_aq_get_phy_caps(hw->port_info, false,
+ ICE_AQC_REPORT_TOPO_CAP, pcaps, NULL);
+ ice_free(hw, pcaps);
+ if (status)
+ goto err_unroll_alloc;
+
+ /* Initialize port_info struct with link information */
+ status = ice_aq_get_link_info(hw->port_info, false, NULL, NULL);
+ if (status)
+ goto err_unroll_alloc;
+
+ status = ice_init_fltr_mgmt_struct(hw);
+ if (status)
+ goto err_unroll_alloc;
+
+ status = ice_init_hw_tbls(hw);
+ if (status)
+ goto err_unroll_fltr_mgmt_struct;
+
+ PMD_INIT_LOG(INFO,
+ "firmware %d.%d.%d api %d.%d.%d build 0x%08x",
+ hw->fw_maj_ver, hw->fw_min_ver, hw->fw_patch,
+ hw->api_maj_ver, hw->api_min_ver, hw->api_patch,
+ hw->fw_build);
+
+ return ICE_SUCCESS;
+
+err_unroll_fltr_mgmt_struct:
+ ice_cleanup_fltr_mgmt_struct(hw);
+err_unroll_alloc:
+ ice_free(hw, hw->port_info);
+ hw->port_info = NULL;
+
+ return status;
+}
+
+static void ice_dcf_uninit_parent_hw(struct ice_hw *hw)
+{
+ ice_cleanup_fltr_mgmt_struct(hw);
+
+ ice_free_seg(hw);
+ ice_free_hw_tbls(hw);
+
+ ice_free(hw, hw->port_info);
+ hw->port_info = NULL;
+
+ ice_clear_all_vsi_ctx(hw);
+}
+
+static int
+ice_dcf_request_pkg_name(struct ice_hw *hw, char *pkg_name)
+{
+ struct ice_dcf_adapter *dcf_adapter =
+ container_of(hw, struct ice_dcf_adapter, parent.hw);
+
+ /* TODO: check with DSN firstly by iAVF */
+ PMD_INIT_LOG(DEBUG,
+ "DCF VSI_ID = %u",
+ dcf_adapter->real_hw.vsi_id);
+
+ snprintf(pkg_name,
+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_UPDATES);
+ if (!access(pkg_name, 0))
+ return 0;
+
+ snprintf(pkg_name,
+ ICE_MAX_PKG_FILENAME_SIZE, "%s", ICE_PKG_FILE_DEFAULT);
+ if (!access(pkg_name, 0))
+ return 0;
+
+ return -1;
+}
+
+static int
+ice_dcf_load_pkg(struct ice_hw *hw)
+{
+ char pkg_name[ICE_MAX_PKG_FILENAME_SIZE];
+ uint8_t *pkg_buf;
+ uint32_t buf_len;
+ struct stat st;
+ FILE *fp;
+ int err;
+
+ if (ice_dcf_request_pkg_name(hw, pkg_name)) {
+ PMD_INIT_LOG(ERR, "Failed to locate the package file");
+ return -ENOENT;
+ }
+
+ PMD_INIT_LOG(DEBUG, "DDP package name: %s", pkg_name);
+
+ err = stat(pkg_name, &st);
+ if (err) {
+ PMD_INIT_LOG(ERR, "Failed to get file status");
+ return err;
+ }
+
+ buf_len = st.st_size;
+ pkg_buf = rte_malloc(NULL, buf_len, 0);
+ if (!pkg_buf) {
+ PMD_INIT_LOG(ERR, "failed to allocate buffer of size %u for package",
+ buf_len);
+ return -1;
+ }
+
+ fp = fopen(pkg_name, "rb");
+ if (!fp) {
+ PMD_INIT_LOG(ERR, "failed to open file: %s", pkg_name);
+ err = -1;
+ goto ret;
+ }
+
+ err = fread(pkg_buf, buf_len, 1, fp);
+ fclose(fp);
+ if (err != 1) {
+ PMD_INIT_LOG(ERR, "failed to read package data");
+ err = -1;
+ goto ret;
+ }
+
+ err = ice_copy_and_init_pkg(hw, pkg_buf, buf_len);
+ if (err)
+ PMD_INIT_LOG(ERR, "ice_copy_and_init_hw failed: %d", err);
+
+ret:
+ rte_free(pkg_buf);
+ return err;
+}
+
+int
+ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+ struct ice_adapter *parent_adapter = &adapter->parent;
+ struct ice_hw *parent_hw = &parent_adapter->hw;
+ struct ice_dcf_hw *hw = &adapter->real_hw;
+ const struct rte_ether_addr *mac;
+ int err;
+
+ parent_adapter->eth_dev = eth_dev;
+ parent_adapter->pf.adapter = parent_adapter;
+ parent_adapter->pf.dev_data = eth_dev->data;
+ parent_hw->back = parent_adapter;
+ parent_hw->mac_type = ICE_MAC_GENERIC;
+ parent_hw->vendor_id = ICE_INTEL_VENDOR_ID;
+
+ ice_init_lock(&parent_hw->adminq.sq_lock);
+ ice_init_lock(&parent_hw->adminq.rq_lock);
+ parent_hw->aq_send_cmd_fn = ice_dcf_send_aq_cmd;
+ parent_hw->aq_send_cmd_param = &adapter->real_hw;
+ parent_hw->dcf_enabled = true;
+
+ err = ice_dcf_init_parent_hw(parent_hw);
+ if (err) {
+ PMD_INIT_LOG(ERR, "failed to init the DCF parent hardware with error %d",
+ err);
+ return err;
+ }
+
+ err = ice_dcf_load_pkg(parent_hw);
+ if (err) {
+ PMD_INIT_LOG(ERR, "failed to load package with error %d",
+ err);
+ goto uninit_hw;
+ }
+ parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
+
+ mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
+ if (rte_is_valid_assigned_ether_addr(mac))
+ rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
+ else
+ rte_eth_random_addr(parent_adapter->pf.dev_addr.addr_bytes);
+
+ eth_dev->data->mac_addrs = &parent_adapter->pf.dev_addr;
+
+ return 0;
+
+uninit_hw:
+ ice_dcf_uninit_parent_hw(parent_hw);
+ return err;
+}
+
+void
+ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev)
+{
+ struct ice_dcf_adapter *adapter = eth_dev->data->dev_private;
+ struct ice_adapter *parent_adapter = &adapter->parent;
+ struct ice_hw *parent_hw = &parent_adapter->hw;
+
+ eth_dev->data->mac_addrs = NULL;
+
+ ice_dcf_uninit_parent_hw(parent_hw);
+}
diff --git a/drivers/net/ice/meson.build b/drivers/net/ice/meson.build
index 0ba9668d1..7e9037f3b 100644
--- a/drivers/net/ice/meson.build
+++ b/drivers/net/ice/meson.build
@@ -38,6 +38,7 @@ if arch_subdir == 'x86'
endif
sources += files('ice_dcf.c',
- 'ice_dcf_ethdev.c')
+ 'ice_dcf_ethdev.c',
+ 'ice_dcf_parent.c')
install_headers('rte_pmd_ice.h')
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* [dpdk-dev] [PATCH v6 7/7] net/ice: get the VF hardware index in DCF
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Haiyue Wang
` (5 preceding siblings ...)
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
@ 2020-03-27 2:56 ` Haiyue Wang
2020-03-27 15:26 ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Ye Xiaolong
7 siblings, 0 replies; 94+ messages in thread
From: Haiyue Wang @ 2020-03-27 2:56 UTC (permalink / raw)
To: dev, xiaolong.ye, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing
Cc: wei.zhao1, Haiyue Wang
The DCF (Device Config Function) needs the hardware index of the VFs to
control the flow setting. And also if the VF resets, the index may be
changed, so it should handle this in VF reset event.
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
---
drivers/net/ice/Makefile | 1 +
drivers/net/ice/ice_dcf.c | 89 +++++++++++++++++++++++++++++++
drivers/net/ice/ice_dcf.h | 6 +++
drivers/net/ice/ice_dcf_parent.c | 90 +++++++++++++++++++++++++++++++-
4 files changed, 185 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile
index 3ecc72219..622a853af 100644
--- a/drivers/net/ice/Makefile
+++ b/drivers/net/ice/Makefile
@@ -16,6 +16,7 @@ CFLAGS += -I$(RTE_SDK)/drivers/common/iavf
LDLIBS += -lrte_eal -lrte_mbuf -lrte_ethdev -lrte_kvargs
LDLIBS += -lrte_bus_pci -lrte_mempool -lrte_hash
LDLIBS += -lrte_net -lrte_common_iavf
+LDLIBS += -lpthread
EXPORT_MAP := rte_pmd_ice_version.map
diff --git a/drivers/net/ice/ice_dcf.c b/drivers/net/ice/ice_dcf.c
index c799cdf83..4c30f0e60 100644
--- a/drivers/net/ice/ice_dcf.c
+++ b/drivers/net/ice/ice_dcf.c
@@ -269,6 +269,65 @@ ice_dcf_get_vf_resource(struct ice_dcf_hw *hw)
return 0;
}
+static int
+ice_dcf_get_vf_vsi_map(struct ice_dcf_hw *hw)
+{
+ struct virtchnl_dcf_vsi_map *vsi_map;
+ uint32_t valid_msg_len;
+ uint16_t len;
+ int err;
+
+ err = ice_dcf_send_cmd_req_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
+ NULL, 0);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to send msg OP_DCF_GET_VSI_MAP");
+ return err;
+ }
+
+ err = ice_dcf_recv_cmd_rsp_no_irq(hw, VIRTCHNL_OP_DCF_GET_VSI_MAP,
+ hw->arq_buf, ICE_DCF_AQ_BUF_SZ,
+ &len);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Failed to get response of OP_DCF_GET_VSI_MAP");
+ return err;
+ }
+
+ vsi_map = (struct virtchnl_dcf_vsi_map *)hw->arq_buf;
+ valid_msg_len = (vsi_map->num_vfs - 1) * sizeof(vsi_map->vf_vsi[0]) +
+ sizeof(*vsi_map);
+ if (len != valid_msg_len) {
+ PMD_DRV_LOG(ERR, "invalid vf vsi map response with length %u",
+ len);
+ return -EINVAL;
+ }
+
+ if (hw->num_vfs != 0 && hw->num_vfs != vsi_map->num_vfs) {
+ PMD_DRV_LOG(ERR, "The number VSI map (%u) doesn't match the number of VFs (%u)",
+ vsi_map->num_vfs, hw->num_vfs);
+ return -EINVAL;
+ }
+
+ len = vsi_map->num_vfs * sizeof(vsi_map->vf_vsi[0]);
+
+ if (!hw->vf_vsi_map) {
+ hw->vf_vsi_map = rte_zmalloc("vf_vsi_ctx", len, 0);
+ if (!hw->vf_vsi_map) {
+ PMD_DRV_LOG(ERR, "Failed to alloc memory for VSI context");
+ return -ENOMEM;
+ }
+
+ hw->num_vfs = vsi_map->num_vfs;
+ }
+
+ if (!memcmp(hw->vf_vsi_map, vsi_map->vf_vsi, len)) {
+ PMD_DRV_LOG(DEBUG, "VF VSI map doesn't change");
+ return 1;
+ }
+
+ rte_memcpy(hw->vf_vsi_map, vsi_map->vf_vsi, len);
+ return 0;
+}
+
static int
ice_dcf_mode_disable(struct ice_dcf_hw *hw)
{
@@ -466,6 +525,28 @@ ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
return err;
}
+int
+ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(hw->eth_dev);
+ int err = 0;
+
+ rte_spinlock_lock(&hw->vc_cmd_send_lock);
+
+ rte_intr_disable(&pci_dev->intr_handle);
+ ice_dcf_disable_irq0(hw);
+
+ if (ice_dcf_get_vf_resource(hw) || ice_dcf_get_vf_vsi_map(hw))
+ err = -1;
+
+ rte_intr_enable(&pci_dev->intr_handle);
+ ice_dcf_enable_irq0(hw);
+
+ rte_spinlock_unlock(&hw->vc_cmd_send_lock);
+
+ return err;
+}
+
int
ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
{
@@ -533,6 +614,13 @@ ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
goto err_alloc;
}
+ if (ice_dcf_get_vf_vsi_map(hw) < 0) {
+ PMD_INIT_LOG(ERR, "Failed to get VF VSI map");
+ ice_dcf_mode_disable(hw);
+ goto err_alloc;
+ }
+
+ hw->eth_dev = eth_dev;
rte_intr_callback_register(&pci_dev->intr_handle,
ice_dcf_dev_interrupt_handler, hw);
rte_intr_enable(&pci_dev->intr_handle);
@@ -565,5 +653,6 @@ ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
iavf_shutdown_adminq(&hw->avf);
rte_free(hw->arq_buf);
+ rte_free(hw->vf_vsi_map);
rte_free(hw->vf_res);
}
diff --git a/drivers/net/ice/ice_dcf.h b/drivers/net/ice/ice_dcf.h
index ecd6303a0..d2e447b48 100644
--- a/drivers/net/ice/ice_dcf.h
+++ b/drivers/net/ice/ice_dcf.h
@@ -41,16 +41,22 @@ struct ice_dcf_hw {
uint8_t *arq_buf;
+ uint16_t num_vfs;
+ uint16_t *vf_vsi_map;
+
struct virtchnl_version_info virtchnl_version;
struct virtchnl_vf_resource *vf_res; /* VF resource */
struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
uint16_t vsi_id;
+
+ struct rte_eth_dev *eth_dev;
};
int ice_dcf_execute_virtchnl_cmd(struct ice_dcf_hw *hw,
struct dcf_virtchnl_cmd *cmd);
int ice_dcf_send_aq_cmd(void *dcf_hw, struct ice_aq_desc *desc,
void *buf, uint16_t buf_size);
+int ice_dcf_handle_vsi_update_event(struct ice_dcf_hw *hw);
int ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
void ice_dcf_uninit_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw);
diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c
index 138838a73..ff08292a1 100644
--- a/drivers/net/ice/ice_dcf_parent.c
+++ b/drivers/net/ice/ice_dcf_parent.c
@@ -3,15 +3,92 @@
*/
#include <sys/types.h>
#include <sys/stat.h>
+#include <pthread.h>
#include <unistd.h>
+#include <rte_spinlock.h>
+
#include "ice_dcf_ethdev.h"
+#define ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL 100000 /* us */
+static rte_spinlock_t vsi_update_lock = RTE_SPINLOCK_INITIALIZER;
+
+static __rte_always_inline void
+ice_dcf_update_vsi_ctx(struct ice_hw *hw, uint16_t vsi_handle,
+ uint16_t vsi_map)
+{
+ struct ice_vsi_ctx *vsi_ctx;
+
+ if (unlikely(vsi_handle >= ICE_MAX_VSI)) {
+ PMD_DRV_LOG(ERR, "Invalid vsi handle %u", vsi_handle);
+ return;
+ }
+
+ vsi_ctx = hw->vsi_ctx[vsi_handle];
+
+ if (vsi_map & VIRTCHNL_DCF_VF_VSI_VALID) {
+ if (!vsi_ctx) {
+ vsi_ctx = ice_malloc(hw, sizeof(*vsi_ctx));
+ if (!vsi_ctx) {
+ PMD_DRV_LOG(ERR, "No memory for vsi context %u",
+ vsi_handle);
+ return;
+ }
+ }
+
+ vsi_ctx->vsi_num = (vsi_map & VIRTCHNL_DCF_VF_VSI_ID_M) >>
+ VIRTCHNL_DCF_VF_VSI_ID_S;
+ hw->vsi_ctx[vsi_handle] = vsi_ctx;
+
+ PMD_DRV_LOG(DEBUG, "VF%u is assigned with vsi number %u",
+ vsi_handle, vsi_ctx->vsi_num);
+ } else {
+ hw->vsi_ctx[vsi_handle] = NULL;
+
+ ice_free(hw, vsi_ctx);
+
+ PMD_DRV_LOG(NOTICE, "VF%u is disabled", vsi_handle);
+ }
+}
+
+static void
+ice_dcf_update_vf_vsi_map(struct ice_hw *hw, uint16_t num_vfs,
+ uint16_t *vf_vsi_map)
+{
+ uint16_t vf_id;
+
+ for (vf_id = 0; vf_id < num_vfs; vf_id++)
+ ice_dcf_update_vsi_ctx(hw, vf_id, vf_vsi_map[vf_id]);
+}
+
+static void*
+ice_dcf_vsi_update_service_handler(void *param)
+{
+ struct ice_dcf_hw *hw = param;
+
+ usleep(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL);
+
+ rte_spinlock_lock(&vsi_update_lock);
+
+ if (!ice_dcf_handle_vsi_update_event(hw)) {
+ struct ice_dcf_adapter *dcf_ad =
+ container_of(hw, struct ice_dcf_adapter, real_hw);
+
+ ice_dcf_update_vf_vsi_map(&dcf_ad->parent.hw,
+ hw->num_vfs, hw->vf_vsi_map);
+ }
+
+ rte_spinlock_unlock(&vsi_update_lock);
+
+ return NULL;
+}
+
void
-ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
+ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw,
uint8_t *msg, uint16_t msglen)
{
struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg;
+ pthread_t thread;
if (msglen < sizeof(struct virtchnl_pf_event)) {
PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen);
@@ -21,6 +98,8 @@ ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
switch (pf_msg->event) {
case VIRTCHNL_EVENT_RESET_IMPENDING:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
+ pthread_create(&thread, NULL,
+ ice_dcf_vsi_update_service_handler, dcf_hw);
break;
case VIRTCHNL_EVENT_LINK_CHANGE:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
@@ -28,6 +107,13 @@ ice_dcf_handle_pf_event_msg(__rte_unused struct ice_dcf_hw *dcf_hw,
case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
break;
+ case VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE:
+ PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE event : VF%u with VSI num %u",
+ pf_msg->event_data.vf_vsi_map.vf_id,
+ pf_msg->event_data.vf_vsi_map.vsi_id);
+ pthread_create(&thread, NULL,
+ ice_dcf_vsi_update_service_handler, dcf_hw);
+ break;
default:
PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event);
break;
@@ -235,6 +321,8 @@ ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)
}
parent_adapter->active_pkg_type = ice_load_pkg_type(parent_hw);
+ ice_dcf_update_vf_vsi_map(parent_hw, hw->num_vfs, hw->vf_vsi_map);
+
mac = (const struct rte_ether_addr *)hw->avf.mac.addr;
if (rte_is_valid_assigned_ether_addr(mac))
rte_ether_addr_copy(mac, &parent_adapter->pf.dev_addr);
--
2.26.0
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Haiyue Wang
` (6 preceding siblings ...)
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
@ 2020-03-27 15:26 ` Ye Xiaolong
7 siblings, 0 replies; 94+ messages in thread
From: Ye Xiaolong @ 2020-03-27 15:26 UTC (permalink / raw)
To: Haiyue Wang
Cc: dev, qi.z.zhang, jingjing.wu, qiming.yang, beilei.xing, wei.zhao1
On 03/27, Haiyue Wang wrote:
>A DCF (Device Config Function) based approach is proposed where a device
>bound to the device's VF0 can act as a sole controlling entity to exercise
>advance functionality (such as switch, ACL) for rest of the VFs.
>
>The DCF works as a standalone PMD to support this function, which shares the
>ice PMD flow control core function and the iavf virtchnl mailbox core module.
>
>v6:
> No change, but to resend the same patchset again to trigger ci/Performance-Testing
> by using the new code base:
> https://lab.dpdk.org/results/dashboard/patchsets/10120/
>
>v5:
> Fixed the shared module compile errror.
>
>v4:
> Change the alarm handler to thread service, since it will need to do more
> work.
>
>v3:
> 1. Fixed the error log message format.
> 2. Fixed some memory allocation check.
> 3. Fixed some code style issue and commmit message description.
>
>v2:
> 1. update the iavf patchset link.
> 2. split more patches for making this work be more understandable
> 3. fix the log function usage, devargs checking from v1.
>
>Haiyue Wang (7):
> net/iavf: stop the PCI probe in DCF mode
> net/ice: add the DCF hardware initialization
> net/ice: acquire and disable the DCF capability
> net/ice: handle the AdminQ command by DCF
> net/ice: export the DDP definition symbols
> net/ice: handle the PF initialization by DCF
> net/ice: get the VF hardware index in DCF
>
> doc/guides/nics/ice.rst | 47 ++
> doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
> doc/guides/rel_notes/release_20_05.rst | 5 +
> drivers/common/Makefile | 1 +
> drivers/net/iavf/iavf_ethdev.c | 43 ++
> drivers/net/ice/Makefile | 7 +
> drivers/net/ice/ice_dcf.c | 658 +++++++++++++++++++++++++
> drivers/net/ice/ice_dcf.h | 63 +++
> drivers/net/ice/ice_dcf_ethdev.c | 321 ++++++++++++
> drivers/net/ice/ice_dcf_ethdev.h | 33 ++
> drivers/net/ice/ice_dcf_parent.c | 351 +++++++++++++
> drivers/net/ice/ice_ethdev.c | 9 +-
> drivers/net/ice/ice_ethdev.h | 8 +
> drivers/net/ice/meson.build | 8 +-
> mk/rte.app.mk | 1 +
> 15 files changed, 1545 insertions(+), 10 deletions(-)
> create mode 100644 doc/guides/nics/img/ice_dcf.png
> create mode 100644 drivers/net/ice/ice_dcf.c
> create mode 100644 drivers/net/ice/ice_dcf.h
> create mode 100644 drivers/net/ice/ice_dcf_ethdev.c
> create mode 100644 drivers/net/ice/ice_dcf_ethdev.h
> create mode 100644 drivers/net/ice/ice_dcf_parent.c
>
>--
>2.26.0
>
Applied to dpdk-next-net-intel, Thanks.
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v6 2/7] net/ice: add the DCF hardware initialization
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
@ 2020-03-31 8:50 ` Ferruh Yigit
2020-03-31 12:17 ` Wang, Haiyue
0 siblings, 1 reply; 94+ messages in thread
From: Ferruh Yigit @ 2020-03-31 8:50 UTC (permalink / raw)
To: Haiyue Wang, dev, xiaolong.ye, qi.z.zhang, jingjing.wu,
qiming.yang, beilei.xing
Cc: wei.zhao1
On 3/27/2020 2:56 AM, Haiyue Wang wrote:
> Introduce the DCF (Device Config Function) feature in the ice PMD, it
> works as a standalone PMD which doesn't handle the packet Rx/Tx related
> things. Its hardware entity is the VF.
>
> Add the basic DCF hardware initialization, this is specified by devarg
> 'cap=dcf'.
>
> Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
> Acked-by: Qi Zhang <qi.z.zhang@intel.com>
> ---
> doc/guides/nics/ice.rst | 47 +++
> doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
Hi Haiyue,
We prefer .svg files as image instead of binary formats (like .png), can you
please make a patch to replace .png with .svg, I will update it in next-net
before it merged in to the master?
Thanks,
ferruh
^ permalink raw reply [flat|nested] 94+ messages in thread
* Re: [dpdk-dev] [PATCH v6 2/7] net/ice: add the DCF hardware initialization
2020-03-31 8:50 ` Ferruh Yigit
@ 2020-03-31 12:17 ` Wang, Haiyue
0 siblings, 0 replies; 94+ messages in thread
From: Wang, Haiyue @ 2020-03-31 12:17 UTC (permalink / raw)
To: Yigit, Ferruh, dev, Ye, Xiaolong, Zhang, Qi Z, Wu, Jingjing,
Yang, Qiming, Xing, Beilei
Cc: Zhao1, Wei
Hi Ferruh,
> -----Original Message-----
> From: Yigit, Ferruh <ferruh.yigit@intel.com>
> Sent: Tuesday, March 31, 2020 16:50
> To: Wang, Haiyue <haiyue.wang@intel.com>; dev@dpdk.org; Ye, Xiaolong <xiaolong.ye@intel.com>; Zhang,
> Qi Z <qi.z.zhang@intel.com>; Wu, Jingjing <jingjing.wu@intel.com>; Yang, Qiming
> <qiming.yang@intel.com>; Xing, Beilei <beilei.xing@intel.com>
> Cc: Zhao1, Wei <wei.zhao1@intel.com>
> Subject: Re: [dpdk-dev] [PATCH v6 2/7] net/ice: add the DCF hardware initialization
>
> On 3/27/2020 2:56 AM, Haiyue Wang wrote:
> > Introduce the DCF (Device Config Function) feature in the ice PMD, it
> > works as a standalone PMD which doesn't handle the packet Rx/Tx related
> > things. Its hardware entity is the VF.
> >
> > Add the basic DCF hardware initialization, this is specified by devarg
> > 'cap=dcf'.
> >
> > Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
> > Acked-by: Qi Zhang <qi.z.zhang@intel.com>
> > ---
> > doc/guides/nics/ice.rst | 47 +++
> > doc/guides/nics/img/ice_dcf.png | Bin 0 -> 39168 bytes
>
> Hi Haiyue,
>
> We prefer .svg files as image instead of binary formats (like .png), can you
> please make a patch to replace .png with .svg, I will update it in next-net
> before it merged in to the master?
Done. https://patchwork.dpdk.org/patch/67477/
And I think checkpatch should ignore to check *svg file. ;-)
WARNING:TYPO_SPELLING: 'whe' may be misspelled - perhaps 'when'?
#1075: FILE: doc/guides/nics/img/ice_dcf.svg:255:
+imrp6JqROV/TKVAhhEZTPTIajV/4whe2bdv23HPPrVu3btasWcPWgTiOq6+vf+211xoaGlJTUymK
total: 0 errors, 1 warnings, 727 lines checked
>
> Thanks,
> ferruh
^ permalink raw reply [flat|nested] 94+ messages in thread
end of thread, other threads:[~2020-03-31 12:17 UTC | newest]
Thread overview: 94+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-09 14:14 [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support Haiyue Wang
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 1/4] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
2020-03-09 15:38 ` Ye Xiaolong
2020-03-10 2:19 ` Wang, Haiyue
2020-03-10 3:37 ` Ye Xiaolong
2020-03-10 4:26 ` Wang, Haiyue
2020-03-23 1:50 ` Wu, Jingjing
2020-03-23 1:55 ` Wang, Haiyue
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 2/4] net/ice: export the DDP definition symbols Haiyue Wang
2020-03-09 16:25 ` Ye Xiaolong
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 3/4] net/ice: add the DCF framework Haiyue Wang
2020-03-10 4:17 ` Ye Xiaolong
2020-03-10 5:09 ` Wang, Haiyue
2020-03-10 5:23 ` Ye Xiaolong
2020-03-09 14:14 ` [dpdk-dev] [PATCH v1 4/4] doc: add release notes for Intel ice PMD Haiyue Wang
2020-03-09 15:22 ` Ye Xiaolong
2020-03-10 2:16 ` Wang, Haiyue
2020-03-09 15:36 ` [dpdk-dev] [PATCH v1 0/4] add Intel DCF PMD support David Marchand
2020-03-09 16:20 ` Ye Xiaolong
2020-03-09 17:57 ` Thomas Monjalon
2020-03-09 19:34 ` Kevin Traynor
2020-03-10 2:00 ` Wang, Haiyue
2020-03-10 7:48 ` Thomas Monjalon
2020-03-10 9:36 ` Ferruh Yigit
2020-03-10 14:11 ` Aaron Conole
2020-03-10 14:09 ` Aaron Conole
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 0/7] " Haiyue Wang
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
2020-03-13 5:27 ` Ye Xiaolong
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 3/7] net/ice: initiate to acquire the DCF capability Haiyue Wang
2020-03-13 5:51 ` Ye Xiaolong
2020-03-13 6:19 ` Wang, Haiyue
2020-03-13 6:04 ` Ye Xiaolong
2020-03-13 6:10 ` Wang, Haiyue
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 5/7] net/ice: export the DDP definition symbols Haiyue Wang
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
2020-03-13 7:59 ` Ye Xiaolong
2020-03-13 8:03 ` Ye Xiaolong
2020-03-16 4:52 ` Wang, Haiyue
2020-03-13 14:06 ` Ye Xiaolong
2020-03-13 14:11 ` Wang, Haiyue
2020-03-10 6:50 ` [dpdk-dev] [PATCH v2 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
2020-03-13 7:01 ` Ye Xiaolong
2020-03-16 5:58 ` Wang, Haiyue
2020-03-13 16:19 ` [dpdk-dev] [PATCH v2 0/7] add Intel DCF PMD support Stillwell Jr, Paul M
2020-03-13 16:25 ` Wang, Haiyue
2020-03-13 16:50 ` Stillwell Jr, Paul M
2020-03-13 17:05 ` Wang, Haiyue
2020-03-13 17:47 ` Stillwell Jr, Paul M
2020-03-14 1:57 ` Wang, Haiyue
2020-03-15 1:49 ` Zhang, Qi Z
2020-03-16 18:54 ` Stillwell Jr, Paul M
2020-03-17 2:35 ` Wang, Haiyue
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 " Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 3/7] net/ice: acquire and disable the DCF capability Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 5/7] net/ice: export the DDP definition symbols Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
2020-03-16 5:52 ` [dpdk-dev] [PATCH v3 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
2020-03-26 3:28 ` Wu, Jingjing
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 3/7] net/ice: acquire and disable the DCF capability Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 5/7] net/ice: export the DDP definition symbols Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
2020-03-26 3:03 ` [dpdk-dev] [PATCH v4 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
2020-03-26 4:11 ` [dpdk-dev] [PATCH v4 0/7] add Intel DCF PMD support Zhang, Qi Z
2020-03-26 5:05 ` Ye Xiaolong
2020-03-26 5:26 ` Wang, Haiyue
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 " Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 3/7] net/ice: acquire and disable the DCF capability Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 5/7] net/ice: export the DDP definition symbols Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
2020-03-26 7:15 ` [dpdk-dev] [PATCH v5 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 1/7] net/iavf: stop the PCI probe in DCF mode Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 2/7] net/ice: add the DCF hardware initialization Haiyue Wang
2020-03-31 8:50 ` Ferruh Yigit
2020-03-31 12:17 ` Wang, Haiyue
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 3/7] net/ice: acquire and disable the DCF capability Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 4/7] net/ice: handle the AdminQ command by DCF Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 5/7] net/ice: export the DDP definition symbols Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 6/7] net/ice: handle the PF initialization by DCF Haiyue Wang
2020-03-27 2:56 ` [dpdk-dev] [PATCH v6 7/7] net/ice: get the VF hardware index in DCF Haiyue Wang
2020-03-27 15:26 ` [dpdk-dev] [PATCH v6 0/7] add Intel DCF PMD support Ye Xiaolong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).