From patchwork Wed Apr 10 06:27:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52528 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id A493758EC; Wed, 10 Apr 2019 08:26:54 +0200 (CEST) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by dpdk.org (Postfix) with ESMTP id BA2A14F93 for ; Wed, 10 Apr 2019 08:26:51 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 23:26:51 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,332,1549958400"; d="scan'208";a="147980589" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by FMSMGA003.fm.intel.com with ESMTP; 09 Apr 2019 23:26:48 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Wed, 10 Apr 2019 14:27:39 +0800 Message-Id: <1554877672-19745-2-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554877672-19745-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554877672-19745-1-git-send-email-rosen.xu@intel.com> Subject: [dpdk-dev] [PATCH v7 01/14] bus/ifpga: add AFU shared data X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" AFU can be implemented into many different acceleration devices, these devices need shared data to store private information when they are handled by users. Signed-off-by: Rosen Xu Signed-off-by: Andy Pei --- drivers/bus/ifpga/rte_bus_ifpga.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h index 0bf43ba..820eeaa 100644 --- a/drivers/bus/ifpga/rte_bus_ifpga.h +++ b/drivers/bus/ifpga/rte_bus_ifpga.h @@ -17,6 +17,7 @@ #include #include +#include /** Name of Intel FPGA Bus */ #define IFPGA_BUS_NAME ifpga @@ -60,6 +61,11 @@ struct rte_afu_pr_conf { #define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) +struct rte_afu_shared { + rte_spinlock_t lock; + void *data; +}; + /** * A structure describing a AFU device. */ @@ -71,6 +77,7 @@ struct rte_afu_device { uint32_t num_region; /**< number of regions found */ struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; /**< AFU Memory Resource */ + struct rte_afu_shared shared; struct rte_intr_handle intr_handle; /**< Interrupt handle */ struct rte_afu_driver *driver; /**< Associated driver */ char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; From patchwork Wed Apr 10 06:27:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52529 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 5F62658CB; Wed, 10 Apr 2019 08:26:58 +0200 (CEST) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by dpdk.org (Postfix) with ESMTP id D00165A6A for ; Wed, 10 Apr 2019 08:26:55 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 23:26:55 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,332,1549958400"; d="scan'208";a="147980601" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by FMSMGA003.fm.intel.com with ESMTP; 09 Apr 2019 23:26:52 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Wed, 10 Apr 2019 14:27:40 +0800 Message-Id: <1554877672-19745-3-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554877672-19745-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554877672-19745-1-git-send-email-rosen.xu@intel.com> Subject: [dpdk-dev] [PATCH v7 02/14] bus/ifpga: add function for AFU search by name X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" In many scenarios, AFU is needed searched by name, this function add the feature. Signed-off-by: Rosen Xu Signed-off-by: Andy Pei --- drivers/bus/ifpga/ifpga_bus.c | 13 +++++++++++++ drivers/bus/ifpga/rte_bus_ifpga.h | 9 +++++++++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 6 ++++++ 3 files changed, 28 insertions(+) diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c index 55d3abf..8bfae29 100644 --- a/drivers/bus/ifpga/ifpga_bus.c +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -73,6 +73,19 @@ void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) return NULL; } +struct rte_afu_device *__rte_experimental +rte_ifpga_find_afu_by_name(const char *name) +{ + struct rte_afu_device *afu_dev = NULL; + + TAILQ_FOREACH(afu_dev, &ifpga_afu_dev_list, next) { + if (afu_dev && + !strcmp(afu_dev->device.name, name)) + return afu_dev; + } + return NULL; +} + static const char * const valid_args[] = { #define IFPGA_ARG_NAME "ifpga" IFPGA_ARG_NAME, diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h index 820eeaa..c00f60e 100644 --- a/drivers/bus/ifpga/rte_bus_ifpga.h +++ b/drivers/bus/ifpga/rte_bus_ifpga.h @@ -120,6 +120,15 @@ struct rte_afu_driver { } /** + * Find AFU by AFU name. + * + * @param name + * A pointer to AFU name string. + */ +struct rte_afu_device *__rte_experimental +rte_ifpga_find_afu_by_name(const char *name); + +/** * Register a ifpga afu device driver. * * @param driver diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map index a027979..247ccfe 100644 --- a/drivers/bus/ifpga/rte_bus_ifpga_version.map +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map @@ -8,3 +8,9 @@ DPDK_18.05 { local: *; }; + +EXPERIMENTAL { + global: + + rte_ifpga_find_afu_by_name; +}; \ No newline at end of file From patchwork Wed Apr 10 06:27:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52530 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B71E25B40; Wed, 10 Apr 2019 08:27:05 +0200 (CEST) Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by dpdk.org (Postfix) with ESMTP id AF20B5424 for ; Wed, 10 Apr 2019 08:27:02 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 23:27:01 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,332,1549958400"; d="scan'208";a="147980644" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by FMSMGA003.fm.intel.com with ESMTP; 09 Apr 2019 23:26:56 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Wed, 10 Apr 2019 14:27:41 +0800 Message-Id: <1554877672-19745-4-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554877672-19745-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554877672-19745-1-git-send-email-rosen.xu@intel.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v7 03/14] net/ipn3ke: add IPN3KE ethdev PMD driver X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add Intel FPGA Acceleration NIC IPN3KE ethdev PMD driver. Signed-off-by: Rosen Xu Signed-off-by: Andy Pei Signed-off-by: Dan Wei --- MAINTAINERS | 6 + config/common_base | 4 + doc/guides/nics/features/ipn3ke.ini | 55 ++ doc/guides/nics/index.rst | 1 + doc/guides/nics/ipn3ke.rst | 108 +++ drivers/net/Makefile | 1 + drivers/net/ipn3ke/Makefile | 36 + drivers/net/ipn3ke/ipn3ke_ethdev.c | 645 ++++++++++++++++++ drivers/net/ipn3ke/ipn3ke_ethdev.h | 942 ++++++++++++++++++++++++++ drivers/net/ipn3ke/ipn3ke_logs.h | 30 + drivers/net/ipn3ke/ipn3ke_rawdev_api.h | 62 ++ drivers/net/ipn3ke/meson.build | 14 + drivers/net/ipn3ke/rte_pmd_ipn3ke_version.map | 4 + drivers/net/meson.build | 1 + mk/rte.app.mk | 1 + usertools/dpdk-devbind.py | 4 +- 16 files changed, 1913 insertions(+), 1 deletion(-) create mode 100644 doc/guides/nics/features/ipn3ke.ini create mode 100644 doc/guides/nics/ipn3ke.rst create mode 100644 drivers/net/ipn3ke/Makefile create mode 100644 drivers/net/ipn3ke/ipn3ke_ethdev.c create mode 100644 drivers/net/ipn3ke/ipn3ke_ethdev.h create mode 100644 drivers/net/ipn3ke/ipn3ke_logs.h create mode 100644 drivers/net/ipn3ke/ipn3ke_rawdev_api.h create mode 100644 drivers/net/ipn3ke/meson.build create mode 100644 drivers/net/ipn3ke/rte_pmd_ipn3ke_version.map diff --git a/MAINTAINERS b/MAINTAINERS index 9774344..8db925f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -633,6 +633,12 @@ F: drivers/net/ice/ F: doc/guides/nics/ice.rst F: doc/guides/nics/features/ice.ini +Intel ipn3ke +M: Rosen Xu +T: git://dpdk.org/next/dpdk-next-net-intel +F: drivers/net/ipn3ke/ +F: doc/guides/nics/ipn3ke.rst +F: doc/guides/nics/features/ipn3ke.ini Marvell mvpp2 M: Tomasz Duszynski M: Liron Himi diff --git a/config/common_base b/config/common_base index 8da0810..cb9e3b6 100644 --- a/config/common_base +++ b/config/common_base @@ -328,6 +328,10 @@ CONFIG_RTE_LIBRTE_IAVF_DEBUG_TX=n CONFIG_RTE_LIBRTE_IAVF_DEBUG_TX_FREE=n CONFIG_RTE_LIBRTE_IAVF_DEBUG_RX=n CONFIG_RTE_LIBRTE_IAVF_16BYTE_RX_DESC=n +# +# Compile burst-oriented IPN3KE PMD driver +# +CONFIG_RTE_LIBRTE_IPN3KE_PMD=y # # Compile burst-oriented Mellanox ConnectX-3 (MLX4) PMD diff --git a/doc/guides/nics/features/ipn3ke.ini b/doc/guides/nics/features/ipn3ke.ini new file mode 100644 index 0000000..a194e35 --- /dev/null +++ b/doc/guides/nics/features/ipn3ke.ini @@ -0,0 +1,55 @@ +; +; Supported features of the 'ipn3ke' network poll mode driver. +; +; Refer to default.ini for the full list of available PMD features. +; +[Features] +Speed capabilities = Y +Link status = Y +Link status event = Y +Rx interrupt = Y +Queue start/stop = Y +Runtime Rx queue setup = Y +Runtime Tx queue setup = Y +Jumbo frame = Y +Scattered Rx = Y +TSO = Y +Promiscuous mode = Y +Allmulticast mode = Y +Unicast MAC filter = Y +Multicast MAC filter = Y +RSS hash = Y +RSS key update = Y +RSS reta update = Y +VMDq = Y +SR-IOV = Y +DCB = Y +VLAN filter = Y +Ethertype filter = Y +Tunnel filter = Y +Hash filter = Y +Flow director = Y +Flow control = Y +Flow API = Y +Traffic mirroring = Y +CRC offload = Y +VLAN offload = Y +QinQ offload = Y +L3 checksum offload = Y +L4 checksum offload = Y +Inner L3 checksum = Y +Inner L4 checksum = Y +Packet type parsing = Y +Timesync = Y +Rx descriptor status = Y +Tx descriptor status = Y +Basic stats = Y +Extended stats = Y +FW version = Y +Module EEPROM dump = Y +Multiprocess aware = Y +BSD nic_uio = Y +Linux UIO = Y +Linux VFIO = Y +x86-32 = Y +x86-64 = Y diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst index a4b80a3..1892350 100644 --- a/doc/guides/nics/index.rst +++ b/doc/guides/nics/index.rst @@ -31,6 +31,7 @@ Network Interface Controller Drivers ice ifc igb + ipn3ke ixgbe intel_vf kni diff --git a/doc/guides/nics/ipn3ke.rst b/doc/guides/nics/ipn3ke.rst new file mode 100644 index 0000000..3254ffe --- /dev/null +++ b/doc/guides/nics/ipn3ke.rst @@ -0,0 +1,108 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2019 Intel Corporation. + +IPN3KE Poll Mode Driver +======================= + +The ipn3ke PMD (librte_pmd_ipn3ke) provides poll mode driver support +for IntelĀ® FPGA PAC(Programmable Acceleration Card) N3000 based on +the Intel Ethernet Controller X710/XXV710 and Intel Arria 10 FPGA. + +In this card, FPGA is an acceleration bridge between network interface +and the Intel Ethernet Controller. Although both FPGA and Ethernet +Controllers are connected to CPU with PCIe Gen3x16 Switch, all the +packet RX/TX is handled by Intel Ethernet Controller. So from application +point of view the data path is still the legacy Intel Ethernet Controller +X710/XXV710 PMD. Besides this, users can enable more acceleration +features by FPGA IP. + +Prerequisites +------------- + +- Identifying your adapter using `Intel Support + `_ and get the latest NVM/FW images. + +- Follow the DPDK :ref:`Getting Started Guide for Linux ` to setup the basic DPDK environment. + +- To get better performance on Intel platforms, please follow the "How to get best performance with NICs on Intel platforms" + section of the :ref:`Getting Started Guide for Linux `. + + +Pre-Installation Configuration +------------------------------ + +Config File Options +~~~~~~~~~~~~~~~~~~~ + +The following options can be modified in the ``config`` file. +Please note that enabling debugging options may affect system performance. + +- ``CONFIG_RTE_LIBRTE_IPN3KE_PMD`` (default ``y``) + + Toggle compilation of the ``librte_pmd_ipn3ke`` driver. + +Runtime Config Options +~~~~~~~~~~~~~~~~~~~~~~ + +- ``AFU name`` + + AFU name identifies which AFU is used by IPN3KE. The AFU name format is "Port|BDF", + Each FPGA can be divided into four blocks at most. "Port" identifies which FPGA block + the AFU bitstream belongs to, but currently only 0 IPN3KE support. "BDF" means FPGA PCIe BDF. + For example:: + + --vdev 'ipn3ke_cfg0,afu=0|b3:00.0' + +- ``FPGA Acceleration list`` + + For IPN3KE FPGA can provide different bitstream, different bitstream includes different + Acceleration, so users need to identify which Acceleration is used. Current IPN3KE can + support TM and Flow Acceleration, for example:: + + --vdev 'ipn3ke_cfg0,afu=0|b3:00.0,fpga_acc={tm|flow}' + +- ``I40e PF name list`` + + Users need to bind FPGA LineSidePort to FVL PF. So I40e PF name list should be involved in + startup command. For example:: + + --vdev 'ipn3ke_cfg0,afu=0|b3:00.0,fpga_acc={tm|flow},i40e_pf={0000:b1:00.0|0000:b1:00.1|0000:b1:00.2|0000:b1:00.3|0000:b5:00.0|0000:b5:00.1|0000:b5:00.2|0000:b5:00.3}' + +Driver compilation and testing +------------------------------ + +Refer to the document :ref:`compiling and testing a PMD for a NIC ` +for details. + +Sample Application Notes +------------------------ + +Packet TX/RX with FPGA Pass-through image +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +FPGA Pass-through bitstream is original FPGA Image. + +To start ``testpmd``, and add I40e PF to FPGA network port: + +.. code-block:: console + + ./app/testpmd -l 0-15 -n 4 --vdev 'ifpga_rawdev_cfg0,ifpga=b3:00.0,port=0' --vdev 'ipn3ke_cfg0,afu=0|b3:00.0,i40e_pf={0000:b1:00.0|0000:b1:00.1|0000:b1:00.2|0000:b1:00.3|0000:b5:00.0|0000:b5:00.1|0000:b5:00.2|0000:b5:00.3}' -- -i --no-numa --port-topology=loop + +HQoS and flow acceleration +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +HQoS and flow acceleration bitstream is used to offloading HQoS and flow classifier. + +To start ``testpmd``, and add I40e PF to FPGA network port, enable FPGA HQoS and Flow Acceleration: + +.. code-block:: console + + ./app/testpmd -l 0-15 -n 4 --vdev 'ifpga_rawdev_cfg0,ifpga=b3:00.0,port=0' --vdev 'ipn3ke_cfg0,afu=0|b3:00.0,fpga_acc={tm|flow},i40e_pf={0000:b1:00.0|0000:b1:00.1|0000:b1:00.2|0000:b1:00.3|0000:b5:00.0|0000:b5:00.1|0000:b5:00.2|0000:b5:00.3}' -- -i --no-numa --forward-mode=macswap + +Limitations or Known issues +--------------------------- + +19.05 limitation +~~~~~~~~~~~~~~~~ + +Ipn3ke code released in 19.05 is for evaluation only. diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 5d401b8..5c972eb 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -32,6 +32,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e DIRS-$(CONFIG_RTE_LIBRTE_IAVF_PMD) += iavf DIRS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice +DIRS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke DIRS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += ixgbe DIRS-$(CONFIG_RTE_LIBRTE_LIO_PMD) += liquidio DIRS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += mlx4 diff --git a/drivers/net/ipn3ke/Makefile b/drivers/net/ipn3ke/Makefile new file mode 100644 index 0000000..d7aa79b --- /dev/null +++ b/drivers/net/ipn3ke/Makefile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2019 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_pmd_ipn3ke.a + +# +# Add the experimenatal APIs called from this PMD +# rte_eth_switch_domain_alloc() +# rte_eth_dev_create() +# rte_eth_dev_destroy() +# rte_eth_switch_domain_free() +# +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga +LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring +LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs +LDLIBS += -lrte_bus_ifpga +LDLIBS += -lrte_bus_vdev + +EXPORT_MAP := rte_pmd_ipn3ke_version.map + +LIBABIVER := 1 + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_ethdev.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/net/ipn3ke/ipn3ke_ethdev.c b/drivers/net/ipn3ke/ipn3ke_ethdev.c new file mode 100644 index 0000000..d5fee6f --- /dev/null +++ b/drivers/net/ipn3ke/ipn3ke_ethdev.c @@ -0,0 +1,645 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ipn3ke_rawdev_api.h" +#include "ipn3ke_logs.h" +#include "ipn3ke_ethdev.h" + +int ipn3ke_afu_logtype; + +static const struct rte_afu_uuid afu_uuid_ipn3ke_map[] = { + { MAP_UUID_10G_LOW, MAP_UUID_10G_HIGH }, + { IPN3KE_UUID_10G_LOW, IPN3KE_UUID_10G_HIGH }, + { IPN3KE_UUID_VBNG_LOW, IPN3KE_UUID_VBNG_HIGH}, + { IPN3KE_UUID_25G_LOW, IPN3KE_UUID_25G_HIGH }, + { 0, 0 /* sentinel */ }, +}; + +static int +ipn3ke_indirect_read(struct ipn3ke_hw *hw, uint32_t *rd_data, + uint32_t addr, uint32_t dev_sel, uint32_t eth_group_sel) +{ + uint32_t i, try_cnt; + uint64_t indirect_value; + volatile void *indirect_addrs; + uint64_t target_addr; + uint64_t read_data = 0; + + if (eth_group_sel != 0 && eth_group_sel != 1) + return -1; + + addr &= 0x3FF; + target_addr = addr | dev_sel << 17; + + indirect_value = RCMD | target_addr << 32; + indirect_addrs = hw->eth_group_bar[eth_group_sel] + 0x10; + + rte_delay_us(10); + + rte_write64((rte_cpu_to_le_64(indirect_value)), indirect_addrs); + + i = 0; + try_cnt = 10; + indirect_addrs = hw->eth_group_bar[eth_group_sel] + + 0x18; + do { + read_data = rte_read64(indirect_addrs); + if ((read_data >> 32) == 1) + break; + i++; + } while (i <= try_cnt); + if (i > try_cnt) + return -1; + + *rd_data = rte_le_to_cpu_32(read_data); + return 0; +} + +static int +ipn3ke_indirect_write(struct ipn3ke_hw *hw, uint32_t wr_data, + uint32_t addr, uint32_t dev_sel, uint32_t eth_group_sel) +{ + volatile void *indirect_addrs; + uint64_t indirect_value; + uint64_t target_addr; + + if (eth_group_sel != 0 && eth_group_sel != 1) + return -1; + + addr &= 0x3FF; + target_addr = addr | dev_sel << 17; + + indirect_value = WCMD | target_addr << 32 | wr_data; + indirect_addrs = hw->eth_group_bar[eth_group_sel] + 0x10; + + rte_write64((rte_cpu_to_le_64(indirect_value)), indirect_addrs); + return 0; +} + +static int +ipn3ke_indirect_mac_read(struct ipn3ke_hw *hw, uint32_t *rd_data, + uint32_t addr, uint32_t mac_num, uint32_t eth_group_sel) +{ + uint32_t dev_sel; + + if (mac_num >= hw->port_num) + return -1; + + mac_num &= 0x7; + dev_sel = mac_num * 2 + 3; + + return ipn3ke_indirect_read(hw, rd_data, addr, dev_sel, eth_group_sel); +} + +static int +ipn3ke_indirect_mac_write(struct ipn3ke_hw *hw, uint32_t wr_data, + uint32_t addr, uint32_t mac_num, uint32_t eth_group_sel) +{ + uint32_t dev_sel; + + if (mac_num >= hw->port_num) + return -1; + + mac_num &= 0x7; + dev_sel = mac_num * 2 + 3; + + return ipn3ke_indirect_write(hw, wr_data, addr, dev_sel, eth_group_sel); +} + +static void +ipn3ke_hw_cap_init(struct ipn3ke_hw *hw) +{ + hw->hw_cap.version_number = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0), 0, 0xFFFF); + hw->hw_cap.capability_registers_block_offset = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x8), 0, 0xFFFFFFFF); + hw->hw_cap.status_registers_block_offset = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x10), 0, 0xFFFFFFFF); + hw->hw_cap.control_registers_block_offset = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x18), 0, 0xFFFFFFFF); + hw->hw_cap.classify_offset = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x20), 0, 0xFFFFFFFF); + hw->hw_cap.classy_size = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x24), 0, 0xFFFF); + hw->hw_cap.policer_offset = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x28), 0, 0xFFFFFFFF); + hw->hw_cap.policer_entry_size = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x2C), 0, 0xFFFF); + hw->hw_cap.rss_key_array_offset = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x30), 0, 0xFFFFFFFF); + hw->hw_cap.rss_key_entry_size = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x34), 0, 0xFFFF); + hw->hw_cap.rss_indirection_table_array_offset = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x38), 0, 0xFFFFFFFF); + hw->hw_cap.rss_indirection_table_entry_size = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x3C), 0, 0xFFFF); + hw->hw_cap.dmac_map_offset = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x40), 0, 0xFFFFFFFF); + hw->hw_cap.dmac_map_size = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x44), 0, 0xFFFF); + hw->hw_cap.qm_offset = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x48), 0, 0xFFFFFFFF); + hw->hw_cap.qm_size = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x4C), 0, 0xFFFF); + hw->hw_cap.ccb_offset = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x50), 0, 0xFFFFFFFF); + hw->hw_cap.ccb_entry_size = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x54), 0, 0xFFFF); + hw->hw_cap.qos_offset = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x58), 0, 0xFFFFFFFF); + hw->hw_cap.qos_size = IPN3KE_MASK_READ_REG(hw, + (IPN3KE_HW_BASE + 0x5C), 0, 0xFFFF); + + hw->hw_cap.num_rx_flow = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CAPABILITY_REGISTERS_BLOCK_OFFSET, + 0, 0xFFFF); + hw->hw_cap.num_rss_blocks = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CAPABILITY_REGISTERS_BLOCK_OFFSET, + 4, 0xFFFF); + hw->hw_cap.num_dmac_map = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CAPABILITY_REGISTERS_BLOCK_OFFSET, + 8, 0xFFFF); + hw->hw_cap.num_tx_flow = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CAPABILITY_REGISTERS_BLOCK_OFFSET, + 0xC, 0xFFFF); + hw->hw_cap.num_smac_map = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CAPABILITY_REGISTERS_BLOCK_OFFSET, + 0x10, 0xFFFF); + + hw->hw_cap.link_speed_mbps = IPN3KE_MASK_READ_REG(hw, + IPN3KE_STATUS_REGISTERS_BLOCK_OFFSET, + 0, 0xFFFFF); +} + +static int +ipn3ke_hw_init(struct rte_afu_device *afu_dev, + struct ipn3ke_hw *hw) +{ + struct rte_rawdev *rawdev; + int ret; + int i; + uint64_t port_num, mac_type, index; + + rawdev = afu_dev->rawdev; + + hw->afu_id.uuid.uuid_low = afu_dev->id.uuid.uuid_low; + hw->afu_id.uuid.uuid_high = afu_dev->id.uuid.uuid_high; + hw->afu_id.port = afu_dev->id.port; + hw->hw_addr = (uint8_t *)(afu_dev->mem_resource[0].addr); + hw->f_mac_read = ipn3ke_indirect_mac_read; + hw->f_mac_write = ipn3ke_indirect_mac_write; + hw->rawdev = rawdev; + rawdev->dev_ops->attr_get(rawdev, + "LineSideBARIndex", &index); + hw->eth_group_bar[0] = (uint8_t *)(afu_dev->mem_resource[index].addr); + rawdev->dev_ops->attr_get(rawdev, + "NICSideBARIndex", &index); + hw->eth_group_bar[1] = (uint8_t *)(afu_dev->mem_resource[index].addr); + rawdev->dev_ops->attr_get(rawdev, + "LineSideLinkPortNum", &port_num); + hw->retimer.port_num = (int)port_num; + hw->port_num = hw->retimer.port_num; + rawdev->dev_ops->attr_get(rawdev, + "LineSideMACType", &mac_type); + hw->retimer.mac_type = (int)mac_type; + + if (afu_dev->id.uuid.uuid_low == IPN3KE_UUID_VBNG_LOW && + afu_dev->id.uuid.uuid_high == IPN3KE_UUID_VBNG_HIGH) { + ipn3ke_hw_cap_init(hw); + IPN3KE_AFU_PMD_DEBUG("UPL_version is 0x%x\n", + IPN3KE_READ_REG(hw, 0)); + + /* Reset FPGA IP */ + IPN3KE_WRITE_REG(hw, IPN3KE_CTRL_RESET, 1); + IPN3KE_WRITE_REG(hw, IPN3KE_CTRL_RESET, 0); + } + + if (hw->retimer.mac_type == IFPGA_RAWDEV_RETIMER_MAC_TYPE_10GE_XFI) { + /* Enable inter connect channel */ + for (i = 0; i < hw->port_num; i++) { + /* Enable the TX path */ + ipn3ke_xmac_tx_enable(hw, i, 1); + + /* Disables source address override */ + ipn3ke_xmac_smac_ovd_dis(hw, i, 1); + + /* Enable the RX path */ + ipn3ke_xmac_rx_enable(hw, i, 1); + + /* Clear all TX statistics counters */ + ipn3ke_xmac_tx_clr_stcs(hw, i, 1); + + /* Clear all RX statistics counters */ + ipn3ke_xmac_rx_clr_stcs(hw, i, 1); + } + } + + ret = rte_eth_switch_domain_alloc(&hw->switch_domain_id); + if (ret) + IPN3KE_AFU_PMD_WARN("failed to allocate switch domain for device %d", + ret); + + hw->tm_hw_enable = 0; + hw->flow_hw_enable = 0; + if (afu_dev->id.uuid.uuid_low == IPN3KE_UUID_VBNG_LOW && + afu_dev->id.uuid.uuid_high == IPN3KE_UUID_VBNG_HIGH) { + hw->tm_hw_enable = 1; + hw->flow_hw_enable = 1; + } + + hw->acc_tm = 0; + hw->acc_flow = 0; + + return 0; +} + +static void +ipn3ke_hw_uninit(struct ipn3ke_hw *hw) +{ + int i; + + if (hw->retimer.mac_type == IFPGA_RAWDEV_RETIMER_MAC_TYPE_10GE_XFI) { + for (i = 0; i < hw->port_num; i++) { + /* Disable the TX path */ + ipn3ke_xmac_tx_disable(hw, i, 1); + + /* Disable the RX path */ + ipn3ke_xmac_rx_disable(hw, i, 1); + + /* Clear all TX statistics counters */ + ipn3ke_xmac_tx_clr_stcs(hw, i, 1); + + /* Clear all RX statistics counters */ + ipn3ke_xmac_rx_clr_stcs(hw, i, 1); + } + } +} + +static int ipn3ke_vswitch_probe(struct rte_afu_device *afu_dev) +{ + char name[RTE_ETH_NAME_MAX_LEN]; + struct ipn3ke_hw *hw; + int i, retval; + + /* check if the AFU device has been probed already */ + /* allocate shared mcp_vswitch structure */ + if (!afu_dev->shared.data) { + snprintf(name, sizeof(name), "net_%s_hw", + afu_dev->device.name); + hw = rte_zmalloc_socket(name, + sizeof(struct ipn3ke_hw), + RTE_CACHE_LINE_SIZE, + afu_dev->device.numa_node); + if (!hw) { + IPN3KE_AFU_PMD_ERR("failed to allocate hardwart data"); + retval = -ENOMEM; + return -ENOMEM; + } + afu_dev->shared.data = hw; + + rte_spinlock_init(&afu_dev->shared.lock); + } else { + hw = afu_dev->shared.data; + } + + retval = ipn3ke_hw_init(afu_dev, hw); + if (retval) + return retval; + + /* probe representor ports */ + for (i = 0; i < hw->port_num; i++) { + struct ipn3ke_rpst rpst = { + .port_id = i, + .switch_domain_id = hw->switch_domain_id, + .hw = hw + }; + + /* representor port net_bdf_port */ + snprintf(name, sizeof(name), "net_%s_representor_%d", + afu_dev->device.name, i); + + retval = rte_eth_dev_create(&afu_dev->device, name, + sizeof(struct ipn3ke_rpst), NULL, NULL, + NULL, &rpst); + + if (retval) + IPN3KE_AFU_PMD_ERR("failed to create ipn3ke representor %s.", + name); + } + + return 0; +} + +static int ipn3ke_vswitch_remove(struct rte_afu_device *afu_dev) +{ + char name[RTE_ETH_NAME_MAX_LEN]; + struct ipn3ke_hw *hw; + struct rte_eth_dev *ethdev; + int i, ret; + + hw = afu_dev->shared.data; + + /* remove representor ports */ + for (i = 0; i < hw->port_num; i++) { + /* representor port net_bdf_port */ + snprintf(name, sizeof(name), "net_%s_representor_%d", + afu_dev->device.name, i); + + ethdev = rte_eth_dev_allocated(afu_dev->device.name); + if (!ethdev) + return -ENODEV; + + rte_eth_dev_destroy(ethdev, NULL); + } + + ret = rte_eth_switch_domain_free(hw->switch_domain_id); + if (ret) + IPN3KE_AFU_PMD_WARN("failed to free switch domain: %d", ret); + + /* hw uninit*/ + ipn3ke_hw_uninit(hw); + + return 0; +} + +static struct rte_afu_driver afu_ipn3ke_driver = { + .id_table = afu_uuid_ipn3ke_map, + .probe = ipn3ke_vswitch_probe, + .remove = ipn3ke_vswitch_remove, +}; + +RTE_PMD_REGISTER_AFU(net_ipn3ke_afu, afu_ipn3ke_driver); + +static const char * const valid_args[] = { +#define IPN3KE_AFU_NAME "afu" + IPN3KE_AFU_NAME, +#define IPN3KE_FPGA_ACCELERATION_LIST "fpga_acc" + IPN3KE_FPGA_ACCELERATION_LIST, +#define IPN3KE_I40E_PF_LIST "i40e_pf" + IPN3KE_I40E_PF_LIST, + NULL +}; + +static int +ipn3ke_cfg_parse_acc_list(const char *afu_name, + const char *acc_list_name) +{ + struct rte_afu_device *afu_dev; + struct ipn3ke_hw *hw; + const char *p_source; + char *p_start; + char name[RTE_ETH_NAME_MAX_LEN]; + + afu_dev = rte_ifpga_find_afu_by_name(afu_name); + if (!afu_dev) + return -1; + hw = afu_dev->shared.data; + if (!hw) + return -1; + + p_source = acc_list_name; + while (*p_source) { + while ((*p_source == '{') || (*p_source == '|')) + p_source++; + p_start = name; + while ((*p_source != '|') && (*p_source != '}')) + *p_start++ = *p_source++; + *p_start = 0; + if (!strcmp(name, "tm") && hw->tm_hw_enable) + hw->acc_tm = 1; + + if (!strcmp(name, "flow") && hw->flow_hw_enable) + hw->acc_flow = 1; + + if (*p_source == '}') + return 0; + } + + return 0; +} + +static int +ipn3ke_cfg_parse_i40e_pf_ethdev(const char *afu_name, + const char *pf_name) +{ + struct rte_eth_dev *i40e_eth, *rpst_eth; + struct rte_afu_device *afu_dev; + struct ipn3ke_rpst *rpst; + struct ipn3ke_hw *hw; + const char *p_source; + char *p_start; + char name[RTE_ETH_NAME_MAX_LEN]; + uint16_t port_id; + int i; + int ret = -1; + + afu_dev = rte_ifpga_find_afu_by_name(afu_name); + if (!afu_dev) + return -1; + hw = afu_dev->shared.data; + if (!hw) + return -1; + + p_source = pf_name; + for (i = 0; i < hw->port_num; i++) { + snprintf(name, sizeof(name), "net_%s_representor_%d", + afu_name, i); + ret = rte_eth_dev_get_port_by_name(name, &port_id); + if (ret) + return -1; + rpst_eth = &rte_eth_devices[port_id]; + rpst = IPN3KE_DEV_PRIVATE_TO_RPST(rpst_eth); + + while ((*p_source == '{') || (*p_source == '|')) + p_source++; + p_start = name; + while ((*p_source != '|') && (*p_source != '}')) + *p_start++ = *p_source++; + *p_start = 0; + + ret = rte_eth_dev_get_port_by_name(name, &port_id); + if (ret) + return -1; + i40e_eth = &rte_eth_devices[port_id]; + + rpst->i40e_pf_eth = i40e_eth; + rpst->i40e_pf_eth_port_id = port_id; + + if ((*p_source == '}') || !(*p_source)) + break; + } + + return 0; +} + +static int +ipn3ke_cfg_probe(struct rte_vdev_device *dev) +{ + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + char *afu_name = NULL; + char *acc_name = NULL; + char *pf_name = NULL; + int afu_name_en = 0; + int acc_list_en = 0; + int pf_list_en = 0; + int ret = -1; + + devargs = dev->device.devargs; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IPN3KE_AFU_PMD_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IPN3KE_AFU_NAME) == 1) { + if (rte_kvargs_process(kvlist, IPN3KE_AFU_NAME, + &rte_ifpga_get_string_arg, + &afu_name) < 0) { + IPN3KE_AFU_PMD_ERR("error to parse %s", + IPN3KE_AFU_NAME); + goto end; + } else { + afu_name_en = 1; + } + } + + if (rte_kvargs_count(kvlist, IPN3KE_FPGA_ACCELERATION_LIST) == 1) { + if (rte_kvargs_process(kvlist, IPN3KE_FPGA_ACCELERATION_LIST, + &rte_ifpga_get_string_arg, + &acc_name) < 0) { + IPN3KE_AFU_PMD_ERR("error to parse %s", + IPN3KE_FPGA_ACCELERATION_LIST); + goto end; + } else { + acc_list_en = 1; + } + } + + if (rte_kvargs_count(kvlist, IPN3KE_I40E_PF_LIST) == 1) { + if (rte_kvargs_process(kvlist, IPN3KE_I40E_PF_LIST, + &rte_ifpga_get_string_arg, + &pf_name) < 0) { + IPN3KE_AFU_PMD_ERR("error to parse %s", + IPN3KE_I40E_PF_LIST); + goto end; + } else { + pf_list_en = 1; + } + } + + if (!afu_name_en) { + IPN3KE_AFU_PMD_ERR("arg %s is mandatory for ipn3ke", + IPN3KE_AFU_NAME); + goto end; + } + + if (!pf_list_en) { + IPN3KE_AFU_PMD_ERR("arg %s is mandatory for ipn3ke", + IPN3KE_I40E_PF_LIST); + goto end; + } + + if (acc_list_en) { + ret = ipn3ke_cfg_parse_acc_list(afu_name, acc_name); + if (ret) { + IPN3KE_AFU_PMD_ERR("arg %s parse error for ipn3ke", + IPN3KE_FPGA_ACCELERATION_LIST); + goto end; + } + } else { + IPN3KE_AFU_PMD_INFO("arg %s is optional for ipn3ke, using i40e acc", + IPN3KE_FPGA_ACCELERATION_LIST); + } + + ret = ipn3ke_cfg_parse_i40e_pf_ethdev(afu_name, pf_name); + if (ret) + goto end; +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (afu_name) + free(afu_name); + if (acc_name) + free(acc_name); + + return ret; +} + +static int +ipn3ke_cfg_remove(struct rte_vdev_device *dev) +{ + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + char *afu_name = NULL; + struct rte_afu_device *afu_dev; + int ret = -1; + + devargs = dev->device.devargs; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IPN3KE_AFU_PMD_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IPN3KE_AFU_NAME) == 1) { + if (rte_kvargs_process(kvlist, IPN3KE_AFU_NAME, + &rte_ifpga_get_string_arg, + &afu_name) < 0) { + IPN3KE_AFU_PMD_ERR("error to parse %s", + IPN3KE_AFU_NAME); + } else { + afu_dev = rte_ifpga_find_afu_by_name(afu_name); + if (!afu_dev) + goto end; + ret = ipn3ke_vswitch_remove(afu_dev); + } + } else { + IPN3KE_AFU_PMD_ERR("Remove ipn3ke_cfg %p error", dev); + } + +end: + if (kvlist) + rte_kvargs_free(kvlist); + + return ret; +} + +static struct rte_vdev_driver ipn3ke_cfg_driver = { + .probe = ipn3ke_cfg_probe, + .remove = ipn3ke_cfg_remove, +}; + +RTE_PMD_REGISTER_VDEV(ipn3ke_cfg, ipn3ke_cfg_driver); +RTE_PMD_REGISTER_PARAM_STRING(ipn3ke_cfg, + "afu= " + "fpga_acc=" + "i40e_pf="); + +RTE_INIT(ipn3ke_afu_init_log) +{ + ipn3ke_afu_logtype = rte_log_register("pmd.afu.ipn3ke"); + if (ipn3ke_afu_logtype >= 0) + rte_log_set_level(ipn3ke_afu_logtype, RTE_LOG_NOTICE); +} diff --git a/drivers/net/ipn3ke/ipn3ke_ethdev.h b/drivers/net/ipn3ke/ipn3ke_ethdev.h new file mode 100644 index 0000000..09d085c --- /dev/null +++ b/drivers/net/ipn3ke/ipn3ke_ethdev.h @@ -0,0 +1,942 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#ifndef _IPN3KE_ETHDEV_H_ +#define _IPN3KE_ETHDEV_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define IPN3KE_TM_SCRATCH_RW 0 + +/* TM Levels */ +enum ipn3ke_tm_node_level { + IPN3KE_TM_NODE_LEVEL_PORT, + IPN3KE_TM_NODE_LEVEL_VT, + IPN3KE_TM_NODE_LEVEL_COS, + IPN3KE_TM_NODE_LEVEL_MAX, +}; + +/* TM Shaper Profile */ +struct ipn3ke_tm_shaper_profile { + uint32_t valid; + uint32_t m; + uint32_t e; + uint64_t rate; + struct rte_tm_shaper_params params; +}; + +TAILQ_HEAD(ipn3ke_tm_shaper_profile_list, ipn3ke_tm_shaper_profile); + + +#define IPN3KE_TDROP_TH1_MASK 0x1ffffff +#define IPN3KE_TDROP_TH1_SHIFT (25) +#define IPN3KE_TDROP_TH2_MASK 0x1ffffff + +/* TM TDROP Profile */ +struct ipn3ke_tm_tdrop_profile { + uint32_t tdrop_profile_id; + uint32_t th1; + uint32_t th2; + uint32_t n_users; + uint32_t valid; + struct rte_tm_wred_params params; +}; + +/* TM node priority */ +enum ipn3ke_tm_node_state { + IPN3KE_TM_NODE_STATE_IDLE = 0, + IPN3KE_TM_NODE_STATE_CONFIGURED_ADD, + IPN3KE_TM_NODE_STATE_CONFIGURED_DEL, + IPN3KE_TM_NODE_STATE_COMMITTED, + IPN3KE_TM_NODE_STATE_MAX, +}; + +TAILQ_HEAD(ipn3ke_tm_node_list, ipn3ke_tm_node); + +/* IPN3KE TM Node */ +struct ipn3ke_tm_node { + TAILQ_ENTRY(ipn3ke_tm_node) node; + uint32_t node_index; + uint32_t level; + uint32_t tm_id; + enum ipn3ke_tm_node_state node_state; + uint32_t parent_node_id; + uint32_t priority; + uint32_t weight; + struct ipn3ke_tm_node *parent_node; + struct ipn3ke_tm_shaper_profile shaper_profile; + struct ipn3ke_tm_tdrop_profile *tdrop_profile; + struct rte_tm_node_params params; + struct rte_tm_node_stats stats; + uint32_t n_children; + struct ipn3ke_tm_node_list children_node_list; +}; + +/* IPN3KE TM Hierarchy Specification */ +struct ipn3ke_tm_hierarchy { + struct ipn3ke_tm_node *port_node; + /*struct ipn3ke_tm_node_list vt_node_list;*/ + /*struct ipn3ke_tm_node_list cos_node_list;*/ + + uint32_t n_shaper_profiles; + /*uint32_t n_shared_shapers;*/ + uint32_t n_tdrop_profiles; + uint32_t n_vt_nodes; + uint32_t n_cos_nodes; + + struct ipn3ke_tm_node *port_commit_node; + struct ipn3ke_tm_node_list vt_commit_node_list; + struct ipn3ke_tm_node_list cos_commit_node_list; + + /*uint32_t n_tm_nodes[IPN3KE_TM_NODE_LEVEL_MAX];*/ +}; + +struct ipn3ke_tm_internals { + /** Hierarchy specification + * + * -Hierarchy is unfrozen at init and when port is stopped. + * -Hierarchy is frozen on successful hierarchy commit. + * -Run-time hierarchy changes are not allowed, therefore it makes + * sense to keep the hierarchy frozen after the port is started. + */ + struct ipn3ke_tm_hierarchy h; + int hierarchy_frozen; + int tm_started; + uint32_t tm_id; +}; + +#define IPN3KE_TM_COS_NODE_NUM (64 * 1024) +#define IPN3KE_TM_VT_NODE_NUM (IPN3KE_TM_COS_NODE_NUM / 8) +#define IPN3KE_TM_10G_PORT_NODE_NUM (8) +#define IPN3KE_TM_25G_PORT_NODE_NUM (4) + +#define IPN3KE_TM_NODE_LEVEL_MOD (100000) +#define IPN3KE_TM_NODE_MOUNT_MAX (8) + +#define IPN3KE_TM_TDROP_PROFILE_NUM (2 * 1024) + +/* TM node priority */ +enum ipn3ke_tm_node_priority { + IPN3KE_TM_NODE_PRIORITY_NORMAL0 = 0, + IPN3KE_TM_NODE_PRIORITY_LOW, + IPN3KE_TM_NODE_PRIORITY_NORMAL1, + IPN3KE_TM_NODE_PRIORITY_HIGHEST, +}; + +#define IPN3KE_TM_NODE_WEIGHT_MAX UINT8_MAX + +/** Set a bit in the uint32 variable */ +#define IPN3KE_BIT_SET(var, pos) \ + ((var) |= ((uint32_t)1 << ((pos)))) + +/** Reset the bit in the variable */ +#define IPN3KE_BIT_RESET(var, pos) \ + ((var) &= ~((uint32_t)1 << ((pos)))) + +/** Check the bit is set in the variable */ +#define IPN3KE_BIT_ISSET(var, pos) \ + (((var) & ((uint32_t)1 << ((pos)))) ? 1 : 0) + +struct ipn3ke_hw; + +#define IPN3KE_HW_BASE 0x4000000 + +#define IPN3KE_CAPABILITY_REGISTERS_BLOCK_OFFSET \ + (IPN3KE_HW_BASE + hw->hw_cap.capability_registers_block_offset) + +#define IPN3KE_STATUS_REGISTERS_BLOCK_OFFSET \ + (IPN3KE_HW_BASE + hw->hw_cap.status_registers_block_offset) + +#define IPN3KE_CTRL_RESET \ + (IPN3KE_HW_BASE + hw->hw_cap.control_registers_block_offset) + +#define IPN3KE_CTRL_MTU \ + (IPN3KE_HW_BASE + hw->hw_cap.control_registers_block_offset + 4) + +#define IPN3KE_CLASSIFY_OFFSET \ + (IPN3KE_HW_BASE + hw->hw_cap.classify_offset) + +#define IPN3KE_POLICER_OFFSET \ + (IPN3KE_HW_BASE + hw->hw_cap.policer_offset) + +#define IPN3KE_RSS_KEY_ARRAY_OFFSET \ + (IPN3KE_HW_BASE + hw->hw_cap.rss_key_array_offset) + +#define IPN3KE_RSS_INDIRECTION_TABLE_ARRAY_OFFSET \ + (IPN3KE_HW_BASE + hw->hw_cap.rss_indirection_table_array_offset) + +#define IPN3KE_DMAC_MAP_OFFSET \ + (IPN3KE_HW_BASE + hw->hw_cap.dmac_map_offset) + +#define IPN3KE_QM_OFFSET \ + (IPN3KE_HW_BASE + hw->hw_cap.qm_offset) + +#define IPN3KE_CCB_OFFSET \ + (IPN3KE_HW_BASE + hw->hw_cap.ccb_offset) + +#define IPN3KE_QOS_OFFSET \ + (IPN3KE_HW_BASE + hw->hw_cap.qos_offset) + +struct ipn3ke_hw_cap { + uint32_t version_number; + uint32_t capability_registers_block_offset; + uint32_t status_registers_block_offset; + uint32_t control_registers_block_offset; + uint32_t classify_offset; + uint32_t classy_size; + uint32_t policer_offset; + uint32_t policer_entry_size; + uint32_t rss_key_array_offset; + uint32_t rss_key_entry_size; + uint32_t rss_indirection_table_array_offset; + uint32_t rss_indirection_table_entry_size; + uint32_t dmac_map_offset; + uint32_t dmac_map_size; + uint32_t qm_offset; + uint32_t qm_size; + uint32_t ccb_offset; + uint32_t ccb_entry_size; + uint32_t qos_offset; + uint32_t qos_size; + + uint32_t num_rx_flow; /* Default: 64K */ + uint32_t num_rss_blocks; /* Default: 512 */ + uint32_t num_dmac_map; /* Default: 1K */ + uint32_t num_tx_flow; /* Default: 64K */ + uint32_t num_smac_map; /* Default: 1K */ + + uint32_t link_speed_mbps; +}; + +/** + * Strucute to store private data for each representor instance + */ +struct ipn3ke_rpst { + TAILQ_ENTRY(ipn3ke_rpst) next; /**< Next in device list. */ + uint16_t switch_domain_id; + /**< Switch ID */ + uint16_t port_id; + struct rte_eth_dev *ethdev; + /**< Port ID */ + struct ipn3ke_hw *hw; + struct rte_eth_dev *i40e_pf_eth; + uint16_t i40e_pf_eth_port_id; + struct rte_eth_link ori_linfo; + struct ipn3ke_tm_internals tm; + /**< Private data store of assocaiated physical function */ + struct ether_addr mac_addr; +}; + +/* UUID IDs */ +#define MAP_UUID_10G_LOW 0xffffffffffffffff +#define MAP_UUID_10G_HIGH 0xffffffffffffffff +#define IPN3KE_UUID_10G_LOW 0xc000c9660d824272 +#define IPN3KE_UUID_10G_HIGH 0x9aeffe5f84570612 +#define IPN3KE_UUID_VBNG_LOW 0x8991165349d23ff9 +#define IPN3KE_UUID_VBNG_HIGH 0xb74cf419d15a481f +#define IPN3KE_UUID_25G_LOW 0xb7d9bac566bfbc80 +#define IPN3KE_UUID_25G_HIGH 0xb07bac1aeef54d67 + +#define IPN3KE_AFU_BUF_SIZE_MIN 1024 +#define IPN3KE_AFU_FRAME_SIZE_MAX 9728 + +#define IPN3KE_RAWDEV_ATTR_LEN_MAX (64) + +typedef int (*ipn3ke_indirect_mac_read_t)(struct ipn3ke_hw *hw, + uint32_t *rd_data, uint32_t addr, uint32_t mac_num, + uint32_t eth_wrapper_sel); + +typedef int (*ipn3ke_indirect_mac_write_t)(struct ipn3ke_hw *hw, + uint32_t wr_data, uint32_t addr, uint32_t mac_num, + uint32_t eth_wrapper_sel); + +struct ipn3ke_hw { + struct rte_eth_dev *eth_dev; + + /* afu info */ + struct rte_afu_id afu_id; + struct rte_rawdev *rawdev; + + struct ipn3ke_hw_cap hw_cap; + + struct ifpga_rawdevg_retimer_info retimer; + + uint16_t switch_domain_id; + uint16_t port_num; + + uint32_t tm_hw_enable; + uint32_t flow_hw_enable; + + uint32_t acc_tm; + uint32_t acc_flow; + + uint32_t flow_max_entries; + uint32_t flow_num_entries; + + struct ipn3ke_tm_node *nodes; + struct ipn3ke_tm_node *port_nodes; + struct ipn3ke_tm_node *vt_nodes; + struct ipn3ke_tm_node *cos_nodes; + + struct ipn3ke_tm_tdrop_profile *tdrop_profile; + uint32_t tdrop_profile_num; + + uint32_t ccb_status; + uint32_t ccb_seg_free; + uint32_t ccb_seg_num; + uint32_t ccb_seg_k; + + uint8_t *eth_group_bar[2]; + /**< MAC Register read */ + ipn3ke_indirect_mac_read_t f_mac_read; + /**< MAC Register write */ + ipn3ke_indirect_mac_write_t f_mac_write; + + uint8_t *hw_addr; +}; + +/** + * @internal + * Helper macro for drivers that need to convert to struct rte_afu_device. + */ +#define RTE_DEV_TO_AFU(ptr) \ + container_of(ptr, struct rte_afu_device, device) + +#define RTE_DEV_TO_AFU_CONST(ptr) \ + container_of(ptr, const struct rte_afu_device, device) + +#define RTE_ETH_DEV_TO_AFU(eth_dev) \ + RTE_DEV_TO_AFU((eth_dev)->device) + +/** + * PCIe MMIO Access + */ + +#define IPN3KE_PCI_REG(reg) rte_read32(reg) +#define IPN3KE_PCI_REG_ADDR(a, reg) \ + ((volatile uint32_t *)((char *)(a)->hw_addr + (reg))) +static inline uint32_t ipn3ke_read_addr(volatile void *addr) +{ + return rte_le_to_cpu_32(IPN3KE_PCI_REG(addr)); +} + +#define WCMD 0x8000000000000000 +#define RCMD 0x4000000000000000 +#define UPL_BASE 0x10000 +static inline uint32_t _ipn3ke_indrct_read(struct ipn3ke_hw *hw, + uint32_t addr) +{ + uint64_t word_offset; + uint64_t read_data = 0; + uint64_t indirect_value; + volatile void *indirect_addrs; + + word_offset = (addr & 0x1FFFFFF) >> 2; + indirect_value = RCMD | word_offset << 32; + indirect_addrs = hw->hw_addr + (uint32_t)(UPL_BASE | 0x10); + + rte_delay_us(10); + + rte_write64((rte_cpu_to_le_64(indirect_value)), indirect_addrs); + + indirect_addrs = hw->hw_addr + (uint32_t)(UPL_BASE | 0x18); + while ((read_data >> 32) != 1) + read_data = rte_read64(indirect_addrs); + + return rte_le_to_cpu_32(read_data); +} + +static inline void _ipn3ke_indrct_write(struct ipn3ke_hw *hw, + uint32_t addr, uint32_t value) +{ + uint64_t word_offset; + uint64_t indirect_value; + volatile void *indirect_addrs = 0; + + word_offset = (addr & 0x1FFFFFF) >> 2; + indirect_value = WCMD | word_offset << 32 | value; + indirect_addrs = hw->hw_addr + (uint32_t)(UPL_BASE | 0x10); + + rte_write64((rte_cpu_to_le_64(indirect_value)), indirect_addrs); + rte_delay_us(10); +} + +#define IPN3KE_PCI_REG_WRITE(reg, value) \ + rte_write32((rte_cpu_to_le_32(value)), reg) + +#define IPN3KE_PCI_REG_WRITE_RELAXED(reg, value) \ + rte_write32_relaxed((rte_cpu_to_le_32(value)), reg) + +#define IPN3KE_READ_REG(hw, reg) \ + _ipn3ke_indrct_read((hw), (reg)) + +#define IPN3KE_WRITE_REG(hw, reg, value) \ + _ipn3ke_indrct_write((hw), (reg), (value)) + +#define IPN3KE_MASK_READ_REG(hw, reg, x, mask) \ + ((mask) & IPN3KE_READ_REG((hw), ((reg) + (0x4 * (x))))) + +#define IPN3KE_MASK_WRITE_REG(hw, reg, x, value, mask) \ + IPN3KE_WRITE_REG((hw), ((reg) + (0x4 * (x))), ((mask) & (value))) + +#define IPN3KE_DEV_PRIVATE_TO_HW(dev) \ + (((struct ipn3ke_rpst *)(dev)->data->dev_private)->hw) + +#define IPN3KE_DEV_PRIVATE_TO_RPST(dev) \ + ((struct ipn3ke_rpst *)(dev)->data->dev_private) + +#define IPN3KE_DEV_PRIVATE_TO_TM(dev) \ + (&(((struct ipn3ke_rpst *)(dev)->data->dev_private)->tm)) + +/* Byte address of IPN3KE internal module */ +#define IPN3KE_TM_VERSION (IPN3KE_QM_OFFSET + 0x0000) +#define IPN3KE_TM_SCRATCH (IPN3KE_QM_OFFSET + 0x0004) +#define IPN3KE_TM_STATUS (IPN3KE_QM_OFFSET + 0x0008) +#define IPN3KE_TM_MISC_STATUS (IPN3KE_QM_OFFSET + 0x0010) +#define IPN3KE_TM_MISC_WARNING_0 (IPN3KE_QM_OFFSET + 0x0040) +#define IPN3KE_TM_MISC_MON_0 (IPN3KE_QM_OFFSET + 0x0048) +#define IPN3KE_TM_MISC_FATAL_0 (IPN3KE_QM_OFFSET + 0x0050) +#define IPN3KE_TM_BW_MON_CTRL_1 (IPN3KE_QM_OFFSET + 0x0080) +#define IPN3KE_TM_BW_MON_CTRL_2 (IPN3KE_QM_OFFSET + 0x0084) +#define IPN3KE_TM_BW_MON_RATE (IPN3KE_QM_OFFSET + 0x0088) +#define IPN3KE_TM_STATS_CTRL (IPN3KE_QM_OFFSET + 0x0100) +#define IPN3KE_TM_STATS_DATA_0 (IPN3KE_QM_OFFSET + 0x0110) +#define IPN3KE_TM_STATS_DATA_1 (IPN3KE_QM_OFFSET + 0x0114) +#define IPN3KE_QM_UID_CONFIG_CTRL (IPN3KE_QM_OFFSET + 0x0200) +#define IPN3KE_QM_UID_CONFIG_DATA (IPN3KE_QM_OFFSET + 0x0204) + +#define IPN3KE_BM_VERSION (IPN3KE_QM_OFFSET + 0x4000) +#define IPN3KE_BM_STATUS (IPN3KE_QM_OFFSET + 0x4008) +#define IPN3KE_BM_STORE_CTRL (IPN3KE_QM_OFFSET + 0x4010) +#define IPN3KE_BM_STORE_STATUS (IPN3KE_QM_OFFSET + 0x4018) +#define IPN3KE_BM_STORE_MON (IPN3KE_QM_OFFSET + 0x4028) +#define IPN3KE_BM_WARNING_0 (IPN3KE_QM_OFFSET + 0x4040) +#define IPN3KE_BM_MON_0 (IPN3KE_QM_OFFSET + 0x4048) +#define IPN3KE_BM_FATAL_0 (IPN3KE_QM_OFFSET + 0x4050) +#define IPN3KE_BM_DRAM_ACCESS_CTRL (IPN3KE_QM_OFFSET + 0x4100) +#define IPN3KE_BM_DRAM_ACCESS_DATA_0 (IPN3KE_QM_OFFSET + 0x4120) +#define IPN3KE_BM_DRAM_ACCESS_DATA_1 (IPN3KE_QM_OFFSET + 0x4124) +#define IPN3KE_BM_DRAM_ACCESS_DATA_2 (IPN3KE_QM_OFFSET + 0x4128) +#define IPN3KE_BM_DRAM_ACCESS_DATA_3 (IPN3KE_QM_OFFSET + 0x412C) +#define IPN3KE_BM_DRAM_ACCESS_DATA_4 (IPN3KE_QM_OFFSET + 0x4130) +#define IPN3KE_BM_DRAM_ACCESS_DATA_5 (IPN3KE_QM_OFFSET + 0x4134) +#define IPN3KE_BM_DRAM_ACCESS_DATA_6 (IPN3KE_QM_OFFSET + 0x4138) + +#define IPN3KE_QM_VERSION (IPN3KE_QM_OFFSET + 0x8000) +#define IPN3KE_QM_STATUS (IPN3KE_QM_OFFSET + 0x8008) +#define IPN3KE_QM_LL_TABLE_MON (IPN3KE_QM_OFFSET + 0x8018) +#define IPN3KE_QM_WARNING_0 (IPN3KE_QM_OFFSET + 0x8040) +#define IPN3KE_QM_MON_0 (IPN3KE_QM_OFFSET + 0x8048) +#define IPN3KE_QM_FATAL_0 (IPN3KE_QM_OFFSET + 0x8050) +#define IPN3KE_QM_FATAL_1 (IPN3KE_QM_OFFSET + 0x8054) +#define IPN3KE_LL_TABLE_ACCESS_CTRL (IPN3KE_QM_OFFSET + 0x8100) +#define IPN3KE_LL_TABLE_ACCESS_DATA_0 (IPN3KE_QM_OFFSET + 0x8110) +#define IPN3KE_LL_TABLE_ACCESS_DATA_1 (IPN3KE_QM_OFFSET + 0x8114) + +#define IPN3KE_CCB_ERROR (IPN3KE_CCB_OFFSET + 0x0008) +#define IPN3KE_CCB_NSEGFREE (IPN3KE_CCB_OFFSET + 0x200000) +#define IPN3KE_CCB_NSEGFREE_MASK 0x3FFFFF +#define IPN3KE_CCB_PSEGMAX_COEF (IPN3KE_CCB_OFFSET + 0x200008) +#define IPN3KE_CCB_PSEGMAX_COEF_MASK 0xFFFFF +#define IPN3KE_CCB_NSEG_P (IPN3KE_CCB_OFFSET + 0x200080) +#define IPN3KE_CCB_NSEG_MASK 0x3FFFFF +#define IPN3KE_CCB_QPROFILE_Q (IPN3KE_CCB_OFFSET + 0x240000) +#define IPN3KE_CCB_QPROFILE_MASK 0x7FF +#define IPN3KE_CCB_PROFILE_P (IPN3KE_CCB_OFFSET + 0x280000) +#define IPN3KE_CCB_PROFILE_MASK 0x1FFFFFF +#define IPN3KE_CCB_PROFILE_MS (IPN3KE_CCB_OFFSET + 0xC) +#define IPN3KE_CCB_PROFILE_MS_MASK 0x1FFFFFF +#define IPN3KE_CCB_LR_LB_DBG_CTRL (IPN3KE_CCB_OFFSET + 0x2C0000) +#define IPN3KE_CCB_LR_LB_DBG_DONE (IPN3KE_CCB_OFFSET + 0x2C0004) +#define IPN3KE_CCB_LR_LB_DBG_RDATA (IPN3KE_CCB_OFFSET + 0x2C000C) + +#define IPN3KE_QOS_MAP_L1_X (IPN3KE_QOS_OFFSET + 0x000000) +#define IPN3KE_QOS_MAP_L1_MASK 0x1FFF +#define IPN3KE_QOS_MAP_L2_X (IPN3KE_QOS_OFFSET + 0x040000) +#define IPN3KE_QOS_MAP_L2_MASK 0x7 +#define IPN3KE_QOS_TYPE_MASK 0x3 +#define IPN3KE_QOS_TYPE_L1_X (IPN3KE_QOS_OFFSET + 0x200000) +#define IPN3KE_QOS_TYPE_L2_X (IPN3KE_QOS_OFFSET + 0x240000) +#define IPN3KE_QOS_TYPE_L3_X (IPN3KE_QOS_OFFSET + 0x280000) +#define IPN3KE_QOS_SCH_WT_MASK 0xFF +#define IPN3KE_QOS_SCH_WT_L1_X (IPN3KE_QOS_OFFSET + 0x400000) +#define IPN3KE_QOS_SCH_WT_L2_X (IPN3KE_QOS_OFFSET + 0x440000) +#define IPN3KE_QOS_SCH_WT_L3_X (IPN3KE_QOS_OFFSET + 0x480000) +#define IPN3KE_QOS_SHAP_WT_MASK 0x3FFF +#define IPN3KE_QOS_SHAP_WT_L1_X (IPN3KE_QOS_OFFSET + 0x600000) +#define IPN3KE_QOS_SHAP_WT_L2_X (IPN3KE_QOS_OFFSET + 0x640000) +#define IPN3KE_QOS_SHAP_WT_L3_X (IPN3KE_QOS_OFFSET + 0x680000) + +#define IPN3KE_CLF_BASE_DST_MAC_ADDR_HI (IPN3KE_CLASSIFY_OFFSET + 0x0000) +#define IPN3KE_CLF_BASE_DST_MAC_ADDR_LOW (IPN3KE_CLASSIFY_OFFSET + 0x0004) +#define IPN3KE_CLF_QINQ_STAG (IPN3KE_CLASSIFY_OFFSET + 0x0008) +#define IPN3KE_CLF_LKUP_ENABLE (IPN3KE_CLASSIFY_OFFSET + 0x000C) +#define IPN3KE_CLF_DFT_FLOW_ID (IPN3KE_CLASSIFY_OFFSET + 0x0040) +#define IPN3KE_CLF_RX_PARSE_CFG (IPN3KE_CLASSIFY_OFFSET + 0x0080) +#define IPN3KE_CLF_RX_STATS_CFG (IPN3KE_CLASSIFY_OFFSET + 0x00C0) +#define IPN3KE_CLF_RX_STATS_RPT (IPN3KE_CLASSIFY_OFFSET + 0x00C4) +#define IPN3KE_CLF_RX_TEST (IPN3KE_CLASSIFY_OFFSET + 0x0400) + +#define IPN3KE_CLF_EM_VERSION (IPN3KE_CLASSIFY_OFFSET + 0x40000 + 0x0000) +#define IPN3KE_CLF_EM_NUM (IPN3KE_CLASSIFY_OFFSET + 0x40000 + 0x0008) +#define IPN3KE_CLF_EM_KEY_WDTH (IPN3KE_CLASSIFY_OFFSET + 0x40000 + 0x000C) +#define IPN3KE_CLF_EM_RES_WDTH (IPN3KE_CLASSIFY_OFFSET + 0x40000 + 0x0010) +#define IPN3KE_CLF_EM_ALARMS (IPN3KE_CLASSIFY_OFFSET + 0x40000 + 0x0014) +#define IPN3KE_CLF_EM_DRC_RLAT (IPN3KE_CLASSIFY_OFFSET + 0x40000 + 0x0018) + +#define IPN3KE_CLF_MHL_VERSION (IPN3KE_CLASSIFY_OFFSET + 0x50000 + 0x0000) +#define IPN3KE_CLF_MHL_GEN_CTRL (IPN3KE_CLASSIFY_OFFSET + 0x50000 + 0x0018) +#define IPN3KE_CLF_MHL_MGMT_CTRL (IPN3KE_CLASSIFY_OFFSET + 0x50000 + 0x0020) +#define IPN3KE_CLF_MHL_MGMT_CTRL_BIT_BUSY 31 +#define IPN3KE_CLF_MHL_MGMT_CTRL_FLUSH 0x0 +#define IPN3KE_CLF_MHL_MGMT_CTRL_INSERT 0x1 +#define IPN3KE_CLF_MHL_MGMT_CTRL_DELETE 0x2 +#define IPN3KE_CLF_MHL_MGMT_CTRL_SEARCH 0x3 +#define IPN3KE_CLF_MHL_FATAL_0 (IPN3KE_CLASSIFY_OFFSET + 0x50000 + 0x0050) +#define IPN3KE_CLF_MHL_MON_0 (IPN3KE_CLASSIFY_OFFSET + 0x50000 + 0x0060) +#define IPN3KE_CLF_MHL_TOTAL_ENTRIES (IPN3KE_CLASSIFY_OFFSET + \ + 0x50000 + 0x0080) +#define IPN3KE_CLF_MHL_ONEHIT_BUCKETS (IPN3KE_CLASSIFY_OFFSET + \ + 0x50000 + 0x0084) +#define IPN3KE_CLF_MHL_KEY_MASK 0xFFFFFFFF +#define IPN3KE_CLF_MHL_KEY_0 (IPN3KE_CLASSIFY_OFFSET + 0x50000 + 0x1000) +#define IPN3KE_CLF_MHL_KEY_1 (IPN3KE_CLASSIFY_OFFSET + 0x50000 + 0x1004) +#define IPN3KE_CLF_MHL_KEY_2 (IPN3KE_CLASSIFY_OFFSET + 0x50000 + 0x1008) +#define IPN3KE_CLF_MHL_KEY_3 (IPN3KE_CLASSIFY_OFFSET + 0x50000 + 0x100C) +#define IPN3KE_CLF_MHL_RES_MASK 0xFFFFFFFF +#define IPN3KE_CLF_MHL_RES (IPN3KE_CLASSIFY_OFFSET + 0x50000 + 0x2000) + + + +/* IPN3KE_MASK is a macro used on 32 bit registers */ +#define IPN3KE_MASK(mask, shift) ((mask) << (shift)) + +#define IPN3KE_MAC_CTRL_BASE_0 0x00000000 +#define IPN3KE_MAC_CTRL_BASE_1 0x00008000 + +#define IPN3KE_MAC_STATS_MASK 0xFFFFFFFFF + +/* All the address are in 4Bytes*/ +#define IPN3KE_MAC_PRIMARY_MAC_ADDR0 0x0010 +#define IPN3KE_MAC_PRIMARY_MAC_ADDR1 0x0011 + +#define IPN3KE_MAC_MAC_RESET_CONTROL 0x001F +#define IPN3KE_MAC_MAC_RESET_CONTROL_TX_SHIFT 0 +#define IPN3KE_MAC_MAC_RESET_CONTROL_TX_MASK \ + IPN3KE_MASK(0x1, IPN3KE_MAC_MAC_RESET_CONTROL_TX_SHIFT) + +#define IPN3KE_MAC_MAC_RESET_CONTROL_RX_SHIFT 8 +#define IPN3KE_MAC_MAC_RESET_CONTROL_RX_MASK \ + IPN3KE_MASK(0x1, IPN3KE_MAC_MAC_RESET_CONTROL_RX_SHIFT) + +#define IPN3KE_MAC_TX_PACKET_CONTROL 0x0020 +#define IPN3KE_MAC_TX_PACKET_CONTROL_SHIFT 0 +#define IPN3KE_MAC_TX_PACKET_CONTROL_MASK \ + IPN3KE_MASK(0x1, IPN3KE_MAC_TX_PACKET_CONTROL_SHIFT) + +#define IPN3KE_MAC_TX_SRC_ADDR_OVERRIDE 0x002A +#define IPN3KE_MAC_TX_SRC_ADDR_OVERRIDE_SHIFT 0 +#define IPN3KE_MAC_TX_SRC_ADDR_OVERRIDE_MASK \ + IPN3KE_MASK(0x1, IPN3KE_MAC_TX_SRC_ADDR_OVERRIDE_SHIFT) + +#define IPN3KE_MAC_TX_FRAME_MAXLENGTH 0x002C +#define IPN3KE_MAC_TX_FRAME_MAXLENGTH_SHIFT 0 +#define IPN3KE_MAC_TX_FRAME_MAXLENGTH_MASK \ + IPN3KE_MASK(0xFFFF, IPN3KE_MAC_TX_FRAME_MAXLENGTH_SHIFT) + +#define IPN3KE_MAC_TX_PAUSEFRAME_CONTROL 0x0040 +#define IPN3KE_MAC_TX_PAUSEFRAME_CONTROL_SHIFT 0 +#define IPN3KE_MAC_TX_PAUSEFRAME_CONTROL_MASK \ + IPN3KE_MASK(0x3, IPN3KE_MAC_TX_PAUSEFRAME_CONTROL_SHIFT) + +#define IPN3KE_MAC_TX_PAUSEFRAME_QUANTA 0x0042 +#define IPN3KE_MAC_TX_PAUSEFRAME_QUANTA_SHIFT 0 +#define IPN3KE_MAC_TX_PAUSEFRAME_QUANTA_MASK \ + IPN3KE_MASK(0xFFFF, IPN3KE_MAC_TX_PAUSEFRAME_QUANTA_SHIFT) + +#define IPN3KE_MAC_TX_PAUSEFRAME_HOLDOFF_QUANTA 0x0043 +#define IPN3KE_MAC_TX_PAUSEFRAME_HOLDOFF_QUANTA_SHIFT 0 +#define IPN3KE_MAC_TX_PAUSEFRAME_HOLDOFF_QUANTA_MASK \ + IPN3KE_MASK(0xFFFF, IPN3KE_MAC_TX_PAUSEFRAME_HOLDOFF_QUANTA_SHIFT) + +#define IPN3KE_MAC_TX_PAUSEFRAME_ENABLE 0x0044 +#define IPN3KE_MAC_TX_PAUSEFRAME_ENABLE_CFG_SHIFT 0 +#define IPN3KE_MAC_TX_PAUSEFRAME_ENABLE_CFG_MASK \ + IPN3KE_MASK(0x1, IPN3KE_MAC_TX_PAUSEFRAME_ENABLE_CFG_SHIFT) + +#define IPN3KE_MAC_TX_PAUSEFRAME_ENABLE_TYPE_SHIFT 1 +#define IPN3KE_MAC_TX_PAUSEFRAME_ENABLE_TYPE_MASK \ + IPN3KE_MASK(0x3, IPN3KE_MAC_TX_PAUSEFRAME_ENABLE_TYPE_SHIFT) + +#define IPN3KE_MAC_RX_TRANSFER_CONTROL 0x00A0 +#define IPN3KE_MAC_RX_TRANSFER_CONTROL_SHIFT 0x0 +#define IPN3KE_MAC_RX_TRANSFER_CONTROL_MASK \ + IPN3KE_MASK(0x1, IPN3KE_MAC_RX_TRANSFER_CONTROL_SHIFT) + +#define IPN3KE_MAC_RX_FRAME_CONTROL 0x00AC +#define IPN3KE_MAC_RX_FRAME_CONTROL_EN_ALLUCAST_SHIFT 0x0 +#define IPN3KE_MAC_RX_FRAME_CONTROL_EN_ALLUCAST_MASK \ + IPN3KE_MASK(0x1, IPN3KE_MAC_RX_FRAME_CONTROL_EN_ALLUCAST_SHIFT) + +#define IPN3KE_MAC_RX_FRAME_CONTROL_EN_ALLMCAST_SHIFT 0x1 +#define IPN3KE_MAC_RX_FRAME_CONTROL_EN_ALLMCAST_MASK \ + IPN3KE_MASK(0x1, IPN3KE_MAC_RX_FRAME_CONTROL_EN_ALLMCAST_SHIFT) + +#define IPN3KE_VLAN_TAG_SIZE 4 +/** + * The overhead from MTU to max frame size. + * Considering QinQ packet, the VLAN tag needs to be counted twice. + */ +#define IPN3KE_ETH_OVERHEAD \ + (ETHER_HDR_LEN + ETHER_CRC_LEN + IPN3KE_VLAN_TAG_SIZE * 2) + +#define IPN3KE_MAC_FRAME_SIZE_MAX 9728 +#define IPN3KE_MAC_RX_FRAME_MAXLENGTH 0x00AE +#define IPN3KE_MAC_RX_FRAME_MAXLENGTH_SHIFT 0 +#define IPN3KE_MAC_RX_FRAME_MAXLENGTH_MASK \ + IPN3KE_MASK(0xFFFF, IPN3KE_MAC_RX_FRAME_MAXLENGTH_SHIFT) + +#define IPN3KE_MAC_TX_STATS_CLR 0x0140 +#define IPN3KE_MAC_TX_STATS_CLR_CLEAR_SHIFT 0 +#define IPN3KE_MAC_TX_STATS_CLR_CLEAR_MASK \ + IPN3KE_MASK(0x1, IPN3KE_MAC_TX_STATS_CLR_CLEAR_SHIFT) + +#define IPN3KE_MAC_RX_STATS_CLR 0x01C0 +#define IPN3KE_MAC_RX_STATS_CLR_CLEAR_SHIFT 0 +#define IPN3KE_MAC_RX_STATS_CLR_CLEAR_MASK \ + IPN3KE_MASK(0x1, IPN3KE_MAC_RX_STATS_CLR_CLEAR_SHIFT) + +/*tx_stats_framesOK*/ +#define IPN3KE_MAC_TX_STATS_FRAMESOK_HI 0x0142 +#define IPN3KE_MAC_TX_STATS_FRAMESOK_LOW 0x0143 + +/*rx_stats_framesOK*/ +#define IPN3KE_MAC_RX_STATS_FRAMESOK_HI 0x01C2 +#define IPN3KE_MAC_RX_STATS_FRAMESOK_LOW 0x01C3 + +/*tx_stats_framesErr*/ +#define IPN3KE_MAC_TX_STATS_FRAMESERR_HI 0x0144 +#define IPN3KE_MAC_TX_STATS_FRAMESERR_LOW 0x0145 + +/*rx_stats_framesErr*/ +#define IPN3KE_MAC_RX_STATS_FRAMESERR_HI 0x01C4 +#define IPN3KE_MAC_RX_STATS_FRAMESERR_LOW 0x01C5 + +/*rx_stats_framesCRCErr*/ +#define IPN3KE_MAC_RX_STATS_FRAMESCRCERR_HI 0x01C6 +#define IPN3KE_MAC_RX_STATS_FRAMESCRCERR_LOW 0x01C7 + +/*tx_stats_octetsOK 64b*/ +#define IPN3KE_MAC_TX_STATS_OCTETSOK_HI 0x0148 +#define IPN3KE_MAC_TX_STATS_OCTETSOK_LOW 0x0149 + +/*rx_stats_octetsOK 64b*/ +#define IPN3KE_MAC_RX_STATS_OCTETSOK_HI 0x01C8 +#define IPN3KE_MAC_RX_STATS_OCTETSOK_LOW 0x01C9 + +/*tx_stats_pauseMACCtrl_Frames*/ +#define IPN3KE_MAC_TX_STATS_PAUSEMACCTRL_FRAMES_HI 0x014A +#define IPN3KE_MAC_TX_STATS_PAUSEMACCTRL_FRAMES_LOW 0x014B + +/*rx_stats_pauseMACCtrl_Frames*/ +#define IPN3KE_MAC_RX_STATS_PAUSEMACCTRL_FRAMES_HI 0x01CA +#define IPN3KE_MAC_RX_STATS_PAUSEMACCTRL_FRAMES_LOW 0x01CB + +/*tx_stats_ifErrors*/ +#define IPN3KE_MAC_TX_STATS_IFERRORS_HI 0x014C +#define IPN3KE_MAC_TX_STATS_IFERRORS_LOW 0x014D + +/*rx_stats_ifErrors*/ +#define IPN3KE_MAC_RX_STATS_IFERRORS_HI 0x01CC +#define IPN3KE_MAC_RX_STATS_IFERRORS_LOW 0x01CD + +/*tx_stats_unicast_FramesOK*/ +#define IPN3KE_MAC_TX_STATS_UNICAST_FRAMESOK_HI 0x014E +#define IPN3KE_MAC_TX_STATS_UNICAST_FRAMESOK_LOW 0x014F + +/*rx_stats_unicast_FramesOK*/ +#define IPN3KE_MAC_RX_STATS_UNICAST_FRAMESOK_HI 0x01CE +#define IPN3KE_MAC_RX_STATS_UNICAST_FRAMESOK_LOW 0x01CF + +/*tx_stats_unicast_FramesErr*/ +#define IPN3KE_MAC_TX_STATS_UNICAST_FRAMESERR_HI 0x0150 +#define IPN3KE_MAC_TX_STATS_UNICAST_FRAMESERR_LOW 0x0151 + +/*rx_stats_unicast_FramesErr*/ +#define IPN3KE_MAC_RX_STATS_UNICAST_FRAMESERR_HI 0x01D0 +#define IPN3KE_MAC_RX_STATS_UNICAST_FRAMESERR_LOW 0x01D1 + +/*tx_stats_multicast_FramesOK*/ +#define IPN3KE_MAC_TX_STATS_MULTICAST_FRAMESOK_HI 0x0152 +#define IPN3KE_MAC_TX_STATS_MULTICAST_FRAMESOK_LOW 0x0153 + +/*rx_stats_multicast_FramesOK*/ +#define IPN3KE_MAC_RX_STATS_MULTICAST_FRAMESOK_HI 0x01D2 +#define IPN3KE_MAC_RX_STATS_MULTICAST_FRAMESOK_LOW 0x01D3 + +/*tx_stats_multicast_FramesErr*/ +#define IPN3KE_MAC_TX_STATS_MULTICAST_FRAMESERR_HI 0x0154 +#define IPN3KE_MAC_TX_STATS_MULTICAST_FRAMESERR_LOW 0x0155 + +/*rx_stats_multicast_FramesErr*/ +#define IPN3KE_MAC_RX_STATS_MULTICAST_FRAMESERR_HI 0x01D4 +#define IPN3KE_MAC_RX_STATS_MULTICAST_FRAMESERR_LOW 0x01D5 + +/*tx_stats_broadcast_FramesOK*/ +#define IPN3KE_MAC_TX_STATS_BROADCAST_FRAMESOK_HI 0x0156 +#define IPN3KE_MAC_TX_STATS_BROADCAST_FRAMESOK_LOW 0x0157 + +/*rx_stats_broadcast_FramesOK*/ +#define IPN3KE_MAC_RX_STATS_BROADCAST_FRAMESOK_HI 0x01D6 +#define IPN3KE_MAC_RX_STATS_BROADCAST_FRAMESOK_LOW 0x01D7 + +/*tx_stats_broadcast_FramesErr*/ +#define IPN3KE_MAC_TX_STATS_BROADCAST_FRAMESERR_HI 0x0158 +#define IPN3KE_MAC_TX_STATS_BROADCAST_FRAMESERR_LOW 0x0159 + +/*rx_stats_broadcast_FramesErr*/ +#define IPN3KE_MAC_RX_STATS_BROADCAST_FRAMESERR_HI 0x01D8 +#define IPN3KE_MAC_RX_STATS_BROADCAST_FRAMESERR_LOW 0x01D9 + +/*tx_stats_etherStatsOctets 64b*/ +#define IPN3KE_MAC_TX_STATS_ETHERSTATSOCTETS_HI 0x015A +#define IPN3KE_MAC_TX_STATS_ETHERSTATSOCTETS_LOW 0x015B + +/*rx_stats_etherStatsOctets 64b*/ +#define IPN3KE_MAC_RX_STATS_ETHERSTATSOCTETS_HI 0x01DA +#define IPN3KE_MAC_RX_STATS_ETHERSTATSOCTETS_LOW 0x01DB + +/*tx_stats_etherStatsPkts*/ +#define IPN3KE_MAC_TX_STATS_ETHERSTATSPKTS_HI 0x015C +#define IPN3KE_MAC_TX_STATS_ETHERSTATSPKTS_LOW 0x015D + +/*rx_stats_etherStatsPkts*/ +#define IPN3KE_MAC_RX_STATS_ETHERSTATSPKTS_HI 0x01DC +#define IPN3KE_MAC_RX_STATS_ETHERSTATSPKTS_LOW 0x01DD + +/*tx_stats_etherStatsUndersizePkts*/ +#define IPN3KE_MAC_TX_STATS_ETHERSTATSUNDERSIZEPKTS_HI 0x015E +#define IPN3KE_MAC_TX_STATS_ETHERSTATSUNDERSIZEPKTS_LOW 0x015F + +/*rx_stats_etherStatsUndersizePkts*/ +#define IPN3KE_MAC_RX_STATS_ETHERSTATSUNDERSIZEPKTS_HI 0x01DE +#define IPN3KE_MAC_RX_STATS_ETHERSTATSUNDERSIZEPKTS_LOW 0x01DF + +/*tx_stats_etherStatsOversizePkts*/ +#define IPN3KE_MAC_TX_STATS_ETHERSTATSOVERSIZEPKTS_HI 0x0160 +#define IPN3KE_MAC_TX_STATS_ETHERSTATSOVERSIZEPKTS_LOW 0x0161 + +/*rx_stats_etherStatsOversizePkts*/ +#define IPN3KE_MAC_RX_STATS_ETHERSTATSOVERSIZEPKTS_HI 0x01E0 +#define IPN3KE_MAC_RX_STATS_ETHERSTATSOVERSIZEPKTS_LOW 0x01E1 + +/*tx_stats_etherStatsPkts64Octets*/ +#define IPN3KE_MAC_TX_STATS_ETHERSTATSPKTS64OCTETS_HI 0x0162 +#define IPN3KE_MAC_TX_STATS_ETHERSTATSPKTS64OCTETS_LOW 0x0163 + +/*rx_stats_etherStatsPkts64Octets*/ +#define IPN3KE_MAC_RX_STATS_ETHERSTATSPKTS64OCTETS_HI 0x01E2 +#define IPN3KE_MAC_RX_STATS_ETHERSTATSPKTS64OCTETS_LOW 0x01E3 + +/*tx_stats_etherStatsPkts65to127Octets*/ +#define IPN3KE_MAC_TX_STATS_ETHERSTATSPKTS65TO127OCTETS_HI 0x0164 +#define IPN3KE_MAC_TX_STATS_ETHERSTATSPKTS65TO127OCTETS_LOW 0x0165 + +/*rx_stats_etherStatsPkts65to127Octets*/ +#define IPN3KE_MAC_RX_STATS_ETHERSTATSPKTS65TO127OCTETS_HI 0x01E4 +#define IPN3KE_MAC_RX_STATS_ETHERSTATSPKTS65TO127OCTETS_LOW 0x01E5 + +/*tx_stats_etherStatsPkts128to255Octets*/ +#define IPN3KE_MAC_TX_STATS_ETHERSTATSPKTS128TO255OCTETS_HI 0x0166 +#define IPN3KE_MAC_TX_STATS_ETHERSTATSPKTS128TO255OCTETS_LOW 0x0167 + +/*rx_stats_etherStatsPkts128to255Octets*/ +#define IPN3KE_MAC_RX_STATS_ETHERSTATSPKTS128TO255OCTETS_HI 0x01E6 +#define IPN3KE_MAC_RX_STATS_ETHERSTATSPKTS128TO255OCTETS_LOW 0x01E7 + +/*tx_stats_etherStatsPkts256to511Octet*/ +#define IPN3KE_MAC_TX_STATS_ETHERSTATSPKTS256TO511OCTET_HI 0x0168 +#define IPN3KE_MAC_TX_STATS_ETHERSTATSPKTS256TO511OCTET_LOW 0x0169 + +/*rx_stats_etherStatsPkts256to511Octets*/ +#define IPN3KE_MAC_RX_STATS_ETHERSTATSPKTS256TO511OCTETS_HI 0x01E8 +#define IPN3KE_MAC_RX_STATS_ETHERSTATSPKTS256TO511OCTETS_LOW 0x01E9 + +/*tx_stats_etherStatsPkts512to1023Octets*/ +#define IPN3KE_MAC_TX_STATS_ETHERSTATSPKTS512TO1023OCTETS_HI 0x016A +#define IPN3KE_MAC_TX_STATS_ETHERSTATSPKTS512TO1023OCTETS_LOW 0x016B + +/*rx_stats_etherStatsPkts512to1023Octets*/ +#define IPN3KE_MAC_RX_STATS_ETHERSTATSPKTS512TO1023OCTETS_HI 0x01EA +#define IPN3KE_MAC_RX_STATS_ETHERSTATSPKTS512TO1023OCTETS_LOW 0x01EB + +/*tx_stats_etherStatPkts1024to1518Octets*/ +#define IPN3KE_MAC_TX_STATS_ETHERSTATPKTS1024TO1518OCTETS_HI 0x016C +#define IPN3KE_MAC_TX_STATS_ETHERSTATPKTS1024TO1518OCTETS_LOW 0x016D + +/*rx_stats_etherStatPkts1024to1518Octets*/ +#define IPN3KE_MAC_RX_STATS_ETHERSTATPKTS1024TO1518OCTETS_HI 0x01EC +#define IPN3KE_MAC_RX_STATS_ETHERSTATPKTS1024TO1518OCTETS_LOW 0x01ED + +/*tx_stats_etherStatsPkts1519toXOctets*/ +#define IPN3KE_MAC_TX_STATS_ETHERSTATSPKTS1519TOXOCTETS_HI 0x016E +#define IPN3KE_MAC_TX_STATS_ETHERSTATSPKTS1519TOXOCTETS_LOW 0x016F + +/*rx_stats_etherStatsPkts1519toXOctets*/ +#define IPN3KE_MAC_RX_STATS_ETHERSTATSPKTS1519TOXOCTETS_HI 0x01EE +#define IPN3KE_MAC_RX_STATS_ETHERSTATSPKTS1519TOXOCTETS_LOW 0x01EF + +/*rx_stats_etherStatsFragments*/ +#define IPN3KE_MAC_RX_STATS_ETHERSTATSFRAGMENTS_HI 0x01F0 +#define IPN3KE_MAC_RX_STATS_ETHERSTATSFRAGMENTS_LOW 0x01F1 + +/*rx_stats_etherStatsJabbers*/ +#define IPN3KE_MAC_RX_STATS_ETHERSTATSJABBERS_HI 0x01F2 +#define IPN3KE_MAC_RX_STATS_ETHERSTATSJABBERS_LOW 0x01F3 + +/*rx_stats_etherStatsCRCErr*/ +#define IPN3KE_MAC_RX_STATS_ETHERSTATSCRCERR_HI 0x01F4 +#define IPN3KE_MAC_RX_STATS_ETHERSTATSCRCERR_LOW 0x01F5 + +/*tx_stats_unicastMACCtrlFrames*/ +#define IPN3KE_MAC_TX_STATS_UNICASTMACCTRLFRAMES_HI 0x0176 +#define IPN3KE_MAC_TX_STATS_UNICASTMACCTRLFRAMES_LOW 0x0177 + +/*rx_stats_unicastMACCtrlFrames*/ +#define IPN3KE_MAC_RX_STATS_UNICASTMACCTRLFRAMES_HI 0x01F6 +#define IPN3KE_MAC_RX_STATS_UNICASTMACCTRLFRAMES_LOW 0x01F7 + +/*tx_stats_multicastMACCtrlFrames*/ +#define IPN3KE_MAC_TX_STATS_MULTICASTMACCTRLFRAMES_HI 0x0178 +#define IPN3KE_MAC_TX_STATS_MULTICASTMACCTRLFRAMES_LOW 0x0179 + +/*rx_stats_multicastMACCtrlFrames*/ +#define IPN3KE_MAC_RX_STATS_MULTICASTMACCTRLFRAMES_HI 0x01F8 +#define IPN3KE_MAC_RX_STATS_MULTICASTMACCTRLFRAMES_LOW 0x01F9 + +/*tx_stats_broadcastMACCtrlFrames*/ +#define IPN3KE_MAC_TX_STATS_BROADCASTMACCTRLFRAMES_HI 0x017A +#define IPN3KE_MAC_TX_STATS_BROADCASTMACCTRLFRAMES_LOW 0x017B + +/*rx_stats_broadcastMACCtrlFrames*/ +#define IPN3KE_MAC_RX_STATS_BROADCASTMACCTRLFRAMES_HI 0x01FA +#define IPN3KE_MAC_RX_STATS_BROADCASTMACCTRLFRAMES_LOW 0x01FB + +/*tx_stats_PFCMACCtrlFrames*/ +#define IPN3KE_MAC_TX_STATS_PFCMACCTRLFRAMES_HI 0x017C +#define IPN3KE_MAC_TX_STATS_PFCMACCTRLFRAMES_LOW 0x017D + +/*rx_stats_PFCMACCtrlFrames*/ +#define IPN3KE_MAC_RX_STATS_PFCMACCTRLFRAMES_HI 0x01FC +#define IPN3KE_MAC_RX_STATS_PFCMACCTRLFRAMES_LOW 0x01FD + +static inline void ipn3ke_xmac_tx_enable(struct ipn3ke_hw *hw, + uint32_t mac_num, uint32_t eth_group_sel) +{ +#define IPN3KE_XMAC_TX_ENABLE (0 & (IPN3KE_MAC_TX_PACKET_CONTROL_MASK)) + + (*hw->f_mac_write)(hw, + IPN3KE_XMAC_TX_ENABLE, + IPN3KE_MAC_TX_PACKET_CONTROL, + mac_num, + eth_group_sel); +} + +static inline void ipn3ke_xmac_tx_disable(struct ipn3ke_hw *hw, + uint32_t mac_num, uint32_t eth_group_sel) +{ +#define IPN3KE_XMAC_TX_DISABLE (1 & (IPN3KE_MAC_TX_PACKET_CONTROL_MASK)) + + (*hw->f_mac_write)(hw, + IPN3KE_XMAC_TX_DISABLE, + IPN3KE_MAC_TX_PACKET_CONTROL, + mac_num, + eth_group_sel); +} + +static inline void ipn3ke_xmac_rx_enable(struct ipn3ke_hw *hw, + uint32_t mac_num, uint32_t eth_group_sel) +{ +#define IPN3KE_XMAC_RX_ENABLE (0 & (IPN3KE_MAC_RX_TRANSFER_CONTROL_MASK)) + + (*hw->f_mac_write)(hw, + IPN3KE_XMAC_RX_ENABLE, + IPN3KE_MAC_RX_TRANSFER_CONTROL, + mac_num, + eth_group_sel); +} + +static inline void ipn3ke_xmac_rx_disable(struct ipn3ke_hw *hw, + uint32_t mac_num, uint32_t eth_group_sel) +{ +#define IPN3KE_XMAC_RX_DISABLE (1 & (IPN3KE_MAC_RX_TRANSFER_CONTROL_MASK)) + + (*hw->f_mac_write)(hw, + IPN3KE_XMAC_RX_DISABLE, + IPN3KE_MAC_RX_TRANSFER_CONTROL, + mac_num, + eth_group_sel); +} + +static inline void ipn3ke_xmac_smac_ovd_dis(struct ipn3ke_hw *hw, + uint32_t mac_num, uint32_t eth_group_sel) +{ +#define IPN3KE_XMAC_SMAC_OVERRIDE_DISABLE (0 & \ + (IPN3KE_MAC_TX_SRC_ADDR_OVERRIDE_MASK)) + + (*hw->f_mac_write)(hw, + IPN3KE_XMAC_SMAC_OVERRIDE_DISABLE, + IPN3KE_MAC_TX_SRC_ADDR_OVERRIDE, + mac_num, + eth_group_sel); +} + +static inline void ipn3ke_xmac_tx_clr_stcs(struct ipn3ke_hw *hw, + uint32_t mac_num, uint32_t eth_group_sel) +{ +#define IPN3KE_XMAC_TX_CLR_STCS (1 & \ + (IPN3KE_MAC_TX_STATS_CLR_CLEAR_MASK)) + + (*hw->f_mac_write)(hw, + IPN3KE_XMAC_TX_CLR_STCS, + IPN3KE_MAC_TX_STATS_CLR, + mac_num, + eth_group_sel); +} + +static inline void ipn3ke_xmac_rx_clr_stcs(struct ipn3ke_hw *hw, + uint32_t mac_num, uint32_t eth_group_sel) +{ +#define IPN3KE_XMAC_RX_CLR_STCS (1 & \ + (IPN3KE_MAC_RX_STATS_CLR_CLEAR_MASK)) + + (*hw->f_mac_write)(hw, + IPN3KE_XMAC_RX_CLR_STCS, + IPN3KE_MAC_RX_STATS_CLR, + mac_num, + eth_group_sel); +} + + +#endif /* _IPN3KE_ETHDEV_H_ */ diff --git a/drivers/net/ipn3ke/ipn3ke_logs.h b/drivers/net/ipn3ke/ipn3ke_logs.h new file mode 100644 index 0000000..147fd80 --- /dev/null +++ b/drivers/net/ipn3ke/ipn3ke_logs.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#ifndef _IPN3KE_LOGS_H_ +#define _IPN3KE_LOGS_H_ + +#include + +extern int ipn3ke_afu_logtype; + +#define IPN3KE_AFU_PMD_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ipn3ke_afu_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IPN3KE_AFU_PMD_FUNC_TRACE() IPN3KE_AFU_PMD_LOG(DEBUG, ">>") + +#define IPN3KE_AFU_PMD_DEBUG(fmt, args...) \ + IPN3KE_AFU_PMD_LOG(DEBUG, fmt, ## args) + +#define IPN3KE_AFU_PMD_INFO(fmt, args...) \ + IPN3KE_AFU_PMD_LOG(INFO, fmt, ## args) + +#define IPN3KE_AFU_PMD_ERR(fmt, args...) \ + IPN3KE_AFU_PMD_LOG(ERR, fmt, ## args) + +#define IPN3KE_AFU_PMD_WARN(fmt, args...) \ + IPN3KE_AFU_PMD_LOG(WARNING, fmt, ## args) + +#endif /* _IPN3KE_LOGS_H_ */ diff --git a/drivers/net/ipn3ke/ipn3ke_rawdev_api.h b/drivers/net/ipn3ke/ipn3ke_rawdev_api.h new file mode 100644 index 0000000..671fae8 --- /dev/null +++ b/drivers/net/ipn3ke/ipn3ke_rawdev_api.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_RAWDEV_API_H_ +#define _IFPGA_RAWDEV_API_H_ + +#include + +enum ifpga_rawdev_retimer_media_type { + IFPGA_RAWDEV_RETIMER_MEDIA_TYPE_UNKNOWN = 0, + IFPGA_RAWDEV_RETIMER_MEDIA_TYPE_100GBASE_LR4, + IFPGA_RAWDEV_RETIMER_MEDIA_TYPE_100GBASE_SR4, + IFPGA_RAWDEV_RETIMER_MEDIA_TYPE_100GBASE_CR4, + IFPGA_RAWDEV_RETIMER_MEDIA_TYPE_40GBASE_LR4, + IFPGA_RAWDEV_RETIMER_MEDIA_TYPE_400GBASE_SR4, + IFPGA_RAWDEV_RETIMER_MEDIA_TYPE_40GBASE_CR4, + IFPGA_RAWDEV_RETIMER_MEDIA_TYPE_25GBASE_SR, + IFPGA_RAWDEV_RETIMER_MEDIA_TYPE_25GBASE_CR, + IFPGA_RAWDEV_RETIMER_MEDIA_TYPE_10GBASE_LR, + IFPGA_RAWDEV_RETIMER_MEDIA_TYPE_10GBASE_SR, + IFPGA_RAWDEV_RETIMER_MEDIA_TYPE_10GBASE_DAC, + IFPGA_RAWDEV_RETIMER_MEDIA_TYPE_DEFAULT +}; + +enum ifpga_rawdev_retimer_mac_type { + IFPGA_RAWDEV_RETIMER_MAC_TYPE_UNKNOWN = 0, + IFPGA_RAWDEV_RETIMER_MAC_TYPE_100GE_CAUI, + IFPGA_RAWDEVG_RETIMER_MAC_TYPE_40GE_XLAUI, + IFPGA_RAWDEV_RETIMER_MAC_TYPE_25GE_25GAUI, + IFPGA_RAWDEV_RETIMER_MAC_TYPE_10GE_XFI, + IFPGA_RAWDEV_RETIMER_MAC_TYPE_DEFAULT +}; + +#define IFPGA_RAWDEV_LINK_SPEED_10GB_SHIFT 0x0 +#define IFPGA_RAWDEV_LINK_SPEED_40GB_SHIFT 0x1 +#define IFPGA_RAWDEV_LINK_SPEED_25GB_SHIFT 0x2 + +enum ifpga_rawdev_link_speed { + IFPGA_RAWDEV_LINK_SPEED_UNKNOWN = 0, + IFPGA_RAWDEV_LINK_SPEED_10GB = + (1 << IFPGA_RAWDEV_LINK_SPEED_10GB_SHIFT), + IFPGA_RAWDEV_LINK_SPEED_40GB = + (1 << IFPGA_RAWDEV_LINK_SPEED_40GB_SHIFT), + IFPGA_RAWDEV_LINK_SPEED_25GB = + (1 << IFPGA_RAWDEV_LINK_SPEED_25GB_SHIFT), +}; + +struct ifpga_rawdevg_retimer_info { + int retimer_num; + int port_num; + enum ifpga_rawdev_retimer_media_type media_type; + enum ifpga_rawdev_retimer_mac_type mac_type; +}; + +struct ifpga_rawdevg_link_info { + int port; + int link_up; + enum ifpga_rawdev_link_speed link_speed; +}; + +#endif /* _IFPGA_RAWDEV_H_ */ diff --git a/drivers/net/ipn3ke/meson.build b/drivers/net/ipn3ke/meson.build new file mode 100644 index 0000000..b511600 --- /dev/null +++ b/drivers/net/ipn3ke/meson.build @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2019 Intel Corporation + +# +# Add the experimenatal APIs called from this PMD +# rte_eth_switch_domain_alloc() +# rte_eth_dev_create() +# rte_eth_dev_destroy() +# rte_eth_switch_domain_free() +# +allow_experimental_apis = true + +sources += files('ipn3ke_ethdev.c') +deps += ['bus_ifpga', 'sched'] diff --git a/drivers/net/ipn3ke/rte_pmd_ipn3ke_version.map b/drivers/net/ipn3ke/rte_pmd_ipn3ke_version.map new file mode 100644 index 0000000..fc8c95e --- /dev/null +++ b/drivers/net/ipn3ke/rte_pmd_ipn3ke_version.map @@ -0,0 +1,4 @@ +DPDK_19.05 { + + local: *; +}; diff --git a/drivers/net/meson.build b/drivers/net/meson.build index 1105e72..6b96786 100644 --- a/drivers/net/meson.build +++ b/drivers/net/meson.build @@ -20,6 +20,7 @@ drivers = ['af_packet', 'iavf', 'ice', 'ifc', + 'ipn3ke', 'ixgbe', 'kni', 'liquidio', diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 7d994be..d2b8ab6 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -298,6 +298,7 @@ endif # CONFIG_RTE_LIBRTE_FSLMC_BUS _LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga ifeq ($(CONFIG_RTE_LIBRTE_IFPGA_BUS),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV) += -lrte_pmd_ifpga_rawdev +_LDLIBS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += -lrte_pmd_ipn3ke endif # CONFIG_RTE_LIBRTE_IFPGA_BUS endif # CONFIG_RTE_LIBRTE_RAWDEV diff --git a/usertools/dpdk-devbind.py b/usertools/dpdk-devbind.py index 249b65a..9e79f0d 100755 --- a/usertools/dpdk-devbind.py +++ b/usertools/dpdk-devbind.py @@ -12,6 +12,8 @@ # The PCI base class for all devices network_class = {'Class': '02', 'Vendor': None, 'Device': None, 'SVendor': None, 'SDevice': None} +ifpga_class = {'Class': '12', 'Vendor': '8086', 'Device': '0b30', + 'SVendor': None, 'SDevice': None} encryption_class = {'Class': '10', 'Vendor': None, 'Device': None, 'SVendor': None, 'SDevice': None} intel_processor_class = {'Class': '0b', 'Vendor': '8086', 'Device': None, @@ -34,7 +36,7 @@ octeontx2_npa = {'Class': '08', 'Vendor': '177d', 'Device': 'a0fb,a0fc', 'SVendor': None, 'SDevice': None} -network_devices = [network_class, cavium_pkx, avp_vnic] +network_devices = [network_class, cavium_pkx, avp_vnic, ifpga_class] crypto_devices = [encryption_class, intel_processor_class] eventdev_devices = [cavium_sso, cavium_tim, octeontx2_sso] mempool_devices = [cavium_fpa, octeontx2_npa] From patchwork Wed Apr 10 06:27:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52531 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 4AA895F2C; Wed, 10 Apr 2019 08:27:09 +0200 (CEST) Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by dpdk.org (Postfix) with ESMTP id 2E8F95F17 for ; Wed, 10 Apr 2019 08:27:07 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 23:27:06 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,332,1549958400"; d="scan'208";a="147980769" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by FMSMGA003.fm.intel.com with ESMTP; 09 Apr 2019 23:27:02 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Wed, 10 Apr 2019 14:27:42 +0800 Message-Id: <1554877672-19745-5-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554877672-19745-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554877672-19745-1-git-send-email-rosen.xu@intel.com> Subject: [dpdk-dev] [PATCH v7 04/14] net/ipn3ke: add IPN3KE representor of PMD driver X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add Intel FPGA Acceleration NIC IPN3KE representor of PMD driver. Signed-off-by: Rosen Xu Signed-off-by: Andy Pei Signed-off-by: Dan Wei --- drivers/net/ipn3ke/Makefile | 2 + drivers/net/ipn3ke/ipn3ke_ethdev.c | 4 +- drivers/net/ipn3ke/ipn3ke_ethdev.h | 25 + drivers/net/ipn3ke/ipn3ke_representor.c | 887 ++++++++++++++++++++++++++++++++ drivers/net/ipn3ke/meson.build | 3 +- 5 files changed, 918 insertions(+), 3 deletions(-) create mode 100644 drivers/net/ipn3ke/ipn3ke_representor.c diff --git a/drivers/net/ipn3ke/Makefile b/drivers/net/ipn3ke/Makefile index d7aa79b..221567d 100644 --- a/drivers/net/ipn3ke/Makefile +++ b/drivers/net/ipn3ke/Makefile @@ -23,6 +23,7 @@ LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs LDLIBS += -lrte_bus_ifpga LDLIBS += -lrte_bus_vdev +LDLIBS += -lpthread EXPORT_MAP := rte_pmd_ipn3ke_version.map @@ -32,5 +33,6 @@ LIBABIVER := 1 # all source are stored in SRCS-y # SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_ethdev.c +SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_representor.c include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/net/ipn3ke/ipn3ke_ethdev.c b/drivers/net/ipn3ke/ipn3ke_ethdev.c index d5fee6f..58c8ce4 100644 --- a/drivers/net/ipn3ke/ipn3ke_ethdev.c +++ b/drivers/net/ipn3ke/ipn3ke_ethdev.c @@ -339,7 +339,7 @@ static int ipn3ke_vswitch_probe(struct rte_afu_device *afu_dev) retval = rte_eth_dev_create(&afu_dev->device, name, sizeof(struct ipn3ke_rpst), NULL, NULL, - NULL, &rpst); + ipn3ke_rpst_init, &rpst); if (retval) IPN3KE_AFU_PMD_ERR("failed to create ipn3ke representor %s.", @@ -368,7 +368,7 @@ static int ipn3ke_vswitch_remove(struct rte_afu_device *afu_dev) if (!ethdev) return -ENODEV; - rte_eth_dev_destroy(ethdev, NULL); + rte_eth_dev_destroy(ethdev, ipn3ke_rpst_uninit); } ret = rte_eth_switch_domain_free(hw->switch_domain_id); diff --git a/drivers/net/ipn3ke/ipn3ke_ethdev.h b/drivers/net/ipn3ke/ipn3ke_ethdev.h index 09d085c..d2c73e5 100644 --- a/drivers/net/ipn3ke/ipn3ke_ethdev.h +++ b/drivers/net/ipn3ke/ipn3ke_ethdev.h @@ -527,6 +527,31 @@ static inline void _ipn3ke_indrct_write(struct ipn3ke_hw *hw, #define IPN3KE_CLF_MHL_RES_MASK 0xFFFFFFFF #define IPN3KE_CLF_MHL_RES (IPN3KE_CLASSIFY_OFFSET + 0x50000 + 0x2000) +int +ipn3ke_rpst_dev_set_link_up(struct rte_eth_dev *dev); +int +ipn3ke_rpst_dev_set_link_down(struct rte_eth_dev *dev); +int +ipn3ke_rpst_link_update(struct rte_eth_dev *ethdev, + __rte_unused int wait_to_complete); +void +ipn3ke_rpst_promiscuous_enable(struct rte_eth_dev *ethdev); +void +ipn3ke_rpst_promiscuous_disable(struct rte_eth_dev *ethdev); +void +ipn3ke_rpst_allmulticast_enable(struct rte_eth_dev *ethdev); +void +ipn3ke_rpst_allmulticast_disable(struct rte_eth_dev *ethdev); +int +ipn3ke_rpst_mac_addr_set(struct rte_eth_dev *ethdev, + struct ether_addr *mac_addr); +int +ipn3ke_rpst_mtu_set(struct rte_eth_dev *ethdev, uint16_t mtu); + +int +ipn3ke_rpst_init(struct rte_eth_dev *ethdev, void *init_params); +int +ipn3ke_rpst_uninit(struct rte_eth_dev *ethdev); /* IPN3KE_MASK is a macro used on 32 bit registers */ diff --git a/drivers/net/ipn3ke/ipn3ke_representor.c b/drivers/net/ipn3ke/ipn3ke_representor.c new file mode 100644 index 0000000..3831982 --- /dev/null +++ b/drivers/net/ipn3ke/ipn3ke_representor.c @@ -0,0 +1,887 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ipn3ke_rawdev_api.h" +#include "ipn3ke_logs.h" +#include "ipn3ke_ethdev.h" + +static int ipn3ke_rpst_scan_num; +static pthread_t ipn3ke_rpst_scan_thread; + +/** Double linked list of representor port. */ +TAILQ_HEAD(ipn3ke_rpst_list, ipn3ke_rpst); + +static struct ipn3ke_rpst_list ipn3ke_rpst_list = + TAILQ_HEAD_INITIALIZER(ipn3ke_rpst_list); + +static rte_spinlock_t ipn3ke_link_notify_list_lk = RTE_SPINLOCK_INITIALIZER; + +static int +ipn3ke_rpst_link_check(struct ipn3ke_rpst *rpst); + +static void +ipn3ke_rpst_dev_infos_get(struct rte_eth_dev *ethdev, + struct rte_eth_dev_info *dev_info) +{ + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(ethdev); + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(ethdev); + + dev_info->speed_capa = + (hw->retimer.mac_type == + IFPGA_RAWDEV_RETIMER_MAC_TYPE_10GE_XFI) ? + ETH_LINK_SPEED_10G : + ((hw->retimer.mac_type == + IFPGA_RAWDEV_RETIMER_MAC_TYPE_25GE_25GAUI) ? + ETH_LINK_SPEED_25G : + ETH_LINK_SPEED_AUTONEG); + + dev_info->max_rx_queues = 1; + dev_info->max_tx_queues = 1; + dev_info->min_rx_bufsize = IPN3KE_AFU_BUF_SIZE_MIN; + dev_info->max_rx_pktlen = IPN3KE_AFU_FRAME_SIZE_MAX; + dev_info->max_mac_addrs = hw->port_num; + dev_info->max_vfs = 0; + dev_info->default_txconf = (struct rte_eth_txconf) { + .offloads = 0, + }; + dev_info->rx_queue_offload_capa = 0; + dev_info->rx_offload_capa = + DEV_RX_OFFLOAD_VLAN_STRIP | + DEV_RX_OFFLOAD_QINQ_STRIP | + DEV_RX_OFFLOAD_IPV4_CKSUM | + DEV_RX_OFFLOAD_UDP_CKSUM | + DEV_RX_OFFLOAD_TCP_CKSUM | + DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM | + DEV_RX_OFFLOAD_VLAN_EXTEND | + DEV_RX_OFFLOAD_VLAN_FILTER | + DEV_RX_OFFLOAD_JUMBO_FRAME; + + dev_info->tx_queue_offload_capa = DEV_TX_OFFLOAD_MBUF_FAST_FREE; + dev_info->tx_offload_capa = + DEV_TX_OFFLOAD_VLAN_INSERT | + DEV_TX_OFFLOAD_QINQ_INSERT | + DEV_TX_OFFLOAD_IPV4_CKSUM | + DEV_TX_OFFLOAD_UDP_CKSUM | + DEV_TX_OFFLOAD_TCP_CKSUM | + DEV_TX_OFFLOAD_SCTP_CKSUM | + DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM | + DEV_TX_OFFLOAD_TCP_TSO | + DEV_TX_OFFLOAD_VXLAN_TNL_TSO | + DEV_TX_OFFLOAD_GRE_TNL_TSO | + DEV_TX_OFFLOAD_IPIP_TNL_TSO | + DEV_TX_OFFLOAD_GENEVE_TNL_TSO | + DEV_TX_OFFLOAD_MULTI_SEGS | + dev_info->tx_queue_offload_capa; + + dev_info->dev_capa = + RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP | + RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP; + + dev_info->switch_info.name = ethdev->device->name; + dev_info->switch_info.domain_id = rpst->switch_domain_id; + dev_info->switch_info.port_id = rpst->port_id; +} + +static int +ipn3ke_rpst_dev_configure(__rte_unused struct rte_eth_dev *dev) +{ + return 0; +} + +static int +ipn3ke_rpst_dev_start(struct rte_eth_dev *dev) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(dev); + struct rte_rawdev *rawdev; + uint64_t base_mac; + uint32_t val; + char attr_name[IPN3KE_RAWDEV_ATTR_LEN_MAX]; + + rawdev = hw->rawdev; + + memset(attr_name, 0, sizeof(attr_name)); + snprintf(attr_name, IPN3KE_RAWDEV_ATTR_LEN_MAX, "%s", + "LineSideBaseMAC"); + rawdev->dev_ops->attr_get(rawdev, attr_name, &base_mac); + ether_addr_copy((struct ether_addr *)&base_mac, &rpst->mac_addr); + + ether_addr_copy(&rpst->mac_addr, &dev->data->mac_addrs[0]); + dev->data->mac_addrs->addr_bytes[ETHER_ADDR_LEN - 1] = + (uint8_t)rpst->port_id + 1; + + if (hw->retimer.mac_type == IFPGA_RAWDEV_RETIMER_MAC_TYPE_10GE_XFI) { + /* Set mac address */ + rte_memcpy(((char *)(&val)), + (char *)&dev->data->mac_addrs->addr_bytes[0], + sizeof(uint32_t)); + (*hw->f_mac_write)(hw, + val, + IPN3KE_MAC_PRIMARY_MAC_ADDR0, + rpst->port_id, + 0); + rte_memcpy(((char *)(&val)), + (char *)&dev->data->mac_addrs->addr_bytes[4], + sizeof(uint16_t)); + (*hw->f_mac_write)(hw, + val, + IPN3KE_MAC_PRIMARY_MAC_ADDR1, + rpst->port_id, + 0); + + /* Enable the TX path */ + ipn3ke_xmac_tx_enable(hw, rpst->port_id, 0); + + /* Disables source address override */ + ipn3ke_xmac_smac_ovd_dis(hw, rpst->port_id, 0); + + /* Enable the RX path */ + ipn3ke_xmac_rx_enable(hw, rpst->port_id, 0); + + /* Clear all TX statistics counters */ + ipn3ke_xmac_tx_clr_stcs(hw, rpst->port_id, 0); + + /* Clear all RX statistics counters */ + ipn3ke_xmac_rx_clr_stcs(hw, rpst->port_id, 0); + } + + ipn3ke_rpst_link_update(dev, 0); + + return 0; +} + +static void +ipn3ke_rpst_dev_stop(struct rte_eth_dev *dev) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(dev); + + if (hw->retimer.mac_type == IFPGA_RAWDEV_RETIMER_MAC_TYPE_10GE_XFI) { + /* Disable the TX path */ + ipn3ke_xmac_tx_disable(hw, rpst->port_id, 0); + + /* Disable the RX path */ + ipn3ke_xmac_rx_disable(hw, rpst->port_id, 0); + } +} + +static void +ipn3ke_rpst_dev_close(struct rte_eth_dev *dev) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(dev); + + if (hw->retimer.mac_type == IFPGA_RAWDEV_RETIMER_MAC_TYPE_10GE_XFI) { + /* Disable the TX path */ + ipn3ke_xmac_tx_disable(hw, rpst->port_id, 0); + + /* Disable the RX path */ + ipn3ke_xmac_rx_disable(hw, rpst->port_id, 0); + } +} + +/* + * Reset PF device only to re-initialize resources in PMD layer + */ +static int +ipn3ke_rpst_dev_reset(struct rte_eth_dev *dev) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(dev); + + if (hw->retimer.mac_type == IFPGA_RAWDEV_RETIMER_MAC_TYPE_10GE_XFI) { + /* Disable the TX path */ + ipn3ke_xmac_tx_disable(hw, rpst->port_id, 0); + + /* Disable the RX path */ + ipn3ke_xmac_rx_disable(hw, rpst->port_id, 0); + } + + return 0; +} + +static int +ipn3ke_rpst_rx_queue_start(__rte_unused struct rte_eth_dev *dev, + __rte_unused uint16_t rx_queue_id) +{ + return 0; +} + +static int +ipn3ke_rpst_rx_queue_stop(__rte_unused struct rte_eth_dev *dev, + __rte_unused uint16_t rx_queue_id) +{ + return 0; +} + +static int +ipn3ke_rpst_tx_queue_start(__rte_unused struct rte_eth_dev *dev, + __rte_unused uint16_t tx_queue_id) +{ + return 0; +} + +static int +ipn3ke_rpst_tx_queue_stop(__rte_unused struct rte_eth_dev *dev, + __rte_unused uint16_t tx_queue_id) +{ + return 0; +} + +static int +ipn3ke_rpst_rx_queue_setup(__rte_unused struct rte_eth_dev *dev, + __rte_unused uint16_t queue_idx, __rte_unused uint16_t nb_desc, + __rte_unused unsigned int socket_id, + __rte_unused const struct rte_eth_rxconf *rx_conf, + __rte_unused struct rte_mempool *mp) +{ + return 0; +} + +static void +ipn3ke_rpst_rx_queue_release(__rte_unused void *rxq) +{ +} + +static int +ipn3ke_rpst_tx_queue_setup(__rte_unused struct rte_eth_dev *dev, + __rte_unused uint16_t queue_idx, __rte_unused uint16_t nb_desc, + __rte_unused unsigned int socket_id, + __rte_unused const struct rte_eth_txconf *tx_conf) +{ + return 0; +} + +static void +ipn3ke_rpst_tx_queue_release(__rte_unused void *txq) +{ +} + +static int +ipn3ke_rpst_stats_get(__rte_unused struct rte_eth_dev *ethdev, + __rte_unused struct rte_eth_stats *stats) +{ + return 0; +} + +static int +ipn3ke_rpst_xstats_get(__rte_unused struct rte_eth_dev *dev, + __rte_unused struct rte_eth_xstat *xstats, __rte_unused unsigned int n) +{ + return 0; +} + +static int +ipn3ke_rpst_xstats_get_names(__rte_unused struct rte_eth_dev *dev, + __rte_unused struct rte_eth_xstat_name *xstats_names, + __rte_unused unsigned int limit) +{ + return 0; +} + +static void +ipn3ke_rpst_stats_reset(__rte_unused struct rte_eth_dev *ethdev) +{ +} + +static void +ipn3ke_update_link(struct rte_rawdev *rawdev, + uint16_t port, struct rte_eth_link *link) +{ + uint64_t line_link_bitmap = 0; + enum ifpga_rawdev_link_speed link_speed; + + rawdev->dev_ops->attr_get(rawdev, + "LineSideLinkStatus", + (uint64_t *)&line_link_bitmap); + + /* Parse the link status */ + if ((1 << port) & line_link_bitmap) + link->link_status = 1; + else + link->link_status = 0; + + IPN3KE_AFU_PMD_DEBUG("port is %d\n", port); + IPN3KE_AFU_PMD_DEBUG("link->link_status is %d\n", link->link_status); + + rawdev->dev_ops->attr_get(rawdev, + "LineSideLinkSpeed", + (uint64_t *)&link_speed); + switch (link_speed) { + case IFPGA_RAWDEV_LINK_SPEED_10GB: + link->link_speed = ETH_SPEED_NUM_10G; + break; + case IFPGA_RAWDEV_LINK_SPEED_25GB: + link->link_speed = ETH_SPEED_NUM_25G; + break; + default: + IPN3KE_AFU_PMD_ERR("Unknown link speed info %u", link_speed); + break; + } +} + +/* + * Set device link up. + */ +int +ipn3ke_rpst_dev_set_link_up(struct rte_eth_dev *dev) +{ + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(dev); + struct rte_eth_dev *pf; + int ret = 0; + + if (rpst->i40e_pf_eth) { + ret = rte_eth_dev_set_link_up(rpst->i40e_pf_eth_port_id); + pf = rpst->i40e_pf_eth; + (*rpst->i40e_pf_eth->dev_ops->link_update)(pf, 1); + } + + return ret; +} + +/* + * Set device link down. + */ +int +ipn3ke_rpst_dev_set_link_down(struct rte_eth_dev *dev) +{ + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(dev); + struct rte_eth_dev *pf; + int ret = 0; + + if (rpst->i40e_pf_eth) { + ret = rte_eth_dev_set_link_down(rpst->i40e_pf_eth_port_id); + pf = rpst->i40e_pf_eth; + (*rpst->i40e_pf_eth->dev_ops->link_update)(pf, 1); + } + + return ret; +} + +int +ipn3ke_rpst_link_update(struct rte_eth_dev *ethdev, + __rte_unused int wait_to_complete) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(ethdev); + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(ethdev); + struct rte_rawdev *rawdev; + struct rte_eth_link link; + struct rte_eth_dev *pf; + + memset(&link, 0, sizeof(link)); + + link.link_duplex = ETH_LINK_FULL_DUPLEX; + link.link_autoneg = !(ethdev->data->dev_conf.link_speeds & + ETH_LINK_SPEED_FIXED); + + rawdev = hw->rawdev; + ipn3ke_update_link(rawdev, rpst->port_id, &link); + + if (!rpst->ori_linfo.link_status && + link.link_status) { + IPN3KE_AFU_PMD_DEBUG("Update Rpst %d Up\n", rpst->port_id); + rpst->ori_linfo.link_status = link.link_status; + rpst->ori_linfo.link_speed = link.link_speed; + + rte_eth_linkstatus_set(ethdev, &link); + + if (rpst->i40e_pf_eth) { + IPN3KE_AFU_PMD_DEBUG("Update FVL PF %d Up\n", + rpst->i40e_pf_eth_port_id); + rte_eth_dev_set_link_up(rpst->i40e_pf_eth_port_id); + pf = rpst->i40e_pf_eth; + (*rpst->i40e_pf_eth->dev_ops->link_update)(pf, 1); + } + } else if (rpst->ori_linfo.link_status && + !link.link_status) { + IPN3KE_AFU_PMD_DEBUG("Update Rpst %d Down\n", + rpst->port_id); + rpst->ori_linfo.link_status = link.link_status; + rpst->ori_linfo.link_speed = link.link_speed; + + rte_eth_linkstatus_set(ethdev, &link); + + if (rpst->i40e_pf_eth) { + IPN3KE_AFU_PMD_DEBUG("Update FVL PF %d Down\n", + rpst->i40e_pf_eth_port_id); + rte_eth_dev_set_link_down(rpst->i40e_pf_eth_port_id); + pf = rpst->i40e_pf_eth; + (*rpst->i40e_pf_eth->dev_ops->link_update)(pf, 1); + } + } + + return 0; +} + +static int +ipn3ke_rpst_link_check(struct ipn3ke_rpst *rpst) +{ + struct ipn3ke_hw *hw; + struct rte_rawdev *rawdev; + struct rte_eth_link link; + struct rte_eth_dev *pf; + + if (rpst == NULL) + return -1; + + hw = rpst->hw; + + memset(&link, 0, sizeof(link)); + + link.link_duplex = ETH_LINK_FULL_DUPLEX; + link.link_autoneg = !(rpst->ethdev->data->dev_conf.link_speeds & + ETH_LINK_SPEED_FIXED); + + rawdev = hw->rawdev; + ipn3ke_update_link(rawdev, rpst->port_id, &link); + + if (!rpst->ori_linfo.link_status && + link.link_status) { + IPN3KE_AFU_PMD_DEBUG("Check Rpst %d Up\n", rpst->port_id); + rpst->ori_linfo.link_status = link.link_status; + rpst->ori_linfo.link_speed = link.link_speed; + + rte_eth_linkstatus_set(rpst->ethdev, &link); + + if (rpst->i40e_pf_eth) { + IPN3KE_AFU_PMD_DEBUG("Check FVL PF %d Up\n", + rpst->i40e_pf_eth_port_id); + rte_eth_dev_set_link_up(rpst->i40e_pf_eth_port_id); + pf = rpst->i40e_pf_eth; + (*rpst->i40e_pf_eth->dev_ops->link_update)(pf, 1); + } + } else if (rpst->ori_linfo.link_status && + !link.link_status) { + IPN3KE_AFU_PMD_DEBUG("Check Rpst %d Down\n", rpst->port_id); + rpst->ori_linfo.link_status = link.link_status; + rpst->ori_linfo.link_speed = link.link_speed; + + rte_eth_linkstatus_set(rpst->ethdev, &link); + + if (rpst->i40e_pf_eth) { + IPN3KE_AFU_PMD_DEBUG("Check FVL PF %d Down\n", + rpst->i40e_pf_eth_port_id); + rte_eth_dev_set_link_down(rpst->i40e_pf_eth_port_id); + pf = rpst->i40e_pf_eth; + (*rpst->i40e_pf_eth->dev_ops->link_update)(pf, 1); + } + } + + return 0; +} + +static void * +ipn3ke_rpst_scan_handle_request(__rte_unused void *param) +{ + struct ipn3ke_rpst *rpst; + int num = 0; +#define MS 1000 +#define SCAN_NUM 32 + + for (;;) { + num = 0; + TAILQ_FOREACH(rpst, &ipn3ke_rpst_list, next) { + if (rpst->i40e_pf_eth && + rpst->ethdev->data->dev_started && + rpst->i40e_pf_eth->data->dev_started) + ipn3ke_rpst_link_check(rpst); + + if (++num > SCAN_NUM) + rte_delay_us(1 * MS); + } + rte_delay_us(50 * MS); + + if (num == 0xffffff) + return NULL; + } + + return NULL; +} + +static int +ipn3ke_rpst_scan_check(void) +{ + int ret; + + if (ipn3ke_rpst_scan_num == 1) { + ret = pthread_create(&ipn3ke_rpst_scan_thread, + NULL, + ipn3ke_rpst_scan_handle_request, NULL); + if (ret) { + IPN3KE_AFU_PMD_ERR("Fail to create ipn3ke rpst scan thread"); + return -1; + } + } else if (ipn3ke_rpst_scan_num == 0) { + ret = pthread_cancel(ipn3ke_rpst_scan_thread); + if (ret) + IPN3KE_AFU_PMD_ERR("Can't cancel the thread"); + + ret = pthread_join(ipn3ke_rpst_scan_thread, NULL); + if (ret) + IPN3KE_AFU_PMD_ERR("Can't join the thread"); + + return ret; + } + + return 0; +} + +void +ipn3ke_rpst_promiscuous_enable(struct rte_eth_dev *ethdev) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(ethdev); + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(ethdev); + uint32_t rddata, val; + + if (hw->retimer.mac_type == IFPGA_RAWDEV_RETIMER_MAC_TYPE_10GE_XFI) { + /* Enable all unicast */ + (*hw->f_mac_read)(hw, + &rddata, + IPN3KE_MAC_RX_FRAME_CONTROL, + rpst->port_id, + 0); + val = 1; + val &= IPN3KE_MAC_RX_FRAME_CONTROL_EN_ALLUCAST_MASK; + val |= rddata; + (*hw->f_mac_write)(hw, + val, + IPN3KE_MAC_RX_FRAME_CONTROL, + rpst->port_id, + 0); + } +} + +void +ipn3ke_rpst_promiscuous_disable(struct rte_eth_dev *ethdev) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(ethdev); + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(ethdev); + uint32_t rddata, val; + + if (hw->retimer.mac_type == IFPGA_RAWDEV_RETIMER_MAC_TYPE_10GE_XFI) { + /* Disable all unicast */ + (*hw->f_mac_read)(hw, + &rddata, + IPN3KE_MAC_RX_FRAME_CONTROL, + rpst->port_id, + 0); + val = 0; + val &= IPN3KE_MAC_RX_FRAME_CONTROL_EN_ALLUCAST_MASK; + val |= rddata; + (*hw->f_mac_write)(hw, + val, + IPN3KE_MAC_RX_FRAME_CONTROL, + rpst->port_id, + 0); + } +} + +void +ipn3ke_rpst_allmulticast_enable(struct rte_eth_dev *ethdev) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(ethdev); + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(ethdev); + uint32_t rddata, val; + + if (hw->retimer.mac_type == IFPGA_RAWDEV_RETIMER_MAC_TYPE_10GE_XFI) { + /* Enable all unicast */ + (*hw->f_mac_read)(hw, + &rddata, + IPN3KE_MAC_RX_FRAME_CONTROL, + rpst->port_id, + 0); + val = 1; + val <<= IPN3KE_MAC_RX_FRAME_CONTROL_EN_ALLMCAST_SHIFT; + val &= IPN3KE_MAC_RX_FRAME_CONTROL_EN_ALLMCAST_MASK; + val |= rddata; + (*hw->f_mac_write)(hw, + val, + IPN3KE_MAC_RX_FRAME_CONTROL, + rpst->port_id, + 0); + } +} + +void +ipn3ke_rpst_allmulticast_disable(struct rte_eth_dev *ethdev) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(ethdev); + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(ethdev); + uint32_t rddata, val; + + if (hw->retimer.mac_type == IFPGA_RAWDEV_RETIMER_MAC_TYPE_10GE_XFI) { + /* Disable all unicast */ + (*hw->f_mac_read)(hw, + &rddata, + IPN3KE_MAC_RX_FRAME_CONTROL, + rpst->port_id, + 0); + val = 0; + val <<= IPN3KE_MAC_RX_FRAME_CONTROL_EN_ALLMCAST_SHIFT; + val &= IPN3KE_MAC_RX_FRAME_CONTROL_EN_ALLMCAST_MASK; + val |= rddata; + (*hw->f_mac_write)(hw, + val, + IPN3KE_MAC_RX_FRAME_CONTROL, + rpst->port_id, + 0); + } +} + +int +ipn3ke_rpst_mac_addr_set(struct rte_eth_dev *ethdev, + struct ether_addr *mac_addr) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(ethdev); + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(ethdev); + uint32_t val; + + if (!is_valid_assigned_ether_addr(mac_addr)) { + IPN3KE_AFU_PMD_ERR("Tried to set invalid MAC address."); + return -EINVAL; + } + + if (hw->retimer.mac_type == IFPGA_RAWDEV_RETIMER_MAC_TYPE_10GE_XFI) { + ether_addr_copy(&mac_addr[0], &rpst->mac_addr); + + /* Set mac address */ + rte_memcpy(((char *)(&val)), &mac_addr[0], sizeof(uint32_t)); + (*hw->f_mac_write)(hw, + val, + IPN3KE_MAC_PRIMARY_MAC_ADDR0, + rpst->port_id, + 0); + rte_memcpy(((char *)(&val)), &mac_addr[4], sizeof(uint16_t)); + (*hw->f_mac_write)(hw, + val, + IPN3KE_MAC_PRIMARY_MAC_ADDR0, + rpst->port_id, + 0); + } + + return 0; +} + +int +ipn3ke_rpst_mtu_set(struct rte_eth_dev *ethdev, uint16_t mtu) +{ + int ret = 0; + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(ethdev); + struct rte_eth_dev_data *dev_data = ethdev->data; + uint32_t frame_size = mtu + IPN3KE_ETH_OVERHEAD; + + /* check if mtu is within the allowed range */ + if (mtu < ETHER_MIN_MTU || + frame_size > IPN3KE_MAC_FRAME_SIZE_MAX) + return -EINVAL; + + /* mtu setting is forbidden if port is start */ + /* make sure NIC port is stopped */ + if (rpst->i40e_pf_eth && rpst->i40e_pf_eth->data->dev_started) { + IPN3KE_AFU_PMD_ERR("NIC port %d must " + "be stopped before configuration", + rpst->i40e_pf_eth->data->port_id); + return -EBUSY; + } + /* mtu setting is forbidden if port is start */ + if (dev_data->dev_started) { + IPN3KE_AFU_PMD_ERR("FPGA port %d must " + "be stopped before configuration", + dev_data->port_id); + return -EBUSY; + } + + if (frame_size > ETHER_MAX_LEN) + dev_data->dev_conf.rxmode.offloads |= + (uint64_t)(DEV_RX_OFFLOAD_JUMBO_FRAME); + else + dev_data->dev_conf.rxmode.offloads &= + (uint64_t)(~DEV_RX_OFFLOAD_JUMBO_FRAME); + + dev_data->dev_conf.rxmode.max_rx_pkt_len = frame_size; + + if (rpst->i40e_pf_eth) { + ret = rpst->i40e_pf_eth->dev_ops->mtu_set(rpst->i40e_pf_eth, + mtu); + if (!ret) + rpst->i40e_pf_eth->data->mtu = mtu; + } + + return ret; +} + +static int +ipn3ke_afu_filter_ctrl(struct rte_eth_dev *ethdev, + enum rte_filter_type filter_type, enum rte_filter_op filter_op, + void *arg) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(ethdev); + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(ethdev); + int ret = 0; + + if (ethdev == NULL) + return -EINVAL; + + if (hw->acc_flow) + switch (filter_type) { + case RTE_ETH_FILTER_GENERIC: + if (filter_op != RTE_ETH_FILTER_GET) + return -EINVAL; + *(const void **)arg = NULL; + break; + default: + IPN3KE_AFU_PMD_WARN("Filter type (%d) not supported", + filter_type); + ret = -EINVAL; + break; + } + else if (rpst->i40e_pf_eth) + (*rpst->i40e_pf_eth->dev_ops->filter_ctrl)(ethdev, + filter_type, + filter_op, + arg); + else + return -EINVAL; + + return ret; +} + +static const struct eth_dev_ops ipn3ke_rpst_dev_ops = { + .dev_infos_get = ipn3ke_rpst_dev_infos_get, + + .dev_configure = ipn3ke_rpst_dev_configure, + .dev_start = ipn3ke_rpst_dev_start, + .dev_stop = ipn3ke_rpst_dev_stop, + .dev_close = ipn3ke_rpst_dev_close, + .dev_reset = ipn3ke_rpst_dev_reset, + + .stats_get = ipn3ke_rpst_stats_get, + .xstats_get = ipn3ke_rpst_xstats_get, + .xstats_get_names = ipn3ke_rpst_xstats_get_names, + .stats_reset = ipn3ke_rpst_stats_reset, + .xstats_reset = ipn3ke_rpst_stats_reset, + + .filter_ctrl = ipn3ke_afu_filter_ctrl, + + .rx_queue_start = ipn3ke_rpst_rx_queue_start, + .rx_queue_stop = ipn3ke_rpst_rx_queue_stop, + .tx_queue_start = ipn3ke_rpst_tx_queue_start, + .tx_queue_stop = ipn3ke_rpst_tx_queue_stop, + .rx_queue_setup = ipn3ke_rpst_rx_queue_setup, + .rx_queue_release = ipn3ke_rpst_rx_queue_release, + .tx_queue_setup = ipn3ke_rpst_tx_queue_setup, + .tx_queue_release = ipn3ke_rpst_tx_queue_release, + + .dev_set_link_up = ipn3ke_rpst_dev_set_link_up, + .dev_set_link_down = ipn3ke_rpst_dev_set_link_down, + .link_update = ipn3ke_rpst_link_update, + + .promiscuous_enable = ipn3ke_rpst_promiscuous_enable, + .promiscuous_disable = ipn3ke_rpst_promiscuous_disable, + .allmulticast_enable = ipn3ke_rpst_allmulticast_enable, + .allmulticast_disable = ipn3ke_rpst_allmulticast_disable, + .mac_addr_set = ipn3ke_rpst_mac_addr_set, + .mtu_set = ipn3ke_rpst_mtu_set, +}; + +static uint16_t ipn3ke_rpst_recv_pkts(__rte_unused void *rx_q, + __rte_unused struct rte_mbuf **rx_pkts, __rte_unused uint16_t nb_pkts) +{ + return 0; +} + +static uint16_t +ipn3ke_rpst_xmit_pkts(__rte_unused void *tx_queue, + __rte_unused struct rte_mbuf **tx_pkts, __rte_unused uint16_t nb_pkts) +{ + return 0; +} + +int +ipn3ke_rpst_init(struct rte_eth_dev *ethdev, void *init_params) +{ + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(ethdev); + struct ipn3ke_rpst *representor_param = + (struct ipn3ke_rpst *)init_params; + + if (representor_param->port_id >= representor_param->hw->port_num) + return -ENODEV; + + rpst->ethdev = ethdev; + rpst->switch_domain_id = representor_param->switch_domain_id; + rpst->port_id = representor_param->port_id; + rpst->hw = representor_param->hw; + rpst->i40e_pf_eth = NULL; + rpst->i40e_pf_eth_port_id = 0xFFFF; + + ethdev->data->mac_addrs = rte_zmalloc("ipn3ke", ETHER_ADDR_LEN, 0); + if (!ethdev->data->mac_addrs) { + IPN3KE_AFU_PMD_ERR("Failed to " + "allocated memory for storing mac address"); + return -ENODEV; + } + + /* Set representor device ops */ + ethdev->dev_ops = &ipn3ke_rpst_dev_ops; + + /* No data-path, but need stub Rx/Tx functions to avoid crash + * when testing with the likes of testpmd. + */ + ethdev->rx_pkt_burst = ipn3ke_rpst_recv_pkts; + ethdev->tx_pkt_burst = ipn3ke_rpst_xmit_pkts; + + ethdev->data->nb_rx_queues = 1; + ethdev->data->nb_tx_queues = 1; + + ethdev->data->mac_addrs = rte_zmalloc("ipn3ke_afu_representor", + ETHER_ADDR_LEN, + 0); + if (!ethdev->data->mac_addrs) { + IPN3KE_AFU_PMD_ERR("Failed to " + "allocated memory for storing mac address"); + return -ENODEV; + } + + ethdev->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR; + + rte_spinlock_lock(&ipn3ke_link_notify_list_lk); + TAILQ_INSERT_TAIL(&ipn3ke_rpst_list, rpst, next); + ipn3ke_rpst_scan_num++; + ipn3ke_rpst_scan_check(); + rte_spinlock_unlock(&ipn3ke_link_notify_list_lk); + + return 0; +} + +int +ipn3ke_rpst_uninit(struct rte_eth_dev *ethdev) +{ + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(ethdev); + + rte_spinlock_lock(&ipn3ke_link_notify_list_lk); + TAILQ_REMOVE(&ipn3ke_rpst_list, rpst, next); + ipn3ke_rpst_scan_num--; + ipn3ke_rpst_scan_check(); + rte_spinlock_unlock(&ipn3ke_link_notify_list_lk); + + return 0; +} diff --git a/drivers/net/ipn3ke/meson.build b/drivers/net/ipn3ke/meson.build index b511600..ec77390 100644 --- a/drivers/net/ipn3ke/meson.build +++ b/drivers/net/ipn3ke/meson.build @@ -10,5 +10,6 @@ # allow_experimental_apis = true -sources += files('ipn3ke_ethdev.c') +sources += files('ipn3ke_ethdev.c', + 'ipn3ke_representor.c') deps += ['bus_ifpga', 'sched'] From patchwork Wed Apr 10 06:27:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52532 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 0CDE95F2A; Wed, 10 Apr 2019 08:27:16 +0200 (CEST) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by dpdk.org (Postfix) with ESMTP id 0D3CF5F20 for ; Wed, 10 Apr 2019 08:27:13 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 23:27:13 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,332,1549958400"; d="scan'208";a="147980899" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by FMSMGA003.fm.intel.com with ESMTP; 09 Apr 2019 23:27:07 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Wed, 10 Apr 2019 14:27:43 +0800 Message-Id: <1554877672-19745-6-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554877672-19745-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554877672-19745-1-git-send-email-rosen.xu@intel.com> Subject: [dpdk-dev] [PATCH v7 05/14] net/ipn3ke: add IPN3KE TM of PMD driver X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add Intel FPGA Acceleration NIC IPN3KE TM of PMD driver. Signed-off-by: Rosen Xu Signed-off-by: Andy Pei Signed-off-by: Dan Wei --- drivers/net/ipn3ke/Makefile | 1 + drivers/net/ipn3ke/ipn3ke_ethdev.c | 3 + drivers/net/ipn3ke/ipn3ke_ethdev.h | 7 + drivers/net/ipn3ke/ipn3ke_representor.c | 5 + drivers/net/ipn3ke/ipn3ke_tm.c | 2068 +++++++++++++++++++++++++++++++ drivers/net/ipn3ke/meson.build | 3 +- 6 files changed, 2086 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ipn3ke/ipn3ke_tm.c diff --git a/drivers/net/ipn3ke/Makefile b/drivers/net/ipn3ke/Makefile index 221567d..38d9384 100644 --- a/drivers/net/ipn3ke/Makefile +++ b/drivers/net/ipn3ke/Makefile @@ -34,5 +34,6 @@ LIBABIVER := 1 # SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_ethdev.c SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_representor.c +SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_tm.c include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/net/ipn3ke/ipn3ke_ethdev.c b/drivers/net/ipn3ke/ipn3ke_ethdev.c index 58c8ce4..508ea01 100644 --- a/drivers/net/ipn3ke/ipn3ke_ethdev.c +++ b/drivers/net/ipn3ke/ipn3ke_ethdev.c @@ -262,6 +262,9 @@ hw->flow_hw_enable = 0; if (afu_dev->id.uuid.uuid_low == IPN3KE_UUID_VBNG_LOW && afu_dev->id.uuid.uuid_high == IPN3KE_UUID_VBNG_HIGH) { + ret = ipn3ke_hw_tm_init(hw); + if (ret) + return ret; hw->tm_hw_enable = 1; hw->flow_hw_enable = 1; } diff --git a/drivers/net/ipn3ke/ipn3ke_ethdev.h b/drivers/net/ipn3ke/ipn3ke_ethdev.h index d2c73e5..36ff2f8 100644 --- a/drivers/net/ipn3ke/ipn3ke_ethdev.h +++ b/drivers/net/ipn3ke/ipn3ke_ethdev.h @@ -552,6 +552,13 @@ static inline void _ipn3ke_indrct_write(struct ipn3ke_hw *hw, ipn3ke_rpst_init(struct rte_eth_dev *ethdev, void *init_params); int ipn3ke_rpst_uninit(struct rte_eth_dev *ethdev); +int +ipn3ke_hw_tm_init(struct ipn3ke_hw *hw); +void +ipn3ke_tm_init(struct ipn3ke_rpst *rpst); +int +ipn3ke_tm_ops_get(struct rte_eth_dev *ethdev, + void *arg); /* IPN3KE_MASK is a macro used on 32 bit registers */ diff --git a/drivers/net/ipn3ke/ipn3ke_representor.c b/drivers/net/ipn3ke/ipn3ke_representor.c index 3831982..63098bf 100644 --- a/drivers/net/ipn3ke/ipn3ke_representor.c +++ b/drivers/net/ipn3ke/ipn3ke_representor.c @@ -801,6 +801,8 @@ .allmulticast_disable = ipn3ke_rpst_allmulticast_disable, .mac_addr_set = ipn3ke_rpst_mac_addr_set, .mtu_set = ipn3ke_rpst_mtu_set, + + .tm_ops_get = ipn3ke_tm_ops_get, }; static uint16_t ipn3ke_rpst_recv_pkts(__rte_unused void *rx_q, @@ -840,6 +842,9 @@ static uint16_t ipn3ke_rpst_recv_pkts(__rte_unused void *rx_q, return -ENODEV; } + if (rpst->hw->tm_hw_enable) + ipn3ke_tm_init(rpst); + /* Set representor device ops */ ethdev->dev_ops = &ipn3ke_rpst_dev_ops; diff --git a/drivers/net/ipn3ke/ipn3ke_tm.c b/drivers/net/ipn3ke/ipn3ke_tm.c new file mode 100644 index 0000000..4ca4c97 --- /dev/null +++ b/drivers/net/ipn3ke/ipn3ke_tm.c @@ -0,0 +1,2068 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ipn3ke_rawdev_api.h" +#include "ipn3ke_logs.h" +#include "ipn3ke_ethdev.h" + +#define BYTES_IN_MBPS (1000 * 1000 / 8) +#define SUBPORT_TC_PERIOD 10 +#define PIPE_TC_PERIOD 40 + +struct ipn3ke_tm_shaper_params_range_type { + uint32_t m1; + uint32_t m2; + uint32_t exp; + uint32_t exp2; + uint32_t low; + uint32_t high; +}; +struct ipn3ke_tm_shaper_params_range_type ipn3ke_tm_shaper_params_rang[] = { + { 0, 1, 0, 1, 0, 4}, + { 2, 3, 0, 1, 8, 12}, + { 4, 7, 0, 1, 16, 28}, + { 8, 15, 0, 1, 32, 60}, + { 16, 31, 0, 1, 64, 124}, + { 32, 63, 0, 1, 128, 252}, + { 64, 127, 0, 1, 256, 508}, + {128, 255, 0, 1, 512, 1020}, + {256, 511, 0, 1, 1024, 2044}, + {512, 1023, 0, 1, 2048, 4092}, + {512, 1023, 1, 2, 4096, 8184}, + {512, 1023, 2, 4, 8192, 16368}, + {512, 1023, 3, 8, 16384, 32736}, + {512, 1023, 4, 16, 32768, 65472}, + {512, 1023, 5, 32, 65536, 130944}, + {512, 1023, 6, 64, 131072, 261888}, + {512, 1023, 7, 128, 262144, 523776}, + {512, 1023, 8, 256, 524288, 1047552}, + {512, 1023, 9, 512, 1048576, 2095104}, + {512, 1023, 10, 1024, 2097152, 4190208}, + {512, 1023, 11, 2048, 4194304, 8380416}, + {512, 1023, 12, 4096, 8388608, 16760832}, + {512, 1023, 13, 8192, 16777216, 33521664}, + {512, 1023, 14, 16384, 33554432, 67043328}, + {512, 1023, 15, 32768, 67108864, 134086656}, +}; + +#define IPN3KE_TM_SHAPER_RANGE_NUM (sizeof(ipn3ke_tm_shaper_params_rang) / \ + sizeof(struct ipn3ke_tm_shaper_params_range_type)) + +#define IPN3KE_TM_SHAPER_COMMITTED_RATE_MAX \ + (ipn3ke_tm_shaper_params_rang[IPN3KE_TM_SHAPER_RANGE_NUM - 1].high) + +#define IPN3KE_TM_SHAPER_PEAK_RATE_MAX \ + (ipn3ke_tm_shaper_params_rang[IPN3KE_TM_SHAPER_RANGE_NUM - 1].high) + +int +ipn3ke_hw_tm_init(struct ipn3ke_hw *hw) +{ +#define SCRATCH_DATA 0xABCDEF + struct ipn3ke_tm_node *nodes; + struct ipn3ke_tm_tdrop_profile *tdrop_profile; + int node_num; + int i; + + if (hw == NULL) + return -EINVAL; +#if IPN3KE_TM_SCRATCH_RW + uint32_t scratch_data; + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_TM_SCRATCH, + 0, + SCRATCH_DATA, + 0xFFFFFFFF); + scratch_data = IPN3KE_MASK_READ_REG(hw, + IPN3KE_TM_SCRATCH, + 0, + 0xFFFFFFFF); + if (scratch_data != SCRATCH_DATA) + return -EINVAL; +#endif + /* alloc memory for all hierarchy nodes */ + node_num = hw->port_num + + IPN3KE_TM_VT_NODE_NUM + + IPN3KE_TM_COS_NODE_NUM; + + nodes = rte_zmalloc("ipn3ke_tm_nodes", + sizeof(struct ipn3ke_tm_node) * node_num, + 0); + if (!nodes) + return -ENOMEM; + + /* alloc memory for Tail Drop Profile */ + tdrop_profile = rte_zmalloc("ipn3ke_tm_tdrop_profile", + sizeof(struct ipn3ke_tm_tdrop_profile) * + IPN3KE_TM_TDROP_PROFILE_NUM, + 0); + if (!tdrop_profile) { + rte_free(nodes); + return -ENOMEM; + } + + hw->nodes = nodes; + hw->port_nodes = nodes; + hw->vt_nodes = hw->port_nodes + hw->port_num; + hw->cos_nodes = hw->vt_nodes + IPN3KE_TM_VT_NODE_NUM; + hw->tdrop_profile = tdrop_profile; + hw->tdrop_profile_num = IPN3KE_TM_TDROP_PROFILE_NUM; + + for (i = 0, nodes = hw->port_nodes; + i < hw->port_num; + i++, nodes++) { + nodes->node_index = i; + nodes->level = IPN3KE_TM_NODE_LEVEL_PORT; + nodes->tm_id = RTE_TM_NODE_ID_NULL; + nodes->node_state = IPN3KE_TM_NODE_STATE_IDLE; + nodes->parent_node_id = RTE_TM_NODE_ID_NULL; + nodes->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0; + nodes->weight = 0; + nodes->parent_node = NULL; + nodes->shaper_profile.valid = 0; + nodes->tdrop_profile = NULL; + nodes->n_children = 0; + TAILQ_INIT(&nodes->children_node_list); + } + + for (i = 0, nodes = hw->vt_nodes; + i < IPN3KE_TM_VT_NODE_NUM; + i++, nodes++) { + nodes->node_index = i; + nodes->level = IPN3KE_TM_NODE_LEVEL_VT; + nodes->tm_id = RTE_TM_NODE_ID_NULL; + nodes->node_state = IPN3KE_TM_NODE_STATE_IDLE; + nodes->parent_node_id = RTE_TM_NODE_ID_NULL; + nodes->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0; + nodes->weight = 0; + nodes->parent_node = NULL; + nodes->shaper_profile.valid = 0; + nodes->tdrop_profile = NULL; + nodes->n_children = 0; + TAILQ_INIT(&nodes->children_node_list); + } + + for (i = 0, nodes = hw->cos_nodes; + i < IPN3KE_TM_COS_NODE_NUM; + i++, nodes++) { + nodes->node_index = i; + nodes->level = IPN3KE_TM_NODE_LEVEL_COS; + nodes->tm_id = RTE_TM_NODE_ID_NULL; + nodes->node_state = IPN3KE_TM_NODE_STATE_IDLE; + nodes->parent_node_id = RTE_TM_NODE_ID_NULL; + nodes->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0; + nodes->weight = 0; + nodes->parent_node = NULL; + nodes->shaper_profile.valid = 0; + nodes->tdrop_profile = NULL; + nodes->n_children = 0; + TAILQ_INIT(&nodes->children_node_list); + } + + for (i = 0, tdrop_profile = hw->tdrop_profile; + i < IPN3KE_TM_TDROP_PROFILE_NUM; + i++, tdrop_profile++) { + tdrop_profile->tdrop_profile_id = i; + tdrop_profile->n_users = 0; + tdrop_profile->valid = 0; + } + + return 0; +} + +void +ipn3ke_tm_init(struct ipn3ke_rpst *rpst) +{ + struct ipn3ke_tm_internals *tm; + struct ipn3ke_tm_node *port_node; + + tm = &rpst->tm; + + port_node = &rpst->hw->port_nodes[rpst->port_id]; + tm->h.port_node = port_node; + + tm->h.n_shaper_profiles = 0; + tm->h.n_tdrop_profiles = 0; + tm->h.n_vt_nodes = 0; + tm->h.n_cos_nodes = 0; + + tm->h.port_commit_node = NULL; + TAILQ_INIT(&tm->h.vt_commit_node_list); + TAILQ_INIT(&tm->h.cos_commit_node_list); + + tm->hierarchy_frozen = 0; + tm->tm_started = 1; + tm->tm_id = rpst->port_id; +} + +static struct ipn3ke_tm_shaper_profile * +ipn3ke_hw_tm_shaper_profile_search(struct ipn3ke_hw *hw, + uint32_t shaper_profile_id, struct rte_tm_error *error) +{ + struct ipn3ke_tm_shaper_profile *sp = NULL; + uint32_t level_of_node_id; + uint32_t node_index; + + /* Shaper profile ID must not be NONE. */ + if (shaper_profile_id == RTE_TM_SHAPER_PROFILE_ID_NONE) { + rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID, + NULL, + rte_strerror(EINVAL)); + + return NULL; + } + + level_of_node_id = shaper_profile_id / IPN3KE_TM_NODE_LEVEL_MOD; + node_index = shaper_profile_id % IPN3KE_TM_NODE_LEVEL_MOD; + + switch (level_of_node_id) { + case IPN3KE_TM_NODE_LEVEL_PORT: + if (node_index >= hw->port_num) + rte_tm_error_set(error, + EEXIST, + RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID, + NULL, + rte_strerror(EEXIST)); + else + sp = &hw->port_nodes[node_index].shaper_profile; + + break; + + case IPN3KE_TM_NODE_LEVEL_VT: + if (node_index >= IPN3KE_TM_VT_NODE_NUM) + rte_tm_error_set(error, + EEXIST, + RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID, + NULL, + rte_strerror(EEXIST)); + else + sp = &hw->vt_nodes[node_index].shaper_profile; + + break; + + case IPN3KE_TM_NODE_LEVEL_COS: + if (node_index >= IPN3KE_TM_COS_NODE_NUM) + rte_tm_error_set(error, + EEXIST, + RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID, + NULL, + rte_strerror(EEXIST)); + else + sp = &hw->cos_nodes[node_index].shaper_profile; + + break; + default: + rte_tm_error_set(error, + EEXIST, + RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID, + NULL, + rte_strerror(EEXIST)); + } + + return sp; +} + +static struct ipn3ke_tm_tdrop_profile * +ipn3ke_hw_tm_tdrop_profile_search(struct ipn3ke_hw *hw, + uint32_t tdrop_profile_id) +{ + struct ipn3ke_tm_tdrop_profile *tdrop_profile; + + if (tdrop_profile_id >= hw->tdrop_profile_num) + return NULL; + + tdrop_profile = &hw->tdrop_profile[tdrop_profile_id]; + if (tdrop_profile->valid) + return tdrop_profile; + + return NULL; +} + +static struct ipn3ke_tm_node * +ipn3ke_hw_tm_node_search(struct ipn3ke_hw *hw, uint32_t tm_id, + uint32_t node_id, uint32_t state_mask) +{ + uint32_t level_of_node_id; + uint32_t node_index; + struct ipn3ke_tm_node *n; + + level_of_node_id = node_id / IPN3KE_TM_NODE_LEVEL_MOD; + node_index = node_id % IPN3KE_TM_NODE_LEVEL_MOD; + + switch (level_of_node_id) { + case IPN3KE_TM_NODE_LEVEL_PORT: + if (node_index >= hw->port_num) + return NULL; + n = &hw->port_nodes[node_index]; + + break; + case IPN3KE_TM_NODE_LEVEL_VT: + if (node_index >= IPN3KE_TM_VT_NODE_NUM) + return NULL; + n = &hw->vt_nodes[node_index]; + + break; + case IPN3KE_TM_NODE_LEVEL_COS: + if (node_index >= IPN3KE_TM_COS_NODE_NUM) + return NULL; + n = &hw->cos_nodes[node_index]; + + break; + default: + return NULL; + } + + /* Check tm node status */ + if (n->node_state == IPN3KE_TM_NODE_STATE_IDLE) { + if (n->tm_id != RTE_TM_NODE_ID_NULL || + n->parent_node_id != RTE_TM_NODE_ID_NULL || + n->parent_node != NULL || + n->n_children > 0) { + IPN3KE_AFU_PMD_ERR("tm node check error %d", 1); + } + } else if (n->node_state < IPN3KE_TM_NODE_STATE_MAX) { + if (n->tm_id == RTE_TM_NODE_ID_NULL || + (level_of_node_id != IPN3KE_TM_NODE_LEVEL_PORT && + n->parent_node_id == RTE_TM_NODE_ID_NULL) || + (level_of_node_id != IPN3KE_TM_NODE_LEVEL_PORT && + n->parent_node == NULL)) { + IPN3KE_AFU_PMD_ERR("tm node check error %d", 1); + } + } else { + IPN3KE_AFU_PMD_ERR("tm node check error %d", 1); + } + + if (IPN3KE_BIT_ISSET(state_mask, n->node_state)) { + if (n->node_state == IPN3KE_TM_NODE_STATE_IDLE) + return n; + else if (n->tm_id == tm_id) + return n; + else + return NULL; + } else { + return NULL; + } +} + +/* Traffic manager node type get */ +static int +ipn3ke_pmd_tm_node_type_get(struct rte_eth_dev *dev, + uint32_t node_id, int *is_leaf, struct rte_tm_error *error) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev); + uint32_t tm_id; + struct ipn3ke_tm_node *node; + uint32_t state_mask; + + if (is_leaf == NULL) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EINVAL)); + + tm_id = tm->tm_id; + + state_mask = 0; + IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED); + node = ipn3ke_hw_tm_node_search(hw, tm_id, node_id, state_mask); + if (node_id == RTE_TM_NODE_ID_NULL || + node == NULL) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + + *is_leaf = (node->level == IPN3KE_TM_NODE_LEVEL_COS) ? 1 : 0; + + return 0; +} + +#define WRED_SUPPORTED 0 + +#define STATS_MASK_DEFAULT \ + (RTE_TM_STATS_N_PKTS | \ + RTE_TM_STATS_N_BYTES | \ + RTE_TM_STATS_N_PKTS_GREEN_DROPPED | \ + RTE_TM_STATS_N_BYTES_GREEN_DROPPED) + +#define STATS_MASK_QUEUE \ + (STATS_MASK_DEFAULT | RTE_TM_STATS_N_PKTS_QUEUED) + +/* Traffic manager capabilities get */ +static int +ipn3ke_tm_capabilities_get(__rte_unused struct rte_eth_dev *dev, + struct rte_tm_capabilities *cap, struct rte_tm_error *error) +{ + if (cap == NULL) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_CAPABILITIES, + NULL, + rte_strerror(EINVAL)); + + /* set all the parameters to 0 first. */ + memset(cap, 0, sizeof(*cap)); + + cap->n_nodes_max = 1 + IPN3KE_TM_COS_NODE_NUM + IPN3KE_TM_VT_NODE_NUM; + cap->n_levels_max = IPN3KE_TM_NODE_LEVEL_MAX; + + cap->non_leaf_nodes_identical = 0; + cap->leaf_nodes_identical = 1; + + cap->shaper_n_max = 1 + IPN3KE_TM_VT_NODE_NUM; + cap->shaper_private_n_max = 1 + IPN3KE_TM_VT_NODE_NUM; + cap->shaper_private_dual_rate_n_max = 0; + cap->shaper_private_rate_min = 1; + cap->shaper_private_rate_max = 1 + IPN3KE_TM_VT_NODE_NUM; + + cap->shaper_shared_n_max = 0; + cap->shaper_shared_n_nodes_per_shaper_max = 0; + cap->shaper_shared_n_shapers_per_node_max = 0; + cap->shaper_shared_dual_rate_n_max = 0; + cap->shaper_shared_rate_min = 0; + cap->shaper_shared_rate_max = 0; + + cap->shaper_pkt_length_adjust_min = RTE_TM_ETH_FRAMING_OVERHEAD_FCS; + cap->shaper_pkt_length_adjust_max = RTE_TM_ETH_FRAMING_OVERHEAD_FCS; + + cap->sched_n_children_max = IPN3KE_TM_COS_NODE_NUM; + cap->sched_sp_n_priorities_max = 3; + cap->sched_wfq_n_children_per_group_max = UINT32_MAX; + cap->sched_wfq_n_groups_max = 1; + cap->sched_wfq_weight_max = UINT32_MAX; + + cap->cman_wred_packet_mode_supported = 0; + cap->cman_wred_byte_mode_supported = 0; + cap->cman_head_drop_supported = 0; + cap->cman_wred_context_n_max = 0; + cap->cman_wred_context_private_n_max = 0; + cap->cman_wred_context_shared_n_max = 0; + cap->cman_wred_context_shared_n_nodes_per_context_max = 0; + cap->cman_wred_context_shared_n_contexts_per_node_max = 0; + + /** + * cap->mark_vlan_dei_supported = {0, 0, 0}; + * cap->mark_ip_ecn_tcp_supported = {0, 0, 0}; + * cap->mark_ip_ecn_sctp_supported = {0, 0, 0}; + * cap->mark_ip_dscp_supported = {0, 0, 0}; + */ + + cap->dynamic_update_mask = 0; + + cap->stats_mask = 0; + + return 0; +} + +/* Traffic manager level capabilities get */ +static int +ipn3ke_tm_level_capabilities_get(struct rte_eth_dev *dev, + uint32_t level_id, struct rte_tm_level_capabilities *cap, + struct rte_tm_error *error) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + + if (cap == NULL) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_CAPABILITIES, + NULL, + rte_strerror(EINVAL)); + + if (level_id >= IPN3KE_TM_NODE_LEVEL_MAX) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_LEVEL_ID, + NULL, + rte_strerror(EINVAL)); + + /* set all the parameters to 0 first. */ + memset(cap, 0, sizeof(*cap)); + + switch (level_id) { + case IPN3KE_TM_NODE_LEVEL_PORT: + cap->n_nodes_max = hw->port_num; + cap->n_nodes_nonleaf_max = IPN3KE_TM_VT_NODE_NUM; + cap->n_nodes_leaf_max = 0; + cap->non_leaf_nodes_identical = 0; + cap->leaf_nodes_identical = 0; + + cap->nonleaf.shaper_private_supported = 0; + cap->nonleaf.shaper_private_dual_rate_supported = 0; + cap->nonleaf.shaper_private_rate_min = 1; + cap->nonleaf.shaper_private_rate_max = UINT32_MAX; + cap->nonleaf.shaper_shared_n_max = 0; + + cap->nonleaf.sched_n_children_max = IPN3KE_TM_VT_NODE_NUM; + cap->nonleaf.sched_sp_n_priorities_max = 1; + cap->nonleaf.sched_wfq_n_children_per_group_max = 0; + cap->nonleaf.sched_wfq_n_groups_max = 0; + cap->nonleaf.sched_wfq_weight_max = 0; + + cap->nonleaf.stats_mask = STATS_MASK_DEFAULT; + break; + + case IPN3KE_TM_NODE_LEVEL_VT: + cap->n_nodes_max = IPN3KE_TM_VT_NODE_NUM; + cap->n_nodes_nonleaf_max = IPN3KE_TM_COS_NODE_NUM; + cap->n_nodes_leaf_max = 0; + cap->non_leaf_nodes_identical = 0; + cap->leaf_nodes_identical = 0; + + cap->nonleaf.shaper_private_supported = 0; + cap->nonleaf.shaper_private_dual_rate_supported = 0; + cap->nonleaf.shaper_private_rate_min = 1; + cap->nonleaf.shaper_private_rate_max = UINT32_MAX; + cap->nonleaf.shaper_shared_n_max = 0; + + cap->nonleaf.sched_n_children_max = IPN3KE_TM_COS_NODE_NUM; + cap->nonleaf.sched_sp_n_priorities_max = 1; + cap->nonleaf.sched_wfq_n_children_per_group_max = 0; + cap->nonleaf.sched_wfq_n_groups_max = 0; + cap->nonleaf.sched_wfq_weight_max = 0; + + cap->nonleaf.stats_mask = STATS_MASK_DEFAULT; + break; + + case IPN3KE_TM_NODE_LEVEL_COS: + cap->n_nodes_max = IPN3KE_TM_COS_NODE_NUM; + cap->n_nodes_nonleaf_max = 0; + cap->n_nodes_leaf_max = IPN3KE_TM_COS_NODE_NUM; + cap->non_leaf_nodes_identical = 0; + cap->leaf_nodes_identical = 0; + + cap->leaf.shaper_private_supported = 0; + cap->leaf.shaper_private_dual_rate_supported = 0; + cap->leaf.shaper_private_rate_min = 0; + cap->leaf.shaper_private_rate_max = 0; + cap->leaf.shaper_shared_n_max = 0; + + cap->leaf.cman_head_drop_supported = 0; + cap->leaf.cman_wred_packet_mode_supported = WRED_SUPPORTED; + cap->leaf.cman_wred_byte_mode_supported = 0; + cap->leaf.cman_wred_context_private_supported = WRED_SUPPORTED; + cap->leaf.cman_wred_context_shared_n_max = 0; + + cap->leaf.stats_mask = STATS_MASK_QUEUE; + break; + + default: + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_LEVEL_ID, + NULL, + rte_strerror(EINVAL)); + break; + } + + return 0; +} + +/* Traffic manager node capabilities get */ +static int +ipn3ke_tm_node_capabilities_get(struct rte_eth_dev *dev, + uint32_t node_id, struct rte_tm_node_capabilities *cap, + struct rte_tm_error *error) +{ + struct ipn3ke_rpst *representor = IPN3KE_DEV_PRIVATE_TO_RPST(dev); + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev); + uint32_t tm_id; + struct ipn3ke_tm_node *tm_node; + uint32_t state_mask; + + if (cap == NULL) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_CAPABILITIES, + NULL, + rte_strerror(EINVAL)); + + tm_id = tm->tm_id; + + state_mask = 0; + IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED); + tm_node = ipn3ke_hw_tm_node_search(hw, tm_id, node_id, state_mask); + if (tm_node == NULL) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + + if (tm_node->tm_id != representor->port_id) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + + /* set all the parameters to 0 first. */ + memset(cap, 0, sizeof(*cap)); + + switch (tm_node->level) { + case IPN3KE_TM_NODE_LEVEL_PORT: + cap->shaper_private_supported = 1; + cap->shaper_private_dual_rate_supported = 0; + cap->shaper_private_rate_min = 1; + cap->shaper_private_rate_max = UINT32_MAX; + cap->shaper_shared_n_max = 0; + + cap->nonleaf.sched_n_children_max = IPN3KE_TM_VT_NODE_NUM; + cap->nonleaf.sched_sp_n_priorities_max = 1; + cap->nonleaf.sched_wfq_n_children_per_group_max = + IPN3KE_TM_VT_NODE_NUM; + cap->nonleaf.sched_wfq_n_groups_max = 1; + cap->nonleaf.sched_wfq_weight_max = 1; + + cap->stats_mask = STATS_MASK_DEFAULT; + break; + + case IPN3KE_TM_NODE_LEVEL_VT: + cap->shaper_private_supported = 1; + cap->shaper_private_dual_rate_supported = 0; + cap->shaper_private_rate_min = 1; + cap->shaper_private_rate_max = UINT32_MAX; + cap->shaper_shared_n_max = 0; + + cap->nonleaf.sched_n_children_max = IPN3KE_TM_COS_NODE_NUM; + cap->nonleaf.sched_sp_n_priorities_max = 1; + cap->nonleaf.sched_wfq_n_children_per_group_max = + IPN3KE_TM_COS_NODE_NUM; + cap->nonleaf.sched_wfq_n_groups_max = 1; + cap->nonleaf.sched_wfq_weight_max = 1; + + cap->stats_mask = STATS_MASK_DEFAULT; + break; + + case IPN3KE_TM_NODE_LEVEL_COS: + cap->shaper_private_supported = 0; + cap->shaper_private_dual_rate_supported = 0; + cap->shaper_private_rate_min = 0; + cap->shaper_private_rate_max = 0; + cap->shaper_shared_n_max = 0; + + cap->leaf.cman_head_drop_supported = 0; + cap->leaf.cman_wred_packet_mode_supported = WRED_SUPPORTED; + cap->leaf.cman_wred_byte_mode_supported = 0; + cap->leaf.cman_wred_context_private_supported = WRED_SUPPORTED; + cap->leaf.cman_wred_context_shared_n_max = 0; + + cap->stats_mask = STATS_MASK_QUEUE; + break; + default: + break; + } + + return 0; +} + +static int +ipn3ke_tm_shaper_parame_trans(struct rte_tm_shaper_params *profile, + struct ipn3ke_tm_shaper_profile *local_profile, + const struct ipn3ke_tm_shaper_params_range_type *ref_data) +{ + uint32_t i; + const struct ipn3ke_tm_shaper_params_range_type *r; + uint64_t rate; + + rate = profile->peak.rate; + for (i = 0, r = ref_data; i < IPN3KE_TM_SHAPER_RANGE_NUM; i++, r++) { + if (rate >= r->low && + rate <= r->high) { + local_profile->m = (rate / 4) / r->exp2; + local_profile->e = r->exp; + local_profile->rate = rate; + + return 0; + } + } + + return -1; +} + +static int +ipn3ke_tm_shaper_profile_add(struct rte_eth_dev *dev, + uint32_t shaper_profile_id, struct rte_tm_shaper_params *profile, + struct rte_tm_error *error) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev); + struct ipn3ke_tm_shaper_profile *sp; + + /* Shaper profile must not exist. */ + sp = ipn3ke_hw_tm_shaper_profile_search(hw, shaper_profile_id, error); + if (!sp || (sp && sp->valid)) + return -rte_tm_error_set(error, + EEXIST, + RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID, + NULL, + rte_strerror(EEXIST)); + + /* Profile must not be NULL. */ + if (profile == NULL) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_SHAPER_PROFILE, + NULL, + rte_strerror(EINVAL)); + + /* Peak rate: non-zero, 32-bit */ + if (profile->peak.rate == 0 || + profile->peak.rate > IPN3KE_TM_SHAPER_PEAK_RATE_MAX) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE, + NULL, + rte_strerror(EINVAL)); + + /* Peak size: non-zero, 32-bit */ + if (profile->peak.size != 0) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE, + NULL, + rte_strerror(EINVAL)); + + /* Dual-rate profiles are not supported. */ + if (profile->committed.rate > IPN3KE_TM_SHAPER_COMMITTED_RATE_MAX) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE, + NULL, + rte_strerror(EINVAL)); + + /* Packet length adjust: 24 bytes */ + if (profile->pkt_length_adjust != 0) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN, + NULL, + rte_strerror(EINVAL)); + + if (ipn3ke_tm_shaper_parame_trans(profile, + sp, + ipn3ke_tm_shaper_params_rang)) { + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE, + NULL, + rte_strerror(EINVAL)); + } else { + sp->valid = 1; + rte_memcpy(&sp->params, profile, sizeof(sp->params)); + } + + tm->h.n_shaper_profiles++; + + return 0; +} + +/* Traffic manager shaper profile delete */ +static int +ipn3ke_tm_shaper_profile_delete(struct rte_eth_dev *dev, + uint32_t shaper_profile_id, struct rte_tm_error *error) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev); + struct ipn3ke_tm_shaper_profile *sp; + + /* Check existing */ + sp = ipn3ke_hw_tm_shaper_profile_search(hw, shaper_profile_id, error); + if (!sp || (sp && !sp->valid)) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID, + NULL, + rte_strerror(EINVAL)); + + sp->valid = 0; + tm->h.n_shaper_profiles--; + + return 0; +} + +static int +ipn3ke_tm_tdrop_profile_check(__rte_unused struct rte_eth_dev *dev, + uint32_t tdrop_profile_id, struct rte_tm_wred_params *profile, + struct rte_tm_error *error) +{ + enum rte_tm_color color; + + /* TDROP profile ID must not be NONE. */ + if (tdrop_profile_id == RTE_TM_WRED_PROFILE_ID_NONE) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_WRED_PROFILE_ID, + NULL, + rte_strerror(EINVAL)); + + /* Profile must not be NULL. */ + if (profile == NULL) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_WRED_PROFILE, + NULL, + rte_strerror(EINVAL)); + + /* TDROP profile should be in packet mode */ + if (profile->packet_mode != 0) + return -rte_tm_error_set(error, + ENOTSUP, + RTE_TM_ERROR_TYPE_WRED_PROFILE, + NULL, + rte_strerror(ENOTSUP)); + + /* min_th <= max_th, max_th > 0 */ + for (color = RTE_TM_GREEN; color <= RTE_TM_GREEN; color++) { + uint64_t min_th = profile->red_params[color].min_th; + uint64_t max_th = profile->red_params[color].max_th; + + if (((min_th >> IPN3KE_TDROP_TH1_SHIFT) >> + IPN3KE_TDROP_TH1_SHIFT) || + max_th != 0) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_WRED_PROFILE, + NULL, + rte_strerror(EINVAL)); + } + + return 0; +} + +static int +ipn3ke_hw_tm_tdrop_wr(struct ipn3ke_hw *hw, + struct ipn3ke_tm_tdrop_profile *tp) +{ + if (tp->valid) { + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CCB_PROFILE_MS, + 0, + tp->th2, + IPN3KE_CCB_PROFILE_MS_MASK); + + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CCB_PROFILE_P, + tp->tdrop_profile_id, + tp->th1, + IPN3KE_CCB_PROFILE_MASK); + } else { + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CCB_PROFILE_MS, + 0, + 0, + IPN3KE_CCB_PROFILE_MS_MASK); + + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CCB_PROFILE_P, + tp->tdrop_profile_id, + 0, + IPN3KE_CCB_PROFILE_MASK); + } + + return 0; +} + +/* Traffic manager TDROP profile add */ +static int +ipn3ke_tm_tdrop_profile_add(struct rte_eth_dev *dev, + uint32_t tdrop_profile_id, struct rte_tm_wred_params *profile, + struct rte_tm_error *error) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev); + struct ipn3ke_tm_tdrop_profile *tp; + int status; + uint64_t min_th; + uint32_t th1, th2; + + /* Check input params */ + status = ipn3ke_tm_tdrop_profile_check(dev, + tdrop_profile_id, + profile, + error); + if (status) + return status; + + /* Memory allocation */ + tp = &hw->tdrop_profile[tdrop_profile_id]; + + /* Fill in */ + tp->valid = 1; + min_th = profile->red_params[RTE_TM_GREEN].min_th; + th1 = (uint32_t)(min_th & IPN3KE_TDROP_TH1_MASK); + th2 = (uint32_t)((min_th >> IPN3KE_TDROP_TH1_SHIFT) & + IPN3KE_TDROP_TH2_MASK); + tp->th1 = th1; + tp->th2 = th2; + rte_memcpy(&tp->params, profile, sizeof(tp->params)); + + /* Add to list */ + tm->h.n_tdrop_profiles++; + + /* Write FPGA */ + ipn3ke_hw_tm_tdrop_wr(hw, tp); + + return 0; +} + +/* Traffic manager TDROP profile delete */ +static int +ipn3ke_tm_tdrop_profile_delete(struct rte_eth_dev *dev, + uint32_t tdrop_profile_id, struct rte_tm_error *error) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev); + struct ipn3ke_tm_tdrop_profile *tp; + + /* Check existing */ + tp = ipn3ke_hw_tm_tdrop_profile_search(hw, tdrop_profile_id); + if (tp == NULL) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_WRED_PROFILE_ID, + NULL, + rte_strerror(EINVAL)); + + /* Check unused */ + if (tp->n_users) + return -rte_tm_error_set(error, + EBUSY, + RTE_TM_ERROR_TYPE_WRED_PROFILE_ID, + NULL, + rte_strerror(EBUSY)); + + /* Set free */ + tp->valid = 0; + tm->h.n_tdrop_profiles--; + + /* Write FPGA */ + ipn3ke_hw_tm_tdrop_wr(hw, tp); + + return 0; +} + +static int +ipn3ke_tm_node_add_check_parameter(uint32_t tm_id, + uint32_t node_id, uint32_t parent_node_id, uint32_t priority, + uint32_t weight, uint32_t level_id, struct rte_tm_node_params *params, + struct rte_tm_error *error) +{ + uint32_t level_of_node_id; + uint32_t node_index; + uint32_t parent_level_id; + + if (node_id == RTE_TM_NODE_ID_NULL) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + + /* priority: must be 0, 1, 2, 3 */ + if (priority > IPN3KE_TM_NODE_PRIORITY_HIGHEST) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_PRIORITY, + NULL, + rte_strerror(EINVAL)); + + /* weight: must be 1 .. 255 */ + if (weight > IPN3KE_TM_NODE_WEIGHT_MAX) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_WEIGHT, + NULL, + rte_strerror(EINVAL)); + + /* check node id and parent id*/ + level_of_node_id = node_id / IPN3KE_TM_NODE_LEVEL_MOD; + if (level_of_node_id != level_id) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + node_index = node_id % IPN3KE_TM_NODE_LEVEL_MOD; + parent_level_id = parent_node_id / IPN3KE_TM_NODE_LEVEL_MOD; + switch (level_id) { + case IPN3KE_TM_NODE_LEVEL_PORT: + if (node_index != tm_id) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + if (parent_node_id != RTE_TM_NODE_ID_NULL) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID, + NULL, + rte_strerror(EINVAL)); + break; + + case IPN3KE_TM_NODE_LEVEL_VT: + if (node_index >= IPN3KE_TM_VT_NODE_NUM) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + if (parent_level_id != IPN3KE_TM_NODE_LEVEL_PORT) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID, + NULL, + rte_strerror(EINVAL)); + break; + + case IPN3KE_TM_NODE_LEVEL_COS: + if (node_index >= IPN3KE_TM_COS_NODE_NUM) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + if (parent_level_id != IPN3KE_TM_NODE_LEVEL_VT) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID, + NULL, + rte_strerror(EINVAL)); + break; + default: + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_LEVEL_ID, + NULL, + rte_strerror(EINVAL)); + } + + /* params: must not be NULL */ + if (params == NULL) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_PARAMS, + NULL, + rte_strerror(EINVAL)); + /* No shared shapers */ + if (params->n_shared_shapers != 0) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS, + NULL, + rte_strerror(EINVAL)); + return 0; +} + +static int +ipn3ke_tm_node_add_check_mount(uint32_t tm_id, + uint32_t node_id, uint32_t parent_node_id, uint32_t level_id, + struct rte_tm_error *error) +{ + /*struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev);*/ + uint32_t node_index; + uint32_t parent_index; + uint32_t parent_index1; + + node_index = node_id % IPN3KE_TM_NODE_LEVEL_MOD; + parent_index = parent_node_id % IPN3KE_TM_NODE_LEVEL_MOD; + parent_index1 = node_index / IPN3KE_TM_NODE_MOUNT_MAX; + switch (level_id) { + case IPN3KE_TM_NODE_LEVEL_PORT: + break; + + case IPN3KE_TM_NODE_LEVEL_VT: + if (parent_index != tm_id) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID, + NULL, + rte_strerror(EINVAL)); + break; + + case IPN3KE_TM_NODE_LEVEL_COS: + if (parent_index != parent_index1) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID, + NULL, + rte_strerror(EINVAL)); + break; + default: + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_LEVEL_ID, + NULL, + rte_strerror(EINVAL)); + } + + return 0; +} + +/* Traffic manager node add */ +static int +ipn3ke_tm_node_add(struct rte_eth_dev *dev, + uint32_t node_id, uint32_t parent_node_id, uint32_t priority, + uint32_t weight, uint32_t level_id, struct rte_tm_node_params *params, + struct rte_tm_error *error) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev); + uint32_t tm_id; + struct ipn3ke_tm_node *n, *parent_node; + uint32_t node_state, state_mask; + int status; + + /* Checks */ + if (tm->hierarchy_frozen) + return -rte_tm_error_set(error, + EBUSY, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EBUSY)); + + tm_id = tm->tm_id; + + status = ipn3ke_tm_node_add_check_parameter(tm_id, + node_id, + parent_node_id, + priority, + weight, + level_id, + params, + error); + if (status) + return status; + + status = ipn3ke_tm_node_add_check_mount(tm_id, + node_id, + parent_node_id, + level_id, + error); + if (status) + return status; + + /* Shaper profile ID must not be NONE. */ + if (params->shaper_profile_id != RTE_TM_SHAPER_PROFILE_ID_NONE && + params->shaper_profile_id != node_id) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID, + NULL, + rte_strerror(EINVAL)); + + /* Memory allocation */ + state_mask = 0; + IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_IDLE); + IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_CONFIGURED_DEL); + n = ipn3ke_hw_tm_node_search(hw, tm_id, node_id, state_mask); + if (!n) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EINVAL)); + node_state = n->node_state; + + /* Check parent node */ + state_mask = 0; + IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_CONFIGURED_ADD); + IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED); + if (parent_node_id != RTE_TM_NODE_ID_NULL) { + parent_node = ipn3ke_hw_tm_node_search(hw, + tm_id, + parent_node_id, + state_mask); + if (!parent_node) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID, + NULL, + rte_strerror(EINVAL)); + } else { + parent_node = NULL; + } + + switch (level_id) { + case IPN3KE_TM_NODE_LEVEL_PORT: + n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_ADD; + n->tm_id = tm_id; + tm->h.port_commit_node = n; + break; + + case IPN3KE_TM_NODE_LEVEL_VT: + if (node_state == IPN3KE_TM_NODE_STATE_IDLE) { + TAILQ_INSERT_TAIL(&tm->h.vt_commit_node_list, n, node); + if (parent_node) + parent_node->n_children++; + tm->h.n_vt_nodes++; + } else if (node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) { + if (parent_node) + parent_node->n_children++; + tm->h.n_vt_nodes++; + } + n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_ADD; + n->parent_node_id = parent_node_id; + n->tm_id = tm_id; + n->parent_node = parent_node; + + break; + + case IPN3KE_TM_NODE_LEVEL_COS: + if (node_state == IPN3KE_TM_NODE_STATE_IDLE) { + TAILQ_INSERT_TAIL(&tm->h.cos_commit_node_list, + n, node); + if (parent_node) + parent_node->n_children++; + tm->h.n_cos_nodes++; + } else if (node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) { + if (parent_node) + parent_node->n_children++; + tm->h.n_cos_nodes++; + } + n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_ADD; + n->parent_node_id = parent_node_id; + n->tm_id = tm_id; + n->parent_node = parent_node; + + break; + default: + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_LEVEL_ID, + NULL, + rte_strerror(EINVAL)); + } + + /* Fill in */ + n->priority = priority; + n->weight = weight; + + if (n->level == IPN3KE_TM_NODE_LEVEL_COS && + params->leaf.cman == RTE_TM_CMAN_TAIL_DROP) + n->tdrop_profile = ipn3ke_hw_tm_tdrop_profile_search(hw, + params->leaf.wred.wred_profile_id); + + rte_memcpy(&n->params, params, sizeof(n->params)); + + return 0; +} + +static int +ipn3ke_tm_node_del_check_parameter(uint32_t tm_id, + uint32_t node_id, struct rte_tm_error *error) +{ + uint32_t level_of_node_id; + uint32_t node_index; + + if (node_id == RTE_TM_NODE_ID_NULL) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + + /* check node id and parent id*/ + level_of_node_id = node_id / IPN3KE_TM_NODE_LEVEL_MOD; + node_index = node_id % IPN3KE_TM_NODE_LEVEL_MOD; + switch (level_of_node_id) { + case IPN3KE_TM_NODE_LEVEL_PORT: + if (node_index != tm_id) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + break; + + case IPN3KE_TM_NODE_LEVEL_VT: + if (node_index >= IPN3KE_TM_VT_NODE_NUM) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + break; + + case IPN3KE_TM_NODE_LEVEL_COS: + if (node_index >= IPN3KE_TM_COS_NODE_NUM) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + break; + default: + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_LEVEL_ID, + NULL, + rte_strerror(EINVAL)); + } + + return 0; +} + +/* Traffic manager node delete */ +static int +ipn3ke_pmd_tm_node_delete(struct rte_eth_dev *dev, + uint32_t node_id, struct rte_tm_error *error) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev); + struct ipn3ke_tm_node *n, *parent_node; + uint32_t tm_id; + int status; + uint32_t level_of_node_id; + uint32_t node_state; + uint32_t state_mask; + + /* Check hierarchy changes are currently allowed */ + if (tm->hierarchy_frozen) + return -rte_tm_error_set(error, + EBUSY, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EBUSY)); + + tm_id = tm->tm_id; + + status = ipn3ke_tm_node_del_check_parameter(tm_id, + node_id, + error); + if (status) + return status; + + /* Check existing */ + state_mask = 0; + IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_CONFIGURED_ADD); + IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED); + n = ipn3ke_hw_tm_node_search(hw, tm_id, node_id, state_mask); + if (n == NULL) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + + if (n->n_children > 0) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + + node_state = n->node_state; + + level_of_node_id = node_id / IPN3KE_TM_NODE_LEVEL_MOD; + + /* Check parent node */ + if (n->parent_node_id != RTE_TM_NODE_ID_NULL) { + state_mask = 0; + IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_CONFIGURED_ADD); + IPN3KE_BIT_SET(state_mask, IPN3KE_TM_NODE_STATE_COMMITTED); + parent_node = ipn3ke_hw_tm_node_search(hw, + tm_id, + n->parent_node_id, + state_mask); + if (!parent_node) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID, + NULL, + rte_strerror(EINVAL)); + if (n->parent_node != parent_node) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + } else { + parent_node = NULL; + } + + switch (level_of_node_id) { + case IPN3KE_TM_NODE_LEVEL_PORT: + if (tm->h.port_node != n) + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_NODE_ID, + NULL, + rte_strerror(EINVAL)); + n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_DEL; + tm->h.port_commit_node = n; + + break; + + case IPN3KE_TM_NODE_LEVEL_VT: + if (node_state == IPN3KE_TM_NODE_STATE_COMMITTED) { + if (parent_node) + TAILQ_REMOVE(&parent_node->children_node_list, + n, node); + TAILQ_INSERT_TAIL(&tm->h.vt_commit_node_list, n, node); + if (parent_node) + parent_node->n_children--; + tm->h.n_vt_nodes--; + } else if (node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) { + if (parent_node) + parent_node->n_children--; + tm->h.n_vt_nodes--; + } + n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_DEL; + + break; + + case IPN3KE_TM_NODE_LEVEL_COS: + if (node_state == IPN3KE_TM_NODE_STATE_COMMITTED) { + if (parent_node) + TAILQ_REMOVE(&parent_node->children_node_list, + n, node); + TAILQ_INSERT_TAIL(&tm->h.cos_commit_node_list, + n, node); + if (parent_node) + parent_node->n_children--; + tm->h.n_cos_nodes--; + } else if (node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) { + if (parent_node) + parent_node->n_children--; + tm->h.n_cos_nodes--; + } + n->node_state = IPN3KE_TM_NODE_STATE_CONFIGURED_DEL; + + break; + default: + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_LEVEL_ID, + NULL, + rte_strerror(EINVAL)); + } + + return 0; +} + +static int +ipn3ke_tm_hierarchy_commit_check(struct rte_eth_dev *dev, + struct rte_tm_error *error) +{ + struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev); + uint32_t tm_id; + struct ipn3ke_tm_node_list *nl; + struct ipn3ke_tm_node *n, *parent_node; + + tm_id = tm->tm_id; + + nl = &tm->h.cos_commit_node_list; + TAILQ_FOREACH(n, nl, node) { + parent_node = n->parent_node; + if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) { + if (n->parent_node_id == RTE_TM_NODE_ID_NULL || + n->level != IPN3KE_TM_NODE_LEVEL_COS || + n->tm_id != tm_id || + parent_node == NULL || + (parent_node && + parent_node->node_state == + IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) || + (parent_node && + parent_node->node_state == + IPN3KE_TM_NODE_STATE_IDLE) || + n->shaper_profile.valid == 0) { + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EINVAL)); + } + } else if (n->node_state == + IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) { + if (n->level != IPN3KE_TM_NODE_LEVEL_COS || + n->n_children != 0) { + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EINVAL)); + } else { + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EINVAL)); + } + } + } + + nl = &tm->h.vt_commit_node_list; + TAILQ_FOREACH(n, nl, node) { + parent_node = n->parent_node; + if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) { + if (n->parent_node_id == RTE_TM_NODE_ID_NULL || + n->level != IPN3KE_TM_NODE_LEVEL_VT || + n->tm_id != tm_id || + parent_node == NULL || + (parent_node && + parent_node->node_state == + IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) || + (parent_node && + parent_node->node_state == + IPN3KE_TM_NODE_STATE_IDLE) || + n->shaper_profile.valid == 0) { + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EINVAL)); + } + } else if (n->node_state == + IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) { + if (n->level != IPN3KE_TM_NODE_LEVEL_VT || + n->n_children != 0) { + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EINVAL)); + } else { + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EINVAL)); + } + } + } + + n = tm->h.port_commit_node; + if (n && + (n->parent_node_id != RTE_TM_NODE_ID_NULL || + n->level != IPN3KE_TM_NODE_LEVEL_PORT || + n->tm_id != tm_id || + n->parent_node != NULL || + n->shaper_profile.valid == 0)) { + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EINVAL)); + } + + return 0; +} + +static int +ipn3ke_hw_tm_node_wr(struct ipn3ke_hw *hw, + struct ipn3ke_tm_node *n) +{ + uint32_t level; + + level = n->level; + + switch (level) { + case IPN3KE_TM_NODE_LEVEL_PORT: + /** + * Configure Type + */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_QOS_TYPE_L3_X, + n->node_index, + n->priority, + IPN3KE_QOS_TYPE_MASK); + + /** + * Configure Sch_wt + */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_QOS_SCH_WT_L3_X, + n->node_index, + n->weight, + IPN3KE_QOS_SCH_WT_MASK); + + /** + * Configure Shap_wt + */ + if (n->shaper_profile.valid) + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_QOS_SHAP_WT_L3_X, + n->node_index, + ((n->shaper_profile.e << 10) | + n->shaper_profile.m), + IPN3KE_QOS_SHAP_WT_MASK); + + break; + case IPN3KE_TM_NODE_LEVEL_VT: + /** + * Configure Type + */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_QOS_TYPE_L2_X, + n->node_index, + n->priority, + IPN3KE_QOS_TYPE_MASK); + + /** + * Configure Sch_wt + */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_QOS_SCH_WT_L2_X, + n->node_index, + n->weight, + IPN3KE_QOS_SCH_WT_MASK); + + /** + * Configure Shap_wt + */ + if (n->shaper_profile.valid) + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_QOS_SHAP_WT_L2_X, + n->node_index, + ((n->shaper_profile.e << 10) | + n->shaper_profile.m), + IPN3KE_QOS_SHAP_WT_MASK); + + /** + * Configure Map + */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_QOS_MAP_L2_X, + n->node_index, + n->parent_node->node_index, + IPN3KE_QOS_MAP_L2_MASK); + + break; + case IPN3KE_TM_NODE_LEVEL_COS: + /** + * Configure Tail Drop mapping + */ + if (n->tdrop_profile && n->tdrop_profile->valid) { + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CCB_QPROFILE_Q, + n->node_index, + n->tdrop_profile->tdrop_profile_id, + IPN3KE_CCB_QPROFILE_MASK); + } + + /** + * Configure Type + */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_QOS_TYPE_L1_X, + n->node_index, + n->priority, + IPN3KE_QOS_TYPE_MASK); + + /** + * Configure Sch_wt + */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_QOS_SCH_WT_L1_X, + n->node_index, + n->weight, + IPN3KE_QOS_SCH_WT_MASK); + + /** + * Configure Shap_wt + */ + if (n->shaper_profile.valid) + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_QOS_SHAP_WT_L1_X, + n->node_index, + ((n->shaper_profile.e << 10) | + n->shaper_profile.m), + IPN3KE_QOS_SHAP_WT_MASK); + + /** + * Configure COS queue to port + */ + while (IPN3KE_MASK_READ_REG(hw, + IPN3KE_QM_UID_CONFIG_CTRL, + 0, + 0x80000000)) + ; + + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_QM_UID_CONFIG_DATA, + 0, + (1 << 8 | n->parent_node->parent_node->node_index), + 0x1FF); + + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_QM_UID_CONFIG_CTRL, + 0, + n->node_index, + 0xFFFFF); + + while (IPN3KE_MASK_READ_REG(hw, + IPN3KE_QM_UID_CONFIG_CTRL, + 0, + 0x80000000)) + ; + + /** + * Configure Map + */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_QOS_MAP_L1_X, + n->node_index, + n->parent_node->node_index, + IPN3KE_QOS_MAP_L1_MASK); + + break; + default: + return -1; + } + + return 0; +} + +static int +ipn3ke_tm_hierarchy_hw_commit(struct rte_eth_dev *dev, + struct rte_tm_error *error) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev); + struct ipn3ke_tm_node_list *nl; + struct ipn3ke_tm_node *n, *nn, *parent_node; + + n = tm->h.port_commit_node; + if (n) { + if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) { + tm->h.port_commit_node = NULL; + + n->node_state = IPN3KE_TM_NODE_STATE_COMMITTED; + } else if (n->node_state == + IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) { + tm->h.port_commit_node = NULL; + + n->node_state = IPN3KE_TM_NODE_STATE_IDLE; + n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0; + n->weight = 0; + n->tm_id = RTE_TM_NODE_ID_NULL; + } else { + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EINVAL)); + } + ipn3ke_hw_tm_node_wr(hw, n); + } + + nl = &tm->h.vt_commit_node_list; + for (n = TAILQ_FIRST(nl); n != NULL; n = nn) { + nn = TAILQ_NEXT(n, node); + if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) { + n->node_state = IPN3KE_TM_NODE_STATE_COMMITTED; + parent_node = n->parent_node; + TAILQ_REMOVE(nl, n, node); + TAILQ_INSERT_TAIL(&parent_node->children_node_list, + n, node); + } else if (n->node_state == + IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) { + parent_node = n->parent_node; + TAILQ_REMOVE(nl, n, node); + + n->node_state = IPN3KE_TM_NODE_STATE_IDLE; + n->parent_node_id = RTE_TM_NODE_ID_NULL; + n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0; + n->weight = 0; + n->tm_id = RTE_TM_NODE_ID_NULL; + n->parent_node = NULL; + } else { + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EINVAL)); + } + ipn3ke_hw_tm_node_wr(hw, n); + } + + nl = &tm->h.cos_commit_node_list; + for (n = TAILQ_FIRST(nl); n != NULL; n = nn) { + nn = TAILQ_NEXT(n, node); + if (n->node_state == IPN3KE_TM_NODE_STATE_CONFIGURED_ADD) { + n->node_state = IPN3KE_TM_NODE_STATE_COMMITTED; + parent_node = n->parent_node; + TAILQ_REMOVE(nl, n, node); + TAILQ_INSERT_TAIL(&parent_node->children_node_list, + n, node); + } else if (n->node_state == + IPN3KE_TM_NODE_STATE_CONFIGURED_DEL) { + n->node_state = IPN3KE_TM_NODE_STATE_IDLE; + parent_node = n->parent_node; + TAILQ_REMOVE(nl, n, node); + + n->node_state = IPN3KE_TM_NODE_STATE_IDLE; + n->parent_node_id = RTE_TM_NODE_ID_NULL; + n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0; + n->weight = 0; + n->tm_id = RTE_TM_NODE_ID_NULL; + n->parent_node = NULL; + + if (n->tdrop_profile) + n->tdrop_profile->n_users--; + } else { + return -rte_tm_error_set(error, + EINVAL, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EINVAL)); + } + ipn3ke_hw_tm_node_wr(hw, n); + } + + return 0; +} + +static int +ipn3ke_tm_hierarchy_commit_clear(struct rte_eth_dev *dev) +{ + struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev); + struct ipn3ke_tm_node_list *nl; + struct ipn3ke_tm_node *n; + struct ipn3ke_tm_node *nn; + + n = tm->h.port_commit_node; + if (n) { + n->node_state = IPN3KE_TM_NODE_STATE_IDLE; + n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0; + n->weight = 0; + n->tm_id = RTE_TM_NODE_ID_NULL; + n->n_children = 0; + + tm->h.port_commit_node = NULL; + } + + nl = &tm->h.vt_commit_node_list; + for (n = TAILQ_FIRST(nl); n != NULL; n = nn) { + nn = TAILQ_NEXT(n, node); + + n->node_state = IPN3KE_TM_NODE_STATE_IDLE; + n->parent_node_id = RTE_TM_NODE_ID_NULL; + n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0; + n->weight = 0; + n->tm_id = RTE_TM_NODE_ID_NULL; + n->parent_node = NULL; + n->n_children = 0; + tm->h.n_vt_nodes--; + + TAILQ_REMOVE(nl, n, node); + } + + nl = &tm->h.cos_commit_node_list; + for (n = TAILQ_FIRST(nl); n != NULL; n = nn) { + nn = TAILQ_NEXT(n, node); + + n->node_state = IPN3KE_TM_NODE_STATE_IDLE; + n->parent_node_id = RTE_TM_NODE_ID_NULL; + n->priority = IPN3KE_TM_NODE_PRIORITY_NORMAL0; + n->weight = 0; + n->tm_id = RTE_TM_NODE_ID_NULL; + n->parent_node = NULL; + tm->h.n_cos_nodes--; + + TAILQ_REMOVE(nl, n, node); + } + + return 0; +} + +static void +ipn3ke_tm_show(struct rte_eth_dev *dev) +{ + struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev); + uint32_t tm_id; + struct ipn3ke_tm_node_list *vt_nl, *cos_nl; + struct ipn3ke_tm_node *port_n, *vt_n, *cos_n; + const char *str_state[IPN3KE_TM_NODE_STATE_MAX] = {"Idle", + "CfgAdd", + "CfgDel", + "Committed"}; + + tm_id = tm->tm_id; + + IPN3KE_AFU_PMD_DEBUG("***HQoS Tree(%d)***\n", tm_id); + + port_n = tm->h.port_node; + IPN3KE_AFU_PMD_DEBUG("Port: (%d|%s)\n", port_n->node_index, + str_state[port_n->node_state]); + + vt_nl = &tm->h.port_node->children_node_list; + TAILQ_FOREACH(vt_n, vt_nl, node) { + cos_nl = &vt_n->children_node_list; + IPN3KE_AFU_PMD_DEBUG(" VT%d: ", vt_n->node_index); + TAILQ_FOREACH(cos_n, cos_nl, node) { + if (cos_n->parent_node_id != + (vt_n->node_index + IPN3KE_TM_NODE_LEVEL_MOD)) + IPN3KE_AFU_PMD_ERR("(%d|%s), ", + cos_n->node_index, + str_state[cos_n->node_state]); + } + IPN3KE_AFU_PMD_DEBUG("\n"); + } +} + +static void +ipn3ke_tm_show_commmit(struct rte_eth_dev *dev) +{ + struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev); + uint32_t tm_id; + struct ipn3ke_tm_node_list *nl; + struct ipn3ke_tm_node *n; + const char *str_state[IPN3KE_TM_NODE_STATE_MAX] = {"Idle", + "CfgAdd", + "CfgDel", + "Committed"}; + + tm_id = tm->tm_id; + + IPN3KE_AFU_PMD_DEBUG("***Commit Tree(%d)***\n", tm_id); + n = tm->h.port_commit_node; + IPN3KE_AFU_PMD_DEBUG("Port: "); + if (n) + IPN3KE_AFU_PMD_DEBUG("(%d|%s)", + n->node_index, + str_state[n->node_state]); + IPN3KE_AFU_PMD_DEBUG("\n"); + + nl = &tm->h.vt_commit_node_list; + IPN3KE_AFU_PMD_DEBUG("VT : "); + TAILQ_FOREACH(n, nl, node) { + IPN3KE_AFU_PMD_DEBUG("(%d|%s), ", + n->node_index, + str_state[n->node_state]); + } + IPN3KE_AFU_PMD_DEBUG("\n"); + + nl = &tm->h.cos_commit_node_list; + IPN3KE_AFU_PMD_DEBUG("COS : "); + TAILQ_FOREACH(n, nl, node) { + IPN3KE_AFU_PMD_DEBUG("(%d|%s), ", + n->node_index, + str_state[n->node_state]); + } + IPN3KE_AFU_PMD_DEBUG("\n"); +} + +/* Traffic manager hierarchy commit */ +static int +ipn3ke_tm_hierarchy_commit(struct rte_eth_dev *dev, + int clear_on_fail, struct rte_tm_error *error) +{ + struct ipn3ke_tm_internals *tm = IPN3KE_DEV_PRIVATE_TO_TM(dev); + int status; + + /* Checks */ + if (tm->hierarchy_frozen) + return -rte_tm_error_set(error, + EBUSY, + RTE_TM_ERROR_TYPE_UNSPECIFIED, + NULL, + rte_strerror(EBUSY)); + + ipn3ke_tm_show_commmit(dev); + + status = ipn3ke_tm_hierarchy_commit_check(dev, error); + if (status) { + if (clear_on_fail) + ipn3ke_tm_hierarchy_commit_clear(dev); + return status; + } + + ipn3ke_tm_hierarchy_hw_commit(dev, error); + ipn3ke_tm_show(dev); + + return 0; +} + +const struct rte_tm_ops ipn3ke_tm_ops = { + .node_type_get = ipn3ke_pmd_tm_node_type_get, + .capabilities_get = ipn3ke_tm_capabilities_get, + .level_capabilities_get = ipn3ke_tm_level_capabilities_get, + .node_capabilities_get = ipn3ke_tm_node_capabilities_get, + + .wred_profile_add = ipn3ke_tm_tdrop_profile_add, + .wred_profile_delete = ipn3ke_tm_tdrop_profile_delete, + .shared_wred_context_add_update = NULL, + .shared_wred_context_delete = NULL, + + .shaper_profile_add = ipn3ke_tm_shaper_profile_add, + .shaper_profile_delete = ipn3ke_tm_shaper_profile_delete, + .shared_shaper_add_update = NULL, + .shared_shaper_delete = NULL, + + .node_add = ipn3ke_tm_node_add, + .node_delete = ipn3ke_pmd_tm_node_delete, + .node_suspend = NULL, + .node_resume = NULL, + .hierarchy_commit = ipn3ke_tm_hierarchy_commit, + + .node_parent_update = NULL, + .node_shaper_update = NULL, + .node_shared_shaper_update = NULL, + .node_stats_update = NULL, + .node_wfq_weight_mode_update = NULL, + .node_cman_update = NULL, + .node_wred_context_update = NULL, + .node_shared_wred_context_update = NULL, + + .node_stats_read = NULL, +}; + +int +ipn3ke_tm_ops_get(struct rte_eth_dev *ethdev, + void *arg) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(ethdev); + struct ipn3ke_rpst *rpst = IPN3KE_DEV_PRIVATE_TO_RPST(ethdev); + struct rte_eth_dev *i40e_pf_eth; + const struct rte_tm_ops *ops; + + if (!arg) + return -EINVAL; + + if (hw->acc_tm) { + *(const void **)arg = &ipn3ke_tm_ops; + } else if (rpst->i40e_pf_eth) { + i40e_pf_eth = rpst->i40e_pf_eth; + if (i40e_pf_eth->dev_ops->tm_ops_get == NULL || + i40e_pf_eth->dev_ops->tm_ops_get(i40e_pf_eth, + &ops) != 0 || + ops == NULL) { + return -EINVAL; + } + *(const void **)arg = ops; + } else { + return -EINVAL; + } + + return 0; +} + diff --git a/drivers/net/ipn3ke/meson.build b/drivers/net/ipn3ke/meson.build index ec77390..3a95efc 100644 --- a/drivers/net/ipn3ke/meson.build +++ b/drivers/net/ipn3ke/meson.build @@ -11,5 +11,6 @@ allow_experimental_apis = true sources += files('ipn3ke_ethdev.c', - 'ipn3ke_representor.c') + 'ipn3ke_representor.c', + 'ipn3ke_tm.c') deps += ['bus_ifpga', 'sched'] From patchwork Wed Apr 10 06:27:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52533 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 8EF90683E; Wed, 10 Apr 2019 08:27:21 +0200 (CEST) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by dpdk.org (Postfix) with ESMTP id 005065F20 for ; Wed, 10 Apr 2019 08:27:19 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 23:27:19 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,332,1549958400"; d="scan'208";a="147980911" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by FMSMGA003.fm.intel.com with ESMTP; 09 Apr 2019 23:27:15 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Wed, 10 Apr 2019 14:27:44 +0800 Message-Id: <1554877672-19745-7-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554877672-19745-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554877672-19745-1-git-send-email-rosen.xu@intel.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v7 06/14] net/ipn3ke: add IPN3KE Flow of PMD driver X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add Intel FPGA Acceleration NIC IPN3KE Flow of PMD driver. Signed-off-by: Rosen Xu Signed-off-by: Andy Pei Signed-off-by: Dan Wei --- drivers/net/ipn3ke/Makefile | 1 + drivers/net/ipn3ke/ipn3ke_ethdev.c | 5 + drivers/net/ipn3ke/ipn3ke_ethdev.h | 1 + drivers/net/ipn3ke/ipn3ke_flow.c | 1374 +++++++++++++++++++++++++++++++ drivers/net/ipn3ke/ipn3ke_flow.h | 106 +++ drivers/net/ipn3ke/ipn3ke_representor.c | 3 +- drivers/net/ipn3ke/ipn3ke_tm.c | 1 + drivers/net/ipn3ke/meson.build | 3 +- 8 files changed, 1492 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ipn3ke/ipn3ke_flow.c create mode 100644 drivers/net/ipn3ke/ipn3ke_flow.h diff --git a/drivers/net/ipn3ke/Makefile b/drivers/net/ipn3ke/Makefile index 38d9384..8c3ae37 100644 --- a/drivers/net/ipn3ke/Makefile +++ b/drivers/net/ipn3ke/Makefile @@ -35,5 +35,6 @@ LIBABIVER := 1 SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_ethdev.c SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_representor.c SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_tm.c +SRCS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke_flow.c include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/net/ipn3ke/ipn3ke_ethdev.c b/drivers/net/ipn3ke/ipn3ke_ethdev.c index 508ea01..9079b57 100644 --- a/drivers/net/ipn3ke/ipn3ke_ethdev.c +++ b/drivers/net/ipn3ke/ipn3ke_ethdev.c @@ -21,6 +21,7 @@ #include #include "ipn3ke_rawdev_api.h" +#include "ipn3ke_flow.h" #include "ipn3ke_logs.h" #include "ipn3ke_ethdev.h" @@ -266,6 +267,10 @@ if (ret) return ret; hw->tm_hw_enable = 1; + + ret = ipn3ke_flow_init(hw); + if (ret) + return ret; hw->flow_hw_enable = 1; } diff --git a/drivers/net/ipn3ke/ipn3ke_ethdev.h b/drivers/net/ipn3ke/ipn3ke_ethdev.h index 36ff2f8..bfda9d5 100644 --- a/drivers/net/ipn3ke/ipn3ke_ethdev.h +++ b/drivers/net/ipn3ke/ipn3ke_ethdev.h @@ -291,6 +291,7 @@ struct ipn3ke_hw { uint32_t acc_tm; uint32_t acc_flow; + struct ipn3ke_flow_list flow_list; uint32_t flow_max_entries; uint32_t flow_num_entries; diff --git a/drivers/net/ipn3ke/ipn3ke_flow.c b/drivers/net/ipn3ke/ipn3ke_flow.c new file mode 100644 index 0000000..e5937df --- /dev/null +++ b/drivers/net/ipn3ke/ipn3ke_flow.c @@ -0,0 +1,1374 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ipn3ke_rawdev_api.h" +#include "ipn3ke_flow.h" +#include "ipn3ke_logs.h" +#include "ipn3ke_ethdev.h" + +/** Static initializer for items. */ +#define FLOW_PATTERNS(...) \ + ((const enum rte_flow_item_type []) { \ + __VA_ARGS__, RTE_FLOW_ITEM_TYPE_END, \ + }) + +enum IPN3KE_HASH_KEY_TYPE { + IPN3KE_HASH_KEY_VXLAN, + IPN3KE_HASH_KEY_MAC, + IPN3KE_HASH_KEY_QINQ, + IPN3KE_HASH_KEY_MPLS, + IPN3KE_HASH_KEY_IP_TCP, + IPN3KE_HASH_KEY_IP_UDP, + IPN3KE_HASH_KEY_IP_NVGRE, + IPN3KE_HASH_KEY_VXLAN_IP_UDP, +}; + +struct ipn3ke_flow_parse { + uint32_t mark:1; /**< Set if the flow is marked. */ + uint32_t drop:1; /**< ACL drop. */ + uint32_t key_type:IPN3KE_FLOW_KEY_ID_BITS; + uint32_t mark_id:IPN3KE_FLOW_RESULT_UID_BITS; /**< Mark identifier. */ + uint8_t key_len; /**< Length in bit. */ + uint8_t key[BITS_TO_BYTES(IPN3KE_FLOW_KEY_DATA_BITS)]; + /**< key1, key2 */ +}; + +typedef int (*pattern_filter_t)(const struct rte_flow_item patterns[], + struct rte_flow_error *error, struct ipn3ke_flow_parse *parser); + + +struct ipn3ke_flow_pattern { + const enum rte_flow_item_type *const items; + + pattern_filter_t filter; +}; + +/* + * @ RTL definition: + * typedef struct packed { + * logic [47:0] vxlan_inner_mac; + * logic [23:0] vxlan_vni; + * } Hash_Key_Vxlan_t; + * + * @ flow items: + * RTE_FLOW_ITEM_TYPE_VXLAN + * RTE_FLOW_ITEM_TYPE_ETH + */ +static int +ipn3ke_pattern_vxlan(const struct rte_flow_item patterns[], + struct rte_flow_error *error, struct ipn3ke_flow_parse *parser) +{ + const struct rte_flow_item_vxlan *vxlan = NULL; + const struct rte_flow_item_eth *eth = NULL; + const struct rte_flow_item *item; + + for (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { + if (/*!item->spec || item->mask || */item->last) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Only support item with 'spec'"); + return -rte_errno; + } + + switch (item->type) { + case RTE_FLOW_ITEM_TYPE_ETH: + eth = item->spec; + + rte_memcpy(&parser->key[0], + eth->src.addr_bytes, + ETHER_ADDR_LEN); + break; + + case RTE_FLOW_ITEM_TYPE_VXLAN: + vxlan = item->spec; + + rte_memcpy(&parser->key[6], vxlan->vni, 3); + break; + + default: + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Not support item type"); + return -rte_errno; + } + } + + if (vxlan != NULL && eth != NULL) { + parser->key_len = 48 + 24; + return 0; + } + + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + patterns, + "Missed some patterns"); + return -rte_errno; +} + +/* + * @ RTL definition: + * typedef struct packed { + * logic [47:0] eth_smac; + * } Hash_Key_Mac_t; + * + * @ flow items: + * RTE_FLOW_ITEM_TYPE_ETH + */ +static int +ipn3ke_pattern_mac(const struct rte_flow_item patterns[], + struct rte_flow_error *error, struct ipn3ke_flow_parse *parser) +{ + const struct rte_flow_item_eth *eth = NULL; + const struct rte_flow_item *item; + + for (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { + if (!item->spec || item->mask || item->last) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Only support item with 'spec'"); + return -rte_errno; + } + + switch (item->type) { + case RTE_FLOW_ITEM_TYPE_ETH: + eth = item->spec; + + rte_memcpy(parser->key, + eth->src.addr_bytes, + ETHER_ADDR_LEN); + break; + + default: + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Not support item type"); + return -rte_errno; + } + } + + if (eth != NULL) { + parser->key_len = 48; + return 0; + } + + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + patterns, + "Missed some patterns"); + return -rte_errno; +} + +/* + * @ RTL definition: + * typedef struct packed { + * logic [11:0] outer_vlan_id; + * logic [11:0] inner_vlan_id; + * } Hash_Key_QinQ_t; + * + * @ flow items: + * RTE_FLOW_ITEM_TYPE_VLAN + * RTE_FLOW_ITEM_TYPE_VLAN + */ +static int +ipn3ke_pattern_qinq(const struct rte_flow_item patterns[], + struct rte_flow_error *error, struct ipn3ke_flow_parse *parser) +{ + const struct rte_flow_item_vlan *outer_vlan = NULL; + const struct rte_flow_item_vlan *inner_vlan = NULL; + const struct rte_flow_item *item; + uint16_t tci; + + for (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { + if (!item->spec || item->mask || item->last) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Only support item with 'spec'"); + return -rte_errno; + } + + switch (item->type) { + case RTE_FLOW_ITEM_TYPE_VLAN: + if (!outer_vlan) { + outer_vlan = item->spec; + + tci = rte_be_to_cpu_16(outer_vlan->tci); + parser->key[0] = (tci & 0xff0) >> 4; + parser->key[1] |= (tci & 0x00f) << 4; + } else { + inner_vlan = item->spec; + + tci = rte_be_to_cpu_16(inner_vlan->tci); + parser->key[1] |= (tci & 0xf00) >> 8; + parser->key[2] = (tci & 0x0ff); + } + break; + + default: + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Not support item type"); + return -rte_errno; + } + } + + if (outer_vlan != NULL && inner_vlan != NULL) { + parser->key_len = 12 + 12; + return 0; + } + + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + patterns, + "Missed some patterns"); + return -rte_errno; +} + +/* + * @ RTL definition: + * typedef struct packed { + * logic [19:0] mpls_label1; + * logic [19:0] mpls_label2; + * } Hash_Key_Mpls_t; + * + * @ flow items: + * RTE_FLOW_ITEM_TYPE_MPLS + * RTE_FLOW_ITEM_TYPE_MPLS + */ +static int +ipn3ke_pattern_mpls(const struct rte_flow_item patterns[], + struct rte_flow_error *error, struct ipn3ke_flow_parse *parser) +{ + const struct rte_flow_item_mpls *mpls1 = NULL; + const struct rte_flow_item_mpls *mpls2 = NULL; + const struct rte_flow_item *item; + + for (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { + if (!item->spec || item->mask || item->last) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Only support item with 'spec'"); + return -rte_errno; + } + + switch (item->type) { + case RTE_FLOW_ITEM_TYPE_MPLS: + if (!mpls1) { + mpls1 = item->spec; + + parser->key[0] = mpls1->label_tc_s[0]; + parser->key[1] = mpls1->label_tc_s[1]; + parser->key[2] = mpls1->label_tc_s[2] & 0xf0; + } else { + mpls2 = item->spec; + + parser->key[2] |= + ((mpls2->label_tc_s[0] & 0xf0) >> 4); + parser->key[3] = + ((mpls2->label_tc_s[0] & 0xf) << 4) | + ((mpls2->label_tc_s[1] & 0xf0) >> 4); + parser->key[4] = + ((mpls2->label_tc_s[1] & 0xf) << 4) | + ((mpls2->label_tc_s[2] & 0xf0) >> 4); + } + break; + + default: + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Not support item type"); + return -rte_errno; + } + } + + if (mpls1 != NULL && mpls2 != NULL) { + parser->key_len = 20 + 20; + return 0; + } + + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + patterns, + "Missed some patterns"); + return -rte_errno; +} + +/* + * @ RTL definition: + * typedef struct packed { + * logic [31:0] ip_sa; + * logic [15:0] tcp_sport; + * } Hash_Key_Ip_Tcp_t; + * + * @ flow items: + * RTE_FLOW_ITEM_TYPE_IPV4 + * RTE_FLOW_ITEM_TYPE_TCP + */ +static int +ipn3ke_pattern_ip_tcp(const struct rte_flow_item patterns[], + struct rte_flow_error *error, struct ipn3ke_flow_parse *parser) +{ + const struct rte_flow_item_ipv4 *ipv4 = NULL; + const struct rte_flow_item_tcp *tcp = NULL; + const struct rte_flow_item *item; + + for (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { + if (!item->spec || item->mask || item->last) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Only support item with 'spec'"); + return -rte_errno; + } + + switch (item->type) { + case RTE_FLOW_ITEM_TYPE_IPV4: + ipv4 = item->spec; + + rte_memcpy(&parser->key[0], &ipv4->hdr.src_addr, 4); + break; + + case RTE_FLOW_ITEM_TYPE_TCP: + tcp = item->spec; + + rte_memcpy(&parser->key[4], &tcp->hdr.src_port, 2); + break; + + default: + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Not support item type"); + return -rte_errno; + } + } + + if (ipv4 != NULL && tcp != NULL) { + parser->key_len = 32 + 16; + return 0; + } + + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + patterns, + "Missed some patterns"); + return -rte_errno; +} + +/* + * @ RTL definition: + * typedef struct packed { + * logic [31:0] ip_sa; + * logic [15:0] udp_sport; + * } Hash_Key_Ip_Udp_t; + * + * @ flow items: + * RTE_FLOW_ITEM_TYPE_IPV4 + * RTE_FLOW_ITEM_TYPE_UDP + */ +static int +ipn3ke_pattern_ip_udp(const struct rte_flow_item patterns[], + struct rte_flow_error *error, struct ipn3ke_flow_parse *parser) +{ + const struct rte_flow_item_ipv4 *ipv4 = NULL; + const struct rte_flow_item_udp *udp = NULL; + const struct rte_flow_item *item; + + for (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { + if (!item->spec || item->mask || item->last) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Only support item with 'spec'"); + return -rte_errno; + } + + switch (item->type) { + case RTE_FLOW_ITEM_TYPE_IPV4: + ipv4 = item->spec; + + rte_memcpy(&parser->key[0], &ipv4->hdr.src_addr, 4); + break; + + case RTE_FLOW_ITEM_TYPE_UDP: + udp = item->spec; + + rte_memcpy(&parser->key[4], &udp->hdr.src_port, 2); + break; + + default: + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Not support item type"); + return -rte_errno; + } + } + + if (ipv4 != NULL && udp != NULL) { + parser->key_len = 32 + 16; + return 0; + } + + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + patterns, + "Missed some patterns"); + return -rte_errno; +} + +/* + * @ RTL definition: + * typedef struct packed { + * logic [31:0] ip_sa; + * logic [15:0] udp_sport; + * logic [23:0] vsid; + * } Hash_Key_Ip_Nvgre_t; + * + * @ flow items: + * RTE_FLOW_ITEM_TYPE_IPV4 + * RTE_FLOW_ITEM_TYPE_UDP + * RTE_FLOW_ITEM_TYPE_NVGRE + */ +static int +ipn3ke_pattern_ip_nvgre(const struct rte_flow_item patterns[], + struct rte_flow_error *error, struct ipn3ke_flow_parse *parser) +{ + const struct rte_flow_item_nvgre *nvgre = NULL; + const struct rte_flow_item_ipv4 *ipv4 = NULL; + const struct rte_flow_item_udp *udp = NULL; + const struct rte_flow_item *item; + + for (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { + if (!item->spec || item->mask || item->last) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Only support item with 'spec'"); + return -rte_errno; + } + + switch (item->type) { + case RTE_FLOW_ITEM_TYPE_IPV4: + ipv4 = item->spec; + + rte_memcpy(&parser->key[0], &ipv4->hdr.src_addr, 4); + break; + + case RTE_FLOW_ITEM_TYPE_UDP: + udp = item->spec; + + rte_memcpy(&parser->key[4], &udp->hdr.src_port, 2); + break; + + case RTE_FLOW_ITEM_TYPE_NVGRE: + nvgre = item->spec; + + rte_memcpy(&parser->key[6], nvgre->tni, 3); + break; + + default: + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Not support item type"); + return -rte_errno; + } + } + + if (ipv4 != NULL && udp != NULL && nvgre != NULL) { + parser->key_len = 32 + 16 + 24; + return 0; + } + + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + patterns, + "Missed some patterns"); + return -rte_errno; +} + +/* + * @ RTL definition: + * typedef struct packed{ + * logic [23:0] vxlan_vni; + * logic [31:0] ip_sa; + * logic [15:0] udp_sport; + * } Hash_Key_Vxlan_Ip_Udp_t; + * + * @ flow items: + * RTE_FLOW_ITEM_TYPE_VXLAN + * RTE_FLOW_ITEM_TYPE_IPV4 + * RTE_FLOW_ITEM_TYPE_UDP + */ +static int +ipn3ke_pattern_vxlan_ip_udp(const struct rte_flow_item patterns[], + struct rte_flow_error *error, struct ipn3ke_flow_parse *parser) +{ + const struct rte_flow_item_vxlan *vxlan = NULL; + const struct rte_flow_item_ipv4 *ipv4 = NULL; + const struct rte_flow_item_udp *udp = NULL; + const struct rte_flow_item *item; + + for (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { + if (!item->spec || item->mask || item->last) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Only support item with 'spec'"); + return -rte_errno; + } + + switch (item->type) { + case RTE_FLOW_ITEM_TYPE_VXLAN: + vxlan = item->spec; + + rte_memcpy(&parser->key[0], vxlan->vni, 3); + break; + + case RTE_FLOW_ITEM_TYPE_IPV4: + ipv4 = item->spec; + + rte_memcpy(&parser->key[3], &ipv4->hdr.src_addr, 4); + break; + + case RTE_FLOW_ITEM_TYPE_UDP: + udp = item->spec; + + rte_memcpy(&parser->key[7], &udp->hdr.src_port, 2); + break; + + default: + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Not support item type"); + return -rte_errno; + } + } + + if (vxlan != NULL && ipv4 != NULL && udp != NULL) { + parser->key_len = 24 + 32 + 16; + return 0; + } + + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + patterns, + "Missed some patterns"); + return -rte_errno; +} + +static const struct ipn3ke_flow_pattern ipn3ke_supported_patterns[] = { + [IPN3KE_HASH_KEY_VXLAN] = { + .items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_VXLAN, + RTE_FLOW_ITEM_TYPE_ETH), + .filter = ipn3ke_pattern_vxlan, + }, + + [IPN3KE_HASH_KEY_MAC] = { + .items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_ETH), + .filter = ipn3ke_pattern_mac, + }, + + [IPN3KE_HASH_KEY_QINQ] = { + .items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_VLAN, + RTE_FLOW_ITEM_TYPE_VLAN), + .filter = ipn3ke_pattern_qinq, + }, + + [IPN3KE_HASH_KEY_MPLS] = { + .items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_MPLS, + RTE_FLOW_ITEM_TYPE_MPLS), + .filter = ipn3ke_pattern_mpls, + }, + + [IPN3KE_HASH_KEY_IP_TCP] = { + .items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_TCP), + .filter = ipn3ke_pattern_ip_tcp, + }, + + [IPN3KE_HASH_KEY_IP_UDP] = { + .items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_UDP), + .filter = ipn3ke_pattern_ip_udp, + }, + + [IPN3KE_HASH_KEY_IP_NVGRE] = { + .items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_UDP, + RTE_FLOW_ITEM_TYPE_NVGRE), + .filter = ipn3ke_pattern_ip_nvgre, + }, + + [IPN3KE_HASH_KEY_VXLAN_IP_UDP] = { + .items = FLOW_PATTERNS(RTE_FLOW_ITEM_TYPE_VXLAN, + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_UDP), + .filter = ipn3ke_pattern_vxlan_ip_udp, + }, +}; + +static int +ipn3ke_flow_convert_attributes(const struct rte_flow_attr *attr, + struct rte_flow_error *error) +{ + if (!attr) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR, + NULL, + "NULL attribute."); + return -rte_errno; + } + + if (attr->group) { + rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ATTR_GROUP, + NULL, + "groups are not supported"); + return -rte_errno; + } + + if (attr->egress) { + rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, + NULL, + "egress is not supported"); + return -rte_errno; + } + + if (attr->transfer) { + rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER, + NULL, + "transfer is not supported"); + return -rte_errno; + } + + if (!attr->ingress) { + rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, + NULL, + "only ingress is supported"); + return -rte_errno; + } + + return 0; +} + +static int +ipn3ke_flow_convert_actions(const struct rte_flow_action actions[], + struct rte_flow_error *error, struct ipn3ke_flow_parse *parser) +{ + const struct rte_flow_action_mark *mark = NULL; + + if (!actions) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION_NUM, + NULL, + "NULL action."); + return -rte_errno; + } + + for (; actions->type != RTE_FLOW_ACTION_TYPE_END; ++actions) { + switch (actions->type) { + case RTE_FLOW_ACTION_TYPE_VOID: + break; + + case RTE_FLOW_ACTION_TYPE_MARK: + if (mark) { + rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + actions, + "duplicated mark"); + return -rte_errno; + } + + mark = actions->conf; + if (!mark) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + actions, + "mark must be defined"); + return -rte_errno; + } else if (mark->id > IPN3KE_FLOW_RESULT_UID_MAX) { + rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + actions, + "mark id is out of range"); + return -rte_errno; + } + + parser->mark = 1; + parser->mark_id = mark->id; + break; + + case RTE_FLOW_ACTION_TYPE_DROP: + parser->drop = 1; + break; + + default: + rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + actions, + "invalid action"); + return -rte_errno; + } + } + + if (!parser->drop && !parser->mark) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + actions, + "no valid actions"); + return -rte_errno; + } + + return 0; +} + +static bool +ipn3ke_match_pattern(const enum rte_flow_item_type *patterns, + const struct rte_flow_item *input) +{ + const struct rte_flow_item *item = input; + + while ((*patterns == item->type) && + (*patterns != RTE_FLOW_ITEM_TYPE_END)) { + patterns++; + item++; + } + + return (*patterns == RTE_FLOW_ITEM_TYPE_END && + item->type == RTE_FLOW_ITEM_TYPE_END); +} + +static pattern_filter_t +ipn3ke_find_filter_func(const struct rte_flow_item *input, + uint32_t *idx) +{ + pattern_filter_t filter = NULL; + uint32_t i; + + for (i = 0; i < RTE_DIM(ipn3ke_supported_patterns); i++) { + if (ipn3ke_match_pattern(ipn3ke_supported_patterns[i].items, + input)) { + filter = ipn3ke_supported_patterns[i].filter; + *idx = i; + break; + } + } + + return filter; +} + +static int +ipn3ke_flow_convert_items(const struct rte_flow_item items[], + struct rte_flow_error *error, struct ipn3ke_flow_parse *parser) +{ + pattern_filter_t filter = NULL; + uint32_t idx; + + if (!items) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM_NUM, + NULL, + "NULL pattern."); + return -rte_errno; + } + + filter = ipn3ke_find_filter_func(items, &idx); + + if (!filter) { + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + items, + "Unsupported pattern"); + return -rte_errno; + } + + parser->key_type = idx; + + return filter(items, error, parser); +} + +/* Put the least @nbits of @data into @offset of @dst bits stream, and + * the @offset starts from MSB to LSB in each byte. + * + * MSB LSB + * +------+------+------+------+ + * | | | | | + * +------+------+------+------+ + * ^ ^ + * |<- data: nbits ->| + * | + * offset + */ +static void +copy_data_bits(uint8_t *dst, uint64_t data, + uint32_t offset, uint8_t nbits) +{ + uint8_t set, *p = &dst[offset / BITS_PER_BYTE]; + uint8_t bits_to_set = BITS_PER_BYTE - (offset % BITS_PER_BYTE); + uint8_t mask_to_set = 0xff >> (offset % BITS_PER_BYTE); + uint32_t size = offset + nbits; + + if (nbits > (sizeof(data) * BITS_PER_BYTE)) { + IPN3KE_AFU_PMD_ERR("nbits is out of range"); + return; + } + + while (nbits - bits_to_set >= 0) { + set = data >> (nbits - bits_to_set); + + *p &= ~mask_to_set; + *p |= (set & mask_to_set); + + nbits -= bits_to_set; + bits_to_set = BITS_PER_BYTE; + mask_to_set = 0xff; + p++; + } + + if (nbits) { + uint8_t shift = BITS_PER_BYTE - (size % BITS_PER_BYTE); + + set = data << shift; + mask_to_set = 0xff << shift; + + *p &= ~mask_to_set; + *p |= (set & mask_to_set); + } +} + +static void +ipn3ke_flow_key_generation(struct ipn3ke_flow_parse *parser, + struct rte_flow *flow) +{ + uint32_t i, shift_bytes, len_in_bytes, offset; + uint64_t key; + uint8_t *dst; + + dst = flow->rule.key; + + copy_data_bits(dst, + parser->key_type, + IPN3KE_FLOW_KEY_ID_OFFSET, + IPN3KE_FLOW_KEY_ID_BITS); + + /* The MSb of key is filled to 0 when it is less than + * IPN3KE_FLOW_KEY_DATA_BITS bit. And the parsed key data is + * save as MSB byte first in the array, it needs to move + * the bits before formatting them. + */ + key = 0; + shift_bytes = 0; + len_in_bytes = BITS_TO_BYTES(parser->key_len); + offset = (IPN3KE_FLOW_KEY_DATA_OFFSET + + IPN3KE_FLOW_KEY_DATA_BITS - + parser->key_len); + + for (i = 0; i < len_in_bytes; i++) { + key = (key << 8) | parser->key[i]; + + if (++shift_bytes == sizeof(key)) { + shift_bytes = 0; + + copy_data_bits(dst, key, offset, + sizeof(key) * BITS_PER_BYTE); + offset += sizeof(key) * BITS_PER_BYTE; + key = 0; + } + } + + if (shift_bytes != 0) { + uint32_t rem_bits; + + rem_bits = parser->key_len % (sizeof(key) * BITS_PER_BYTE); + key >>= (shift_bytes * 8 - rem_bits); + copy_data_bits(dst, key, offset, rem_bits); + } +} + +static void +ipn3ke_flow_result_generation(struct ipn3ke_flow_parse *parser, + struct rte_flow *flow) +{ + uint8_t *dst; + + if (parser->drop) + return; + + dst = flow->rule.result; + + copy_data_bits(dst, + 1, + IPN3KE_FLOW_RESULT_ACL_OFFSET, + IPN3KE_FLOW_RESULT_ACL_BITS); + + copy_data_bits(dst, + parser->mark_id, + IPN3KE_FLOW_RESULT_UID_OFFSET, + IPN3KE_FLOW_RESULT_UID_BITS); +} + +#define MHL_COMMAND_TIME_COUNT 0xFFFF +#define MHL_COMMAND_TIME_INTERVAL_US 10 + +static int +ipn3ke_flow_hw_update(struct ipn3ke_hw *hw, + struct rte_flow *flow, uint32_t is_add) +{ + uint32_t *pdata = NULL; + uint32_t data; + uint32_t time_out = MHL_COMMAND_TIME_COUNT; + uint32_t i; + + IPN3KE_AFU_PMD_DEBUG("IPN3KE flow dump start\n"); + + pdata = (uint32_t *)flow->rule.key; + IPN3KE_AFU_PMD_DEBUG(" - key :"); + + for (i = 0; i < RTE_DIM(flow->rule.key); i++) + IPN3KE_AFU_PMD_DEBUG(" %02x", flow->rule.key[i]); + + for (i = 0; i < 4; i++) + IPN3KE_AFU_PMD_DEBUG(" %02x", ipn3ke_swap32(pdata[3 - i])); + IPN3KE_AFU_PMD_DEBUG("\n"); + + pdata = (uint32_t *)flow->rule.result; + IPN3KE_AFU_PMD_DEBUG(" - result:"); + + for (i = 0; i < RTE_DIM(flow->rule.result); i++) + IPN3KE_AFU_PMD_DEBUG(" %02x", flow->rule.result[i]); + + for (i = 0; i < 1; i++) + IPN3KE_AFU_PMD_DEBUG(" %02x", pdata[i]); + IPN3KE_AFU_PMD_DEBUG("IPN3KE flow dump end\n"); + + pdata = (uint32_t *)flow->rule.key; + + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_MHL_KEY_0, + 0, + ipn3ke_swap32(pdata[3]), + IPN3KE_CLF_MHL_KEY_MASK); + + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_MHL_KEY_1, + 0, + ipn3ke_swap32(pdata[2]), + IPN3KE_CLF_MHL_KEY_MASK); + + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_MHL_KEY_2, + 0, + ipn3ke_swap32(pdata[1]), + IPN3KE_CLF_MHL_KEY_MASK); + + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_MHL_KEY_3, + 0, + ipn3ke_swap32(pdata[0]), + IPN3KE_CLF_MHL_KEY_MASK); + + pdata = (uint32_t *)flow->rule.result; + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_MHL_RES, + 0, + ipn3ke_swap32(pdata[0]), + IPN3KE_CLF_MHL_RES_MASK); + + /* insert/delete the key and result */ + data = 0; + data = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CLF_MHL_MGMT_CTRL, + 0, + 0x80000000); + time_out = MHL_COMMAND_TIME_COUNT; + while (IPN3KE_BIT_ISSET(data, IPN3KE_CLF_MHL_MGMT_CTRL_BIT_BUSY) && + (time_out > 0)) { + data = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CLF_MHL_MGMT_CTRL, + 0, + 0x80000000); + time_out--; + rte_delay_us(MHL_COMMAND_TIME_INTERVAL_US); + } + if (!time_out) + return -1; + if (is_add) + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_MHL_MGMT_CTRL, + 0, + IPN3KE_CLF_MHL_MGMT_CTRL_INSERT, + 0x3); + else + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_MHL_MGMT_CTRL, + 0, + IPN3KE_CLF_MHL_MGMT_CTRL_DELETE, + 0x3); + + return 0; +} + +static int +ipn3ke_flow_hw_flush(struct ipn3ke_hw *hw) +{ + uint32_t data; + uint32_t time_out = MHL_COMMAND_TIME_COUNT; + + /* flush the MHL lookup table */ + data = 0; + data = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CLF_MHL_MGMT_CTRL, + 0, + 0x80000000); + time_out = MHL_COMMAND_TIME_COUNT; + while (IPN3KE_BIT_ISSET(data, IPN3KE_CLF_MHL_MGMT_CTRL_BIT_BUSY) && + (time_out > 0)) { + data = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CLF_MHL_MGMT_CTRL, + 0, + 0x80000000); + time_out--; + rte_delay_us(MHL_COMMAND_TIME_INTERVAL_US); + } + if (!time_out) + return -1; + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_MHL_MGMT_CTRL, + 0, + IPN3KE_CLF_MHL_MGMT_CTRL_FLUSH, + 0x3); + + return 0; +} + +static void +ipn3ke_flow_convert_finalise(struct ipn3ke_hw *hw, + struct ipn3ke_flow_parse *parser, struct rte_flow *flow) +{ + ipn3ke_flow_key_generation(parser, flow); + ipn3ke_flow_result_generation(parser, flow); + ipn3ke_flow_hw_update(hw, flow, 1); +} + +static int +ipn3ke_flow_convert(const struct rte_flow_attr *attr, + const struct rte_flow_item items[], + const struct rte_flow_action actions[], struct rte_flow_error *error, + struct ipn3ke_flow_parse *parser) +{ + int ret; + + ret = ipn3ke_flow_convert_attributes(attr, error); + if (ret) + return ret; + + ret = ipn3ke_flow_convert_actions(actions, error, parser); + if (ret) + return ret; + + ret = ipn3ke_flow_convert_items(items, error, parser); + if (ret) + return ret; + + return 0; +} + +static int +ipn3ke_flow_validate(__rte_unused struct rte_eth_dev *dev, + const struct rte_flow_attr *attr, const struct rte_flow_item pattern[], + const struct rte_flow_action actions[], struct rte_flow_error *error) +{ + struct ipn3ke_flow_parse parser = {0}; + return ipn3ke_flow_convert(attr, pattern, actions, error, &parser); +} + +static struct rte_flow * +ipn3ke_flow_create(struct rte_eth_dev *dev, + const struct rte_flow_attr *attr, const struct rte_flow_item pattern[], + const struct rte_flow_action actions[], struct rte_flow_error *error) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct ipn3ke_flow_parse parser = {0}; + struct rte_flow *flow; + int ret; + + if (hw->flow_num_entries == hw->flow_max_entries) { + rte_flow_error_set(error, + ENOBUFS, + RTE_FLOW_ERROR_TYPE_HANDLE, + NULL, + "The flow table is full."); + return NULL; + } + + ret = ipn3ke_flow_convert(attr, pattern, actions, error, &parser); + if (ret < 0) { + rte_flow_error_set(error, + -ret, + RTE_FLOW_ERROR_TYPE_HANDLE, + NULL, + "Failed to create flow."); + return NULL; + } + + flow = rte_zmalloc("ipn3ke_flow", sizeof(struct rte_flow), 0); + if (!flow) { + rte_flow_error_set(error, + ENOMEM, + RTE_FLOW_ERROR_TYPE_HANDLE, + NULL, + "Failed to allocate memory"); + return flow; + } + + ipn3ke_flow_convert_finalise(hw, &parser, flow); + + TAILQ_INSERT_TAIL(&hw->flow_list, flow, next); + + return flow; +} + +static int +ipn3ke_flow_destroy(struct rte_eth_dev *dev, + struct rte_flow *flow, struct rte_flow_error *error) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + int ret = 0; + + ret = ipn3ke_flow_hw_update(hw, flow, 0); + if (!ret) { + TAILQ_REMOVE(&hw->flow_list, flow, next); + rte_free(flow); + } else { + rte_flow_error_set(error, + -ret, + RTE_FLOW_ERROR_TYPE_HANDLE, + NULL, + "Failed to destroy flow."); + } + + return ret; +} + +static int +ipn3ke_flow_flush(struct rte_eth_dev *dev, + __rte_unused struct rte_flow_error *error) +{ + struct ipn3ke_hw *hw = IPN3KE_DEV_PRIVATE_TO_HW(dev); + struct rte_flow *flow, *temp; + + TAILQ_FOREACH_SAFE(flow, &hw->flow_list, next, temp) { + TAILQ_REMOVE(&hw->flow_list, flow, next); + rte_free(flow); + } + + return ipn3ke_flow_hw_flush(hw); +} + +int ipn3ke_flow_init(void *dev) +{ + struct ipn3ke_hw *hw = (struct ipn3ke_hw *)dev; + uint32_t data; + + /* disable rx classifier bypass */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_RX_TEST, + 0, 0, 0x1); + + data = 0; + data = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CLF_RX_TEST, + 0, + 0x1); + IPN3KE_AFU_PMD_DEBUG("IPN3KE_CLF_RX_TEST: %x\n", data); + + /* configure base mac address */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_BASE_DST_MAC_ADDR_HI, + 0, + 0x2457, + 0xFFFF); + + data = 0; + data = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CLF_BASE_DST_MAC_ADDR_HI, + 0, + 0xFFFF); + IPN3KE_AFU_PMD_DEBUG("IPN3KE_CLF_BASE_DST_MAC_ADDR_HI: %x\n", data); + + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_BASE_DST_MAC_ADDR_LOW, + 0, + 0x9bdf1000, + 0xFFFFFFFF); + + data = 0; + data = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CLF_BASE_DST_MAC_ADDR_LOW, + 0, + 0xFFFFFFFF); + IPN3KE_AFU_PMD_DEBUG("IPN3KE_CLF_BASE_DST_MAC_ADDR_LOW: %x\n", data); + + + /* configure hash lookup rules enable */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_LKUP_ENABLE, + 0, + 0xFD, + 0xFF); + + data = 0; + data = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CLF_LKUP_ENABLE, + 0, + 0xFF); + IPN3KE_AFU_PMD_DEBUG("IPN3KE_CLF_LKUP_ENABLE: %x\n", data); + + + /* configure rx parse config, settings associatied with VxLAN */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_RX_PARSE_CFG, + 0, + 0x212b5, + 0x3FFFF); + + data = 0; + data = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CLF_RX_PARSE_CFG, + 0, + 0x3FFFF); + IPN3KE_AFU_PMD_DEBUG("IPN3KE_CLF_RX_PARSE_CFG: %x\n", data); + + + /* configure QinQ S-Tag */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_QINQ_STAG, + 0, + 0x88a8, + 0xFFFF); + + data = 0; + data = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CLF_QINQ_STAG, + 0, + 0xFFFF); + IPN3KE_AFU_PMD_DEBUG("IPN3KE_CLF_QINQ_STAG: %x\n", data); + + + /* configure gen ctrl */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_MHL_GEN_CTRL, + 0, + 0x3, + 0x3); + + data = 0; + data = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CLF_MHL_GEN_CTRL, + 0, + 0x1F); + IPN3KE_AFU_PMD_DEBUG("IPN3KE_CLF_MHL_GEN_CTRL: %x\n", data); + + + /* clear monitoring register */ + IPN3KE_MASK_WRITE_REG(hw, + IPN3KE_CLF_MHL_MON_0, + 0, + 0xFFFFFFFF, + 0xFFFFFFFF); + + data = 0; + data = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CLF_MHL_MON_0, + 0, + 0xFFFFFFFF); + IPN3KE_AFU_PMD_DEBUG("IPN3KE_CLF_MHL_MON_0: %x\n", data); + + + ipn3ke_flow_hw_flush(hw); + + TAILQ_INIT(&hw->flow_list); + hw->flow_max_entries = IPN3KE_MASK_READ_REG(hw, + IPN3KE_CLF_EM_NUM, + 0, + 0xFFFFFFFF); + hw->flow_num_entries = 0; + + return 0; +} + +const struct rte_flow_ops ipn3ke_flow_ops = { + .validate = ipn3ke_flow_validate, + .create = ipn3ke_flow_create, + .destroy = ipn3ke_flow_destroy, + .flush = ipn3ke_flow_flush, +}; + diff --git a/drivers/net/ipn3ke/ipn3ke_flow.h b/drivers/net/ipn3ke/ipn3ke_flow.h new file mode 100644 index 0000000..ef1a61f --- /dev/null +++ b/drivers/net/ipn3ke/ipn3ke_flow.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#ifndef _IPN3KE_FLOW_H_ +#define _IPN3KE_FLOW_H_ + +/** + * Expand the length to DWORD alignment with 'Unused' field. + * + * FLOW KEY: + * | Unused |Ruler id (id) | Key1 Key2 ā€¦ (data) | + * |--------+---------------+--------------------| + * | 17bits | 3 bits | Total 108 bits | + * MSB ---> LSB + * + * Note: And the MSb of key data is filled to 0 when it is less + * than 108 bit. + */ +#define IPN3KE_FLOW_KEY_UNUSED_BITS 17 +#define IPN3KE_FLOW_KEY_ID_BITS 3 +#define IPN3KE_FLOW_KEY_DATA_BITS 108 + +#define IPN3KE_FLOW_KEY_TOTAL_BITS \ + (IPN3KE_FLOW_KEY_UNUSED_BITS + \ + IPN3KE_FLOW_KEY_ID_BITS + \ + IPN3KE_FLOW_KEY_DATA_BITS) + +#define IPN3KE_FLOW_KEY_ID_OFFSET \ + (IPN3KE_FLOW_KEY_UNUSED_BITS) + +#define IPN3KE_FLOW_KEY_DATA_OFFSET \ + (IPN3KE_FLOW_KEY_ID_OFFSET + IPN3KE_FLOW_KEY_ID_BITS) + +/** + * Expand the length to DWORD alignment with 'Unused' field. + * + * FLOW RESULT: + * | Unused | enable (acl) | uid | + * |---------+--------------+--------------| + * | 15 bits | 1 bit | 16 bits | + * MSB ---> LSB + */ + +#define IPN3KE_FLOW_RESULT_UNUSED_BITS 15 +#define IPN3KE_FLOW_RESULT_ACL_BITS 1 +#define IPN3KE_FLOW_RESULT_UID_BITS 16 + +#define IPN3KE_FLOW_RESULT_TOTAL_BITS \ + (IPN3KE_FLOW_RESULT_UNUSED_BITS + \ + IPN3KE_FLOW_RESULT_ACL_BITS + \ + IPN3KE_FLOW_RESULT_UID_BITS) + +#define IPN3KE_FLOW_RESULT_ACL_OFFSET \ + (IPN3KE_FLOW_RESULT_UNUSED_BITS) + +#define IPN3KE_FLOW_RESULT_UID_OFFSET \ + (IPN3KE_FLOW_RESULT_ACL_OFFSET + IPN3KE_FLOW_RESULT_ACL_BITS) + +#define IPN3KE_FLOW_RESULT_UID_MAX \ + ((1UL << IPN3KE_FLOW_RESULT_UID_BITS) - 1) + +#ifndef BITS_PER_BYTE +#define BITS_PER_BYTE 8 +#endif +#define BITS_TO_BYTES(bits) \ + (((bits) + BITS_PER_BYTE - 1) / BITS_PER_BYTE) + +struct ipn3ke_flow_rule { + uint8_t key[BITS_TO_BYTES(IPN3KE_FLOW_KEY_TOTAL_BITS)]; + uint8_t result[BITS_TO_BYTES(IPN3KE_FLOW_RESULT_TOTAL_BITS)]; +}; + +struct rte_flow { + TAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */ + + struct ipn3ke_flow_rule rule; +}; + +TAILQ_HEAD(ipn3ke_flow_list, rte_flow); + +static inline uint16_t ipn3ke_swap16(uint16_t x) +{ + return ((x & 0xff) << 8) | ((x >> 8) & 0xff); +} + +static inline uint32_t ipn3ke_swap32(uint32_t x) +{ + uint32_t high, low; + uint32_t high1, low1; + + high = (x >> 16) & 0xffff; + low = x & 0xffff; + high1 = ipn3ke_swap16(low); + high1 = high1 << 16; + low1 = ipn3ke_swap16(high); + low1 = low1 & 0xffff; + + return high1 | low1; +} + +extern const struct rte_flow_ops ipn3ke_flow_ops; + +int ipn3ke_flow_init(void *dev); + +#endif /* _IPN3KE_FLOW_H_ */ diff --git a/drivers/net/ipn3ke/ipn3ke_representor.c b/drivers/net/ipn3ke/ipn3ke_representor.c index 63098bf..cf3b214 100644 --- a/drivers/net/ipn3ke/ipn3ke_representor.c +++ b/drivers/net/ipn3ke/ipn3ke_representor.c @@ -21,6 +21,7 @@ #include #include "ipn3ke_rawdev_api.h" +#include "ipn3ke_flow.h" #include "ipn3ke_logs.h" #include "ipn3ke_ethdev.h" @@ -746,7 +747,7 @@ case RTE_ETH_FILTER_GENERIC: if (filter_op != RTE_ETH_FILTER_GET) return -EINVAL; - *(const void **)arg = NULL; + *(const void **)arg = &ipn3ke_flow_ops; break; default: IPN3KE_AFU_PMD_WARN("Filter type (%d) not supported", diff --git a/drivers/net/ipn3ke/ipn3ke_tm.c b/drivers/net/ipn3ke/ipn3ke_tm.c index 4ca4c97..ef87a41 100644 --- a/drivers/net/ipn3ke/ipn3ke_tm.c +++ b/drivers/net/ipn3ke/ipn3ke_tm.c @@ -23,6 +23,7 @@ #include #include "ipn3ke_rawdev_api.h" +#include "ipn3ke_flow.h" #include "ipn3ke_logs.h" #include "ipn3ke_ethdev.h" diff --git a/drivers/net/ipn3ke/meson.build b/drivers/net/ipn3ke/meson.build index 3a95efc..74b4d7c 100644 --- a/drivers/net/ipn3ke/meson.build +++ b/drivers/net/ipn3ke/meson.build @@ -12,5 +12,6 @@ allow_experimental_apis = true sources += files('ipn3ke_ethdev.c', 'ipn3ke_representor.c', - 'ipn3ke_tm.c') + 'ipn3ke_tm.c', + 'ipn3ke_flow.c') deps += ['bus_ifpga', 'sched'] From patchwork Wed Apr 10 06:27:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52534 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 4E8B069D4; Wed, 10 Apr 2019 08:27:26 +0200 (CEST) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by dpdk.org (Postfix) with ESMTP id 2CFC369D4 for ; Wed, 10 Apr 2019 08:27:24 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 23:27:23 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,332,1549958400"; d="scan'208";a="147980924" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by FMSMGA003.fm.intel.com with ESMTP; 09 Apr 2019 23:27:20 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Wed, 10 Apr 2019 14:27:45 +0800 Message-Id: <1554877672-19745-8-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554877672-19745-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554877672-19745-1-git-send-email-rosen.xu@intel.com> Subject: [dpdk-dev] [PATCH v7 07/14] raw/ifpga_rawdev: clean up code for ifpga share code X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Tianfei zhang clean up code: 1. use opae_memcpy instead of memcpy 2. use opae_memset instead of memset 3. disable opae_adapter_dump by default Signed-off-by: Tianfei Zhang --- drivers/raw/ifpga_rawdev/base/ifpga_api.c | 2 +- drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 4 ++-- drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 2 +- drivers/raw/ifpga_rawdev/base/opae_debug.c | 16 ++++++++-------- drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 2 +- drivers/raw/ifpga_rawdev/base/opae_osdep.h | 1 + drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h | 1 + drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h | 2 ++ 8 files changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.c b/drivers/raw/ifpga_rawdev/base/ifpga_api.c index 540e171..77d9471 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_api.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -202,7 +202,7 @@ static int ifpga_adapter_enumerate(struct opae_adapter *adapter) struct ifpga_hw *hw = malloc(sizeof(*hw)); if (hw) { - memset(hw, 0, sizeof(*hw)); + opae_memset(hw, 0, sizeof(*hw)); hw->pci_data = adapter->data; hw->adapter = adapter; if (ifpga_bus_enumerate(hw)) diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c index be7ac9e..0a27c38 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -77,8 +77,8 @@ int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) guidh = readq(&port_hdr->afu_header.guid.b[8]); spinlock_unlock(&port->lock); - memcpy(uuid->b, &guidl, sizeof(u64)); - memcpy(uuid->b + 8, &guidh, sizeof(u64)); + opae_memcpy(uuid->b, &guidl, sizeof(u64)); + opae_memcpy(uuid->b + 8, &guidh, sizeof(u64)); return 0; } diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c index ec0beeb..8890f4b 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c @@ -257,7 +257,7 @@ static int fme_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, return -EINVAL; } - memset(&info, 0, sizeof(struct fpga_pr_info)); + opae_memset(&info, 0, sizeof(struct fpga_pr_info)); info.flags = FPGA_MGR_PARTIAL_RECONFIG; info.port_id = port_id; diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.c b/drivers/raw/ifpga_rawdev/base/opae_debug.c index 024d7d2..88f2d5c 100644 --- a/drivers/raw/ifpga_rawdev/base/opae_debug.c +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.c @@ -78,13 +78,13 @@ void opae_adapter_dump(struct opae_adapter *adapter, int verbose) { struct opae_accelerator *acc; - opae_log("=====%s=====\n", __func__); - opae_log("OPAE Adapter %s\n", adapter->name); - opae_log("OPAE Adapter OPs = %p\n", adapter->ops); - opae_log("OPAE Adapter Private Data = %p\n", adapter->data); - opae_log("OPAE Manager (downstream) = %p\n", adapter->mgr); - if (verbose) { + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Adapter %s\n", adapter->name); + opae_log("OPAE Adapter OPs = %p\n", adapter->ops); + opae_log("OPAE Adapter Private Data = %p\n", adapter->data); + opae_log("OPAE Manager (downstream) = %p\n", adapter->mgr); + if (adapter->mgr) opae_manager_dump(adapter->mgr); @@ -93,7 +93,7 @@ void opae_adapter_dump(struct opae_adapter *adapter, int verbose) if (adapter->data) opae_adapter_data_dump(adapter->data); - } - opae_log("==========================\n"); + opae_log("==========================\n"); + } } diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c index 1541b67..41c5903 100644 --- a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -341,7 +341,7 @@ int opae_adapter_enumerate(struct opae_adapter *adapter) ret = adapter->ops->enumerate(adapter); if (!ret) - opae_adapter_dump(adapter, 1); + opae_adapter_dump(adapter, 0); return ret; } diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h index 90f54f7..78fec50 100644 --- a/drivers/raw/ifpga_rawdev/base/opae_osdep.h +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -76,4 +76,5 @@ struct uuid { #define msleep(x) opae_udelay(1000 * (x)) #define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000)) +#define opae_memset(a, b, c) memset((a), (b), (c)) #endif diff --git a/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h index 895a1d8..6769109 100644 --- a/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h +++ b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h @@ -71,5 +71,6 @@ static inline void opae_writeq(uint64_t value, volatile void *addr) } #define opae_free(addr) free(addr) +#define opae_memcpy(a, b, c) memcpy((a), (b), (c)) #endif diff --git a/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h index 76902e2..3d9a0ca 100644 --- a/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h +++ b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h @@ -11,6 +11,7 @@ #include #include #include +#include #define dev_printf(level, fmt, args...) \ RTE_LOG(level, PMD, "osdep_rte: " fmt, ## args) @@ -42,4 +43,5 @@ #define spinlock_lock(x) rte_spinlock_lock(x) #define spinlock_unlock(x) rte_spinlock_unlock(x) +#define opae_memcpy(a, b, c) rte_memcpy((a), (b), (c)) #endif From patchwork Wed Apr 10 06:27:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52535 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id D79D86CD8; Wed, 10 Apr 2019 08:27:30 +0200 (CEST) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by dpdk.org (Postfix) with ESMTP id EFAED7CEB for ; Wed, 10 Apr 2019 08:27:28 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 23:27:28 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,332,1549958400"; d="scan'208";a="147980933" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by FMSMGA003.fm.intel.com with ESMTP; 09 Apr 2019 23:27:24 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Wed, 10 Apr 2019 14:27:46 +0800 Message-Id: <1554877672-19745-9-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554877672-19745-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554877672-19745-1-git-send-email-rosen.xu@intel.com> Subject: [dpdk-dev] [PATCH v7 08/14] raw/ifpga_rawdev: store private features in FME and Port X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Tianfei zhang Get private features attrubite like size, id, address after enumeration, and insert into FEM or Port dedicate list. when initial the private feature driver, we just compare the private feature id between the list and feature drivers array to match the proper drivers. This patch avoid the hardcore in feature_info array in previous implementation. and the same time we can use one driver for mulitple devices which the id is the same. Signed-off-by: Tianfei Zhang --- drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 46 ++- drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 347 ++++++++-------------- drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 160 +++++++--- drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 46 ++- drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 32 ++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 16 +- drivers/raw/ifpga_rawdev/base/ifpga_port.c | 21 ++ 7 files changed, 363 insertions(+), 305 deletions(-) diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h index aa02527..217d0b1 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -15,6 +15,7 @@ #define FME_FEATURE_GLOBAL_IPERF "fme_iperf" #define FME_FEATURE_GLOBAL_ERR "fme_error" #define FME_FEATURE_PR_MGMT "fme_pr" +#define FME_FEATURE_EMIF_MGMT "fme_emif" #define FME_FEATURE_HSSI_ETH "fme_hssi" #define FME_FEATURE_GLOBAL_DPERF "fme_dperf" #define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" @@ -59,7 +60,8 @@ #define FEATURE_FIU_ID_FME 0x0 #define FEATURE_FIU_ID_PORT 0x1 -#define FEATURE_ID_HEADER 0x0 +/* Reserved 0xfe for Header, 0xff for AFU*/ +#define FEATURE_ID_FIU_HEADER 0xfe #define FEATURE_ID_AFU 0xff enum fpga_id_type { @@ -68,31 +70,23 @@ enum fpga_id_type { FPGA_ID_MAX, }; -enum fme_feature_id { - FME_FEATURE_ID_HEADER = 0x0, - - FME_FEATURE_ID_THERMAL_MGMT = 0x1, - FME_FEATURE_ID_POWER_MGMT = 0x2, - FME_FEATURE_ID_GLOBAL_IPERF = 0x3, - FME_FEATURE_ID_GLOBAL_ERR = 0x4, - FME_FEATURE_ID_PR_MGMT = 0x5, - FME_FEATURE_ID_HSSI_ETH = 0x6, - FME_FEATURE_ID_GLOBAL_DPERF = 0x7, - FME_FEATURE_ID_QSPI_FLASH = 0x8, - - /* one for fme header. */ - FME_FEATURE_ID_MAX = 0x9, -}; - -enum port_feature_id { - PORT_FEATURE_ID_HEADER = 0x0, - PORT_FEATURE_ID_ERROR = 0x1, - PORT_FEATURE_ID_UMSG = 0x2, - PORT_FEATURE_ID_UINT = 0x3, - PORT_FEATURE_ID_STP = 0x4, - PORT_FEATURE_ID_UAFU = 0x5, - PORT_FEATURE_ID_MAX = 0x6, -}; +#define FME_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER +#define FME_FEATURE_ID_THERMAL_MGMT 0x1 +#define FME_FEATURE_ID_POWER_MGMT 0x2 +#define FME_FEATURE_ID_GLOBAL_IPERF 0x3 +#define FME_FEATURE_ID_GLOBAL_ERR 0x4 +#define FME_FEATURE_ID_PR_MGMT 0x5 +#define FME_FEATURE_ID_HSSI_ETH 0x6 +#define FME_FEATURE_ID_GLOBAL_DPERF 0x7 +#define FME_FEATURE_ID_QSPI_FLASH 0x8 +#define FME_FEATURE_ID_EMIF_MGMT 0x9 + +#define PORT_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER +#define PORT_FEATURE_ID_ERROR 0x10 +#define PORT_FEATURE_ID_UMSG 0x12 +#define PORT_FEATURE_ID_UINT 0x13 +#define PORT_FEATURE_ID_STP 0x14 +#define PORT_FEATURE_ID_UAFU FEATURE_ID_AFU /* * All headers and structures must be byte-packed to match the spec. diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c index 848e518..c779e0c 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -28,121 +28,24 @@ struct build_feature_devs_info { struct ifpga_hw *hw; }; -struct feature_info { - const char *name; - u32 resource_size; - int feature_index; - int revision_id; - unsigned int vec_start; - unsigned int vec_cnt; - - struct feature_ops *ops; -}; +static int feature_revision(void __iomem *start) +{ + struct feature_header header; -/* indexed by fme feature IDs which are defined in 'enum fme_feature_id'. */ -static struct feature_info fme_features[] = { - { - .name = FME_FEATURE_HEADER, - .resource_size = sizeof(struct feature_fme_header), - .feature_index = FME_FEATURE_ID_HEADER, - .revision_id = FME_HEADER_REVISION, - .ops = &fme_hdr_ops, - }, - { - .name = FME_FEATURE_THERMAL_MGMT, - .resource_size = sizeof(struct feature_fme_thermal), - .feature_index = FME_FEATURE_ID_THERMAL_MGMT, - .revision_id = FME_THERMAL_MGMT_REVISION, - .ops = &fme_thermal_mgmt_ops, - }, - { - .name = FME_FEATURE_POWER_MGMT, - .resource_size = sizeof(struct feature_fme_power), - .feature_index = FME_FEATURE_ID_POWER_MGMT, - .revision_id = FME_POWER_MGMT_REVISION, - .ops = &fme_power_mgmt_ops, - }, - { - .name = FME_FEATURE_GLOBAL_IPERF, - .resource_size = sizeof(struct feature_fme_iperf), - .feature_index = FME_FEATURE_ID_GLOBAL_IPERF, - .revision_id = FME_GLOBAL_IPERF_REVISION, - .ops = &fme_global_iperf_ops, - }, - { - .name = FME_FEATURE_GLOBAL_ERR, - .resource_size = sizeof(struct feature_fme_err), - .feature_index = FME_FEATURE_ID_GLOBAL_ERR, - .revision_id = FME_GLOBAL_ERR_REVISION, - .ops = &fme_global_err_ops, - }, - { - .name = FME_FEATURE_PR_MGMT, - .resource_size = sizeof(struct feature_fme_pr), - .feature_index = FME_FEATURE_ID_PR_MGMT, - .revision_id = FME_PR_MGMT_REVISION, - .ops = &fme_pr_mgmt_ops, - }, - { - .name = FME_FEATURE_HSSI_ETH, - .resource_size = sizeof(struct feature_fme_hssi), - .feature_index = FME_FEATURE_ID_HSSI_ETH, - .revision_id = FME_HSSI_ETH_REVISION - }, - { - .name = FME_FEATURE_GLOBAL_DPERF, - .resource_size = sizeof(struct feature_fme_dperf), - .feature_index = FME_FEATURE_ID_GLOBAL_DPERF, - .revision_id = FME_GLOBAL_DPERF_REVISION, - .ops = &fme_global_dperf_ops, - } -}; + header.csr = readq(start); -static struct feature_info port_features[] = { - { - .name = PORT_FEATURE_HEADER, - .resource_size = sizeof(struct feature_port_header), - .feature_index = PORT_FEATURE_ID_HEADER, - .revision_id = PORT_HEADER_REVISION, - .ops = &ifpga_rawdev_port_hdr_ops, - }, - { - .name = PORT_FEATURE_ERR, - .resource_size = sizeof(struct feature_port_error), - .feature_index = PORT_FEATURE_ID_ERROR, - .revision_id = PORT_ERR_REVISION, - .ops = &ifpga_rawdev_port_error_ops, - }, - { - .name = PORT_FEATURE_UMSG, - .resource_size = sizeof(struct feature_port_umsg), - .feature_index = PORT_FEATURE_ID_UMSG, - .revision_id = PORT_UMSG_REVISION, - }, - { - .name = PORT_FEATURE_UINT, - .resource_size = sizeof(struct feature_port_uint), - .feature_index = PORT_FEATURE_ID_UINT, - .revision_id = PORT_UINT_REVISION, - .ops = &ifpga_rawdev_port_uint_ops, - }, - { - .name = PORT_FEATURE_STP, - .resource_size = PORT_FEATURE_STP_REGION_SIZE, - .feature_index = PORT_FEATURE_ID_STP, - .revision_id = PORT_STP_REVISION, - .ops = &ifpga_rawdev_port_stp_ops, - }, - { - .name = PORT_FEATURE_UAFU, - /* UAFU feature size should be read from PORT_CAP.MMIOSIZE. - * Will set uafu feature size while parse port device. - */ - .resource_size = 0, - .feature_index = PORT_FEATURE_ID_UAFU, - .revision_id = PORT_UAFU_REVISION - }, -}; + return header.revision; +} + +static u32 feature_size(void __iomem *start) +{ + struct feature_header header; + + header.csr = readq(start); + + /*the size of private feature is 4KB aligned*/ + return header.next_header_offset ? header.next_header_offset:4096; +} static u64 feature_id(void __iomem *start) { @@ -152,7 +55,7 @@ static u64 feature_id(void __iomem *start) switch (header.type) { case FEATURE_TYPE_FIU: - return FEATURE_ID_HEADER; + return FEATURE_ID_FIU_HEADER; case FEATURE_TYPE_PRIVATE: return header.id; case FEATURE_TYPE_AFU: @@ -165,37 +68,36 @@ static u64 feature_id(void __iomem *start) static int build_info_add_sub_feature(struct build_feature_devs_info *binfo, - struct feature_info *finfo, void __iomem *start) + void __iomem *start, u64 fid, unsigned int size, + unsigned int vec_start, + unsigned int vec_cnt) { struct ifpga_hw *hw = binfo->hw; struct feature *feature = NULL; - int feature_idx = finfo->feature_index; - unsigned int vec_start = finfo->vec_start; - unsigned int vec_cnt = finfo->vec_cnt; struct feature_irq_ctx *ctx = NULL; int port_id, ret = 0; unsigned int i; - if (binfo->current_type == FME_ID) { - feature = &hw->fme.sub_feature[feature_idx]; - feature->parent = &hw->fme; - } else if (binfo->current_type == PORT_ID) { - port_id = binfo->current_port_id; - feature = &hw->port[port_id].sub_feature[feature_idx]; - feature->parent = &hw->port[port_id]; - } else { - return -EFAULT; - } + fid = fid?fid:feature_id(start); + size = size?size:feature_size(start); + + feature = opae_malloc(sizeof(struct feature)); + if (!feature) + return -ENOMEM; feature->state = IFPGA_FEATURE_ATTACHED; feature->addr = start; - feature->id = feature_id(start); - feature->size = finfo->resource_size; - feature->name = finfo->name; - feature->revision = finfo->revision_id; - feature->ops = finfo->ops; + feature->id = fid; + feature->size = size; + feature->revision = feature_revision(start); feature->phys_addr = binfo->phys_addr + ((u8 *)start - (u8 *)binfo->ioaddr); + feature->vec_start = vec_start; + feature->vec_cnt = vec_cnt; + + dev_debug(binfo, "%s: id=0x%llx, phys_addr=0x%llx, size=%u\n", + __func__, (unsigned long long)feature->id, + (unsigned long long)feature->phys_addr, size); if (vec_cnt) { if (vec_start + vec_cnt <= vec_start) @@ -215,22 +117,32 @@ static u64 feature_id(void __iomem *start) feature->ctx_num = vec_cnt; feature->vfio_dev_fd = binfo->pci_data->vfio_dev_fd; + if (binfo->current_type == FME_ID) { + feature->parent = &hw->fme; + feature->type = FEATURE_FME_TYPE; + feature->name = get_fme_feature_name(fid); + TAILQ_INSERT_TAIL(&hw->fme.feature_list, feature, next); + } else if (binfo->current_type == PORT_ID) { + port_id = binfo->current_port_id; + feature->parent = &hw->port[port_id]; + feature->type = FEATURE_PORT_TYPE; + feature->name = get_port_feature_name(fid); + TAILQ_INSERT_TAIL(&hw->port[port_id].feature_list, + feature, next); + } else { + return -EFAULT; + } return ret; } static int create_feature_instance(struct build_feature_devs_info *binfo, - void __iomem *start, struct feature_info *finfo) + void __iomem *start, u64 fid, + unsigned int size, unsigned int vec_start, + unsigned int vec_cnt) { - struct feature_header *hdr = start; - - if (finfo->revision_id != SKIP_REVISION_CHECK && - hdr->revision > finfo->revision_id) { - dev_err(binfo, "feature %s revision :default:%x, now at:%x, mis-match.\n", - finfo->name, finfo->revision_id, hdr->revision); - } - - return build_info_add_sub_feature(binfo, finfo, start); + return build_info_add_sub_feature(binfo, start, fid, size, vec_start, + vec_cnt); } /* @@ -249,31 +161,30 @@ static bool feature_is_UAFU(struct build_feature_devs_info *binfo) static int parse_feature_port_uafu(struct build_feature_devs_info *binfo, struct feature_header *hdr) { - enum port_feature_id id = PORT_FEATURE_ID_UAFU; + u64 id = PORT_FEATURE_ID_UAFU; struct ifpga_afu_info *info; void *start = (void *)hdr; + struct feature_port_header *port_hdr = binfo->ioaddr; + struct feature_port_capability capability; int ret; + int size; - if (port_features[id].resource_size) { - ret = create_feature_instance(binfo, hdr, &port_features[id]); - } else { - dev_err(binfo, "the uafu feature header is mis-configured.\n"); - ret = -EINVAL; - } + capability.csr = readq(&port_hdr->capability); + + size = capability.mmio_size << 10; + ret = create_feature_instance(binfo, hdr, id, size, 0, 0); if (ret) return ret; - /* FIXME: need to figure out a better name */ - info = malloc(sizeof(*info)); + info = opae_malloc(sizeof(*info)); if (!info) return -ENOMEM; info->region[0].addr = start; info->region[0].phys_addr = binfo->phys_addr + (uint8_t *)start - (uint8_t *)binfo->ioaddr; - info->region[0].len = port_features[id].resource_size; - port_features[id].resource_size = 0; + info->region[0].len = size; info->num_regions = 1; binfo->acc_info = info; @@ -320,6 +231,8 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) struct opae_manager *mgr; struct opae_bridge *br; struct opae_accelerator *acc; + struct ifpga_port_hw *port; + struct feature *feature; if (!binfo->fiu) return 0; @@ -337,7 +250,11 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) br->id = binfo->current_port_id; /* update irq info */ - info->num_irqs = port_features[PORT_FEATURE_ID_UINT].vec_cnt; + port = &hw->port[binfo->current_port_id]; + feature = get_feature_by_id(&port->feature_list, + PORT_FEATURE_ID_UINT); + if (feature) + info->num_irqs = feature->vec_cnt; acc = opae_accelerator_alloc(hw->adapter->name, &ifpga_acc_ops, info); @@ -353,7 +270,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) } else if (binfo->current_type == FME_ID) { mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops, - binfo->fiu); + binfo->fiu); if (!mgr) return -ENOMEM; @@ -402,10 +319,10 @@ static int parse_feature_fme(struct build_feature_devs_info *binfo, /* Update FME states */ fme->state = IFPGA_FME_IMPLEMENTED; fme->parent = hw; + TAILQ_INIT(&fme->feature_list); spinlock_init(&fme->lock); - return create_feature_instance(binfo, start, - &fme_features[FME_FEATURE_ID_HEADER]); + return create_feature_instance(binfo, start, 0, 0, 0, 0); } static int parse_feature_port(struct build_feature_devs_info *binfo, @@ -433,29 +350,19 @@ static int parse_feature_port(struct build_feature_devs_info *binfo, port->parent = hw; port->state = IFPGA_PORT_ATTACHED; spinlock_init(&port->lock); + TAILQ_INIT(&port->feature_list); - return create_feature_instance(binfo, start, - &port_features[PORT_FEATURE_ID_HEADER]); + return create_feature_instance(binfo, start, 0, 0, 0, 0); } static void enable_port_uafu(struct build_feature_devs_info *binfo, void __iomem *start) { - enum port_feature_id id = PORT_FEATURE_ID_UAFU; - struct feature_port_header *port_hdr; - struct feature_port_capability capability; struct ifpga_port_hw *port = &binfo->hw->port[binfo->current_port_id]; - port_hdr = (struct feature_port_header *)start; - capability.csr = readq(&port_hdr->capability); - port_features[id].resource_size = (capability.mmio_size << 10); - - /* - * From spec, to Enable UAFU, we should reset related port, - * or the whole mmio space in this UAFU will be invalid - */ - if (port_features[id].resource_size) - fpga_port_reset(port); + UNUSED(start); + + fpga_port_reset(port); } static int parse_feature_fiu(struct build_feature_devs_info *binfo, @@ -505,44 +412,45 @@ static int parse_feature_fiu(struct build_feature_devs_info *binfo, } static void parse_feature_irqs(struct build_feature_devs_info *binfo, - void __iomem *start, struct feature_info *finfo) + void __iomem *start, unsigned int *vec_start, + unsigned int *vec_cnt) { - finfo->vec_start = 0; - finfo->vec_cnt = 0; - UNUSED(binfo); + u64 id; + + id = feature_id(start); - if (!strcmp(finfo->name, PORT_FEATURE_UINT)) { + if (id == PORT_FEATURE_ID_UINT) { struct feature_port_uint *port_uint = start; struct feature_port_uint_cap uint_cap; uint_cap.csr = readq(&port_uint->capability); if (uint_cap.intr_num) { - finfo->vec_start = uint_cap.first_vec_num; - finfo->vec_cnt = uint_cap.intr_num; + *vec_start = uint_cap.first_vec_num; + *vec_cnt = uint_cap.intr_num; } else { dev_debug(binfo, "UAFU doesn't support interrupt\n"); } - } else if (!strcmp(finfo->name, PORT_FEATURE_ERR)) { + } else if (id == PORT_FEATURE_ID_ERROR) { struct feature_port_error *port_err = start; struct feature_port_err_capability port_err_cap; port_err_cap.csr = readq(&port_err->error_capability); if (port_err_cap.support_intr) { - finfo->vec_start = port_err_cap.intr_vector_num; - finfo->vec_cnt = 1; + *vec_start = port_err_cap.intr_vector_num; + *vec_cnt = 1; } else { dev_debug(&binfo, "Port error doesn't support interrupt\n"); } - } else if (!strcmp(finfo->name, FME_FEATURE_GLOBAL_ERR)) { + } else if (id == FME_FEATURE_ID_GLOBAL_ERR) { struct feature_fme_err *fme_err = start; struct feature_fme_error_capability fme_err_cap; fme_err_cap.csr = readq(&fme_err->fme_err_capability); if (fme_err_cap.support_intr) { - finfo->vec_start = fme_err_cap.intr_vector_num; - finfo->vec_cnt = 1; + *vec_start = fme_err_cap.intr_vector_num; + *vec_cnt = 1; } else { dev_debug(&binfo, "FME error doesn't support interrupt\n"); } @@ -552,43 +460,23 @@ static void parse_feature_irqs(struct build_feature_devs_info *binfo, static int parse_feature_fme_private(struct build_feature_devs_info *binfo, struct feature_header *hdr) { - struct feature_header header; - - header.csr = readq(hdr); - - if (header.id >= ARRAY_SIZE(fme_features)) { - dev_err(binfo, "FME feature id %x is not supported yet.\n", - header.id); - return 0; - } + unsigned int vec_start = 0; + unsigned int vec_cnt = 0; - parse_feature_irqs(binfo, hdr, &fme_features[header.id]); + parse_feature_irqs(binfo, hdr, &vec_start, &vec_cnt); - return create_feature_instance(binfo, hdr, &fme_features[header.id]); + return create_feature_instance(binfo, hdr, 0, 0, vec_start, vec_cnt); } static int parse_feature_port_private(struct build_feature_devs_info *binfo, struct feature_header *hdr) { - struct feature_header header; - enum port_feature_id id; + unsigned int vec_start = 0; + unsigned int vec_cnt = 0; - header.csr = readq(hdr); - /* - * the region of port feature id is [0x10, 0x13], + 1 to reserve 0 - * which is dedicated for port-hdr. - */ - id = (header.id & 0x000f) + 1; - - if (id >= ARRAY_SIZE(port_features)) { - dev_err(binfo, "Port feature id %x is not supported yet.\n", - header.id); - return 0; - } - - parse_feature_irqs(binfo, hdr, &port_features[id]); + parse_feature_irqs(binfo, hdr, &vec_start, &vec_cnt); - return create_feature_instance(binfo, hdr, &port_features[id]); + return create_feature_instance(binfo, hdr, 0, 0, vec_start, vec_cnt); } static int parse_feature_private(struct build_feature_devs_info *binfo, @@ -651,12 +539,18 @@ static int parse_feature(struct build_feature_devs_info *binfo, } hdr = (struct feature_header *)start; + header.csr = readq(hdr); + + dev_debug(binfo, "%s: address=0x%p, val=0x%llx, header.id=0x%x, header.next_offset=0x%x, header.eol=0x%x, header.type=0x%x\n", + __func__, hdr, (unsigned long long)header.csr, + header.id, header.next_header_offset, + header.end_of_list, header.type); + ret = parse_feature(binfo, hdr); if (ret) return ret; - header.csr = readq(hdr); - if (!header.next_header_offset) + if (header.end_of_list || !header.next_header_offset) break; } @@ -746,20 +640,20 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw) struct ifpga_fme_hw *fme = &hw->fme; struct ifpga_port_hw *port; struct feature *feature; - int i, j; + int i; dev_info(hw, "found fme_device, is in PF: %s\n", is_ifpga_hw_pf(hw) ? "yes" : "no"); - for (i = 0; i < FME_FEATURE_ID_MAX; i++) { - feature = &fme->sub_feature[i]; + ifpga_for_each_fme_feature(fme, feature) { if (feature->state != IFPGA_FEATURE_ATTACHED) continue; - dev_info(hw, "%12s: 0x%p - 0x%p - paddr: 0x%lx\n", + dev_info(hw, "%12s: %p - %p - paddr: 0x%lx\n", feature->name, feature->addr, feature->addr + feature->size - 1, (unsigned long)feature->phys_addr); + } for (i = 0; i < MAX_FPGA_PORT_NUM; i++) { @@ -770,18 +664,18 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw) dev_info(hw, "port device: %d\n", port->port_id); - for (j = 0; j < PORT_FEATURE_ID_MAX; j++) { - feature = &port->sub_feature[j]; + ifpga_for_each_port_feature(port, feature) { if (feature->state != IFPGA_FEATURE_ATTACHED) continue; - dev_info(hw, "%12s: 0x%p - 0x%p - paddr:0x%lx\n", + dev_info(hw, "%12s: %p - %p - paddr:0x%lx\n", feature->name, feature->addr, feature->addr + feature->size - 1, (unsigned long)feature->phys_addr); } + } } @@ -812,10 +706,13 @@ int ifpga_bus_enumerate(struct ifpga_hw *hw) int ifpga_bus_init(struct ifpga_hw *hw) { int i; + struct ifpga_port_hw *port; fme_hw_init(&hw->fme); - for (i = 0; i < MAX_FPGA_PORT_NUM; i++) - port_hw_init(&hw->port[i]); + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) { + port = &hw->port[i]; + port_hw_init(port); + } return 0; } diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c index 0a27c38..d82a890 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -70,6 +70,9 @@ int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) struct feature_port_header *port_hdr; u64 guidl, guidh; + if (!uuid) + return -EINVAL; + port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU); spinlock_lock(&port->lock); @@ -177,77 +180,146 @@ int port_clear_error(struct ifpga_port_hw *port) return port_err_clear(port, error.csr); } -void fme_hw_uinit(struct ifpga_fme_hw *fme) +static struct feature_driver fme_feature_drvs[] = { + {FEATURE_DRV(FME_FEATURE_ID_HEADER, FME_FEATURE_HEADER, + &fme_hdr_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_THERMAL_MGMT, FME_FEATURE_THERMAL_MGMT, + &fme_thermal_mgmt_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_POWER_MGMT, FME_FEATURE_POWER_MGMT, + &fme_power_mgmt_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_GLOBAL_ERR, FME_FEATURE_GLOBAL_ERR, + &fme_global_err_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_PR_MGMT, FME_FEATURE_PR_MGMT, + &fme_pr_mgmt_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_GLOBAL_DPERF, FME_FEATURE_GLOBAL_DPERF, + &fme_global_dperf_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_HSSI_ETH, FME_FEATURE_HSSI_ETH, + &fme_hssi_eth_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_EMIF_MGMT, FME_FEATURE_EMIF_MGMT, + &fme_emif_ops),}, + {0, NULL, NULL}, /* end of arrary */ +}; + +static struct feature_driver port_feature_drvs[] = { + {FEATURE_DRV(PORT_FEATURE_ID_HEADER, PORT_FEATURE_HEADER, + &ifpga_rawdev_port_hdr_ops)}, + {FEATURE_DRV(PORT_FEATURE_ID_ERROR, PORT_FEATURE_ERR, + &ifpga_rawdev_port_error_ops)}, + {FEATURE_DRV(PORT_FEATURE_ID_UINT, PORT_FEATURE_UINT, + &ifpga_rawdev_port_uint_ops)}, + {FEATURE_DRV(PORT_FEATURE_ID_STP, PORT_FEATURE_STP, + &ifpga_rawdev_port_stp_ops)}, + {FEATURE_DRV(PORT_FEATURE_ID_UAFU, PORT_FEATURE_UAFU, + &ifpga_rawdev_port_afu_ops)}, + {0, NULL, NULL}, /* end of array */ +}; + +const char *get_fme_feature_name(unsigned int id) { - struct feature *feature; - int i; + struct feature_driver *drv = fme_feature_drvs; - if (fme->state != IFPGA_FME_IMPLEMENTED) - return; + while (drv->name) { + if (drv->id == id) + return drv->name; - for (i = 0; i < FME_FEATURE_ID_MAX; i++) { - feature = &fme->sub_feature[i]; - if (feature->state == IFPGA_FEATURE_ATTACHED && - feature->ops && feature->ops->uinit) - feature->ops->uinit(feature); + drv++; } + + return NULL; } -int fme_hw_init(struct ifpga_fme_hw *fme) +const char *get_port_feature_name(unsigned int id) +{ + struct feature_driver *drv = port_feature_drvs; + + while (drv->name) { + if (drv->id == id) + return drv->name; + + drv++; + } + + return NULL; +} + +static void feature_uinit(struct ifpga_feature_list *list) { struct feature *feature; - int i, ret; - if (fme->state != IFPGA_FME_IMPLEMENTED) - return -EINVAL; + TAILQ_FOREACH(feature, list, next) { + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + if (feature->ops && feature->ops->uinit) + feature->ops->uinit(feature); + } +} - for (i = 0; i < FME_FEATURE_ID_MAX; i++) { - feature = &fme->sub_feature[i]; - if (feature->state == IFPGA_FEATURE_ATTACHED && - feature->ops && feature->ops->init) { - ret = feature->ops->init(feature); - if (ret) { - fme_hw_uinit(fme); - return ret; +static int feature_init(struct feature_driver *drv, + struct ifpga_feature_list *list) +{ + struct feature *feature; + int ret; + + while (drv->ops) { + TAILQ_FOREACH(feature, list, next) { + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + if (feature->id == drv->id) { + feature->ops = drv->ops; + feature->name = drv->name; + if (feature->ops->init) { + ret = feature->ops->init(feature); + if (ret) + goto error; + } } } + drv++; } return 0; +error: + feature_uinit(list); + return ret; } -void port_hw_uinit(struct ifpga_port_hw *port) +int fme_hw_init(struct ifpga_fme_hw *fme) { - struct feature *feature; - int i; + int ret; - for (i = 0; i < PORT_FEATURE_ID_MAX; i++) { - feature = &port->sub_feature[i]; - if (feature->state == IFPGA_FEATURE_ATTACHED && - feature->ops && feature->ops->uinit) - feature->ops->uinit(feature); - } + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -ENODEV; + + ret = feature_init(fme_feature_drvs, &fme->feature_list); + if (ret) + return ret; + + return 0; +} + +void fme_hw_uinit(struct ifpga_fme_hw *fme) +{ + feature_uinit(&fme->feature_list); +} + +void port_hw_uinit(struct ifpga_port_hw *port) +{ + feature_uinit(&port->feature_list); } int port_hw_init(struct ifpga_port_hw *port) { - struct feature *feature; - int i, ret; + int ret; if (port->state == IFPGA_PORT_UNUSED) return 0; - for (i = 0; i < PORT_FEATURE_ID_MAX; i++) { - feature = &port->sub_feature[i]; - if (feature->ops && feature->ops->init) { - ret = feature->ops->init(feature); - if (ret) { - port_hw_uinit(port); - return ret; - } - } - } + ret = feature_init(port_feature_drvs, &port->feature_list); + if (ret) + goto error; return 0; +error: + port_hw_uinit(port); + return ret; } - diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h index 4391f2f..1d80f1d 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -7,6 +7,18 @@ #include "ifpga_hw.h" +struct feature_driver { + u64 id; + const char *name; + struct feature_ops *ops; +}; + +/** + * FEATURE_DRV - macro used to describe a specific feature driver + */ +#define FEATURE_DRV(n, s, p) \ + .id = (n), .name = (s), .ops = (p) + static inline struct ifpga_port_hw * get_port(struct ifpga_hw *hw, u32 port_id) { @@ -17,12 +29,10 @@ } #define ifpga_for_each_fme_feature(hw, feature) \ - for ((feature) = (hw)->sub_feature; \ - (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++) + TAILQ_FOREACH(feature, &hw->feature_list, next) -#define ifpga_for_each_port_feature(hw, feature) \ - for ((feature) = (hw)->sub_feature; \ - (feature) < (hw)->sub_feature + (PORT_FEATURE_ID_MAX); (feature)++) +#define ifpga_for_each_port_feature(port, feature) \ + TAILQ_FOREACH(feature, &port->feature_list, next) static inline struct feature * get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) @@ -50,16 +60,32 @@ return NULL; } +static inline struct feature * +get_feature_by_id(struct ifpga_feature_list *list, u64 id) +{ + struct feature *feature; + + TAILQ_FOREACH(feature, list, next) + if (feature->id == id) + return feature; + + return NULL; +} + static inline void * get_fme_feature_ioaddr_by_index(struct ifpga_fme_hw *fme, int index) { - return fme->sub_feature[index].addr; + struct feature *feature = get_feature_by_id(&fme->feature_list, index); + + return feature ? feature->addr : NULL; } static inline void * get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index) { - return port->sub_feature[index].addr; + struct feature *feature = get_feature_by_id(&port->feature_list, index); + + return feature ? feature->addr : NULL; } static inline bool @@ -143,6 +169,8 @@ int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, extern struct feature_ops fme_pr_mgmt_ops; extern struct feature_ops fme_global_iperf_ops; extern struct feature_ops fme_global_dperf_ops; +extern struct feature_ops fme_hssi_eth_ops; +extern struct feature_ops fme_emif_ops; int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop); int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop); @@ -155,14 +183,16 @@ struct fpga_uafu_irq_set { }; int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set); +const char *get_fme_feature_name(unsigned int id); +const char *get_port_feature_name(unsigned int id); extern struct feature_ops ifpga_rawdev_port_hdr_ops; extern struct feature_ops ifpga_rawdev_port_error_ops; extern struct feature_ops ifpga_rawdev_port_stp_ops; extern struct feature_ops ifpga_rawdev_port_uint_ops; +extern struct feature_ops ifpga_rawdev_port_afu_ops; /* help functions for feature ops */ int fpga_msix_set_block(struct feature *feature, unsigned int start, unsigned int count, s32 *fds); - #endif /* _IFPGA_FEATURE_DEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c index 4be60c0..9451086 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_fme.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -732,3 +732,35 @@ struct feature_ops fme_power_mgmt_ops = { .get_prop = fme_power_mgmt_get_prop, .set_prop = fme_power_mgmt_set_prop, }; + +static int fme_hssi_eth_init(struct feature *feature) +{ + UNUSED(feature); + return 0; +} + +static void fme_hssi_eth_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +struct feature_ops fme_hssi_eth_ops = { + .init = fme_hssi_eth_init, + .uinit = fme_hssi_eth_uinit, +}; + +static int fme_emif_init(struct feature *feature) +{ + UNUSED(feature); + return 0; +} + +static void fme_emif_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +struct feature_ops fme_emif_ops = { + .init = fme_emif_init, + .uinit = fme_emif_uinit, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_hw.h b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h index a20520c..8aaa056 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_hw.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -8,18 +8,28 @@ #include "ifpga_defines.h" #include "opae_ifpga_hw_api.h" +/** List of private feateues */ +TAILQ_HEAD(ifpga_feature_list, feature); + enum ifpga_feature_state { IFPGA_FEATURE_UNUSED = 0, IFPGA_FEATURE_ATTACHED, }; +enum feature_type { + FEATURE_FME_TYPE = 0, + FEATURE_PORT_TYPE, +}; + struct feature_irq_ctx { int eventfd; int idx; }; struct feature { + TAILQ_ENTRY(feature)next; enum ifpga_feature_state state; + enum feature_type type; const char *name; u64 id; u8 *addr; @@ -34,6 +44,8 @@ struct feature { void *parent; /* to parent hw data structure */ struct feature_ops *ops;/* callback to this private feature */ + unsigned int vec_start; + unsigned int vec_cnt; }; struct feature_ops { @@ -52,7 +64,7 @@ enum ifpga_fme_state { struct ifpga_fme_hw { enum ifpga_fme_state state; - struct feature sub_feature[FME_FEATURE_ID_MAX]; + struct ifpga_feature_list feature_list; spinlock_t lock; /* protect hardware access */ void *parent; /* pointer to ifpga_hw */ @@ -78,7 +90,7 @@ enum ifpga_port_state { struct ifpga_port_hw { enum ifpga_port_state state; - struct feature sub_feature[PORT_FEATURE_ID_MAX]; + struct ifpga_feature_list feature_list; spinlock_t lock; /* protect access to hw */ void *parent; /* pointer to ifpga_hw */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c index 8b5668d..4628783 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_port.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c @@ -386,3 +386,24 @@ struct feature_ops ifpga_rawdev_port_uint_ops = { .init = port_uint_init, .uinit = port_uint_uinit, }; + +static int port_afu_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT AFU Init.\n"); + + return 0; +} + +static void port_afu_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT AFU UInit.\n"); +} + +struct feature_ops ifpga_rawdev_port_afu_ops = { + .init = port_afu_init, + .uinit = port_afu_uinit, +}; From patchwork Wed Apr 10 06:27:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52536 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 5FC621B104; Wed, 10 Apr 2019 08:27:37 +0200 (CEST) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by dpdk.org (Postfix) with ESMTP id 9DF747D4A for ; Wed, 10 Apr 2019 08:27:33 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 23:27:33 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,332,1549958400"; d="scan'208";a="147980939" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by FMSMGA003.fm.intel.com with ESMTP; 09 Apr 2019 23:27:29 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Wed, 10 Apr 2019 14:27:47 +0800 Message-Id: <1554877672-19745-10-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554877672-19745-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554877672-19745-1-git-send-email-rosen.xu@intel.com> Subject: [dpdk-dev] [PATCH v7 09/14] raw/ifpga_rawdev: add SPI and MAX10 device driver X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Tianfei zhang There is a SPI bus link between A10 FPGA and MAX10 FPGA. MAX10 is in charge of board management, like power management, sensors, flash devices. Signed-off-by: Tianfei Zhang --- drivers/raw/ifpga_rawdev/base/Makefile | 3 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 5 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 4 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 2 + drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 196 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 2 + drivers/raw/ifpga_rawdev/base/meson.build | 5 +- drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 1 + drivers/raw/ifpga_rawdev/base/opae_intel_max10.c | 88 +++++ drivers/raw/ifpga_rawdev/base/opae_intel_max10.h | 60 +++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 4 + drivers/raw/ifpga_rawdev/base/opae_spi.c | 304 ++++++++++++++ drivers/raw/ifpga_rawdev/base/opae_spi.h | 160 ++++++++ .../raw/ifpga_rawdev/base/opae_spi_transaction.c | 438 +++++++++++++++++++++ .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 14 + 15 files changed, 1285 insertions(+), 1 deletion(-) create mode 100644 drivers/raw/ifpga_rawdev/base/opae_intel_max10.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_intel_max10.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_spi.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_spi.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_spi_transaction.c diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile index d79da72..c6f51a8 100644 --- a/drivers/raw/ifpga_rawdev/base/Makefile +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -22,5 +22,8 @@ SRCS-y += opae_hw_api.c SRCS-y += opae_ifpga_hw_api.c SRCS-y += opae_debug.c SRCS-y += ifpga_fme_pr.c +SRCS-y += opae_spi.c +SRCS-y += opae_spi_transaction.c +SRCS-y += opae_intel_max10.c SRCS-y += $(wildcard $(SRCDIR)/base/$(OSDEP)/*.c) diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h index 217d0b1..f5e22ae 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -19,6 +19,8 @@ #define FME_FEATURE_HSSI_ETH "fme_hssi" #define FME_FEATURE_GLOBAL_DPERF "fme_dperf" #define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" +#define FME_FEATURE_MAX10_SPI "fme_max10_spi" +#define FME_FEATURE_NIOS_SPI "fme_nios_spi" #define PORT_FEATURE_HEADER "port_hdr" #define PORT_FEATURE_UAFU "port_uafu" @@ -43,6 +45,7 @@ #define FME_HSSI_ETH_REVISION 0 #define FME_GLOBAL_DPERF_REVISION 0 #define FME_QSPI_REVISION 0 +#define FME_MAX10_SPI 0 #define PORT_HEADER_REVISION 0 /* UAFU's header info depends on the downloaded GBS */ @@ -80,6 +83,8 @@ enum fpga_id_type { #define FME_FEATURE_ID_GLOBAL_DPERF 0x7 #define FME_FEATURE_ID_QSPI_FLASH 0x8 #define FME_FEATURE_ID_EMIF_MGMT 0x9 +#define FME_FEATURE_ID_MAX10_SPI 0xe +#define FME_FEATURE_ID_NIOS_SPI 0xd #define PORT_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER #define PORT_FEATURE_ID_ERROR 0x10 diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c index d82a890..2a35c06 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -197,6 +197,10 @@ int port_clear_error(struct ifpga_port_hw *port) &fme_hssi_eth_ops),}, {FEATURE_DRV(FME_FEATURE_ID_EMIF_MGMT, FME_FEATURE_EMIF_MGMT, &fme_emif_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_MAX10_SPI, FME_FEATURE_MAX10_SPI, + &fme_spi_master_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_NIOS_SPI, FME_FEATURE_NIOS_SPI, + &fme_nios_spi_master_ops),}, {0, NULL, NULL}, /* end of arrary */ }; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h index 1d80f1d..72352ee 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -171,6 +171,8 @@ int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, extern struct feature_ops fme_global_dperf_ops; extern struct feature_ops fme_hssi_eth_ops; extern struct feature_ops fme_emif_ops; +extern struct feature_ops fme_spi_master_ops; +extern struct feature_ops fme_nios_spi_master_ops; int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop); int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop); diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c index 9451086..28226f0 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_fme.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -3,6 +3,8 @@ */ #include "ifpga_feature_dev.h" +#include "opae_spi.h" +#include "opae_intel_max10.h" #define PWR_THRESHOLD_MAX 0x7F @@ -764,3 +766,197 @@ struct feature_ops fme_emif_ops = { .init = fme_emif_init, .uinit = fme_emif_uinit, }; + +static int spi_self_checking(void) +{ + u32 val; + int ret; + + ret = max10_reg_read(0x30043c, &val); + if (ret) + return -EIO; + + if (val != 0x87654321) { + dev_err(NULL, "Read MAX10 test register fail: 0x%x\n", val); + return -EIO; + } + + dev_info(NULL, "Read MAX10 test register success, SPI self-test done\n"); + + return 0; +} + +static int fme_spi_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; + struct altera_spi_device *spi_master; + struct intel_max10_device *max10; + int ret = 0; + + dev_info(fme, "FME SPI Master (Max10) Init.\n"); + dev_debug(fme, "FME SPI base addr %p.\n", + feature->addr); + dev_debug(fme, "spi param=0x%llx\n", + (unsigned long long)opae_readq(feature->addr + 0x8)); + + spi_master = altera_spi_alloc(feature->addr, TYPE_SPI); + if (!spi_master) + return -ENODEV; + + altera_spi_init(spi_master); + + max10 = intel_max10_device_probe(spi_master, 0); + if (!max10) { + ret = -ENODEV; + dev_err(fme, "max10 init fail\n"); + goto spi_fail; + } + + fme->max10_dev = max10; + + /* SPI self test */ + if (spi_self_checking()) { + ret = -EIO; + goto max10_fail; + } + + return ret; + +max10_fail: + intel_max10_device_remove(fme->max10_dev); +spi_fail: + altera_spi_release(spi_master); + return ret; +} + +static void fme_spi_uinit(struct feature *feature) +{ + struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; + + if (fme->max10_dev) + intel_max10_device_remove(fme->max10_dev); +} + +struct feature_ops fme_spi_master_ops = { + .init = fme_spi_init, + .uinit = fme_spi_uinit, +}; + +static int nios_spi_wait_init_done(struct altera_spi_device *dev) +{ + u32 val = 0; + unsigned long timeout = msecs_to_timer_cycles(10000); + unsigned long ticks; + + do { + if (spi_reg_read(dev, NIOS_SPI_INIT_DONE, &val)) + return -EIO; + if (val) + break; + + ticks = rte_get_timer_cycles(); + if (time_after(ticks, timeout)) + return -ETIMEDOUT; + msleep(100); + } while (!val); + + return 0; +} + +static int nios_spi_check_error(struct altera_spi_device *dev) +{ + u32 value = 0; + + if (spi_reg_read(dev, NIOS_SPI_INIT_STS0, &value)) + return -EIO; + + dev_debug(dev, "SPI init status0 0x%x\n", value); + + /* Error code: 0xFFF0 to 0xFFFC */ + if (value >= 0xFFF0 && value <= 0xFFFC) + return -EINVAL; + + value = 0; + if (spi_reg_read(dev, NIOS_SPI_INIT_STS1, &value)) + return -EIO; + + dev_debug(dev, "SPI init status1 0x%x\n", value); + + /* Error code: 0xFFF0 to 0xFFFC */ + if (value >= 0xFFF0 && value <= 0xFFFC) + return -EINVAL; + + return 0; +} + +static int fme_nios_spi_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; + struct altera_spi_device *spi_master; + struct intel_max10_device *max10; + int ret = 0; + + dev_info(fme, "FME SPI Master (NIOS) Init.\n"); + dev_debug(fme, "FME SPI base addr %p.\n", + feature->addr); + dev_debug(fme, "spi param=0x%llx\n", + (unsigned long long)opae_readq(feature->addr + 0x8)); + + spi_master = altera_spi_alloc(feature->addr, TYPE_NIOS_SPI); + if (!spi_master) + return -ENODEV; + + /** + * 1. wait A10 NIOS initial finished and + * release the SPI master to Host + */ + ret = nios_spi_wait_init_done(spi_master); + if (ret != 0) { + dev_err(fme, "FME NIOS_SPI init fail\n"); + goto release_dev; + } + + dev_info(fme, "FME NIOS_SPI initial done\n"); + + /* 2. check if error occur? */ + if (nios_spi_check_error(spi_master)) + dev_info(fme, "NIOS_SPI INIT done, but found some error\n"); + + /* 3. init the spi master*/ + altera_spi_init(spi_master); + + /* init the max10 device */ + max10 = intel_max10_device_probe(spi_master, 0); + if (!max10) { + ret = -ENODEV; + dev_err(fme, "max10 init fail\n"); + goto release_dev; + } + + fme->max10_dev = max10; + + /* SPI self test */ + if (spi_self_checking()) + goto spi_fail; + + return ret; + +spi_fail: + intel_max10_device_remove(fme->max10_dev); +release_dev: + altera_spi_release(spi_master); + return -ENODEV; +} + +static void fme_nios_spi_uinit(struct feature *feature) +{ + struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; + + if (fme->max10_dev) + intel_max10_device_remove(fme->max10_dev); +} + +struct feature_ops fme_nios_spi_master_ops = { + .init = fme_nios_spi_init, + .uinit = fme_nios_spi_uinit, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_hw.h b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h index 8aaa056..a2f4776 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_hw.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -79,6 +79,8 @@ struct ifpga_fme_hw { u32 cache_size; u32 capability; + + void *max10_dev; /* MAX10 device */ }; enum ifpga_port_state { diff --git a/drivers/raw/ifpga_rawdev/base/meson.build b/drivers/raw/ifpga_rawdev/base/meson.build index 03f5112..6bc762f 100644 --- a/drivers/raw/ifpga_rawdev/base/meson.build +++ b/drivers/raw/ifpga_rawdev/base/meson.build @@ -14,7 +14,10 @@ sources = [ 'ifpga_fme_pr.c', 'opae_hw_api.c', 'opae_ifpga_hw_api.c', - 'opae_debug.c' + 'opae_debug.c', + 'opae_spi.c', + 'opae_spi_transaction.c', + 'opae_intel_max10.c', ] error_cflags = ['-Wno-sign-compare', '-Wno-unused-value', diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h index 332e0f3..76224b4 100644 --- a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -11,6 +11,7 @@ #include #include "opae_osdep.h" +#include "opae_intel_max10.h" #ifndef PCI_MAX_RESOURCE #define PCI_MAX_RESOURCE 6 diff --git a/drivers/raw/ifpga_rawdev/base/opae_intel_max10.c b/drivers/raw/ifpga_rawdev/base/opae_intel_max10.c new file mode 100644 index 0000000..f354ee4 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_intel_max10.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2019 Intel Corporation + */ + +#include "opae_intel_max10.h" + +static struct intel_max10_device *g_max10; + +int max10_reg_read(unsigned int reg, unsigned int *val) +{ + if (!g_max10) + return -ENODEV; + + return spi_transaction_read(g_max10->spi_tran_dev, + reg, 4, (unsigned char *)val); +} + +int max10_reg_write(unsigned int reg, unsigned int val) +{ + if (!g_max10) + return -ENODEV; + + return spi_transaction_write(g_max10->spi_tran_dev, + reg, 4, (unsigned char *)&val); +} + +struct intel_max10_device * +intel_max10_device_probe(struct altera_spi_device *spi, + int chipselect) +{ + struct intel_max10_device *dev; + int ret; + unsigned int val; + + dev = opae_malloc(sizeof(*dev)); + if (!dev) + return NULL; + + dev->spi_master = spi; + + dev->spi_tran_dev = spi_transaction_init(spi, chipselect); + if (!dev->spi_tran_dev) { + dev_err(dev, "%s spi tran init fail\n", __func__); + goto free_dev; + } + + /* set the max10 device firstly */ + g_max10 = dev; + + /* read FPGA loading information */ + ret = max10_reg_read(FPGA_PAGE_INFO_OFF, &val); + if (ret) { + dev_err(dev, "fail to get FPGA loading info\n"); + goto spi_tran_fail; + } + dev_info(dev, "FPGA loaded from %s Image\n", val ? "User" : "Factory"); + + /* set PKVL Polling manually in BBS */ + ret = max10_reg_write(PKVL_POLLING_CTRL, 0x3); + if (ret) { + dev_err(dev, "%s set PKVL polling fail\n", __func__); + goto spi_tran_fail; + } + + return dev; + +spi_tran_fail: + spi_transaction_remove(dev->spi_tran_dev); +free_dev: + g_max10 = NULL; + opae_free(dev); + + return NULL; +} + +int intel_max10_device_remove(struct intel_max10_device *dev) +{ + if (!dev) + return 0; + + if (dev->spi_tran_dev) + spi_transaction_remove(dev->spi_tran_dev); + + g_max10 = NULL; + opae_free(dev); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_intel_max10.h b/drivers/raw/ifpga_rawdev/base/opae_intel_max10.h new file mode 100644 index 0000000..91a188d --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_intel_max10.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#ifndef _OPAE_INTEL_MAX10_H_ +#define _OPAE_INTEL_MAX10_H_ + +#include "opae_osdep.h" +#include "opae_spi.h" + +#define INTEL_MAX10_MAX_MDIO_DEVS 2 +#define PKVL_NUMBER_PORTS 4 + +/* max10 capability flags */ +#define MAX10_FLAGS_NO_I2C2 BIT(0) +#define MAX10_FLAGS_NO_BMCIMG_FLASH BIT(1) +#define MAX10_FLAGS_DEVICE_TABLE BIT(2) +#define MAX10_FLAGS_SPI BIT(3) +#define MAX10_FLGAS_NIOS_SPI BIT(4) +#define MAX10_FLAGS_PKVL BIT(5) + +struct intel_max10_device { + unsigned int flags; /*max10 hardware capability*/ + struct altera_spi_device *spi_master; + struct spi_transaction_dev *spi_tran_dev; +}; + +#define FLASH_BASE 0x10000000 +#define FLASH_OPTION_BITS 0x10000 + +#define NIOS2_FW_VERSION_OFF 0x300400 +#define RSU_REG_OFF 0x30042c +#define FPGA_RP_LOAD BIT(3) +#define NIOS2_PRERESET BIT(4) +#define NIOS2_HANG BIT(5) +#define RSU_ENABLE BIT(6) +#define NIOS2_RESET BIT(7) +#define NIOS2_I2C2_POLL_STOP BIT(13) +#define FPGA_RECONF_REG_OFF 0x300430 +#define COUNTDOWN_START BIT(18) +#define MAX10_BUILD_VER_OFF 0x300468 +#define PCB_INFO GENMASK(31, 24) +#define MAX10_BUILD_VERION GENMASK(23, 0) +#define FPGA_PAGE_INFO_OFF 0x30046c +#define DT_AVAIL_REG_OFF 0x300490 +#define DT_AVAIL BIT(0) +#define DT_BASE_ADDR_REG_OFF 0x300494 +#define PKVL_POLLING_CTRL 0x300480 +#define PKVL_LINK_STATUS 0x300564 + +#define DFT_MAX_SIZE 0x7e0000 + +int max10_reg_read(unsigned int reg, unsigned int *val); +int max10_reg_write(unsigned int reg, unsigned int val); +struct intel_max10_device * +intel_max10_device_probe(struct altera_spi_device *spi, + int chipselect); +int intel_max10_device_remove(struct intel_max10_device *dev); + +#endif diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h index 78fec50..d710ec0 100644 --- a/drivers/raw/ifpga_rawdev/base/opae_osdep.h +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -35,6 +35,7 @@ struct uuid { #ifndef BIT #define BIT(a) (1UL << (a)) #endif /* BIT */ +#define U64_C(x) x ## ULL #ifndef BIT_ULL #define BIT_ULL(a) (1ULL << (a)) #endif /* BIT_ULL */ @@ -76,5 +77,8 @@ struct uuid { #define msleep(x) opae_udelay(1000 * (x)) #define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000)) +#define time_after(a, b) ((long)((b) - (a)) < 0) +#define time_before(a, b) time_after(b, a) #define opae_memset(a, b, c) memset((a), (b), (c)) + #endif diff --git a/drivers/raw/ifpga_rawdev/base/opae_spi.c b/drivers/raw/ifpga_rawdev/base/opae_spi.c new file mode 100644 index 0000000..cc52782 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_spi.c @@ -0,0 +1,304 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2019 Intel Corporation + */ + +#include "opae_osdep.h" +#include "opae_spi.h" + +static int nios_spi_indirect_read(struct altera_spi_device *dev, u32 reg, + u32 *val) +{ + u64 ctrl = 0; + u64 stat = 0; + int loops = SPI_MAX_RETRY; + + ctrl = NIOS_SPI_RD | ((u64)reg << 32); + opae_writeq(ctrl, dev->regs + NIOS_SPI_CTRL); + + stat = opae_readq(dev->regs + NIOS_SPI_STAT); + while (!(stat & NIOS_SPI_VALID) && --loops) + stat = opae_readq(dev->regs + NIOS_SPI_STAT); + + *val = stat & NIOS_SPI_READ_DATA; + + return loops ? 0 : -ETIMEDOUT; +} + +static int nios_spi_indirect_write(struct altera_spi_device *dev, u32 reg, + u32 value) +{ + + u64 ctrl = 0; + u64 stat = 0; + int loops = SPI_MAX_RETRY; + + ctrl |= NIOS_SPI_WR | (u64)reg << 32; + ctrl |= value & NIOS_SPI_WRITE_DATA; + + opae_writeq(ctrl, dev->regs + NIOS_SPI_CTRL); + + stat = opae_readq(dev->regs + NIOS_SPI_STAT); + while (!(stat & NIOS_SPI_VALID) && --loops) + stat = opae_readq(dev->regs + NIOS_SPI_STAT); + + return loops ? 0 : -ETIMEDOUT; +} + +static int spi_indirect_write(struct altera_spi_device *dev, u32 reg, + u32 value) +{ + u64 ctrl; + + opae_writeq(value & WRITE_DATA_MASK, dev->regs + SPI_WRITE); + + ctrl = CTRL_W | (reg >> 2); + opae_writeq(ctrl, dev->regs + SPI_CTRL); + + return 0; +} + +static int spi_indirect_read(struct altera_spi_device *dev, u32 reg, + u32 *val) +{ + u64 tmp; + u64 ctrl; + + ctrl = CTRL_R | (reg >> 2); + opae_writeq(ctrl, dev->regs + SPI_CTRL); + + /** + * FIXME: Read one more time to avoid HW timing issue. This is + * a short term workaround solution, and must be removed once + * hardware fixing is done. + */ + tmp = opae_readq(dev->regs + SPI_READ); + + *val = (u32)tmp; + + return 0; +} + +int spi_reg_write(struct altera_spi_device *dev, u32 reg, + u32 value) +{ + return dev->reg_write(dev, reg, value); +} + +int spi_reg_read(struct altera_spi_device *dev, u32 reg, + u32 *val) +{ + return dev->reg_read(dev, reg, val); +} + +void spi_cs_activate(struct altera_spi_device *dev, unsigned int chip_select) +{ + spi_reg_write(dev, ALTERA_SPI_SLAVE_SEL, 1 << chip_select); + spi_reg_write(dev, ALTERA_SPI_CONTROL, ALTERA_SPI_CONTROL_SSO_MSK); +} + +void spi_cs_deactivate(struct altera_spi_device *dev) +{ + spi_reg_write(dev, ALTERA_SPI_CONTROL, 0); +} + +static int spi_flush_rx(struct altera_spi_device *dev) +{ + u32 val = 0; + int ret; + + ret = spi_reg_read(dev, ALTERA_SPI_STATUS, &val); + if (ret) + return ret; + + if (val & ALTERA_SPI_STATUS_RRDY_MSK) { + ret = spi_reg_read(dev, ALTERA_SPI_RXDATA, &val); + if (ret) + return ret; + } + + return 0; +} + +static unsigned int spi_write_bytes(struct altera_spi_device *dev, int count) +{ + unsigned int val = 0; + u16 *p16; + u32 *p32; + + if (dev->txbuf) { + switch (dev->data_width) { + case 1: + val = dev->txbuf[count]; + break; + case 2: + p16 = (u16 *)(dev->txbuf + 2*count); + val = *p16; + if (dev->endian == SPI_BIG_ENDIAN) + val = cpu_to_be16(val); + break; + case 4: + p32 = (u32 *)(dev->txbuf + 4*count); + val = *p32; + break; + } + } + + return val; +} + +static void spi_fill_readbuffer(struct altera_spi_device *dev, + unsigned int value, int count) +{ + u16 *p16; + u32 *p32; + + if (dev->rxbuf) { + switch (dev->data_width) { + case 1: + dev->rxbuf[count] = value; + break; + case 2: + p16 = (u16 *)(dev->rxbuf + 2*count); + if (dev->endian == SPI_BIG_ENDIAN) + *p16 = cpu_to_be16((u16)value); + else + *p16 = (u16)value; + break; + case 4: + p32 = (u32 *)(dev->rxbuf + 4*count); + if (dev->endian == SPI_BIG_ENDIAN) + *p32 = cpu_to_be32(value); + else + *p32 = value; + break; + } + } +} + +static int spi_txrx(struct altera_spi_device *dev) +{ + unsigned int count = 0; + u32 rxd; + unsigned int tx_data; + u32 status; + int retry = 0; + int ret; + + while (count < dev->len) { + tx_data = spi_write_bytes(dev, count); + spi_reg_write(dev, ALTERA_SPI_TXDATA, tx_data); + + while (1) { + ret = spi_reg_read(dev, ALTERA_SPI_STATUS, &status); + if (ret) + return -EIO; + if (status & ALTERA_SPI_STATUS_RRDY_MSK) + break; + if (retry++ > SPI_MAX_RETRY) { + dev_err(dev, "%s, read timeout\n", __func__); + return -EBUSY; + } + } + + ret = spi_reg_read(dev, ALTERA_SPI_RXDATA, &rxd); + if (ret) + return -EIO; + + spi_fill_readbuffer(dev, rxd, count); + + count++; + } + + return 0; +} + +int spi_command(struct altera_spi_device *dev, unsigned int chip_select, + unsigned int wlen, void *wdata, + unsigned int rlen, void *rdata) +{ + if (((wlen > 0) && !wdata) || ((rlen > 0) && !rdata)) { + dev_err(dev, "error on spi command checking\n"); + return -EINVAL; + } + + wlen = wlen / dev->data_width; + rlen = rlen / dev->data_width; + + /* flush rx buffer */ + spi_flush_rx(dev); + + spi_cs_activate(dev, chip_select); + if (wlen) { + dev->txbuf = wdata; + dev->rxbuf = rdata; + dev->len = wlen; + spi_txrx(dev); + } + if (rlen) { + dev->rxbuf = rdata; + dev->txbuf = NULL; + dev->len = rlen; + spi_txrx(dev); + } + spi_cs_deactivate(dev); + return 0; +} + +struct altera_spi_device *altera_spi_alloc(void *base, int type) +{ + struct altera_spi_device *spi_dev = + opae_malloc(sizeof(struct altera_spi_device)); + + if (!spi_dev) + return NULL; + + spi_dev->regs = base; + + switch (type) { + case TYPE_SPI: + spi_dev->reg_read = spi_indirect_read; + spi_dev->reg_write = spi_indirect_write; + break; + case TYPE_NIOS_SPI: + spi_dev->reg_read = nios_spi_indirect_read; + spi_dev->reg_write = nios_spi_indirect_write; + break; + default: + dev_err(dev, "%s: invalid SPI type\n", __func__); + goto error; + } + + return spi_dev; + +error: + altera_spi_release(spi_dev); + return NULL; +} + +void altera_spi_init(struct altera_spi_device *spi_dev) +{ + spi_dev->spi_param.info = opae_readq(spi_dev->regs + SPI_CORE_PARAM); + + spi_dev->data_width = spi_dev->spi_param.data_width / 8; + spi_dev->endian = spi_dev->spi_param.endian; + spi_dev->num_chipselect = spi_dev->spi_param.num_chipselect; + dev_info(spi_dev, "spi param: type=%d, data width:%d, endian:%d, clock_polarity=%d, clock=%dMHz, chips=%d, cpha=%d\n", + spi_dev->spi_param.type, + spi_dev->data_width, spi_dev->endian, + spi_dev->spi_param.clock_polarity, + spi_dev->spi_param.clock, + spi_dev->num_chipselect, + spi_dev->spi_param.clock_phase); + + /* clear */ + spi_reg_write(spi_dev, ALTERA_SPI_CONTROL, 0); + spi_reg_write(spi_dev, ALTERA_SPI_STATUS, 0); + /* flush rxdata */ + spi_flush_rx(spi_dev); +} + +void altera_spi_release(struct altera_spi_device *dev) +{ + if (dev) + opae_free(dev); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_spi.h b/drivers/raw/ifpga_rawdev/base/opae_spi.h new file mode 100644 index 0000000..ab66e1f --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_spi.h @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2019 Intel Corporation + */ + +#ifndef _OPAE_SPI_H +#define _OPAE_SPI_H + +#include "opae_osdep.h" + +#define ALTERA_SPI_RXDATA 0 +#define ALTERA_SPI_TXDATA 4 +#define ALTERA_SPI_STATUS 8 +#define ALTERA_SPI_CONTROL 12 +#define ALTERA_SPI_SLAVE_SEL 20 + +#define ALTERA_SPI_STATUS_ROE_MSK 0x8 +#define ALTERA_SPI_STATUS_TOE_MSK 0x10 +#define ALTERA_SPI_STATUS_TMT_MSK 0x20 +#define ALTERA_SPI_STATUS_TRDY_MSK 0x40 +#define ALTERA_SPI_STATUS_RRDY_MSK 0x80 +#define ALTERA_SPI_STATUS_E_MSK 0x100 + +#define ALTERA_SPI_CONTROL_IROE_MSK 0x8 +#define ALTERA_SPI_CONTROL_ITOE_MSK 0x10 +#define ALTERA_SPI_CONTROL_ITRDY_MSK 0x40 +#define ALTERA_SPI_CONTROL_IRRDY_MSK 0x80 +#define ALTERA_SPI_CONTROL_IE_MSK 0x100 +#define ALTERA_SPI_CONTROL_SSO_MSK 0x400 + +#define SPI_CORE_PARAM 0x8 +#define SPI_CTRL 0x10 +#define CTRL_R BIT_ULL(9) +#define CTRL_W BIT_ULL(8) +#define CTRL_ADDR_MASK GENMASK_ULL(2, 0) +#define SPI_READ 0x18 +#define READ_DATA_VALID BIT_ULL(32) +#define READ_DATA_MASK GENMASK_ULL(31, 0) +#define SPI_WRITE 0x20 +#define WRITE_DATA_MASK GENMASK_ULL(31, 0) + +#define SPI_MAX_RETRY 100000 + +#define TYPE_SPI 0 +#define TYPE_NIOS_SPI 1 + +struct spi_core_param { + union { + u64 info; + struct { + u8 type:1; + u8 endian:1; + u8 data_width:6; + u8 num_chipselect:6; + u8 clock_polarity:1; + u8 clock_phase:1; + u8 stages:2; + u8 resvd:4; + u16 clock:10; + u16 peripheral_id:16; + u8 controller_type:1; + u16 resvd1:15; + }; + }; +}; + +struct altera_spi_device { + u8 *regs; + struct spi_core_param spi_param; + int data_width; /* how many bytes for data width */ + int endian; + #define SPI_BIG_ENDIAN 0 + #define SPI_LITTLE_ENDIAN 1 + int num_chipselect; + unsigned char *rxbuf; + unsigned char *txbuf; + unsigned int len; + int (*reg_read)(struct altera_spi_device *dev, u32 reg, u32 *val); + int (*reg_write)(struct altera_spi_device *dev, u32 reg, + u32 value); +}; + +#define HEADER_LEN 8 +#define RESPONSE_LEN 4 +#define SPI_TRANSACTION_MAX_LEN 1024 +#define TRAN_SEND_MAX_LEN (SPI_TRANSACTION_MAX_LEN + HEADER_LEN) +#define TRAN_RESP_MAX_LEN SPI_TRANSACTION_MAX_LEN +#define PACKET_SEND_MAX_LEN (2*TRAN_SEND_MAX_LEN + 4) +#define PACKET_RESP_MAX_LEN (2*TRAN_RESP_MAX_LEN + 4) +#define BYTES_SEND_MAX_LEN (2*PACKET_SEND_MAX_LEN) +#define BYTES_RESP_MAX_LEN (2*PACKET_RESP_MAX_LEN) + +struct spi_tran_buffer { + unsigned char tran_send[TRAN_SEND_MAX_LEN]; + unsigned char tran_resp[TRAN_RESP_MAX_LEN]; + unsigned char packet_send[PACKET_SEND_MAX_LEN]; + unsigned char packet_resp[PACKET_RESP_MAX_LEN]; + unsigned char bytes_send[BYTES_SEND_MAX_LEN]; + unsigned char bytes_resp[2*BYTES_RESP_MAX_LEN]; +}; + +struct spi_transaction_dev { + struct altera_spi_device *dev; + int chipselect; + struct spi_tran_buffer *buffer; +}; + +struct spi_tran_header { + u8 trans_type; + u8 reserve; + u16 size; + u32 addr; +}; + +int spi_command(struct altera_spi_device *dev, unsigned int chip_select, + unsigned int wlen, void *wdata, unsigned int rlen, void *rdata); +void spi_cs_deactivate(struct altera_spi_device *dev); +void spi_cs_activate(struct altera_spi_device *dev, unsigned int chip_select); +struct altera_spi_device *altera_spi_alloc(void *base, int type); +void altera_spi_init(struct altera_spi_device *dev); +void altera_spi_release(struct altera_spi_device *dev); +int spi_transaction_read(struct spi_transaction_dev *dev, unsigned int addr, + unsigned int size, unsigned char *data); +int spi_transaction_write(struct spi_transaction_dev *dev, unsigned int addr, + unsigned int size, unsigned char *data); +struct spi_transaction_dev *spi_transaction_init(struct altera_spi_device *dev, + int chipselect); +void spi_transaction_remove(struct spi_transaction_dev *dev); +int spi_reg_write(struct altera_spi_device *dev, u32 reg, + u32 value); +int spi_reg_read(struct altera_spi_device *dev, u32 reg, u32 *val); + +#define NIOS_SPI_PARAM 0x8 +#define CONTROL_TYPE BIT_ULL(48) +#define PERI_ID GENMASK_ULL(47, 32) +#define SPI_CLK GENMASK_ULL(31, 22) +#define SYNC_STAGES GENMASK_ULL(17, 16) +#define CLOCK_PHASE BIT_ULL(15) +#define CLOCK_POLARITY BIT_ULL(14) +#define NUM_SELECT GENMASK_ULL(13, 8) +#define DATA_WIDTH GENMASK_ULL(7, 2) +#define SHIFT_DIRECTION BIT_ULL(1) +#define SPI_TYPE BIT_ULL(0) +#define NIOS_SPI_CTRL 0x10 +#define NIOS_SPI_RD (0x1ULL << 62) +#define NIOS_SPI_WR (0x2ULL << 62) +#define NIOS_SPI_COMMAND GENMASK_ULL(63, 62) +#define NIOS_SPI_ADDR GENMASK_ULL(44, 32) +#define NIOS_SPI_WRITE_DATA GENMASK_ULL(31, 0) +#define NIOS_SPI_STAT 0x18 +#define NIOS_SPI_VALID BIT_ULL(32) +#define NIOS_SPI_READ_DATA GENMASK_ULL(31, 0) +#define NIOS_SPI_INIT_DONE 0x1000 + +#define NIOS_SPI_INIT_DONE 0x1000 +#define NIOS_SPI_INIT_STS0 0x1020 +#define NIOS_SPI_INIT_STS1 0x1024 +#define PKVL_STATUS_RESET 0 +#define PKVL_10G_MODE 1 +#define PKVL_25G_MODE 2 +#endif diff --git a/drivers/raw/ifpga_rawdev/base/opae_spi_transaction.c b/drivers/raw/ifpga_rawdev/base/opae_spi_transaction.c new file mode 100644 index 0000000..17ec3c1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_spi_transaction.c @@ -0,0 +1,438 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2019 Intel Corporation + */ + +#include "opae_spi.h" +#include "ifpga_compat.h" + +/*transaction opcodes*/ +#define SPI_TRAN_SEQ_WRITE 0x04 /* SPI transaction sequential write */ +#define SPI_TRAN_SEQ_READ 0x14 /* SPI transaction sequential read */ +#define SPI_TRAN_NON_SEQ_WRITE 0x00 /* SPI transaction non-sequential write */ +#define SPI_TRAN_NON_SEQ_READ 0x10 /* SPI transaction non-sequential read*/ + +/*specail packet characters*/ +#define SPI_PACKET_SOP 0x7a +#define SPI_PACKET_EOP 0x7b +#define SPI_PACKET_CHANNEL 0x7c +#define SPI_PACKET_ESC 0x7d + +/*special byte characters*/ +#define SPI_BYTE_IDLE 0x4a +#define SPI_BYTE_ESC 0x4d + +#define SPI_REG_BYTES 4 + +#define INIT_SPI_TRAN_HEADER(trans_type, size, address) \ +({ \ + header.trans_type = trans_type; \ + header.reserve = 0; \ + header.size = cpu_to_be16(size); \ + header.addr = cpu_to_be32(addr); \ +}) + +#ifdef OPAE_SPI_DEBUG +static void print_buffer(const char *string, void *buffer, int len) +{ + int i; + unsigned char *p = buffer; + + printf("%s print buffer, len=%d\n", string, len); + + for (i = 0; i < len; i++) + printf("%x ", *(p+i)); + printf("\n"); +} +#else +static void print_buffer(const char *string, void *buffer, int len) +{ + UNUSED(string); + UNUSED(buffer); + UNUSED(len); +} +#endif + +static unsigned char xor_20(unsigned char val) +{ + return val^0x20; +} + +static void reorder_phy_data(u8 bits_per_word, + void *buf, unsigned int len) +{ + unsigned int count = len / (bits_per_word/8); + u32 *p; + + if (bits_per_word == 32) { + p = (u32 *)buf; + while (count--) { + *p = cpu_to_be32(*p); + p++; + } + } +} + +enum { + SPI_FOUND_SOP, + SPI_FOUND_EOP, + SPI_NOT_FOUND, +}; + +static int resp_find_sop_eop(unsigned char *resp, unsigned int len, + int flags) +{ + int ret = SPI_NOT_FOUND; + + unsigned char *b = resp; + + /* find SOP */ + if (flags != SPI_FOUND_SOP) { + while (b < resp + len && *b != SPI_PACKET_SOP) + b++; + + if (*b != SPI_PACKET_SOP) + goto done; + + ret = SPI_FOUND_SOP; + } + + /* find EOP */ + while (b < resp + len && *b != SPI_PACKET_EOP) + b++; + + if (*b != SPI_PACKET_EOP) + goto done; + + ret = SPI_FOUND_EOP; + +done: + return ret; +} + +static int byte_to_core_convert(struct spi_transaction_dev *dev, + unsigned int send_len, unsigned char *send_data, + unsigned int resp_len, unsigned char *resp_data, + unsigned int *valid_resp_len) +{ + unsigned int i; + int ret = 0; + unsigned char *send_packet = dev->buffer->bytes_send; + unsigned char *resp_packet = dev->buffer->bytes_resp; + unsigned char *p; + unsigned char current_byte; + unsigned char *tx_buffer; + unsigned int tx_len = 0; + unsigned char *rx_buffer; + unsigned int rx_len = 0; + int retry = 0; + int spi_flags; + unsigned int resp_max_len = 2 * resp_len; + + print_buffer("before bytes:", send_data, send_len); + + p = send_packet; + + for (i = 0; i < send_len; i++) { + current_byte = send_data[i]; + switch (current_byte) { + case SPI_BYTE_IDLE: + *p++ = SPI_BYTE_IDLE; + *p++ = xor_20(current_byte); + break; + case SPI_BYTE_ESC: + *p++ = SPI_BYTE_ESC; + *p++ = xor_20(current_byte); + break; + default: + *p++ = current_byte; + break; + } + } + + print_buffer("before spi:", send_packet, p-send_packet); + + reorder_phy_data(32, send_packet, p - send_packet); + + print_buffer("after order to spi:", send_packet, p-send_packet); + + /* call spi */ + tx_buffer = send_packet; + tx_len = p - send_packet; + rx_buffer = resp_packet; + rx_len = resp_max_len; + spi_flags = SPI_NOT_FOUND; + +read_again: + ret = spi_command(dev->dev, dev->chipselect, tx_len, tx_buffer, + rx_len, rx_buffer); + if (ret) + return -EBUSY; + + print_buffer("read from spi:", rx_buffer, rx_len); + + /* look for SOP firstly*/ + ret = resp_find_sop_eop(rx_buffer, rx_len - 1, spi_flags); + if (ret != SPI_FOUND_EOP) { + tx_buffer = NULL; + tx_len = 0; + if (retry++ > 10) { + dev_err(NULL, "cannot found valid data from SPI\n"); + return -EBUSY; + } + + if (ret == SPI_FOUND_SOP) { + rx_buffer += rx_len; + resp_max_len += rx_len; + } + + spi_flags = ret; + goto read_again; + } + + print_buffer("found valid data:", resp_packet, resp_max_len); + + /* analyze response packet */ + i = 0; + p = resp_data; + while (i < resp_max_len) { + current_byte = resp_packet[i]; + switch (current_byte) { + case SPI_BYTE_IDLE: + i++; + break; + case SPI_BYTE_ESC: + i++; + current_byte = resp_packet[i]; + *p++ = xor_20(current_byte); + i++; + break; + default: + *p++ = current_byte; + i++; + break; + } + } + + /* receive "4a" means the SPI is idle, not valid data */ + *valid_resp_len = p - resp_data; + if (*valid_resp_len == 0) { + dev_err(NULL, "error: repond package without valid data\n"); + return -EINVAL; + } + + return 0; +} + +static int packet_to_byte_conver(struct spi_transaction_dev *dev, + unsigned int send_len, unsigned char *send_buf, + unsigned int resp_len, unsigned char *resp_buf, + unsigned int *valid) +{ + int ret = 0; + unsigned int i; + unsigned char current_byte; + unsigned int resp_max_len; + unsigned char *send_packet = dev->buffer->packet_send; + unsigned char *resp_packet = dev->buffer->packet_resp; + unsigned char *p; + unsigned int valid_resp_len = 0; + + print_buffer("before packet:", send_buf, send_len); + + resp_max_len = 2 * resp_len + 4; + + p = send_packet; + + /* SOP header */ + *p++ = SPI_PACKET_SOP; + + *p++ = SPI_PACKET_CHANNEL; + *p++ = 0; + + /* append the data into a packet */ + for (i = 0; i < send_len; i++) { + current_byte = send_buf[i]; + + /* EOP for last byte */ + if (i == send_len - 1) + *p++ = SPI_PACKET_EOP; + + switch (current_byte) { + case SPI_PACKET_SOP: + case SPI_PACKET_EOP: + case SPI_PACKET_CHANNEL: + case SPI_PACKET_ESC: + *p++ = SPI_PACKET_ESC; + *p++ = xor_20(current_byte); + break; + default: + *p++ = current_byte; + } + } + + ret = byte_to_core_convert(dev, p - send_packet, + send_packet, resp_max_len, resp_packet, + &valid_resp_len); + if (ret) + return -EBUSY; + + print_buffer("after byte conver:", resp_packet, valid_resp_len); + + /* analyze the response packet */ + p = resp_buf; + + /* look for SOP */ + for (i = 0; i < valid_resp_len; i++) { + if (resp_packet[i] == SPI_PACKET_SOP) + break; + } + + if (i == valid_resp_len) { + dev_err(NULL, "error on analyze response packet 0x%x\n", + resp_packet[i]); + return -EINVAL; + } + + i++; + + /* continue parsing data after SOP */ + while (i < valid_resp_len) { + current_byte = resp_packet[i]; + + switch (current_byte) { + case SPI_PACKET_ESC: + case SPI_PACKET_CHANNEL: + case SPI_PACKET_SOP: + i++; + current_byte = resp_packet[i]; + *p++ = xor_20(current_byte); + i++; + break; + case SPI_PACKET_EOP: + i++; + current_byte = resp_packet[i]; + if (current_byte == SPI_PACKET_ESC || + current_byte == SPI_PACKET_CHANNEL || + current_byte == SPI_PACKET_SOP) { + i++; + current_byte = resp_packet[i]; + *p++ = xor_20(current_byte); + } else + *p++ = current_byte; + i = valid_resp_len; + break; + default: + *p++ = current_byte; + i++; + } + + } + + *valid = p - resp_buf; + + print_buffer("after packet:", resp_buf, *valid); + + return ret; +} + +static int do_transaction(struct spi_transaction_dev *dev, unsigned int addr, + unsigned int size, unsigned char *data, + unsigned int trans_type) +{ + + struct spi_tran_header header; + unsigned char *transaction = dev->buffer->tran_send; + unsigned char *response = dev->buffer->tran_resp; + unsigned char *p; + int ret = 0; + unsigned int i; + unsigned int valid_len = 0; + + /* make transacation header */ + INIT_SPI_TRAN_HEADER(trans_type, size, addr); + + /* fill the header */ + p = transaction; + opae_memcpy(p, &header, sizeof(struct spi_tran_header)); + p = p + sizeof(struct spi_tran_header); + + switch (trans_type) { + case SPI_TRAN_SEQ_WRITE: + case SPI_TRAN_NON_SEQ_WRITE: + for (i = 0; i < size; i++) + *p++ = *data++; + + ret = packet_to_byte_conver(dev, size + HEADER_LEN, + transaction, RESPONSE_LEN, response, + &valid_len); + if (ret) + return -EBUSY; + + /* check the result */ + if (size != ((unsigned int)(response[2] & 0xff) << 8 | + (unsigned int)(response[3] & 0xff))) + ret = -EBUSY; + + break; + case SPI_TRAN_SEQ_READ: + case SPI_TRAN_NON_SEQ_READ: + ret = packet_to_byte_conver(dev, HEADER_LEN, + transaction, size, response, + &valid_len); + if (ret || valid_len != size) + return -EBUSY; + + for (i = 0; i < size; i++) + *data++ = *response++; + + ret = 0; + break; + } + + return ret; +} + +int spi_transaction_read(struct spi_transaction_dev *dev, unsigned int addr, + unsigned int size, unsigned char *data) +{ + return do_transaction(dev, addr, size, data, + (size > SPI_REG_BYTES) ? + SPI_TRAN_SEQ_READ : SPI_TRAN_NON_SEQ_READ); +} + +int spi_transaction_write(struct spi_transaction_dev *dev, unsigned int addr, + unsigned int size, unsigned char *data) +{ + return do_transaction(dev, addr, size, data, + (size > SPI_REG_BYTES) ? + SPI_TRAN_SEQ_WRITE : SPI_TRAN_NON_SEQ_WRITE); +} + +struct spi_transaction_dev *spi_transaction_init(struct altera_spi_device *dev, + int chipselect) +{ + struct spi_transaction_dev *spi_tran_dev; + + spi_tran_dev = opae_malloc(sizeof(struct spi_transaction_dev)); + if (!spi_tran_dev) + return NULL; + + spi_tran_dev->dev = dev; + spi_tran_dev->chipselect = chipselect; + + spi_tran_dev->buffer = opae_malloc(sizeof(struct spi_tran_buffer)); + if (!spi_tran_dev->buffer) { + opae_free(spi_tran_dev); + return NULL; + } + + return spi_tran_dev; +} + +void spi_transaction_remove(struct spi_transaction_dev *dev) +{ + if (dev && dev->buffer) + opae_free(dev->buffer); + if (dev) + opae_free(dev); +} diff --git a/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h index 3d9a0ca..3ff49a8 100644 --- a/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h +++ b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #define dev_printf(level, fmt, args...) \ @@ -43,5 +44,18 @@ #define spinlock_lock(x) rte_spinlock_lock(x) #define spinlock_unlock(x) rte_spinlock_unlock(x) +#define cpu_to_be16(o) rte_cpu_to_be_16(o) +#define cpu_to_be32(o) rte_cpu_to_be_32(o) +#define cpu_to_be64(o) rte_cpu_to_be_64(o) +#define cpu_to_le16(o) rte_cpu_to_le_16(o) +#define cpu_to_le32(o) rte_cpu_to_le_32(o) +#define cpu_to_le64(o) rte_cpu_to_le_64(o) + #define opae_memcpy(a, b, c) rte_memcpy((a), (b), (c)) + +static inline unsigned long msecs_to_timer_cycles(unsigned int m) +{ + return rte_get_timer_hz() * (m / 1000); +} + #endif From patchwork Wed Apr 10 06:27:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52537 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 1027A1B107; Wed, 10 Apr 2019 08:27:44 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 4C5A454AE for ; Wed, 10 Apr 2019 08:27:41 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 23:27:40 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,332,1549958400"; d="scan'208";a="147980995" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by FMSMGA003.fm.intel.com with ESMTP; 09 Apr 2019 23:27:35 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Wed, 10 Apr 2019 14:27:48 +0800 Message-Id: <1554877672-19745-11-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554877672-19745-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554877672-19745-1-git-send-email-rosen.xu@intel.com> Subject: [dpdk-dev] [PATCH v7 10/14] raw/ifpga_rawdev: add I2C and at24 EEPROM driver X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Tianfei zhang 1. Add Altera I2C master device driver 2. Add at24 eeprom driver which is i2c slave device 3. Introducing a new ops for opae_manager: opae_manager_networking_ops. This ops will include some networking operation by FPGA, like vBNG operation, MAC ROM operation and so on. Signed-off-by: Tianfei Zhang --- drivers/raw/ifpga_rawdev/base/Makefile | 2 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 22 + drivers/raw/ifpga_rawdev/base/ifpga_api.h | 1 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 3 + drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 2 +- drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 2 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 7 + drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 90 ++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 1 + drivers/raw/ifpga_rawdev/base/meson.build | 2 + drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.c | 88 ++++ drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.h | 14 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 49 ++- drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 26 +- drivers/raw/ifpga_rawdev/base/opae_i2c.c | 490 ++++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/opae_i2c.h | 130 ++++++ 16 files changed, 926 insertions(+), 3 deletions(-) create mode 100644 drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_i2c.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_i2c.h diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile index c6f51a8..edb538f 100644 --- a/drivers/raw/ifpga_rawdev/base/Makefile +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -25,5 +25,7 @@ SRCS-y += ifpga_fme_pr.c SRCS-y += opae_spi.c SRCS-y += opae_spi_transaction.c SRCS-y += opae_intel_max10.c +SRCS-y += opae_i2c.c +SRCS-y += opae_at24_eeprom.c SRCS-y += $(wildcard $(SRCDIR)/base/$(OSDEP)/*.c) diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.c b/drivers/raw/ifpga_rawdev/base/ifpga_api.c index 77d9471..c447b3c 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_api.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -196,6 +196,28 @@ struct opae_manager_ops ifpga_mgr_ops = { .flash = ifpga_mgr_flash, }; +static int ifpga_mgr_read_mac_rom(struct opae_manager *mgr, int offset, + void *buf, int size) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_read_mac_rom(fme, offset, buf, size); +} + +static int ifpga_mgr_write_mac_rom(struct opae_manager *mgr, int offset, + void *buf, int size) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_write_mac_rom(fme, offset, buf, size); +} + +/* Network APIs in FME */ +struct opae_manager_networking_ops ifpga_mgr_network_ops = { + .read_mac_rom = ifpga_mgr_read_mac_rom, + .write_mac_rom = ifpga_mgr_write_mac_rom, +}; + /* Adapter APIs */ static int ifpga_adapter_enumerate(struct opae_adapter *adapter) { diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.h b/drivers/raw/ifpga_rawdev/base/ifpga_api.h index dae7ca1..4a24769 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_api.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.h @@ -12,6 +12,7 @@ extern struct opae_manager_ops ifpga_mgr_ops; extern struct opae_bridge_ops ifpga_br_ops; extern struct opae_accelerator_ops ifpga_acc_ops; +extern struct opae_manager_networking_ops ifpga_mgr_network_ops; /* common APIs */ int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h index f5e22ae..62f71c7 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -21,6 +21,7 @@ #define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" #define FME_FEATURE_MAX10_SPI "fme_max10_spi" #define FME_FEATURE_NIOS_SPI "fme_nios_spi" +#define FME_FEATURE_I2C_MASTER "fme_i2c_master" #define PORT_FEATURE_HEADER "port_hdr" #define PORT_FEATURE_UAFU "port_uafu" @@ -46,6 +47,7 @@ #define FME_GLOBAL_DPERF_REVISION 0 #define FME_QSPI_REVISION 0 #define FME_MAX10_SPI 0 +#define FME_I2C_MASTER 0 #define PORT_HEADER_REVISION 0 /* UAFU's header info depends on the downloaded GBS */ @@ -85,6 +87,7 @@ enum fpga_id_type { #define FME_FEATURE_ID_EMIF_MGMT 0x9 #define FME_FEATURE_ID_MAX10_SPI 0xe #define FME_FEATURE_ID_NIOS_SPI 0xd +#define FME_FEATURE_ID_I2C_MASTER 0xf #define PORT_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER #define PORT_FEATURE_ID_ERROR 0x10 diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c index c779e0c..666dae1 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -270,7 +270,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) } else if (binfo->current_type == FME_ID) { mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops, - binfo->fiu); + &ifpga_mgr_network_ops, binfo->fiu); if (!mgr) return -ENOMEM; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c index 2a35c06..0454f80 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -201,6 +201,8 @@ int port_clear_error(struct ifpga_port_hw *port) &fme_spi_master_ops),}, {FEATURE_DRV(FME_FEATURE_ID_NIOS_SPI, FME_FEATURE_NIOS_SPI, &fme_nios_spi_master_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_I2C_MASTER, FME_FEATURE_I2C_MASTER, + &fme_i2c_master_ops),}, {0, NULL, NULL}, /* end of arrary */ }; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h index 72352ee..a398a98 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -172,6 +172,7 @@ int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, extern struct feature_ops fme_hssi_eth_ops; extern struct feature_ops fme_emif_ops; extern struct feature_ops fme_spi_master_ops; +extern struct feature_ops fme_i2c_master_ops; extern struct feature_ops fme_nios_spi_master_ops; int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop); @@ -197,4 +198,10 @@ struct fpga_uafu_irq_set { /* help functions for feature ops */ int fpga_msix_set_block(struct feature *feature, unsigned int start, unsigned int count, s32 *fds); + +/* FME network function ops*/ +int fme_mgr_read_mac_rom(struct ifpga_fme_hw *fme, int offset, + void *buf, int size); +int fme_mgr_write_mac_rom(struct ifpga_fme_hw *fme, int offset, + void *buf, int size); #endif /* _IFPGA_FEATURE_DEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c index 28226f0..95e022e 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_fme.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -5,6 +5,8 @@ #include "ifpga_feature_dev.h" #include "opae_spi.h" #include "opae_intel_max10.h" +#include "opae_i2c.h" +#include "opae_at24_eeprom.h" #define PWR_THRESHOLD_MAX 0x7F @@ -960,3 +962,91 @@ struct feature_ops fme_nios_spi_master_ops = { .init = fme_nios_spi_init, .uinit = fme_nios_spi_uinit, }; + +static int i2c_mac_rom_test(struct altera_i2c_dev *dev) +{ + char buf[20]; + int ret; + char read_buf[20] = {0,}; + const char *string = "1a2b3c4d5e"; + + opae_memcpy(buf, string, strlen(string)); + + ret = at24_eeprom_write(dev, AT24512_SLAVE_ADDR, 0, + (u8 *)buf, strlen(string)); + if (ret < 0) { + dev_err(NULL, "write i2c error:%d\n", ret); + return ret; + } + + ret = at24_eeprom_read(dev, AT24512_SLAVE_ADDR, 0, + (u8 *)read_buf, strlen(string)); + if (ret < 0) { + dev_err(NULL, "read i2c error:%d\n", ret); + return ret; + } + + if (memcmp(buf, read_buf, strlen(string))) { + dev_err(NULL, "%s test fail!\n", __func__); + return -EFAULT; + } + + dev_info(NULL, "%s test successful\n", __func__); + + return 0; +} + +static int fme_i2c_init(struct feature *feature) +{ + struct feature_fme_i2c *i2c; + struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; + + i2c = (struct feature_fme_i2c *)feature->addr; + + dev_info(NULL, "FME I2C Master Init.\n"); + + fme->i2c_master = altera_i2c_probe(i2c); + if (!fme->i2c_master) + return -ENODEV; + + /* MAC ROM self test */ + i2c_mac_rom_test(fme->i2c_master); + + return 0; +} + +static void fme_i2c_uninit(struct feature *feature) +{ + struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; + + altera_i2c_remove(fme->i2c_master); +} + +struct feature_ops fme_i2c_master_ops = { + .init = fme_i2c_init, + .uinit = fme_i2c_uninit, +}; + +int fme_mgr_read_mac_rom(struct ifpga_fme_hw *fme, int offset, + void *buf, int size) +{ + struct altera_i2c_dev *dev; + + dev = fme->i2c_master; + if (!dev) + return -ENODEV; + + return at24_eeprom_read(dev, AT24512_SLAVE_ADDR, offset, buf, size); +} + +int fme_mgr_write_mac_rom(struct ifpga_fme_hw *fme, int offset, + void *buf, int size) +{ + struct altera_i2c_dev *dev; + + dev = fme->i2c_master; + if (!dev) + return -ENODEV; + + return at24_eeprom_write(dev, AT24512_SLAVE_ADDR, offset, buf, size); +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_hw.h b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h index a2f4776..e296dd2 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_hw.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -81,6 +81,7 @@ struct ifpga_fme_hw { u32 capability; void *max10_dev; /* MAX10 device */ + void *i2c_master; /* I2C Master device */ }; enum ifpga_port_state { diff --git a/drivers/raw/ifpga_rawdev/base/meson.build b/drivers/raw/ifpga_rawdev/base/meson.build index 6bc762f..7655985 100644 --- a/drivers/raw/ifpga_rawdev/base/meson.build +++ b/drivers/raw/ifpga_rawdev/base/meson.build @@ -18,6 +18,8 @@ sources = [ 'opae_spi.c', 'opae_spi_transaction.c', 'opae_intel_max10.c', + 'opae_i2c.c', + 'opae_at24_eeprom.c', ] error_cflags = ['-Wno-sign-compare', '-Wno-unused-value', diff --git a/drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.c b/drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.c new file mode 100644 index 0000000..d70f7af --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2019 Intel Corporation + */ + +#include "opae_osdep.h" +#include "opae_i2c.h" +#include "opae_at24_eeprom.h" + +#define AT24_READ_RETRY 10 + +static int at24_eeprom_read_and_try(struct altera_i2c_dev *dev, + unsigned int slave_addr, + u32 offset, u8 *buf, u32 len) +{ + int i; + int ret = 0; + + for (i = 0; i < AT24_READ_RETRY; i++) { + ret = i2c_read16(dev, slave_addr, offset, + buf, len); + if (ret == 0) + break; + + opae_udelay(100); + } + + return ret; +} + +int at24_eeprom_read(struct altera_i2c_dev *dev, unsigned int slave_addr, + u32 offset, u8 *buf, int count) +{ + int len; + int status; + int read_count = 0; + + if (!count) + return count; + + if (count > AT24C512_IO_LIMIT) + len = AT24C512_IO_LIMIT; + else + len = count; + + while (count) { + status = at24_eeprom_read_and_try(dev, slave_addr, offset, + buf, len); + if (status) + break; + + buf += len; + offset += len; + count -= len; + read_count += len; + } + + return read_count; +} + +int at24_eeprom_write(struct altera_i2c_dev *dev, unsigned int slave_addr, + u32 offset, u8 *buf, int count) +{ + int len; + int status; + int write_count = 0; + + if (!count) + return count; + + if (count > AT24C512_PAGE_SIZE) + len = AT24C512_PAGE_SIZE; + else + len = count; + + while (count) { + status = i2c_write16(dev, slave_addr, offset, buf, len); + if (status) + break; + + buf += len; + offset += len; + count -= len; + write_count += len; + } + + return write_count; +} + diff --git a/drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.h b/drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.h new file mode 100644 index 0000000..caae9a3 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_at24_eeprom.h @@ -0,0 +1,14 @@ + +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2019 Intel Corporation + */ + +#define AT24C512_PAGE_SIZE 128 +#define AT24C512_IO_LIMIT 128 + +#define AT24512_SLAVE_ADDR 0x51 + +int at24_eeprom_read(struct altera_i2c_dev *dev, unsigned int slave_addr, + u32 offset, u8 *buf, int count); +int at24_eeprom_write(struct altera_i2c_dev *dev, unsigned int slave_addr, + u32 offset, u8 *buf, int count); diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c index 41c5903..ec2b4c7 100644 --- a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -210,12 +210,14 @@ int opae_acc_get_uuid(struct opae_accelerator *acc, * opae_manager_alloc - alloc opae_manager data structure * @name: manager name. * @ops: ops of this manager. + * @network_ops: ops of network management. * @data: private data of this manager. * * Return: opae_manager on success, otherwise NULL. */ struct opae_manager * -opae_manager_alloc(const char *name, struct opae_manager_ops *ops, void *data) +opae_manager_alloc(const char *name, struct opae_manager_ops *ops, + struct opae_manager_networking_ops *network_ops, void *data) { struct opae_manager *mgr = opae_zmalloc(sizeof(*mgr)); @@ -224,6 +226,7 @@ struct opae_manager * mgr->name = name; mgr->ops = ops; + mgr->network_ops = network_ops; mgr->data = data; opae_log("%s %p\n", __func__, mgr); @@ -379,3 +382,47 @@ struct opae_accelerator * return NULL; } + +/** + * opae_manager_read_mac_rom - read the content of the MAC ROM + * @mgr: opae_manager for MAC ROM + * @port: the port number of retimer + * @addr: buffer of the MAC address + * + * Return: return the bytes of read successfully + */ +int opae_manager_read_mac_rom(struct opae_manager *mgr, int port, + struct opae_ether_addr *addr) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + if (mgr->network_ops->read_mac_rom) + return mgr->network_ops->read_mac_rom(mgr, + port * sizeof(struct opae_ether_addr), + addr, sizeof(struct opae_ether_addr)); + + return -ENOENT; +} + +/** + * opae_manager_write_mac_rom - write data into MAC ROM + * @mgr: opae_manager for MAC ROM + * @port: the port number of the retimer + * @addr: data of the MAC address + * + * Return: return written bytes + */ +int opae_manager_write_mac_rom(struct opae_manager *mgr, int port, + struct opae_ether_addr *addr) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + if (mgr->network_ops && mgr->network_ops->write_mac_rom) + return mgr->network_ops->write_mac_rom(mgr, + port * sizeof(struct opae_ether_addr), + addr, sizeof(struct opae_ether_addr)); + + return -ENOENT; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h index 76224b4..826da37 100644 --- a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -26,6 +26,7 @@ enum opae_adapter_type { /* OPAE Manager Data Structure */ struct opae_manager_ops; +struct opae_manager_networking_ops; /* * opae_manager has pointer to its parent adapter, as it could be able to manage @@ -36,6 +37,7 @@ struct opae_manager { const char *name; struct opae_adapter *adapter; struct opae_manager_ops *ops; + struct opae_manager_networking_ops *network_ops; void *data; }; @@ -45,9 +47,18 @@ struct opae_manager_ops { u32 size, u64 *status); }; +/* networking management ops in FME */ +struct opae_manager_networking_ops { + int (*read_mac_rom)(struct opae_manager *mgr, int offset, void *buf, + int size); + int (*write_mac_rom)(struct opae_manager *mgr, int offset, void *buf, + int size); +}; + /* OPAE Manager APIs */ struct opae_manager * -opae_manager_alloc(const char *name, struct opae_manager_ops *ops, void *data); +opae_manager_alloc(const char *name, struct opae_manager_ops *ops, + struct opae_manager_networking_ops *network_ops, void *data); #define opae_manager_free(mgr) opae_free(mgr) int opae_manager_flash(struct opae_manager *mgr, int acc_id, void *buf, u32 size, u64 *status); @@ -252,4 +263,17 @@ static inline void opae_adapter_remove_acc(struct opae_adapter *adapter, { TAILQ_REMOVE(&adapter->acc_list, acc, node); } + +/* OPAE vBNG network datastruct */ +#define OPAE_ETHER_ADDR_LEN 6 + +struct opae_ether_addr { + unsigned char addr_bytes[OPAE_ETHER_ADDR_LEN]; +} __attribute__((__packed__)); + +/* OPAE vBNG network API*/ +int opae_manager_read_mac_rom(struct opae_manager *mgr, int port, + struct opae_ether_addr *addr); +int opae_manager_write_mac_rom(struct opae_manager *mgr, int port, + struct opae_ether_addr *addr); #endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga_rawdev/base/opae_i2c.c b/drivers/raw/ifpga_rawdev/base/opae_i2c.c new file mode 100644 index 0000000..f8bc247 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_i2c.c @@ -0,0 +1,490 @@ + +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2019 Intel Corporation + */ + +#include "opae_osdep.h" +#include "opae_i2c.h" + +static int i2c_transfer(struct altera_i2c_dev *dev, + struct i2c_msg *msg, int num) +{ + int ret, try; + + for (ret = 0, try = 0; try < I2C_XFER_RETRY; try++) { + ret = dev->xfer(dev, msg, num); + if (ret != -EAGAIN) + break; + } + + return ret; +} + +/** + * i2c read function + */ +int i2c_read(struct altera_i2c_dev *dev, int flags, unsigned int slave_addr, + u32 offset, u8 *buf, u32 count) +{ + u8 msgbuf[2]; + int i = 0; + + if (flags & I2C_FLAG_ADDR16) + msgbuf[i++] = offset >> 8; + + msgbuf[i++] = offset; + + struct i2c_msg msg[2] = { + { + .addr = slave_addr, + .flags = 0, + .len = i, + .buf = msgbuf, + }, + { + .addr = slave_addr, + .flags = I2C_M_RD, + .len = count, + .buf = buf, + }, + }; + + if (!dev->xfer) + return -ENODEV; + + return i2c_transfer(dev, msg, 2); +} + +int i2c_write(struct altera_i2c_dev *dev, int flags, unsigned int slave_addr, + u32 offset, u8 *buffer, int len) +{ + struct i2c_msg msg; + u8 *buf; + int ret; + int i = 0; + + if (!dev->xfer) + return -ENODEV; + + buf = opae_malloc(I2C_MAX_OFFSET_LEN + len); + if (!buf) + return -ENOMEM; + + msg.addr = slave_addr; + msg.flags = 0; + msg.buf = buf; + + if (flags & I2C_FLAG_ADDR16) + msg.buf[i++] = offset >> 8; + + msg.buf[i++] = offset; + opae_memcpy(&msg.buf[i], buffer, len); + msg.len = i + len; + + ret = i2c_transfer(dev, &msg, 1); + + opae_free(buf); + return ret; +} + +int i2c_read8(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count) +{ + return i2c_read(dev, 0, slave_addr, offset, buf, count); +} + +int i2c_read16(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count) +{ + return i2c_read(dev, I2C_FLAG_ADDR16, slave_addr, offset, + buf, count); +} + +int i2c_write8(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count) +{ + return i2c_write(dev, 0, slave_addr, offset, buf, count); +} + +int i2c_write16(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count) +{ + return i2c_write(dev, I2C_FLAG_ADDR16, slave_addr, offset, + buf, count); +} + +static void i2c_indirect_write(struct altera_i2c_dev *dev, u32 reg, + u32 value) +{ + u64 ctrl; + + ctrl = I2C_CTRL_W | (reg >> 2); + + opae_writeq(value & I2C_WRITE_DATA_MASK, dev->base + I2C_WRITE); + opae_writeq(ctrl, dev->base + I2C_CTRL); +} + +static u32 i2c_indirect_read(struct altera_i2c_dev *dev, u32 reg) +{ + u64 tmp; + u64 ctrl; + u32 value; + + ctrl = I2C_CTRL_R | (reg >> 2); + opae_writeq(ctrl, dev->base + I2C_CTRL); + + /* FIXME: Read one more time to avoid HW timing issue. */ + tmp = opae_readq(dev->base + I2C_READ); + tmp = opae_readq(dev->base + I2C_READ); + + value = tmp & I2C_READ_DATA_MASK; + + return value; +} + +static void altera_i2c_transfer(struct altera_i2c_dev *dev, u32 data) +{ + /*send STOP on last byte*/ + if (dev->msg_len == 1) + data |= ALTERA_I2C_TFR_CMD_STO; + if (dev->msg_len > 0) + i2c_indirect_write(dev, ALTERA_I2C_TFR_CMD, data); +} + +static void altera_i2c_disable(struct altera_i2c_dev *dev) +{ + u32 val = i2c_indirect_read(dev, ALTERA_I2C_CTRL); + + i2c_indirect_write(dev, ALTERA_I2C_CTRL, val&~ALTERA_I2C_CTRL_EN); +} + +static void altera_i2c_enable(struct altera_i2c_dev *dev) +{ + u32 val = i2c_indirect_read(dev, ALTERA_I2C_CTRL); + + i2c_indirect_write(dev, ALTERA_I2C_CTRL, val | ALTERA_I2C_CTRL_EN); +} + +static void altera_i2c_reset(struct altera_i2c_dev *dev) +{ + altera_i2c_disable(dev); + altera_i2c_enable(dev); +} + +static int altera_i2c_wait_core_idle(struct altera_i2c_dev *dev) +{ + int retry = 0; + + while (i2c_indirect_read(dev, ALTERA_I2C_STATUS) + & ALTERA_I2C_STAT_CORE) { + if (retry++ > ALTERA_I2C_TIMEOUT_US) { + dev_err(dev, "timeout: Core Status not IDLE...\n"); + return -EBUSY; + } + udelay(1); + } + + return 0; +} + +static void altera_i2c_enable_interrupt(struct altera_i2c_dev *dev, + u32 mask, bool enable) +{ + u32 status; + + status = i2c_indirect_read(dev, ALTERA_I2C_ISER); + if (enable) + dev->isr_mask = status | mask; + else + dev->isr_mask = status&~mask; + + i2c_indirect_write(dev, ALTERA_I2C_ISER, dev->isr_mask); +} + +static void altera_i2c_interrupt_clear(struct altera_i2c_dev *dev, u32 mask) +{ + u32 int_en; + + int_en = i2c_indirect_read(dev, ALTERA_I2C_ISR); + + i2c_indirect_write(dev, ALTERA_I2C_ISR, int_en | mask); +} + +static void altera_i2c_read_rx_fifo(struct altera_i2c_dev *dev) +{ + size_t rx_avail; + size_t bytes; + + rx_avail = i2c_indirect_read(dev, ALTERA_I2C_RX_FIFO_LVL); + bytes = min(rx_avail, dev->msg_len); + + while (bytes-- > 0) { + *dev->buf++ = i2c_indirect_read(dev, ALTERA_I2C_RX_DATA); + dev->msg_len--; + altera_i2c_transfer(dev, 0); + } +} + +static void altera_i2c_stop(struct altera_i2c_dev *dev) +{ + i2c_indirect_write(dev, ALTERA_I2C_TFR_CMD, ALTERA_I2C_TFR_CMD_STO); +} + +static int altera_i2c_fill_tx_fifo(struct altera_i2c_dev *dev) +{ + size_t tx_avail; + int bytes; + int ret; + + tx_avail = dev->fifo_size - + i2c_indirect_read(dev, ALTERA_I2C_TC_FIFO_LVL); + bytes = min(tx_avail, dev->msg_len); + ret = dev->msg_len - bytes; + + while (bytes-- > 0) { + altera_i2c_transfer(dev, *dev->buf++); + dev->msg_len--; + } + + return ret; +} + +static u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg) +{ + return (msg->addr << 1) | (msg->flags & I2C_M_RD ? 1 : 0); +} + +static int altera_i2c_wait_complete(struct altera_i2c_dev *dev, + u32 *status) +{ + int retry = 0; + + while (!((*status = i2c_indirect_read(dev, ALTERA_I2C_ISR)) + & dev->isr_mask)) { + if (retry++ > ALTERA_I2C_TIMEOUT_US) + return -EBUSY; + + udelay(1000); + } + + return 0; +} + +static bool altera_handle_i2c_status(struct altera_i2c_dev *dev, u32 status) +{ + bool read, finish = false; + int ret; + + read = (dev->msg->flags & I2C_M_RD) != 0; + + if (status & ALTERA_I2C_ISR_ARB) { + altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISR_ARB); + dev->msg_err = -EAGAIN; + finish = true; + } else if (status & ALTERA_I2C_ISR_NACK) { + dev_debug(dev, "could not get ACK\n"); + dev->msg_err = -ENXIO; + altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISR_NACK); + altera_i2c_stop(dev); + finish = true; + } else if (read && (status & ALTERA_I2C_ISR_RXOF)) { + /* RX FIFO Overflow */ + altera_i2c_read_rx_fifo(dev); + altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISER_RXOF_EN); + altera_i2c_stop(dev); + dev_err(dev, "error: RX FIFO overflow\n"); + finish = true; + } else if (read && (status & ALTERA_I2C_ISR_RXRDY)) { + altera_i2c_read_rx_fifo(dev); + altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISR_RXRDY); + if (!dev->msg_len) + finish = true; + } else if (!read && (status & ALTERA_I2C_ISR_TXRDY)) { + altera_i2c_interrupt_clear(dev, ALTERA_I2C_ISR_TXRDY); + if (dev->msg_len > 0) + altera_i2c_fill_tx_fifo(dev); + else + finish = true; + } else { + dev_err(dev, "unexpected status:0x%x\n", status); + altera_i2c_interrupt_clear(dev, ALTERA_I2C_ALL_IRQ); + } + + if (finish) { + ret = altera_i2c_wait_core_idle(dev); + if (ret) + dev_err(dev, "message timeout\n"); + + altera_i2c_enable_interrupt(dev, ALTERA_I2C_ALL_IRQ, false); + altera_i2c_interrupt_clear(dev, ALTERA_I2C_ALL_IRQ); + dev_debug(dev, "message done\n"); + } + + return finish; +} + +static bool altera_i2c_poll_status(struct altera_i2c_dev *dev) +{ + u32 status; + bool finish = false; + int i = 0; + + do { + if (altera_i2c_wait_complete(dev, &status)) { + dev_err(dev, "altera i2c wait complete timeout, status=0x%x\n", + status); + return -EBUSY; + } + + finish = altera_handle_i2c_status(dev, status); + + if (i++ > I2C_XFER_RETRY) + break; + + } while (!finish); + + return finish; +} + +static int altera_i2c_xfer_msg(struct altera_i2c_dev *dev, + struct i2c_msg *msg) +{ + u32 int_mask = ALTERA_I2C_ISR_RXOF | + ALTERA_I2C_ISR_ARB | ALTERA_I2C_ISR_NACK; + u8 addr = i2c_8bit_addr_from_msg(msg); + bool finish; + + dev->msg = msg; + dev->msg_len = msg->len; + dev->buf = msg->buf; + dev->msg_err = 0; + altera_i2c_enable(dev); + + /*make sure RX FIFO is emtry*/ + do { + i2c_indirect_read(dev, ALTERA_I2C_RX_DATA); + } while (i2c_indirect_read(dev, ALTERA_I2C_RX_FIFO_LVL)); + + i2c_indirect_write(dev, ALTERA_I2C_TFR_CMD_RW_D, + ALTERA_I2C_TFR_CMD_STA | addr); + + /*enable irq*/ + if (msg->flags & I2C_M_RD) { + int_mask |= ALTERA_I2C_ISR_RXOF | ALTERA_I2C_ISR_RXRDY; + /* in polling mode, we should set this ISR register? */ + altera_i2c_enable_interrupt(dev, int_mask, true); + altera_i2c_transfer(dev, 0); + } else { + int_mask |= ALTERA_I2C_ISR_TXRDY; + altera_i2c_enable_interrupt(dev, int_mask, true); + altera_i2c_fill_tx_fifo(dev); + } + + finish = altera_i2c_poll_status(dev); + if (!finish) { + dev->msg_err = -ETIMEDOUT; + dev_err(dev, "%s: i2c transfer error\n", __func__); + } + + altera_i2c_enable_interrupt(dev, int_mask, false); + + if (i2c_indirect_read(dev, ALTERA_I2C_STATUS) & ALTERA_I2C_STAT_CORE) + dev_info(dev, "core not idle...\n"); + + altera_i2c_disable(dev); + + return dev->msg_err; +} + +static int altera_i2c_xfer(struct altera_i2c_dev *dev, + struct i2c_msg *msg, int num) +{ + int ret = 0; + int i; + + for (i = 0; i < num; i++, msg++) { + ret = altera_i2c_xfer_msg(dev, msg); + if (ret) + break; + } + + return ret; +} + +static void altera_i2c_hardware_init(struct altera_i2c_dev *dev) +{ + u32 divisor = dev->i2c_clk / dev->bus_clk_rate; + u32 clk_mhz = dev->i2c_clk / 1000000; + u32 tmp = (ALTERA_I2C_THRESHOLD << ALTERA_I2C_CTRL_RXT_SHFT) | + (ALTERA_I2C_THRESHOLD << ALTERA_I2C_CTRL_TCT_SHFT); + u32 t_high, t_low; + + if (dev->bus_clk_rate <= 100000) { + tmp &= ~ALTERA_I2C_CTRL_BSPEED; + /*standard mode SCL 50/50*/ + t_high = divisor*1/2; + t_low = divisor*1/2; + } else { + tmp |= ALTERA_I2C_CTRL_BSPEED; + /*Fast mode SCL 33/66*/ + t_high = divisor*1/3; + t_low = divisor*2/3; + } + + i2c_indirect_write(dev, ALTERA_I2C_CTRL, tmp); + + dev_info(dev, "%s: rate=%uHz per_clk=%uMHz -> ratio=1:%u\n", + __func__, dev->bus_clk_rate, clk_mhz, divisor); + + /*reset the i2c*/ + altera_i2c_reset(dev); + + /*Set SCL high Time*/ + i2c_indirect_write(dev, ALTERA_I2C_SCL_HIGH, t_high); + /*Set SCL low time*/ + i2c_indirect_write(dev, ALTERA_I2C_SCL_LOW, t_low); + /*Set SDA Hold time, 300ms*/ + i2c_indirect_write(dev, ALTERA_I2C_SDA_HOLD, (300*clk_mhz)/1000); + + altera_i2c_enable_interrupt(dev, ALTERA_I2C_ALL_IRQ, false); +} + +struct altera_i2c_dev *altera_i2c_probe(void *base) +{ + struct altera_i2c_dev *dev; + + dev = opae_malloc(sizeof(*dev)); + if (!dev) + return NULL; + + dev->base = (u8 *)base; + dev->i2c_param.info = opae_readq(dev->base + I2C_PARAM); + + if (dev->i2c_param.devid != 0xEE011) { + dev_err(dev, "find a invalid i2c master\n"); + return NULL; + } + + dev->fifo_size = dev->i2c_param.fifo_depth; + + if (dev->i2c_param.max_req == ALTERA_I2C_100KHZ) + dev->bus_clk_rate = 100000; + else if (dev->i2c_param.max_req == ALTERA_I2C_400KHZ) + /* i2c bus clk 400KHz*/ + dev->bus_clk_rate = 400000; + + /* i2c input clock for vista creek is 100MHz */ + dev->i2c_clk = dev->i2c_param.ref_clk * 1000000; + dev->xfer = altera_i2c_xfer; + + altera_i2c_hardware_init(dev); + + return dev; +} + +int altera_i2c_remove(struct altera_i2c_dev *dev) +{ + altera_i2c_disable(dev); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_i2c.h b/drivers/raw/ifpga_rawdev/base/opae_i2c.h new file mode 100644 index 0000000..8890c8f --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_i2c.h @@ -0,0 +1,130 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2019 Intel Corporation + */ + +#ifndef _OPAE_I2C_H +#define _OPAE_I2C_H + +#include "opae_osdep.h" + +#define ALTERA_I2C_TFR_CMD 0x00 /* Transfer Command register */ +#define ALTERA_I2C_TFR_CMD_STA BIT(9) /* send START before byte */ +#define ALTERA_I2C_TFR_CMD_STO BIT(8) /* send STOP after byte */ +#define ALTERA_I2C_TFR_CMD_RW_D BIT(0) /* Direction of transfer */ +#define ALTERA_I2C_RX_DATA 0x04 /* RX data FIFO register */ +#define ALTERA_I2C_CTRL 0x8 /* Control register */ +#define ALTERA_I2C_CTRL_RXT_SHFT 4 /* RX FIFO Threshold */ +#define ALTERA_I2C_CTRL_TCT_SHFT 2 /* TFER CMD FIFO Threshold */ +#define ALTERA_I2C_CTRL_BSPEED BIT(1) /* Bus Speed */ +#define ALTERA_I2C_CTRL_EN BIT(0) /* Enable Core */ +#define ALTERA_I2C_ISER 0xc /* Interrupt Status Enable register */ +#define ALTERA_I2C_ISER_RXOF_EN BIT(4) /* Enable RX OVERFLOW IRQ */ +#define ALTERA_I2C_ISER_ARB_EN BIT(3) /* Enable ARB LOST IRQ */ +#define ALTERA_I2C_ISER_NACK_EN BIT(2) /* Enable NACK DET IRQ */ +#define ALTERA_I2C_ISER_RXRDY_EN BIT(1) /* Enable RX Ready IRQ */ +#define ALTERA_I2C_ISER_TXRDY_EN BIT(0) /* Enable TX Ready IRQ */ +#define ALTERA_I2C_ISR 0x10 /* Interrupt Status register */ +#define ALTERA_I2C_ISR_RXOF BIT(4) /* RX OVERFLOW */ +#define ALTERA_I2C_ISR_ARB BIT(3) /* ARB LOST */ +#define ALTERA_I2C_ISR_NACK BIT(2) /* NACK DET */ +#define ALTERA_I2C_ISR_RXRDY BIT(1) /* RX Ready */ +#define ALTERA_I2C_ISR_TXRDY BIT(0) /* TX Ready */ +#define ALTERA_I2C_STATUS 0x14 /* Status register */ +#define ALTERA_I2C_STAT_CORE BIT(0) /* Core Status */ +#define ALTERA_I2C_TC_FIFO_LVL 0x18 /* Transfer FIFO LVL register */ +#define ALTERA_I2C_RX_FIFO_LVL 0x1c /* Receive FIFO LVL register */ +#define ALTERA_I2C_SCL_LOW 0x20 /* SCL low count register */ +#define ALTERA_I2C_SCL_HIGH 0x24 /* SCL high count register */ +#define ALTERA_I2C_SDA_HOLD 0x28 /* SDA hold count register */ + +#define ALTERA_I2C_ALL_IRQ (ALTERA_I2C_ISR_RXOF | ALTERA_I2C_ISR_ARB | \ + ALTERA_I2C_ISR_NACK | ALTERA_I2C_ISR_RXRDY | \ + ALTERA_I2C_ISR_TXRDY) + +#define ALTERA_I2C_THRESHOLD 0 +#define ALTERA_I2C_DFLT_FIFO_SZ 8 +#define ALTERA_I2C_TIMEOUT_US 250000 /* 250ms */ + +#define I2C_PARAM 0x8 +#define I2C_CTRL 0x10 +#define I2C_CTRL_R BIT_ULL(9) +#define I2C_CTRL_W BIT_ULL(8) +#define I2C_CTRL_ADDR_MASK GENMASK_ULL(3, 0) +#define I2C_READ 0x18 +#define I2C_READ_DATA_VALID BIT_ULL(32) +#define I2C_READ_DATA_MASK GENMASK_ULL(31, 0) +#define I2C_WRITE 0x20 +#define I2C_WRITE_DATA_MASK GENMASK_ULL(31, 0) + +#define ALTERA_I2C_100KHZ 0 +#define ALTERA_I2C_400KHZ 1 + +/* i2c slave using 16bit address */ +#define I2C_FLAG_ADDR16 1 + +#define I2C_XFER_RETRY 10 + +struct i2c_core_param { + union { + u64 info; + struct { + u16 fifo_depth:9; + u8 interface:1; + /*reference clock of I2C core in MHz*/ + u32 ref_clk:10; + /*Max I2C interface freq*/ + u8 max_req:4; + u64 devid:32; + /* number of MAC address*/ + u8 nu_macs:8; + }; + }; +}; + +struct altera_i2c_dev { + u8 *base; + struct i2c_core_param i2c_param; + u32 fifo_size; + u32 bus_clk_rate; /* i2c bus clock */ + u32 i2c_clk; /* i2c input clock */ + struct i2c_msg *msg; + size_t msg_len; + int msg_err; + u32 isr_mask; + u8 *buf; + int (*xfer)(struct altera_i2c_dev *dev, struct i2c_msg *msg, int num); +}; + +/** + * struct i2c_msg: an I2C message + */ +struct i2c_msg { + unsigned int addr; + unsigned int flags; + unsigned int len; + u8 *buf; +}; + +#define I2C_MAX_OFFSET_LEN 4 + +enum i2c_msg_flags { + I2C_M_TEN = 0x0010, /*ten-bit chip address*/ + I2C_M_RD = 0x0001, /*read data*/ + I2C_M_STOP = 0x8000, /*send stop after this message*/ +}; + +struct altera_i2c_dev *altera_i2c_probe(void *base); +int altera_i2c_remove(struct altera_i2c_dev *dev); +int i2c_read(struct altera_i2c_dev *dev, int flags, unsigned int slave_addr, + u32 offset, u8 *buf, u32 count); +int i2c_write(struct altera_i2c_dev *dev, int flags, unsigned int slave_addr, + u32 offset, u8 *buffer, int len); +int i2c_read8(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count); +int i2c_read16(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count); +int i2c_write8(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count); +int i2c_write16(struct altera_i2c_dev *dev, unsigned int slave_addr, u32 offset, + u8 *buf, u32 count); +#endif From patchwork Wed Apr 10 06:27:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52538 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 211331B10E; Wed, 10 Apr 2019 08:27:50 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 549501B0FF for ; Wed, 10 Apr 2019 08:27:45 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 23:27:44 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,332,1549958400"; d="scan'208";a="147981011" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by FMSMGA003.fm.intel.com with ESMTP; 09 Apr 2019 23:27:41 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Wed, 10 Apr 2019 14:27:49 +0800 Message-Id: <1554877672-19745-12-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554877672-19745-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554877672-19745-1-git-send-email-rosen.xu@intel.com> Subject: [dpdk-dev] [PATCH v7 11/14] raw/ifpga_rawdev: add eth group driver X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Tianfei zhang There is two eth group devices in PAC N3000 card, each eth group include PHY device and MAC device. Exposing APIs for DPDK PMD driver to access those devices. Signed-off-by: Tianfei Zhang --- drivers/raw/ifpga_rawdev/base/Makefile | 1 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 74 ++++++- drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 39 ++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 6 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 2 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 12 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 250 ++++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 7 + drivers/raw/ifpga_rawdev/base/meson.build | 1 + drivers/raw/ifpga_rawdev/base/opae_eth_group.c | 145 +++++++++++++ drivers/raw/ifpga_rawdev/base/opae_eth_group.h | 96 +++++++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 149 +++++++++++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 27 +++ drivers/raw/ifpga_rawdev/base/opae_intel_max10.h | 42 +++- drivers/raw/ifpga_rawdev/base/opae_osdep.h | 16 +- 15 files changed, 858 insertions(+), 9 deletions(-) create mode 100644 drivers/raw/ifpga_rawdev/base/opae_eth_group.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_eth_group.h diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile index edb538f..c5bbcbd 100644 --- a/drivers/raw/ifpga_rawdev/base/Makefile +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -27,5 +27,6 @@ SRCS-y += opae_spi_transaction.c SRCS-y += opae_intel_max10.c SRCS-y += opae_i2c.c SRCS-y += opae_at24_eeprom.c +SRCS-y += opae_eth_group.c SRCS-y += $(wildcard $(SRCDIR)/base/$(OSDEP)/*.c) diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.c b/drivers/raw/ifpga_rawdev/base/ifpga_api.c index c447b3c..3ddbcdc 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_api.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -170,7 +170,6 @@ struct opae_accelerator_ops ifpga_acc_ops = { }; /* Bridge APIs */ - static int ifpga_br_reset(struct opae_bridge *br) { struct ifpga_port_hw *port = br->data; @@ -192,8 +191,26 @@ static int ifpga_mgr_flash(struct opae_manager *mgr, int id, void *buf, return ifpga_pr(hw, id, buf, size, status); } +static int ifpga_mgr_get_eth_group_region_info(struct opae_manager *mgr, + struct opae_eth_group_region_info *info) +{ + struct ifpga_fme_hw *fme = mgr->data; + + if (info->group_id >= MAX_ETH_GROUP_DEVICES) + return -EINVAL; + + info->phys_addr = fme->eth_group_region[info->group_id].phys_addr; + info->addr = fme->eth_group_region[info->group_id].addr; + info->len = fme->eth_group_region[info->group_id].len; + + info->mem_idx = fme->nums_acc_region + info->group_id; + + return 0; +} + struct opae_manager_ops ifpga_mgr_ops = { .flash = ifpga_mgr_flash, + .get_eth_group_region_info = ifpga_mgr_get_eth_group_region_info, }; static int ifpga_mgr_read_mac_rom(struct opae_manager *mgr, int offset, @@ -212,10 +229,65 @@ static int ifpga_mgr_write_mac_rom(struct opae_manager *mgr, int offset, return fme_mgr_write_mac_rom(fme, offset, buf, size); } +static int ifpga_mgr_get_eth_group_nums(struct opae_manager *mgr) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_get_eth_group_nums(fme); +} + +static int ifpga_mgr_get_eth_group_info(struct opae_manager *mgr, + u8 group_id, struct opae_eth_group_info *info) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_get_eth_group_info(fme, group_id, info); +} + +static int ifpga_mgr_eth_group_reg_read(struct opae_manager *mgr, u8 group_id, + u8 type, u8 index, u16 addr, u32 *data) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_eth_group_read_reg(fme, group_id, + type, index, addr, data); +} + +static int ifpga_mgr_eth_group_reg_write(struct opae_manager *mgr, u8 group_id, + u8 type, u8 index, u16 addr, u32 data) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_eth_group_write_reg(fme, group_id, + type, index, addr, data); +} + +static int ifpga_mgr_get_retimer_info(struct opae_manager *mgr, + struct opae_retimer_info *info) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_get_retimer_info(fme, info); +} + +static int ifpga_mgr_get_retimer_status(struct opae_manager *mgr, + struct opae_retimer_status *status) +{ + struct ifpga_fme_hw *fme = mgr->data; + + return fme_mgr_get_retimer_status(fme, status); +} + /* Network APIs in FME */ struct opae_manager_networking_ops ifpga_mgr_network_ops = { .read_mac_rom = ifpga_mgr_read_mac_rom, .write_mac_rom = ifpga_mgr_write_mac_rom, + .get_eth_group_nums = ifpga_mgr_get_eth_group_nums, + .get_eth_group_info = ifpga_mgr_get_eth_group_info, + .eth_group_reg_read = ifpga_mgr_eth_group_reg_read, + .eth_group_reg_write = ifpga_mgr_eth_group_reg_write, + .get_retimer_info = ifpga_mgr_get_retimer_info, + .get_retimer_status = ifpga_mgr_get_retimer_status, }; /* Adapter APIs */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h index 62f71c7..b7151ca 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -22,6 +22,7 @@ #define FME_FEATURE_MAX10_SPI "fme_max10_spi" #define FME_FEATURE_NIOS_SPI "fme_nios_spi" #define FME_FEATURE_I2C_MASTER "fme_i2c_master" +#define FME_FEATURE_ETH_GROUP "fme_eth_group" #define PORT_FEATURE_HEADER "port_hdr" #define PORT_FEATURE_UAFU "port_uafu" @@ -88,6 +89,7 @@ enum fpga_id_type { #define FME_FEATURE_ID_MAX10_SPI 0xe #define FME_FEATURE_ID_NIOS_SPI 0xd #define FME_FEATURE_ID_I2C_MASTER 0xf +#define FME_FEATURE_ID_ETH_GROUP 0x10 #define PORT_FEATURE_ID_HEADER FEATURE_ID_FIU_HEADER #define PORT_FEATURE_ID_ERROR 0x10 @@ -1661,5 +1663,42 @@ struct bts_header { (((bts_hdr)->guid_h == GBS_GUID_H) && \ ((bts_hdr)->guid_l == GBS_GUID_L)) +/* bitstream id definition */ +struct fme_bitstream_id { + union { + u64 id; + struct { + u64 hash:32; + u64 interface:4; + u64 reserved:12; + u64 debug:4; + u64 patch:4; + u64 minor:4; + u64 major:4; + }; + }; +}; + +enum board_interface { + VC_8_10G = 0, + VC_4_25G = 1, + VC_2_1_25 = 2, + VC_4_25G_2_25G = 3, + VC_2_2_25G = 4, +}; + +struct ifpga_fme_board_info { + enum board_interface type; + u32 build_hash; + u32 debug_version; + u32 patch_version; + u32 minor_version; + u32 major_version; + u32 nums_of_retimer; + u32 ports_per_retimer; + u32 nums_of_fvl; + u32 ports_per_fvl; +}; + #pragma pack(pop) #endif /* _BASE_IFPGA_DEFINES_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c index 666dae1..44086c1 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -232,6 +232,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) struct opae_bridge *br; struct opae_accelerator *acc; struct ifpga_port_hw *port; + struct ifpga_fme_hw *fme; struct feature *feature; if (!binfo->fiu) @@ -264,8 +265,13 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) } acc->br = br; + if (hw->adapter->mgr) + acc->mgr = hw->adapter->mgr; acc->index = br->id; + fme = &hw->fme; + fme->nums_acc_region = info->num_regions; + opae_adapter_add_acc(hw->adapter, acc); } else if (binfo->current_type == FME_ID) { diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c index 0454f80..5ebc449 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -203,6 +203,8 @@ int port_clear_error(struct ifpga_port_hw *port) &fme_nios_spi_master_ops),}, {FEATURE_DRV(FME_FEATURE_ID_I2C_MASTER, FME_FEATURE_I2C_MASTER, &fme_i2c_master_ops),}, + {FEATURE_DRV(FME_FEATURE_ID_ETH_GROUP, FME_FEATURE_ETH_GROUP, + &fme_eth_group_ops),}, {0, NULL, NULL}, /* end of arrary */ }; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h index a398a98..3f63f5a 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -173,6 +173,7 @@ int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, extern struct feature_ops fme_emif_ops; extern struct feature_ops fme_spi_master_ops; extern struct feature_ops fme_i2c_master_ops; +extern struct feature_ops fme_eth_group_ops; extern struct feature_ops fme_nios_spi_master_ops; int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop); @@ -204,4 +205,15 @@ int fme_mgr_read_mac_rom(struct ifpga_fme_hw *fme, int offset, void *buf, int size); int fme_mgr_write_mac_rom(struct ifpga_fme_hw *fme, int offset, void *buf, int size); +int fme_mgr_get_eth_group_nums(struct ifpga_fme_hw *fme); +int fme_mgr_get_eth_group_info(struct ifpga_fme_hw *fme, + u8 group_id, struct opae_eth_group_info *info); +int fme_mgr_eth_group_read_reg(struct ifpga_fme_hw *fme, u8 group_id, + u8 type, u8 index, u16 addr, u32 *data); +int fme_mgr_eth_group_write_reg(struct ifpga_fme_hw *fme, u8 group_id, + u8 type, u8 index, u16 addr, u32 data); +int fme_mgr_get_retimer_info(struct ifpga_fme_hw *fme, + struct opae_retimer_info *info); +int fme_mgr_get_retimer_status(struct ifpga_fme_hw *fme, + struct opae_retimer_status *status); #endif /* _IFPGA_FEATURE_DEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c index 95e022e..2cfb158 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_fme.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -769,6 +769,90 @@ struct feature_ops fme_emif_ops = { .uinit = fme_emif_uinit, }; +static const char *board_type_to_string(u32 type) +{ + switch (type) { + case VC_8_10G: + return "VC_8x10G"; + case VC_4_25G: + return "VC_4x25G"; + case VC_2_1_25: + return "VC_2x1x25G"; + case VC_4_25G_2_25G: + return "VC_4x25G+2x25G"; + case VC_2_2_25G: + return "VC_2x2x25G"; + } + + return "unknown"; +} + +static int board_type_to_info(u32 type, + struct ifpga_fme_board_info *info) +{ + switch (type) { + case VC_8_10G: + info->nums_of_retimer = 2; + info->ports_per_retimer = 4; + info->nums_of_fvl = 2; + info->ports_per_fvl = 4; + break; + case VC_4_25G: + info->nums_of_retimer = 1; + info->ports_per_retimer = 4; + info->nums_of_fvl = 2; + info->ports_per_fvl = 2; + break; + case VC_2_1_25: + info->nums_of_retimer = 2; + info->ports_per_retimer = 1; + info->nums_of_fvl = 1; + info->ports_per_fvl = 2; + break; + case VC_2_2_25G: + info->nums_of_retimer = 2; + info->ports_per_retimer = 2; + info->nums_of_fvl = 2; + info->ports_per_fvl = 2; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int fme_get_board_interface(struct ifpga_fme_hw *fme) +{ + struct fme_bitstream_id id; + + if (fme_hdr_get_bitstream_id(fme, &id.id)) + return -EINVAL; + + fme->board_info.type = id.interface; + fme->board_info.build_hash = id.hash; + fme->board_info.debug_version = id.debug; + fme->board_info.major_version = id.major; + fme->board_info.minor_version = id.minor; + + dev_info(fme, "board type: %s major_version:%u minor_version:%u build_hash:%u\n", + board_type_to_string(fme->board_info.type), + fme->board_info.major_version, + fme->board_info.minor_version, + fme->board_info.build_hash); + + if (board_type_to_info(fme->board_info.type, &fme->board_info)) + return -EINVAL; + + dev_info(fme, "get board info: nums_retimers %d ports_per_retimer %d nums_fvl %d ports_per_fvl %d\n", + fme->board_info.nums_of_retimer, + fme->board_info.ports_per_retimer, + fme->board_info.nums_of_fvl, + fme->board_info.ports_per_fvl); + + return 0; +} + static int spi_self_checking(void) { u32 val; @@ -935,6 +1019,8 @@ static int fme_nios_spi_init(struct feature *feature) goto release_dev; } + fme_get_board_interface(fme); + fme->max10_dev = max10; /* SPI self test */ @@ -1027,6 +1113,45 @@ struct feature_ops fme_i2c_master_ops = { .uinit = fme_i2c_uninit, }; +static int fme_eth_group_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; + struct eth_group_device *dev; + + dev = (struct eth_group_device *)eth_group_probe(feature->addr); + if (!dev) + return -ENODEV; + + fme->eth_dev[dev->group_id] = dev; + + fme->eth_group_region[dev->group_id].addr = + feature->addr; + fme->eth_group_region[dev->group_id].phys_addr = + feature->phys_addr; + fme->eth_group_region[dev->group_id].len = + feature->size; + + fme->nums_eth_dev++; + + dev_info(NULL, "FME PHY Group %d Init.\n", dev->group_id); + dev_info(NULL, "found %d eth group, addr %p phys_addr 0x%llx len %u\n", + dev->group_id, feature->addr, + (unsigned long long)feature->phys_addr, + feature->size); + + return 0; +} + +static void fme_eth_group_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +struct feature_ops fme_eth_group_ops = { + .init = fme_eth_group_init, + .uinit = fme_eth_group_uinit, +}; + int fme_mgr_read_mac_rom(struct ifpga_fme_hw *fme, int offset, void *buf, int size) { @@ -1050,3 +1175,128 @@ int fme_mgr_write_mac_rom(struct ifpga_fme_hw *fme, int offset, return at24_eeprom_write(dev, AT24512_SLAVE_ADDR, offset, buf, size); } + +static struct eth_group_device *get_eth_group_dev(struct ifpga_fme_hw *fme, + u8 group_id) +{ + struct eth_group_device *dev; + + if (group_id > (MAX_ETH_GROUP_DEVICES - 1)) + return NULL; + + dev = (struct eth_group_device *)fme->eth_dev[group_id]; + if (!dev) + return NULL; + + if (dev->status != ETH_GROUP_DEV_ATTACHED) + return NULL; + + return dev; +} + +int fme_mgr_get_eth_group_nums(struct ifpga_fme_hw *fme) +{ + return fme->nums_eth_dev; +} + +int fme_mgr_get_eth_group_info(struct ifpga_fme_hw *fme, + u8 group_id, struct opae_eth_group_info *info) +{ + struct eth_group_device *dev; + + dev = get_eth_group_dev(fme, group_id); + if (!dev) + return -ENODEV; + + info->group_id = group_id; + info->speed = dev->speed; + info->nums_of_mac = dev->mac_num; + info->nums_of_phy = dev->phy_num; + + return 0; +} + +int fme_mgr_eth_group_read_reg(struct ifpga_fme_hw *fme, u8 group_id, + u8 type, u8 index, u16 addr, u32 *data) +{ + struct eth_group_device *dev; + + dev = get_eth_group_dev(fme, group_id); + if (!dev) + return -ENODEV; + + return eth_group_read_reg(dev, type, index, addr, data); +} + +int fme_mgr_eth_group_write_reg(struct ifpga_fme_hw *fme, u8 group_id, + u8 type, u8 index, u16 addr, u32 data) +{ + struct eth_group_device *dev; + + dev = get_eth_group_dev(fme, group_id); + if (!dev) + return -ENODEV; + + return eth_group_write_reg(dev, type, index, addr, data); +} + +static int fme_get_eth_group_speed(struct ifpga_fme_hw *fme, + u8 group_id) +{ + struct eth_group_device *dev; + + dev = get_eth_group_dev(fme, group_id); + if (!dev) + return -ENODEV; + + return dev->speed; +} + +int fme_mgr_get_retimer_info(struct ifpga_fme_hw *fme, + struct opae_retimer_info *info) +{ + struct intel_max10_device *dev; + + dev = (struct intel_max10_device *)fme->max10_dev; + if (!dev) + return -ENODEV; + + info->nums_retimer = fme->board_info.nums_of_retimer; + info->ports_per_retimer = fme->board_info.ports_per_retimer; + info->nums_fvl = fme->board_info.nums_of_fvl; + info->ports_per_fvl = fme->board_info.ports_per_fvl; + + /* The speed of PKVL is identical the eth group's speed */ + info->support_speed = fme_get_eth_group_speed(fme, + LINE_SIDE_GROUP_ID); + + return 0; +} + +int fme_mgr_get_retimer_status(struct ifpga_fme_hw *fme, + struct opae_retimer_status *status) +{ + struct intel_max10_device *dev; + unsigned int val; + + dev = (struct intel_max10_device *)fme->max10_dev; + if (!dev) + return -ENODEV; + + if (max10_reg_read(PKVL_LINK_STATUS, &val)) { + dev_err(dev, "%s: read pkvl status fail\n", __func__); + return -EINVAL; + } + + /* The speed of PKVL is identical the eth group's speed */ + status->speed = fme_get_eth_group_speed(fme, + LINE_SIDE_GROUP_ID); + + status->line_link_bitmap = val; + + dev_debug(dev, "get retimer status: speed:%d. line_link_bitmap:0x%x\n", + status->speed, + status->line_link_bitmap); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_hw.h b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h index e296dd2..a428d69 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_hw.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -7,6 +7,7 @@ #include "ifpga_defines.h" #include "opae_ifpga_hw_api.h" +#include "opae_eth_group.h" /** List of private feateues */ TAILQ_HEAD(ifpga_feature_list, feature); @@ -82,6 +83,12 @@ struct ifpga_fme_hw { void *max10_dev; /* MAX10 device */ void *i2c_master; /* I2C Master device */ + void *eth_dev[MAX_ETH_GROUP_DEVICES]; + struct opae_reg_region + eth_group_region[MAX_ETH_GROUP_DEVICES]; + struct ifpga_fme_board_info board_info; + int nums_eth_dev; + unsigned int nums_acc_region; }; enum ifpga_port_state { diff --git a/drivers/raw/ifpga_rawdev/base/meson.build b/drivers/raw/ifpga_rawdev/base/meson.build index 7655985..f1015bb 100644 --- a/drivers/raw/ifpga_rawdev/base/meson.build +++ b/drivers/raw/ifpga_rawdev/base/meson.build @@ -20,6 +20,7 @@ sources = [ 'opae_intel_max10.c', 'opae_i2c.c', 'opae_at24_eeprom.c', + 'opae_eth_group.c', ] error_cflags = ['-Wno-sign-compare', '-Wno-unused-value', diff --git a/drivers/raw/ifpga_rawdev/base/opae_eth_group.c b/drivers/raw/ifpga_rawdev/base/opae_eth_group.c new file mode 100644 index 0000000..8db6693 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_eth_group.c @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2019 Intel Corporation + */ + +#include "opae_osdep.h" +#include "opae_eth_group.h" + +#define DATA_VAL_INVL 1 /* us */ +#define DATA_VAL_POLL_TIMEOUT 10 /* us */ + +static const char *eth_type_to_string(u8 type) +{ + switch (type) { + case ETH_GROUP_PHY: + return "phy"; + case ETH_GROUP_MAC: + return "mac"; + case ETH_GROUP_ETHER: + return "ethernet wrapper"; + } + + return "unknown"; +} + +static int eth_group_get_select(struct eth_group_device *dev, + u8 type, u8 index, u8 *select) +{ + /* + * in different speed configuration, the index of + * PHY and MAC are different. + * + * 1 ethernet wrapper -> Device Select 0x0 - fixed value + * n PHYs -> Device Select 0x2,4,6,8,A,C,E,10,... + * n MACs -> Device Select 0x3,5,7,9,B,D,F,11,... + */ + + if (type == ETH_GROUP_PHY && index < dev->phy_num) + *select = index * 2 + 2; + else if (type == ETH_GROUP_MAC && index < dev->mac_num) + *select = index * 2 + 3; + else if (type == ETH_GROUP_ETHER && index == 0) + *select = 0; + else + return -EINVAL; + + return 0; +} + +int eth_group_write_reg(struct eth_group_device *dev, + u8 type, u8 index, u16 addr, u32 data) +{ + u8 dev_select = 0; + u64 v = 0; + int ret; + + dev_debug(dev, "%s type %s index %u addr 0x%x\n", + __func__, eth_type_to_string(type), index, addr); + + /* find device select */ + ret = eth_group_get_select(dev, type, index, &dev_select); + if (ret) + return ret; + + v = CMD_WR << CTRL_CMD_SHIT | + (u64)dev_select << CTRL_DS_SHIFT | + (u64)addr << CTRL_ADDR_SHIFT | + (data & CTRL_WR_DATA); + + /* only PHY has additional feature bit */ + if (type == ETH_GROUP_PHY) + v |= CTRL_FEAT_SELECT; + + opae_writeq(v, dev->base + ETH_GROUP_CTRL); + + return 0; +} + +int eth_group_read_reg(struct eth_group_device *dev, + u8 type, u8 index, u16 addr, u32 *data) +{ + u8 dev_select = 0; + u64 v = 0; + int ret; + + dev_debug(dev, "%s type %s index %u addr 0x%x\n", + __func__, eth_type_to_string(type), index, + addr); + + /* find device select */ + ret = eth_group_get_select(dev, type, index, &dev_select); + if (ret) + return ret; + + v = CMD_RD << CTRL_CMD_SHIT | + (u64)dev_select << CTRL_DS_SHIFT | + (u64)addr << CTRL_ADDR_SHIFT; + + /* only PHY has additional feature bit */ + if (type == ETH_GROUP_PHY) + v |= CTRL_FEAT_SELECT; + + opae_writeq(v, dev->base + ETH_GROUP_CTRL); + + if (opae_readq_poll_timeout(dev->base + ETH_GROUP_STAT, + v, v & STAT_DATA_VAL, DATA_VAL_INVL, + DATA_VAL_POLL_TIMEOUT)) + return -ETIMEDOUT; + + *data = (v & STAT_RD_DATA); + + dev_debug(dev, "%s data 0x%x\n", __func__, *data); + + return 0; +} + +struct eth_group_device *eth_group_probe(void *base) +{ + struct eth_group_device *dev; + + dev = opae_malloc(sizeof(*dev)); + if (!dev) + return NULL; + + dev->base = (u8 *)base; + + dev->info.info = opae_readq(dev->base + ETH_GROUP_INFO); + dev->group_id = dev->info.group_id; + dev->phy_num = dev->mac_num = dev->info.num_phys; + dev->speed = dev->info.speed; + + dev->status = ETH_GROUP_DEV_ATTACHED; + + dev_info(dev, "eth group device %d probe done: phy_num=mac_num:%d, speed=%d\n", + dev->group_id, dev->phy_num, dev->speed); + + return dev; +} + +void eth_group_release(struct eth_group_device *dev) +{ + if (dev) { + dev->status = ETH_GROUP_DEV_NOUSED; + opae_free(dev); + } +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_eth_group.h b/drivers/raw/ifpga_rawdev/base/opae_eth_group.h new file mode 100644 index 0000000..8d695cc --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_eth_group.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2019 Intel Corporation + */ + +#ifndef _OPAE_PHY_MAC_H +#define _OPAE_PHY_MAC_H + +#include "opae_osdep.h" + +#define MAX_ETH_GROUP_DEVICES 2 + +#define LINE_SIDE_GROUP_ID 0 +#define HOST_SIDE_GROUP_ID 1 + +#define ETH_GROUP_SELECT_FEAT 1 + +#define ETH_GROUP_PHY 1 +#define ETH_GROUP_MAC 2 +#define ETH_GROUP_ETHER 3 + +#define ETH_GROUP_INFO 0x8 +#define INFO_SPEED GENMASK_ULL(23, 16) +#define ETH_SPEED_10G 10 +#define ETH_SPEED_25G 25 +#define INFO_PHY_NUM GENMASK_ULL(15, 8) +#define INFO_GROUP_NUM GENMASK_ULL(7, 0) + +#define ETH_GROUP_CTRL 0x10 +#define CTRL_CMD GENMASK_ULL(63, 62) +#define CTRL_CMD_SHIT 62 +#define CMD_NOP 0ULL +#define CMD_RD 1ULL +#define CMD_WR 2ULL +#define CTRL_DEV_SELECT GENMASK_ULL(52, 49) +#define CTRL_DS_SHIFT 49 +#define CTRL_FEAT_SELECT BIT_ULL(48) +#define SELECT_IP 0 +#define SELECT_FEAT 1 +#define CTRL_ADDR GENMASK_ULL(47, 32) +#define CTRL_ADDR_SHIFT 32 +#define CTRL_WR_DATA GENMASK_ULL(31, 0) + +#define ETH_GROUP_STAT 0x18 +#define STAT_DATA_VAL BIT_ULL(32) +#define STAT_RD_DATA GENMASK_ULL(31, 0) + +struct opae_eth_group_info { + u8 group_id; + u8 speed; + u8 nums_of_phy; + u8 nums_of_mac; +}; + +struct opae_eth_group_region_info { + u8 group_id; + u64 phys_addr; + u64 len; + u8 *addr; + u8 mem_idx; +}; + +struct eth_group_info_reg { + union { + u64 info; + struct { + u8 group_id:8; + u8 num_phys:8; + u8 speed:8; + u8 direction:1; + u64 resvd:39; + }; + }; +}; + +enum eth_group_status { + ETH_GROUP_DEV_NOUSED = 0, + ETH_GROUP_DEV_ATTACHED, +}; + +struct eth_group_device { + u8 *base; + struct eth_group_info_reg info; + enum eth_group_status status; + u8 speed; + u8 group_id; + u8 phy_num; + u8 mac_num; +}; + +struct eth_group_device *eth_group_probe(void *base); +void eth_group_release(struct eth_group_device *dev); +int eth_group_read_reg(struct eth_group_device *dev, + u8 type, u8 index, u16 addr, u32 *data); +int eth_group_write_reg(struct eth_group_device *dev, + u8 type, u8 index, u16 addr, u32 data); +#endif diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c index ec2b4c7..0e117d0 100644 --- a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -426,3 +426,152 @@ int opae_manager_write_mac_rom(struct opae_manager *mgr, int port, return -ENOENT; } + +/** + * opae_manager_get_eth_group_nums - get eth group numbers + * @mgr: opae_manager for eth group + * + * Return: the numbers of eth group + */ +int opae_manager_get_eth_group_nums(struct opae_manager *mgr) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + if (mgr->network_ops->get_retimer_info) + return mgr->network_ops->get_eth_group_nums(mgr); + + return -ENOENT; +} + +/** + * opae_manager_get_eth_group_info - get eth group info + * @mgr: opae_manager for eth group + * @group_id: id for eth group + * @info: info return to caller + * + * Return: 0 on success, otherwise error code + */ +int opae_manager_get_eth_group_info(struct opae_manager *mgr, + u8 group_id, struct opae_eth_group_info *info) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + if (mgr->network_ops->get_retimer_info) + return mgr->network_ops->get_eth_group_info(mgr, + group_id, info); + + return -ENOENT; +} + +/** + * opae_manager_get_eth_group_region_info + * @mgr: opae_manager for flash. + * @info: the memory region info for eth group + * + * Return: 0 on success, otherwise error code. + */ +int opae_manager_get_eth_group_region_info(struct opae_manager *mgr, + u8 group_id, struct opae_eth_group_region_info *info) +{ + if (!mgr) + return -EINVAL; + + if (group_id >= MAX_ETH_GROUP_DEVICES) + return -EINVAL; + + info->group_id = group_id; + + if (mgr && mgr->ops && mgr->ops->get_eth_group_region_info) + return mgr->ops->get_eth_group_region_info(mgr, info); + + return -ENOENT; +} + +/** + * opae_manager_eth_group_read_reg - read ETH group register + * @mgr: opae_manager for ETH Group + * @group_id: ETH group id + * @type: eth type + * @index: port index in eth group device + * @addr: register address of ETH Group + * @data: read buffer + * + * Return: 0 on success, otherwise error code + */ +int opae_manager_eth_group_read_reg(struct opae_manager *mgr, u8 group_id, + u8 type, u8 index, u16 addr, u32 *data) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + if (mgr->network_ops->eth_group_reg_read) + return mgr->network_ops->eth_group_reg_read(mgr, group_id, + type, index, addr, data); + + return -ENOENT; +} + +/** + * opae_manager_eth_group_write_reg - write ETH group register + * @mgr: opae_manager for ETH Group + * @group_id: ETH group id + * @type: eth type + * @index: port index in eth group device + * @addr: register address of ETH Group + * @data: data will write to register + * + * Return: 0 on success, otherwise error code + */ +int opae_manager_eth_group_write_reg(struct opae_manager *mgr, u8 group_id, + u8 type, u8 index, u16 addr, u32 data) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + if (mgr->network_ops->eth_group_reg_write) + return mgr->network_ops->eth_group_reg_write(mgr, group_id, + type, index, addr, data); + + return -ENOENT; +} + +/** + * opae_manager_get_retimer_info - get retimer info like PKVL chip + * @mgr: opae_manager for retimer + * @info: info return to caller + * + * Return: 0 on success, otherwise error code + */ +int opae_manager_get_retimer_info(struct opae_manager *mgr, + struct opae_retimer_info *info) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + if (mgr->network_ops->get_retimer_info) + return mgr->network_ops->get_retimer_info(mgr, info); + + return -ENOENT; +} + +/** + * opae_manager_get_retimer_status - get retimer status + * @mgr: opae_manager of retimer + * @status: status of retimer + * + * Return: 0 on success, otherwise error code + */ +int opae_manager_get_retimer_status(struct opae_manager *mgr, + struct opae_retimer_status *status) +{ + if (!mgr || !mgr->network_ops) + return -EINVAL; + + if (mgr->network_ops->get_retimer_status) + return mgr->network_ops->get_retimer_status(mgr, + status); + + return -ENOENT; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h index 826da37..383e751 100644 --- a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -12,6 +12,7 @@ #include "opae_osdep.h" #include "opae_intel_max10.h" +#include "opae_eth_group.h" #ifndef PCI_MAX_RESOURCE #define PCI_MAX_RESOURCE 6 @@ -45,6 +46,8 @@ struct opae_manager { struct opae_manager_ops { int (*flash)(struct opae_manager *mgr, int id, void *buffer, u32 size, u64 *status); + int (*get_eth_group_region_info)(struct opae_manager *mgr, + struct opae_eth_group_region_info *info); }; /* networking management ops in FME */ @@ -53,6 +56,17 @@ struct opae_manager_networking_ops { int size); int (*write_mac_rom)(struct opae_manager *mgr, int offset, void *buf, int size); + int (*get_eth_group_nums)(struct opae_manager *mgr); + int (*get_eth_group_info)(struct opae_manager *mgr, + u8 group_id, struct opae_eth_group_info *info); + int (*eth_group_reg_read)(struct opae_manager *mgr, u8 group_id, + u8 type, u8 index, u16 addr, u32 *data); + int (*eth_group_reg_write)(struct opae_manager *mgr, u8 group_id, + u8 type, u8 index, u16 addr, u32 data); + int (*get_retimer_info)(struct opae_manager *mgr, + struct opae_retimer_info *info); + int (*get_retimer_status)(struct opae_manager *mgr, + struct opae_retimer_status *status); }; /* OPAE Manager APIs */ @@ -62,6 +76,8 @@ struct opae_manager * #define opae_manager_free(mgr) opae_free(mgr) int opae_manager_flash(struct opae_manager *mgr, int acc_id, void *buf, u32 size, u64 *status); +int opae_manager_get_eth_group_region_info(struct opae_manager *mgr, + u8 group_id, struct opae_eth_group_region_info *info); /* OPAE Bridge Data Structure */ struct opae_bridge_ops; @@ -276,4 +292,15 @@ int opae_manager_read_mac_rom(struct opae_manager *mgr, int port, struct opae_ether_addr *addr); int opae_manager_write_mac_rom(struct opae_manager *mgr, int port, struct opae_ether_addr *addr); +int opae_manager_get_retimer_info(struct opae_manager *mgr, + struct opae_retimer_info *info); +int opae_manager_get_retimer_status(struct opae_manager *mgr, + struct opae_retimer_status *status); +int opae_manager_get_eth_group_nums(struct opae_manager *mgr); +int opae_manager_get_eth_group_info(struct opae_manager *mgr, + u8 group_id, struct opae_eth_group_info *info); +int opae_manager_eth_group_write_reg(struct opae_manager *mgr, u8 group_id, + u8 type, u8 index, u16 addr, u32 data); +int opae_manager_eth_group_read_reg(struct opae_manager *mgr, u8 group_id, + u8 type, u8 index, u16 addr, u32 *data); #endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga_rawdev/base/opae_intel_max10.h b/drivers/raw/ifpga_rawdev/base/opae_intel_max10.h index 91a188d..08b387e 100644 --- a/drivers/raw/ifpga_rawdev/base/opae_intel_max10.h +++ b/drivers/raw/ifpga_rawdev/base/opae_intel_max10.h @@ -8,9 +8,6 @@ #include "opae_osdep.h" #include "opae_spi.h" -#define INTEL_MAX10_MAX_MDIO_DEVS 2 -#define PKVL_NUMBER_PORTS 4 - /* max10 capability flags */ #define MAX10_FLAGS_NO_I2C2 BIT(0) #define MAX10_FLAGS_NO_BMCIMG_FLASH BIT(1) @@ -25,6 +22,45 @@ struct intel_max10_device { struct spi_transaction_dev *spi_tran_dev; }; +/* retimer speed */ +enum retimer_speed { + MXD_1GB = 1, + MXD_2_5GB = 2, + MXD_5GB = 5, + MXD_10GB = 10, + MXD_25GB = 25, + MXD_40GB = 40, + MXD_100GB = 100, + MXD_SPEED_UNKNOWN, +}; + +/* retimer info */ +struct opae_retimer_info { + unsigned int nums_retimer; + unsigned int ports_per_retimer; + unsigned int nums_fvl; + unsigned int ports_per_fvl; + enum retimer_speed support_speed; +}; + +/* retimer status*/ +struct opae_retimer_status { + enum retimer_speed speed; + /* + * retimer line link status bitmap: + * bit 0: Retimer0 Port0 link status + * bit 1: Retimer0 Port1 link status + * bit 2: Retimer0 Port2 link status + * bit 3: Retimer0 Port3 link status + * + * bit 4: Retimer1 Port0 link status + * bit 5: Retimer1 Port1 link status + * bit 6: Retimer1 Port2 link status + * bit 7: Retimer1 Port3 link status + */ + unsigned int line_link_bitmap; +}; + #define FLASH_BASE 0x10000000 #define FLASH_OPTION_BITS 0x10000 diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h index d710ec0..1596adc 100644 --- a/drivers/raw/ifpga_rawdev/base/opae_osdep.h +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -53,12 +53,7 @@ struct uuid { #define dev_err(x, args...) dev_printf(ERR, args) #define dev_info(x, args...) dev_printf(INFO, args) #define dev_warn(x, args...) dev_printf(WARNING, args) - -#ifdef OPAE_DEBUG #define dev_debug(x, args...) dev_printf(DEBUG, args) -#else -#define dev_debug(x, args...) do { } while (0) -#endif #define pr_err(y, args...) dev_err(0, y, ##args) #define pr_warn(y, args...) dev_warn(0, y, ##args) @@ -81,4 +76,15 @@ struct uuid { #define time_before(a, b) time_after(b, a) #define opae_memset(a, b, c) memset((a), (b), (c)) +#define opae_readq_poll_timeout(addr, val, cond, invl, timeout)\ +({ \ + int wait = 0; \ + for (; wait <= timeout; wait += invl) { \ + (val) = opae_readq(addr); \ + if (cond) \ + break; \ + udelay(invl); \ + } \ + (cond) ? 0 : -ETIMEDOUT; \ +}) #endif From patchwork Wed Apr 10 06:27:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52539 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 36E721B115; Wed, 10 Apr 2019 08:27:56 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id D3E8E1B108 for ; Wed, 10 Apr 2019 08:27:49 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 23:27:49 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,332,1549958400"; d="scan'208";a="147981050" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by FMSMGA003.fm.intel.com with ESMTP; 09 Apr 2019 23:27:46 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Wed, 10 Apr 2019 14:27:50 +0800 Message-Id: <1554877672-19745-13-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554877672-19745-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554877672-19745-1-git-send-email-rosen.xu@intel.com> Subject: [dpdk-dev] [PATCH v7 12/14] raw/ifpga_rawdev: add version description on README X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Tianfei zhang add verion description on READ about ifpga base code. Signed-off-by: Tianfei Zhang --- drivers/raw/ifpga_rawdev/base/README | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/raw/ifpga_rawdev/base/README b/drivers/raw/ifpga_rawdev/base/README index 5bc2ed0..6b2b171 100644 --- a/drivers/raw/ifpga_rawdev/base/README +++ b/drivers/raw/ifpga_rawdev/base/README @@ -29,3 +29,18 @@ the following file(s): osdep_raw/osdep_generic.h osdep_rte/osdep_generic.h + + +New Features +================== + +2019-03: +Support Intel FPGA PAC N3000 card. +Some features added in this version: +1. Store private features in FME and Port list. +2. Add eth group devices driver. +3. Add altera SPI master driver and Intel MAX10 device driver. +4. Add Altera I2C master driver and AT24 eeprom driver. +5. Add Device Tree support to get the configuration from card. +6. Instruding and exposing APIs to DPDK PMD driver to access networking +functionality. From patchwork Wed Apr 10 06:27:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52540 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 472431B11C; Wed, 10 Apr 2019 08:28:02 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 479BA1B116 for ; Wed, 10 Apr 2019 08:27:56 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 23:27:55 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,332,1549958400"; d="scan'208";a="147981065" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by FMSMGA003.fm.intel.com with ESMTP; 09 Apr 2019 23:27:50 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Wed, 10 Apr 2019 14:27:51 +0800 Message-Id: <1554877672-19745-14-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554877672-19745-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554877672-19745-1-git-send-email-rosen.xu@intel.com> Subject: [dpdk-dev] [PATCH v7 13/14] raw/ifpga_rawdev: using prefix name for feature and its ops X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Tianfei zhang Using prefix name "ifpga_" for feature and feature_ops data struct on ifpga base code, which is suggested by Yigit, Ferruh. Signed-off-by: Tianfei Zhang --- drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 8 +-- drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 4 +- drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 58 ++++++++++--------- drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 70 +++++++++++------------ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 16 +++--- drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 18 +++--- drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 28 ++++----- drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 6 +- drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 22 +++---- drivers/raw/ifpga_rawdev/base/ifpga_port.c | 36 ++++++------ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 10 ++-- 11 files changed, 141 insertions(+), 135 deletions(-) diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c index 44086c1..b8846e3 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -73,7 +73,7 @@ static u64 feature_id(void __iomem *start) unsigned int vec_cnt) { struct ifpga_hw *hw = binfo->hw; - struct feature *feature = NULL; + struct ifpga_feature *feature = NULL; struct feature_irq_ctx *ctx = NULL; int port_id, ret = 0; unsigned int i; @@ -81,7 +81,7 @@ static u64 feature_id(void __iomem *start) fid = fid?fid:feature_id(start); size = size?size:feature_size(start); - feature = opae_malloc(sizeof(struct feature)); + feature = opae_malloc(sizeof(struct ifpga_feature)); if (!feature) return -ENOMEM; @@ -233,7 +233,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) struct opae_accelerator *acc; struct ifpga_port_hw *port; struct ifpga_fme_hw *fme; - struct feature *feature; + struct ifpga_feature *feature; if (!binfo->fiu) return 0; @@ -645,7 +645,7 @@ static void ifpga_print_device_feature_list(struct ifpga_hw *hw) { struct ifpga_fme_hw *fme = &hw->fme; struct ifpga_port_hw *port; - struct feature *feature; + struct ifpga_feature *feature; int i; dev_info(hw, "found fme_device, is in PF: %s\n", diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c index 5ebc449..63c8bcc 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -252,7 +252,7 @@ const char *get_port_feature_name(unsigned int id) static void feature_uinit(struct ifpga_feature_list *list) { - struct feature *feature; + struct ifpga_feature *feature; TAILQ_FOREACH(feature, list, next) { if (feature->state != IFPGA_FEATURE_ATTACHED) @@ -265,7 +265,7 @@ static void feature_uinit(struct ifpga_feature_list *list) static int feature_init(struct feature_driver *drv, struct ifpga_feature_list *list) { - struct feature *feature; + struct ifpga_feature *feature; int ret; while (drv->ops) { diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h index 3f63f5a..bb9fcc2 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -10,7 +10,7 @@ struct feature_driver { u64 id; const char *name; - struct feature_ops *ops; + struct ifpga_feature_ops *ops; }; /** @@ -34,10 +34,10 @@ struct feature_driver { #define ifpga_for_each_port_feature(port, feature) \ TAILQ_FOREACH(feature, &port->feature_list, next) -static inline struct feature * +static inline struct ifpga_feature * get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) { - struct feature *feature; + struct ifpga_feature *feature; ifpga_for_each_fme_feature(fme, feature) { if (feature->id == id) @@ -47,10 +47,10 @@ struct feature_driver { return NULL; } -static inline struct feature * +static inline struct ifpga_feature * get_port_feature_by_id(struct ifpga_port_hw *port, u64 id) { - struct feature *feature; + struct ifpga_feature *feature; ifpga_for_each_port_feature(port, feature) { if (feature->id == id) @@ -60,10 +60,10 @@ struct feature_driver { return NULL; } -static inline struct feature * +static inline struct ifpga_feature * get_feature_by_id(struct ifpga_feature_list *list, u64 id) { - struct feature *feature; + struct ifpga_feature *feature; TAILQ_FOREACH(feature, list, next) if (feature->id == id) @@ -75,7 +75,8 @@ struct feature_driver { static inline void * get_fme_feature_ioaddr_by_index(struct ifpga_fme_hw *fme, int index) { - struct feature *feature = get_feature_by_id(&fme->feature_list, index); + struct ifpga_feature *feature = + get_feature_by_id(&fme->feature_list, index); return feature ? feature->addr : NULL; } @@ -83,7 +84,8 @@ struct feature_driver { static inline void * get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index) { - struct feature *feature = get_feature_by_id(&port->feature_list, index); + struct ifpga_feature *feature = + get_feature_by_id(&port->feature_list, index); return feature ? feature->addr : NULL; } @@ -162,19 +164,19 @@ int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, void port_err_mask(struct ifpga_port_hw *port, bool mask); int port_err_clear(struct ifpga_port_hw *port, u64 err); -extern struct feature_ops fme_hdr_ops; -extern struct feature_ops fme_thermal_mgmt_ops; -extern struct feature_ops fme_power_mgmt_ops; -extern struct feature_ops fme_global_err_ops; -extern struct feature_ops fme_pr_mgmt_ops; -extern struct feature_ops fme_global_iperf_ops; -extern struct feature_ops fme_global_dperf_ops; -extern struct feature_ops fme_hssi_eth_ops; -extern struct feature_ops fme_emif_ops; -extern struct feature_ops fme_spi_master_ops; -extern struct feature_ops fme_i2c_master_ops; -extern struct feature_ops fme_eth_group_ops; -extern struct feature_ops fme_nios_spi_master_ops; +extern struct ifpga_feature_ops fme_hdr_ops; +extern struct ifpga_feature_ops fme_thermal_mgmt_ops; +extern struct ifpga_feature_ops fme_power_mgmt_ops; +extern struct ifpga_feature_ops fme_global_err_ops; +extern struct ifpga_feature_ops fme_pr_mgmt_ops; +extern struct ifpga_feature_ops fme_global_iperf_ops; +extern struct ifpga_feature_ops fme_global_dperf_ops; +extern struct ifpga_feature_ops fme_hssi_eth_ops; +extern struct ifpga_feature_ops fme_emif_ops; +extern struct ifpga_feature_ops fme_spi_master_ops; +extern struct ifpga_feature_ops fme_i2c_master_ops; +extern struct ifpga_feature_ops fme_eth_group_ops; +extern struct ifpga_feature_ops fme_nios_spi_master_ops; int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop); int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop); @@ -190,14 +192,14 @@ struct fpga_uafu_irq_set { const char *get_fme_feature_name(unsigned int id); const char *get_port_feature_name(unsigned int id); -extern struct feature_ops ifpga_rawdev_port_hdr_ops; -extern struct feature_ops ifpga_rawdev_port_error_ops; -extern struct feature_ops ifpga_rawdev_port_stp_ops; -extern struct feature_ops ifpga_rawdev_port_uint_ops; -extern struct feature_ops ifpga_rawdev_port_afu_ops; +extern struct ifpga_feature_ops ifpga_rawdev_port_hdr_ops; +extern struct ifpga_feature_ops ifpga_rawdev_port_error_ops; +extern struct ifpga_feature_ops ifpga_rawdev_port_stp_ops; +extern struct ifpga_feature_ops ifpga_rawdev_port_uint_ops; +extern struct ifpga_feature_ops ifpga_rawdev_port_afu_ops; /* help functions for feature ops */ -int fpga_msix_set_block(struct feature *feature, unsigned int start, +int fpga_msix_set_block(struct ifpga_feature *feature, unsigned int start, unsigned int count, s32 *fds); /* FME network function ops*/ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c index 2cfb158..2b447fd 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_fme.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -12,7 +12,7 @@ int fme_get_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) { - struct feature *feature; + struct ifpga_feature *feature; if (!fme) return -ENOENT; @@ -27,7 +27,7 @@ int fme_get_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) int fme_set_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) { - struct feature *feature; + struct ifpga_feature *feature; if (!fme) return -ENOENT; @@ -42,7 +42,7 @@ int fme_set_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set) { - struct feature *feature; + struct ifpga_feature *feature; if (!fme) return -ENOENT; @@ -56,7 +56,7 @@ int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set) } /* fme private feature head */ -static int fme_hdr_init(struct feature *feature) +static int fme_hdr_init(struct ifpga_feature *feature) { struct feature_fme_header *fme_hdr; @@ -69,7 +69,7 @@ static int fme_hdr_init(struct feature *feature) return 0; } -static void fme_hdr_uinit(struct feature *feature) +static void fme_hdr_uinit(struct ifpga_feature *feature) { UNUSED(feature); @@ -159,7 +159,7 @@ static int fme_hdr_get_bitstream_metadata(struct ifpga_fme_hw *fme, } static int -fme_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +fme_hdr_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -183,7 +183,7 @@ static int fme_hdr_get_bitstream_metadata(struct ifpga_fme_hw *fme, return -ENOENT; } -struct feature_ops fme_hdr_ops = { +struct ifpga_feature_ops fme_hdr_ops = { .init = fme_hdr_init, .uinit = fme_hdr_uinit, .get_prop = fme_hdr_get_prop, @@ -404,7 +404,7 @@ static int fme_thermal_get_revision(struct ifpga_fme_hw *fme, u64 *revision) #define FME_THERMAL_CAP_NO_TMP_THRESHOLD 0x1 -static int fme_thermal_mgmt_init(struct feature *feature) +static int fme_thermal_mgmt_init(struct ifpga_feature *feature) { struct feature_fme_thermal *fme_thermal; struct feature_fme_tmp_threshold_cap thermal_cap; @@ -425,7 +425,7 @@ static int fme_thermal_mgmt_init(struct feature *feature) return 0; } -static void fme_thermal_mgmt_uinit(struct feature *feature) +static void fme_thermal_mgmt_uinit(struct ifpga_feature *feature) { UNUSED(feature); @@ -433,7 +433,7 @@ static void fme_thermal_mgmt_uinit(struct feature *feature) } static int -fme_thermal_set_prop(struct feature *feature, struct feature_prop *prop) +fme_thermal_set_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -453,7 +453,7 @@ static void fme_thermal_mgmt_uinit(struct feature *feature) } static int -fme_thermal_get_prop(struct feature *feature, struct feature_prop *prop) +fme_thermal_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -484,7 +484,7 @@ static void fme_thermal_mgmt_uinit(struct feature *feature) return -ENOENT; } -struct feature_ops fme_thermal_mgmt_ops = { +struct ifpga_feature_ops fme_thermal_mgmt_ops = { .init = fme_thermal_mgmt_init, .uinit = fme_thermal_mgmt_uinit, .get_prop = fme_thermal_get_prop, @@ -670,7 +670,7 @@ static int fme_pwr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) return 0; } -static int fme_power_mgmt_init(struct feature *feature) +static int fme_power_mgmt_init(struct ifpga_feature *feature) { UNUSED(feature); @@ -679,14 +679,14 @@ static int fme_power_mgmt_init(struct feature *feature) return 0; } -static void fme_power_mgmt_uinit(struct feature *feature) +static void fme_power_mgmt_uinit(struct ifpga_feature *feature) { UNUSED(feature); dev_info(NULL, "FME power mgmt UInit.\n"); } -static int fme_power_mgmt_get_prop(struct feature *feature, +static int fme_power_mgmt_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -715,7 +715,7 @@ static int fme_power_mgmt_get_prop(struct feature *feature, return -ENOENT; } -static int fme_power_mgmt_set_prop(struct feature *feature, +static int fme_power_mgmt_set_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -730,41 +730,41 @@ static int fme_power_mgmt_set_prop(struct feature *feature, return -ENOENT; } -struct feature_ops fme_power_mgmt_ops = { +struct ifpga_feature_ops fme_power_mgmt_ops = { .init = fme_power_mgmt_init, .uinit = fme_power_mgmt_uinit, .get_prop = fme_power_mgmt_get_prop, .set_prop = fme_power_mgmt_set_prop, }; -static int fme_hssi_eth_init(struct feature *feature) +static int fme_hssi_eth_init(struct ifpga_feature *feature) { UNUSED(feature); return 0; } -static void fme_hssi_eth_uinit(struct feature *feature) +static void fme_hssi_eth_uinit(struct ifpga_feature *feature) { UNUSED(feature); } -struct feature_ops fme_hssi_eth_ops = { +struct ifpga_feature_ops fme_hssi_eth_ops = { .init = fme_hssi_eth_init, .uinit = fme_hssi_eth_uinit, }; -static int fme_emif_init(struct feature *feature) +static int fme_emif_init(struct ifpga_feature *feature) { UNUSED(feature); return 0; } -static void fme_emif_uinit(struct feature *feature) +static void fme_emif_uinit(struct ifpga_feature *feature) { UNUSED(feature); } -struct feature_ops fme_emif_ops = { +struct ifpga_feature_ops fme_emif_ops = { .init = fme_emif_init, .uinit = fme_emif_uinit, }; @@ -872,7 +872,7 @@ static int spi_self_checking(void) return 0; } -static int fme_spi_init(struct feature *feature) +static int fme_spi_init(struct ifpga_feature *feature) { struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; struct altera_spi_device *spi_master; @@ -915,7 +915,7 @@ static int fme_spi_init(struct feature *feature) return ret; } -static void fme_spi_uinit(struct feature *feature) +static void fme_spi_uinit(struct ifpga_feature *feature) { struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; @@ -923,7 +923,7 @@ static void fme_spi_uinit(struct feature *feature) intel_max10_device_remove(fme->max10_dev); } -struct feature_ops fme_spi_master_ops = { +struct ifpga_feature_ops fme_spi_master_ops = { .init = fme_spi_init, .uinit = fme_spi_uinit, }; @@ -975,7 +975,7 @@ static int nios_spi_check_error(struct altera_spi_device *dev) return 0; } -static int fme_nios_spi_init(struct feature *feature) +static int fme_nios_spi_init(struct ifpga_feature *feature) { struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; struct altera_spi_device *spi_master; @@ -1036,7 +1036,7 @@ static int fme_nios_spi_init(struct feature *feature) return -ENODEV; } -static void fme_nios_spi_uinit(struct feature *feature) +static void fme_nios_spi_uinit(struct ifpga_feature *feature) { struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; @@ -1044,7 +1044,7 @@ static void fme_nios_spi_uinit(struct feature *feature) intel_max10_device_remove(fme->max10_dev); } -struct feature_ops fme_nios_spi_master_ops = { +struct ifpga_feature_ops fme_nios_spi_master_ops = { .init = fme_nios_spi_init, .uinit = fme_nios_spi_uinit, }; @@ -1082,7 +1082,7 @@ static int i2c_mac_rom_test(struct altera_i2c_dev *dev) return 0; } -static int fme_i2c_init(struct feature *feature) +static int fme_i2c_init(struct ifpga_feature *feature) { struct feature_fme_i2c *i2c; struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; @@ -1101,19 +1101,19 @@ static int fme_i2c_init(struct feature *feature) return 0; } -static void fme_i2c_uninit(struct feature *feature) +static void fme_i2c_uninit(struct ifpga_feature *feature) { struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; altera_i2c_remove(fme->i2c_master); } -struct feature_ops fme_i2c_master_ops = { +struct ifpga_feature_ops fme_i2c_master_ops = { .init = fme_i2c_init, .uinit = fme_i2c_uninit, }; -static int fme_eth_group_init(struct feature *feature) +static int fme_eth_group_init(struct ifpga_feature *feature) { struct ifpga_fme_hw *fme = (struct ifpga_fme_hw *)feature->parent; struct eth_group_device *dev; @@ -1142,12 +1142,12 @@ static int fme_eth_group_init(struct feature *feature) return 0; } -static void fme_eth_group_uinit(struct feature *feature) +static void fme_eth_group_uinit(struct ifpga_feature *feature) { UNUSED(feature); } -struct feature_ops fme_eth_group_ops = { +struct ifpga_feature_ops fme_eth_group_ops = { .init = fme_eth_group_init, .uinit = fme_eth_group_uinit, }; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c index 1773b87..954f8a8 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c @@ -183,7 +183,7 @@ static int fme_dperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) #define PERF_MAX_PORT_NUM 1 -static int fme_global_dperf_init(struct feature *feature) +static int fme_global_dperf_init(struct ifpga_feature *feature) { UNUSED(feature); @@ -192,14 +192,14 @@ static int fme_global_dperf_init(struct feature *feature) return 0; } -static void fme_global_dperf_uinit(struct feature *feature) +static void fme_global_dperf_uinit(struct ifpga_feature *feature) { UNUSED(feature); dev_info(NULL, "FME global_dperf UInit.\n"); } -static int fme_dperf_fab_get_prop(struct feature *feature, +static int fme_dperf_fab_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -225,7 +225,7 @@ static int fme_dperf_fab_get_prop(struct feature *feature, return -ENOENT; } -static int fme_dperf_root_get_prop(struct feature *feature, +static int fme_dperf_root_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -245,7 +245,7 @@ static int fme_dperf_root_get_prop(struct feature *feature, return -ENOENT; } -static int fme_global_dperf_get_prop(struct feature *feature, +static int fme_global_dperf_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { u8 top = GET_FIELD(PROP_TOP, prop->prop_id); @@ -260,7 +260,7 @@ static int fme_global_dperf_get_prop(struct feature *feature, return -ENOENT; } -static int fme_dperf_fab_set_prop(struct feature *feature, +static int fme_dperf_fab_set_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -279,7 +279,7 @@ static int fme_dperf_fab_set_prop(struct feature *feature, return -ENOENT; } -static int fme_global_dperf_set_prop(struct feature *feature, +static int fme_global_dperf_set_prop(struct ifpga_feature *feature, struct feature_prop *prop) { u8 top = GET_FIELD(PROP_TOP, prop->prop_id); @@ -292,7 +292,7 @@ static int fme_global_dperf_set_prop(struct feature *feature, return -ENOENT; } -struct feature_ops fme_global_dperf_ops = { +struct ifpga_feature_ops fme_global_dperf_ops = { .init = fme_global_dperf_init, .uinit = fme_global_dperf_uinit, .get_prop = fme_global_dperf_get_prop, diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c index 8c26fb2..3794564 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c @@ -240,7 +240,7 @@ static void fme_error_enable(struct ifpga_fme_hw *fme) writeq(0UL, &fme_err->ras_catfat_mask); } -static int fme_global_error_init(struct feature *feature) +static int fme_global_error_init(struct ifpga_feature *feature) { struct ifpga_fme_hw *fme = feature->parent; @@ -252,12 +252,12 @@ static int fme_global_error_init(struct feature *feature) return 0; } -static void fme_global_error_uinit(struct feature *feature) +static void fme_global_error_uinit(struct ifpga_feature *feature) { UNUSED(feature); } -static int fme_err_fme_err_get_prop(struct feature *feature, +static int fme_err_fme_err_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -275,7 +275,7 @@ static int fme_err_fme_err_get_prop(struct feature *feature, return -ENOENT; } -static int fme_err_root_get_prop(struct feature *feature, +static int fme_err_root_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -301,7 +301,7 @@ static int fme_err_root_get_prop(struct feature *feature, return -ENOENT; } -static int fme_global_error_get_prop(struct feature *feature, +static int fme_global_error_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { u8 top = GET_FIELD(PROP_TOP, prop->prop_id); @@ -321,7 +321,7 @@ static int fme_global_error_get_prop(struct feature *feature, return -ENOENT; } -static int fme_err_fme_err_set_prop(struct feature *feature, +static int fme_err_fme_err_set_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -335,7 +335,7 @@ static int fme_err_fme_err_set_prop(struct feature *feature, return -ENOENT; } -static int fme_err_root_set_prop(struct feature *feature, +static int fme_err_root_set_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -353,7 +353,7 @@ static int fme_err_root_set_prop(struct feature *feature, return -ENOENT; } -static int fme_global_error_set_prop(struct feature *feature, +static int fme_global_error_set_prop(struct ifpga_feature *feature, struct feature_prop *prop) { u8 top = GET_FIELD(PROP_TOP, prop->prop_id); @@ -373,7 +373,7 @@ static int fme_global_error_set_prop(struct feature *feature, return -ENOENT; } -struct feature_ops fme_global_err_ops = { +struct ifpga_feature_ops fme_global_err_ops = { .init = fme_global_error_init, .uinit = fme_global_error_uinit, .get_prop = fme_global_error_get_prop, diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c index e6c40a1..70543b9 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c @@ -407,7 +407,7 @@ static int fme_iperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) #define PERF_MAX_PORT_NUM 1 #define FME_IPERF_CAP_IOMMU 0x1 -static int fme_global_iperf_init(struct feature *feature) +static int fme_global_iperf_init(struct ifpga_feature *feature) { struct ifpga_fme_hw *fme; struct feature_fme_header *fme_hdr; @@ -429,14 +429,14 @@ static int fme_global_iperf_init(struct feature *feature) return 0; } -static void fme_global_iperf_uinit(struct feature *feature) +static void fme_global_iperf_uinit(struct ifpga_feature *feature) { UNUSED(feature); dev_info(NULL, "FME global_iperf UInit.\n"); } -static int fme_iperf_root_get_prop(struct feature *feature, +static int fme_iperf_root_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -456,7 +456,7 @@ static int fme_iperf_root_get_prop(struct feature *feature, return -ENOENT; } -static int fme_iperf_cache_get_prop(struct feature *feature, +static int fme_iperf_cache_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -496,7 +496,7 @@ static int fme_iperf_cache_get_prop(struct feature *feature, return -ENOENT; } -static int fme_iperf_vtd_root_get_prop(struct feature *feature, +static int fme_iperf_vtd_root_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -534,7 +534,7 @@ static int fme_iperf_vtd_root_get_prop(struct feature *feature, return -ENOENT; } -static int fme_iperf_vtd_sub_get_prop(struct feature *feature, +static int fme_iperf_vtd_sub_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -571,7 +571,7 @@ static int fme_iperf_vtd_sub_get_prop(struct feature *feature, return -ENOENT; } -static int fme_iperf_vtd_get_prop(struct feature *feature, +static int fme_iperf_vtd_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); @@ -582,7 +582,7 @@ static int fme_iperf_vtd_get_prop(struct feature *feature, return fme_iperf_vtd_sub_get_prop(feature, prop); } -static int fme_iperf_fab_get_prop(struct feature *feature, +static int fme_iperf_fab_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -626,7 +626,7 @@ static int fme_iperf_fab_get_prop(struct feature *feature, return -ENOENT; } -static int fme_global_iperf_get_prop(struct feature *feature, +static int fme_global_iperf_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { u8 top = GET_FIELD(PROP_TOP, prop->prop_id); @@ -645,7 +645,7 @@ static int fme_global_iperf_get_prop(struct feature *feature, return -ENOENT; } -static int fme_iperf_cache_set_prop(struct feature *feature, +static int fme_iperf_cache_set_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -658,7 +658,7 @@ static int fme_iperf_cache_set_prop(struct feature *feature, return -ENOENT; } -static int fme_iperf_vtd_set_prop(struct feature *feature, +static int fme_iperf_vtd_set_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -671,7 +671,7 @@ static int fme_iperf_vtd_set_prop(struct feature *feature, return -ENOENT; } -static int fme_iperf_fab_set_prop(struct feature *feature, +static int fme_iperf_fab_set_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_fme_hw *fme = feature->parent; @@ -690,7 +690,7 @@ static int fme_iperf_fab_set_prop(struct feature *feature, return -ENOENT; } -static int fme_global_iperf_set_prop(struct feature *feature, +static int fme_global_iperf_set_prop(struct ifpga_feature *feature, struct feature_prop *prop) { u8 top = GET_FIELD(PROP_TOP, prop->prop_id); @@ -707,7 +707,7 @@ static int fme_global_iperf_set_prop(struct feature *feature, return -ENOENT; } -struct feature_ops fme_global_iperf_ops = { +struct ifpga_feature_ops fme_global_iperf_ops = { .init = fme_global_iperf_init, .uinit = fme_global_iperf_uinit, .get_prop = fme_global_iperf_get_prop, diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c index 8890f4b..efa7266 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c @@ -315,7 +315,7 @@ int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, u64 *status) return fme_pr(hw, port_id, buf, size, status); } -static int fme_pr_mgmt_init(struct feature *feature) +static int fme_pr_mgmt_init(struct ifpga_feature *feature) { struct feature_fme_pr *fme_pr; struct feature_header fme_pr_header; @@ -339,14 +339,14 @@ static int fme_pr_mgmt_init(struct feature *feature) return 0; } -static void fme_pr_mgmt_uinit(struct feature *feature) +static void fme_pr_mgmt_uinit(struct ifpga_feature *feature) { UNUSED(feature); dev_info(NULL, "FME PR MGMT UInit.\n"); } -struct feature_ops fme_pr_mgmt_ops = { +struct ifpga_feature_ops fme_pr_mgmt_ops = { .init = fme_pr_mgmt_init, .uinit = fme_pr_mgmt_uinit, }; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_hw.h b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h index a428d69..ff91c46 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_hw.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -10,7 +10,7 @@ #include "opae_eth_group.h" /** List of private feateues */ -TAILQ_HEAD(ifpga_feature_list, feature); +TAILQ_HEAD(ifpga_feature_list, ifpga_feature); enum ifpga_feature_state { IFPGA_FEATURE_UNUSED = 0, @@ -27,8 +27,8 @@ struct feature_irq_ctx { int idx; }; -struct feature { - TAILQ_ENTRY(feature)next; +struct ifpga_feature { + TAILQ_ENTRY(ifpga_feature)next; enum ifpga_feature_state state; enum feature_type type; const char *name; @@ -44,17 +44,19 @@ struct feature { void *parent; /* to parent hw data structure */ - struct feature_ops *ops;/* callback to this private feature */ + struct ifpga_feature_ops *ops;/* callback to this private feature */ unsigned int vec_start; unsigned int vec_cnt; }; -struct feature_ops { - int (*init)(struct feature *feature); - void (*uinit)(struct feature *feature); - int (*get_prop)(struct feature *feature, struct feature_prop *prop); - int (*set_prop)(struct feature *feature, struct feature_prop *prop); - int (*set_irq)(struct feature *feature, void *irq_set); +struct ifpga_feature_ops { + int (*init)(struct ifpga_feature *feature); + void (*uinit)(struct ifpga_feature *feature); + int (*get_prop)(struct ifpga_feature *feature, + struct feature_prop *prop); + int (*set_prop)(struct ifpga_feature *feature, + struct feature_prop *prop); + int (*set_irq)(struct ifpga_feature *feature, void *irq_set); }; enum ifpga_fme_state { diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c index 4628783..6c41164 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_port.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c @@ -6,7 +6,7 @@ int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop) { - struct feature *feature; + struct ifpga_feature *feature; if (!port) return -ENOENT; @@ -21,7 +21,7 @@ int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop) int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop) { - struct feature *feature; + struct ifpga_feature *feature; if (!port) return -ENOENT; @@ -36,7 +36,7 @@ int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop) int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set) { - struct feature *feature; + struct ifpga_feature *feature; if (!port) return -ENOENT; @@ -260,7 +260,7 @@ static int port_get_userclk_freqcntrsts(struct ifpga_port_hw *port, u64 *val) return 0; } -static int port_hdr_init(struct feature *feature) +static int port_hdr_init(struct ifpga_feature *feature) { struct ifpga_port_hw *port = feature->parent; @@ -271,14 +271,15 @@ static int port_hdr_init(struct feature *feature) return 0; } -static void port_hdr_uinit(struct feature *feature) +static void port_hdr_uinit(struct ifpga_feature *feature) { UNUSED(feature); dev_info(NULL, "port hdr uinit.\n"); } -static int port_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +static int port_hdr_get_prop(struct ifpga_feature *feature, + struct feature_prop *prop) { struct ifpga_port_hw *port = feature->parent; @@ -308,7 +309,8 @@ static int port_hdr_get_prop(struct feature *feature, struct feature_prop *prop) return -ENOENT; } -static int port_hdr_set_prop(struct feature *feature, struct feature_prop *prop) +static int port_hdr_set_prop(struct ifpga_feature *feature, + struct feature_prop *prop) { struct ifpga_port_hw *port = feature->parent; @@ -326,14 +328,14 @@ static int port_hdr_set_prop(struct feature *feature, struct feature_prop *prop) return -ENOENT; } -struct feature_ops ifpga_rawdev_port_hdr_ops = { +struct ifpga_feature_ops ifpga_rawdev_port_hdr_ops = { .init = port_hdr_init, .uinit = port_hdr_uinit, .get_prop = port_hdr_get_prop, .set_prop = port_hdr_set_prop, }; -static int port_stp_init(struct feature *feature) +static int port_stp_init(struct ifpga_feature *feature) { struct ifpga_port_hw *port = feature->parent; @@ -347,19 +349,19 @@ static int port_stp_init(struct feature *feature) return 0; } -static void port_stp_uinit(struct feature *feature) +static void port_stp_uinit(struct ifpga_feature *feature) { UNUSED(feature); dev_info(NULL, "port stp uinit.\n"); } -struct feature_ops ifpga_rawdev_port_stp_ops = { +struct ifpga_feature_ops ifpga_rawdev_port_stp_ops = { .init = port_stp_init, .uinit = port_stp_uinit, }; -static int port_uint_init(struct feature *feature) +static int port_uint_init(struct ifpga_feature *feature) { struct ifpga_port_hw *port = feature->parent; @@ -375,19 +377,19 @@ static int port_uint_init(struct feature *feature) return 0; } -static void port_uint_uinit(struct feature *feature) +static void port_uint_uinit(struct ifpga_feature *feature) { UNUSED(feature); dev_info(NULL, "PORT UINT UInit.\n"); } -struct feature_ops ifpga_rawdev_port_uint_ops = { +struct ifpga_feature_ops ifpga_rawdev_port_uint_ops = { .init = port_uint_init, .uinit = port_uint_uinit, }; -static int port_afu_init(struct feature *feature) +static int port_afu_init(struct ifpga_feature *feature) { UNUSED(feature); @@ -396,14 +398,14 @@ static int port_afu_init(struct feature *feature) return 0; } -static void port_afu_uinit(struct feature *feature) +static void port_afu_uinit(struct ifpga_feature *feature) { UNUSED(feature); dev_info(NULL, "PORT AFU UInit.\n"); } -struct feature_ops ifpga_rawdev_port_afu_ops = { +struct ifpga_feature_ops ifpga_rawdev_port_afu_ops = { .init = port_afu_init, .uinit = port_afu_uinit, }; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c index 9dd1cf5..138284e 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c @@ -84,7 +84,7 @@ static int port_err_set_clear(struct ifpga_port_hw *port, u64 val) return ret; } -static int port_error_init(struct feature *feature) +static int port_error_init(struct ifpga_feature *feature) { struct ifpga_port_hw *port = feature->parent; @@ -99,12 +99,12 @@ static int port_error_init(struct feature *feature) return 0; } -static void port_error_uinit(struct feature *feature) +static void port_error_uinit(struct ifpga_feature *feature) { UNUSED(feature); } -static int port_error_get_prop(struct feature *feature, +static int port_error_get_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_port_hw *port = feature->parent; @@ -125,7 +125,7 @@ static int port_error_get_prop(struct feature *feature, return -ENOENT; } -static int port_error_set_prop(struct feature *feature, +static int port_error_set_prop(struct ifpga_feature *feature, struct feature_prop *prop) { struct ifpga_port_hw *port = feature->parent; @@ -136,7 +136,7 @@ static int port_error_set_prop(struct feature *feature, return -ENOENT; } -struct feature_ops ifpga_rawdev_port_error_ops = { +struct ifpga_feature_ops ifpga_rawdev_port_error_ops = { .init = port_error_init, .uinit = port_error_uinit, .get_prop = port_error_get_prop, From patchwork Wed Apr 10 06:27:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Xu, Rosen" X-Patchwork-Id: 52541 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id E55F21B123; Wed, 10 Apr 2019 08:28:08 +0200 (CEST) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id 66FED4F9A for ; Wed, 10 Apr 2019 08:28:01 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Apr 2019 23:28:00 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,332,1549958400"; d="scan'208";a="147981083" Received: from dpdkx8602.sh.intel.com ([10.67.110.200]) by FMSMGA003.fm.intel.com with ESMTP; 09 Apr 2019 23:27:56 -0700 From: Rosen Xu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, tianfei.zhang@intel.com, dan.wei@intel.com, rosen.xu@intel.com, andy.pei@intel.com, qiming.yang@intel.com, haiyue.wang@intel.com, santos.chen@intel.com, zhang.zhang@intel.com, david.lomartire@intel.com, jia.hu@intel.com Date: Wed, 10 Apr 2019 14:27:52 +0800 Message-Id: <1554877672-19745-15-git-send-email-rosen.xu@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1554877672-19745-1-git-send-email-rosen.xu@intel.com> References: <1551338000-120348-1-git-send-email-rosen.xu@intel.com> <1554877672-19745-1-git-send-email-rosen.xu@intel.com> Subject: [dpdk-dev] [PATCH v7 14/14] raw/ifpga_rawdev: add IPN3KE support for IFPGA Rawdev X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add Intel FPGA Acceleration NIC IPN3KE support for IFPGA Rawdev. Signed-off-by: Rosen Xu Signed-off-by: Tianfei Zhang Signed-off-by: Andy Pei --- drivers/raw/ifpga_rawdev/Makefile | 1 + drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 248 +++++++++++++++++++++++++++++++- drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 16 ++- drivers/raw/ifpga_rawdev/meson.build | 6 +- 4 files changed, 265 insertions(+), 6 deletions(-) diff --git a/drivers/raw/ifpga_rawdev/Makefile b/drivers/raw/ifpga_rawdev/Makefile index f3b9d5e..f60b547 100644 --- a/drivers/raw/ifpga_rawdev/Makefile +++ b/drivers/raw/ifpga_rawdev/Makefile @@ -13,6 +13,7 @@ CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev +CFLAGS += -I$(RTE_SDK)/drivers/net/ipn3ke LDLIBS += -lrte_eal LDLIBS += -lrte_rawdev LDLIBS += -lrte_bus_vdev diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c index da772d0..9042fe9 100644 --- a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c @@ -34,6 +34,7 @@ #include "ifpga_common.h" #include "ifpga_logs.h" #include "ifpga_rawdev.h" +#include "ipn3ke_rawdev_api.h" int ifpga_rawdev_logtype; @@ -42,10 +43,12 @@ #define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD #define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0 #define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4 +#define PCIE_DEVICE_ID_PAC_N3000 0x0B30 /* VF Device */ #define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF #define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1 #define PCIE_DEVICE_ID_VF_DSC_1_X 0x09C5 +#define PCIE_DEVICE_ID_VF_PAC_N3000 0x0B31 #define RTE_MAX_RAW_DEVICE 10 static const struct rte_pci_id pci_ifpga_map[] = { @@ -55,6 +58,8 @@ { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_6_X) }, { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_DSC_1_X) }, { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PAC_N3000),}, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_PAC_N3000),}, { .vendor_id = 0, /* sentinel */ }, }; @@ -103,6 +108,10 @@ struct opae_adapter *adapter; struct opae_accelerator *acc; struct rte_afu_device *afu_dev; + struct opae_manager *mgr = NULL; + struct opae_eth_group_region_info opae_lside_eth_info; + struct opae_eth_group_region_info opae_nside_eth_info; + int lside_bar_idx, nside_bar_idx; IFPGA_RAWDEV_PMD_FUNC_TRACE(); @@ -128,6 +137,45 @@ return; } } + + /* get opae_manager to rawdev */ + mgr = opae_adapter_get_mgr(adapter); + if (mgr) { + //get LineSide BAR Index + if (opae_manager_get_eth_group_region_info(mgr, 0, + &opae_lside_eth_info)) { + return; + } + lside_bar_idx = opae_lside_eth_info.mem_idx; + + //get NICSide BAR Index + if (opae_manager_get_eth_group_region_info(mgr, 1, + &opae_nside_eth_info)) { + return; + } + nside_bar_idx = opae_nside_eth_info.mem_idx; + + if (lside_bar_idx >= PCI_MAX_RESOURCE || + nside_bar_idx >= PCI_MAX_RESOURCE || + lside_bar_idx == nside_bar_idx) + return; + + //fill LineSide BAR Index + afu_dev->mem_resource[lside_bar_idx].phys_addr = + opae_lside_eth_info.phys_addr; + afu_dev->mem_resource[lside_bar_idx].len = + opae_lside_eth_info.len; + afu_dev->mem_resource[lside_bar_idx].addr = + opae_lside_eth_info.addr; + + //fill NICSide BAR Index + afu_dev->mem_resource[nside_bar_idx].phys_addr = + opae_nside_eth_info.phys_addr; + afu_dev->mem_resource[nside_bar_idx].len = + opae_nside_eth_info.len; + afu_dev->mem_resource[nside_bar_idx].addr = + opae_nside_eth_info.addr; + } } static int @@ -327,6 +375,201 @@ return 0; } +static int +ifpga_rawdev_get_attr(struct rte_rawdev *dev, + const char *attr_name, uint64_t *attr_value) +{ + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_retimer_info opae_rtm_info; + struct opae_retimer_status opae_rtm_status; + struct opae_eth_group_info opae_eth_grp_info; + struct opae_eth_group_region_info opae_eth_grp_reg_info; + int eth_group_num = 0; + uint64_t port_link_bitmap = 0, port_link_bit; + uint32_t i, j, p, q; + +#define MAX_PORT_PER_RETIMER 4 + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + if (!dev || !attr_name || !attr_value) { + IFPGA_RAWDEV_PMD_ERR("Invalid arguments for getting attributes"); + return -1; + } + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) { + IFPGA_RAWDEV_PMD_ERR("Adapter of dev %s is NULL", dev->name); + return -1; + } + + mgr = opae_adapter_get_mgr(adapter); + if (!mgr) { + IFPGA_RAWDEV_PMD_ERR("opae_manager of opae_adapter is NULL"); + return -1; + } + + /* currently, eth_group_num is always 2 */ + eth_group_num = opae_manager_get_eth_group_nums(mgr); + if (eth_group_num < 0) + return -1; + + if (!strcmp(attr_name, "LineSideBaseMAC")) { + /* Currently FPGA not implement, so just set all zeros*/ + *attr_value = (uint64_t)0; + return 0; + } + if (!strcmp(attr_name, "LineSideMACType")) { + /* eth_group 0 on FPGA connect to LineSide */ + if (opae_manager_get_eth_group_info(mgr, 0, + &opae_eth_grp_info)) + return -1; + switch (opae_eth_grp_info.speed) { + case ETH_SPEED_10G: + *attr_value = + (uint64_t)(IFPGA_RAWDEV_RETIMER_MAC_TYPE_10GE_XFI); + break; + case ETH_SPEED_25G: + *attr_value = + (uint64_t)(IFPGA_RAWDEV_RETIMER_MAC_TYPE_25GE_25GAUI); + break; + default: + *attr_value = + (uint64_t)(IFPGA_RAWDEV_RETIMER_MAC_TYPE_UNKNOWN); + break; + } + return 0; + } + if (!strcmp(attr_name, "LineSideLinkSpeed")) { + if (opae_manager_get_retimer_status(mgr, &opae_rtm_status)) + return -1; + switch (opae_rtm_status.speed) { + case MXD_1GB: + *attr_value = + (uint64_t)(IFPGA_RAWDEV_LINK_SPEED_UNKNOWN); + break; + case MXD_2_5GB: + *attr_value = + (uint64_t)(IFPGA_RAWDEV_LINK_SPEED_UNKNOWN); + break; + case MXD_5GB: + *attr_value = + (uint64_t)(IFPGA_RAWDEV_LINK_SPEED_UNKNOWN); + break; + case MXD_10GB: + *attr_value = + (uint64_t)(IFPGA_RAWDEV_LINK_SPEED_10GB); + break; + case MXD_25GB: + *attr_value = + (uint64_t)(IFPGA_RAWDEV_LINK_SPEED_25GB); + break; + case MXD_40GB: + *attr_value = + (uint64_t)(IFPGA_RAWDEV_LINK_SPEED_40GB); + break; + case MXD_100GB: + *attr_value = + (uint64_t)(IFPGA_RAWDEV_LINK_SPEED_UNKNOWN); + break; + case MXD_SPEED_UNKNOWN: + *attr_value = + (uint64_t)(IFPGA_RAWDEV_LINK_SPEED_UNKNOWN); + break; + default: + *attr_value = + (uint64_t)(IFPGA_RAWDEV_LINK_SPEED_UNKNOWN); + break; + } + return 0; + } + if (!strcmp(attr_name, "LineSideLinkRetimerNum")) { + if (opae_manager_get_retimer_info(mgr, &opae_rtm_info)) + return -1; + *attr_value = (uint64_t)(opae_rtm_info.nums_retimer); + return 0; + } + if (!strcmp(attr_name, "LineSideLinkPortNum")) { + if (opae_manager_get_retimer_info(mgr, &opae_rtm_info)) + return -1; + uint64_t tmp = opae_rtm_info.ports_per_retimer * + opae_rtm_info.nums_retimer; + *attr_value = tmp; + return 0; + } + if (!strcmp(attr_name, "LineSideLinkStatus")) { + if (opae_manager_get_retimer_info(mgr, &opae_rtm_info)) + return -1; + if (opae_manager_get_retimer_status(mgr, &opae_rtm_status)) + return -1; + (*attr_value) = 0; + q = 0; + port_link_bitmap = (uint64_t)(opae_rtm_status.line_link_bitmap); + for (i = 0; i < opae_rtm_info.nums_retimer; i++) { + p = i * MAX_PORT_PER_RETIMER; + for (j = 0; j < opae_rtm_info.ports_per_retimer; j++) { + port_link_bit = 0; + IFPGA_BIT_SET(port_link_bit, (p+j)); + port_link_bit &= port_link_bitmap; + if (port_link_bit) + IFPGA_BIT_SET((*attr_value), q); + q++; + } + } + return 0; + } + if (!strcmp(attr_name, "LineSideBARIndex")) { + /* eth_group 0 on FPGA connect to LineSide */ + if (opae_manager_get_eth_group_region_info(mgr, 0, + &opae_eth_grp_reg_info)) + return -1; + *attr_value = (uint64_t)opae_eth_grp_reg_info.mem_idx; + return 0; + } + if (!strcmp(attr_name, "NICSideMACType")) { + /* eth_group 1 on FPGA connect to NicSide */ + if (opae_manager_get_eth_group_info(mgr, 1, + &opae_eth_grp_info)) + return -1; + *attr_value = (uint64_t)(opae_eth_grp_info.speed); + return 0; + } + if (!strcmp(attr_name, "NICSideLinkSpeed")) { + /* eth_group 1 on FPGA connect to NicSide */ + if (opae_manager_get_eth_group_info(mgr, 1, + &opae_eth_grp_info)) + return -1; + *attr_value = (uint64_t)(opae_eth_grp_info.speed); + return 0; + } + if (!strcmp(attr_name, "NICSideLinkPortNum")) { + if (opae_manager_get_retimer_info(mgr, &opae_rtm_info)) + return -1; + uint64_t tmp = opae_rtm_info.nums_fvl * + opae_rtm_info.ports_per_fvl; + *attr_value = tmp; + return 0; + } + if (!strcmp(attr_name, "NICSideLinkStatus")) { + /* + * + */ + return 0; + } + if (!strcmp(attr_name, "NICSideBARIndex")) { + /* eth_group 1 on FPGA connect to NicSide */ + if (opae_manager_get_eth_group_region_info(mgr, 1, + &opae_eth_grp_reg_info)) + return -1; + *attr_value = (uint64_t)opae_eth_grp_reg_info.mem_idx; + return 0; + } + + IFPGA_RAWDEV_PMD_ERR("attr_name not support"); + return -1; +} + static const struct rte_rawdev_ops ifpga_rawdev_ops = { .dev_info_get = ifpga_rawdev_info_get, .dev_configure = ifpga_rawdev_configure, @@ -339,7 +582,7 @@ .queue_setup = NULL, .queue_release = NULL, - .attr_get = NULL, + .attr_get = ifpga_rawdev_get_attr, .attr_set = NULL, .enqueue_bufs = NULL, @@ -419,7 +662,7 @@ rawdev->dev_ops = &ifpga_rawdev_ops; rawdev->device = &pci_dev->device; - rawdev->driver_name = pci_dev->device.driver->name; + rawdev->driver_name = pci_dev->driver->driver.name; /* must enumerate the adapter before use it */ ret = opae_adapter_enumerate(adapter); @@ -491,7 +734,6 @@ ifpga_rawdev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, struct rte_pci_device *pci_dev) { - IFPGA_RAWDEV_PMD_FUNC_TRACE(); return ifpga_rawdev_create(pci_dev, rte_socket_id()); } diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h index 234ce36..fcb1a96 100644 --- a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h @@ -8,8 +8,8 @@ extern int ifpga_rawdev_logtype; #define IFPGA_RAWDEV_PMD_LOG(level, fmt, args...) \ - rte_log(RTE_LOG_ ## level, ifpga_rawdev_logtype, "%s(): " fmt "\n", \ - __func__, ##args) + rte_log(RTE_LOG_ ## level, ifpga_rawdev_logtype, "ifpga_rawdev: " fmt, \ + ##args) #define IFPGA_RAWDEV_PMD_FUNC_TRACE() IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") @@ -28,6 +28,18 @@ enum ifpga_rawdev_device_state { IFPGA_ERROR }; +/** Set a bit in the uint64 variable */ +#define IFPGA_BIT_SET(var, pos) \ + ((var) |= ((uint64_t)1 << ((pos)))) + +/** Reset the bit in the variable */ +#define IFPGA_BIT_RESET(var, pos) \ + ((var) &= ~((uint64_t)1 << ((pos)))) + +/** Check the bit is set in the variable */ +#define IFPGA_BIT_ISSET(var, pos) \ + (((var) & ((uint64_t)1 << ((pos)))) ? 1 : 0) + static inline struct opae_adapter * ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) { diff --git a/drivers/raw/ifpga_rawdev/meson.build b/drivers/raw/ifpga_rawdev/meson.build index 6725687..132b777 100644 --- a/drivers/raw/ifpga_rawdev/meson.build +++ b/drivers/raw/ifpga_rawdev/meson.build @@ -6,8 +6,12 @@ version = 1 subdir('base') objs = [base_objs] +dep = dependency('libfdt', required: false) +if not dep.found() + build = false +endif deps += ['rawdev', 'pci', 'bus_pci', 'kvargs', - 'bus_vdev', 'bus_ifpga'] + 'bus_vdev', 'bus_ifpga', 'net'] sources = files('ifpga_rawdev.c') includes += include_directories('base')