* [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS @ 2018-03-20 13:45 Rosen Xu 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 1/5] Add Intel FPGA BUS Command Parse Code Rosen Xu ` (17 more replies) 0 siblings, 18 replies; 149+ messages in thread From: Rosen Xu @ 2018-03-20 13:45 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu, gaetan.rivet Intel FPGA BUS in DPDK ------------------------- This patch set introduces Intel FPGA BUS support in DPDK. Motivation ========== FPGA is used more and more widely in Cloud and NFV, one primary reason is that FPGA not only provide ASIC performance but also it's more flexible than ASIC. FPGA use Partial Reconfigure(PR) Parts of Bitstream to achieve its flexibility. Another reason is that one FPGA can be shared by different Users, and each User can use some of AFUs of One FPGA. That means One FPGA Device Bitstream is divided into many Parts of Bitstream(each Part of Bitstream is defined as AFU-Accelerated Function Unit), and each AFU is a Hardware Acceleration Unit and it can dynamically Reload respectively. Scope ===== The Intel FPGA BUS implementation is target towards various FPGA Devices use PR to provide many Acceleration Function. Specific PMDs may also bind to its AFU. And Applications don't care they are using ASIC Acceleration or FPGA AFU Acceleration. Proposed Solution ================= - Involve Rawdev to take FPGA Partial Configuration(Download/PR) - Defined FPGA-BUS for Acceleration Drivers of AFUs - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream Status ===== With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable Acceleration Engine) Share Code, Intel FPGA BUS runs well in Intel PSG FPGA Cards. Patch set Information ==================== This patch set includes 6 patches: * 0 : Introduce the Intel FPGA BUS library and enable its compilation. * 1 : Adds command parse code, for start-up application with Intel FPGA BUS. * 2 : Adds Driver Probe Code, for AFU Drivers should probed after PCI Drivers. * 3 : Adds Intel FPGA BUS library code, for AFU Device scan and AFU Drivers probe. * 4 : Adds a Intel FPGA rawdevice driver, for FPGA Device Management such as PR. * 5 : Adds Intel OPAE(Open Programmable Acceleration Engine) Share Code, it's Intel FPGA Software Stack. Rosen Xu (5): Add Intel FPGA BUS Command Parse Code Add Intel FPGA BUS Probe Code Add Intel FPGA BUS Lib Code Add Intel FPGA BUS Rawdev Code Add Intel OPAE Share Code drivers/bus/ifpga/Makefile | 64 + drivers/bus/ifpga/ifpga_bus.c | 573 +++++++ drivers/bus/ifpga/ifpga_common.c | 154 ++ drivers/bus/ifpga/ifpga_common.h | 25 + drivers/bus/ifpga/ifpga_logs.h | 32 + drivers/bus/ifpga/rte_bus_ifpga.h | 141 ++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 8 + drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 63 + drivers/raw/ifpga_rawdev/base/Makefile | 54 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 543 +++++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 77 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 84 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1696 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 861 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 38 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 340 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 197 +++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 763 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 328 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 430 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 742 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 395 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 152 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 730 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 236 +++ drivers/raw/ifpga_rawdev/base/opae_debug.c | 126 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 46 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 389 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 276 ++++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 151 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 293 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 111 ++ .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 104 ++ .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 72 + drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 486 ++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 38 + drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c | 99 ++ .../ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map | 4 + lib/librte_eal/common/eal_common_bus.c | 14 +- lib/librte_eal/common/eal_common_options.c | 8 +- lib/librte_eal/common/eal_options.h | 2 + 42 files changed, 10944 insertions(+), 2 deletions(-) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c create mode 100644 drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH V1 1/5] Add Intel FPGA BUS Command Parse Code 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu @ 2018-03-20 13:45 ` Rosen Xu 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 2/5] Add Intel FPGA BUS Probe Code Rosen Xu ` (16 subsequent siblings) 17 siblings, 0 replies; 149+ messages in thread From: Rosen Xu @ 2018-03-20 13:45 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu, gaetan.rivet Signed-off-by: Rosen Xu <rosen.xu@intel.com> --- lib/librte_eal/common/eal_common_options.c | 8 +++++++- lib/librte_eal/common/eal_options.h | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c index 9f2f8d2..4fe0875 100644 --- a/lib/librte_eal/common/eal_common_options.c +++ b/lib/librte_eal/common/eal_common_options.c @@ -73,6 +73,7 @@ {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM }, + {OPT_IFPGA, 1, NULL, OPT_IFPGA_NUM }, {0, 0, NULL, 0 } }; @@ -1160,7 +1161,12 @@ static int xdigit2val(unsigned char c) core_parsed = LCORE_OPT_MAP; break; - + case OPT_IFPGA_NUM: + if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL, + optarg) < 0) { + return -1; + } + break; /* don't know what to do, leave this to caller */ default: return 1; diff --git a/lib/librte_eal/common/eal_options.h b/lib/librte_eal/common/eal_options.h index e86c711..bdbb2c4 100644 --- a/lib/librte_eal/common/eal_options.h +++ b/lib/librte_eal/common/eal_options.h @@ -55,6 +55,8 @@ enum { OPT_VFIO_INTR_NUM, #define OPT_VMWARE_TSC_MAP "vmware-tsc-map" OPT_VMWARE_TSC_MAP_NUM, +#define OPT_IFPGA "ifpga" + OPT_IFPGA_NUM, OPT_LONG_MAX_NUM }; -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH V1 2/5] Add Intel FPGA BUS Probe Code 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 1/5] Add Intel FPGA BUS Command Parse Code Rosen Xu @ 2018-03-20 13:45 ` Rosen Xu 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 3/5] Add Intel FPGA BUS Lib Code Rosen Xu ` (15 subsequent siblings) 17 siblings, 0 replies; 149+ messages in thread From: Rosen Xu @ 2018-03-20 13:45 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu, gaetan.rivet Signed-off-by: Rosen Xu <rosen.xu@intel.com> --- lib/librte_eal/common/eal_common_bus.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/librte_eal/common/eal_common_bus.c b/lib/librte_eal/common/eal_common_bus.c index 3e022d5..e3bcebe 100644 --- a/lib/librte_eal/common/eal_common_bus.c +++ b/lib/librte_eal/common/eal_common_bus.c @@ -87,7 +87,7 @@ struct rte_bus_list rte_bus_list = rte_bus_probe(void) { int ret; - struct rte_bus *bus, *vbus = NULL; + struct rte_bus *bus, *vbus = NULL, *ifpga_bus = NULL; TAILQ_FOREACH(bus, &rte_bus_list, next) { if (!strcmp(bus->name, "vdev")) { @@ -95,6 +95,11 @@ struct rte_bus_list rte_bus_list = continue; } + if (!strcmp(bus->name, "ifpga")) { + ifpga_bus = bus; + continue; + } + ret = bus->probe(); if (ret) RTE_LOG(ERR, EAL, "Bus (%s) probe failed.\n", @@ -108,6 +113,13 @@ struct rte_bus_list rte_bus_list = vbus->name); } + if (ifpga_bus) { + ret = ifpga_bus->probe(); + if (ret) + RTE_LOG(ERR, EAL, "Scan for (%s) bus failed.\n", + ifpga_bus->name); + } + return 0; } -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH V1 3/5] Add Intel FPGA BUS Lib Code 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 1/5] Add Intel FPGA BUS Command Parse Code Rosen Xu 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 2/5] Add Intel FPGA BUS Probe Code Rosen Xu @ 2018-03-20 13:45 ` Rosen Xu 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 4/5] Add Intel FPGA BUS Rawdev Code Rosen Xu ` (14 subsequent siblings) 17 siblings, 0 replies; 149+ messages in thread From: Rosen Xu @ 2018-03-20 13:45 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu, gaetan.rivet Signed-off-by: Rosen Xu <rosen.xu@intel.com> --- drivers/bus/ifpga/Makefile | 64 ++++ drivers/bus/ifpga/ifpga_bus.c | 573 ++++++++++++++++++++++++++++ drivers/bus/ifpga/ifpga_common.c | 154 ++++++++ drivers/bus/ifpga/ifpga_common.h | 25 ++ drivers/bus/ifpga/ifpga_logs.h | 32 ++ drivers/bus/ifpga/rte_bus_ifpga.h | 141 +++++++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 8 + 7 files changed, 997 insertions(+) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile new file mode 100644 index 0000000..c71f186 --- /dev/null +++ b/drivers/bus/ifpga/Makefile @@ -0,0 +1,64 @@ +# BSD LICENSE +# +# Copyright(c) 2010-2017 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_bus_ifpga.a +LIBABIVER := 1 +EXPORT_MAP := rte_bus_ifpga_version.map + +ifeq ($(CONFIG_RTE_LIBRTE_DPAA2_DEBUG_INIT),y) +CFLAGS += -O0 -g +CFLAGS += "-Wno-error" +else +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +endif + +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga +CFLAGS += -I$(RTE_SDK)/drivers/bus/pci +CFLAGS += -I$(RTE_SDK)/lib/librte_eal/linuxapp/eal +CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common +#CFLAGS += -I$(RTE_SDK)/lib/librte_rawdev +#LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring -lrte_rawdev +LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring +#LDLIBS += -lrte_ethdev + +VPATH += $(SRCDIR)/base + +SRCS-y += \ + ifpga_bus.c \ + ifpga_common.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index 0000000..ff72b74 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -0,0 +1,573 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation. + * Copyright 2013-2014 6WIND S.A. + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_bus_logtype; + +/*register a ifpga bus based driver */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver) +{ + RTE_VERIFY(driver); + + TAILQ_INSERT_TAIL(&rte_ifpga_bus.driver_list, driver, next); +} + +/*un-register a fpga bus based driver */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) +{ + TAILQ_REMOVE(&rte_ifpga_bus.driver_list, driver, next); +} + +static struct rte_ifpga_device * +ifpga_find_ifpga_dev(const struct rte_pci_addr *pci_addr) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { + if (!ifpga_pci_addr_cmp_1(&ifpga_dev->pci_addr, pci_addr)) + return ifpga_dev; + } + return NULL; +} + +static struct rte_afu_device * +ifpga_find_afu_dev(const struct rte_afu_id *afu_id) +{ + struct rte_afu_device *afu_dev = NULL; + + TAILQ_FOREACH(afu_dev, &rte_ifpga_bus.afu_list, next) { + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) + return afu_dev; + } + return NULL; +} + +static const char *valid_args[] = { +#define IFPGA_ARG_BDF "bdf" + IFPGA_ARG_BDF, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_ARG_PATH "path" + IFPGA_ARG_PATH, +#define IFPGA_ARG_UUID_HIGH "uuid_high" + IFPGA_ARG_UUID_HIGH, +#define IFPGA_ARG_UUID_LOW "uuid_low" + IFPGA_ARG_UUID_LOW, +#define IFPGA_ARG_PR_ENABLE "pr_enable" + IFPGA_ARG_PR_ENABLE, +#define IFPGA_ARG_DEBUG "debug" + IFPGA_ARG_DEBUG, + NULL +}; + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static struct rte_afu_device * +rte_ifpga_scan_one(struct rte_devargs *devargs, + struct rte_rawdev *rawdev) +{ + struct rte_kvargs *kvlist = NULL; + struct rte_bus *pci_bus = NULL; + struct rte_device *dev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_afu_pr_conf afu_pr_conf; + int ret = 0; + char *path = NULL; + int pr_enable = 1; + int debug = 0; + + memset((char *)(&afu_pr_conf), 0, sizeof(struct rte_afu_pr_conf)); + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, + &ifpga_get_bdf_arg, &afu_pr_conf.afu_id.pci_addr) < 0) { + IFPGA_BUS_ERR("error to parse %s", IFPGA_ARG_BDF); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PATH); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PATH); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PATH) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PATH, + &ifpga_get_string_arg, &path) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_PATH); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PATH); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_UUID_HIGH) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_UUID_HIGH, + &ifpga_get_integer64_arg, &afu_pr_conf.afu_id.uuid_high) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_UUID_HIGH); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PATH); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_UUID_LOW) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_UUID_LOW, + &ifpga_get_integer64_arg, &afu_pr_conf.afu_id.uuid_low) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_UUID_LOW); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PATH); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PR_ENABLE) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PR_ENABLE, + &ifpga_get_integer32_arg, &pr_enable) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_UUID_HIGH); + goto end; + } + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_DEBUG) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_DEBUG, + &ifpga_get_integer32_arg, &debug) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_UUID_HIGH); + goto end; + } + } + + if (!debug) { + pci_bus = rte_bus_find_by_name("pci"); + if (pci_bus == NULL) { + IFPGA_BUS_ERR("unable to find PCI bus\n"); + goto end; + } + + dev = pci_bus->find_device(NULL, + ifpga_pci_addr_cmp, + &afu_pr_conf.afu_id.pci_addr); + if (dev == NULL) { + IFPGA_BUS_ERR("unable to find PCI device\n"); + goto end; + } + } else { + IFPGA_BUS_DEBUG("pci_addr domain : %x\n", + afu_pr_conf.afu_id.pci_addr.domain); + IFPGA_BUS_DEBUG("pci_addr bus : %x\n", + afu_pr_conf.afu_id.pci_addr.bus); + IFPGA_BUS_DEBUG("pci_addr devid : %x\n", + afu_pr_conf.afu_id.pci_addr.devid); + IFPGA_BUS_DEBUG("pci_addr function : %x\n", + afu_pr_conf.afu_id.pci_addr.function); + IFPGA_BUS_DEBUG("uuid_low : %lx\n", + afu_pr_conf.afu_id.uuid_low); + IFPGA_BUS_DEBUG("uuid_high : %lx\n", + afu_pr_conf.afu_id.uuid_high); + IFPGA_BUS_DEBUG("afu port : %x\n", + afu_pr_conf.afu_id.port); + } + + if (ifpga_find_afu_dev(&afu_pr_conf.afu_id)) + goto end; + + + afu_dev = calloc(1, sizeof(*afu_dev)); + if (!afu_dev) + goto end; + + afu_dev->device.devargs = devargs; + afu_dev->device.numa_node = SOCKET_ID_ANY; + afu_dev->device.name = devargs->name; + afu_dev->rawdev = rawdev; + afu_dev->id.pci_addr.domain = afu_pr_conf.afu_id.pci_addr.domain; + afu_dev->id.pci_addr.bus = afu_pr_conf.afu_id.pci_addr.bus; + afu_dev->id.pci_addr.devid = afu_pr_conf.afu_id.pci_addr.devid; + afu_dev->id.pci_addr.function = afu_pr_conf.afu_id.pci_addr.function; + afu_dev->id.uuid_low = afu_pr_conf.afu_id.uuid_low; + afu_dev->id.uuid_high = afu_pr_conf.afu_id.uuid_high; + afu_dev->id.port = afu_pr_conf.afu_id.port; + + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); + + if (rawdev->dev_ops && + rawdev->dev_ops->dev_start && + rawdev->dev_ops->dev_start(rawdev)) + goto free_dev; + if (pr_enable) { + strncpy(afu_pr_conf.bs_path, path, strlen(path)); + if (rawdev->dev_ops->firmware_load && + rawdev->dev_ops->firmware_load(rawdev, + &afu_pr_conf)){ + printf("firmware load error %d\n", ret); + goto free_dev; + } + } + + return afu_dev; + +free_dev: + free(afu_dev); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (path) + free(path); + + return NULL; +} + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static int +rte_ifpga_scan(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + struct rte_pci_addr pci_addr; + + /* for FPGA devices we scan the devargs_list populated via cmdline */ + TAILQ_FOREACH(devargs, &devargs_list, next) { + if (devargs->bus != &rte_ifpga_bus.bus) + continue; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, + &ifpga_get_bdf_arg, &pci_addr) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_BDF); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PATH); + goto end; + } + + if (ifpga_find_ifpga_dev(&pci_addr)) + goto end; + + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); + if (!ifpga_dev) + goto end; + + ifpga_dev->pci_addr.bus = pci_addr.bus; + ifpga_dev->pci_addr.devid = pci_addr.devid; + ifpga_dev->pci_addr.function = pci_addr.function; + + TAILQ_INSERT_TAIL(&rte_ifpga_bus.ifpga_list, ifpga_dev, next); + } + + return 0; + +end: + if (kvlist) + rte_kvargs_free(kvlist); + + return 0; +} + +/* + * Scan the content of the PCI bus, and call the probe() function for + * all registered drivers that have a matching entry in its id_table + * for discovered devices. + */ +int +rte_ifpga_scan_2nd(void *conf, void *id) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_rawdev *rdev; + struct rte_pci_addr *pci_addr; + struct rte_devargs *devargs; + struct rte_afu_device *afu_dev = NULL; + + rdev = conf; + pci_addr = id; + + ifpga_dev = ifpga_find_ifpga_dev(pci_addr); + if (!ifpga_dev) + return 0; + + ifpga_dev->rdev = rdev; + + /* for FPGA devices we scan the devargs_list populated via cmdline */ + TAILQ_FOREACH(devargs, &devargs_list, next) { + afu_dev = rte_ifpga_scan_one(devargs, rdev); + if (afu_dev != NULL) + TAILQ_INSERT_TAIL(&rte_ifpga_bus.afu_list, afu_dev, next); + else + return 0; + } + + return 0; +} + +static int +ifpga_probe_one_driver(struct rte_afu_driver *drv, + struct rte_afu_device *afu_dev) +{ + int ret; + + if ((drv->id.pci_addr.bus == afu_dev->id.pci_addr.bus) && + (drv->id.pci_addr.devid == afu_dev->id.pci_addr.devid) && + (drv->id.pci_addr.function == afu_dev->id.pci_addr.function) && + (drv->id.uuid_low == afu_dev->id.uuid_low) && + (drv->id.uuid_high == afu_dev->id.uuid_high) && + (drv->id.port == afu_dev->id.port)) { + + afu_dev->driver = drv; + + /* call the driver probe() function */ + ret = drv->probe(afu_dev); + if (ret) + afu_dev->driver = NULL; + return ret; + } + + /* return positive value if driver doesn't support this device */ + return 1; +} + +static int +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) +{ + const char *name; + struct rte_afu_driver *drv = NULL; + int rc; + + if (afu_dev == NULL) + return -1; + + /* Check if a driver is already loaded */ + if (afu_dev->driver != NULL) + return 0; + + name = rte_ifpga_device_name(afu_dev); + IFPGA_BUS_DEBUG("Search driver %s to probe device %s\n", name, + rte_ifpga_device_name(afu_dev)); + + TAILQ_FOREACH(drv, &rte_ifpga_bus.driver_list, next) { + rc = ifpga_probe_one_driver(drv, afu_dev); + if (rc < 0) + /* negative value is an error */ + return -1; + if (rc > 0) + /* positive value means driver doesn't support it */ + continue; + return 0; + } + return 1; +} + +/* + * Scan the content of the PCI bus, and call the probe() function for + * all registered drivers that have a matching entry in its id_table + * for discovered devices. + */ +static int +rte_ifpga_probe(void) +{ + struct rte_afu_device *afu_dev = NULL; + int ret = 0; + + TAILQ_FOREACH(afu_dev, &rte_ifpga_bus.afu_list, next) { + + if (afu_dev->device.driver) + continue; + + ret = ifpga_probe_all_drivers(afu_dev); + if (ret < 0) + IFPGA_BUS_ERR("failed to initialize %s device\n", + rte_ifpga_device_name(afu_dev)); + } + + return 0; +} + +static int +rte_ifpga_plug(struct rte_device *dev) +{ + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); +} + +static int ifpga_remove_driver(struct rte_afu_device *afu_dev) +{ + const char *name; + const struct rte_afu_driver *driver; + + name = rte_ifpga_device_name(afu_dev); + if (!afu_dev->device.driver) { + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); + return 1; + } + + driver = container_of(afu_dev->device.driver, + const struct rte_afu_driver, + driver); + return driver->remove(afu_dev); +} + +static int +rte_ifpga_unplug(struct rte_device *dev) +{ + struct rte_afu_device *afu_dev; + struct rte_devargs *devargs; + int ret; + + if (dev == NULL) + return -EINVAL; + + afu_dev = RTE_DEV_TO_AFU(dev); + if (!dev) + return -ENOENT; + + devargs = dev->devargs; + + ret = ifpga_remove_driver(afu_dev); + if (ret) + return ret; + + TAILQ_REMOVE(&rte_ifpga_bus.afu_list, afu_dev, next); + + TAILQ_REMOVE(&devargs_list, devargs, next); + + free(devargs->args); + free(devargs); + free(afu_dev); + return 0; + +} + +static struct rte_device * +rte_ifpga_find_device(const struct rte_device *start, + rte_dev_cmp_t cmp, const void *data) +{ + struct rte_afu_device *afu_dev; + + TAILQ_FOREACH(afu_dev, &rte_ifpga_bus.afu_list, next) { + if (start && &afu_dev->device == start) { + start = NULL; + continue; + } + if (cmp(&afu_dev->device, data) == 0) + return &afu_dev->device; + } + return NULL; +} +static int +rte_ifpga_parse(const char *name, void *addr) +{ + struct rte_afu_driver **out = addr; + struct rte_afu_driver *driver = NULL; + + TAILQ_FOREACH(driver, &rte_ifpga_bus.driver_list, next) { + if (strncmp(driver->driver.name, name, + strlen(driver->driver.name)) == 0) + break; + if (driver->driver.alias && + strncmp(driver->driver.alias, name, + strlen(driver->driver.alias)) == 0) + break; + } + if (driver != NULL && + addr != NULL) + *out = driver; + return driver == NULL; +} + +struct rte_ifpga_bus rte_ifpga_bus = { + .bus = { + .scan = rte_ifpga_scan, + .probe = rte_ifpga_probe, + .find_device = rte_ifpga_find_device, + .plug = rte_ifpga_plug, + .unplug = rte_ifpga_unplug, + .parse = rte_ifpga_parse, + }, + .ifpga_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.ifpga_list), + .afu_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.afu_list), + .driver_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.driver_list), +}; + +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus.bus); + +RTE_INIT(ifpga_init_log) +{ + ifpga_bus_logtype = rte_log_register("bus.ifpga"); + if (ifpga_bus_logtype >= 0) + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); +} + diff --git a/drivers/bus/ifpga/ifpga_common.c b/drivers/bus/ifpga/ifpga_common.c new file mode 100644 index 0000000..8d98854 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.c @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation. + * Copyright 2013-2014 6WIND S.A. + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(char **)extra_args = strdup(value); + + if (!*(char **)extra_args) + return -ENOMEM; + + return 0; +} +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(int *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(uint64_t *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_unsigned_long(const char *str, int base) +{ + unsigned long num; + char *end = NULL; + + errno = 0; + + num = strtoul(str, &end, base); + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) + return -1; + + return num; + +} +int ifpga_get_bdf_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ +#define MAX_PATH_LEN 1024 + struct rte_pci_addr *addr; + int num[4]; + char str[MAX_PATH_LEN]; + int i, j; + + if (!value || !extra_args) + return -EINVAL; + + addr = (struct rte_pci_addr *)extra_args; + strcpy(str, value); + memset(num, 0, 4 * sizeof(num[0])); + i = strlen(str) - 1; + j = 3; + while (i > 0 && j >= 0) { + while ((str[i - 1] != ':' && str[i - 1] != '.') && i > 0) + i--; + num[j--] = ifpga_get_unsigned_long(&str[i], 16); + i--; + if (i >= 0) + str[i] = '\0'; + } + addr->domain = num[0]; + addr->bus = num[1]; + addr->devid = num[2]; + addr->function = num[3]; + printf("[%s]: bdf %04d:%02d:%02d.%02d\n", + __func__, + addr->domain, + addr->bus, + addr->devid, + addr->function); + + return 0; +} + +int ifpga_pci_addr_cmp_1(const struct rte_pci_addr *pci_addr0, + const struct rte_pci_addr *pci_addr1) +{ + if ((pci_addr0->bus == pci_addr1->bus) && + (pci_addr0->devid == pci_addr1->devid) && + (pci_addr0->function == pci_addr1->function)) { + return 0; + } + + return 1; +} + +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1) +{ + if ((afu_id0->pci_addr.bus == afu_id1->pci_addr.bus) && + (afu_id0->pci_addr.devid == afu_id1->pci_addr.devid) && + (afu_id0->pci_addr.function == afu_id1->pci_addr.function) && + (afu_id0->uuid_low == afu_id1->uuid_low) && + (afu_id0->uuid_high == afu_id1->uuid_high) && + (afu_id0->port == afu_id1->port)) { + return 0; + } else + return 1; +} +int ifpga_pci_addr_cmp(const struct rte_device *dev, + const void *_pci_addr) +{ + struct rte_pci_device *pdev; + const struct rte_pci_addr *paddr = _pci_addr; + + pdev = RTE_DEV_TO_PCI(*(struct rte_device **)(void *)&dev); + return rte_eal_compare_pci_addr(&pdev->addr, paddr); +} diff --git a/drivers/bus/ifpga/ifpga_common.h b/drivers/bus/ifpga/ifpga_common.h new file mode 100644 index 0000000..23b68d4 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2015 Intel Corporation. + * Copyright 2013-2014 6WIND S.A. + */ + +#ifndef _IFPGA_COMMON_H_ +#define _IFPGA_COMMON_H_ + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_unsigned_long(const char *str, int base); +int ifpga_get_bdf_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_pci_addr_cmp_1(const struct rte_pci_addr *pci_addr0, + const struct rte_pci_addr *pci_addr1); +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1); +int ifpga_pci_addr_cmp(const struct rte_device *dev, + const void *_pci_addr); + +#endif /* _IFPGA_COMMON_H_ */ diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index 0000000..36b9b3f --- /dev/null +++ b/drivers/bus/ifpga/ifpga_logs.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2015 Intel Corporation. + * Copyright 2013-2014 6WIND S.A. + */ + +#ifndef _IFPGA_BUS_LOGS_H_ +#define _IFPGA_BUS_LOGS_H_ + +#include <rte_log.h> + +extern int ifpga_bus_logtype; + +#define IFPGA_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") + +#define IFPGA_BUS_DEBUG(fmt, args...) \ + IFPGA_BUS_LOG(DEBUG, fmt, ## args) +#define IFPGA_BUS_INFO(fmt, args...) \ + IFPGA_BUS_LOG(INFO, fmt, ## args) +#define IFPGA_BUS_ERR(fmt, args...) \ + IFPGA_BUS_LOG(ERR, fmt, ## args) +#define IFPGA_BUS_WARN(fmt, args...) \ + IFPGA_BUS_LOG(WARNING, fmt, ## args) + +#endif /* _IFPGA_BUS_LOGS_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h new file mode 100644 index 0000000..3ffa30a --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2015 Intel Corporation. + * Copyright 2013-2014 6WIND S.A. + */ + +#ifndef _RTE_BUS_IFPGA_H_ +#define _RTE_BUS_IFPGA_H_ + +/** + * @file + * + * RTE PCI Bus Interface + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_bus.h> +#include <rte_pci.h> + +/** Name of Intel FPGA Bus */ +#define IFPGA_BUS_NAME ifpga + +/* Forward declarations */ +struct rte_ifpga_device; +struct rte_afu_device; +struct rte_afu_driver; + +/** List of Intel FPGA devices */ +TAILQ_HEAD(rte_ifpga_device_list, rte_ifpga_device); +/** List of Intel AFU devices */ +TAILQ_HEAD(rte_afu_device_list, rte_afu_device); +/** List of AFU drivers */ +TAILQ_HEAD(rte_afu_driver_list, rte_afu_driver); + +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 + +/** + * A structure describing an ID for a AFU driver. Each driver provides a + * table of these IDs for each device that it supports. + */ +struct rte_afu_id { + struct rte_pci_addr pci_addr; + uint64_t uuid_low; + uint64_t uuid_high; + int port; +} __attribute__ ((packed)); + +/** + * A structure pr configuration AFU driver. + */ + +struct rte_afu_pr_conf { + struct rte_afu_id afu_id; + int pr_enable; + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +}; + +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) + +/** + * A structure describing a fpga device. + */ +struct rte_ifpga_device { + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ + struct rte_pci_addr pci_addr; + struct rte_rawdev *rdev; +}; + +/** + * A structure describing a AFU device. + */ +struct rte_afu_device { + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ + struct rte_device device; /**< Inherit core device */ + struct rte_rawdev *rawdev; + struct rte_afu_id id; /**< AFU id within FPGA. */ + uint32_t num_region; /**< number of regions found */ + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; + /**< PCI Memory Resource */ + struct rte_intr_handle intr_handle; /**< Interrupt handle */ + struct rte_afu_driver *driver; /**< Associated driver */ + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +} __attribute__ ((packed)); + +/** + * @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) + +/** + * Initialisation function for the driver called during PCI probing. + */ +typedef int (afu_probe_t)(struct rte_afu_device *); + +/** + * Uninitialisation function for the driver called during hotplugging. + */ +typedef int (afu_remove_t)(struct rte_afu_device *); + +/** + * A structure describing a PCI device. + */ +struct rte_afu_driver { + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ + struct rte_driver driver; /**< Inherit core driver. */ + afu_probe_t *probe; /**< Device Probe function. */ + afu_remove_t *remove; /**< Device Remove function. */ + struct rte_afu_id id; /**< AFU id within FPGA. */ + uint32_t drv_flags; /**< Flags contolling handling of device. */ +}; + +/** + * Structure describing the Intel FPGA bus + */ +struct rte_ifpga_bus { + struct rte_bus bus; /**< Inherit the generic class */ + struct rte_ifpga_device_list ifpga_list; /**< List of FPGA devices */ + struct rte_afu_device_list afu_list; /**< List of AFU devices */ + struct rte_afu_driver_list driver_list; /**< List of FPGA drivers */ +}; + +static inline const char * +rte_ifpga_device_name(const struct rte_afu_device *afu) +{ + if (afu && afu->device.name) + return afu->device.name; + return NULL; +} + +extern struct rte_ifpga_bus rte_ifpga_bus; + +void rte_ifpga_driver_register(struct rte_afu_driver *driver); +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); +int rte_ifpga_scan_2nd(void *conf, void *id); + + +#endif /* _RTE_BUS_IFPGA_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map new file mode 100644 index 0000000..e2aa7da --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map @@ -0,0 +1,8 @@ +DPDK_17.11 { + global: + + rte_ifpga_driver_register; + rte_ifpga_driver_unregister; + + local: *; +}; -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH V1 4/5] Add Intel FPGA BUS Rawdev Code 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (2 preceding siblings ...) 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 3/5] Add Intel FPGA BUS Lib Code Rosen Xu @ 2018-03-20 13:45 ` Rosen Xu 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 5/5] Add Intel OPAE Share Code Rosen Xu ` (13 subsequent siblings) 17 siblings, 0 replies; 149+ messages in thread From: Rosen Xu @ 2018-03-20 13:45 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu, gaetan.rivet, Yanglong Wu Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> --- drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 63 +++ drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 486 +++++++++++++++++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 38 ++ drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c | 99 +++++ .../ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map | 4 + 6 files changed, 691 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c create mode 100644 drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index da7c8b4..47cc567 100644 --- a/drivers/raw/Makefile +++ b/drivers/raw/Makefile @@ -5,5 +5,6 @@ include $(RTE_SDK)/mk/rte.vars.mk # DIRS-$(<configuration>) += <directory> DIRS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += skeleton_rawdev +DIRS-y += ifpga_rawdev include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/raw/ifpga_rawdev/Makefile b/drivers/raw/ifpga_rawdev/Makefile new file mode 100644 index 0000000..7efc2f5 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/Makefile @@ -0,0 +1,63 @@ +# BSD LICENSE +# +# Copyright(c) 2010-2017 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_pmd_ifpga_rawdev.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_bus_vdev +LDLIBS += -lrte_kvargs + +EXPORT_MAP := rte_pmd_ifpga_rawdev_version.map + +LIBABIVER := 1 + +VPATH += $(SRCDIR)/base + +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += ifpga_rawdev.c +SRCS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += ifpga_rawdev_example.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c new file mode 100644 index 0000000..a2a41d2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c @@ -0,0 +1,486 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation. + * Copyright 2013-2014 6WIND S.A. + */ + +#include <string.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <rte_log.h> +#include <rte_bus.h> +#include <rte_eal_memconfig.h> +#include <rte_malloc.h> +#include <rte_devargs.h> +#include <rte_memcpy.h> +#include <rte_ethdev.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include <rte_errno.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include "base/opae_hw_api.h" +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" +#include "rte_bus_ifpga.h" +#include "ifpga_rawdev.h" + +int ifpga_rawdev_logtype; + +#define PCI_VENDOR_ID_INTEL 0x8086 +/* PCI Device ID */ +#define PCIe_DEVICE_ID_RCiEP0_MCP 0xBCBD +#define PCIe_DEVICE_ID_RCiEP0_SKX_P 0xBCC0 +#define PCIe_DEVICE_ID_RCiEP0_DCP 0x09C4 +/* VF Device */ +#define PCIe_DEVICE_ID_VF_MCP 0xBCBF +#define PCIe_DEVICE_ID_VF_SKX_P 0xBCC1 +#define PCIe_DEVICE_ID_VF_DCP 0x09C5 +#define RTE_MAX_RAW_DEVICE 10 + +static const struct rte_pci_id pci_ifpga_map[] = { + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIe_DEVICE_ID_RCiEP0_MCP) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIe_DEVICE_ID_VF_MCP) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIe_DEVICE_ID_RCiEP0_SKX_P) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIe_DEVICE_ID_VF_SKX_P) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIe_DEVICE_ID_RCiEP0_DCP) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIe_DEVICE_ID_VF_DCP) }, + { .vendor_id = 0, /* sentinel */ }, +}; + +static int ifpga_fill_afu_dev(struct opae_accelerator *acc, + struct rte_afu_device *afu_dev) +{ + struct rte_mem_resource *res = afu_dev->mem_resource; + struct opae_acc_region_info region_info; + struct opae_acc_info info; + unsigned long i; + int ret; + + ret = opae_acc_get_info(acc, &info); + if (ret) + return ret; + + if (info.num_regions > PCI_MAX_RESOURCE) + return -EFAULT; + + afu_dev->num_region = info.num_regions; + + for (i = 0; i < info.num_regions; i++) { + region_info.index = i; + ret = opae_acc_get_region_info(acc, ®ion_info); + if (ret) + return ret; + + if ((region_info.flags & ACC_REGION_MMIO) && + (region_info.flags & ACC_REGION_READ) && + (region_info.flags & ACC_REGION_WRITE)) { + res[i].phys_addr = region_info.phys_addr; + res[i].len = region_info.len; + res[i].addr = region_info.addr; + } else + return -EFAULT; + } + + return 0; +} + +static void ifpga_rawdev_info_get(struct rte_rawdev *dev, + rte_rawdev_obj_t dev_info) +{ + struct opae_adapter *adapter; + struct opae_accelerator *acc; + struct rte_afu_device *afu_dev; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + if (!dev_info) { + IFPGA_RAWDEV_PMD_ERR("Invalid request"); + return; + } + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return; + + afu_dev = dev_info; + afu_dev->rawdev = dev; + + /* find opae_accelerator and fill info into afu_device */ + opae_adapter_for_each_acc(adapter, acc) { + if (acc->index != afu_dev->id.port) + continue; + + if (ifpga_fill_afu_dev(acc, afu_dev)) { + IFPGA_RAWDEV_PMD_ERR("cannot get info\n"); + return; + } + } +} + +static int ifpga_rawdev_start(struct rte_rawdev *dev) +{ + int ret = 0; + struct opae_adapter *adapter; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + return ret; +} + +static void ifpga_rawdev_stop(struct rte_rawdev *dev) +{ + dev->started = 0; +} + +static int ifpga_rawdev_close(struct rte_rawdev *dev) +{ + if (!dev) + return 1; + else + return 0; +} + +static int ifpga_rawdev_reset(struct rte_rawdev *dev) +{ + if (!dev) + return 1; + else + return 0; +} + +static int +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, + u64 *status){ + + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_accelerator *acc; + struct opae_bridge *br; + int ret; + + adapter = ifpga_rawdev_get_priv(raw_dev); + if (!adapter) + return -ENODEV; + + mgr = opae_adapter_get_mgr(adapter); + if (!mgr) + return -ENODEV; + + acc = opae_adapter_get_acc(adapter, port_id); + if (!acc) + return -ENODEV; + + br = opae_acc_get_br(acc); + if (!br) + return -ENODEV; + + ret = opae_manager_flash(mgr, port_id, buffer, size, status); + if (ret) { + printf("%s pr error %d\n", __func__, ret); + return ret; + } + + usleep(100); + ret = opae_bridge_reset(br); + if (ret) { + printf("%s reset port:%d error %d\n", __func__, port_id, ret); + return ret; + } + + return ret; +} + +static int rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, + const char *file_name) +{ + struct stat file_stat; + int file_fd; + int ret = 0; + u32 buffer_size; + void *buffer; + u64 pr_error; + + if (!file_name) + return -EINVAL; + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + printf("%s: open file error: %s\n", __func__, file_name); + printf("Message : %s\n", strerror(errno)); + return -EINVAL; + } + ret = stat(file_name, &file_stat); + if (ret) { + printf("stat on bitstream file failed: %s\n", file_name); + return -EINVAL; + } + buffer_size = file_stat.st_size; + printf("bitstream file size: %u\n", buffer_size); + buffer = rte_malloc(NULL, buffer_size, 0); + if (!buffer) { + ret = -ENOMEM; + goto close_fd; + } + + /*read the raw data*/ + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { + ret = -EINVAL; + goto free_buffer; + } + + /*do PR now*/ + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); + printf("downloading to device port %d....%s.\n", port_id, + ret ? "failed" : "success"); + if (ret) { + ret = -EINVAL; + //raw_dev->ops->show_pr_error(pr_error); + goto free_buffer; + } + +free_buffer: + if (buffer) + rte_free(buffer); +close_fd: + close(file_fd); + file_fd = 0; + return ret; +} + +static int ifpga_rawdev_pr(struct rte_rawdev *dev, + rte_rawdev_obj_t pr_conf) +{ + struct opae_adapter *adapter; + struct rte_afu_pr_conf *afu_pr_conf; + int ret; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + if (!pr_conf) + return -EINVAL; + + afu_pr_conf = pr_conf; + + ret = rte_fpga_do_pr(dev, afu_pr_conf->afu_id.port, + afu_pr_conf->bs_path); + if (ret) { + printf("===do pr error %d\n", ret); + return ret; + } + + return 0; +} + +static const struct rte_rawdev_ops ifpga_rawdev_ops = { + .dev_info_get = ifpga_rawdev_info_get, + .dev_configure = NULL, + .dev_start = ifpga_rawdev_start, + .dev_stop = ifpga_rawdev_stop, + .dev_close = ifpga_rawdev_close, + .dev_reset = ifpga_rawdev_reset, + + .queue_def_conf = NULL, + .queue_setup = NULL, + .queue_release = NULL, + + .attr_get = NULL, + .attr_set = NULL, + + .enqueue_bufs = NULL, + .dequeue_bufs = NULL, + + .dump = NULL, + + .xstats_get = NULL, + .xstats_get_names = NULL, + .xstats_get_by_name = NULL, + .xstats_reset = NULL, + + .firmware_status_get = NULL, + .firmware_version_get = NULL, + .firmware_load = ifpga_rawdev_pr, + .firmware_unload = NULL, + + .dev_selftest = NULL, +}; + +static int +ifpga_rawdev_create(struct rte_pci_device *pci_dev, + int socket_id) +{ + int ret = 0; + struct rte_rawdev *rawdev = NULL; + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_adapter_data_pci *data; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + int i; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + goto cleanup; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%x:%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id()); + + /* Allocate device structure */ + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct opae_adapter), + socket_id); + if (rawdev == NULL) { + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); + ret = -EINVAL; + goto cleanup; + } + + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API */ + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); + if (!data) + return -ENOMEM; + + /* init opae_adapter_data_pci for device specific information */ + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + data->region[i].phys_addr = pci_dev->mem_resource[i].phys_addr; + data->region[i].len = pci_dev->mem_resource[i].len; + data->region[i].addr = pci_dev->mem_resource[i].addr; + } + data->device_id = pci_dev->id.device_id; + data->vendor_id = pci_dev->id.vendor_id; + + /* create a opae_adapter based on above device data */ + adapter = opae_adapter_alloc(pci_dev->device.name, data); + if (!adapter) { + opae_adapter_data_free(data); + return -ENOMEM; + } + + rawdev->dev_ops = &ifpga_rawdev_ops; + rawdev->device = &pci_dev->device; + rawdev->driver_name = pci_dev->device.driver->name; + + rawdev->dev_private = adapter; + + /* must enumerate the adapter before use it */ + ret = opae_adapter_enumerate(adapter); + if (ret) + return ret; + + /* set opae_manager to rawdev */ + mgr = opae_adapter_get_mgr(adapter); + if (mgr) { + /*PF function*/ + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); + } + + rte_ifpga_scan_2nd(rawdev, &pci_dev->addr); + + return ret; + +cleanup: + if (rawdev) + rte_rawdev_pmd_release(rawdev); + + return ret; +} + +static int +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) +{ + int ret; + struct rte_rawdev *rawdev; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + struct opae_adapter *adapter; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + return ret; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%x:%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", + name, rte_socket_id()); + + rawdev = rte_rawdev_pmd_get_named_dev(name); + if (!rawdev) { + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name); + return -EINVAL; + } + + adapter = ifpga_rawdev_get_priv(rawdev); + if (!adapter) + return -ENODEV; + + opae_adapter_data_free(adapter->data); + opae_adapter_free(adapter); + + /* rte_rawdev_close is called by pmd_release */ + ret = rte_rawdev_pmd_release(rawdev); + if (ret) + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); + + return 0; +} + +static int +ifpga_rawdev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, + struct rte_pci_device *pci_dev) +{ + + printf("## %s\n", __func__); + return ifpga_rawdev_create(pci_dev, rte_socket_id()); +} + +static int ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) +{ + return ifpga_rawdev_destroy(pci_dev); +} + +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { + .id_table = pci_ifpga_map, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, + .probe = ifpga_rawdev_pci_probe, + .remove = ifpga_rawdev_pci_remove, +}; + +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | uio_pci_generic | vfio-pci"); + +RTE_INIT(ifpga_rawdev_init_log); +static void +ifpga_rawdev_init_log(void) +{ + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); + if (ifpga_rawdev_logtype >= 0) + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); +} diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h new file mode 100644 index 0000000..f346d1a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2015 Intel Corporation. + * Copyright 2013-2014 6WIND S.A. + */ + +#ifndef _IFPGA_RAWDEV_H_ +#define _IFPGA_RAWDEV_H_ + +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) + +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") + +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) +#define IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) +#define IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) +#define IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) + +enum ifpga_rawdev_device_state { + IFPGA_IDLE, + IFPGA_READY, + IFPGA_ERROR +}; + +static inline struct opae_adapter * +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) +{ + return rawdev->dev_private; +} + +#endif /* _IFPGA_RAWDEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c b/drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c new file mode 100644 index 0000000..e073db2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation. + * Copyright 2013-2014 6WIND S.A. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <inttypes.h> +#include <sys/types.h> +#include <sys/queue.h> +#include <netinet/in.h> +#include <setjmp.h> +#include <stdarg.h> +#include <ctype.h> +#include <errno.h> +#include <getopt.h> +#include <signal.h> +#include <stdbool.h> + +#include <rte_common.h> +#include <rte_log.h> +#include <rte_malloc.h> +#include <rte_memory.h> +#include <rte_memcpy.h> +#include <rte_eal.h> +#include <rte_launch.h> +#include <rte_atomic.h> +#include <rte_cycles.h> +#include <rte_prefetch.h> +#include <rte_lcore.h> +#include <rte_per_lcore.h> +#include <rte_branch_prediction.h> +#include <rte_interrupts.h> +#include <rte_random.h> +#include <rte_debug.h> +#include <rte_ether.h> +#include <rte_ethdev.h> +#include <rte_mempool.h> +#include <rte_mbuf.h> +#include <rte_io.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_memzone.h> + +#include <rte_devargs.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_alarm.h> + +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" + +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ +RTE_INIT(afudrvinitfn_ ##afudrv);\ +static const char *afudrvinit_ ## nm ## _alias;\ +static void afudrvinitfn_ ##afudrv(void)\ +{\ + (afudrv).driver.name = RTE_STR(nm);\ + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ + rte_ifpga_driver_register(&afudrv);\ +} \ +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) + +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ +static const char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) + +static int afu_dev_probe(struct rte_afu_device *afu_dev) +{ + if (!afu_dev) + return 1; + else + return 0; +} +static int afu_dev_remove(struct rte_afu_device *afu_dev) +{ + if (!afu_dev) + return 1; + else + return 0; +} + +static struct rte_afu_driver afu_dev_driver = { + .probe = afu_dev_probe, + .remove = afu_dev_remove, +}; + +RTE_PMD_REGISTER_AFU(net_afu_drv_example, afu_dev_driver); +RTE_PMD_REGISTER_AFU_ALIAS(net_afu_drv_example, afu_dev); +RTE_PMD_REGISTER_PARAM_STRING(net_afu_drv_example, + "bdf=<string> " + "port=<int> " + "uudi_high=<int64> " + "uuid_low=<int64> " + "path=<string> " + "pr_enable=<int>" + "debug=<int>"); diff --git a/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map new file mode 100644 index 0000000..179140f --- /dev/null +++ b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map @@ -0,0 +1,4 @@ +DPDK_18.02 { + + local: *; +}; -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH V1 5/5] Add Intel OPAE Share Code 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (3 preceding siblings ...) 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 4/5] Add Intel FPGA BUS Rawdev Code Rosen Xu @ 2018-03-20 13:45 ` Rosen Xu 2018-03-20 14:58 ` [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Gaëtan Rivet ` (12 subsequent siblings) 17 siblings, 0 replies; 149+ messages in thread From: Rosen Xu @ 2018-03-20 13:45 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu, gaetan.rivet Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> Signed-off-by: Wu, Hao <hao.wu@intel.com> --- drivers/raw/ifpga_rawdev/base/Makefile | 54 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 543 +++++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 77 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 84 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1696 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 861 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 38 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 340 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 197 +++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 763 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 328 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 430 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 742 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 395 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 152 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 730 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 236 +++ drivers/raw/ifpga_rawdev/base/opae_debug.c | 126 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 46 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 389 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 276 ++++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 151 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 293 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 111 ++ .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 104 ++ .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 72 + 26 files changed, 9234 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile new file mode 100644 index 0000000..9c0d64b --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -0,0 +1,54 @@ +# BSD LICENSE +# +# Copyright(c) 2017-2018 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +ifneq ($(CONFIG_RTE_LIBRTE_EAL),) +OSDEP := osdep_rte +else +OSDEP := osdep_raw +endif + +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev/base/$(OSDEP) + +SRCS-y += ifpga_api.c +SRCS-y += ifpga_enumerate.c +SRCS-y += ifpga_feature_dev.c +SRCS-y += ifpga_fme.c +SRCS-y += ifpga_fme_iperf.c +SRCS-y += ifpga_fme_dperf.c +SRCS-y += ifpga_fme_error.c +SRCS-y += ifpga_port.c +SRCS-y += ifpga_port_error.c +SRCS-y += ifpga_fme_pr.c +SRCS-y += opae_hw_api.c +SRCS-y += opae_ifpga_hw_api.c +SRCS-y += opae_debug.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 new file mode 100644 index 0000000..54a2e42 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -0,0 +1,543 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_api.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +#include "opae_hw_api.h" + +/* Accelerator APIs */ +static int ifpga_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + struct fpga_uafu_irq_set irq_set; + + if (!br || !br->data) + return -EINVAL; + + if (start >= afu_info->num_irqs || start + count > afu_info->num_irqs) + return -EINVAL; + + port = br->data; + + irq_set.start = start; + irq_set.count = count; + irq_set.evtfds = evtfds; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + PORT_FEATURE_ID_UINT, &irq_set); +} + +static int ifpga_acc_get_info(struct opae_accelerator *acc, + struct opae_acc_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -ENODEV; + + info->num_regions = afu_info->num_regions; + info->num_irqs = afu_info->num_irqs; + + return 0; +} + +static int ifpga_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -EINVAL; + + if (afu_info->num_regions >= info->index) + return -EINVAL; + + /* always one RW region only for AFU now */ + info->flags = ACC_REGION_READ | ACC_REGION_WRITE | ACC_REGION_MMIO; + info->len = afu_info->region[info->index].len; + + return 0; +} + +static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + switch (byte) { + case 8: + *(u64 *)data = opae_readq(region->addr + offset); + break; + case 4: + *(u32 *)data = opae_readl(region->addr + offset); + break; + case 2: + *(u16 *)data = opae_readw(region->addr + offset); + break; + case 1: + *(u8 *)data = opae_readb(region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ifpga_acc_write(struct opae_accelerator *acc, + unsigned int region_idx, u64 offset, + unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + /* normal mmio case */ + switch (byte) { + case 8: + opae_writeq(*(u64 *)data, region->addr + offset); + break; + case 4: + opae_writel(*(u32 *)data, region->addr + offset); + break; + case 2: + opae_writew(*(u16 *)data, region->addr + offset); + break; + case 1: + opae_writeb(*(u8 *)data, region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +struct opae_accelerator_ops ifpga_acc_ops = { + .read = ifpga_acc_read, + .write = ifpga_acc_write, + .set_irq = ifpga_acc_set_irq, + .get_info = ifpga_acc_get_info, + .get_region_info = ifpga_acc_get_region_info, +}; + +/* Bridge APIs */ + +static int ifpga_br_reset(struct opae_bridge *br) +{ + struct ifpga_port_hw *port = br->data; + + return fpga_port_reset(port); +} + +struct opae_bridge_ops ifpga_br_ops = { + .reset = ifpga_br_reset, +}; + +/* Manager APIs */ +static int ifpga_mgr_flash(struct opae_manager *mgr, int id, void *buf, + u32 size, u64 *status) +{ + struct ifpga_fme_hw *fme = mgr->data; + struct ifpga_hw *hw = fme->parent; + + return ifpga_pr(hw, id, buf, size, status); +} + +struct opae_manager_ops ifpga_mgr_ops = { + .flash = ifpga_mgr_flash, +}; + +/* Adapter APIs */ +static int ifpga_adapter_enumerate(struct opae_adapter *adapter) +{ + struct ifpga_hw *hw = malloc(sizeof(*hw)); + + if (hw) { + memset(hw, 0, sizeof(*hw)); + hw->pci_data = adapter->data; + hw->adapter = adapter; + if (ifpga_bus_enumerate(hw)) + goto error; + return ifpga_bus_init(hw); + } + +error: + return -ENOMEM; +} + +struct opae_adapter_ops ifpga_adapter_ops = { + .enumerate = ifpga_adapter_enumerate, +}; + +/** + * ifpga_enumerate - enumerate the Device Feature List + * @hw: pointer to the HW structure + * + * This function enumerate the Device Feature List to discover + * the FME and Port devices. The FME device and Port devices + * will fill into HW structure when enumerate done. + * + * @return + * - 0: Success, device enumated. + * - <0: Error code returned in enumeration. + **/ +int ifpga_enumerate(struct ifpga_hw *hw) +{ + return ifpga_bus_enumerate(hw); +} + +/** + * ifpga_reset_port - reset a port device + * @hw: pointer to the HW structure + * @port_id: port device id + * + * @return + * - 0: Success + * - <0: Failure to reset a port device. + **/ +int ifpga_reset_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return fpga_port_reset(&hw->port[port_id]); +} + +/** + * ifpga_get_afu_mmio_addr - get UAFU MMIO address + * @hw: pointer to the HW structure + * @port_id: port device id + * @mem_resource: afu mmio resource + * @num_resource: number of resource + * + * return 0 on success or error code + **/ +int ifpga_get_afu_mmio_info(struct ifpga_hw *hw, u32 port_id, + struct rte_mem_resource *mem_resource, + u32 *num_resource) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + mem_resource->addr = + hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + mem_resource->len = + hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + mem_resource->phys_addr = + hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].phys_addr; + + *num_resource = 1; + + return 0; +} + +/** + * ifpga_get_afu_uuid - get AFU uuid + * @hw: pointer to the HW structure + * @port_id: port device id + * @uuid: the AFU's uuid + * + * @return + * - 0: Success + * - <0: Failure to get uuid. + **/ +int ifpga_get_afu_uuid(struct ifpga_hw *hw, u32 port_id, struct uuid *uuid) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + if (!hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size) + return -ENODEV; + + return fpga_get_afu_uuid(&hw->port[port_id], uuid); +} + +/** + * ifpga_pr - do the partial reconfiguration for a given port device + * @hw: pointer to the HW structure + * @port_id: the port device id + * @buffer: the buffer of the bitstream + * @size: the size of the bitstream + * @status: hardware status including PR error code if return -EIO. + * + * @return + * - 0: Success, partial reconfiguration finished. + * - <0: Error code returned in partial reconfiguration. + **/ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return do_pr(hw, port_id, buffer, size, status); +} + +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_get_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_get_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set) +{ + if (!hw || !irq_set) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_irq(&hw->fme, feature_id, irq_set); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_irq(&hw->port[port_id], feature_id, irq_set); + } + + return -ENOENT; +} + +int ifpga_port_umsg_enable(struct ifpga_hw *hw, u32 port_id, bool enable) +{ + struct ifpga_port_hw *port = get_port(hw, port_id); + + if (!port) + return -ENODEV; + + spinlock_lock(&port->lock); + if (afu_port_umsg_enable(port, enable)) + return -ENODEV; + spinlock_unlock(&port->lock); + + return 0; +} + +int ifpga_port_umsg_set_mode(struct ifpga_hw *hw, u32 port_id, u32 mode) +{ + struct ifpga_port_hw *port = get_port(hw, port_id); + + if (!port) + return -ENODEV; + + spinlock_lock(&port->lock); + if (afu_port_umsg_set_mode(port, mode)) + return -ENODEV; + spinlock_unlock(&port->lock); + + return 0; +} + +void ifpga_show_pr_error(u64 pr_error) +{ +#if 0 + int i = 0; + + for_each_set_bit(i, &pr_error, PR_MAX_ERR_NUM) + printf("PR Error: %s\n", pr_err_msg[i]); +#endif + printf("PR Error: 0x%lx\n", pr_error); +} + +int ifpga_mmio64_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 *value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + *value = readq(addr + offset); + + return 0; +} + +int ifpga_mmio64_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + writeq(value, addr + offset); + + return 0; +} + +int ifpga_mmio32_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 *value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + *value = readl(addr + offset); + + return 0; +} + +int ifpga_mmio32_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + writel(value, addr + offset); + + return 0; +} + +int ifpga_fme_hw_init(struct ifpga_hw *hw) +{ + return fme_hw_init(&hw->fme); +} + +void ifpga_fme_hw_uinit(struct ifpga_hw *hw) +{ + fme_hw_uinit(&hw->fme); +} + +void ifpga_port_hw_uinit(struct ifpga_hw *hw, int port_id) +{ + struct ifpga_port_hw *port; + + if (!is_valid_port_id(hw, port_id)) + return; + + port = &hw->port[port_id]; + + if (port->state == IFPGA_PORT_ATTACHED) + port_hw_uinit(port); +} + +int ifpga_port_hw_init(struct ifpga_hw *hw, int port_id) +{ + struct ifpga_port_hw *port; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + port = &hw->port[port_id]; + + if (port->state != IFPGA_PORT_ATTACHED) + return -EINVAL; + + return port_hw_init(port); +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.h b/drivers/raw/ifpga_rawdev/base/ifpga_api.h new file mode 100644 index 0000000..f8bca80 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.h @@ -0,0 +1,77 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_API_H_ +#define _IFPGA_API_H_ + +#include "opae_hw_api.h" +#include "ifpga_hw.h" + +extern struct opae_adapter_ops ifpga_adapter_ops; +extern struct opae_manager_ops ifpga_mgr_ops; +extern struct opae_bridge_ops ifpga_br_ops; +extern struct opae_accelerator_ops ifpga_acc_ops; + +/* common APIs */ +int ifpga_enumerate(struct ifpga_hw *hw); +int ifpga_fme_hw_init(struct ifpga_hw *hw); +void ifpga_fme_hw_uinit(struct ifpga_hw *hw); +int ifpga_port_hw_init(struct ifpga_hw *hw, int port_id); +void ifpga_port_hw_uinit(struct ifpga_hw *hw, int port_id); +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set); + +/* Port/AFU APIs */ +int ifpga_reset_port(struct ifpga_hw *hw, u32 port_id); +int ifpga_get_afu_mmio_info(struct ifpga_hw *hw, u32 port_id, + struct rte_mem_resource *mem_resource, + u32 *num_resource); +int ifpga_get_afu_uuid(struct ifpga_hw *hw, u32 port_id, struct uuid *uuid); + +int ifpga_mmio64_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 *value); +int ifpga_mmio64_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 value); +int ifpga_mmio32_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 *value); +int ifpga_mmio32_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 value); + +/* FME APIs */ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); +void ifpga_show_pr_error(u64 pr_error); + +/* Port APIs */ +int ifpga_port_umsg_enable(struct ifpga_hw *hw, u32 port_id, bool enable); +int ifpga_port_umsg_set_mode(struct ifpga_hw *hw, u32 port_id, u32 mode); + +#endif /* _IFPGA_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_compat.h b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h new file mode 100644 index 0000000..6670630 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h @@ -0,0 +1,84 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_COMPAT_H_ +#define _IFPGA_COMPAT_H_ + +#include "opae_osdep.h" + +#undef container_of +#define container_of(ptr, type, member) ({ \ + typeof(((type *)0)->member)(*__mptr) = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) +#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE) + +#define readl(addr) opae_readl(addr) +#define readq(addr) opae_readq(addr) +#define writel(value, addr) opae_writel(value, addr) +#define writeq(value, addr) opae_writeq(value, addr) + +#define malloc(size) opae_malloc(size) +#define zmalloc(size) opae_zmalloc(size) +#define free(size) opae_free(size) + +/* + * Wait register's _field to be changed to the given value (_expect's _field) + * by polling with given interval and timeout. + */ +#define fpga_wait_register_field(_field, _expect, _reg_addr, _timeout, _invl)\ +({ \ + int wait = 0; \ + int ret = -ETIMEDOUT; \ + typeof(_expect) value; \ + for (; wait <= _timeout; wait += _invl) { \ + value.csr = readq(_reg_addr); \ + if (_expect._field == value._field) { \ + ret = 0; \ + break; \ + } \ + udelay(_invl); \ + } \ + ret; \ +}) + +#define __maybe_unused __attribute__((__unused__)) + +#define UNUSED(x) (void)(x) + +#endif /* _IFPGA_COMPAT_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h new file mode 100644 index 0000000..7fc99c2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -0,0 +1,1696 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_DEFINES_H_ +#define _IFPGA_DEFINES_H_ + +#include "ifpga_compat.h" + +#define MAX_FPGA_PORT_NUM 4 + +#define FME_FEATURE_HEADER "fme_hdr" +#define FME_FEATURE_THERMAL_MGMT "fme_thermal" +#define FME_FEATURE_POWER_MGMT "fme_power" +#define FME_FEATURE_GLOBAL_IPERF "fme_iperf" +#define FME_FEATURE_GLOBAL_ERR "fme_error" +#define FME_FEATURE_PR_MGMT "fme_pr" +#define FME_FEATURE_HSSI_ETH "fme_hssi" +#define FME_FEATURE_GLOBAL_DPERF "fme_dperf" +#define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" + +#define PORT_FEATURE_HEADER "port_hdr" +#define PORT_FEATURE_UAFU "port_uafu" +#define PORT_FEATURE_ERR "port_err" +#define PORT_FEATURE_UMSG "port_umsg" +#define PORT_FEATURE_PR "port_pr" +#define PORT_FEATURE_UINT "port_uint" +#define PORT_FEATURE_STP "port_stp" + +/* + * do not check the revision id as id may be dynamic under + * some cases, e.g, UAFU. + */ +#define SKIP_REVISION_CHECK 0xff + +#define FME_HEADER_REVISION 1 +#define FME_THERMAL_MGMT_REVISION 0 +#define FME_POWER_MGMT_REVISION 1 +#define FME_GLOBAL_IPERF_REVISION 1 +#define FME_GLOBAL_ERR_REVISION 1 +#define FME_PR_MGMT_REVISION 2 +#define FME_HSSI_ETH_REVISION 0 +#define FME_GLOBAL_DPERF_REVISION 0 +#define FME_QSPI_REVISION 0 + +#define PORT_HEADER_REVISION 0 +/* UAFU's header info depends on the downloaded GBS */ +#define PORT_UAFU_REVISION SKIP_REVISION_CHECK +#define PORT_ERR_REVISION 1 +#define PORT_UMSG_REVISION 0 +#define PORT_UINT_REVISION 0 +#define PORT_STP_REVISION 1 + +#define FEATURE_TYPE_AFU 0x1 +#define FEATURE_TYPE_BBB 0x2 +#define FEATURE_TYPE_PRIVATE 0x3 +#define FEATURE_TYPE_FIU 0x4 + +#define FEATURE_FIU_ID_FME 0x0 +#define FEATURE_FIU_ID_PORT 0x1 + +#define FEATURE_ID_HEADER 0x0 +#define FEATURE_ID_AFU 0xff + +enum fpga_id_type { + FME_ID, + PORT_ID, + 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, +}; + +struct uuid { + u8 b[16]; +}; + +/* + * All headers and structures must be byte-packed to match the + * SAS spec. + */ +#pragma pack(1) + +struct feature_header { + union { + u64 csr; + struct { + u16 id:12; + u8 revision:4; + u32 next_header_offset:24; + u8 end_of_list:1; + u32 reserved:19; + u8 type:4; + }; + }; +}; + +struct feature_bbb_header { + struct uuid guid; +}; + +struct feature_afu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fiu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fme_capability { + union { + u64 csr; + struct { + u8 fabric_verid; /* Fabric version ID */ + u8 socket_id:1; /* Socket id */ + u8 rsvd1:3; /* Reserved */ + /* pci0 link available yes /no */ + u8 pci0_link_avile:1; + /* pci1 link available yes /no */ + u8 pci1_link_avile:1; + /* Coherent (QPI/UPI) link available yes /no */ + u8 qpi_link_avile:1; + u8 rsvd2:1; /* Reserved */ + /* IOMMU or VT-d supported yes/no */ + u8 iommu_support:1; + u8 num_ports:3; /* Number of ports */ + u8 sf_fab_ctl:1; /* Internal validation bit */ + u8 rsvd3:3; /* Reserved */ + /* + * Address width supported in bits + * BXT -0x26 , SKX -0x30 + */ + u8 address_width_bits:6; + u8 rsvd4:2; /* Reserved */ + /* Size of cache supported in kb */ + u16 cache_size:12; + u8 cache_assoc:4; /* Cache Associativity */ + u16 rsvd5:15; /* Reserved */ + u8 lock_bit:1; /* Lock bit */ + }; + }; +}; + +#define FME_AFU_ACCESS_PF 0 +#define FME_AFU_ACCESS_VF 1 + +struct feature_fme_port { + union { + u64 csr; + struct { + u32 port_offset:24; + u8 reserved1; + u8 port_bar:3; + u32 reserved2:20; + u8 afu_access_control:1; + u8 reserved3:4; + u8 port_implemented:1; + u8 reserved4:3; + }; + }; +}; + +struct feature_fme_fab_status { + union { + u64 csr; + struct { + u8 upilink_status:4; /* UPI Link Status */ + u8 rsvd1:4; /* Reserved */ + u8 pci0link_status:1; /* pci0 link status */ + u8 rsvd2:3; /* Reserved */ + u8 pci1link_status:1; /* pci1 link status */ + u64 rsvd3:51; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_base { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Base Address of memory range */ + u8 protected_base_addrss:4; + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_limit { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Limit Address of memory range */ + u8 protected_limit_addrss:4; + u16 rsvd2:11; /* Reserved */ + u8 enable:1; /* Enable GENPROTRANGE check */ + u32 rsvd3; /* Reserved */ + }; + }; +}; + +struct feature_fme_dxe_lock { + union { + u64 csr; + struct { + /* + * Determines write access to the DXE region CSRs + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_early_lock:1; + /* + * Determines write access to the HSSI CSR + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_late_lock:1; + u64 rsvd:62; + }; + }; +}; + +#define HSSI_ID_NO_HASSI 0 +#define HSSI_ID_PCIE_RP 1 +#define HSSI_ID_ETHERNET 2 + +struct feature_fme_bitstream_id { + union { + u64 csr; + struct { + u32 gitrepo_hash:32; /* GIT repository hash */ + /* + * HSSI configuration identifier: + * 0 - No HSSI + * 1 - PCIe-RP + * 2 - Ethernet + */ + u8 hssi_id:4; + u16 rsvd1:12; /* Reserved */ + /* Bitstream version patch number */ + u8 bs_verpatch:4; + /* Bitstream version minor number */ + u8 bs_verminor:4; + /* Bitstream version major number */ + u8 bs_vermajor:4; + /* Bitstream version debug number */ + u8 bs_verdebug:4; + }; + }; +}; + +struct feature_fme_bitstream_md { + union { + u64 csr; + struct { + /* Seed number userd for synthesis flow */ + u8 synth_seed:4; + /* Synthesis date(day number - 2 digits) */ + u8 synth_day:8; + /* Synthesis date(month number - 2 digits) */ + u8 synth_month:8; + /* Synthesis date(year number - 2 digits) */ + u8 synth_year:8; + u64 rsvd:36; /* Reserved */ + }; + }; +}; + +struct feature_fme_iommu_ctrl { + union { + u64 csr; + struct { + /* Disables IOMMU prefetcher for C0 channel */ + u8 prefetch_disableC0:1; + /* Disables IOMMU prefetcher for C1 channel */ + u8 prefetch_disableC1:1; + /* Disables IOMMU partial cache line writes */ + u8 prefetch_wrdisable:1; + u8 rsvd1:1; /* Reserved */ + /* + * Select counter and read value from register + * iommu_stat.dbg_counters + * 0 - Number of 4K page translation response + * 1 - Number of 2M page translation response + * 2 - Number of 1G page translation response + */ + u8 counter_sel:2; + u32 rsvd2:26; /* Reserved */ + /* Connected to IOMMU SIP Capabilities */ + u32 capecap_defeature; + }; + }; +}; + +struct feature_fme_iommu_stat { + union { + u64 csr; + struct { + /* Translation Enable bit from IOMMU SIP */ + u8 translation_enable:1; + /* Drain request in progress */ + u8 drain_req_inprog:1; + /* Invalidation current state */ + u8 inv_state:3; + /* C0 Response Buffer current state */ + u8 respbuffer_stateC0:3; + /* C1 Response Buffer current state */ + u8 respbuffer_stateC1:3; + /* Last request ID to IOMMU SIP */ + u8 last_reqID:4; + /* Last IOMMU SIP response ID value */ + u8 last_respID:4; + /* Last IOMMU SIP response status value */ + u8 last_respstatus:3; + /* C0 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC0:1; + /* C1 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC1:1; + /* C0 Request FIFO is not empty */ + u8 reqFIFO_notemptyC0:1; + /* C1 Request FIFO is not empty */ + u8 reqFIFO_notemptyC1:1; + /* C0 Response FIFO is not empty */ + u8 respFIFO_notemptyC0:1; + /* C1 Response FIFO is not empty */ + u8 respFIFO_notemptyC1:1; + /* C0 Response FIFO overflow detected */ + u8 respFIFO_overflowC0:1; + /* C1 Response FIFO overflow detected */ + u8 respFIFO_overflowC1:1; + /* C0 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC0:1; + /* C1 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC1:1; + /* Request FIFO overflow detected */ + u8 reqFIFO_overflow:1; + /* IOMMU memory read in progress */ + u8 memrd_inprog:1; + /* IOMMU memory write in progress */ + u8 memwr_inprog:1; + u8 rsvd1:1; /* Reserved */ + /* Value of counter selected by iommu_ctl.counter_sel */ + u16 dbg_counters:16; + u16 rsvd2:12; /* Reserved */ + }; + }; +}; + +struct feature_fme_pcie0_ctrl { + union { + u64 csr; + struct { + u64 vtd_bar_lock:1; /* Lock VT-D BAR register */ + u64 rsvd1:3; + u64 rciep:1; /* Configure PCIE0 as RCiEP */ + u64 rsvd2:59; + }; + }; +}; + +struct feature_fme_llpr_smrr_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR rule is valid or not */ + /* + * SMRR memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR2 rule is valid or not */ + /* + * SMRR2 memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_meseg_base { + union { + u64 csr; + struct { + /* A[45:19] of base address memory range */ + u64 me_base:27; + u64 rsvd:37; + }; + }; +}; + +struct feature_fme_llpr_meseg_limit { + union { + u64 csr; + struct { + /* A[45:19] of limit address memory range */ + u64 me_limit:27; + u64 rsvd1:4; + u64 enable:1; /* Enable LLPR MESEG rule */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 reserved; + u64 scratchpad; + struct feature_fme_capability capability; + struct feature_fme_port port[MAX_FPGA_PORT_NUM]; + struct feature_fme_fab_status fab_status; + struct feature_fme_bitstream_id bitstream_id; + struct feature_fme_bitstream_md bitstream_md; + struct feature_fme_genprotrange2_base genprotrange2_base; + struct feature_fme_genprotrange2_limit genprotrange2_limit; + struct feature_fme_dxe_lock dxe_lock; + struct feature_fme_iommu_ctrl iommu_ctrl; + struct feature_fme_iommu_stat iommu_stat; + struct feature_fme_pcie0_ctrl pcie0_control; + struct feature_fme_llpr_smrr_base smrr_base; + struct feature_fme_llpr_smrr_mask smrr_mask; + struct feature_fme_llpr_smrr2_base smrr2_base; + struct feature_fme_llpr_smrr2_mask smrr2_mask; + struct feature_fme_llpr_meseg_base meseg_base; + struct feature_fme_llpr_meseg_limit meseg_limit; +}; + +struct feature_port_capability { + union { + u64 csr; + struct { + u8 port_number:2; /* Port Number 0-3 */ + u8 rsvd1:6; /* Reserved */ + u16 mmio_size; /* User MMIO size in KB */ + u8 rsvd2; /* Reserved */ + u8 sp_intr_num:4; /* Supported interrupts num */ + u32 rsvd3:28; /* Reserved */ + }; + }; +}; + +struct feature_port_control { + union { + u64 csr; + struct { + u8 port_sftrst:1; /* Port Soft Reset */ + u8 rsvd1:1; /* Reserved */ + u8 latency_tolerance:1;/* '1' >= 40us, '0' < 40us */ + u8 rsvd2:1; /* Reserved */ + u8 port_sftrst_ack:1; /* HW ACK for Soft Reset */ + u64 rsvd3:59; /* Reserved */ + }; + }; +}; + +#define PORT_POWER_STATE_NORMAL 0 +#define PORT_POWER_STATE_AP1 1 +#define PORT_POWER_STATE_AP2 2 +#define PORT_POWER_STATE_AP6 6 + +struct feature_port_status { + union { + u64 csr; + struct { + u8 port_freeze:1; /* '1' - freezed '0' - normal */ + u8 rsvd1:7; /* Reserved */ + u8 power_state:4; /* Power State */ + u8 ap1_event:1; /* AP1 event was detected */ + u8 ap2_event:1; /* AP2 event was detected */ + u64 rsvd2:50; /* Reserved */ + }; + }; +}; + +/* Port Header Register Set */ +struct feature_port_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 port_mailbox; + u64 scratchpad; + struct feature_port_capability capability; + struct feature_port_control control; + struct feature_port_status status; + u64 rsvd2; + u64 user_clk_freq_cmd0; + u64 user_clk_freq_cmd1; + u64 user_clk_freq_sts0; + u64 user_clk_freq_sts1; +}; + +struct feature_fme_tmp_threshold { + union { + u64 csr; + struct { + u8 tmp_thshold1:7; /* temperature Threshold 1 */ + /* temperature Threshold 1 enable/disable */ + u8 tmp_thshold1_enable:1; + u8 tmp_thshold2:7; /* temperature Threshold 2 */ + /* temperature Threshold 2 enable /disable */ + u8 tmp_thshold2_enable:1; + u8 pro_hot_setpoint:7; /* Proc Hot set point */ + u8 rsvd4:1; /* Reserved */ + u8 therm_trip_thshold:7; /* Thermeal Trip Threshold */ + u8 rsvd3:1; /* Reserved */ + u8 thshold1_status:1; /* Threshold 1 Status */ + u8 thshold2_status:1; /* Threshold 2 Status */ + u8 rsvd5:1; /* Reserved */ + /* Thermeal Trip Threshold status */ + u8 therm_trip_thshold_status:1; + u8 rsvd6:4; /* Reserved */ + /* Validation mode- Force Proc Hot */ + u8 valmodeforce:1; + /* Validation mode - Therm trip Hot */ + u8 valmodetherm:1; + u8 rsvd2:2; /* Reserved */ + u8 thshold_policy:1; /* threshold policy */ + u32 rsvd:19; /* Reserved */ + }; + }; +}; + +/* Temperature Sensor Read values format 1 */ +struct feature_fme_temp_rdsensor_fmt1 { + union { + u64 csr; + struct { + /* Reads out FPGA temperature in celsius */ + u8 fpga_temp:7; + u8 rsvd0:1; /* Reserved */ + /* Temperature reading sequence number */ + u16 tmp_reading_seq_num; + /* Temperature reading is valid */ + u8 tmp_reading_valid:1; + u8 rsvd1:7; /* Reserved */ + u16 dbg_mode:10; /* Debug mode */ + u32 rsvd2:22; /* Reserved */ + }; + }; +}; + +/* Temperature sensor read values format 2 */ +struct feature_fme_temp_rdsensor_fmt2 { + u64 rsvd; /* Reserved */ +}; + +/* Temperature Threshold Capability Register */ +struct feature_fme_tmp_threshold_cap { + union { + u64 csr; + struct { + /* Temperature Threshold Unsupported */ + u8 tmp_thshold_disabled:1; + u64 rsvd:63; /* Reserved */ + }; + }; +}; + +/* FME THERNAL FEATURE */ +struct feature_fme_thermal { + struct feature_header header; + struct feature_fme_tmp_threshold threshold; + struct feature_fme_temp_rdsensor_fmt1 rdsensor_fm1; + struct feature_fme_temp_rdsensor_fmt2 rdsensor_fm2; + struct feature_fme_tmp_threshold_cap threshold_cap; +}; + +/* Power Status register */ +struct feature_fme_pm_status { + union { + u64 csr; + struct { + /* FPGA Power consumed, The format is to be defined */ + u32 pwr_consumed:18; + /* FPGA Latency Tolerance Reporting */ + u8 fpga_latency_report:1; + u64 rsvd:45; /* Reserved */ + }; + }; +}; + +/* AP Thresholds */ +struct feature_fme_pm_ap_threshold { + union { + u64 csr; + struct { + /* + * Number of clocks (5ns period) for assertion + * of FME_data + */ + u8 threshold1:7; + u8 rsvd1:1; + u8 threshold2:7; + u8 rsvd2:1; + u8 threshold1_status:1; + u8 threshold2_status:1; + u64 rsvd3:46; /* Reserved */ + }; + }; +}; + +/* Xeon Power Limit */ +struct feature_fme_pm_xeon_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* MCP Power Limit */ +struct feature_fme_pm_fpga_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FME POWER FEATURE */ +struct feature_fme_power { + struct feature_header header; + struct feature_fme_pm_status status; + struct feature_fme_pm_ap_threshold threshold; + struct feature_fme_pm_xeon_limit xeon_limit; + struct feature_fme_pm_fpga_limit fpga_limit; +}; + +#define CACHE_CHANNEL_RD 0 +#define CACHE_CHANNEL_WR 1 + +enum iperf_cache_events { + IPERF_CACHE_RD_HIT, + IPERF_CACHE_WR_HIT, + IPERF_CACHE_RD_MISS, + IPERF_CACHE_WR_MISS, + IPERF_CACHE_RSVD, /* reserved */ + IPERF_CACHE_HOLD_REQ, + IPERF_CACHE_DATA_WR_PORT_CONTEN, + IPERF_CACHE_TAG_WR_PORT_CONTEN, + IPERF_CACHE_TX_REQ_STALL, + IPERF_CACHE_RX_REQ_STALL, + IPERF_CACHE_EVICTIONS, +}; + +/* FPMON Cache Control */ +struct feature_fme_ifpmon_ch_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd1:7; /* Reserved */ + u8 freeze:1; /* Freeze if set to 1 */ + u8 rsvd2:7; /* Reserved */ + u8 cache_event:4; /* Select the cache event */ + u8 cci_chsel:1; /* Select the channel */ + u64 rsvd3:43; /* Reserved */ + }; + }; +}; + +/* FPMON Cache Counter */ +struct feature_fme_ifpmon_ch_ctr { + union { + u64 csr; + struct { + /* Cache Counter for even addresse */ + u64 cache_counter:48; + u16 rsvd:12; /* Reserved */ + /* Cache Event being reported */ + u8 event_code:4; + }; + }; +}; + +enum iperf_fab_events { + IPERF_FAB_PCIE0_RD, + IPERF_FAB_PCIE0_WR, + IPERF_FAB_PCIE1_RD, + IPERF_FAB_PCIE1_WR, + IPERF_FAB_UPI_RD, + IPERF_FAB_UPI_WR, + IPERF_FAB_MMIO_RD, + IPERF_FAB_MMIO_WR, +}; + +#define FAB_DISABLE_FILTER 0 +#define FAB_ENABLE_FILTER 1 + +/* FPMON FAB Control */ +struct feature_fme_ifpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_ifpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_ifpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +enum iperf_vtd_events { + IPERF_VTD_AFU_MEM_RD_TRANS, + IPERF_VTD_AFU_MEM_WR_TRANS, + IPERF_VTD_AFU_DEVTLB_RD_HIT, + IPERF_VTD_AFU_DEVTLB_WR_HIT, + IPERF_VTD_DEVTLB_4K_FILL, + IPERF_VTD_DEVTLB_2M_FILL, + IPERF_VTD_DEVTLB_1G_FILL, +}; + +/* VT-d control register */ +struct feature_fme_ifpmon_vtd_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d event counter */ +struct feature_fme_ifpmon_vtd_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +enum iperf_vtd_sip_events { + IPERF_VTD_SIP_IOTLB_4K_HIT, + IPERF_VTD_SIP_IOTLB_2M_HIT, + IPERF_VTD_SIP_IOTLB_1G_HIT, + IPERF_VTD_SIP_SLPWC_L3_HIT, + IPERF_VTD_SIP_SLPWC_L4_HIT, + IPERF_VTD_SIP_RCC_HIT, + IPERF_VTD_SIP_IOTLB_4K_MISS, + IPERF_VTD_SIP_IOTLB_2M_MISS, + IPERF_VTD_SIP_IOTLB_1G_MISS, + IPERF_VTD_SIP_SLPWC_L3_MISS, + IPERF_VTD_SIP_SLPWC_L4_MISS, + IPERF_VTD_SIP_RCC_MISS, +}; + +/* VT-d SIP control register */ +struct feature_fme_ifpmon_vtd_sip_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d SIP event counter */ +struct feature_fme_ifpmon_vtd_sip_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +/* FME IPERF FEATURE */ +struct feature_fme_iperf { + struct feature_header header; + struct feature_fme_ifpmon_ch_ctl ch_ctl; + struct feature_fme_ifpmon_ch_ctr ch_ctr0; + struct feature_fme_ifpmon_ch_ctr ch_ctr1; + struct feature_fme_ifpmon_fab_ctl fab_ctl; + struct feature_fme_ifpmon_fab_ctr fab_ctr; + struct feature_fme_ifpmon_clk_ctr clk; + struct feature_fme_ifpmon_vtd_ctl vtd_ctl; + struct feature_fme_ifpmon_vtd_ctr vtd_ctr; + struct feature_fme_ifpmon_vtd_sip_ctl vtd_sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr vtd_sip_ctr; +}; + +enum dperf_fab_events { + DPERF_FAB_PCIE0_RD, + DPERF_FAB_PCIE0_WR, + DPERF_FAB_MMIO_RD = 6, + DPERF_FAB_MMIO_WR, +}; + +#define DCP_FAB_DISABLE_FILTER 0 +#define DCP_FAB_ENABLE_FILTER 1 + +/* FPMON FAB Control */ +struct feature_fme_dfpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_dfpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_dfpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +/* FME DPERF FEATURE */ +struct feature_fme_dperf { + struct feature_header header; + u64 rsvd[3]; + struct feature_fme_dfpmon_fab_ctl fab_ctl; + struct feature_fme_dfpmon_fab_ctr fab_ctr; + struct feature_fme_dfpmon_clk_ctr clk; +}; + +struct feature_fme_error0 { +#define FME_ERROR0_MASK 0xFFUL +#define FME_ERROR0_MASK_DEFAULT 0x40UL /* pcode workaround */ + union { + u64 csr; + struct { + u8 fabric_err:1; /* Fabric error */ + u8 fabfifo_overflow:1; /* Fabric fifo overflow */ + u8 kticdc_parity_err:2;/* KTI CDC Parity Error */ + u8 iommu_parity_err:1; /* IOMMU Parity error */ + /* AFU PF/VF access mismatch detected */ + u8 afu_acc_mode_err:1; + u8 mbp_err:1; /* Indicates an MBP event */ + /* PCIE0 CDC Parity Error */ + u8 pcie0cdc_parity_err:5; + /* PCIE1 CDC Parity Error */ + u8 pcie1cdc_parity_err:5; + /* CVL CDC Parity Error */ + u8 cvlcdc_parity_err:3; + u64 rsvd:44; /* Reserved */ + }; + }; +}; + +/* PCIe0 Error Status register */ +struct feature_fme_pcie0_error { +#define FME_PCIE0_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:52; /* Reserved */ + u8 vfnumb_err:1; /* Number of error VF */ + u8 funct_type_err:1; /* Virtual (1) or Physical */ + }; + }; +}; + +/* PCIe1 Error Status register */ +struct feature_fme_pcie1_error { +#define FME_PCIE1_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:54; /* Reserved */ + }; + }; +}; + +/* FME First Error register */ +struct feature_fme_first_error { +#define FME_FIRST_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered first + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered first + */ + u8 errReg_id:4; + }; + }; +}; + +/* FME Next Error register */ +struct feature_fme_next_error { +#define FME_NEXT_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered second + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered second + */ + u8 errReg_id:4; + }; + }; +}; + +/* RAS Non Fatal Error Status register */ +struct feature_fme_ras_nonfaterror { + union { + u64 csr; + struct { + /* thremal threshold AP1 */ + u8 temp_thresh_ap1:1; + /* thremal threshold AP2 */ + u8 temp_thresh_ap2:1; + u8 pcie_error:1; /* pcie Error */ + u8 portfatal_error:1; /* port fatal error */ + u8 proc_hot:1; /* Indicates a ProcHot event */ + /* Indicates an AFU PF/VF access mismatch */ + u8 afu_acc_mode_err:1; + /* Injected nonfata Error */ + u8 injected_nonfata_err:1; + u8 rsvd1:2; + /* Temperature threshold triggered AP6*/ + u8 temp_thresh_AP6:1; + /* Power threshold triggered AP1 */ + u8 power_thresh_AP1:1; + /* Power threshold triggered AP2 */ + u8 power_thresh_AP2:1; + /* Indicates a MBP event */ + u8 mbp_err:1; + u64 rsvd2:51; /* Reserved */ + }; + }; +}; + +/* RAS Catastrophic Fatal Error Status register */ +struct feature_fme_ras_catfaterror { + union { + u64 csr; + struct { + /* KTI Link layer error detected */ + u8 ktilink_fatal_err:1; + /* tag-n-cache error detected */ + u8 tagcch_fatal_err:1; + /* CCI error detected */ + u8 cci_fatal_err:1; + /* KTI Protocol error detected */ + u8 ktiprpto_fatal_err:1; + /* Fatal DRAM error detected */ + u8 dram_fatal_err:1; + /* IOMMU detected */ + u8 iommu_fatal_err:1; + /* Fabric Fatal Error */ + u8 fabric_fatal_err:1; + /* PCIe possion Error */ + u8 pcie_poison_err:1; + /* Injected fatal Error */ + u8 inject_fata_err:1; + /* Catastrophic CRC Error */ + u8 crc_catast_err:1; + /* Catastrophic Thermal Error */ + u8 therm_catast_err:1; + /* Injected Catastrophic Error */ + u8 injected_catast_err:1; + u64 rsvd:52; + }; + }; +}; + +/* RAS Error injection register */ +struct feature_fme_ras_error_inj { +#define FME_RAS_ERROR_INJ_MASK 0x7UL + union { + u64 csr; + struct { + u8 catast_error:1; /* Catastrophic error flag */ + u8 fatal_error:1; /* Fatal error flag */ + u8 nonfatal_error:1; /* NonFatal error flag */ + u64 rsvd:61; /* Reserved */ + }; + }; +}; + +/* FME error capabilities */ +struct feature_fme_error_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* FME ERR FEATURE */ +struct feature_fme_err { + struct feature_header header; + struct feature_fme_error0 fme_err_mask; + struct feature_fme_error0 fme_err; + struct feature_fme_pcie0_error pcie0_err_mask; + struct feature_fme_pcie0_error pcie0_err; + struct feature_fme_pcie1_error pcie1_err_mask; + struct feature_fme_pcie1_error pcie1_err; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + struct feature_fme_ras_nonfaterror ras_nonfat_mask; + struct feature_fme_ras_nonfaterror ras_nonfaterr; + struct feature_fme_ras_catfaterror ras_catfat_mask; + struct feature_fme_ras_catfaterror ras_catfaterr; + struct feature_fme_ras_error_inj ras_error_inj; + struct feature_fme_error_capability fme_err_capability; +}; + +/* FME Partial Reconfiguration Control */ +struct feature_fme_pr_ctl { + union { + u64 csr; + struct { + u8 pr_reset:1; /* Reset PR Engine */ + u8 rsvd3:3; /* Reserved */ + u8 pr_reset_ack:1; /* Reset PR Engine Ack */ + u8 rsvd4:3; /* Reserved */ + u8 pr_regionid:2; /* PR Region ID */ + u8 rsvd1:2; /* Reserved */ + u8 pr_start_req:1; /* PR Start Request */ + u8 pr_push_complete:1; /* PR Data push complete */ + u8 pr_kind:1; /* PR Data push complete */ + u32 rsvd:17; /* Reserved */ + u32 config_data; /* Config data TBD */ + }; + }; +}; + +/* FME Partial Reconfiguration Status */ +struct feature_fme_pr_status { + union { + u64 csr; + struct { + u16 pr_credit:9; /* PR Credits */ + u8 rsvd2:7; /* Reserved */ + u8 pr_status:1; /* PR status */ + u8 rsvd:3; /* Reserved */ + /* Altra PR Controller Block status */ + u8 pr_controller_status:3; + u8 rsvd1:1; /* Reserved */ + u8 pr_host_status:4; /* PR Host status */ + u8 rsvd3:4; /* Reserved */ + /* Security Block Status fields (TBD) */ + u32 security_bstatus; + }; + }; +}; + +/* FME Partial Reconfiguration Data */ +struct feature_fme_pr_data { + union { + u64 csr; /* PR data from the raw-binary file */ + struct { + /* PR data from the raw-binary file */ + u32 pr_data_raw; + u32 rsvd; + }; + }; +}; + +/* FME PR Public Key */ +struct feature_fme_pr_key { + u64 key; /* FME PR Public Hash */ +}; + +/* FME PR FEATURE */ +struct feature_fme_pr { + struct feature_header header; + /*Partial Reconfiguration control */ + struct feature_fme_pr_ctl ccip_fme_pr_control; + + /* Partial Reconfiguration Status */ + struct feature_fme_pr_status ccip_fme_pr_status; + + /* Partial Reconfiguration data */ + struct feature_fme_pr_data ccip_fme_pr_data; + + /* Partial Reconfiguration data */ + u64 ccip_fme_pr_err; + + u64 rsvd1[3]; + + /* Partial Reconfiguration data registers */ + u64 fme_pr_data1; + u64 fme_pr_data2; + u64 fme_pr_data3; + u64 fme_pr_data4; + u64 fme_pr_data5; + u64 fme_pr_data6; + u64 fme_pr_data7; + u64 fme_pr_data8; + + u64 rsvd2[5]; + + /* PR Interface ID */ + u64 fme_pr_intfc_id_l; + u64 fme_pr_intfc_id_h; + + /* MSIX filed to be Added */ +}; + +/* FME HSSI Control */ +struct feature_fme_hssi_eth_ctrl { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u16 address:16; /* HSSI address */ + /* + * HSSI comamnd + * 0x0 - No request + * 0x08 - SW register RD request + * 0x10 - SW register WR request + * 0x40 - Auxiliar bus RD request + * 0x80 - Auxiliar bus WR request + */ + u16 cmd:16; + }; + }; +}; + +/* FME HSSI Status */ +struct feature_fme_hssi_eth_stat { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u8 acknowledge:1; /* HSSI acknowledge */ + u8 spare:1; /* HSSI spare */ + u32 rsvd:30; /* Reserved */ + }; + }; +}; + +/* FME HSSI FEATURE */ +struct feature_fme_hssi { + struct feature_header header; + struct feature_fme_hssi_eth_ctrl hssi_control; + struct feature_fme_hssi_eth_stat hssi_status; +}; + +#define PORT_ERR_MASK 0xfff0703ff001f +struct feature_port_err_key { + union { + u64 csr; + struct { + /* Tx Channel0: Overflow */ + u8 tx_ch0_overflow:1; + /* Tx Channel0: Invalid request encoding */ + u8 tx_ch0_invaldreq :1; + /* Tx Channel0: Request with cl_len=3 not supported */ + u8 tx_ch0_cl_len3:1; + /* Tx Channel0: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch0_cl_len2:1; + /* Tx Channel0: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch0_cl_len4:1; + + u16 rsvd1:4; /* Reserved */ + + /* AFU MMIO RD received while PORT is in reset */ + u8 mmio_rd_whilerst:1; + /* AFU MMIO WR received while PORT is in reset */ + u8 mmio_wr_whilerst:1; + + u16 rsvd2:5; /* Reserved */ + + /* Tx Channel1: Overflow */ + u8 tx_ch1_overflow:1; + /* Tx Channel1: Invalid request encoding */ + u8 tx_ch1_invaldreq:1; + /* Tx Channel1: Request with cl_len=3 not supported */ + u8 tx_ch1_cl_len3:1; + /* Tx Channel1: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch1_cl_len2:1; + /* Tx Channel1: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch1_cl_len4:1; + + /* Tx Channel1: Insufficient data payload */ + u8 tx_ch1_insuff_data:1; + /* Tx Channel1: Data payload overrun */ + u8 tx_ch1_data_overrun:1; + /* Tx Channel1 : Incorrect address */ + u8 tx_ch1_incorr_addr:1; + /* Tx Channel1 : NON-Zero SOP Detected */ + u8 tx_ch1_nzsop:1; + /* Tx Channel1 : Illegal VC_SEL, atomic request VLO */ + u8 tx_ch1_illegal_vcsel:1; + + u8 rsvd3:6; /* Reserved */ + + /* MMIO Read Timeout in AFU */ + u8 mmioread_timeout:1; + + /* Tx Channel2: FIFO Overflow */ + u8 tx_ch2_fifo_overflow:1; + + /* MMIO read is not matching pending request */ + u8 unexp_mmio_resp:1; + + u8 rsvd4:5; /* Reserved */ + + /* Number of pending Requests: counter overflow */ + u8 tx_req_counter_overflow:1; + /* Req with Address violating SMM Range */ + u8 llpr_smrr_err:1; + /* Req with Address violating second SMM Range */ + u8 llpr_smrr2_err:1; + /* Req with Address violating ME Stolen message */ + u8 llpr_mesg_err:1; + /* Req with Address violating Generic Protected Range */ + u8 genprot_range_err:1; + /* Req with Address violating Legacy Range low */ + u8 legrange_low_err:1; + /* Req with Address violating Legacy Range High */ + u8 legrange_high_err:1; + /* Req with Address violating VGA memory range */ + u8 vgmem_range_err:1; + u8 page_fault_err:1; /* Page fault */ + u8 pmr_err:1; /* PMR Error */ + u8 ap6_event:1; /* AP6 event */ + /* VF FLR detected on Port with PF access control */ + u8 vfflr_access_err:1; + u16 rsvd5:12; /* Reserved */ + }; + }; +}; + +/* Port first error register, not contain all error bits in error register. */ +struct feature_port_first_err_key { + union { + u64 csr; + struct { + u8 tx_ch0_overflow:1; + u8 tx_ch0_invaldreq :1; + u8 tx_ch0_cl_len3:1; + u8 tx_ch0_cl_len2:1; + u8 tx_ch0_cl_len4:1; + u8 rsvd1:4; /* Reserved */ + u8 mmio_rd_whilerst:1; + u8 mmio_wr_whilerst:1; + u8 rsvd2:5; /* Reserved */ + u8 tx_ch1_overflow:1; + u8 tx_ch1_invaldreq:1; + u8 tx_ch1_cl_len3:1; + u8 tx_ch1_cl_len2:1; + u8 tx_ch1_cl_len4:1; + u8 tx_ch1_insuff_data:1; + u8 tx_ch1_data_overrun:1; + u8 tx_ch1_incorr_addr:1; + u8 tx_ch1_nzsop:1; + u8 tx_ch1_illegal_vcsel:1; + u8 rsvd3:6; /* Reserved */ + u8 mmioread_timeout:1; + u8 tx_ch2_fifo_overflow:1; + u8 rsvd4:6; /* Reserved */ + u8 tx_req_counter_overflow:1; + u32 rsvd5:23; /* Reserved */ + }; + }; +}; + +/* Port malformed Req0 */ +struct feature_port_malformed_req0 { + u64 header_lsb; +}; + +/* Port malformed Req1 */ +struct feature_port_malformed_req1 { + u64 header_msb; +}; + +/* Port debug register */ +struct feature_port_debug { + u64 port_debug; +}; + +/* Port error capabilities */ +struct feature_port_err_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE ERROR */ +struct feature_port_error { + struct feature_header header; + struct feature_port_err_key error_mask; + struct feature_port_err_key port_error; + struct feature_port_first_err_key port_first_error; + struct feature_port_malformed_req0 malreq0; + struct feature_port_malformed_req1 malreq1; + struct feature_port_debug port_debug; + struct feature_port_err_capability error_capability; +}; + +/* Port UMSG Capability */ +struct feature_port_umsg_cap { + union { + u64 csr; + struct { + /* Number of umsg allocated to this port */ + u8 umsg_allocated; + /* Enable / Disable UMsg engine for this port */ + u8 umsg_enable:1; + /* Usmg initialization status */ + u8 umsg_init_complete:1; + /* IOMMU can not translate the umsg base address */ + u8 umsg_trans_error:1; + u64 rsvd:53; /* Reserved */ + }; + }; +}; + +/* Port UMSG base address */ +struct feature_port_umsg_baseaddr { + union { + u64 csr; + struct { + u64 base_addr:48; /* 48 bit physical address */ + u16 rsvd; /* Reserved */ + }; + }; +}; + +struct feature_port_umsg_mode { + union { + u64 csr; + struct { + u32 umsg_hint_enable; /* UMSG hint enable/disable */ + u32 rsvd; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE UMSG */ +struct feature_port_umsg { + struct feature_header header; + struct feature_port_umsg_cap capability; + struct feature_port_umsg_baseaddr baseaddr; + struct feature_port_umsg_mode mode; +}; + +#define UMSG_EN_POLL_INVL 10 /* us */ +#define UMSG_EN_POLL_TIMEOUT 1000 /* us */ + +/* Port UINT Capability */ +struct feature_port_uint_cap { + union { + u64 csr; + struct { + u16 intr_num:12; /* Supported interrupts num */ + /* First MSI-X vector table entry number */ + u16 first_vec_num:12; + u64 rsvd:40; + }; + }; +}; + +/* PORT FEATURE UINT */ +struct feature_port_uint { + struct feature_header header; + struct feature_port_uint_cap capability; +}; + +/* STP region supports mmap operation, so use page aligned size. */ +#define PORT_FEATURE_STP_REGION_SIZE PAGE_ALIGN(sizeof(struct feature_port_stp)) + +/* Port STP status register (for debug only)*/ +struct feature_port_stp_status { + union { + u64 csr; + struct { + /* SLD Hub end-point read/write timeout */ + u8 sld_ep_timeout:1; + /* Remote STP in reset/disable */ + u8 rstp_disabled:1; + u8 unsupported_read:1; + /* MMIO timeout detected and faked with a response */ + u8 mmio_timeout:1; + u8 txfifo_count:4; + u8 rxfifo_count:4; + u8 txfifo_overflow:1; + u8 txfifo_underflow:1; + u8 rxfifo_overflow:1; + u8 rxfifo_underflow:1; + /* Number of MMIO write requests */ + u16 write_requests; + /* Number of MMIO read requests */ + u16 read_requests; + /* Number of MMIO read responses */ + u16 read_responses; + }; + }; +}; + +/* + * PORT FEATURE STP + * Most registers in STP region are not touched by driver, but mmapped to user + * space. So they are not defined in below data structure, as its actual size + * is 0x18c per spec. + */ +struct feature_port_stp { + struct feature_header header; + struct feature_port_stp_status stp_status; +}; + +/** + * enum fpga_pr_states - fpga PR states + * @FPGA_PR_STATE_UNKNOWN: can't determine state + * @FPGA_PR_STATE_WRITE_INIT: preparing FPGA for programming + * @FPGA_PR_STATE_WRITE_INIT_ERR: Error during WRITE_INIT stage + * @FPGA_PR_STATE_WRITE: writing image to FPGA + * @FPGA_PR_STATE_WRITE_ERR: Error while writing FPGA + * @FPGA_PR_STATE_WRITE_COMPLETE: Doing post programming steps + * @FPGA_PR_STATE_WRITE_COMPLETE_ERR: Error during WRITE_COMPLETE + * @FPGA_PR_STATE_OPERATING: FPGA PR done + */ +enum fpga_pr_states { + /* canot determine state states */ + FPGA_PR_STATE_UNKNOWN, + + /* write sequence: init, write, complete */ + FPGA_PR_STATE_WRITE_INIT, + FPGA_PR_STATE_WRITE_INIT_ERR, + FPGA_PR_STATE_WRITE, + FPGA_PR_STATE_WRITE_ERR, + FPGA_PR_STATE_WRITE_COMPLETE, + FPGA_PR_STATE_WRITE_COMPLETE_ERR, + + /* FPGA PR done */ + FPGA_PR_STATE_DONE, +}; + +/* + * FPGA Manager flags + * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported + */ +#define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + +/** + * struct fpga_pr_info - specific information to a FPGA PR + * @flags: boolean flags as defined above + * @pr_err: PR error code + * @state: fpga manager state + * @port_id: port id + */ +struct fpga_pr_info { + u32 flags; + u64 pr_err; + enum fpga_pr_states state; + int port_id; +}; + +#define DEFINE_FPGA_PR_ERR_MSG(_name_) \ +static const char * const _name_[] = { \ + "PR operation error detected", \ + "PR CRC error detected", \ + "PR incompatiable bitstream error detected", \ + "PR IP protocol error detected", \ + "PR FIFO overflow error detected", \ + "PR timeout error detected", \ + "PR secure load error detected", \ +} + +#define RST_POLL_INVL 10 /* us */ +#define RST_POLL_TIMEOUT 1000 /* us */ + +#define PR_WAIT_TIMEOUT 15000000 + +#define PR_HOST_STATUS_IDLE 0 +#define PR_MAX_ERR_NUM 7 + +DEFINE_FPGA_PR_ERR_MSG(pr_err_msg); + +/* + * green bitstream header must be byte-packed to match the + * real file format. + */ +struct bts_header { + u64 guid_h; + u64 guid_l; + u32 metadata_len; +}; + +#define GBS_GUID_H 0x414750466e6f6558 +#define GBS_GUID_L 0x31303076534247b7 +#define is_valid_bts(bts_hdr) \ + (((bts_hdr)->guid_h == GBS_GUID_H) && \ + ((bts_hdr)->guid_l == GBS_GUID_L)) + +#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 new file mode 100644 index 0000000..c6c081a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -0,0 +1,861 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "opae_hw_api.h" +#include "ifpga_api.h" + +#include "ifpga_hw.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +struct build_feature_devs_info { + struct opae_adapter_data_pci *pci_data; + + struct ifpga_afu_info *acc_info; + + void *fiu; + enum fpga_id_type current_type; + int current_port_id; + + void *ioaddr; + void *ioend; + uint64_t phys_addr; + int current_bar; + + void *pfme_hdr; + + struct ifpga_hw *hw; +}; + +struct feature_info { + const char *name; + uint32_t resource_size; + int feature_index; + int revision_id; + unsigned int vec_start; + unsigned int vec_cnt; + + struct feature_ops *ops; +}; + +/* 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, + } +}; + +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 = &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 = &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, + .ops = &port_umsg_ops, + }, + { + .name = PORT_FEATURE_UINT, + .resource_size = sizeof(struct feature_port_uint), + .feature_index = PORT_FEATURE_ID_UINT, + .revision_id = PORT_UINT_REVISION, + .ops = &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 = &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 + }, +}; + +static u64 feature_id(void __iomem *start) +{ + struct feature_header header; + + header.csr = readq(start); + + switch (header.type) { + case FEATURE_TYPE_FIU: + return FEATURE_ID_HEADER; + case FEATURE_TYPE_PRIVATE: + return header.id; + case FEATURE_TYPE_AFU: + return FEATURE_ID_AFU; + } + + WARN_ON(1); + return 0; +} + +static int +build_info_add_sub_feature(struct build_feature_devs_info *binfo, + struct feature_info *finfo, void __iomem *start) +{ + 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; + } + + 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->phys_addr = binfo->phys_addr + + ((u8 *)start - (u8 *)binfo->ioaddr); + + if (vec_cnt) { + if (vec_start + vec_cnt <= vec_start) + return -EINVAL; + + ctx = zmalloc(sizeof(*ctx) * vec_cnt); + if (!ctx) + return -ENOMEM; + + for (i = 0; i < vec_cnt; i++) { + ctx[i].eventfd = -1; + ctx[i].idx = vec_start + i; + } + } + + feature->ctx = ctx; + feature->ctx_num = vec_cnt; + feature->vfio_dev_fd = binfo->pci_data->vfio_dev_fd; + + return ret; +} + +static int +create_feature_instance(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + struct feature_header *hdr = start; + + if (((u8 *)binfo->ioend - (u8 *)start) < finfo->resource_size) + return -EINVAL; + + 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); +} + +/* + * UAFU GUID is dynamic as it can be changed after FME downloads different + * Green Bitstream to the port, so we treat the unknown GUIDs which are + * attached on port's feature list as UAFU. + */ +static bool feature_is_UAFU(struct build_feature_devs_info *binfo) +{ + if (binfo->current_type != PORT_ID) + return false; + + return true; +} + +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; + struct ifpga_afu_info *info; + void *start = (void *)hdr; + int ret; + + if (port_features[id].resource_size) { + ret = create_feature_instance(binfo, hdr, &port_features[id]); + //port_features[id].resource_size = 0; + } else { + dev_err(binfo, "the uafu feature header is mis-configured.\n"); + ret = -EINVAL; + } + + if (ret) + return ret; + + /* FIXME: need to figure out a better name */ + info = 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->num_regions = 1; + + binfo->acc_info = info; + + return ret; +} + +static int parse_feature_afus(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + int ret; + struct feature_afu_header *afu_hdr, header; + u8 __iomem *start; + u8 __iomem *end = binfo->ioend; + + start = (u8 __iomem *)hdr; + for (; start < end; start += header.next_afu) { + if (end - start < + (unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr))) + return -EINVAL; + + hdr = (struct feature_header *)start; + afu_hdr = (struct feature_afu_header *)(hdr + 1); + header.csr = readq(&afu_hdr->csr); + + if (feature_is_UAFU(binfo)) + ret = parse_feature_port_uafu(binfo, hdr); + if (ret) + return ret; + + if (!header.next_afu) + break; + } + + return 0; +} + +/* create and register proper private data */ +static int build_info_commit_dev(struct build_feature_devs_info *binfo) +{ + struct ifpga_afu_info *info = binfo->acc_info; + struct ifpga_hw *hw = binfo->hw; + struct opae_manager *mgr; + struct opae_bridge *br; + struct opae_accelerator *acc; + + if (!binfo->fiu) + return 0; + + if (binfo->current_type == PORT_ID) { + /* return error if no valid acc info data structure */ + if (!info) + return -EFAULT; + + br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops, + binfo->fiu); + if (!br) + return -ENOMEM; + + br->id = binfo->current_port_id; + + /* update irq info */ + info->num_irqs = port_features[PORT_FEATURE_ID_UINT].vec_cnt; + + acc = opae_accelerator_alloc(hw->adapter->name, + &ifpga_acc_ops, info); + if (!acc) { + opae_bridge_free(br); + return -ENOMEM; + } + + acc->br = br; + acc->index = br->id; + + opae_adapter_add_acc(hw->adapter, acc); + + } else if (binfo->current_type == FME_ID) { + mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops, + binfo->fiu); + if (!mgr) + return -ENOMEM; + + mgr->adapter = hw->adapter; + hw->adapter->mgr = mgr; + } + + binfo->fiu = NULL; + + return 0; +} + +static int +build_info_create_dev(struct build_feature_devs_info *binfo, + enum fpga_id_type type, unsigned int index) +{ + int ret; + + ret = build_info_commit_dev(binfo); + if (ret) + return ret; + + binfo->current_type = type; + + if (type == FME_ID) { + binfo->fiu = &binfo->hw->fme; + } else if (type == PORT_ID) { + binfo->fiu = &binfo->hw->port[index]; + binfo->current_port_id = index; + } + + return 0; +} + +static int parse_feature_fme(struct build_feature_devs_info *binfo, + struct feature_header *start) +{ + struct ifpga_hw *hw = binfo->hw; + struct ifpga_fme_hw *fme = &hw->fme; + int ret; + + ret = build_info_create_dev(binfo, FME_ID, 0); + if (ret) + return ret; + + /* Update FME states */ + fme->state = IFPGA_FME_IMPLEMENTED; + fme->parent = hw; + spinlock_init(&fme->lock); + + return create_feature_instance(binfo, start, + &fme_features[FME_FEATURE_ID_HEADER]); +} + +static int parse_feature_port(struct build_feature_devs_info *binfo, + void __iomem *start) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + struct ifpga_hw *hw = binfo->hw; + struct ifpga_port_hw *port; + unsigned int port_id; + int ret; + + /* Get current port's id */ + port_hdr = (struct feature_port_header *)start; + capability.csr = readq(&port_hdr->capability); + port_id = capability.port_number; + + ret = build_info_create_dev(binfo, PORT_ID, port_id); + if (ret) + return ret; + + /*found a Port device*/ + port = &hw->port[port_id]; + port->port_id = binfo->current_port_id; + port->parent = hw; + port->state = IFPGA_PORT_ATTACHED; + spinlock_init(&port->lock); + + return create_feature_instance(binfo, start, + &port_features[PORT_FEATURE_ID_HEADER]); +} + +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 SAS 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); +} + +static int parse_feature_fiu(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + struct feature_fiu_header *fiu_hdr, fiu_header; + u8 __iomem *start = (u8 __iomem *)hdr; + int ret; + + header.csr = readq(hdr); + + switch (header.id) { + case FEATURE_FIU_ID_FME: + ret = parse_feature_fme(binfo, hdr); + //check_features_header(binfo->pdev, hdr, FPGA_DEVT_FME, 0); + binfo->pfme_hdr = hdr; + if (ret) + return ret; + break; + case FEATURE_FIU_ID_PORT: + ret = parse_feature_port(binfo, hdr); + //check_features_header(binfo->pdev, hdr, FPGA_DEVT_PORT, 0); + enable_port_uafu(binfo, hdr); + if (ret) + return ret; + + /* Check Port FIU's next_afu pointer to User AFU DFH */ + fiu_hdr = (struct feature_fiu_header *)(hdr + 1); + fiu_header.csr = readq(&fiu_hdr->csr); + + if (fiu_header.next_afu) { + start += fiu_header.next_afu; + ret = parse_feature_afus(binfo, + (struct feature_header *)start); + if (ret) + return ret; + } else { + dev_info(binfo, "No AFUs detected on Port\n"); + } + + break; + default: + dev_info(binfo, "FIU TYPE %d is not supported yet.\n", + header.id); + } + + return 0; +} + +static void parse_feature_irqs(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + finfo->vec_start = 0; + finfo->vec_cnt = 0; + + UNUSED(binfo); + + if (!strcmp(finfo->name, PORT_FEATURE_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; + } else { + dev_debug(binfo, "UAFU doesn't support interrupt\n"); + } + + } else if (!strcmp(finfo->name, PORT_FEATURE_ERR)) { + 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; + } else + dev_debug(&binfo, "Port error doesn't support interrupt\n"); + + } else if (!strcmp(finfo->name, FME_FEATURE_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; + } else + dev_debug(&binfo, "FME error doesn't support interrupt\n"); + } +} + +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; + } + + parse_feature_irqs(binfo, hdr, &fme_features[header.id]); + + //check_features_header(binfo->pdev, hdr, FPGA_DEVT_FME, header.id); + + return create_feature_instance(binfo, hdr, &fme_features[header.id]); +} + +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; + + 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]); + + //check_features_header(binfo->pdev, hdr, FPGA_DEVT_PORT, id); + + return create_feature_instance(binfo, hdr, &port_features[id]); +} + +static int parse_feature_private(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + + header.csr = readq(hdr); + + switch (binfo->current_type) { + case FME_ID: + return parse_feature_fme_private(binfo, hdr); + case PORT_ID: + return parse_feature_port_private(binfo, hdr); + default: + dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n", + header.id, binfo->current_type); + } + return 0; +} + +static int parse_feature(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + int ret = 0; + + header.csr = readq(hdr); + + switch (header.type) { + case FEATURE_TYPE_AFU: + ret = parse_feature_afus(binfo, hdr); + break; + case FEATURE_TYPE_PRIVATE: + ret = parse_feature_private(binfo, hdr); + break; + case FEATURE_TYPE_FIU: + ret = parse_feature_fiu(binfo, hdr); + break; + default: + dev_err(binfo, "Feature Type %x is not supported.\n", + hdr->type); + }; + + return ret; +} + +static int +parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start) +{ + struct feature_header *hdr, header; + u8 __iomem *end = (u8 __iomem *)binfo->ioend; + int ret = 0; + + for (; start < end; start += header.next_header_offset) { + if (end - start < (unsigned int)sizeof(*hdr)) { + dev_err(binfo, "The region is too small to contain a feature.\n"); + ret = -EINVAL; + break; + } + + hdr = (struct feature_header *)start; + ret = parse_feature(binfo, hdr); + if (ret) + return ret; + + header.csr = readq(hdr); + if (!header.next_header_offset) + break; + } + + return build_info_commit_dev(binfo); +} + +/* switch the memory mapping to BAR# @bar */ +static int parse_switch_to(struct build_feature_devs_info *binfo, int bar) +{ + struct opae_adapter_data_pci *pci_data = binfo->pci_data; + + if (!pci_data->region[bar].addr) + return -ENOMEM; + + binfo->ioaddr = pci_data->region[bar].addr; + binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len; + binfo->phys_addr = pci_data->region[bar].phys_addr; + binfo->current_bar = bar; + + return 0; +} + +static int parse_ports_from_fme(struct build_feature_devs_info *binfo) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_port port; + int i = 0, ret = 0; + + if (!binfo->pfme_hdr) { + dev_info(binfo, "VF is detected.\n"); + return ret; + } + + fme_hdr = binfo->pfme_hdr; + + do { + port.csr = readq(&fme_hdr->port[i]); + if (!port.port_implemented) + break; + + /* skip port which only could be accessed via VF */ + if (port.afu_access_control == FME_AFU_ACCESS_VF) + continue; + + ret = parse_switch_to(binfo, port.port_bar); + if (ret) + break; + + ret = parse_feature_list(binfo, + (u8 __iomem *)binfo->ioaddr + port.port_offset); + if (ret) + break; + } while (++i < MAX_FPGA_PORT_NUM); + + return ret; +} + +static struct build_feature_devs_info * +build_info_alloc_and_init(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + + binfo = zmalloc(sizeof(*binfo)); + if (!binfo) + return binfo; + + binfo->hw = hw; + binfo->pci_data = hw->pci_data; + + /* fpga feature list starts from BAR 0 */ + if (parse_switch_to(binfo, 0)) { + free(binfo); + return NULL; + } + + return binfo; +} + +static void build_info_free(struct build_feature_devs_info *binfo) +{ + free(binfo); +} + +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; + +#if 0 + dev_info(hw, "found a fpga device : %x:%x.%x\n", pci->addr.bus, + pci->addr.devid, pci->addr.function); +#endif + + 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]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr: 0x%lx\n", + feature->name, (unsigned long long)feature->addr, + (unsigned long long)feature->addr + feature->size - 1, + feature->phys_addr); + } + + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) { + port = &hw->port[i]; + + if (port->state != IFPGA_PORT_ATTACHED) + continue; + + dev_info(hw, "port device: %d\n", port->port_id); + + for (j = 0; j < PORT_FEATURE_ID_MAX; j++) { + feature = &port->sub_feature[j]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr:0x%lx\n", + feature->name, + (unsigned long long)feature->addr, + (unsigned long long)feature->addr + + feature->size - 1, + feature->phys_addr); + } + } +} + +int ifpga_bus_enumerate(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + int ret; + + binfo = build_info_alloc_and_init(hw); + if (!binfo) + return -ENOMEM; + + ret = parse_feature_list(binfo, binfo->ioaddr); + if (ret) + goto exit; + + ret = parse_ports_from_fme(binfo); + if (ret) + goto exit; + + ifpga_print_device_feature_list(hw); + +exit: + build_info_free(binfo); + return ret; +} + +int ifpga_bus_init(struct ifpga_hw *hw) +{ + int i; + + fme_hw_init(&hw->fme); + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) + port_hw_init(&hw->port[i]); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h new file mode 100644 index 0000000..0df7b2f --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h @@ -0,0 +1,38 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_ENUMERATE_H_ +#define _IFPGA_ENUMERATE_H_ + +int ifpga_bus_init(struct ifpga_hw *hw); +int ifpga_bus_enumerate(struct ifpga_hw *hw); + +#endif /* _IFPGA_ENUMERATE_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c new file mode 100644 index 0000000..6bc8b90 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -0,0 +1,340 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include <linux/vfio.h> +#include <sys/ioctl.h> + +#include "ifpga_feature_dev.h" + +/* + * Enable Port by clear the port soft reset bit, which is set by default. + * The AFU is unable to respond to any MMIO access while in reset. + * __fpga_port_enable function should only be used after __fpga_port_disable + * function. + */ +void __fpga_port_enable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + WARN_ON(!port->disable_count); + + if (--port->disable_count != 0) + return; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x0; + writeq(control.csr, &port_hdr->control); +} + +int __fpga_port_disable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + if (port->disable_count++ != 0) + return 0; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + /* Set port soft reset */ + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x1; + writeq(control.csr, &port_hdr->control); + + /* + * HW sets ack bit to 1 when all outstanding requests have been drained + * on this port and minimum soft reset pulse width has elapsed. + * Driver polls port_soft_reset_ack to determine if reset done by HW. + */ + control.port_sftrst_ack = 1; + + if (fpga_wait_register_field(port_sftrst_ack, control, + &port_hdr->control, RST_POLL_TIMEOUT, + RST_POLL_INVL)) { + dev_err(port, "timeout, fail to reset device\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) +{ + struct feature_port_header *port_hdr; + u64 guidl, guidh; + + port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU); + + spinlock_lock(&port->lock); + guidl = readq(&port_hdr->afu_header.guid.b[0]); + guidh = readq(&port_hdr->afu_header.guid.b[8]); + spinlock_unlock(&port->lock); + + printf("%s: guidl=0x%lx, guidh=0x%lx\n", __func__, guidl, guidh); + + memcpy(uuid->b, &guidl, sizeof(u64)); + memcpy(uuid->b + 8, &guidh, sizeof(u64)); + + return 0; +} + +/* Mask / Unmask Port Errors by the Error Mask register. */ +void port_err_mask(struct ifpga_port_hw *port, bool mask) +{ + struct feature_port_error *port_err; + struct feature_port_err_key err_mask; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + if (mask) + err_mask.csr = PORT_ERR_MASK; + else + err_mask.csr = 0; + + writeq(err_mask.csr, &port_err->error_mask); +} + +/* Clear All Port Errors. */ +int port_err_clear(struct ifpga_port_hw *port, u64 err) +{ + struct feature_port_header *port_hdr; + struct feature_port_error *port_err; + struct feature_port_err_key mask; + struct feature_port_first_err_key first; + struct feature_port_status status; + int ret = 0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + /* + * Clear All Port Errors + * + * - Check for AP6 State + * - Halt Port by keeping Port in reset + * - Set PORT Error mask to all 1 to mask errors + * - Clear all errors + * - Set Port mask to all 0 to enable errors + * - All errors start capturing new errors + * - Enable Port by pulling the port out of reset + */ + + /* If device is still in AP6 state, can not clear any error.*/ + status.csr = readq(&port_hdr->status); + if (status.power_state == PORT_POWER_STATE_AP6) { + dev_err(dev, "Could not clear errors, device in AP6 state.\n"); + return -EBUSY; + } + + /* Halt Port by keeping Port in reset */ + ret = __fpga_port_disable(port); + if (ret) + return ret; + + /* Mask all errors */ + port_err_mask(port, true); + + /* Clear errors if err input matches with current port errors.*/ + mask.csr = readq(&port_err->port_error); + + if (mask.csr == err) { + writeq(mask.csr, &port_err->port_error); + + first.csr = readq(&port_err->port_first_error); + writeq(first.csr, &port_err->port_first_error); + } else + ret = -EBUSY; + + /* Clear mask */ + port_err_mask(port, false); + + /* Enable the Port by clear the reset */ + __fpga_port_enable(port); + + return ret; +} + +int port_clear_error(struct ifpga_port_hw *port) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + u64 port_error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + port_error = error.csr = readq(&port_err->port_error); + + dev_info(port, "read port error: 0x%lx\n", port_error); + + return port_err_clear(port, port_error); +} + +void fme_hw_uinit(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return; + + 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); + } +} + +int fme_hw_init(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i, ret; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + 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; + } + } + } + + return 0; +} + +void port_hw_uinit(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i; + + 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); + } +} + +int port_hw_init(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i, 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; + } + } + + return 0; +} + +/* + * FIXME: we should get msix vec count during pci enumeration instead of + * below hardcode value. + */ +#define FPGA_MSIX_VEC_COUNT 20 +/* irq set buffer length for interrupt */ +#define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \ + sizeof(int) * FPGA_MSIX_VEC_COUNT) + +/* only support msix for now*/ +static int vfio_msix_enable_block(s32 vfio_dev_fd, unsigned int vec_start, + unsigned int count, s32 *fds) +{ + char irq_set_buf[MSIX_IRQ_SET_BUF_LEN]; + struct vfio_irq_set *irq_set; + int len, ret; + int *fd_ptr; + + len = sizeof(irq_set_buf); + + irq_set = (struct vfio_irq_set *)irq_set_buf; + irq_set->argsz = len; + irq_set->count = count; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; + irq_set->start = vec_start; + + fd_ptr = (int *)&irq_set->data; + memcpy(fd_ptr, fds, sizeof(int) * count); + + ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set); + if (ret) + printf("Error enabling MSI-X interrupts\n"); + + return ret; +} + +int fpga_msix_set_block(struct feature *feature, unsigned int start, + unsigned int count, s32 *fds) +{ + struct feature_irq_ctx *ctx = feature->ctx; + unsigned int i; + int ret; + + if (start >= feature->ctx_num || start + count > feature->ctx_num) + return -EINVAL; + + /* assume that each feature has continuous vector space in msix*/ + ret = vfio_msix_enable_block(feature->vfio_dev_fd, + ctx[start].idx, count, fds); + if (!ret) { + for (i = 0; i < count; i++) + ctx[i].eventfd = fds[i]; + } + + return ret; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h new file mode 100644 index 0000000..1dc6eff --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -0,0 +1,197 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_FEATURE_DEV_H_ +#define _IFPGA_FEATURE_DEV_H_ + +#include "ifpga_hw.h" + +static inline struct ifpga_port_hw * +get_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return NULL; + + return &hw->port[port_id]; +} + +#define ifpga_for_each_feature(hw, feature) \ + for ((feature) = (hw)->sub_feature; \ + (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++) + +static inline struct feature * +get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(fme, feature) { + if (feature->id == id) + return feature; + } + + return NULL; +} + +static inline struct feature * +get_port_feature_by_id(struct ifpga_port_hw *port, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(port, feature) { + 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; +} + +static inline void * +get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index) +{ + return port->sub_feature[index].addr; +} + +static inline bool +is_fme_feature_present(struct ifpga_fme_hw *fme, int index) +{ + return !!get_fme_feature_ioaddr_by_index(fme, index); +} + +static inline bool +is_port_feature_present(struct ifpga_port_hw *port, int index) +{ + return !!get_port_feature_ioaddr_by_index(port, index); +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid); + +int __fpga_port_disable(struct ifpga_port_hw *port); +void __fpga_port_enable(struct ifpga_port_hw *port); + +static inline int fpga_port_disable(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_disable(port); + spinlock_unlock(&port->lock); + return ret; +} + +static inline int fpga_port_enable(struct ifpga_port_hw *port) +{ + spinlock_lock(&port->lock); + __fpga_port_enable(port); + spinlock_unlock(&port->lock); + + return 0; +} + +static inline int __fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + ret = __fpga_port_disable(port); + if (ret) + return ret; + + __fpga_port_enable(port); + + return 0; +} + +static inline int fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_reset(port); + spinlock_unlock(&port->lock); + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +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); +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set); + +int fme_hw_init(struct ifpga_fme_hw *fme); +void fme_hw_uinit(struct ifpga_fme_hw *fme); +void port_hw_uinit(struct ifpga_port_hw *port); +int port_hw_init(struct ifpga_port_hw *port); +int port_clear_error(struct ifpga_port_hw *port); +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; + +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); + +/* This struct is used when parsing uafu irq_set */ +struct fpga_uafu_irq_set { + u32 start; + u32 count; + s32 *evtfds; +}; + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set); + +extern struct feature_ops port_hdr_ops; +extern struct feature_ops port_error_ops; +extern struct feature_ops port_stp_ops; +extern struct feature_ops port_umsg_ops; +extern struct feature_ops port_uint_ops; + +int afu_port_umsg_enable(struct ifpga_port_hw *port, bool enable); +int afu_port_umsg_set_mode(struct ifpga_port_hw *port, u32 mode); + +/* help functions for feature ops */ +int fpga_msix_set_block(struct feature *feature, unsigned int start, + unsigned int count, s32 *fds); +void port_check_reg(void __iomem *addr, const char *reg_name, u64 dflt); + + +#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 new file mode 100644 index 0000000..ecfddfc --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -0,0 +1,763 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +#define PWR_THRESHOLD_MAX 0x7F + +int fme_get_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +/* fme private feature head */ +static int fme_hdr_init(struct feature *feature) +{ + struct feature_fme_header *fme_hdr; + + fme_hdr = (struct feature_fme_header *)feature->addr; + + dev_info(NULL, "FME HDR Init.\n"); + dev_info(NULL, "FME cap %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + return 0; +} + +static void fme_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME HDR UInit.\n"); +} + +static int fme_hdr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&fme_hdr->header); + *revision = header.revision; + + return 0; +} + +static int fme_hdr_get_ports_num(struct ifpga_fme_hw *fme, u64 *ports_num) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *ports_num = fme_capability.num_ports; + + return 0; +} + +static int fme_hdr_get_cache_size(struct ifpga_fme_hw *fme, u64 *cache_size) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *cache_size = fme_capability.cache_size; + + return 0; +} + +static int fme_hdr_get_version(struct ifpga_fme_hw *fme, u64 *version) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *version = fme_capability.fabric_verid; + + return 0; +} + +static int fme_hdr_get_socket_id(struct ifpga_fme_hw *fme, u64 *socket_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *socket_id = fme_capability.socket_id; + + return 0; +} + +static int fme_hdr_get_bitstream_id(struct ifpga_fme_hw *fme, + u64 *bitstream_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_id = readq(&fme_hdr->bitstream_id); + + return 0; +} + +static int fme_hdr_get_bitstream_metadata(struct ifpga_fme_hw *fme, + u64 *bitstream_metadata) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_metadata = readq(&fme_hdr->bitstream_md); + + return 0; +} + +static int +fme_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_HDR_PROP_REVISION: + return fme_hdr_get_revision(fme, &prop->data); + case FME_HDR_PROP_PORTS_NUM: + return fme_hdr_get_ports_num(fme, &prop->data); + case FME_HDR_PROP_CACHE_SIZE: + return fme_hdr_get_cache_size(fme, &prop->data); + case FME_HDR_PROP_VERSION: + return fme_hdr_get_version(fme, &prop->data); + case FME_HDR_PROP_SOCKET_ID: + return fme_hdr_get_socket_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_ID: + return fme_hdr_get_bitstream_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_METADATA: + return fme_hdr_get_bitstream_metadata(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_hdr_ops = { + .init = fme_hdr_init, + .uinit = fme_hdr_uinit, + .get_prop = fme_hdr_get_prop, +}; + +/* thermal management */ +static int fme_thermal_get_threshold1(struct ifpga_fme_hw *fme, u64 *thres1) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold temp_threshold; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&fme_thermal->threshold); + *thres1 = temp_threshold.tmp_thshold1; + + return 0; +} + +static int fme_thermal_set_threshold1(struct ifpga_fme_hw *fme, u64 thres1) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&fme_thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres1 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres1 == 0) { + tmp_threshold.tmp_thshold1_enable = 0; + tmp_threshold.tmp_thshold1 = thres1; + } else { + tmp_threshold.tmp_thshold1_enable = 1; + tmp_threshold.tmp_thshold1 = thres1; + } + + writeq(tmp_threshold.csr, &fme_thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold2(struct ifpga_fme_hw *fme, u64 *thres2) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold temp_threshold; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&fme_thermal->threshold); + *thres2 = temp_threshold.tmp_thshold2; + + return 0; +} + +static int fme_thermal_set_threshold2(struct ifpga_fme_hw *fme, u64 thres2) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&fme_thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres2 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres2 == 0) { + tmp_threshold.tmp_thshold2_enable = 0; + tmp_threshold.tmp_thshold2 = thres2; + } else { + tmp_threshold.tmp_thshold2_enable = 1; + tmp_threshold.tmp_thshold2 = thres2; + } + + writeq(tmp_threshold.csr, &fme_thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold_trip(struct ifpga_fme_hw *fme, + u64 *thres_trip) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold temp_threshold; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&fme_thermal->threshold); + *thres_trip = temp_threshold.therm_trip_thshold; + + return 0; +} + +static int fme_thermal_get_threshold1_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold temp_threshold; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&fme_thermal->threshold); + *thres1_reached = temp_threshold.thshold1_status; + + return 0; +} + +static int fme_thermal_get_threshold2_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold temp_threshold; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&fme_thermal->threshold); + *thres1_reached = temp_threshold.thshold2_status; + + return 0; +} + +static int fme_thermal_get_threshold1_policy(struct ifpga_fme_hw *fme, + u64 *thres1_policy) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold temp_threshold; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&fme_thermal->threshold); + *thres1_policy = temp_threshold.thshold_policy; + + return 0; +} + +static int fme_thermal_set_threshold1_policy(struct ifpga_fme_hw *fme, + u64 thres1_policy) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold tmp_threshold; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&fme_thermal->threshold); + + if (thres1_policy == 0) + tmp_threshold.thshold_policy = 0; + else if (thres1_policy == 1) + tmp_threshold.thshold_policy = 1; + else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(tmp_threshold.csr, &fme_thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_temperature(struct ifpga_fme_hw *fme, u64 *temp) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_temp_rdsensor_fmt1 temp_rdsensor_fmt1; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_rdsensor_fmt1.csr = readq(&fme_thermal->rdsensor_fm1); + *temp = temp_rdsensor_fmt1.fpga_temp; + + return 0; +} + +static int fme_thermal_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_thermal *fme_thermal + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + struct feature_header header; + + header.csr = readq(&fme_thermal->header); + *revision = header.revision; + + return 0; +} + +#define FME_THERMAL_CAP_NO_TMP_THRESHOLD 0x1 + +static int fme_thermal_mgmt_init(struct feature *feature) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold_cap thermal_cap; + + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt Init.\n"); + + fme_thermal = (struct feature_fme_thermal *)feature->addr; + thermal_cap.csr = readq(&fme_thermal->threshold_cap); + + dev_info(NULL, "FME thermal cap %llx.\n", + (unsigned long long)fme_thermal->threshold_cap.csr); + + if (thermal_cap.tmp_thshold_disabled) + feature->cap |= FME_THERMAL_CAP_NO_TMP_THRESHOLD; + + return 0; +} + +static void fme_thermal_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt UInit.\n"); +} + +static int +fme_thermal_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_set_threshold1(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_set_threshold2(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_set_threshold1_policy(fme, prop->data); + } + + return -ENOENT; +} + +static int +fme_thermal_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD && + prop->prop_id != FME_THERMAL_PROP_TEMPERATURE && + prop->prop_id != FME_THERMAL_PROP_REVISION) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_get_threshold1(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_get_threshold2(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD_TRIP: + return fme_thermal_get_threshold_trip(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_REACHED: + return fme_thermal_get_threshold1_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2_REACHED: + return fme_thermal_get_threshold2_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_get_threshold1_policy(fme, &prop->data); + case FME_THERMAL_PROP_TEMPERATURE: + return fme_thermal_get_temperature(fme, &prop->data); + case FME_THERMAL_PROP_REVISION: + return fme_thermal_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_thermal_mgmt_ops = { + .init = fme_thermal_mgmt_init, + .uinit = fme_thermal_mgmt_uinit, + .get_prop = fme_thermal_get_prop, + .set_prop = fme_thermal_set_prop, +}; + + +static int fme_pwr_get_consumed(struct ifpga_fme_hw *fme, u64 *consumed) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *consumed = pm_status.pwr_consumed; + + return 0; +} + +static int fme_pwr_get_threshold1(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold1; + + return 0; +} + +static int fme_pwr_set_threshold1(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) + pm_ap_threshold.threshold1 = threshold; + else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold2(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold2; + + return 0; +} + +static int fme_pwr_set_threshold2(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) + pm_ap_threshold.threshold2 = threshold; + else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold1_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold1_status; + + return 0; +} + +static int fme_pwr_get_threshold2_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold2_status; + + return 0; +} + +static int fme_pwr_get_rtl(struct ifpga_fme_hw *fme, u64 *rtl) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *rtl = pm_status.fpga_latency_report; + + return 0; +} + +static int fme_pwr_get_xeon_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_xeon_limit xeon_limit; + + xeon_limit.csr = readq(&fme_power->xeon_limit); + + if (!xeon_limit.enable) + xeon_limit.pwr_limit = 0; + + *limit = xeon_limit.pwr_limit; + + return 0; + +} + +static int fme_pwr_get_fpga_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_fpga_limit fpga_limit; + + fpga_limit.csr = readq(&fme_power->fpga_limit); + + if (!fpga_limit.enable) + fpga_limit.pwr_limit = 0; + + *limit = fpga_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_header header; + + header.csr = readq(&fme_power->header); + *revision = header.revision; + + return 0; +} + +static int fme_power_mgmt_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt Init.\n"); + + return 0; +} + +static void fme_power_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt UInit.\n"); +} + +static int fme_power_mgmt_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_CONSUMED: + return fme_pwr_get_consumed(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_get_threshold1(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_get_threshold2(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1_STATUS: + return fme_pwr_get_threshold1_status(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2_STATUS: + return fme_pwr_get_threshold2_status(fme, &prop->data); + case FME_PWR_PROP_RTL: + return fme_pwr_get_rtl(fme, &prop->data); + case FME_PWR_PROP_XEON_LIMIT: + return fme_pwr_get_xeon_limit(fme, &prop->data); + case FME_PWR_PROP_FPGA_LIMIT: + return fme_pwr_get_fpga_limit(fme, &prop->data); + case FME_PWR_PROP_REVISION: + return fme_pwr_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_power_mgmt_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_set_threshold1(fme, prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_set_threshold2(fme, prop->data); + } + + return -ENOENT; +} + +struct 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, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c new file mode 100644 index 0000000..dbbd564 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c @@ -0,0 +1,328 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_dperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_clk_ctr clk; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + clk.afu_interf_clock = readq(&dperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_dperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_dperf *dperf; + struct feature_header header; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + header.csr = readq(&dperf->header); + *revision = header.revision; + + return 0; +} + +#define DPERF_TIMEOUT 30 + +static bool fabric_pobj_is_enabled(int port_id, + struct feature_fme_dperf *dperf) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + + ctl.csr = readq(&dperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum dperf_fab_events fab_event) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dfpmon_fab_ctr ctr; + struct feature_fme_dperf *dperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, dperf)) + goto exit; + + ctl.csr = readq(&dperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &dperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &dperf->fab_ctr, DPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&dperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_dperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, DPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, DPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(mmio_read, DPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, DPERF_FAB_MMIO_WR); + +static int fme_dperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_dperf *dperf; + int status; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + status = fabric_pobj_is_enabled(port_id, dperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_dperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dperf *dperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, dperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&dperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) + ctl.port_filter = FAB_DISABLE_FILTER; + else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_dperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_dperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 + +static int fme_global_dperf_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf Init.\n"); + + return 0; +} + +static void fme_global_dperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf UInit.\n"); +} + +static int fme_dperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_dperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_dperf_get_fab_port_pcie0_read(fme, sub, &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_dperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* MMIO_READ */ + return fme_dperf_get_fab_port_mmio_read(fme, sub, &prop->data); + case 0x5: /* MMIO_WRITE */ + return fme_dperf_get_fab_port_mmio_write(fme, sub, &prop->data); + case 0x6: /* ENABLE */ + return fme_dperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_dperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_dperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_dperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_dperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_dperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE - fab root only prop */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_dperf_set_fab_freeze(fme, prop->data); + case 0x6: /* ENABLE - fab both root and sub */ + return fme_dperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_dperf_ops = { + .init = fme_global_dperf_init, + .uinit = fme_global_dperf_uinit, + .get_prop = fme_global_dperf_get_prop, + .set_prop = fme_global_dperf_set_prop, + +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c new file mode 100644 index 0000000..a8a6a3c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c @@ -0,0 +1,430 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +static int fme_err_get_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + + fme_error0.csr = readq(&fme_err->fme_err); + *val = fme_error0.csr; + + return 0; +} + +static int fme_err_get_first_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_first_error fme_first_err; + + fme_first_err.csr = readq(&fme_err->fme_first_err); + *val = fme_first_err.err_reg_status; + + return 0; +} + +static int fme_err_get_next_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_next_error fme_next_err; + + fme_next_err.csr = readq(&fme_err->fme_next_err); + *val = fme_next_err.err_reg_status; + + return 0; +} + +static int fme_err_set_clear(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_ERROR0_MASK, &fme_err->fme_err_mask); + + fme_error0.csr = readq(&fme_err->fme_err); + if (val != fme_error0.csr) { + ret = -EBUSY; + goto exit; + } + + fme_first_err.csr = readq(&fme_err->fme_first_err); + fme_next_err.csr = readq(&fme_err->fme_next_err); + + writeq(fme_error0.csr & FME_ERROR0_MASK, &fme_err->fme_err); + writeq(fme_first_err.csr & FME_FIRST_ERROR_MASK, + &fme_err->fme_first_err); + writeq(fme_next_err.csr & FME_NEXT_ERROR_MASK, + &fme_err->fme_next_err); + +exit: + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_revision(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_header header; + + header.csr = readq(&fme_err->header); + *val = header.revision; + + return 0; +} + +static int fme_err_get_pcie0_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + + pcie0_err.csr = readq(&fme_err->pcie0_err); + *val = pcie0_err.csr; + + return 0; +} + +static int fme_err_set_pcie0_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE0_ERROR_MASK, &fme_err->pcie0_err_mask); + + pcie0_err.csr = readq(&fme_err->pcie0_err); + if (val != pcie0_err.csr) + ret = -EBUSY; + else + writeq(pcie0_err.csr & FME_PCIE0_ERROR_MASK, + &fme_err->pcie0_err); + + writeq(0UL, &fme_err->pcie0_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_pcie1_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + + pcie1_err.csr = readq(&fme_err->pcie1_err); + *val = pcie1_err.csr; + + return 0; +} + +static int fme_err_set_pcie1_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE1_ERROR_MASK, &fme_err->pcie1_err_mask); + + pcie1_err.csr = readq(&fme_err->pcie1_err); + if (val != pcie1_err.csr) + ret = -EBUSY; + else + writeq(pcie1_err.csr & FME_PCIE1_ERROR_MASK, + &fme_err->pcie1_err); + + writeq(0UL, &fme_err->pcie1_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_nonfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_nonfaterror ras_nonfaterr; + + ras_nonfaterr.csr = readq(&fme_err->ras_nonfaterr); + *val = ras_nonfaterr.csr; + + return 0; +} + +static int fme_err_get_catfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_catfaterror ras_catfaterr; + + ras_catfaterr.csr = readq(&fme_err->ras_catfaterr); + *val = ras_catfaterr.csr; + + return 0; +} + +static int fme_err_get_inject_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + *val = ras_error_inj.csr & FME_RAS_ERROR_INJ_MASK; + + return 0; +} + +static int fme_err_set_inject_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + spinlock_lock(&fme->lock); + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + + if (val <= FME_RAS_ERROR_INJ_MASK) { + ras_error_inj.csr = val; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(ras_error_inj.csr, &fme_err->ras_error_inj); + spinlock_unlock(&fme->lock); + + return 0; +} + +static void fme_error_enable(struct ifpga_fme_hw *fme) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + writeq(0UL, &fme_err->pcie0_err_mask); + writeq(0UL, &fme_err->pcie1_err_mask); + writeq(0UL, &fme_err->ras_nonfat_mask); + writeq(0UL, &fme_err->ras_catfat_mask); +} + +static int fme_global_error_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = feature->parent; + + fme_error_enable(fme); + + if (feature->ctx_num) + fme->capability |= FPGA_FME_CAP_ERR_IRQ; + + return 0; +} + +static void fme_global_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int fme_err_fme_err_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* ERRORS */ + return fme_err_get_errors(fme, &prop->data); + case 0x2: /* FIRST_ERROR */ + return fme_err_get_first_error(fme, &prop->data); + case 0x3: /* NEXT_ERROR */ + return fme_err_get_next_error(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x5: /* REVISION */ + return fme_err_get_revision(fme, &prop->data); + case 0x6: /* PCIE0_ERRORS */ + return fme_err_get_pcie0_errors(fme, &prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_get_pcie1_errors(fme, &prop->data); + case 0x8: /* NONFATAL_ERRORS */ + return fme_err_get_nonfatal_errors(fme, &prop->data); + case 0x9: /* CATFATAL_ERRORS */ + return fme_err_get_catfatal_errors(fme, &prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_get_inject_errors(fme, &prop->data); + case 0xb: /* REVISION*/ + return fme_err_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_get_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_err_fme_err_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x4: /* CLEAR */ + return fme_err_set_clear(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x6: /* PCIE0_ERRORS */ + return fme_err_set_pcie0_errors(fme, prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_set_pcie1_errors(fme, prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_set_inject_errors(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_set_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_set_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_global_err_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_fme_err_irq_set *err_irq_set = + (struct fpga_fme_err_irq_set *)irq_set; + struct ifpga_fme_hw *fme; + int ret; + + fme = (struct ifpga_fme_hw *)feature->parent; + + spinlock_lock(&fme->lock); + if (!(fme->capability & FPGA_FME_CAP_ERR_IRQ)) { + spinlock_unlock(&fme->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&fme->lock); + + return ret; +} + +struct feature_ops fme_global_err_ops = { + .init = fme_global_error_init, + .uinit = fme_global_error_uinit, + .get_prop = fme_global_error_get_prop, + .set_prop = fme_global_error_set_prop, + .set_irq = fme_global_err_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c new file mode 100644 index 0000000..33c3598 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c @@ -0,0 +1,742 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_iperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_clk_ctr clk; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + clk.afu_interf_clock = readq(&iperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_iperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_iperf *iperf; + struct feature_header header; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + header.csr = readq(&iperf->header); + *revision = header.revision; + + return 0; +} + +static int fme_iperf_get_cache_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + *freeze = (u64)ctl.freeze; + return 0; +} + +static int fme_iperf_set_cache_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->ch_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define IPERF_TIMEOUT 30 + +static u64 read_cache_counter(struct ifpga_fme_hw *fme, + u8 channel, enum iperf_cache_events event) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + struct feature_fme_ifpmon_ch_ctr ctr0, ctr1; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* set channel access type and cache event code. */ + ctl.csr = readq(&iperf->ch_ctl); + ctl.cci_chsel = channel; + ctl.cache_event = event; + writeq(ctl.csr, &iperf->ch_ctl); + + /* check the event type in the counter registers */ + ctr0.event_code = event; + + if (fpga_wait_register_field(event_code, ctr0, + &iperf->ch_ctr0, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched cache event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr0.csr = readq(&iperf->ch_ctr0); + ctr1.csr = readq(&iperf->ch_ctr1); + counter = ctr0.cache_counter + ctr1.cache_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define CACHE_SHOW(name, type, event) \ +static int fme_iperf_get_cache_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_cache_counter(fme, type, event); \ + return 0; \ +} + +CACHE_SHOW(read_hit, CACHE_CHANNEL_RD, IPERF_CACHE_RD_HIT); +CACHE_SHOW(read_miss, CACHE_CHANNEL_RD, IPERF_CACHE_RD_MISS); +CACHE_SHOW(write_hit, CACHE_CHANNEL_WR, IPERF_CACHE_WR_HIT); +CACHE_SHOW(write_miss, CACHE_CHANNEL_WR, IPERF_CACHE_WR_MISS); +CACHE_SHOW(hold_request, CACHE_CHANNEL_RD, IPERF_CACHE_HOLD_REQ); +CACHE_SHOW(tx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_TX_REQ_STALL); +CACHE_SHOW(rx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_RX_REQ_STALL); +CACHE_SHOW(rx_eviction, CACHE_CHANNEL_RD, IPERF_CACHE_EVICTIONS); +CACHE_SHOW(data_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_DATA_WR_PORT_CONTEN); +CACHE_SHOW(tag_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_TAG_WR_PORT_CONTEN); + +static int fme_iperf_get_vtd_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_vtd_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->vtd_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static u64 read_iommu_sip_counter(struct ifpga_fme_hw *fme, + enum iperf_vtd_sip_events event) +{ + struct feature_fme_ifpmon_vtd_sip_ctl sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr sip_ctr; + struct feature_fme_iperf *iperf; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + sip_ctl.csr = readq(&iperf->vtd_sip_ctl); + sip_ctl.vtd_evtcode = event; + writeq(sip_ctl.csr, &iperf->vtd_sip_ctl); + + sip_ctr.event_code = event; + + if (fpga_wait_register_field(event_code, sip_ctr, + &iperf->vtd_sip_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd SIP event type in counter registers\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + sip_ctr.csr = readq(&iperf->vtd_sip_ctr); + counter = sip_ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_SIP_SHOW(name, event) \ +static int fme_iperf_get_vtd_sip_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_iommu_sip_counter(fme, event); \ + return 0; \ +} + +VTD_SIP_SHOW(iotlb_4k_hit, IPERF_VTD_SIP_IOTLB_4K_HIT); +VTD_SIP_SHOW(iotlb_2m_hit, IPERF_VTD_SIP_IOTLB_2M_HIT); +VTD_SIP_SHOW(iotlb_1g_hit, IPERF_VTD_SIP_IOTLB_1G_HIT); +VTD_SIP_SHOW(slpwc_l3_hit, IPERF_VTD_SIP_SLPWC_L3_HIT); +VTD_SIP_SHOW(slpwc_l4_hit, IPERF_VTD_SIP_SLPWC_L4_HIT); +VTD_SIP_SHOW(rcc_hit, IPERF_VTD_SIP_RCC_HIT); +VTD_SIP_SHOW(iotlb_4k_miss, IPERF_VTD_SIP_IOTLB_4K_MISS); +VTD_SIP_SHOW(iotlb_2m_miss, IPERF_VTD_SIP_IOTLB_2M_MISS); +VTD_SIP_SHOW(iotlb_1g_miss, IPERF_VTD_SIP_IOTLB_1G_MISS); +VTD_SIP_SHOW(slpwc_l3_miss, IPERF_VTD_SIP_SLPWC_L3_MISS); +VTD_SIP_SHOW(slpwc_l4_miss, IPERF_VTD_SIP_SLPWC_L4_MISS); +VTD_SIP_SHOW(rcc_miss, IPERF_VTD_SIP_RCC_MISS); + +static u64 read_iommu_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_vtd_events base_event) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_ifpmon_vtd_ctr ctr; + struct feature_fme_iperf *iperf; + enum iperf_vtd_events event = base_event + port_id; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.vtd_evtcode = event; + writeq(ctl.csr, &iperf->vtd_ctl); + + ctr.event_code = event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->vtd_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->vtd_ctr); + counter = ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_PORT_SHOW(name, base_event) \ +static int fme_iperf_get_vtd_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_iommu_counter(fme, port_id, base_event); \ + return 0; \ +} + +VTD_PORT_SHOW(read_transaction, IPERF_VTD_AFU_MEM_RD_TRANS); +VTD_PORT_SHOW(write_transaction, IPERF_VTD_AFU_MEM_WR_TRANS); +VTD_PORT_SHOW(devtlb_read_hit, IPERF_VTD_AFU_DEVTLB_RD_HIT); +VTD_PORT_SHOW(devtlb_write_hit, IPERF_VTD_AFU_DEVTLB_WR_HIT); +VTD_PORT_SHOW(devtlb_4k_fill, IPERF_VTD_DEVTLB_4K_FILL); +VTD_PORT_SHOW(devtlb_2m_fill, IPERF_VTD_DEVTLB_2M_FILL); +VTD_PORT_SHOW(devtlb_1g_fill, IPERF_VTD_DEVTLB_1G_FILL); + +static bool fabric_pobj_is_enabled(u8 port_id, struct feature_fme_iperf *iperf) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + + ctl.csr = readq(&iperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_fab_events fab_event) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_ifpmon_fab_ctr ctr; + struct feature_fme_iperf *iperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, iperf)) + goto exit; + + ctl.csr = readq(&iperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &iperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->fab_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_iperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, IPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, IPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(pcie1_read, IPERF_FAB_PCIE1_RD); +FAB_PORT_SHOW(pcie1_write, IPERF_FAB_PCIE1_WR); +FAB_PORT_SHOW(upi_read, IPERF_FAB_UPI_RD); +FAB_PORT_SHOW(upi_write, IPERF_FAB_UPI_WR); +FAB_PORT_SHOW(mmio_read, IPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, IPERF_FAB_MMIO_WR); + +static int fme_iperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_iperf *iperf; + int status; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + status = fabric_pobj_is_enabled(port_id, iperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_iperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, iperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&iperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) + ctl.port_filter = FAB_DISABLE_FILTER; + else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_iperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 +#define FME_IPERF_CAP_IOMMU 0x1 + +static int fme_global_iperf_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme; + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + + dev_info(NULL, "FME global_iperf Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + /* check if iommu is not supported on this device. */ + fme_capability.csr = readq(&fme_hdr->capability); + dev_info(NULL, "FME HEAD fme_capability %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + if (fme_capability.iommu_support) + feature->cap |= FME_IPERF_CAP_IOMMU; + + return 0; +} + +static void fme_global_iperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_iperf UInit.\n"); +} + +static int fme_iperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_iperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_iperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_cache_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_cache_freeze(fme, &prop->data); + case 0x2: /* READ_HIT */ + return fme_iperf_get_cache_read_hit(fme, &prop->data); + case 0x3: /* READ_MISS */ + return fme_iperf_get_cache_read_miss(fme, &prop->data); + case 0x4: /* WRITE_HIT */ + return fme_iperf_get_cache_write_hit(fme, &prop->data); + case 0x5: /* WRITE_MISS */ + return fme_iperf_get_cache_write_miss(fme, &prop->data); + case 0x6: /* HOLD_REQUEST */ + return fme_iperf_get_cache_hold_request(fme, &prop->data); + case 0x7: /* TX_REQ_STALL */ + return fme_iperf_get_cache_tx_req_stall(fme, &prop->data); + case 0x8: /* RX_REQ_STALL */ + return fme_iperf_get_cache_rx_req_stall(fme, &prop->data); + case 0x9: /* RX_EVICTION */ + return fme_iperf_get_cache_rx_eviction(fme, &prop->data); + case 0xa: /* DATA_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_data_write_port_contention(fme, + &prop->data); + case 0xb: /* TAG_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_tag_write_port_contention(fme, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_vtd_freeze(fme, &prop->data); + case 0x2: /* IOTLB_4K_HIT */ + return fme_iperf_get_vtd_sip_iotlb_4k_hit(fme, &prop->data); + case 0x3: /* IOTLB_2M_HIT */ + return fme_iperf_get_vtd_sip_iotlb_2m_hit(fme, &prop->data); + case 0x4: /* IOTLB_1G_HIT */ + return fme_iperf_get_vtd_sip_iotlb_1g_hit(fme, &prop->data); + case 0x5: /* SLPWC_L3_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l3_hit(fme, &prop->data); + case 0x6: /* SLPWC_L4_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l4_hit(fme, &prop->data); + case 0x7: /* RCC_HIT */ + return fme_iperf_get_vtd_sip_rcc_hit(fme, &prop->data); + case 0x8: /* IOTLB_4K_MISS */ + return fme_iperf_get_vtd_sip_iotlb_4k_miss(fme, &prop->data); + case 0x9: /* IOTLB_2M_MISS */ + return fme_iperf_get_vtd_sip_iotlb_2m_miss(fme, &prop->data); + case 0xa: /* IOTLB_1G_MISS */ + return fme_iperf_get_vtd_sip_iotlb_1g_miss(fme, &prop->data); + case 0xb: /* SLPWC_L3_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l3_miss(fme, &prop->data); + case 0xc: /* SLPWC_L4_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l4_miss(fme, &prop->data); + case 0xd: /* RCC_MISS */ + return fme_iperf_get_vtd_sip_rcc_miss(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_sub_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub > PERF_MAX_PORT_NUM) + return -ENOENT; + + switch (id) { + case 0xe: /* READ_TRANSACTION */ + return fme_iperf_get_vtd_port_read_transaction(fme, sub, + &prop->data); + case 0xf: /* WRITE_TRANSACTION */ + return fme_iperf_get_vtd_port_write_transaction(fme, sub, + &prop->data); + case 0x10: /* DEVTLB_READ_HIT */ + return fme_iperf_get_vtd_port_devtlb_read_hit(fme, sub, + &prop->data); + case 0x11: /* DEVTLB_WRITE_HIT */ + return fme_iperf_get_vtd_port_devtlb_write_hit(fme, sub, + &prop->data); + case 0x12: /* DEVTLB_4K_FILL */ + return fme_iperf_get_vtd_port_devtlb_4k_fill(fme, sub, + &prop->data); + case 0x13: /* DEVTLB_2M_FILL */ + return fme_iperf_get_vtd_port_devtlb_2m_fill(fme, sub, + &prop->data); + case 0x14: /* DEVTLB_1G_FILL */ + return fme_iperf_get_vtd_port_devtlb_1g_fill(fme, sub, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED) + return fme_iperf_vtd_root_get_prop(feature, prop); + + return fme_iperf_vtd_sub_get_prop(feature, prop); +} + +static int fme_iperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + /* Other properties are present for both top and sub levels */ + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_iperf_get_fab_port_pcie0_read(fme, sub, + &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_iperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* PCIE1_READ */ + return fme_iperf_get_fab_port_pcie1_read(fme, sub, + &prop->data); + case 0x5: /* PCIE1_WRITE */ + return fme_iperf_get_fab_port_pcie1_write(fme, sub, + &prop->data); + case 0x6: /* UPI_READ */ + return fme_iperf_get_fab_port_upi_read(fme, sub, + &prop->data); + case 0x7: /* UPI_WRITE */ + return fme_iperf_get_fab_port_upi_write(fme, sub, + &prop->data); + case 0x8: /* MMIO_READ */ + return fme_iperf_get_fab_port_mmio_read(fme, sub, + &prop->data); + case 0x9: /* MMIO_WRITE */ + return fme_iperf_get_fab_port_mmio_write(fme, sub, + &prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_get_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_get_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_iperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_iperf_cache_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_cache_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_vtd_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_vtd_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_set_fab_freeze(fme, prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_set_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_set_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_iperf_ops = { + .init = fme_global_iperf_init, + .uinit = fme_global_iperf_uinit, + .get_prop = fme_global_iperf_get_prop, + .set_prop = fme_global_iperf_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c new file mode 100644 index 0000000..fec6013 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c @@ -0,0 +1,395 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +//#if defined(RTE_ARCH_X86) && defined(RTE_MACHINE_CPUFLAG_AVX512F) +#if 1 +static inline void copy512(const void *src, void *dst) +{ + asm volatile("vmovdqu64 (%0), %%zmm0;" + "vmovntdq %%zmm0, (%1);" + : + : "r"(src), "r"(dst)); +} +#else +static inline void copy512(void *src, void *dst) +{ + WARN_ON(1); +} +#endif + +static u64 +pr_err_handle(struct feature_fme_pr *fme_pr) +{ + struct feature_fme_pr_status fme_pr_status; + unsigned long err_code; + u64 fme_pr_error; +#if 0 + int i = 0; +#endif + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + if (!fme_pr_status.pr_status) + return 0; + + err_code = readq(&fme_pr->ccip_fme_pr_err); + fme_pr_error = err_code; +#if 0 + for_each_set_bit(i, &err_code, PR_MAX_ERR_NUM) + dev_info(NULL, "%s\n", pr_err_msg[i]); +#endif + writeq(fme_pr_error, &fme_pr->ccip_fme_pr_err); + return fme_pr_error; +} + +static int fme_pr_write_init(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + if (info->flags != FPGA_MGR_PARTIAL_RECONFIG) + return -EINVAL; + + dev_info(fme_dev, "resetting PR before initiated PR\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + fme_pr_ctl.pr_reset_ack = 1; + + if (fpga_wait_register_field(pr_reset_ack, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 0; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "waiting for PR resource in HW to be initialized and ready\n"); + + fme_pr_status.pr_host_status = PR_HOST_STATUS_IDLE; + + if (fpga_wait_register_field(pr_host_status, fme_pr_status, + &fme_pr->ccip_fme_pr_status, PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "check if have any previous PR error\n"); + pr_err_handle(fme_pr); + return 0; +} + +static int fme_pr_write(struct ifpga_fme_hw *fme_dev, + int port_id, const char *buf, size_t count, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + struct feature_fme_pr_data fme_pr_data; + int delay, pr_credit; + int ret = 0; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + dev_info(fme_dev, "set PR port ID and start request\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_regionid = port_id; + fme_pr_ctl.pr_start_req = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "pushing data from bitstream to HW\n"); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + + while (count > 0) { + delay = 0; + while (pr_credit <= 1) { + if (delay++ > PR_WAIT_TIMEOUT) { + dev_err(fme_dev, "maximum try\n"); + + info->pr_err = pr_err_handle(fme_pr); + return info->pr_err ? -EIO : -ETIMEDOUT; + } + udelay(1); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + }; + + if (count >= fme_dev->pr_bandwidth) { + switch (fme_dev->pr_bandwidth) { + case 4: + fme_pr_data.rsvd = 0; + fme_pr_data.pr_data_raw = *((const u32 *)buf); + writeq(fme_pr_data.csr, + &fme_pr->ccip_fme_pr_data); + break; + case 64: + copy512(buf, &fme_pr->fme_pr_data1); + break; + default: + ret = -EFAULT; + goto done; + } + + buf += fme_dev->pr_bandwidth; + count -= fme_dev->pr_bandwidth; + pr_credit--; + } else { + WARN_ON(1); + return -EINVAL; + goto done; + } + } + +done: + return ret; +} + +static int fme_pr_write_complete(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_push_complete = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "green bitstream push complete\n"); + dev_info(fme_dev, "waiting for HW to release PR resource\n"); + + fme_pr_ctl.pr_start_req = 0; + + if (fpga_wait_register_field(pr_start_req, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, PR_WAIT_TIMEOUT, 1)) { + printf("maximum try.\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "PR operation complete, checking status\n"); + info->pr_err = pr_err_handle(fme_pr); + if (info->pr_err) + return -EIO; + + dev_info(fme_dev, "PR done successfully\n"); + return 0; +} + +static int fpga_pr_buf_load(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info, const char *buf, + size_t count) +{ + int ret; + + info->state = FPGA_PR_STATE_WRITE_INIT; + ret = fme_pr_write_init(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error preparing FPGA for writing\n"); + info->state = FPGA_PR_STATE_WRITE_INIT_ERR; + return ret; + } + + /* + * Write the FPGA image to the FPGA. + */ + info->state = FPGA_PR_STATE_WRITE; + ret = fme_pr_write(fme_dev, info->port_id, buf, count, info); + if (ret) { + dev_err(fme_dev, "Error while writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_ERR; + return ret; + } + + /* + * After all the FPGA image has been written, do the device specific + * steps to finish and set the FPGA into operating mode. + */ + info->state = FPGA_PR_STATE_WRITE_COMPLETE; + ret = fme_pr_write_complete(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error after writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_COMPLETE_ERR; + return ret; + } + info->state = FPGA_PR_STATE_DONE; + + return 0; +} + +static int fme_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + struct ifpga_fme_hw *fme = &hw->fme; + struct fpga_pr_info info; + struct ifpga_port_hw *port; + int ret = 0; + + if (!buffer || size == 0) + return -EINVAL; + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + /* + * Padding extra zeros to align PR buffer with PR bandwidth, HW will + * ignore these zeros automatically. + */ + size = ALIGN(size, fme->pr_bandwidth); + + /* get fme header region */ + fme_hdr = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_HEADER); + if (!fme_hdr) + return -EINVAL; + + /* check port id */ + fme_capability.csr = readq(&fme_hdr->capability); + if (port_id >= fme_capability.num_ports) { + dev_err(fme, "port number more than maximum\n"); + return -EINVAL; + } + + memset(&info, 0, sizeof(struct fpga_pr_info)); + info.flags = FPGA_MGR_PARTIAL_RECONFIG; + info.port_id = port_id; + + spinlock_lock(&fme->lock); + + /* get port device by port_id */ + port = &hw->port[port_id]; + + /* Disable Port before PR */ + fpga_port_disable(port); + + ret = fpga_pr_buf_load(fme, &info, (void *)buffer, size); + + *status = info.pr_err; + + /* Re-enable Port after PR finished */ + fpga_port_enable(port); + spinlock_unlock(&fme->lock); + + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, u64 *status) +{ + struct bts_header *bts_hdr; + void *buf; + struct ifpga_port_hw *port; + int ret; + + if (!buffer || size == 0) { + dev_err(hw, "invalid parameter\n"); + return -EINVAL; + } + + bts_hdr = (struct bts_header *)buffer; + + if (is_valid_bts(bts_hdr)) { + dev_info(hw, "this is a valid bitsteam..\n"); + size -= (sizeof(struct bts_header) + + bts_hdr->metadata_len); + buf = (u8 *)buffer + sizeof(struct bts_header) + + bts_hdr->metadata_len; + } else { + return -EINVAL; + } + + /* clean port error before do PR */ + port = &hw->port[port_id]; + ret = port_clear_error(port); + if (ret) { + dev_err(hw, "port cannot clear error\n"); + return -EINVAL; + } + + return fme_pr(hw, port_id, buf, size, status); +} + +static int fme_pr_mgmt_init(struct feature *feature) +{ + struct feature_fme_pr *fme_pr; + struct feature_header fme_pr_header; + struct ifpga_fme_hw *fme; + + dev_info(NULL, "FME PR MGMT Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + + fme_pr = (struct feature_fme_pr *)feature->addr; + + fme_pr_header.csr = readq(&fme_pr->header); + if (fme_pr_header.revision == 2) { + dev_info(NULL, "using 512-bit PR\n"); + fme->pr_bandwidth = 64; + } else { + dev_info(NULL, "using 32-bit PR\n"); + fme->pr_bandwidth = 4; + } + + return 0; +} + +static void fme_pr_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME PR MGMT UInit.\n"); +} + +struct 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 new file mode 100644 index 0000000..5be615c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -0,0 +1,152 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_HW_H_ +#define _IFPGA_HW_H_ + +#include "ifpga_defines.h" +#include "opae_ifpga_hw_api.h" + +enum ifpga_feature_state { + IFPGA_FEATURE_UNUSED = 0, + IFPGA_FEATURE_ATTACHED, +}; + +struct feature_irq_ctx { + int eventfd; + int idx; +}; + +struct feature { + enum ifpga_feature_state state; + const char *name; + u64 id; + u8 *addr; + uint64_t phys_addr; + u32 size; + int revision; + u64 cap; + int vfio_dev_fd; + struct feature_irq_ctx *ctx; + unsigned int ctx_num; + + void *parent; /* to parent hw data structure */ + + struct feature_ops *ops;/* callback to this private feature */ +}; + +struct feature_ops { + int (*init)(struct feature *feature); + void (*uinit)(struct feature *feature); + int (*test)(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); +}; + +enum ifpga_fme_state { + IFPGA_FME_UNUSED = 0, + IFPGA_FME_IMPLEMENTED, +}; + +struct ifpga_fme_hw { + enum ifpga_fme_state state; + + struct feature sub_feature[FME_FEATURE_ID_MAX]; + spinlock_t lock; /* protect hardware access */ + + void *parent; /* pointer to ifpga_hw */ + + /* provied by HEADER feature */ + u32 port_num; + struct uuid bitstream_id; + u64 bitstream_md; + size_t pr_bandwidth; + u32 socket_id; + u32 fabric_version_id; + u32 cache_size; + + u32 capability; +}; + +enum ifpga_port_state { + IFPGA_PORT_UNUSED = 0, + IFPGA_PORT_ATTACHED, + IFPGA_PORT_DETACHED, +}; + +struct ifpga_port_hw { + enum ifpga_port_state state; + + struct feature sub_feature[PORT_FEATURE_ID_MAX]; + spinlock_t lock; /* protect access to hw */ + + void *parent; /* pointer to ifpga_hw */ + + int port_id; /* provied by HEADER feature */ + struct uuid afu_id; /* provied by User AFU feature */ + + unsigned int disable_count; + + u32 capability; + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ +}; + +#define AFU_MAX_REGION 1 + +struct ifpga_afu_info { + struct opae_reg_region region[AFU_MAX_REGION]; + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct ifpga_hw { + struct opae_adapter *adapter; + struct opae_adapter_data_pci *pci_data; + + struct ifpga_fme_hw fme; + struct ifpga_port_hw port[MAX_FPGA_PORT_NUM]; +}; + +static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) +{ + return hw->fme.state != IFPGA_FME_UNUSED; +} + +static inline bool is_valid_port_id(struct ifpga_hw *hw, u32 port_id) +{ + if (port_id >= MAX_FPGA_PORT_NUM || + (hw->port[port_id].state != IFPGA_PORT_ATTACHED)) + return false; + return true; +} +#endif /* _IFPGA_HW_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c new file mode 100644 index 0000000..bf2e248 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c @@ -0,0 +1,730 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + + +void port_check_reg(void __iomem *addr, + const char *reg_name, u64 dflt) +{ + u64 value = readq(addr); + + UNUSED(reg_name); + + if (value != dflt) + dev_debug(NULL, "%s: incorrect value 0x%llx vs defautl 0x%llx\n", + reg_name, (unsigned long long)value, + (unsigned long long)dflt); +} + +static int port_get_revision(struct ifpga_port_hw *port, u64 *revision) +{ + struct feature_port_header *port_hdr + = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&port_hdr->header); + + *revision = header.revision; + + return 0; +} + +static int port_get_portidx(struct ifpga_port_hw *port, u64 *idx) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + capability.csr = readq(&port_hdr->capability); + *idx = capability.port_number; + + return 0; +} + +static int port_get_latency_tolerance(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + control.csr = readq(&port_hdr->control); + *val = control.latency_tolerance; + + return 0; +} + +static int port_get_ap1_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap1_event; + + return 0; +} + +static int port_set_ap1_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap1_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_ap2_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap2_event; + + return 0; +} + +static int port_set_ap2_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap2_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_power_state(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.power_state; + + return 0; +} + +static int port_get_userclk_freqcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts1); + spinlock_unlock(&port->lock); + + return 0; +} + +static struct feature_port_header hdr_dflt = { + .port_mailbox = 0x0000000000000000, + .scratchpad = 0x0000000000000000, + .capability = { + .csr = 0x0000000100010000, + }, + .control = { + /* Port Reset Bit is cleared in PCIe driver */ + .csr = 0x0000000000000004, + }, + .status = { + .csr = 0x0000000000000000, + }, + .rsvd2 = 0x0000000000000000, + .user_clk_freq_cmd0 = 0x0000000000000000, + .user_clk_freq_cmd1 = 0x0000000000000000, + .user_clk_freq_sts0 = 0x0000000000000000, + .user_clk_freq_sts1 = 0x0000000000000000, +}; + +static int port_hdr_test(struct feature *feature) +{ + struct feature_port_header *port_hdr = + (struct feature_port_header *)feature->addr; + + /* Check if default value of hardware registers matches with spec */ + port_check_reg(&port_hdr->port_mailbox, + "hdr:port_mailbox", hdr_dflt.port_mailbox); + port_check_reg(&port_hdr->scratchpad, + "hdr:scratchpad", hdr_dflt.scratchpad); + port_check_reg(&port_hdr->capability, + "hdr:capability", hdr_dflt.capability.csr); + port_check_reg(&port_hdr->control, + "hdr:control", hdr_dflt.control.csr); + port_check_reg(&port_hdr->status, + "hdr:status", hdr_dflt.status.csr); + port_check_reg(&port_hdr->rsvd2, + "hdr:rsvd2", hdr_dflt.rsvd2); + port_check_reg(&port_hdr->user_clk_freq_cmd0, + "hdr:user_clk_cmd0", hdr_dflt.user_clk_freq_cmd0); + port_check_reg(&port_hdr->user_clk_freq_cmd1, + "hdr:user_clk_cmd1", hdr_dflt.user_clk_freq_cmd1); + port_check_reg(&port_hdr->user_clk_freq_sts0, + "hdr:user_clk_sts0", hdr_dflt.user_clk_freq_sts0); + port_check_reg(&port_hdr->user_clk_freq_sts1, + "hdr:user_clk_sts1", hdr_dflt.user_clk_freq_sts1); + + dev_debug(NULL, "%s finished\n", __func__); + + return 0; +} + +static int port_hdr_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port hdr Init.\n"); + + fpga_port_reset(port); + + return 0; +} + +static void port_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port hdr uinit.\n"); +} + +static int port_hdr_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_REVISION: + return port_get_revision(port, &prop->data); + case PORT_HDR_PROP_PORTIDX: + return port_get_portidx(port, &prop->data); + case PORT_HDR_PROP_LATENCY_TOLERANCE: + return port_get_latency_tolerance(port, &prop->data); + case PORT_HDR_PROP_AP1_EVENT: + return port_get_ap1_event(port, &prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_get_ap2_event(port, &prop->data); + case PORT_HDR_PROP_POWER_STATE: + return port_get_power_state(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_get_userclk_freqcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_get_userclk_freqcntrcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQSTS: + return port_get_userclk_freqsts(port, &prop->data); + case PORT_HDR_PROP_USERCLK_CNTRSTS: + return port_get_userclk_freqcntrsts(port, &prop->data); + } + + return -ENOENT; +} + +static int port_hdr_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_AP1_EVENT: + return port_set_ap1_event(port, prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_set_ap2_event(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_set_userclk_freqcmd(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_set_userclk_freqcntrcmd(port, prop->data); + } + + return -ENOENT; +} + +struct feature_ops port_hdr_ops = { + .init = port_hdr_init, + .uinit = port_hdr_uinit, + .test = port_hdr_test, + .get_prop = port_hdr_get_prop, + .set_prop = port_hdr_set_prop, +}; + +static struct feature_port_umsg umsg_dflt = { + .capability = { + .csr = 0x0000000000000008, + }, + .baseaddr = { + .csr = 0x0000000000000000, + }, + .mode = { + .csr = 0x0000000000000000, + }, +}; + +static int port_umsg_test(struct feature *feature) +{ + struct feature_port_umsg *port_umsg = + (struct feature_port_umsg *)feature->addr; + + port_check_reg(&port_umsg->capability, + "umsg:capaiblity", umsg_dflt.capability.csr); + port_check_reg(&port_umsg->baseaddr, + "umsg:baseaddr", umsg_dflt.baseaddr.csr); + port_check_reg(&port_umsg->mode, + "umsg:mode", umsg_dflt.mode.csr); + + dev_debug(NULL, "%s finished\n", __func__); + return 0; +} + +static u8 port_umsg_get_num(struct ifpga_port_hw *port) +{ + struct feature_port_umsg *port_umsg; + struct feature_port_umsg_cap capability; + + port_umsg = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_UMSG); + + capability.csr = readq(&port_umsg->capability); + + return capability.umsg_allocated; +} + +static u64 port_umsg_get_addr(struct ifpga_port_hw *port) +{ + struct feature_port_umsg *port_umsg; + struct feature_port_umsg_baseaddr baseaddr; + + port_umsg = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_UMSG); + + baseaddr.csr = readq(&port_umsg->baseaddr); + + return baseaddr.base_addr; +} + +static int port_umsg_enable(struct ifpga_port_hw *port, bool enable) +{ + struct feature_port_umsg *port_umsg; + struct feature_port_umsg_cap capability; + + port_umsg = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_UMSG); + + capability.csr = readq(&port_umsg->capability); + + /* Return directly if UMSG is already enabled/disabled */ + if ((enable && capability.umsg_enable) || + !(enable || capability.umsg_enable)) + return 0; + + capability.umsg_enable = enable; + writeq(capability.csr, &port_umsg->capability); + + /* + * Each time umsg engine enabled/disabled, driver polls the + * init_complete bit for confirmation. + */ + capability.umsg_init_complete = !!enable; + + if (fpga_wait_register_field(umsg_init_complete, capability, + &port_umsg->capability, + UMSG_EN_POLL_TIMEOUT, UMSG_EN_POLL_INVL)) { + dev_err(dev, "timeout, fail to %s umsg\n", + enable ? "enable" : "disable"); + return -ETIMEDOUT; + } + + return 0; +} + +static bool port_umsg_is_enabled(struct ifpga_port_hw *port) +{ + struct feature_port_umsg *port_umsg; + struct feature_port_umsg_cap capability; + + port_umsg = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_UMSG); + + capability.csr = readq(&port_umsg->capability); + + return capability.umsg_enable; +} + +static void port_umsg_set_mode(struct ifpga_port_hw *port, u32 mode) +{ + struct feature_port_umsg *port_umsg; + struct feature_port_umsg_mode umode; + + port_umsg = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_UMSG); + + umode.csr = readq(&port_umsg->mode); + umode.umsg_hint_enable = mode; + writeq(umode.csr, &port_umsg->mode); +} + +static void port_umsg_set_addr(struct ifpga_port_hw *port, u64 iova) +{ + struct feature_port_umsg *port_umsg; + struct feature_port_umsg_baseaddr baseaddr; + + port_umsg = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_UMSG); + + baseaddr.csr = readq(&port_umsg->baseaddr); + baseaddr.base_addr = iova; + writeq(baseaddr.csr, &port_umsg->baseaddr); +} + +int afu_port_umsg_enable(struct ifpga_port_hw *port, bool enable) +{ + if (enable && port_umsg_get_addr(port)) + return -EIO; + if (port_umsg_enable(port, enable)) + return -ENODEV; + + return 0; +} + +int afu_port_umsg_set_mode(struct ifpga_port_hw *port, u32 mode) +{ + u8 num_umsgs = port_umsg_get_num(port); + + if (mode >> num_umsgs) { + dev_err(port, "invaild UMsg config hint_bitmap\n"); + return -EINVAL; + } + + port_umsg_set_mode(port, mode); + + return 0; +} + +static int __maybe_unused afu_port_umsg_set_addr(struct ifpga_port_hw *port, + u64 iova) +{ + u8 num_umsgs = port_umsg_get_num(port); + u64 size = num_umsgs * PAGE_SIZE; + + /* Make sure base addr is configured only when umsg is disabled */ + if (port_umsg_is_enabled(port)) { + dev_err(port, "umsg is still enabled\n"); + return -EIO; + } + + if (iova) { + /* Check input, only accept page-aligned region for umsg */ + if (!PAGE_ALIGNED(iova)) + return -EINVAL; + + /* Check overflow */ + if (iova + size < iova) + return -EINVAL; + + port_umsg_set_addr(port, iova); + } else { + /* Read current iova from hardware */ + iova = port_umsg_get_addr(port); + if (!iova) + return 0; + + /* Check overflow */ + if ((iova + size < iova)) + return -EINVAL; + + port_umsg_set_addr(port, 0); + } + + return 0; +} + +static int port_umsg_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port umsg Init.\n"); + + return 0; +} + +static void port_umsg_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port umsg uinit.\n"); +} + +struct feature_ops port_umsg_ops = { + .init = port_umsg_init, + .uinit = port_umsg_uinit, + .test = port_umsg_test, +}; + +static struct feature_port_stp stp_dflt = { + .stp_status = { + .csr = 0x0000000000000000, + }, +}; + +static int port_stp_test(struct feature *feature) +{ + struct feature_port_stp *port_stp = + (struct feature_port_stp *)feature->addr; + + port_check_reg(&port_stp->stp_status, + "stp:stp_csr", stp_dflt.stp_status.csr); + + dev_debug(NULL, "%s finished\n", __func__); + return 0; +} + +static int port_stp_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port stp Init.\n"); + + return 0; +} + +static void port_stp_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port stp uinit.\n"); +} + +struct feature_ops port_stp_ops = { + .init = port_stp_init, + .uinit = port_stp_uinit, + .test = port_stp_test, +}; + +static int port_uint_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "PORT UINT Init.\n"); + + spinlock_lock(&port->lock); + if (feature->ctx_num) { + port->capability |= FPGA_PORT_CAP_UAFU_IRQ; + port->num_uafu_irqs = feature->ctx_num; + } + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_uint_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT UINT UInit.\n"); +} + +static int port_uint_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_uafu_irq_set *uafu_irq_set = irq_set; + struct ifpga_port_hw *port = feature->parent; + int ret; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_UAFU_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, uafu_irq_set->start, + uafu_irq_set->count, uafu_irq_set->evtfds); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_uint_ops = { + .init = port_uint_init, + .uinit = port_uint_uinit, + .set_irq = port_uint_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c new file mode 100644 index 0000000..1a55155 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c @@ -0,0 +1,236 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +static int port_err_get_revision(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_header header; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + header.csr = readq(&port_err->header); + *val = header.revision; + + return 0; +} + +static int port_err_get_errors(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + *val = error.csr; + + return 0; +} + +static int port_err_get_first_error(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_first_err_key first_error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + first_error.csr = readq(&port_err->port_first_error); + *val = first_error.csr; + + return 0; +} + +static int port_err_get_first_malformed_req_lsb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req0 malreq0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq0.header_lsb = readq(&port_err->malreq0); + *val = malreq0.header_lsb; + + return 0; +} + +static int port_err_get_first_malformed_req_msb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req1 malreq1; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq1.header_msb = readq(&port_err->malreq1); + *val = malreq1.header_msb; + + return 0; +} + +static int port_err_set_clear(struct ifpga_port_hw *port, u64 val) +{ + int ret; + + spinlock_lock(&port->lock); + ret = port_err_clear(port, val); + spinlock_unlock(&port->lock); + + return ret; +} + +static struct feature_port_error err_dflt = { + .error_mask = { + .csr = 0x0000000000000000, + }, + .port_error = { + .csr = 0x0000000000000000, + }, + .port_first_error = { + .csr = 0x0000000000000000, + }, + .malreq0 = { + .header_lsb = 0x0000000000000000, + }, + .malreq1 = { + .header_msb = 0x0000000000000000, + }, + .port_debug = { + .port_debug = 0x0000000000000000, + }, +}; + +static int port_err_test(struct feature *feature) +{ + struct feature_port_error *port_err = + (struct feature_port_error *)feature->addr; + + port_check_reg(&port_err->error_mask, + "err:error_mask", err_dflt.error_mask.csr); + port_check_reg(&port_err->port_error, + "err:port_error", err_dflt.port_error.csr); + port_check_reg(&port_err->port_first_error, + "err:port_first_err", err_dflt.port_first_error.csr); + port_check_reg(&port_err->malreq0, + "err:malreq0", err_dflt.malreq0.header_lsb); + port_check_reg(&port_err->malreq1, + "err:malreq1", err_dflt.malreq1.header_msb); + port_check_reg(&port_err->port_debug, + "err:port_debug", err_dflt.port_debug.port_debug); + + dev_debug(NULL, "%s finished\n", __func__); + return 0; +} + +static int port_error_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port error Init.\n"); + + spinlock_lock(&port->lock); + port_err_mask(port, false); + if (feature->ctx_num) + port->capability |= FPGA_PORT_CAP_ERR_IRQ; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int port_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_ERR_PROP_REVISION: + return port_err_get_revision(port, &prop->data); + case PORT_ERR_PROP_ERRORS: + return port_err_get_errors(port, &prop->data); + case PORT_ERR_PROP_FIRST_ERROR: + return port_err_get_first_error(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB: + return port_err_get_first_malformed_req_lsb(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB: + return port_err_get_first_malformed_req_msb(port, &prop->data); + } + + return -ENOENT; +} + +static int port_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + if (prop->prop_id == PORT_ERR_PROP_CLEAR) + return port_err_set_clear(port, prop->data); + + return -ENOENT; +} + +static int port_error_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_port_err_irq_set *err_irq_set = irq_set; + struct ifpga_port_hw *port; + int ret; + + port = feature->parent; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_ERR_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_error_ops = { + .init = port_error_init, + .uinit = port_error_uinit, + .test = port_err_test, + .get_prop = port_error_get_prop, + .set_prop = port_error_set_prop, + .set_irq = port_error_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.c b/drivers/raw/ifpga_rawdev/base/opae_debug.c new file mode 100644 index 0000000..07935e7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.c @@ -0,0 +1,126 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#define OPAE_HW_DEBUG + +#include "opae_hw_api.h" +#include "opae_debug.h" + +void opae_manager_dump(struct opae_manager *mgr) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Manger %s\n", mgr->name); + opae_log("OPAE Manger OPs = %p\n", mgr->ops); + opae_log("OPAE Manager Private Data = %p\n", mgr->data); + opae_log("OPAE Adapter(parent) = %p\n", mgr->adapter); + opae_log("==========================\n"); +} + +void opae_bridge_dump(struct opae_bridge *br) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Bridge %s\n", br->name); + opae_log("OPAE Bridge ID = %d\n", br->id); + opae_log("OPAE Bridge OPs = %p\n", br->ops); + opae_log("OPAE Bridge Private Data = %p\n", br->data); + opae_log("OPAE Accelerator(under this bridge) = %p\n", br->acc); + opae_log("==========================\n"); +} + +void opae_accelerator_dump(struct opae_accelerator *acc) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Accelerator %s\n", acc->name); + opae_log("OPAE Accelerator Index = %d\n", acc->index); + opae_log("OPAE Accelerator OPs = %p\n", acc->ops); + opae_log("OPAE Accelerator Private Data = %p\n", acc->data); + opae_log("OPAE Bridge (upstream) = %p\n", acc->br); + opae_log("OPAE Manager (upstream) = %p\n", acc->mgr); + opae_log("==========================\n"); + + if (acc->br) + opae_bridge_dump(acc->br); +} + +static void opae_adapter_data_dump(void *data) +{ + struct opae_adapter_data *d = data; + struct opae_adapter_data_pci *d_pci; + struct opae_reg_region *r; + int i; + + opae_log("=====%s=====\n", __func__); + + switch (d->type) { + case OPAE_FPGA_PCI: + d_pci = (struct opae_adapter_data_pci *)d; + + opae_log("OPAE Adapter Type = PCI\n"); + opae_log("PCI Device ID: 0x%04x\n", d_pci->device_id); + opae_log("PCI Vendor ID: 0x%04x\n", d_pci->vendor_id); + + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + r = &d_pci->region[i]; + opae_log("PCI Bar %d: phy(%llx) len(%llx) addr(%p)\n", + i, (unsigned long long)r->phys_addr, + (unsigned long long)r->len, r->addr); + } + break; + case OPAE_FPGA_NET: + break; + } + + opae_log("==========================\n"); +} + +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) { + if (adapter->mgr) + opae_manager_dump(adapter->mgr); + + opae_adapter_for_each_acc(adapter, acc) + opae_accelerator_dump(acc); + + if (adapter->data) + opae_adapter_data_dump(adapter->data); + } + + opae_log("==========================\n"); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.h b/drivers/raw/ifpga_rawdev/base/opae_debug.h new file mode 100644 index 0000000..ceddf9d --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.h @@ -0,0 +1,46 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_DEBUG_H_ +#define _OPAE_DEBUG_H_ + +#ifdef OPAE_HW_DEBUG +#define opae_log(fmt, args...) printf(fmt, ## args) +#else +#define opae_log(fme, args...) do {} while (0) +#endif + +void opae_manager_dump(struct opae_manager *mgr); +void opae_bridge_dump(struct opae_bridge *br); +void opae_accelerator_dump(struct opae_accelerator *acc); +void opae_adapter_dump(struct opae_adapter *adapter, int verbose); + +#endif /* _OPAE_DEBUG_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c new file mode 100644 index 0000000..a0cecfb --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -0,0 +1,389 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "opae_hw_api.h" +#include "opae_debug.h" +#include "ifpga_api.h" + +/* OPAE Bridge Functions */ + +/** + * opae_bridge_alloc - alloc opae_bridge data structure + * @name: bridge name. + * @ops: ops of this bridge. + * @data: private data of this bridge. + * + * Return opae_bridge on success, otherwise NULL. + */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data) +{ + struct opae_bridge *br = opae_zmalloc(sizeof(*br)); + + if (!br) + return NULL; + + br->name = name; + br->ops = ops; + br->data = data; + + opae_log("%s %p\n", __func__, br); + + return br; +} + +/** + * opae_bridge_reset - reset opae_bridge + * @br: bridge to be reset. + * + * Return: 0 on success, otherwise error code. + */ +int opae_bridge_reset(struct opae_bridge *br) +{ + if (!br) + return -EINVAL; + + if (br->ops && br->ops->reset) + return br->ops->reset(br); + + opae_log("%s no ops\n", __func__); + + return -ENOENT; +} + +/* Accelerator Functions */ + +/** + * opae_accelerator_alloc - alloc opae_accelerator data structure + * @name: accelerator name. + * @ops: ops of this accelerator. + * @data: private data of this accelerator. + * + * Return: opae_accelerator on success, otherwise NULL. + */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data) +{ + struct opae_accelerator *acc = opae_zmalloc(sizeof(*acc)); + + if (!acc) + return NULL; + + acc->name = name; + acc->ops = ops; + acc->data = data; + + opae_log("%s %p\n", __func__, acc); + + return acc; +} + +/** + * opae_acc_reg_read - read accelerator's register from its reg region. + * @acc: accelerator to read. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: read operation width, e.g 4 byte = 32bit read. + * @data: data to store the value read from the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->read) + return acc->ops->read(acc, offset, region_idx, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_reg_write - write to accelerator's register from its reg region. + * @acc: accelerator to write. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: write operation width, e.g 4 byte = 32bit write. + * @data: data stored the value to write to the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->write) + return acc->ops->write(acc, offset, region_idx, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_get_info - get information of an accelerator. + * @acc: targeted accelerator + * @info: accelerator info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_info) + return acc->ops->get_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_get_region_info - get information of an accelerator register region. + * @acc: targeted accelerator + * @info: accelerator region info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_region_info) + return acc->ops->get_region_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_set_irq - set an accelerator's irq. + * @acc: targeted accelerator + * @start: start vector number + * @count: count of vectors to be set from the start vector + * @evtfds: event fds to be notified when corresponding irqs happens + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + if (!acc || !acc->data) + return -EINVAL; + + if (start + count <= start) + return -EINVAL; + + if (acc->ops && acc->ops->set_irq) + return acc->ops->set_irq(acc, start, count, evtfds); + + return -ENOENT; +} + +/* Manager Functions */ + +/** + * opae_manager_alloc - alloc opae_manager data structure + * @name: manager name. + * @ops: ops of this manager. + * @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) +{ + struct opae_manager *mgr = opae_zmalloc(sizeof(*mgr)); + + if (!mgr) + return NULL; + + mgr->name = name; + mgr->ops = ops; + mgr->data = data; + + opae_log("%s %p\n", __func__, mgr); + + return mgr; +} + +/** + * opae_manager_flash - flash a reconfiguration image via opae_manager + * @mgr: opae_manager for flash. + * @id: id of target region (accelerator). + * @buf: image data buffer. + * @size: buffer size. + * @status: status to store flash result. + * + * Return: 0 on success, otherwise error code. + */ +int opae_manager_flash(struct opae_manager *mgr, int id, void *buf, u32 size, + u64 *status) +{ + if (!mgr) + return -EINVAL; + + if (mgr && mgr->ops && mgr->ops->flash) + return mgr->ops->flash(mgr, id, buf, size, status); + + return -ENOENT; +} + +/* Adapter Functions */ + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @type: opae_adapter_type. + * + * Return: opae_adapter_data on success, otherwise NULL. + */ +void *opae_adapter_data_alloc(enum opae_adapter_type type) +{ + struct opae_adapter_data *data; + int size; + + switch (type) { + case OPAE_FPGA_PCI: + size = sizeof(struct opae_adapter_data_pci); + break; + case OPAE_FPGA_NET: + size = sizeof(struct opae_adapter_data_net); + break; + default: + size = sizeof(struct opae_adapter_data); + break; + } + + data = opae_zmalloc(size); + if (!data) + return NULL; + + data->type = type; + + return data; +} + +static struct opae_adapter_ops *match_ops(struct opae_adapter *adapter) +{ + struct opae_adapter_data *data; + + if (!adapter || !adapter->data) + return NULL; + + data = adapter->data; + + if (data->type == OPAE_FPGA_PCI) + return &ifpga_adapter_ops; + + return NULL; +} + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @name: adapter name. + * @data: private data of this adapter. + * + * Return: opae_adapter on success, otherwise NULL. + */ +struct opae_adapter *opae_adapter_alloc(const char *name, void *data) +{ + struct opae_adapter *adapter = opae_zmalloc(sizeof(*adapter)); + + if (!adapter) + return NULL; + + TAILQ_INIT(&adapter->acc_list); + adapter->data = data; + adapter->name = name; + adapter->ops = match_ops(adapter); + + return adapter; +} + +/** + * opae_adapter_enumerate - enumerate this adapter + * @adapter: adapter to enumerate. + * + * Return: 0 on success, otherwise error code. + */ +int opae_adapter_enumerate(struct opae_adapter *adapter) +{ + int ret = -ENOENT; + + if (!adapter) + return -EINVAL; + + if (adapter->ops && adapter->ops->enumerate) + ret = adapter->ops->enumerate(adapter); + + if (!ret) + opae_adapter_dump(adapter, 1); + + return ret; +} + +/** + * opae_adapter_destroy - destroy this adapter + * @adapter: adapter to destroy. + * + * destroy things allocated during adapter enumeration. + */ +void opae_adapter_destroy(struct opae_adapter *adapter) +{ + if (adapter && adapter->ops && adapter->ops->destroy) + adapter->ops->destroy(adapter); +} + +/** + * opae_adapter_get_acc - find and return accelerator with matched id + * @adapter: adapter to find the accelerator. + * @acc_id: id (index) of the accelerator. + * + * destroy things allocated during adapter enumeration. + */ +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id) +{ + struct opae_accelerator *acc = NULL; + + if (!adapter) + return NULL; + + opae_adapter_for_each_acc(adapter, acc) + if (acc->index == acc_id) + return acc; + + return NULL; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h new file mode 100644 index 0000000..1f2391c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -0,0 +1,276 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_HW_API_H_ +#define _OPAE_HW_API_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> + +#include "opae_osdep.h" + +#ifndef PCI_MAX_RESOURCE +#define PCI_MAX_RESOURCE 6 +#endif + +struct opae_adapter; + +enum opae_adapter_type { + OPAE_FPGA_PCI, + OPAE_FPGA_NET, +}; + +/* OPAE Manager Data Structure */ +struct opae_manager_ops; + +/* + * opae_manager has pointer to its parent adapter, as it could be able to manage + * all components on this FPGA device (adapter). If not the case, don't set this + * adapter, which limit opae_manager ops to manager itself. + */ +struct opae_manager { + const char *name; + struct opae_adapter *adapter; + struct opae_manager_ops *ops; + void *data; +}; + +/* FIXME: add more management ops, e.g power/thermal and etc */ +struct opae_manager_ops { + int (*flash)(struct opae_manager *mgr, int id, void *buffer, + u32 size, u64 *status); +}; + +/* OPAE Manager APIs */ +struct opae_manager * +opae_manager_alloc(const char *name, struct opae_manager_ops *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); + +/* OPAE Bridge Data Structure */ +struct opae_bridge_ops; + +/* + * opae_bridge only has pointer to its downstream accelerator. + */ +struct opae_bridge { + const char *name; + int id; + struct opae_accelerator *acc; + struct opae_bridge_ops *ops; + void *data; +}; + +struct opae_bridge_ops { + int (*reset)(struct opae_bridge *br); +}; + +/* OPAE Bridge APIs */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data); +int opae_bridge_reset(struct opae_bridge *br); +#define opae_bridge_free(br) opae_free(br) + +/* OPAE Acceleraotr Data Structure */ +struct opae_accelerator_ops; + +/* + * opae_accelerator has pointer to its upstream bridge(port). + * In some cases, if we allow same user to do PR on its own accelerator, then + * set the manager pointer during the enumeration. But in other cases, the PR + * functions only could be done via manager in another module / thread / service + * / application for better protection. + */ +struct opae_accelerator { + TAILQ_ENTRY(opae_accelerator) node; + const char *name; + int index; + struct opae_bridge *br; + struct opae_manager *mgr; + struct opae_accelerator_ops *ops; + void *data; +}; + +struct opae_acc_info { + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct opae_acc_region_info { + u32 flags; +#define ACC_REGION_READ (1 << 0) +#define ACC_REGION_WRITE (1 << 1) +#define ACC_REGION_MMIO (1 << 2) + u32 index; + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_accelerator_ops { + int (*read)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*write)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*get_info)(struct opae_accelerator *acc, + struct opae_acc_info *info); + int (*get_region_info)(struct opae_accelerator *acc, + struct opae_acc_region_info *info); + int (*set_irq)(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); +}; + +/* OPAE accelerator APIs */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data); +#define opae_accelerator_free(acc) opae_free(acc) +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info); +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info); +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); + +static inline struct opae_bridge * +opae_acc_get_br(struct opae_accelerator *acc) +{ + return acc ? acc->br : NULL; +} + +static inline struct opae_manager * +opae_acc_get_mgr(struct opae_accelerator *acc) +{ + return acc ? acc->mgr : NULL; +} + +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + +#define opae_acc_reg_read64(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 8, data) +#define opae_acc_reg_write64(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 8, data) +#define opae_acc_reg_read32(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 4, data) +#define opae_acc_reg_write32(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 4, data) +#define opae_acc_reg_read16(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 2, data) +#define opae_acc_reg_write16(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 2, data) +#define opae_acc_reg_read8(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 1, data) +#define opae_acc_reg_write8(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 1, data) + +/*for data stream read/write*/ +int opae_acc_data_read(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); +int opae_acc_data_write(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); + +/* OPAE Adapter Data Structure */ +struct opae_adapter_data { + enum opae_adapter_type type; +}; + +struct opae_reg_region { + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_adapter_data_pci { + enum opae_adapter_type type; + u16 device_id; + u16 vendor_id; + struct opae_reg_region region[PCI_MAX_RESOURCE]; + int vfio_dev_fd; /* VFIO device file descriptor */ +}; + +/* FIXME: OPAE_FPGA_NET type */ +struct opae_adapter_data_net { + enum opae_adapter_type type; +}; + +struct opae_adapter_ops { + int (*enumerate)(struct opae_adapter *adapter); + void (*destroy)(struct opae_adapter *adapter); +}; + +TAILQ_HEAD(opae_accelerator_list, opae_accelerator); + +#define opae_adapter_for_each_acc(adatper, acc) \ + TAILQ_FOREACH(acc, &adapter->acc_list, node) + +struct opae_adapter { + const char *name; + struct opae_manager *mgr; + struct opae_accelerator_list acc_list; + struct opae_adapter_ops *ops; + void *data; +}; + +/* OPAE Adapter APIs */ +void *opae_adapter_data_alloc(enum opae_adapter_type type); +#define opae_adapter_data_free(data) opae_free(data) + +struct opae_adapter *opae_adapter_alloc(const char *name, void *data); +#define opae_adapter_free(adapter) opae_free(adapter) + +int opae_adapter_enumerate(struct opae_adapter *adapter); +void opae_adapter_destroy(struct opae_adapter *adapter); +static inline struct opae_manager * +opae_adapter_get_mgr(struct opae_adapter *adapter) +{ + return adapter ? adapter->mgr : NULL; +} + +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id); + +static inline void opae_adapter_add_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_INSERT_TAIL(&adapter->acc_list, acc, node); +} + +static inline void opae_adapter_remove_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_REMOVE(&adapter->acc_list, acc, node); +} +#endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c new file mode 100644 index 0000000..9d3bc2f --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c @@ -0,0 +1,151 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "opae_ifpga_hw_api.h" +#include "ifpga_api.h" + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data || !fme_info) + return -EINVAL; + + fme = mgr->data; + + spinlock_lock(&fme->lock); + fme_info->capability = fme->capability; + spinlock_unlock(&fme->lock); + + return 0; +} + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_irq(fme->parent, FEATURE_FIU_ID_FME, 0, + FME_FEATURE_ID_GLOBAL_ERR, err_irq_set); +} + +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_get_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !port_info) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + port_info->capability = port->capability; + port_info->num_umsgs = port->num_umsgs; + port_info->num_uafu_irqs = port->num_uafu_irqs; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + PORT_FEATURE_ID_ERROR, err_irq_set); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h new file mode 100644 index 0000000..047945e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h @@ -0,0 +1,293 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_IFPGA_HW_API_H_ +#define _OPAE_IFPGA_HW_API_H_ + +#include "opae_hw_api.h" + +/** + * struct feature_prop - data structure for feature property + * @feature_id: id of this feature. + * @prop_id: id of this property under this feature. + * @data: property value to set/get. + */ +struct feature_prop { + u64 feature_id; + u64 prop_id; + u64 data; +}; + +#define IFPGA_FIU_ID_FME 0x0 +#define IFPGA_FIU_ID_PORT 0x1 + +#define IFPGA_FME_FEATURE_ID_HEADER 0x0 +#define IFPGA_FME_FEATURE_ID_THERMAL_MGMT 0x1 +#define IFPGA_FME_FEATURE_ID_POWER_MGMT 0x2 +#define IFPGA_FME_FEATURE_ID_GLOBAL_IPERF 0x3 +#define IFPGA_FME_FEATURE_ID_GLOBAL_ERR 0x4 +#define IFPGA_FME_FEATURE_ID_PR_MGMT 0x5 +#define IFPGA_FME_FEATURE_ID_HSSI 0x6 +#define IFPGA_FME_FEATURE_ID_GLOBAL_DPERF 0x7 + +#define IFPGA_PORT_FEATURE_ID_HEADER 0x0 +#define IFPGA_PORT_FEATURE_ID_AFU 0xff +#define IFPGA_PORT_FEATURE_ID_ERROR 0x10 +#define IFPGA_PORT_FEATURE_ID_UMSG 0x11 +#define IFPGA_PORT_FEATURE_ID_UINT 0x12 +#define IFPGA_PORT_FEATURE_ID_STP 0x13 + +/* + * PROP format (TOP + SUB + ID) + * + * (~0x0) means this field is unused. + */ +#define PROP_TOP GENMASK(31, 24) +#define PROP_TOP_UNUSED 0xff +#define PROP_SUB GENMASK(23, 16) +#define PROP_SUB_UNUSED 0xff +#define PROP_ID GENMASK(15, 0) + +#define PROP(_top, _sub, _id) \ + (SET_FIELD(PROP_TOP, _top) | SET_FIELD(PROP_SUB, _sub) |\ + SET_FIELD(PROP_ID, _id)) + +/* FME head feature's properties*/ +#define FME_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define FME_HDR_PROP_PORTS_NUM 0x2 /* RDONLY */ +#define FME_HDR_PROP_CACHE_SIZE 0x3 /* RDONLY */ +#define FME_HDR_PROP_VERSION 0x4 /* RDONLY */ +#define FME_HDR_PROP_SOCKET_ID 0x5 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_ID 0x6 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_METADATA 0x7 /* RDONLY */ + +/* FME error reporting feature's properties */ +/* FME error reporting properties format */ +#define ERR_PROP(_top, _id) PROP(_top, 0xff, _id) +#define ERR_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define ERR_PROP_TOP_FME_ERR 0x1 +#define ERR_PROP_ROOT(_id) ERR_PROP(0xff, _id) +#define ERR_PROP_FME_ERR(_id) ERR_PROP(ERR_PROP_TOP_FME_ERR, _id) + +#define FME_ERR_PROP_ERRORS ERR_PROP_FME_ERR(0x1) +#define FME_ERR_PROP_FIRST_ERROR ERR_PROP_FME_ERR(0x2) +#define FME_ERR_PROP_NEXT_ERROR ERR_PROP_FME_ERR(0x3) +#define FME_ERR_PROP_CLEAR ERR_PROP_FME_ERR(0x4) /* WO */ +#define FME_ERR_PROP_REVISION ERR_PROP_ROOT(0x5) +#define FME_ERR_PROP_PCIE0_ERRORS ERR_PROP_ROOT(0x6) /* RW */ +#define FME_ERR_PROP_PCIE1_ERRORS ERR_PROP_ROOT(0x7) /* RW */ +#define FME_ERR_PROP_NONFATAL_ERRORS ERR_PROP_ROOT(0x8) +#define FME_ERR_PROP_CATFATAL_ERRORS ERR_PROP_ROOT(0x9) +#define FME_ERR_PROP_INJECT_ERRORS ERR_PROP_ROOT(0xa) /* RW */ + +/* FME thermal feature's properties */ +#define FME_THERMAL_PROP_THRESHOLD1 0x1 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD2 0x2 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD_TRIP 0x3 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_REACHED 0x4 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD2_REACHED 0x5 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_POLICY 0x6 /* RW */ +#define FME_THERMAL_PROP_TEMPERATURE 0x7 /* RDONLY */ +#define FME_THERMAL_PROP_REVISION 0x8 /* RDONLY */ + +/* FME power feature's properties */ +#define FME_PWR_PROP_CONSUMED 0x1 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD1 0x2 /* RW */ +#define FME_PWR_PROP_THRESHOLD2 0x3 /* RW */ +#define FME_PWR_PROP_THRESHOLD1_STATUS 0x4 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD2_STATUS 0x5 /* RDONLY */ +#define FME_PWR_PROP_RTL 0x6 /* RDONLY */ +#define FME_PWR_PROP_XEON_LIMIT 0x7 /* RDONLY */ +#define FME_PWR_PROP_FPGA_LIMIT 0x8 /* RDONLY */ +#define FME_PWR_PROP_REVISION 0x9 /* RDONLY */ + +/* FME iperf/dperf PROP format */ +#define PERF_PROP_TOP_CACHE 0x1 +#define PERF_PROP_TOP_VTD 0x2 +#define PERF_PROP_TOP_FAB 0x3 +#define PERF_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define PERF_PROP_SUB_UNUSED PROP_SUB_UNUSED + +#define PERF_PROP_ROOT(_id) PROP(0xff, 0xff, _id) +#define PERF_PROP_CACHE(_id) PROP(PERF_PROP_TOP_CACHE, 0xff, _id) +#define PERF_PROP_VTD(_sub, _id) PROP(PERF_PROP_TOP_VTD, _sub, _id) +#define PERF_PROP_VTD_ROOT(_id) PROP(PERF_PROP_TOP_VTD, 0xff, _id) +#define PERF_PROP_FAB(_sub, _id) PROP(PERF_PROP_TOP_FAB, _sub, _id) +#define PERF_PROP_FAB_ROOT(_id) PROP(PERF_PROP_TOP_FAB, 0xff, _id) + +/* FME iperf feature's properties */ +#define FME_IPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_IPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* iperf CACHE properties */ +#define FME_IPERF_PROP_CACHE_FREEZE PERF_PROP_CACHE(0x1) /* RW */ +#define FME_IPERF_PROP_CACHE_READ_HIT PERF_PROP_CACHE(0x2) +#define FME_IPERF_PROP_CACHE_READ_MISS PERF_PROP_CACHE(0x3) +#define FME_IPERF_PROP_CACHE_WRITE_HIT PERF_PROP_CACHE(0x4) +#define FME_IPERF_PROP_CACHE_WRITE_MISS PERF_PROP_CACHE(0x5) +#define FME_IPERF_PROP_CACHE_HOLD_REQUEST PERF_PROP_CACHE(0x6) +#define FME_IPERF_PROP_CACHE_TX_REQ_STALL PERF_PROP_CACHE(0x7) +#define FME_IPERF_PROP_CACHE_RX_REQ_STALL PERF_PROP_CACHE(0x8) +#define FME_IPERF_PROP_CACHE_RX_EVICTION PERF_PROP_CACHE(0x9) +#define FME_IPERF_PROP_CACHE_DATA_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xa) +#define FME_IPERF_PROP_CACHE_TAG_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xb) +/* iperf VTD properties */ +#define FME_IPERF_PROP_VTD_FREEZE PERF_PROP_VTD_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_HIT PERF_PROP_VTD_ROOT(0x2) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_HIT PERF_PROP_VTD_ROOT(0x3) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_HIT PERF_PROP_VTD_ROOT(0x4) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_HIT PERF_PROP_VTD_ROOT(0x5) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_HIT PERF_PROP_VTD_ROOT(0x6) +#define FME_IPERF_PROP_VTD_SIP_RCC_HIT PERF_PROP_VTD_ROOT(0x7) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_MISS PERF_PROP_VTD_ROOT(0x8) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_MISS PERF_PROP_VTD_ROOT(0x9) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_MISS PERF_PROP_VTD_ROOT(0xa) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_MISS PERF_PROP_VTD_ROOT(0xb) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_MISS PERF_PROP_VTD_ROOT(0xc) +#define FME_IPERF_PROP_VTD_SIP_RCC_MISS PERF_PROP_VTD_ROOT(0xd) +#define FME_IPERF_PROP_VTD_PORT_READ_TRANSACTION(n) PERF_PROP_VTD(n, 0xe) +#define FME_IPERF_PROP_VTD_PORT_WRITE_TRANSACTION(n) PERF_PROP_VTD(n, 0xf) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_READ_HIT(n) PERF_PROP_VTD(n, 0x10) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_WRITE_HIT(n) PERF_PROP_VTD(n, 0x11) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_4K_FILL(n) PERF_PROP_VTD(n, 0x12) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_2M_FILL(n) PERF_PROP_VTD(n, 0x13) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_1G_FILL(n) PERF_PROP_VTD(n, 0x14) +/* iperf FAB properties */ +#define FME_IPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_IPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_IPERF_PROP_FAB_PCIE1_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_IPERF_PROP_FAB_PCIE1_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_IPERF_PROP_FAB_UPI_READ PERF_PROP_FAB_ROOT(0x6) +#define FME_IPERF_PROP_FAB_PORT_UPI_READ(n) PERF_PROP_FAB(n, 0x6) +#define FME_IPERF_PROP_FAB_UPI_WRITE PERF_PROP_FAB_ROOT(0x7) +#define FME_IPERF_PROP_FAB_PORT_UPI_WRITE(n) PERF_PROP_FAB(n, 0x7) +#define FME_IPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x8) +#define FME_IPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x8) +#define FME_IPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x9) +#define FME_IPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x9) +#define FME_IPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0xa) /* RW */ +#define FME_IPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0xa) /* RW */ + +/* FME dperf properties */ +#define FME_DPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_DPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* dperf FAB properties */ +#define FME_DPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_DPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_DPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_DPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_DPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_DPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_DPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_DPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0x6) /* RW */ +#define FME_DPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0x6) /* RW */ + +/*PORT hdr feature's properties*/ +#define PORT_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_HDR_PROP_PORTIDX 0x2 /* RDONLY */ +#define PORT_HDR_PROP_LATENCY_TOLERANCE 0x3 /* RDONLY */ +#define PORT_HDR_PROP_AP1_EVENT 0x4 /* RW */ +#define PORT_HDR_PROP_AP2_EVENT 0x5 /* RW */ +#define PORT_HDR_PROP_POWER_STATE 0x6 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_FREQCMD 0x7 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQCNTRCMD 0x8 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQSTS 0x9 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_CNTRSTS 0xa /* RDONLY */ + +/*PORT error feature's properties*/ +#define PORT_ERR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_ERR_PROP_ERRORS 0x2 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_ERROR 0x3 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB 0x4 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB 0x5 /* RDONLY */ +#define PORT_ERR_PROP_CLEAR 0x6 /* WRONLY */ + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop); +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop); + +/* + * Retrieve information about the fpga fme. + * Driver fills the info in provided struct fpga_fme_info. + */ +struct fpga_fme_info { + u32 capability; /* The capability of FME device */ +#define FPGA_FME_CAP_ERR_IRQ (1 << 0) /* Support fme error interrupt */ +}; + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info); + +/* Set eventfd information for ifpga FME error interrupt */ +struct fpga_fme_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set); + +/* + * Retrieve information about the fpga port. + * Driver fills the info in provided struct fpga_port_info. + */ +struct fpga_port_info { + u32 capability; /* The capability of port device */ +#define FPGA_PORT_CAP_ERR_IRQ (1 << 0) /* Support port error interrupt */ +#define FPGA_PORT_CAP_UAFU_IRQ (1 << 1) /* Support uafu error interrupt */ + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ +}; + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info); + +/* Set eventfd information for ifpga port error interrupt */ +struct fpga_port_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set); + +#endif /* _OPAE_IFPGA_HW_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h new file mode 100644 index 0000000..00d3736 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -0,0 +1,111 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_OSDEP_H +#define _OPAE_OSDEP_H + +#include <string.h> +#include <stdbool.h> + +#ifdef RTE_LIBRTE_EAL +#include "osdep_rte/osdep_generic.h" +#else +#include "osdep_raw/osdep_generic.h" +#endif + +#include <asm/types.h> + +#define __iomem + +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef uint64_t dma_addr_t; + +#ifndef LINUX_MACROS +#ifndef BITS_PER_LONG +#define BITS_PER_LONG (__SIZEOF_LONG__ * 8) +#endif +#ifndef BIT +#define BIT(a) (1UL << (a)) +#endif /* BIT */ +#ifndef BIT_ULL +#define BIT_ULL(a) (1ULL << (a)) +#endif /* BIT_ULL */ +#ifndef GENMASK +#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#endif /* GENMASK */ +#ifndef GENMASK_ULL +#define GENMASK_ULL(h, l) (((U64_C(1) << ((h) - (l) + 1)) - 1) << (l)) +#endif /* GENMASK_ULL */ +#endif /* LINUX_MACROS */ + +#define SET_FIELD(m, v) (((v) << (__builtin_ffsll(m) - 1)) & (m)) +#define GET_FIELD(m, v) (((v) & (m)) >> (__builtin_ffsll(m) - 1)) + +#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) +#define pr_info(y, args...) dev_info(0, y, ##args) +#define BUG() pr_err("BUG at %s:%d", __func__, __LINE__) + +#define ASSERT(x) do {\ + if (!(x)) \ + osdep_panic("osdep_panic: x"); \ +} while (0) +#define BUG_ON(x) ASSERT(!(x)) + +#ifndef WARN_ON +#define WARN_ON(x) do { \ + int ret = !!(x); \ + if (unlikely(ret)) \ + pr_warn("WARN_ON: \"" #x "\" at %s:%d\n", __func__, __LINE__); \ +} while (0) +#endif + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define udelay(x) opae_udelay(x) +#define msleep(x) opae_udelay(1000 * (x)) +#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000)) + +#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 new file mode 100644 index 0000000..12ad018 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h @@ -0,0 +1,104 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OSDEP_RAW_GENERIC_H +#define _OSDEP_RAW_GENERIC_H + +#define compiler_barrier() do { \ + asm volatile ("" : : : "memory"); \ +} while (0) + +#define io_wmb() compiler_barrier() +#define io_rmb() compiler_barrier() + +static inline uint8_t opae_readb(const volatile void *addr) +{ + uint8_t val; + + val = *(const volatile uint8_t *)addr; + io_rmb(); + return val; +} + +static inline uint16_t opae_readw(const volatile void *addr) +{ + uint16_t val; + + val = *(const volatile uint16_t *)addr; + io_rmb(); + return val; +} + +static inline uint32_t opae_readl(const volatile void *addr) +{ + uint32_t val; + + val = *(const volatile uint32_t *)addr; + io_rmb(); + return val; +} + +static inline uint64_t opae_readq(const volatile void *addr) +{ + uint64_t val; + + val = *(const volatile uint64_t *)addr; + io_rmb(); + return val; +} + +static inline void opae_writeb(uint8_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint8_t *)addr = value; +} + +static inline void opae_writew(uint16_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint16_t *)addr = value; +} + +static inline void opae_writel(uint32_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint32_t *)addr = value; +} + +static inline void opae_writeq(uint64_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint64_t *)addr = value; +} + +#define opae_free(addr) free(addr) + +#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 new file mode 100644 index 0000000..9ff580e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h @@ -0,0 +1,72 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OSDEP_RTE_GENERIC_H +#define _OSDEP_RTE_GENERIC_H + +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_spinlock.h> +#include <rte_log.h> +#include <rte_io.h> +#include <rte_malloc.h> + +#define dev_printf(level, fmt, args...) \ + RTE_LOG(level, PMD, "osdep_rte: " fmt, ## args) + +#define osdep_panic(...) rte_panic(...) + +#define opae_udelay(x) rte_delay_us(x) + +#define opae_readb(addr) rte_read8(addr) +#define opae_readw(addr) rte_read16(addr) +#define opae_readl(addr) rte_read32(addr) +#define opae_readq(addr) rte_read64(addr) +#define opae_writeb(value, addr) rte_write8(value, addr) +#define opae_writew(value, addr) rte_write16(value, addr) +#define opae_writel(value, addr) rte_write32(value, addr) +#define opae_writeq(value, addr) rte_write64(value, addr) + +#define opae_malloc(size) rte_malloc(NULL, size, 0) +#define opae_zmalloc(size) rte_zmalloc(NULL, size, 0) +#define opae_free(addr) rte_free(addr) + +#define ARRAY_SIZE(arr) RTE_DIM(arr) + +#define min(a, b) RTE_MIN(a, b) +#define max(a, b) RTE_MAX(a, b) + +#define spinlock_t rte_spinlock_t +#define spinlock_init(x) rte_spinlock_init(x) +#define spinlock_lock(x) rte_spinlock_lock(x) +#define spinlock_unlock(x) rte_spinlock_unlock(x) + +#endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (4 preceding siblings ...) 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 5/5] Add Intel OPAE Share Code Rosen Xu @ 2018-03-20 14:58 ` Gaëtan Rivet 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 0/6] " Rosen Xu ` (11 subsequent siblings) 17 siblings, 0 replies; 149+ messages in thread From: Gaëtan Rivet @ 2018-03-20 14:58 UTC (permalink / raw) To: Rosen Xu Cc: dev, declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu Hi Rosen, Unless I'm mistaken, this is the v1? Did you mean to send the v2 instead and got mixed up or did I miss something? I would have the same remarks regarding PCI parsing of devices etc. Can you send the v2 as a response to this cover-letter? You have to take the Message-ID of the previous patch and use "--in-reply-to" option from git-send-email. On Tue, Mar 20, 2018 at 09:45:51PM +0800, Rosen Xu wrote: > Intel FPGA BUS in DPDK > ------------------------- > > This patch set introduces Intel FPGA BUS support in DPDK. > > Motivation > ========== > > FPGA is used more and more widely in Cloud and NFV, one primary reason is > that FPGA not only provide ASIC performance but also it's more flexible > than ASIC. FPGA use Partial Reconfigure(PR) Parts of Bitstream to achieve > its flexibility. Another reason is that one FPGA can be shared > by different Users, and each User can use some of AFUs of One FPGA. > > That means One FPGA Device Bitstream is divided into many Parts of > Bitstream(each Part of Bitstream is defined as AFU-Accelerated > Function Unit), and each AFU is a Hardware Acceleration Unit and > it can dynamically Reload respectively. > > Scope > ===== > > The Intel FPGA BUS implementation is target towards various FPGA Devices > use PR to provide many Acceleration Function. Specific PMDs may also > bind to its AFU. And Applications don't care they are using ASIC > Acceleration or FPGA AFU Acceleration. > > Proposed Solution > ================= > - Involve Rawdev to take FPGA Partial Configuration(Download/PR) > - Defined FPGA-BUS for Acceleration Drivers of AFUs > - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, > probe Intel FPGA Rawdev Driver > - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream > > Status > ===== > With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable > Acceleration Engine) Share Code, Intel FPGA BUS runs well in > Intel PSG FPGA Cards. > > Patch set Information > ==================== > > This patch set includes 6 patches: > * 0 : Introduce the Intel FPGA BUS library and enable its compilation. > * 1 : Adds command parse code, for start-up application > with Intel FPGA BUS. > * 2 : Adds Driver Probe Code, for AFU Drivers should probed > after PCI Drivers. > * 3 : Adds Intel FPGA BUS library code, for AFU Device scan > and AFU Drivers probe. > * 4 : Adds a Intel FPGA rawdevice driver, for FPGA Device Management > such as PR. > * 5 : Adds Intel OPAE(Open Programmable Acceleration Engine) Share Code, > it's Intel FPGA Software Stack. > > Rosen Xu (5): > Add Intel FPGA BUS Command Parse Code > Add Intel FPGA BUS Probe Code > Add Intel FPGA BUS Lib Code > Add Intel FPGA BUS Rawdev Code > Add Intel OPAE Share Code > > drivers/bus/ifpga/Makefile | 64 + > drivers/bus/ifpga/ifpga_bus.c | 573 +++++++ > drivers/bus/ifpga/ifpga_common.c | 154 ++ > drivers/bus/ifpga/ifpga_common.h | 25 + > drivers/bus/ifpga/ifpga_logs.h | 32 + > drivers/bus/ifpga/rte_bus_ifpga.h | 141 ++ > drivers/bus/ifpga/rte_bus_ifpga_version.map | 8 + > drivers/raw/Makefile | 1 + > drivers/raw/ifpga_rawdev/Makefile | 63 + > drivers/raw/ifpga_rawdev/base/Makefile | 54 + > drivers/raw/ifpga_rawdev/base/ifpga_api.c | 543 +++++++ > drivers/raw/ifpga_rawdev/base/ifpga_api.h | 77 + > drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 84 + > drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1696 ++++++++++++++++++++ > drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 861 ++++++++++ > drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 38 + > drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 340 ++++ > drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 197 +++ > drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 763 +++++++++ > drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 328 ++++ > drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 430 +++++ > drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 742 +++++++++ > drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 395 +++++ > drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 152 ++ > drivers/raw/ifpga_rawdev/base/ifpga_port.c | 730 +++++++++ > drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 236 +++ > drivers/raw/ifpga_rawdev/base/opae_debug.c | 126 ++ > drivers/raw/ifpga_rawdev/base/opae_debug.h | 46 + > drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 389 +++++ > drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 276 ++++ > drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 151 ++ > drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 293 ++++ > drivers/raw/ifpga_rawdev/base/opae_osdep.h | 111 ++ > .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 104 ++ > .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 72 + > drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 486 ++++++ > drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 38 + > drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c | 99 ++ > .../ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map | 4 + > lib/librte_eal/common/eal_common_bus.c | 14 +- > lib/librte_eal/common/eal_common_options.c | 8 +- > lib/librte_eal/common/eal_options.h | 2 + > 42 files changed, 10944 insertions(+), 2 deletions(-) > create mode 100644 drivers/bus/ifpga/Makefile > create mode 100644 drivers/bus/ifpga/ifpga_bus.c > create mode 100644 drivers/bus/ifpga/ifpga_common.c > create mode 100644 drivers/bus/ifpga/ifpga_common.h > create mode 100644 drivers/bus/ifpga/ifpga_logs.h > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map > create mode 100644 drivers/raw/ifpga_rawdev/Makefile > create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c > create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c > create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c > create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h > create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c > create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h > create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c > create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h > create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h > create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h > create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c > create mode 100644 drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map > > -- > 1.8.3.1 > -- Gaëtan Rivet 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v3 0/6] Introduce Intel FPGA BUS 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (5 preceding siblings ...) 2018-03-20 14:58 ` [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Gaëtan Rivet @ 2018-03-28 9:29 ` Rosen Xu 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 1/6] Add Intel FPGA BUS Command Parse Code Rosen Xu ` (7 more replies) 2018-03-31 16:02 ` [dpdk-dev] [PATCH v4 0/3] " Rosen Xu ` (10 subsequent siblings) 17 siblings, 8 replies; 149+ messages in thread From: Rosen Xu @ 2018-03-28 9:29 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu, gaetan.rivet [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset=y, Size: 7805 bytes --] Intel FPGA BUS in DPDK ------------------------- This patch set introduces Intel FPGA BUS support in DPDK. v3 updates: =========== - Remove all modifications of bus scan and probe - FPGA BUS Scan is trigged by hotplug of Rawdev - Took Modifications of comments - Move AFU Device to IFPGA - FPGA BUS Scan depend on it¡¯s IFPGA Rawdev - Add Build Macros for FPGA BUS and IFPGA Rawdev Questions ========= Why not PCI Bus? All of the AFUs of one FPGA may share same PCI BDF. Why not vdev Bus? Because AFUs depend on Rawdev, and it's hardware specpic. Motivation ========== FPGA is used more and more widely in Cloud and NFV, one primary reason is that FPGA not only provide ASIC performance but also it's more flexible than ASIC. FPGA use Partial Reconfigure(PR) Parts of Bitstream to achieve its flexibility. Another reason is that one FPGA can be shared by different Users, and each User can use some of AFUs of One FPGA. That means One FPGA Device Bitstream is divided into many Parts of Bitstream(each Part of Bitstream is defined as AFU-Accelerated Function Unit), and each AFU is a Hardware Acceleration Unit and it can dynamically Reload respectively. Proposed Solution ================= - Involve Rawdev to take FPGA Partial Configuration(Download/PR) - Defined FPGA-BUS for Acceleration Drivers of AFUs - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver. FPGA-BUS scan is called, but AFU depend on Rawdev, so this scan doesn't trig AFU device create. - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their dirves are also probed. Scope ===== The Intel FPGA BUS implementation is target towards various FPGA Devices use PR to provide many Acceleration Function. Specific PMDs may also bind to its AFU. And Applications don't care they are using ASIC Acceleration or FPGA AFU Acceleration. Status ===== With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable Acceleration Engine) Share Code, Intel FPGA BUS runs well in Intel PSG FPGA Cards. Rosen Xu (6): Add Intel FPGA BUS Command Parse Code config/common_base: Add Intel FPGA Build Configuration Macro mk/rte.app.mk: Add Intel FPGA Bus Build Configuration Macro To App Script drivers/bus: Add Intel FPGA Bus Lib Code drivers/raw/ifpga_rawdev: Add Intel FPGA Rawdev Driver Code drivers/raw/ifpga_rawdev: Add Intel FPGA OPAE Share Code config/common_base | 6 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 33 + drivers/bus/ifpga/ifpga_bus.c | 562 +++++++ drivers/bus/ifpga/ifpga_common.c | 141 ++ drivers/bus/ifpga/ifpga_common.h | 22 + drivers/bus/ifpga/ifpga_logs.h | 31 + drivers/bus/ifpga/rte_bus_ifpga.h | 140 ++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 8 + drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 35 + drivers/raw/ifpga_rawdev/base/Makefile | 54 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 543 +++++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 77 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 84 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1696 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 861 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 38 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 340 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 197 +++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 763 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 328 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 430 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 742 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 395 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 154 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 735 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 236 +++ drivers/raw/ifpga_rawdev/base/opae_debug.c | 126 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 46 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 389 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 276 ++++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 173 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 306 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 111 ++ .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 104 ++ .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 72 + drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 492 ++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 + drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c | 98 ++ .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + lib/librte_eal/common/eal_common_options.c | 8 +- lib/librte_eal/common/eal_options.h | 2 + mk/rte.app.mk | 3 + 44 files changed, 10899 insertions(+), 1 deletion(-) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c create mode 100644 drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v3 1/6] Add Intel FPGA BUS Command Parse Code 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 0/6] " Rosen Xu @ 2018-03-28 9:29 ` Rosen Xu 2018-03-28 13:26 ` Gaëtan Rivet 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 2/6] config/common_base: Add Intel FPGA Build Configuration Macro Rosen Xu ` (6 subsequent siblings) 7 siblings, 1 reply; 149+ messages in thread From: Rosen Xu @ 2018-03-28 9:29 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu, gaetan.rivet Signed-off-by: Rosen Xu <rosen.xu@intel.com> --- lib/librte_eal/common/eal_common_options.c | 8 +++++++- lib/librte_eal/common/eal_options.h | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c index 9f2f8d2..4fe0875 100644 --- a/lib/librte_eal/common/eal_common_options.c +++ b/lib/librte_eal/common/eal_common_options.c @@ -73,6 +73,7 @@ {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM }, + {OPT_IFPGA, 1, NULL, OPT_IFPGA_NUM }, {0, 0, NULL, 0 } }; @@ -1160,7 +1161,12 @@ static int xdigit2val(unsigned char c) core_parsed = LCORE_OPT_MAP; break; - + case OPT_IFPGA_NUM: + if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL, + optarg) < 0) { + return -1; + } + break; /* don't know what to do, leave this to caller */ default: return 1; diff --git a/lib/librte_eal/common/eal_options.h b/lib/librte_eal/common/eal_options.h index e86c711..bdbb2c4 100644 --- a/lib/librte_eal/common/eal_options.h +++ b/lib/librte_eal/common/eal_options.h @@ -55,6 +55,8 @@ enum { OPT_VFIO_INTR_NUM, #define OPT_VMWARE_TSC_MAP "vmware-tsc-map" OPT_VMWARE_TSC_MAP_NUM, +#define OPT_IFPGA "ifpga" + OPT_IFPGA_NUM, OPT_LONG_MAX_NUM }; -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 1/6] Add Intel FPGA BUS Command Parse Code 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 1/6] Add Intel FPGA BUS Command Parse Code Rosen Xu @ 2018-03-28 13:26 ` Gaëtan Rivet 2018-03-31 16:25 ` Xu, Rosen 0 siblings, 1 reply; 149+ messages in thread From: Gaëtan Rivet @ 2018-03-28 13:26 UTC (permalink / raw) To: Rosen Xu Cc: dev, declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu On Wed, Mar 28, 2018 at 05:29:51PM +0800, Rosen Xu wrote: > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > --- > lib/librte_eal/common/eal_common_options.c | 8 +++++++- > lib/librte_eal/common/eal_options.h | 2 ++ > 2 files changed, 9 insertions(+), 1 deletion(-) > > diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c > index 9f2f8d2..4fe0875 100644 > --- a/lib/librte_eal/common/eal_common_options.c > +++ b/lib/librte_eal/common/eal_common_options.c > @@ -73,6 +73,7 @@ > {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, > {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, > {OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM }, > + {OPT_IFPGA, 1, NULL, OPT_IFPGA_NUM }, > {0, 0, NULL, 0 } > }; > > @@ -1160,7 +1161,12 @@ static int xdigit2val(unsigned char c) > > core_parsed = LCORE_OPT_MAP; > break; > - > + case OPT_IFPGA_NUM: > + if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL, > + optarg) < 0) { > + return -1; > + } > + break; why do you need to add a new option if you only insert a virtual devargs? Why wouldn't --vdev option work instead? and for that matter, I was expecting you to provide a PCI address. Can you give a command line showing how you create your device? The devtype is essentially ignored currently (at option stage, maybe there are still cruft left in PCI bus), instead the devargs parsing will detect the bus from the given optarg. This part of EAL will change rather soon, I'd prefer not to deal with additional options unless necessary. > /* don't know what to do, leave this to caller */ > default: > return 1; > diff --git a/lib/librte_eal/common/eal_options.h b/lib/librte_eal/common/eal_options.h > index e86c711..bdbb2c4 100644 > --- a/lib/librte_eal/common/eal_options.h > +++ b/lib/librte_eal/common/eal_options.h > @@ -55,6 +55,8 @@ enum { > OPT_VFIO_INTR_NUM, > #define OPT_VMWARE_TSC_MAP "vmware-tsc-map" > OPT_VMWARE_TSC_MAP_NUM, > +#define OPT_IFPGA "ifpga" > + OPT_IFPGA_NUM, > OPT_LONG_MAX_NUM > }; > > -- > 1.8.3.1 > -- Gaëtan Rivet 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 1/6] Add Intel FPGA BUS Command Parse Code 2018-03-28 13:26 ` Gaëtan Rivet @ 2018-03-31 16:25 ` Xu, Rosen 2018-04-04 1:58 ` Xu, Rosen 0 siblings, 1 reply; 149+ messages in thread From: Xu, Rosen @ 2018-03-31 16:25 UTC (permalink / raw) To: gaetan.rivet Cc: dev, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Zhang, Tianfei, Wu, Hao > -----Original Message----- > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com] > Sent: Wednesday, March 28, 2018 21:26 > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com> > Subject: Re: [PATCH v3 1/6] Add Intel FPGA BUS Command Parse Code > > On Wed, Mar 28, 2018 at 05:29:51PM +0800, Rosen Xu wrote: > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > --- > > lib/librte_eal/common/eal_common_options.c | 8 +++++++- > > lib/librte_eal/common/eal_options.h | 2 ++ > > 2 files changed, 9 insertions(+), 1 deletion(-) > > > > diff --git a/lib/librte_eal/common/eal_common_options.c > > b/lib/librte_eal/common/eal_common_options.c > > index 9f2f8d2..4fe0875 100644 > > --- a/lib/librte_eal/common/eal_common_options.c > > +++ b/lib/librte_eal/common/eal_common_options.c > > @@ -73,6 +73,7 @@ > > {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, > > {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, > > {OPT_VMWARE_TSC_MAP, 0, NULL, > OPT_VMWARE_TSC_MAP_NUM }, > > + {OPT_IFPGA, 1, NULL, OPT_IFPGA_NUM }, > > {0, 0, NULL, 0 } > > }; > > > > @@ -1160,7 +1161,12 @@ static int xdigit2val(unsigned char c) > > > > core_parsed = LCORE_OPT_MAP; > > break; > > - > > + case OPT_IFPGA_NUM: > > + if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL, > > + optarg) < 0) { > > + return -1; > > + } > > + break; > > why do you need to add a new option if you only insert a virtual devargs? > > Why wouldn't --vdev option work instead? and for that matter, I was > expecting you to provide a PCI address. Can you give a command line > showing how you create your device? The devtype is essentially ignored > currently (at option stage, maybe there are still cruft left in PCI bus), instead > the devargs parsing will detect the bus from the given optarg. > > This part of EAL will change rather soon, I'd prefer not to deal with additional > options unless necessary. For PATCH v4, I have removed all the modification from eal library. Create vdev to take IFPGA parameters configuration. The command line for PATCH v4 is(just take 2 AFU for example): testpmd -c 0x3 -n 4 --socket-mem 1024,0 --huge-dir=/mnt/huge \ --vdev 'net_ifpga_cfg0,bdf=5e:00.0,port=0,afu_bts=./xxx.gbs' \ --vdev 'net_ifpga_cfg1,bdf=be:00.0,port=0,afu_bts=./xxx.gbs' -- -i --no-numa Note: the parameter of "port" is used by OPAE for download bitstream. > > /* don't know what to do, leave this to caller */ > > default: > > return 1; > > diff --git a/lib/librte_eal/common/eal_options.h > > b/lib/librte_eal/common/eal_options.h > > index e86c711..bdbb2c4 100644 > > --- a/lib/librte_eal/common/eal_options.h > > +++ b/lib/librte_eal/common/eal_options.h > > @@ -55,6 +55,8 @@ enum { > > OPT_VFIO_INTR_NUM, > > #define OPT_VMWARE_TSC_MAP "vmware-tsc-map" > > OPT_VMWARE_TSC_MAP_NUM, > > +#define OPT_IFPGA "ifpga" > > + OPT_IFPGA_NUM, > > OPT_LONG_MAX_NUM > > }; > > > > -- > > 1.8.3.1 > > > > -- > Gaëtan Rivet > 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 1/6] Add Intel FPGA BUS Command Parse Code 2018-03-31 16:25 ` Xu, Rosen @ 2018-04-04 1:58 ` Xu, Rosen 0 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-04-04 1:58 UTC (permalink / raw) To: 'gaetan.rivet@6wind.com' Cc: 'dev@dpdk.org', Doherty, Declan, Richardson, Bruce, 'shreyansh.jain@nxp.com', Zhang, Tianfei, Wu, Hao Hello Gaetan, Are my answers ok? If so, could you reply it? Many thanks to you. > -----Original Message----- > From: Xu, Rosen > Sent: Sunday, April 01, 2018 0:26 > To: gaetan.rivet@6wind.com > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com> > Subject: RE: [PATCH v3 1/6] Add Intel FPGA BUS Command Parse Code > > > > > -----Original Message----- > > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com] > > Sent: Wednesday, March 28, 2018 21:26 > > To: Xu, Rosen <rosen.xu@intel.com> > > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > > Richardson, Bruce <bruce.richardson@intel.com>; > > shreyansh.jain@nxp.com; Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, > > Hao <hao.wu@intel.com> > > Subject: Re: [PATCH v3 1/6] Add Intel FPGA BUS Command Parse Code > > > > On Wed, Mar 28, 2018 at 05:29:51PM +0800, Rosen Xu wrote: > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > > --- > > > lib/librte_eal/common/eal_common_options.c | 8 +++++++- > > > lib/librte_eal/common/eal_options.h | 2 ++ > > > 2 files changed, 9 insertions(+), 1 deletion(-) > > > > > > diff --git a/lib/librte_eal/common/eal_common_options.c > > > b/lib/librte_eal/common/eal_common_options.c > > > index 9f2f8d2..4fe0875 100644 > > > --- a/lib/librte_eal/common/eal_common_options.c > > > +++ b/lib/librte_eal/common/eal_common_options.c > > > @@ -73,6 +73,7 @@ > > > {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, > > > {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, > > > {OPT_VMWARE_TSC_MAP, 0, NULL, > > OPT_VMWARE_TSC_MAP_NUM }, > > > + {OPT_IFPGA, 1, NULL, OPT_IFPGA_NUM }, > > > {0, 0, NULL, 0 } > > > }; > > > > > > @@ -1160,7 +1161,12 @@ static int xdigit2val(unsigned char c) > > > > > > core_parsed = LCORE_OPT_MAP; > > > break; > > > - > > > + case OPT_IFPGA_NUM: > > > + if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL, > > > + optarg) < 0) { > > > + return -1; > > > + } > > > + break; > > > > why do you need to add a new option if you only insert a virtual devargs? > > > > Why wouldn't --vdev option work instead? and for that matter, I was > > expecting you to provide a PCI address. Can you give a command line > > showing how you create your device? The devtype is essentially ignored > > currently (at option stage, maybe there are still cruft left in PCI > > bus), instead the devargs parsing will detect the bus from the given optarg. > > > > This part of EAL will change rather soon, I'd prefer not to deal with > > additional options unless necessary. > > For PATCH v4, I have removed all the modification from eal library. > Create vdev to take IFPGA parameters configuration. > > The command line for PATCH v4 is(just take 2 AFU for example): > testpmd -c 0x3 -n 4 --socket-mem 1024,0 --huge-dir=/mnt/huge \ --vdev > 'net_ifpga_cfg0,bdf=5e:00.0,port=0,afu_bts=./xxx.gbs' \ --vdev > 'net_ifpga_cfg1,bdf=be:00.0,port=0,afu_bts=./xxx.gbs' -- -i --no-numa > Note: the parameter of "port" is used by OPAE for download bitstream. > > > > /* don't know what to do, leave this to caller */ > > > default: > > > return 1; > > > diff --git a/lib/librte_eal/common/eal_options.h > > > b/lib/librte_eal/common/eal_options.h > > > index e86c711..bdbb2c4 100644 > > > --- a/lib/librte_eal/common/eal_options.h > > > +++ b/lib/librte_eal/common/eal_options.h > > > @@ -55,6 +55,8 @@ enum { > > > OPT_VFIO_INTR_NUM, > > > #define OPT_VMWARE_TSC_MAP "vmware-tsc-map" > > > OPT_VMWARE_TSC_MAP_NUM, > > > +#define OPT_IFPGA "ifpga" > > > + OPT_IFPGA_NUM, > > > OPT_LONG_MAX_NUM > > > }; > > > > > > -- > > > 1.8.3.1 > > > > > > > -- > > Gaëtan Rivet > > 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v3 2/6] config/common_base: Add Intel FPGA Build Configuration Macro 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 0/6] " Rosen Xu 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 1/6] Add Intel FPGA BUS Command Parse Code Rosen Xu @ 2018-03-28 9:29 ` Rosen Xu 2018-03-28 13:27 ` Gaëtan Rivet 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 3/6] mk/rte.app.mk: Add Intel FPGA Bus Build Configuration Macro To App Script Rosen Xu ` (5 subsequent siblings) 7 siblings, 1 reply; 149+ messages in thread From: Rosen Xu @ 2018-03-28 9:29 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu, gaetan.rivet Signed-off-by: Rosen Xu <rosen.xu@intel.com> --- config/common_base | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/common_base b/config/common_base index ad03cf4..08b7cce 100644 --- a/config/common_base +++ b/config/common_base @@ -134,6 +134,12 @@ CONFIG_RTE_LIBRTE_PCI_BUS=y CONFIG_RTE_LIBRTE_VDEV_BUS=y # +# Compile the Intel FPGA bus +# +CONFIG_RTE_LIBRTE_IFPGA_BUS=y +CONFIG_RTE_LIBRTE_IFPGA_RAWDEV=y + +# # Compile ARK PMD # CONFIG_RTE_LIBRTE_ARK_PMD=y -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 2/6] config/common_base: Add Intel FPGA Build Configuration Macro 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 2/6] config/common_base: Add Intel FPGA Build Configuration Macro Rosen Xu @ 2018-03-28 13:27 ` Gaëtan Rivet 2018-03-31 16:26 ` Xu, Rosen 2018-04-04 2:01 ` Xu, Rosen 0 siblings, 2 replies; 149+ messages in thread From: Gaëtan Rivet @ 2018-03-28 13:27 UTC (permalink / raw) To: Rosen Xu Cc: dev, declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu On Wed, Mar 28, 2018 at 05:29:52PM +0800, Rosen Xu wrote: > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > --- > config/common_base | 6 ++++++ > 1 file changed, 6 insertions(+) > > diff --git a/config/common_base b/config/common_base > index ad03cf4..08b7cce 100644 > --- a/config/common_base > +++ b/config/common_base > @@ -134,6 +134,12 @@ CONFIG_RTE_LIBRTE_PCI_BUS=y > CONFIG_RTE_LIBRTE_VDEV_BUS=y > > # > +# Compile the Intel FPGA bus > +# > +CONFIG_RTE_LIBRTE_IFPGA_BUS=y > +CONFIG_RTE_LIBRTE_IFPGA_RAWDEV=y > + > +# Please squash this patch with their relevant counterparts. As it is, this won't trigger an error but the patch is meaningless. > # Compile ARK PMD > # > CONFIG_RTE_LIBRTE_ARK_PMD=y > -- > 1.8.3.1 > -- Gaëtan Rivet 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 2/6] config/common_base: Add Intel FPGA Build Configuration Macro 2018-03-28 13:27 ` Gaëtan Rivet @ 2018-03-31 16:26 ` Xu, Rosen 2018-04-04 2:01 ` Xu, Rosen 1 sibling, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-03-31 16:26 UTC (permalink / raw) To: gaetan.rivet Cc: dev, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Zhang, Tianfei, Wu, Hao > -----Original Message----- > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com] > Sent: Wednesday, March 28, 2018 21:27 > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com> > Subject: Re: [PATCH v3 2/6] config/common_base: Add Intel FPGA Build > Configuration Macro > > On Wed, Mar 28, 2018 at 05:29:52PM +0800, Rosen Xu wrote: > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > --- > > config/common_base | 6 ++++++ > > 1 file changed, 6 insertions(+) > > > > diff --git a/config/common_base b/config/common_base index > > ad03cf4..08b7cce 100644 > > --- a/config/common_base > > +++ b/config/common_base > > @@ -134,6 +134,12 @@ CONFIG_RTE_LIBRTE_PCI_BUS=y > > CONFIG_RTE_LIBRTE_VDEV_BUS=y > > > > # > > +# Compile the Intel FPGA bus > > +# > > +CONFIG_RTE_LIBRTE_IFPGA_BUS=y > > +CONFIG_RTE_LIBRTE_IFPGA_RAWDEV=y > > + > > +# > > Please squash this patch with their relevant counterparts. > As it is, this won't trigger an error but the patch is meaningless. It's done by PATCH v4. > > # Compile ARK PMD > > # > > CONFIG_RTE_LIBRTE_ARK_PMD=y > > -- > > 1.8.3.1 > > > > -- > Gaëtan Rivet > 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 2/6] config/common_base: Add Intel FPGA Build Configuration Macro 2018-03-28 13:27 ` Gaëtan Rivet 2018-03-31 16:26 ` Xu, Rosen @ 2018-04-04 2:01 ` Xu, Rosen 1 sibling, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-04-04 2:01 UTC (permalink / raw) To: gaetan.rivet Cc: dev, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Zhang, Tianfei, Wu, Hao Hi Gaetan, I have squash this patch with their relevant counterparts. For PATCH v4 and later version CONFIG_RTE_LIBRTE_IFPGA_BUS is squashed with ifpga_bus driver, And CONFIG_RTE_LIBRTE_IFPGA_RAWDEV is squashed with ifpga_rawdev driver. Is it ok? > -----Original Message----- > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com] > Sent: Wednesday, March 28, 2018 21:27 > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com> > Subject: Re: [PATCH v3 2/6] config/common_base: Add Intel FPGA Build > Configuration Macro > > On Wed, Mar 28, 2018 at 05:29:52PM +0800, Rosen Xu wrote: > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > --- > > config/common_base | 6 ++++++ > > 1 file changed, 6 insertions(+) > > > > diff --git a/config/common_base b/config/common_base index > > ad03cf4..08b7cce 100644 > > --- a/config/common_base > > +++ b/config/common_base > > @@ -134,6 +134,12 @@ CONFIG_RTE_LIBRTE_PCI_BUS=y > > CONFIG_RTE_LIBRTE_VDEV_BUS=y > > > > # > > +# Compile the Intel FPGA bus > > +# > > +CONFIG_RTE_LIBRTE_IFPGA_BUS=y > > +CONFIG_RTE_LIBRTE_IFPGA_RAWDEV=y > > + > > +# > > Please squash this patch with their relevant counterparts. > As it is, this won't trigger an error but the patch is meaningless. > > > # Compile ARK PMD > > # > > CONFIG_RTE_LIBRTE_ARK_PMD=y > > -- > > 1.8.3.1 > > > > -- > Gaëtan Rivet > 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v3 3/6] mk/rte.app.mk: Add Intel FPGA Bus Build Configuration Macro To App Script 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 0/6] " Rosen Xu 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 1/6] Add Intel FPGA BUS Command Parse Code Rosen Xu 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 2/6] config/common_base: Add Intel FPGA Build Configuration Macro Rosen Xu @ 2018-03-28 9:29 ` Rosen Xu 2018-03-28 13:28 ` Gaëtan Rivet 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code Rosen Xu ` (4 subsequent siblings) 7 siblings, 1 reply; 149+ messages in thread From: Rosen Xu @ 2018-03-28 9:29 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu, gaetan.rivet Signed-off-by: Rosen Xu <rosen.xu@intel.com> --- mk/rte.app.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 3eb41d1..958b6b5 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -107,6 +107,9 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE) += -lrte_cmdline _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrte_sched +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += -lrte_ifpga_rawdev + ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 3/6] mk/rte.app.mk: Add Intel FPGA Bus Build Configuration Macro To App Script 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 3/6] mk/rte.app.mk: Add Intel FPGA Bus Build Configuration Macro To App Script Rosen Xu @ 2018-03-28 13:28 ` Gaëtan Rivet 2018-03-31 16:27 ` Xu, Rosen 2018-04-04 2:02 ` Xu, Rosen 0 siblings, 2 replies; 149+ messages in thread From: Gaëtan Rivet @ 2018-03-28 13:28 UTC (permalink / raw) To: Rosen Xu Cc: dev, declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu On Wed, Mar 28, 2018 at 05:29:53PM +0800, Rosen Xu wrote: > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > --- > mk/rte.app.mk | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/mk/rte.app.mk b/mk/rte.app.mk > index 3eb41d1..958b6b5 100644 > --- a/mk/rte.app.mk > +++ b/mk/rte.app.mk > @@ -107,6 +107,9 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE) += -lrte_cmdline > _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder > _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrte_sched > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += -lrte_ifpga_rawdev > + This however, should trigger a link error given that the relevant libraries are not yet available. Same as before, please squash with the patch introducing the libraries. > ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) > _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni > endif > -- > 1.8.3.1 > -- Gaëtan Rivet 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 3/6] mk/rte.app.mk: Add Intel FPGA Bus Build Configuration Macro To App Script 2018-03-28 13:28 ` Gaëtan Rivet @ 2018-03-31 16:27 ` Xu, Rosen 2018-04-04 2:02 ` Xu, Rosen 1 sibling, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-03-31 16:27 UTC (permalink / raw) To: gaetan.rivet Cc: dev, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Zhang, Tianfei, Wu, Hao > -----Original Message----- > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com] > Sent: Wednesday, March 28, 2018 21:29 > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com> > Subject: Re: [PATCH v3 3/6] mk/rte.app.mk: Add Intel FPGA Bus Build > Configuration Macro To App Script > > On Wed, Mar 28, 2018 at 05:29:53PM +0800, Rosen Xu wrote: > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > --- > > mk/rte.app.mk | 3 +++ > > 1 file changed, 3 insertions(+) > > > > diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 3eb41d1..958b6b5 > > 100644 > > --- a/mk/rte.app.mk > > +++ b/mk/rte.app.mk > > @@ -107,6 +107,9 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE) += - > lrte_cmdline > > _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder > > _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrte_sched > > > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += - > lrte_ifpga_rawdev > > + > > This however, should trigger a link error given that the relevant libraries are > not yet available. Same as before, please squash with the patch introducing > the libraries. It's done by PATCH v4. > > ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) > > _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni > > endif > > -- > > 1.8.3.1 > > > > -- > Gaëtan Rivet > 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 3/6] mk/rte.app.mk: Add Intel FPGA Bus Build Configuration Macro To App Script 2018-03-28 13:28 ` Gaëtan Rivet 2018-03-31 16:27 ` Xu, Rosen @ 2018-04-04 2:02 ` Xu, Rosen 1 sibling, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-04-04 2:02 UTC (permalink / raw) To: gaetan.rivet Cc: dev, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Zhang, Tianfei, Wu, Hao Hi Gaetan, > -----Original Message----- > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com] > Sent: Wednesday, March 28, 2018 21:29 > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com> > Subject: Re: [PATCH v3 3/6] mk/rte.app.mk: Add Intel FPGA Bus Build > Configuration Macro To App Script > > On Wed, Mar 28, 2018 at 05:29:53PM +0800, Rosen Xu wrote: > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > --- > > mk/rte.app.mk | 3 +++ > > 1 file changed, 3 insertions(+) > > > > diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 3eb41d1..958b6b5 > > 100644 > > --- a/mk/rte.app.mk > > +++ b/mk/rte.app.mk > > @@ -107,6 +107,9 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE) += - > lrte_cmdline > > _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder > > _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrte_sched > > > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += - > lrte_ifpga_rawdev > > + > > This however, should trigger a link error given that the relevant libraries are > not yet available. Same as before, please squash with the patch introducing > the libraries. I have fixed the link error comment in my PATCH v5. For squash comment I have fixed it in my PATCH v4. Are they ok? > > ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) > > _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni > > endif > > -- > > 1.8.3.1 > > > > -- > Gaëtan Rivet > 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 0/6] " Rosen Xu ` (2 preceding siblings ...) 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 3/6] mk/rte.app.mk: Add Intel FPGA Bus Build Configuration Macro To App Script Rosen Xu @ 2018-03-28 9:29 ` Rosen Xu 2018-03-28 13:52 ` Gaëtan Rivet 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 5/6] drivers/raw/ifpga_rawdev: Add Intel FPGA Rawdev Driver Code Rosen Xu ` (3 subsequent siblings) 7 siblings, 1 reply; 149+ messages in thread From: Rosen Xu @ 2018-03-28 9:29 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu, gaetan.rivet Signed-off-by: Rosen Xu <rosen.xu@intel.com> --- drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 33 ++ drivers/bus/ifpga/ifpga_bus.c | 562 ++++++++++++++++++++++++++++ drivers/bus/ifpga/ifpga_common.c | 141 +++++++ drivers/bus/ifpga/ifpga_common.h | 22 ++ drivers/bus/ifpga/ifpga_logs.h | 31 ++ drivers/bus/ifpga/rte_bus_ifpga.h | 140 +++++++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 8 + 8 files changed, 938 insertions(+) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index 7ef2593..55d2dfe 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -7,5 +7,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile new file mode 100644 index 0000000..e611950 --- /dev/null +++ b/drivers/bus/ifpga/Makefile @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2017 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_bus_ifpga.a + +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) + +# versioning export map +EXPORT_MAP := rte_bus_ifpga_version.map + +# library version +LIBABIVER := 1 + +VPATH += $(SRCDIR)/base + +SRCS-y += \ + ifpga_bus.c \ + ifpga_common.c + +LDLIBS += -lrte_eal + +# +# Export include files +# +SYMLINK-y-include += rte_bus_ifpga.h + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index 0000000..092be65 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -0,0 +1,562 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2017 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_bus_logtype; + +/* register a ifpga bus based driver */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver) +{ + RTE_VERIFY(driver); + + TAILQ_INSERT_TAIL(&rte_ifpga_bus.driver_list, driver, next); +} + +/* un-register a fpga bus based driver */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) +{ + TAILQ_REMOVE(&rte_ifpga_bus.driver_list, driver, next); +} + +static struct rte_ifpga_device * +ifpga_find_ifpga_dev(const struct rte_pci_addr *pci_addr) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { + if (!rte_pci_addr_cmp(&ifpga_dev->pci_addr, pci_addr)) + return ifpga_dev; + } + return NULL; +} + +static struct rte_afu_device * +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, + const struct rte_afu_id *afu_id) +{ + struct rte_afu_device *afu_dev = NULL; + + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) + return afu_dev; + } + return NULL; +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_BDF "bdf" + IFPGA_ARG_BDF, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_ARG_PATH "path" + IFPGA_ARG_PATH, +#define IFPGA_ARG_UUID_HIGH "uuid_high" + IFPGA_ARG_UUID_HIGH, +#define IFPGA_ARG_UUID_LOW "uuid_low" + IFPGA_ARG_UUID_LOW, +#define IFPGA_ARG_PR_ENABLE "pr_enable" + IFPGA_ARG_PR_ENABLE, +#define IFPGA_ARG_DEBUG "debug" + IFPGA_ARG_DEBUG, + NULL +}; + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static struct rte_afu_device * +rte_ifpga_scan_one(struct rte_devargs *devargs, + struct rte_ifpga_device *ifpga_dev) +{ + struct rte_kvargs *kvlist = NULL; + struct rte_bus *pci_bus = NULL; + struct rte_device *dev = NULL; + struct rte_rawdev *rawdev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_afu_pr_conf afu_pr_conf; + int ret = 0; + char *path = NULL; + int pr_enable = 1; + int debug = 0; + + memset((char *)(&afu_pr_conf), 0, sizeof(struct rte_afu_pr_conf)); + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, + &ifpga_get_bdf_arg, &afu_pr_conf.afu_id.pci_addr) < 0) { + IFPGA_BUS_ERR("error to parse %s", IFPGA_ARG_BDF); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PATH); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PATH); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PATH) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PATH, + &ifpga_get_string_arg, &path) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_PATH); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PATH); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_UUID_HIGH) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_UUID_HIGH, + &ifpga_get_integer64_arg, &afu_pr_conf.afu_id.uuid_high) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_UUID_HIGH); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PATH); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_UUID_LOW) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_UUID_LOW, + &ifpga_get_integer64_arg, &afu_pr_conf.afu_id.uuid_low) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_UUID_LOW); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PATH); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PR_ENABLE) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PR_ENABLE, + &ifpga_get_integer32_arg, &pr_enable) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_UUID_HIGH); + goto end; + } + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_DEBUG) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_DEBUG, + &ifpga_get_integer32_arg, &debug) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_UUID_HIGH); + goto end; + } + } + + if (!debug) { + pci_bus = rte_bus_find_by_name("pci"); + if (pci_bus == NULL) { + IFPGA_BUS_ERR("unable to find PCI bus\n"); + goto end; + } + + dev = pci_bus->find_device(NULL, + ifpga_pci_addr_cmp, + &afu_pr_conf.afu_id.pci_addr); + if (dev == NULL) { + IFPGA_BUS_ERR("unable to find PCI device\n"); + goto end; + } + } else { + IFPGA_BUS_DEBUG("pci_addr domain : %x\n", + afu_pr_conf.afu_id.pci_addr.domain); + IFPGA_BUS_DEBUG("pci_addr bus : %x\n", + afu_pr_conf.afu_id.pci_addr.bus); + IFPGA_BUS_DEBUG("pci_addr devid : %x\n", + afu_pr_conf.afu_id.pci_addr.devid); + IFPGA_BUS_DEBUG("pci_addr function : %x\n", + afu_pr_conf.afu_id.pci_addr.function); + IFPGA_BUS_DEBUG("uuid_low : %lx\n", + afu_pr_conf.afu_id.uuid_low); + IFPGA_BUS_DEBUG("uuid_high : %lx\n", + afu_pr_conf.afu_id.uuid_high); + IFPGA_BUS_DEBUG("afu port : %x\n", + afu_pr_conf.afu_id.port); + } + + rawdev = ifpga_dev->rdev; + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) + goto end; + + afu_dev = calloc(1, sizeof(*afu_dev)); + if (!afu_dev) + goto end; + + afu_dev->device.devargs = devargs; + afu_dev->device.numa_node = SOCKET_ID_ANY; + afu_dev->device.name = devargs->name; + afu_dev->rawdev = rawdev; + afu_dev->id.pci_addr.domain = afu_pr_conf.afu_id.pci_addr.domain; + afu_dev->id.pci_addr.bus = afu_pr_conf.afu_id.pci_addr.bus; + afu_dev->id.pci_addr.devid = afu_pr_conf.afu_id.pci_addr.devid; + afu_dev->id.pci_addr.function = afu_pr_conf.afu_id.pci_addr.function; + afu_dev->id.uuid_low = afu_pr_conf.afu_id.uuid_low; + afu_dev->id.uuid_high = afu_pr_conf.afu_id.uuid_high; + afu_dev->id.port = afu_pr_conf.afu_id.port; + afu_dev->ifpga_dev = ifpga_dev; + + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); + + if (rawdev->dev_ops && + rawdev->dev_ops->dev_start && + rawdev->dev_ops->dev_start(rawdev)) + goto free_dev; + if (pr_enable) { + strncpy(afu_pr_conf.bs_path, path, strlen(path)); + if (rawdev->dev_ops->firmware_load && + rawdev->dev_ops->firmware_load(rawdev, + &afu_pr_conf)){ + printf("firmware load error %d\n", ret); + goto free_dev; + } + } + + return afu_dev; + +free_dev: + free(afu_dev); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (path) + free(path); + + return NULL; +} + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static int +rte_ifpga_scan(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + struct rte_pci_addr pci_addr; + struct rte_rawdev *rawdev = NULL; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + struct rte_afu_device *afu_dev = NULL; + + /* for FPGA devices we scan the devargs_list populated via cmdline */ + TAILQ_FOREACH(devargs, &devargs_list, next) { + if (devargs->bus != &rte_ifpga_bus.bus) + continue; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, + &ifpga_get_bdf_arg, &pci_addr) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_BDF); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PATH); + goto end; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%x:%x", + pci_addr.bus, pci_addr.devid, pci_addr.function); + + rawdev = rte_rawdev_pmd_get_named_dev(name); + if (!rawdev) + goto end; + + if (ifpga_find_ifpga_dev(&pci_addr)) + goto end; + + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); + if (!ifpga_dev) + goto end; + + ifpga_dev->pci_addr.domain = pci_addr.domain; + ifpga_dev->pci_addr.bus = pci_addr.bus; + ifpga_dev->pci_addr.devid = pci_addr.devid; + ifpga_dev->pci_addr.function = pci_addr.function; + ifpga_dev->rdev = rawdev; + TAILQ_INIT(&ifpga_dev->afu_list); + + TAILQ_INSERT_TAIL(&rte_ifpga_bus.ifpga_list, ifpga_dev, next); + afu_dev = rte_ifpga_scan_one(devargs, ifpga_dev); + if (afu_dev != NULL) + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, next); + } + +end: + if (kvlist) + rte_kvargs_free(kvlist); + + return 0; +} + +static int +ifpga_probe_one_driver(struct rte_afu_driver *drv, + struct rte_afu_device *afu_dev) +{ + int ret; + + if ((drv->id.pci_addr.bus == afu_dev->id.pci_addr.bus) && + (drv->id.pci_addr.devid == afu_dev->id.pci_addr.devid) && + (drv->id.pci_addr.function == afu_dev->id.pci_addr.function) && + (drv->id.uuid_low == afu_dev->id.uuid_low) && + (drv->id.uuid_high == afu_dev->id.uuid_high) && + (drv->id.port == afu_dev->id.port)) { + + afu_dev->driver = drv; + + /* call the driver probe() function */ + ret = drv->probe(afu_dev); + if (ret) + afu_dev->driver = NULL; + return ret; + } + + /* return positive value if driver doesn't support this device */ + return 1; +} + +static int +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) +{ + const char *name; + struct rte_afu_driver *drv = NULL; + int rc; + + if (afu_dev == NULL) + return -1; + + /* Check if a driver is already loaded */ + if (afu_dev->driver != NULL) + return 0; + + name = rte_ifpga_device_name(afu_dev); + IFPGA_BUS_DEBUG("Search driver %s to probe device %s\n", name, + rte_ifpga_device_name(afu_dev)); + + TAILQ_FOREACH(drv, &rte_ifpga_bus.driver_list, next) { + rc = ifpga_probe_one_driver(drv, afu_dev); + if (rc < 0) + /* negative value is an error */ + return -1; + if (rc > 0) + /* positive value means driver doesn't support it */ + continue; + return 0; + } + return 1; +} + +/* + * Scan the content of the PCI bus, and call the probe() function for + * all registered drivers that have a matching entry in its id_table + * for discovered devices. + */ +static int +rte_ifpga_probe(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev = NULL; + int ret = 0; + + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + + if (afu_dev->device.driver) + continue; + + ret = ifpga_probe_all_drivers(afu_dev); + if (ret < 0) + IFPGA_BUS_ERR("failed to initialize %s device\n", + rte_ifpga_device_name(afu_dev)); + } + } + + return 0; +} + +static int +rte_ifpga_plug(struct rte_device *dev) +{ + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); +} + +static int ifpga_remove_driver(struct rte_afu_device *afu_dev) +{ + const char *name; + const struct rte_afu_driver *driver; + + name = rte_ifpga_device_name(afu_dev); + if (!afu_dev->device.driver) { + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); + return 1; + } + + driver = container_of(afu_dev->device.driver, + const struct rte_afu_driver, + driver); + return driver->remove(afu_dev); +} + +static int +rte_ifpga_unplug(struct rte_device *dev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_devargs *devargs = NULL; + int ret; + + if (dev == NULL) + return -EINVAL; + + afu_dev = RTE_DEV_TO_AFU(dev); + if (!dev) + return -ENOENT; + + ifpga_dev = afu_dev->ifpga_dev; + devargs = dev->devargs; + + ret = ifpga_remove_driver(afu_dev); + if (ret) + return ret; + + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); + + TAILQ_REMOVE(&devargs_list, devargs, next); + + free(devargs->args); + free(devargs); + free(afu_dev); + return 0; + +} + +static struct rte_device * +rte_ifpga_find_device(const struct rte_device *start, + rte_dev_cmp_t cmp, const void *data) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev; + + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (start && &afu_dev->device == start) { + start = NULL; + continue; + } + if (cmp(&afu_dev->device, data) == 0) + return &afu_dev->device; + } + } + return NULL; +} +static int +rte_ifpga_parse(const char *name, void *addr) +{ + struct rte_afu_driver **out = addr; + struct rte_afu_driver *driver = NULL; + + TAILQ_FOREACH(driver, &rte_ifpga_bus.driver_list, next) { + if (strncmp(driver->driver.name, name, + strlen(driver->driver.name)) == 0) + break; + if (driver->driver.alias && + strncmp(driver->driver.alias, name, + strlen(driver->driver.alias)) == 0) + break; + } + if (driver != NULL && + addr != NULL) + *out = driver; + return driver == NULL; +} + +struct rte_ifpga_bus rte_ifpga_bus = { + .bus = { + .scan = rte_ifpga_scan, + .probe = rte_ifpga_probe, + .find_device = rte_ifpga_find_device, + .plug = rte_ifpga_plug, + .unplug = rte_ifpga_unplug, + .parse = rte_ifpga_parse, + }, + .ifpga_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.ifpga_list), + .driver_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.driver_list), +}; + +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus.bus); + +RTE_INIT(ifpga_init_log) +{ + ifpga_bus_logtype = rte_log_register("bus.ifpga"); + if (ifpga_bus_logtype >= 0) + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); +} + diff --git a/drivers/bus/ifpga/ifpga_common.c b/drivers/bus/ifpga/ifpga_common.c new file mode 100644 index 0000000..03a8d48 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.c @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2017 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(char **)extra_args = strdup(value); + + if (!*(char **)extra_args) + return -ENOMEM; + + return 0; +} +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(int *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(uint64_t *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_unsigned_long(const char *str, int base) +{ + unsigned long num; + char *end = NULL; + + errno = 0; + + num = strtoul(str, &end, base); + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) + return -1; + + return num; + +} +int ifpga_get_bdf_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ +#define MAX_PATH_LEN 1024 + struct rte_pci_addr *addr; + int num[4]; + char str[MAX_PATH_LEN]; + int i, j; + + if (!value || !extra_args) + return -EINVAL; + + addr = (struct rte_pci_addr *)extra_args; + strcpy(str, value); + memset(num, 0, 4 * sizeof(num[0])); + i = strlen(str) - 1; + j = 3; + while (i > 0 && j >= 0) { + while ((str[i - 1] != ':' && str[i - 1] != '.') && i > 0) + i--; + num[j--] = ifpga_get_unsigned_long(&str[i], 16); + i--; + if (i >= 0) + str[i] = '\0'; + } + addr->domain = num[0]; + addr->bus = num[1]; + addr->devid = num[2]; + addr->function = num[3]; + printf("[%s]: bdf %04d:%02d:%02d.%02d\n", + __func__, + addr->domain, + addr->bus, + addr->devid, + addr->function); + + return 0; +} + +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1) +{ + if ((afu_id0->pci_addr.bus == afu_id1->pci_addr.bus) && + (afu_id0->pci_addr.devid == afu_id1->pci_addr.devid) && + (afu_id0->pci_addr.function == afu_id1->pci_addr.function) && + (afu_id0->uuid_low == afu_id1->uuid_low) && + (afu_id0->uuid_high == afu_id1->uuid_high) && + (afu_id0->port == afu_id1->port)) { + return 0; + } else + return 1; +} +int ifpga_pci_addr_cmp(const struct rte_device *dev, + const void *_pci_addr) +{ + struct rte_pci_device *pdev; + const struct rte_pci_addr *paddr = _pci_addr; + + pdev = RTE_DEV_TO_PCI(*(struct rte_device **)(void *)&dev); + return rte_eal_compare_pci_addr(&pdev->addr, paddr); +} diff --git a/drivers/bus/ifpga/ifpga_common.h b/drivers/bus/ifpga/ifpga_common.h new file mode 100644 index 0000000..48a5012 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2017 Intel Corporation + */ + +#ifndef _IFPGA_COMMON_H_ +#define _IFPGA_COMMON_H_ + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_unsigned_long(const char *str, int base); +int ifpga_get_bdf_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1); +int ifpga_pci_addr_cmp(const struct rte_device *dev, + const void *_pci_addr); + +#endif /* _IFPGA_COMMON_H_ */ diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index 0000000..e3f4849 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_logs.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2017 Intel Corporation + */ + +#ifndef _IFPGA_LOGS_H_ +#define _IFPGA_LOGS_H_ + +#include <rte_log.h> + +extern int ifpga_bus_logtype; + +#define IFPGA_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") + +#define IFPGA_BUS_DEBUG(fmt, args...) \ + IFPGA_BUS_LOG(DEBUG, fmt, ## args) +#define IFPGA_BUS_INFO(fmt, args...) \ + IFPGA_BUS_LOG(INFO, fmt, ## args) +#define IFPGA_BUS_ERR(fmt, args...) \ + IFPGA_BUS_LOG(ERR, fmt, ## args) +#define IFPGA_BUS_WARN(fmt, args...) \ + IFPGA_BUS_LOG(WARNING, fmt, ## args) + +#endif /* _IFPGA_BUS_LOGS_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h new file mode 100644 index 0000000..7290149 --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2017 Intel Corporation + */ + +#ifndef _RTE_BUS_IFPGA_H_ +#define _RTE_BUS_IFPGA_H_ + +/** + * @file + * + * RTE PCI Bus Interface + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_bus.h> +#include <rte_pci.h> + +/** Name of Intel FPGA Bus */ +#define IFPGA_BUS_NAME ifpga + +/* Forward declarations */ +struct rte_ifpga_device; +struct rte_afu_device; +struct rte_afu_driver; + +/** List of Intel FPGA devices */ +TAILQ_HEAD(rte_ifpga_device_list, rte_ifpga_device); +/** List of Intel AFU devices */ +TAILQ_HEAD(rte_afu_device_list, rte_afu_device); +/** List of AFU drivers */ +TAILQ_HEAD(rte_afu_driver_list, rte_afu_driver); + +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 + +/** + * A structure describing an ID for a AFU driver. Each driver provides a + * table of these IDs for each device that it supports. + */ +struct rte_afu_id { + struct rte_pci_addr pci_addr; + uint64_t uuid_low; + uint64_t uuid_high; + int port; +} __attribute__ ((packed)); + +/** + * A structure pr configuration AFU driver. + */ + +struct rte_afu_pr_conf { + struct rte_afu_id afu_id; + int pr_enable; + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +}; + +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) + +/** + * A structure describing a fpga device. + */ +struct rte_ifpga_device { + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ + struct rte_pci_addr pci_addr; + struct rte_rawdev *rdev; + struct rte_afu_device_list afu_list; /**< List of AFU devices */ +}; + +/** + * A structure describing a AFU device. + */ +struct rte_afu_device { + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ + struct rte_device device; /**< Inherit core device */ + struct rte_rawdev *rawdev; /**< Point Rawdev */ + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ + struct rte_afu_id id; /**< AFU id within FPGA. */ + uint32_t num_region; /**< number of regions found */ + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; + /**< PCI Memory Resource */ + struct rte_intr_handle intr_handle; /**< Interrupt handle */ + struct rte_afu_driver *driver; /**< Associated driver */ + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +} __attribute__ ((packed)); + +/** + * @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) + +/** + * Initialisation function for the driver called during PCI probing. + */ +typedef int (afu_probe_t)(struct rte_afu_device *); + +/** + * Uninitialisation function for the driver called during hotplugging. + */ +typedef int (afu_remove_t)(struct rte_afu_device *); + +/** + * A structure describing a PCI device. + */ +struct rte_afu_driver { + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ + struct rte_driver driver; /**< Inherit core driver. */ + afu_probe_t *probe; /**< Device Probe function. */ + afu_remove_t *remove; /**< Device Remove function. */ + struct rte_afu_id id; /**< AFU id within FPGA. */ + uint32_t drv_flags; /**< Flags contolling handling of device. */ +}; + +/** + * Structure describing the Intel FPGA bus + */ +struct rte_ifpga_bus { + struct rte_bus bus; /**< Inherit the generic class */ + struct rte_ifpga_device_list ifpga_list; /**< List of FPGA devices */ + struct rte_afu_driver_list driver_list; /**< List of FPGA drivers */ +}; + +static inline const char * +rte_ifpga_device_name(const struct rte_afu_device *afu) +{ + if (afu && afu->device.name) + return afu->device.name; + return NULL; +} + +extern struct rte_ifpga_bus rte_ifpga_bus; + +void rte_ifpga_driver_register(struct rte_afu_driver *driver); +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); + + +#endif /* _RTE_BUS_IFPGA_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map new file mode 100644 index 0000000..4edc9c0 --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map @@ -0,0 +1,8 @@ +DPDK_18.05 { + global: + + rte_ifpga_driver_register; + rte_ifpga_driver_unregister; + + local: *; +}; -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code Rosen Xu @ 2018-03-28 13:52 ` Gaëtan Rivet 2018-03-31 16:31 ` Xu, Rosen 2018-04-04 4:01 ` Xu, Rosen 0 siblings, 2 replies; 149+ messages in thread From: Gaëtan Rivet @ 2018-03-28 13:52 UTC (permalink / raw) To: Rosen Xu Cc: dev, declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu On Wed, Mar 28, 2018 at 05:29:54PM +0800, Rosen Xu wrote: > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > --- > drivers/bus/Makefile | 1 + > drivers/bus/ifpga/Makefile | 33 ++ > drivers/bus/ifpga/ifpga_bus.c | 562 ++++++++++++++++++++++++++++ > drivers/bus/ifpga/ifpga_common.c | 141 +++++++ > drivers/bus/ifpga/ifpga_common.h | 22 ++ > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > drivers/bus/ifpga/rte_bus_ifpga.h | 140 +++++++ > drivers/bus/ifpga/rte_bus_ifpga_version.map | 8 + > 8 files changed, 938 insertions(+) > create mode 100644 drivers/bus/ifpga/Makefile > create mode 100644 drivers/bus/ifpga/ifpga_bus.c > create mode 100644 drivers/bus/ifpga/ifpga_common.c > create mode 100644 drivers/bus/ifpga/ifpga_common.h > create mode 100644 drivers/bus/ifpga/ifpga_logs.h > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map > > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile > index 7ef2593..55d2dfe 100644 > --- a/drivers/bus/Makefile > +++ b/drivers/bus/Makefile > @@ -7,5 +7,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa > DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > > include $(RTE_SDK)/mk/rte.subdir.mk > diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile > new file mode 100644 > index 0000000..e611950 > --- /dev/null > +++ b/drivers/bus/ifpga/Makefile > @@ -0,0 +1,33 @@ > +# SPDX-License-Identifier: BSD-3-Clause > +# Copyright(c) 2017 Intel Corporation Copyrigth 2018 (same comment for most SPDX tags, I think I saw 2017 or a variation of it everywhere I think). > + > +include $(RTE_SDK)/mk/rte.vars.mk > + > +# > +# library name > +# > +LIB = librte_bus_ifpga.a > + > +CFLAGS += -O3 > +CFLAGS += $(WERROR_FLAGS) > + > +# versioning export map > +EXPORT_MAP := rte_bus_ifpga_version.map > + > +# library version > +LIBABIVER := 1 > + > +VPATH += $(SRCDIR)/base > + > +SRCS-y += \ > + ifpga_bus.c \ > + ifpga_common.c > + > +LDLIBS += -lrte_eal you should probably load librte_pci. You use afterward functions (at least address comparison). I haven't tested the SHARED build, but my guess is that it would break. On that note, you haven't acted on my previous remarks to use the common PCI utilities provided. > + > +# > +# Export include files > +# > +SYMLINK-y-include += rte_bus_ifpga.h > + > +include $(RTE_SDK)/mk/rte.lib.mk > diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c > new file mode 100644 > index 0000000..092be65 > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_bus.c > @@ -0,0 +1,562 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2017 Intel Corporation > + */ > + > +#include <string.h> > +#include <inttypes.h> > +#include <stdint.h> > +#include <stdlib.h> > +#include <stdio.h> > +#include <sys/queue.h> > +#include <sys/mman.h> > +#include <sys/types.h> > +#include <unistd.h> > +#include <fcntl.h> > + > +#include <rte_errno.h> > +#include <rte_bus.h> > +#include <rte_per_lcore.h> > +#include <rte_memory.h> > +#include <rte_memzone.h> > +#include <rte_eal.h> > +#include <rte_common.h> > + > +#include <rte_devargs.h> > +#include <rte_pci.h> > +#include <rte_bus_pci.h> > +#include <rte_kvargs.h> > +#include <rte_alarm.h> > + > +#include "rte_rawdev.h" > +#include "rte_rawdev_pmd.h" > +#include "rte_bus_ifpga.h" > +#include "ifpga_logs.h" > +#include "ifpga_common.h" > + > +int ifpga_bus_logtype; > + > +/* register a ifpga bus based driver */ > +void rte_ifpga_driver_register(struct rte_afu_driver *driver) > +{ > + RTE_VERIFY(driver); > + > + TAILQ_INSERT_TAIL(&rte_ifpga_bus.driver_list, driver, next); > +} > + > +/* un-register a fpga bus based driver */ > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) > +{ > + TAILQ_REMOVE(&rte_ifpga_bus.driver_list, driver, next); > +} > + > +static struct rte_ifpga_device * > +ifpga_find_ifpga_dev(const struct rte_pci_addr *pci_addr) > +{ > + struct rte_ifpga_device *ifpga_dev = NULL; > + > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > + if (!rte_pci_addr_cmp(&ifpga_dev->pci_addr, pci_addr)) > + return ifpga_dev; > + } > + return NULL; > +} > + > +static struct rte_afu_device * > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > + const struct rte_afu_id *afu_id) > +{ > + struct rte_afu_device *afu_dev = NULL; > + > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > + return afu_dev; > + } > + return NULL; > +} > + > +static const char * const valid_args[] = { > +#define IFPGA_ARG_BDF "bdf" > + IFPGA_ARG_BDF, > +#define IFPGA_ARG_PORT "port" > + IFPGA_ARG_PORT, > +#define IFPGA_ARG_PATH "path" > + IFPGA_ARG_PATH, > +#define IFPGA_ARG_UUID_HIGH "uuid_high" > + IFPGA_ARG_UUID_HIGH, > +#define IFPGA_ARG_UUID_LOW "uuid_low" > + IFPGA_ARG_UUID_LOW, > +#define IFPGA_ARG_PR_ENABLE "pr_enable" > + IFPGA_ARG_PR_ENABLE, > +#define IFPGA_ARG_DEBUG "debug" > + IFPGA_ARG_DEBUG, > + NULL > +}; So these parameters are parsed during scan afterward, taken from the PCI device that was probed. Given the kerfuffle of the VIRTUAL devtype in the EAL option, I'm not sure how the PCI bus would react with your IFPGA PCI device being probed by its blacklist operation: the devargs would be null. Do you segfault during your scan? Have you tested this? Why are those parameters parsed again here on this note? Shouldn't they be parsed by the PCI device being probed with a custome PCI driver that you would have added (and I think you provide it afterward), that would spawn the rawdev with the relevant metadata? Then you could scan this rawdev here and have all these parameters already parsed? Is there a reason that you did all this in this order? (specific initialization step for example?) > + > +/* > + * Scan the content of the FPGA bus, and the devices in the devices > + * list > + */ > +static struct rte_afu_device * > +rte_ifpga_scan_one(struct rte_devargs *devargs, > + struct rte_ifpga_device *ifpga_dev) > +{ > + struct rte_kvargs *kvlist = NULL; > + struct rte_bus *pci_bus = NULL; > + struct rte_device *dev = NULL; > + struct rte_rawdev *rawdev = NULL; > + struct rte_afu_device *afu_dev = NULL; > + struct rte_afu_pr_conf afu_pr_conf; > + int ret = 0; > + char *path = NULL; > + int pr_enable = 1; > + int debug = 0; > + > + memset((char *)(&afu_pr_conf), 0, sizeof(struct rte_afu_pr_conf)); > + > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > + if (!kvlist) { > + IFPGA_BUS_ERR("error when parsing param"); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, > + &ifpga_get_bdf_arg, &afu_pr_conf.afu_id.pci_addr) < 0) { > + IFPGA_BUS_ERR("error to parse %s", IFPGA_ARG_BDF); > + goto end; > + } > + } else { > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_ARG_PATH); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, > + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { > + IFPGA_BUS_ERR("error to parse %s", > + IFPGA_ARG_PORT); > + goto end; > + } > + } else { > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_ARG_PATH); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PATH) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PATH, > + &ifpga_get_string_arg, &path) < 0) { > + IFPGA_BUS_ERR("error to parse %s", > + IFPGA_ARG_PATH); > + goto end; > + } > + } else { > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_ARG_PATH); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_UUID_HIGH) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_ARG_UUID_HIGH, > + &ifpga_get_integer64_arg, &afu_pr_conf.afu_id.uuid_high) < 0) { > + IFPGA_BUS_ERR("error to parse %s", > + IFPGA_ARG_UUID_HIGH); > + goto end; > + } > + } else { > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_ARG_PATH); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_UUID_LOW) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_ARG_UUID_LOW, > + &ifpga_get_integer64_arg, &afu_pr_conf.afu_id.uuid_low) < 0) { > + IFPGA_BUS_ERR("error to parse %s", > + IFPGA_ARG_UUID_LOW); > + goto end; > + } > + } else { > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_ARG_PATH); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PR_ENABLE) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PR_ENABLE, > + &ifpga_get_integer32_arg, &pr_enable) < 0) { > + IFPGA_BUS_ERR("error to parse %s", > + IFPGA_ARG_UUID_HIGH); > + goto end; > + } > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_DEBUG) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_ARG_DEBUG, > + &ifpga_get_integer32_arg, &debug) < 0) { > + IFPGA_BUS_ERR("error to parse %s", > + IFPGA_ARG_UUID_HIGH); > + goto end; > + } > + } > + > + if (!debug) { > + pci_bus = rte_bus_find_by_name("pci"); > + if (pci_bus == NULL) { > + IFPGA_BUS_ERR("unable to find PCI bus\n"); > + goto end; > + } > + > + dev = pci_bus->find_device(NULL, > + ifpga_pci_addr_cmp, > + &afu_pr_conf.afu_id.pci_addr); > + if (dev == NULL) { > + IFPGA_BUS_ERR("unable to find PCI device\n"); > + goto end; > + } > + } else { > + IFPGA_BUS_DEBUG("pci_addr domain : %x\n", > + afu_pr_conf.afu_id.pci_addr.domain); > + IFPGA_BUS_DEBUG("pci_addr bus : %x\n", > + afu_pr_conf.afu_id.pci_addr.bus); > + IFPGA_BUS_DEBUG("pci_addr devid : %x\n", > + afu_pr_conf.afu_id.pci_addr.devid); > + IFPGA_BUS_DEBUG("pci_addr function : %x\n", > + afu_pr_conf.afu_id.pci_addr.function); > + IFPGA_BUS_DEBUG("uuid_low : %lx\n", > + afu_pr_conf.afu_id.uuid_low); > + IFPGA_BUS_DEBUG("uuid_high : %lx\n", > + afu_pr_conf.afu_id.uuid_high); > + IFPGA_BUS_DEBUG("afu port : %x\n", > + afu_pr_conf.afu_id.port); > + } > + > + rawdev = ifpga_dev->rdev; > + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) > + goto end; > + > + afu_dev = calloc(1, sizeof(*afu_dev)); > + if (!afu_dev) > + goto end; > + > + afu_dev->device.devargs = devargs; > + afu_dev->device.numa_node = SOCKET_ID_ANY; > + afu_dev->device.name = devargs->name; > + afu_dev->rawdev = rawdev; > + afu_dev->id.pci_addr.domain = afu_pr_conf.afu_id.pci_addr.domain; > + afu_dev->id.pci_addr.bus = afu_pr_conf.afu_id.pci_addr.bus; > + afu_dev->id.pci_addr.devid = afu_pr_conf.afu_id.pci_addr.devid; > + afu_dev->id.pci_addr.function = afu_pr_conf.afu_id.pci_addr.function; Can you add a function called rte_pci_addr_cpy in librte_pci and use it instead of doing this by hand here? Others would benefit from this. > + afu_dev->id.uuid_low = afu_pr_conf.afu_id.uuid_low; > + afu_dev->id.uuid_high = afu_pr_conf.afu_id.uuid_high; > + afu_dev->id.port = afu_pr_conf.afu_id.port; > + afu_dev->ifpga_dev = ifpga_dev; > + > + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) > + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); > + > + if (rawdev->dev_ops && > + rawdev->dev_ops->dev_start && > + rawdev->dev_ops->dev_start(rawdev)) > + goto free_dev; > + if (pr_enable) { > + strncpy(afu_pr_conf.bs_path, path, strlen(path)); strncpy is dangerous here, please use strlcpy or snprintf. (And your use of strncpy is dangerous, you are limitting the write to the length of the source, not to the size of the destination.) > + if (rawdev->dev_ops->firmware_load && > + rawdev->dev_ops->firmware_load(rawdev, > + &afu_pr_conf)){ > + printf("firmware load error %d\n", ret); > + goto free_dev; > + } > + } > + > + return afu_dev; > + > +free_dev: > + free(afu_dev); > +end: > + if (kvlist) > + rte_kvargs_free(kvlist); > + if (path) > + free(path); > + > + return NULL; > +} > + > +/* > + * Scan the content of the FPGA bus, and the devices in the devices > + * list > + */ > +static int > +rte_ifpga_scan(void) > +{ > + struct rte_ifpga_device *ifpga_dev; > + struct rte_devargs *devargs; > + struct rte_kvargs *kvlist = NULL; > + struct rte_pci_addr pci_addr; > + struct rte_rawdev *rawdev = NULL; > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > + struct rte_afu_device *afu_dev = NULL; > + > + /* for FPGA devices we scan the devargs_list populated via cmdline */ > + TAILQ_FOREACH(devargs, &devargs_list, next) { > + if (devargs->bus != &rte_ifpga_bus.bus) > + continue; > + > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > + if (!kvlist) { > + IFPGA_BUS_ERR("error when parsing param"); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, > + &ifpga_get_bdf_arg, &pci_addr) < 0) { > + IFPGA_BUS_ERR("error to parse %s", > + IFPGA_ARG_BDF); > + goto end; > + } > + } else { > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_ARG_PATH); > + goto end; > + } > + > + memset(name, 0, sizeof(name)); > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%x:%x", > + pci_addr.bus, pci_addr.devid, pci_addr.function); > + > + rawdev = rte_rawdev_pmd_get_named_dev(name); > + if (!rawdev) > + goto end; > + > + if (ifpga_find_ifpga_dev(&pci_addr)) > + goto end; > + > + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); > + if (!ifpga_dev) > + goto end; > + > + ifpga_dev->pci_addr.domain = pci_addr.domain; > + ifpga_dev->pci_addr.bus = pci_addr.bus; > + ifpga_dev->pci_addr.devid = pci_addr.devid; > + ifpga_dev->pci_addr.function = pci_addr.function; Again, PCI copy would be nice instead of doing it by hand. > + ifpga_dev->rdev = rawdev; > + TAILQ_INIT(&ifpga_dev->afu_list); > + > + TAILQ_INSERT_TAIL(&rte_ifpga_bus.ifpga_list, ifpga_dev, next); > + afu_dev = rte_ifpga_scan_one(devargs, ifpga_dev); > + if (afu_dev != NULL) > + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, next); > + } > + > +end: > + if (kvlist) > + rte_kvargs_free(kvlist); > + > + return 0; > +} > + > +static int > +ifpga_probe_one_driver(struct rte_afu_driver *drv, > + struct rte_afu_device *afu_dev) > +{ > + int ret; > + > + if ((drv->id.pci_addr.bus == afu_dev->id.pci_addr.bus) && > + (drv->id.pci_addr.devid == afu_dev->id.pci_addr.devid) && > + (drv->id.pci_addr.function == afu_dev->id.pci_addr.function) && There is the rte_pci_addr_cmp function that should be used here instead. Additionally, you haven't responded to my comment about ignoring the Domain part of the address. Why? Is there a reason for this? Is the domain irrelevant? If so, it should be documented. If not, please use the relevant function instead. > + (drv->id.uuid_low == afu_dev->id.uuid_low) && > + (drv->id.uuid_high == afu_dev->id.uuid_high) && > + (drv->id.port == afu_dev->id.port)) { > + > + afu_dev->driver = drv; > + > + /* call the driver probe() function */ > + ret = drv->probe(afu_dev); > + if (ret) > + afu_dev->driver = NULL; > + return ret; > + } > + > + /* return positive value if driver doesn't support this device */ > + return 1; > +} > + > +static int > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) > +{ > + const char *name; > + struct rte_afu_driver *drv = NULL; > + int rc; > + > + if (afu_dev == NULL) > + return -1; > + > + /* Check if a driver is already loaded */ > + if (afu_dev->driver != NULL) > + return 0; > + > + name = rte_ifpga_device_name(afu_dev); > + IFPGA_BUS_DEBUG("Search driver %s to probe device %s\n", name, > + rte_ifpga_device_name(afu_dev)); > + > + TAILQ_FOREACH(drv, &rte_ifpga_bus.driver_list, next) { > + rc = ifpga_probe_one_driver(drv, afu_dev); > + if (rc < 0) > + /* negative value is an error */ > + return -1; > + if (rc > 0) > + /* positive value means driver doesn't support it */ > + continue; > + return 0; > + } > + return 1; > +} > + > +/* > + * Scan the content of the PCI bus, and call the probe() function for One should read IFPGA bus here I guess. > + * all registered drivers that have a matching entry in its id_table > + * for discovered devices. > + */ > +static int > +rte_ifpga_probe(void) > +{ > + struct rte_ifpga_device *ifpga_dev; > + struct rte_afu_device *afu_dev = NULL; > + int ret = 0; > + > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > + > + if (afu_dev->device.driver) > + continue; > + > + ret = ifpga_probe_all_drivers(afu_dev); > + if (ret < 0) > + IFPGA_BUS_ERR("failed to initialize %s device\n", > + rte_ifpga_device_name(afu_dev)); > + } > + } > + > + return 0; > +} > + > +static int > +rte_ifpga_plug(struct rte_device *dev) > +{ > + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); > +} > + > +static int ifpga_remove_driver(struct rte_afu_device *afu_dev) > +{ > + const char *name; > + const struct rte_afu_driver *driver; > + > + name = rte_ifpga_device_name(afu_dev); > + if (!afu_dev->device.driver) { > + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); > + return 1; > + } > + > + driver = container_of(afu_dev->device.driver, > + const struct rte_afu_driver, > + driver); No RTE_DRV_TO_AFU_CONST? It would be easier to read. > + return driver->remove(afu_dev); > +} > + > +static int > +rte_ifpga_unplug(struct rte_device *dev) > +{ > + struct rte_ifpga_device *ifpga_dev = NULL; > + struct rte_afu_device *afu_dev = NULL; > + struct rte_devargs *devargs = NULL; > + int ret; > + > + if (dev == NULL) > + return -EINVAL; > + > + afu_dev = RTE_DEV_TO_AFU(dev); > + if (!dev) > + return -ENOENT; > + > + ifpga_dev = afu_dev->ifpga_dev; > + devargs = dev->devargs; > + > + ret = ifpga_remove_driver(afu_dev); > + if (ret) > + return ret; > + > + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); > + > + TAILQ_REMOVE(&devargs_list, devargs, next); > + > + free(devargs->args); > + free(devargs); > + free(afu_dev); > + return 0; > + > +} > + > +static struct rte_device * > +rte_ifpga_find_device(const struct rte_device *start, > + rte_dev_cmp_t cmp, const void *data) > +{ > + struct rte_ifpga_device *ifpga_dev; > + struct rte_afu_device *afu_dev; > + > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > + if (start && &afu_dev->device == start) { > + start = NULL; > + continue; > + } > + if (cmp(&afu_dev->device, data) == 0) > + return &afu_dev->device; > + } > + } > + return NULL; > +} > +static int > +rte_ifpga_parse(const char *name, void *addr) > +{ > + struct rte_afu_driver **out = addr; > + struct rte_afu_driver *driver = NULL; > + > + TAILQ_FOREACH(driver, &rte_ifpga_bus.driver_list, next) { > + if (strncmp(driver->driver.name, name, > + strlen(driver->driver.name)) == 0) > + break; > + if (driver->driver.alias && > + strncmp(driver->driver.alias, name, > + strlen(driver->driver.alias)) == 0) > + break; > + } > + if (driver != NULL && > + addr != NULL) > + *out = driver; > + return driver == NULL; > +} > + > +struct rte_ifpga_bus rte_ifpga_bus = { > + .bus = { > + .scan = rte_ifpga_scan, > + .probe = rte_ifpga_probe, > + .find_device = rte_ifpga_find_device, Wrong indentation (2 tabs instead of one). > + .plug = rte_ifpga_plug, > + .unplug = rte_ifpga_unplug, > + .parse = rte_ifpga_parse, > + }, > + .ifpga_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.ifpga_list), > + .driver_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.driver_list), Why are those lists part of the bus definition? Can you do the same as the vdev bus and have them statically declared in your source file only? Is there a reason you want them part of the bus, do you need to access it somewhere? > +}; > + > +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus.bus); > + > +RTE_INIT(ifpga_init_log) > +{ > + ifpga_bus_logtype = rte_log_register("bus.ifpga"); > + if (ifpga_bus_logtype >= 0) > + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); > +} > + > diff --git a/drivers/bus/ifpga/ifpga_common.c b/drivers/bus/ifpga/ifpga_common.c > new file mode 100644 > index 0000000..03a8d48 > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_common.c > @@ -0,0 +1,141 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2017 Intel Corporation > + */ > + > +#include <string.h> > +#include <inttypes.h> > +#include <stdint.h> > +#include <stdlib.h> > +#include <stdio.h> > +#include <sys/queue.h> > +#include <sys/mman.h> > +#include <sys/types.h> > +#include <unistd.h> > +#include <fcntl.h> > + > +#include <rte_errno.h> > +#include <rte_bus.h> > +#include <rte_per_lcore.h> > +#include <rte_memory.h> > +#include <rte_memzone.h> > +#include <rte_eal.h> > +#include <rte_common.h> > + > +#include <rte_devargs.h> > +#include <rte_pci.h> > +#include <rte_bus_pci.h> > +#include <rte_kvargs.h> > +#include <rte_alarm.h> > + > +#include "rte_bus_ifpga.h" > +#include "ifpga_logs.h" > +#include "ifpga_common.h" > + > +int ifpga_get_string_arg(const char *key __rte_unused, > + const char *value, void *extra_args) > +{ > + if (!value || !extra_args) > + return -EINVAL; > + > + *(char **)extra_args = strdup(value); > + > + if (!*(char **)extra_args) > + return -ENOMEM; > + > + return 0; > +} > +int ifpga_get_integer32_arg(const char *key __rte_unused, > + const char *value, void *extra_args) > +{ > + if (!value || !extra_args) > + return -EINVAL; > + > + *(int *)extra_args = strtoull(value, NULL, 0); > + > + return 0; > +} > +int ifpga_get_integer64_arg(const char *key __rte_unused, > + const char *value, void *extra_args) > +{ > + if (!value || !extra_args) > + return -EINVAL; > + > + *(uint64_t *)extra_args = strtoull(value, NULL, 0); > + > + return 0; > +} > +int ifpga_get_unsigned_long(const char *str, int base) > +{ > + unsigned long num; > + char *end = NULL; > + > + errno = 0; > + > + num = strtoul(str, &end, base); > + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) > + return -1; > + > + return num; > + > +} Missing newline here. > +int ifpga_get_bdf_arg(const char *key __rte_unused, > + const char *value, void *extra_args) > +{ > +#define MAX_PATH_LEN 1024 > + struct rte_pci_addr *addr; > + int num[4]; > + char str[MAX_PATH_LEN]; > + int i, j; > + > + if (!value || !extra_args) > + return -EINVAL; > + > + addr = (struct rte_pci_addr *)extra_args; > + strcpy(str, value); > + memset(num, 0, 4 * sizeof(num[0])); > + i = strlen(str) - 1; > + j = 3; > + while (i > 0 && j >= 0) { > + while ((str[i - 1] != ':' && str[i - 1] != '.') && i > 0) > + i--; > + num[j--] = ifpga_get_unsigned_long(&str[i], 16); > + i--; > + if (i >= 0) > + str[i] = '\0'; > + } > + addr->domain = num[0]; > + addr->bus = num[1]; > + addr->devid = num[2]; > + addr->function = num[3]; > + printf("[%s]: bdf %04d:%02d:%02d.%02d\n", > + __func__, > + addr->domain, > + addr->bus, > + addr->devid, > + addr->function); > + > + return 0; > +} Use rte_pci_addr_parse instead of rewriting it please. > + > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > + const struct rte_afu_id *afu_id1) > +{ > + if ((afu_id0->pci_addr.bus == afu_id1->pci_addr.bus) && > + (afu_id0->pci_addr.devid == afu_id1->pci_addr.devid) && > + (afu_id0->pci_addr.function == afu_id1->pci_addr.function) && > + (afu_id0->uuid_low == afu_id1->uuid_low) && > + (afu_id0->uuid_high == afu_id1->uuid_high) && > + (afu_id0->port == afu_id1->port)) { > + return 0; > + } else > + return 1; > +} You used the exact same check in the ifpga_bus.c file, why not call this function instead? > +int ifpga_pci_addr_cmp(const struct rte_device *dev, > + const void *_pci_addr) > +{ > + struct rte_pci_device *pdev; > + const struct rte_pci_addr *paddr = _pci_addr; > + > + pdev = RTE_DEV_TO_PCI(*(struct rte_device **)(void *)&dev); > + return rte_eal_compare_pci_addr(&pdev->addr, paddr); This function is deprecated (I should mark is as so to forbid its use). Use rte_pci_addr_cmp() instead. > +} > diff --git a/drivers/bus/ifpga/ifpga_common.h b/drivers/bus/ifpga/ifpga_common.h > new file mode 100644 > index 0000000..48a5012 > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_common.h > @@ -0,0 +1,22 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2017 Intel Corporation > + */ > + > +#ifndef _IFPGA_COMMON_H_ > +#define _IFPGA_COMMON_H_ > + > +int ifpga_get_string_arg(const char *key __rte_unused, > + const char *value, void *extra_args); > +int ifpga_get_integer32_arg(const char *key __rte_unused, > + const char *value, void *extra_args); > +int ifpga_get_integer64_arg(const char *key __rte_unused, > + const char *value, void *extra_args); > +int ifpga_get_unsigned_long(const char *str, int base); > +int ifpga_get_bdf_arg(const char *key __rte_unused, > + const char *value, void *extra_args); > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > + const struct rte_afu_id *afu_id1); > +int ifpga_pci_addr_cmp(const struct rte_device *dev, > + const void *_pci_addr); > + > +#endif /* _IFPGA_COMMON_H_ */ > diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h > new file mode 100644 > index 0000000..e3f4849 > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_logs.h > @@ -0,0 +1,31 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2017 Intel Corporation > + */ > + > +#ifndef _IFPGA_LOGS_H_ > +#define _IFPGA_LOGS_H_ > + > +#include <rte_log.h> > + > +extern int ifpga_bus_logtype; > + > +#define IFPGA_LOG(level, fmt, args...) \ > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > + __func__, ##args) > + > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > + __func__, ##args) > + > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > + > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) > +#define IFPGA_BUS_INFO(fmt, args...) \ > + IFPGA_BUS_LOG(INFO, fmt, ## args) > +#define IFPGA_BUS_ERR(fmt, args...) \ > + IFPGA_BUS_LOG(ERR, fmt, ## args) > +#define IFPGA_BUS_WARN(fmt, args...) \ > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > + > +#endif /* _IFPGA_BUS_LOGS_H_ */ > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h > new file mode 100644 > index 0000000..7290149 > --- /dev/null > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > @@ -0,0 +1,140 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2017 Intel Corporation > + */ > + > +#ifndef _RTE_BUS_IFPGA_H_ > +#define _RTE_BUS_IFPGA_H_ > + > +/** > + * @file > + * > + * RTE PCI Bus Interface > + */ > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include <rte_bus.h> > +#include <rte_pci.h> > + > +/** Name of Intel FPGA Bus */ > +#define IFPGA_BUS_NAME ifpga > + > +/* Forward declarations */ > +struct rte_ifpga_device; > +struct rte_afu_device; > +struct rte_afu_driver; > + > +/** List of Intel FPGA devices */ > +TAILQ_HEAD(rte_ifpga_device_list, rte_ifpga_device); > +/** List of Intel AFU devices */ > +TAILQ_HEAD(rte_afu_device_list, rte_afu_device); > +/** List of AFU drivers */ > +TAILQ_HEAD(rte_afu_driver_list, rte_afu_driver); Is there a reason for you to expose your lists publicly? These symbols should be made private to your bus unless necessary. > + > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > + > +/** > + * A structure describing an ID for a AFU driver. Each driver provides a > + * table of these IDs for each device that it supports. > + */ > +struct rte_afu_id { > + struct rte_pci_addr pci_addr; You use a symbol from librte_pci, without linking it. > + uint64_t uuid_low; > + uint64_t uuid_high; > + int port; > +} __attribute__ ((packed)); > + > +/** > + * A structure pr configuration AFU driver. > + */ > + > +struct rte_afu_pr_conf { > + struct rte_afu_id afu_id; > + int pr_enable; > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > +}; > + > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > + > +/** > + * A structure describing a fpga device. > + */ > +struct rte_ifpga_device { > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ > + struct rte_pci_addr pci_addr; > + struct rte_rawdev *rdev; > + struct rte_afu_device_list afu_list; /**< List of AFU devices */ > +}; > + > +/** > + * A structure describing a AFU device. > + */ > +struct rte_afu_device { > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ > + struct rte_device device; /**< Inherit core device */ > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > + struct rte_afu_id id; /**< AFU id within FPGA. */ > + uint32_t num_region; /**< number of regions found */ > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > + /**< PCI Memory Resource */ > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > + struct rte_afu_driver *driver; /**< Associated driver */ > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > +} __attribute__ ((packed)); > + > +/** > + * @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) > + > +/** > + * Initialisation function for the driver called during PCI probing. > + */ > +typedef int (afu_probe_t)(struct rte_afu_device *); > + > +/** > + * Uninitialisation function for the driver called during hotplugging. > + */ > +typedef int (afu_remove_t)(struct rte_afu_device *); > + > +/** > + * A structure describing a PCI device. > + */ > +struct rte_afu_driver { > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > + struct rte_driver driver; /**< Inherit core driver. */ > + afu_probe_t *probe; /**< Device Probe function. */ > + afu_remove_t *remove; /**< Device Remove function. */ > + struct rte_afu_id id; /**< AFU id within FPGA. */ > + uint32_t drv_flags; /**< Flags contolling handling of device. */ > +}; > + > +/** > + * Structure describing the Intel FPGA bus > + */ > +struct rte_ifpga_bus { > + struct rte_bus bus; /**< Inherit the generic class */ > + struct rte_ifpga_device_list ifpga_list; /**< List of FPGA devices */ > + struct rte_afu_driver_list driver_list; /**< List of FPGA drivers */ > +}; > + > +static inline const char * > +rte_ifpga_device_name(const struct rte_afu_device *afu) > +{ > + if (afu && afu->device.name) > + return afu->device.name; > + return NULL; > +} > + > +extern struct rte_ifpga_bus rte_ifpga_bus; > + > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > + > + > +#endif /* _RTE_BUS_IFPGA_H_ */ > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map > new file mode 100644 > index 0000000..4edc9c0 > --- /dev/null > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > @@ -0,0 +1,8 @@ > +DPDK_18.05 { > + global: > + > + rte_ifpga_driver_register; > + rte_ifpga_driver_unregister; Wrong indentation. It should be one tabulation, not 4 spaces. > + > + local: *; > +}; > -- > 1.8.3.1 > -- Gaëtan Rivet 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code 2018-03-28 13:52 ` Gaëtan Rivet @ 2018-03-31 16:31 ` Xu, Rosen 2018-04-02 4:25 ` Xu, Rosen 2018-04-02 4:31 ` Xu, Rosen 2018-04-04 4:01 ` Xu, Rosen 1 sibling, 2 replies; 149+ messages in thread From: Xu, Rosen @ 2018-03-31 16:31 UTC (permalink / raw) To: gaetan.rivet Cc: dev, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Zhang, Tianfei, Wu, Hao > -----Original Message----- > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com] > Sent: Wednesday, March 28, 2018 21:52 > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com> > Subject: Re: [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code > > On Wed, Mar 28, 2018 at 05:29:54PM +0800, Rosen Xu wrote: > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > --- > > drivers/bus/Makefile | 1 + > > drivers/bus/ifpga/Makefile | 33 ++ > > drivers/bus/ifpga/ifpga_bus.c | 562 > ++++++++++++++++++++++++++++ > > drivers/bus/ifpga/ifpga_common.c | 141 +++++++ > > drivers/bus/ifpga/ifpga_common.h | 22 ++ > > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > > drivers/bus/ifpga/rte_bus_ifpga.h | 140 +++++++ > > drivers/bus/ifpga/rte_bus_ifpga_version.map | 8 + > > 8 files changed, 938 insertions(+) > > create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 > > drivers/bus/ifpga/ifpga_bus.c create mode 100644 > > drivers/bus/ifpga/ifpga_common.c create mode 100644 > > drivers/bus/ifpga/ifpga_common.h create mode 100644 > > drivers/bus/ifpga/ifpga_logs.h create mode 100644 > > drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 > > drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index > > 7ef2593..55d2dfe 100644 > > --- a/drivers/bus/Makefile > > +++ b/drivers/bus/Makefile > > @@ -7,5 +7,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa > > DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc > > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > > > > include $(RTE_SDK)/mk/rte.subdir.mk > > diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile > > new file mode 100644 index 0000000..e611950 > > --- /dev/null > > +++ b/drivers/bus/ifpga/Makefile > > @@ -0,0 +1,33 @@ > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel > > +Corporation > > Copyrigth 2018 (same comment for most SPDX tags, I think I saw 2017 or a > variation of it everywhere I think). It's done by PATCH v4. > > + > > +include $(RTE_SDK)/mk/rte.vars.mk > > + > > +# > > +# library name > > +# > > +LIB = librte_bus_ifpga.a > > + > > +CFLAGS += -O3 > > +CFLAGS += $(WERROR_FLAGS) > > + > > +# versioning export map > > +EXPORT_MAP := rte_bus_ifpga_version.map > > + > > +# library version > > +LIBABIVER := 1 > > + > > +VPATH += $(SRCDIR)/base > > + > > +SRCS-y += \ > > + ifpga_bus.c \ > > + ifpga_common.c > > + > > +LDLIBS += -lrte_eal > > you should probably load librte_pci. > You use afterward functions (at least address comparison). > I haven't tested the SHARED build, but my guess is that it would break. The FPGA BUS is based PCI(IFPGA is probed by PCI), do you think so users to add it? > On that note, you haven't acted on my previous remarks to use the common > PCI utilities provided. It's done in PATCH v4. > > + > > +# > > +# Export include files > > +# > > +SYMLINK-y-include += rte_bus_ifpga.h > > + > > +include $(RTE_SDK)/mk/rte.lib.mk > > diff --git a/drivers/bus/ifpga/ifpga_bus.c > > b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index > > 0000000..092be65 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_bus.c > > @@ -0,0 +1,562 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2017 Intel Corporation */ > > + > > +#include <string.h> > > +#include <inttypes.h> > > +#include <stdint.h> > > +#include <stdlib.h> > > +#include <stdio.h> > > +#include <sys/queue.h> > > +#include <sys/mman.h> > > +#include <sys/types.h> > > +#include <unistd.h> > > +#include <fcntl.h> > > + > > +#include <rte_errno.h> > > +#include <rte_bus.h> > > +#include <rte_per_lcore.h> > > +#include <rte_memory.h> > > +#include <rte_memzone.h> > > +#include <rte_eal.h> > > +#include <rte_common.h> > > + > > +#include <rte_devargs.h> > > +#include <rte_pci.h> > > +#include <rte_bus_pci.h> > > +#include <rte_kvargs.h> > > +#include <rte_alarm.h> > > + > > +#include "rte_rawdev.h" > > +#include "rte_rawdev_pmd.h" > > +#include "rte_bus_ifpga.h" > > +#include "ifpga_logs.h" > > +#include "ifpga_common.h" > > + > > +int ifpga_bus_logtype; > > + > > +/* register a ifpga bus based driver */ void > > +rte_ifpga_driver_register(struct rte_afu_driver *driver) { > > + RTE_VERIFY(driver); > > + > > + TAILQ_INSERT_TAIL(&rte_ifpga_bus.driver_list, driver, next); } > > + > > +/* un-register a fpga bus based driver */ void > > +rte_ifpga_driver_unregister(struct rte_afu_driver *driver) { > > + TAILQ_REMOVE(&rte_ifpga_bus.driver_list, driver, next); } > > + > > +static struct rte_ifpga_device * > > +ifpga_find_ifpga_dev(const struct rte_pci_addr *pci_addr) { > > + struct rte_ifpga_device *ifpga_dev = NULL; > > + > > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > > + if (!rte_pci_addr_cmp(&ifpga_dev->pci_addr, pci_addr)) > > + return ifpga_dev; > > + } > > + return NULL; > > +} > > + > > +static struct rte_afu_device * > > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > > + const struct rte_afu_id *afu_id) > > +{ > > + struct rte_afu_device *afu_dev = NULL; > > + > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > > + return afu_dev; > > + } > > + return NULL; > > +} > > + > > +static const char * const valid_args[] = { > > +#define IFPGA_ARG_BDF "bdf" > > + IFPGA_ARG_BDF, > > +#define IFPGA_ARG_PORT "port" > > + IFPGA_ARG_PORT, > > +#define IFPGA_ARG_PATH "path" > > + IFPGA_ARG_PATH, > > +#define IFPGA_ARG_UUID_HIGH "uuid_high" > > + IFPGA_ARG_UUID_HIGH, > > +#define IFPGA_ARG_UUID_LOW "uuid_low" > > + IFPGA_ARG_UUID_LOW, > > +#define IFPGA_ARG_PR_ENABLE "pr_enable" > > + IFPGA_ARG_PR_ENABLE, > > +#define IFPGA_ARG_DEBUG "debug" > > + IFPGA_ARG_DEBUG, > > + NULL > > +}; > > So these parameters are parsed during scan afterward, taken from the PCI > device that was probed. > > Given the kerfuffle of the VIRTUAL devtype in the EAL option, I'm not sure > how the PCI bus would react with your IFPGA PCI device being probed by its > blacklist operation: the devargs would be null. Do you segfault during your > scan? Have you tested this? > > Why are those parameters parsed again here on this note? Shouldn't they be > parsed by the PCI device being probed with a custome PCI driver that you > would have added (and I think you provide it afterward), that would spawn > the rawdev with the relevant metadata? Then you could scan this rawdev > here and have all these parameters already parsed? > > Is there a reason that you did all this in this order? (specific initialization step > for example?) Pls see PATCH v4 and my reply for your email of PATCH v3 1/6. The command line is in that email. > > + > > +/* > > + * Scan the content of the FPGA bus, and the devices in the devices > > + * list > > + */ > > +static struct rte_afu_device * > > +rte_ifpga_scan_one(struct rte_devargs *devargs, > > + struct rte_ifpga_device *ifpga_dev) > > +{ > > + struct rte_kvargs *kvlist = NULL; > > + struct rte_bus *pci_bus = NULL; > > + struct rte_device *dev = NULL; > > + struct rte_rawdev *rawdev = NULL; > > + struct rte_afu_device *afu_dev = NULL; > > + struct rte_afu_pr_conf afu_pr_conf; > > + int ret = 0; > > + char *path = NULL; > > + int pr_enable = 1; > > + int debug = 0; > > + > > + memset((char *)(&afu_pr_conf), 0, sizeof(struct rte_afu_pr_conf)); > > + > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > + if (!kvlist) { > > + IFPGA_BUS_ERR("error when parsing param"); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, > > + &ifpga_get_bdf_arg, &afu_pr_conf.afu_id.pci_addr) > < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > IFPGA_ARG_BDF); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PATH); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, > > + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_PORT); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PATH); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PATH) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PATH, > > + &ifpga_get_string_arg, &path) < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_PATH); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PATH); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_UUID_HIGH) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_UUID_HIGH, > > + &ifpga_get_integer64_arg, &afu_pr_conf.afu_id.uuid_high) > < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_UUID_HIGH); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PATH); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_UUID_LOW) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_UUID_LOW, > > + &ifpga_get_integer64_arg, &afu_pr_conf.afu_id.uuid_low) < > 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_UUID_LOW); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PATH); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PR_ENABLE) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PR_ENABLE, > > + &ifpga_get_integer32_arg, &pr_enable) < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_UUID_HIGH); > > + goto end; > > + } > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_DEBUG) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_DEBUG, > > + &ifpga_get_integer32_arg, &debug) < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_UUID_HIGH); > > + goto end; > > + } > > + } > > + > > + if (!debug) { > > + pci_bus = rte_bus_find_by_name("pci"); > > + if (pci_bus == NULL) { > > + IFPGA_BUS_ERR("unable to find PCI bus\n"); > > + goto end; > > + } > > + > > + dev = pci_bus->find_device(NULL, > > + ifpga_pci_addr_cmp, > > + &afu_pr_conf.afu_id.pci_addr); > > + if (dev == NULL) { > > + IFPGA_BUS_ERR("unable to find PCI device\n"); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_DEBUG("pci_addr domain : %x\n", > > + afu_pr_conf.afu_id.pci_addr.domain); > > + IFPGA_BUS_DEBUG("pci_addr bus : %x\n", > > + afu_pr_conf.afu_id.pci_addr.bus); > > + IFPGA_BUS_DEBUG("pci_addr devid : %x\n", > > + afu_pr_conf.afu_id.pci_addr.devid); > > + IFPGA_BUS_DEBUG("pci_addr function : %x\n", > > + afu_pr_conf.afu_id.pci_addr.function); > > + IFPGA_BUS_DEBUG("uuid_low : %lx\n", > > + afu_pr_conf.afu_id.uuid_low); > > + IFPGA_BUS_DEBUG("uuid_high : %lx\n", > > + afu_pr_conf.afu_id.uuid_high); > > + IFPGA_BUS_DEBUG("afu port : %x\n", > > + afu_pr_conf.afu_id.port); > > + } > > + > > + rawdev = ifpga_dev->rdev; > > + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) > > + goto end; > > + > > + afu_dev = calloc(1, sizeof(*afu_dev)); > > + if (!afu_dev) > > + goto end; > > + > > + afu_dev->device.devargs = devargs; > > + afu_dev->device.numa_node = SOCKET_ID_ANY; > > + afu_dev->device.name = devargs->name; > > + afu_dev->rawdev = rawdev; > > + afu_dev->id.pci_addr.domain = afu_pr_conf.afu_id.pci_addr.domain; > > + afu_dev->id.pci_addr.bus = afu_pr_conf.afu_id.pci_addr.bus; > > + afu_dev->id.pci_addr.devid = afu_pr_conf.afu_id.pci_addr.devid; > > + afu_dev->id.pci_addr.function = > > +afu_pr_conf.afu_id.pci_addr.function; > > Can you add a function called rte_pci_addr_cpy in librte_pci and use it > instead of doing this by hand here? Others would benefit from this. > > > + afu_dev->id.uuid_low = afu_pr_conf.afu_id.uuid_low; > > + afu_dev->id.uuid_high = afu_pr_conf.afu_id.uuid_high; > > + afu_dev->id.port = afu_pr_conf.afu_id.port; > > + afu_dev->ifpga_dev = ifpga_dev; > > + > > + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) > > + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); > > + > > + if (rawdev->dev_ops && > > + rawdev->dev_ops->dev_start && > > + rawdev->dev_ops->dev_start(rawdev)) > > + goto free_dev; > > + if (pr_enable) { > > + strncpy(afu_pr_conf.bs_path, path, strlen(path)); > > strncpy is dangerous here, please use strlcpy or snprintf. > (And your use of strncpy is dangerous, you are limitting the write to the > length of the source, not to the size of the destination.) > > > + if (rawdev->dev_ops->firmware_load && > > + rawdev->dev_ops->firmware_load(rawdev, > > + &afu_pr_conf)){ > > + printf("firmware load error %d\n", ret); > > + goto free_dev; > > + } > > + } > > + > > + return afu_dev; > > + > > +free_dev: > > + free(afu_dev); > > +end: > > + if (kvlist) > > + rte_kvargs_free(kvlist); > > + if (path) > > + free(path); > > + > > + return NULL; > > +} > > + > > +/* > > + * Scan the content of the FPGA bus, and the devices in the devices > > + * list > > + */ > > +static int > > +rte_ifpga_scan(void) > > +{ > > + struct rte_ifpga_device *ifpga_dev; > > + struct rte_devargs *devargs; > > + struct rte_kvargs *kvlist = NULL; > > + struct rte_pci_addr pci_addr; > > + struct rte_rawdev *rawdev = NULL; > > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > > + struct rte_afu_device *afu_dev = NULL; > > + > > + /* for FPGA devices we scan the devargs_list populated via cmdline > */ > > + TAILQ_FOREACH(devargs, &devargs_list, next) { > > + if (devargs->bus != &rte_ifpga_bus.bus) > > + continue; > > + > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > + if (!kvlist) { > > + IFPGA_BUS_ERR("error when parsing param"); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, > > + &ifpga_get_bdf_arg, &pci_addr) < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_BDF); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PATH); > > + goto end; > > + } > > + > > + memset(name, 0, sizeof(name)); > > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, > "IFPGA:%x:%x:%x", > > + pci_addr.bus, pci_addr.devid, pci_addr.function); > > + > > + rawdev = rte_rawdev_pmd_get_named_dev(name); > > + if (!rawdev) > > + goto end; > > + > > + if (ifpga_find_ifpga_dev(&pci_addr)) > > + goto end; > > + > > + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); > > + if (!ifpga_dev) > > + goto end; > > + > > + ifpga_dev->pci_addr.domain = pci_addr.domain; > > + ifpga_dev->pci_addr.bus = pci_addr.bus; > > + ifpga_dev->pci_addr.devid = pci_addr.devid; > > + ifpga_dev->pci_addr.function = pci_addr.function; > > Again, PCI copy would be nice instead of doing it by hand. > > > + ifpga_dev->rdev = rawdev; > > + TAILQ_INIT(&ifpga_dev->afu_list); > > + > > + TAILQ_INSERT_TAIL(&rte_ifpga_bus.ifpga_list, ifpga_dev, > next); > > + afu_dev = rte_ifpga_scan_one(devargs, ifpga_dev); > > + if (afu_dev != NULL) > > + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, > next); > > + } > > + > > +end: > > + if (kvlist) > > + rte_kvargs_free(kvlist); > > + > > + return 0; > > +} > > + > > +static int > > +ifpga_probe_one_driver(struct rte_afu_driver *drv, > > + struct rte_afu_device *afu_dev) > > +{ > > + int ret; > > + > > + if ((drv->id.pci_addr.bus == afu_dev->id.pci_addr.bus) && > > + (drv->id.pci_addr.devid == afu_dev->id.pci_addr.devid) && > > + (drv->id.pci_addr.function == afu_dev->id.pci_addr.function) > && > > There is the rte_pci_addr_cmp function that should be used here instead. > Additionally, you haven't responded to my comment about ignoring the > Domain part of the address. Why? Is there a reason for this? Is the domain > irrelevant? If so, it should be documented. If not, please use the relevant > function instead. > > > + (drv->id.uuid_low == afu_dev->id.uuid_low) && > > + (drv->id.uuid_high == afu_dev->id.uuid_high) && > > + (drv->id.port == afu_dev->id.port)) { > > + > > + afu_dev->driver = drv; > > + > > + /* call the driver probe() function */ > > + ret = drv->probe(afu_dev); > > + if (ret) > > + afu_dev->driver = NULL; > > + return ret; > > + } > > + > > + /* return positive value if driver doesn't support this device */ > > + return 1; > > +} > > + > > +static int > > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) { > > + const char *name; > > + struct rte_afu_driver *drv = NULL; > > + int rc; > > + > > + if (afu_dev == NULL) > > + return -1; > > + > > + /* Check if a driver is already loaded */ > > + if (afu_dev->driver != NULL) > > + return 0; > > + > > + name = rte_ifpga_device_name(afu_dev); > > + IFPGA_BUS_DEBUG("Search driver %s to probe device %s\n", name, > > + rte_ifpga_device_name(afu_dev)); > > + > > + TAILQ_FOREACH(drv, &rte_ifpga_bus.driver_list, next) { > > + rc = ifpga_probe_one_driver(drv, afu_dev); > > + if (rc < 0) > > + /* negative value is an error */ > > + return -1; > > + if (rc > 0) > > + /* positive value means driver doesn't support it */ > > + continue; > > + return 0; > > + } > > + return 1; > > +} > > + > > +/* > > + * Scan the content of the PCI bus, and call the probe() function for > > One should read IFPGA bus here I guess. > > > + * all registered drivers that have a matching entry in its id_table > > + * for discovered devices. > > + */ > > +static int > > +rte_ifpga_probe(void) > > +{ > > + struct rte_ifpga_device *ifpga_dev; > > + struct rte_afu_device *afu_dev = NULL; > > + int ret = 0; > > + > > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > + > > + if (afu_dev->device.driver) > > + continue; > > + > > + ret = ifpga_probe_all_drivers(afu_dev); > > + if (ret < 0) > > + IFPGA_BUS_ERR("failed to initialize %s > device\n", > > + rte_ifpga_device_name(afu_dev)); > > + } > > + } > > + > > + return 0; > > +} > > + > > +static int > > +rte_ifpga_plug(struct rte_device *dev) { > > + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); > > +} > > + > > +static int ifpga_remove_driver(struct rte_afu_device *afu_dev) { > > + const char *name; > > + const struct rte_afu_driver *driver; > > + > > + name = rte_ifpga_device_name(afu_dev); > > + if (!afu_dev->device.driver) { > > + IFPGA_BUS_DEBUG("no driver attach to device %s\n", > name); > > + return 1; > > + } > > + > > + driver = container_of(afu_dev->device.driver, > > + const struct rte_afu_driver, > > + driver); > > No RTE_DRV_TO_AFU_CONST? It would be easier to read. > > > + return driver->remove(afu_dev); > > +} > > + > > +static int > > +rte_ifpga_unplug(struct rte_device *dev) { > > + struct rte_ifpga_device *ifpga_dev = NULL; > > + struct rte_afu_device *afu_dev = NULL; > > + struct rte_devargs *devargs = NULL; > > + int ret; > > + > > + if (dev == NULL) > > + return -EINVAL; > > + > > + afu_dev = RTE_DEV_TO_AFU(dev); > > + if (!dev) > > + return -ENOENT; > > + > > + ifpga_dev = afu_dev->ifpga_dev; > > + devargs = dev->devargs; > > + > > + ret = ifpga_remove_driver(afu_dev); > > + if (ret) > > + return ret; > > + > > + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); > > + > > + TAILQ_REMOVE(&devargs_list, devargs, next); > > + > > + free(devargs->args); > > + free(devargs); > > + free(afu_dev); > > + return 0; > > + > > +} > > + > > +static struct rte_device * > > +rte_ifpga_find_device(const struct rte_device *start, > > + rte_dev_cmp_t cmp, const void *data) { > > + struct rte_ifpga_device *ifpga_dev; > > + struct rte_afu_device *afu_dev; > > + > > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > + if (start && &afu_dev->device == start) { > > + start = NULL; > > + continue; > > + } > > + if (cmp(&afu_dev->device, data) == 0) > > + return &afu_dev->device; > > + } > > + } > > + return NULL; > > +} > > +static int > > +rte_ifpga_parse(const char *name, void *addr) { > > + struct rte_afu_driver **out = addr; > > + struct rte_afu_driver *driver = NULL; > > + > > + TAILQ_FOREACH(driver, &rte_ifpga_bus.driver_list, next) { > > + if (strncmp(driver->driver.name, name, > > + strlen(driver->driver.name)) == 0) > > + break; > > + if (driver->driver.alias && > > + strncmp(driver->driver.alias, name, > > + strlen(driver->driver.alias)) == 0) > > + break; > > + } > > + if (driver != NULL && > > + addr != NULL) > > + *out = driver; > > + return driver == NULL; > > +} > > + > > +struct rte_ifpga_bus rte_ifpga_bus = { > > + .bus = { > > + .scan = rte_ifpga_scan, > > + .probe = rte_ifpga_probe, > > + .find_device = rte_ifpga_find_device, > > Wrong indentation (2 tabs instead of one). > > > + .plug = rte_ifpga_plug, > > + .unplug = rte_ifpga_unplug, > > + .parse = rte_ifpga_parse, > > + }, > > + .ifpga_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.ifpga_list), > > + .driver_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.driver_list), > > Why are those lists part of the bus definition? Can you do the same as the > vdev bus and have them statically declared in your source file only? > > Is there a reason you want them part of the bus, do you need to access it > somewhere? > > > +}; > > + > > +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus.bus); > > + > > +RTE_INIT(ifpga_init_log) > > +{ > > + ifpga_bus_logtype = rte_log_register("bus.ifpga"); > > + if (ifpga_bus_logtype >= 0) > > + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); } > > + > > diff --git a/drivers/bus/ifpga/ifpga_common.c > > b/drivers/bus/ifpga/ifpga_common.c > > new file mode 100644 > > index 0000000..03a8d48 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_common.c > > @@ -0,0 +1,141 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2017 Intel Corporation */ > > + > > +#include <string.h> > > +#include <inttypes.h> > > +#include <stdint.h> > > +#include <stdlib.h> > > +#include <stdio.h> > > +#include <sys/queue.h> > > +#include <sys/mman.h> > > +#include <sys/types.h> > > +#include <unistd.h> > > +#include <fcntl.h> > > + > > +#include <rte_errno.h> > > +#include <rte_bus.h> > > +#include <rte_per_lcore.h> > > +#include <rte_memory.h> > > +#include <rte_memzone.h> > > +#include <rte_eal.h> > > +#include <rte_common.h> > > + > > +#include <rte_devargs.h> > > +#include <rte_pci.h> > > +#include <rte_bus_pci.h> > > +#include <rte_kvargs.h> > > +#include <rte_alarm.h> > > + > > +#include "rte_bus_ifpga.h" > > +#include "ifpga_logs.h" > > +#include "ifpga_common.h" > > + > > +int ifpga_get_string_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) { > > + if (!value || !extra_args) > > + return -EINVAL; > > + > > + *(char **)extra_args = strdup(value); > > + > > + if (!*(char **)extra_args) > > + return -ENOMEM; > > + > > + return 0; > > +} > > +int ifpga_get_integer32_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) { > > + if (!value || !extra_args) > > + return -EINVAL; > > + > > + *(int *)extra_args = strtoull(value, NULL, 0); > > + > > + return 0; > > +} > > +int ifpga_get_integer64_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) { > > + if (!value || !extra_args) > > + return -EINVAL; > > + > > + *(uint64_t *)extra_args = strtoull(value, NULL, 0); > > + > > + return 0; > > +} > > +int ifpga_get_unsigned_long(const char *str, int base) { > > + unsigned long num; > > + char *end = NULL; > > + > > + errno = 0; > > + > > + num = strtoul(str, &end, base); > > + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) > > + return -1; > > + > > + return num; > > + > > +} > > Missing newline here. > > > +int ifpga_get_bdf_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) { #define MAX_PATH_LEN 1024 > > + struct rte_pci_addr *addr; > > + int num[4]; > > + char str[MAX_PATH_LEN]; > > + int i, j; > > + > > + if (!value || !extra_args) > > + return -EINVAL; > > + > > + addr = (struct rte_pci_addr *)extra_args; > > + strcpy(str, value); > > + memset(num, 0, 4 * sizeof(num[0])); > > + i = strlen(str) - 1; > > + j = 3; > > + while (i > 0 && j >= 0) { > > + while ((str[i - 1] != ':' && str[i - 1] != '.') && i > 0) > > + i--; > > + num[j--] = ifpga_get_unsigned_long(&str[i], 16); > > + i--; > > + if (i >= 0) > > + str[i] = '\0'; > > + } > > + addr->domain = num[0]; > > + addr->bus = num[1]; > > + addr->devid = num[2]; > > + addr->function = num[3]; > > + printf("[%s]: bdf %04d:%02d:%02d.%02d\n", > > + __func__, > > + addr->domain, > > + addr->bus, > > + addr->devid, > > + addr->function); > > + > > + return 0; > > +} > > Use rte_pci_addr_parse instead of rewriting it please. > > > + > > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > + const struct rte_afu_id *afu_id1) > > +{ > > + if ((afu_id0->pci_addr.bus == afu_id1->pci_addr.bus) && > > + (afu_id0->pci_addr.devid == afu_id1->pci_addr.devid) && > > + (afu_id0->pci_addr.function == afu_id1->pci_addr.function) > && > > + (afu_id0->uuid_low == afu_id1->uuid_low) && > > + (afu_id0->uuid_high == afu_id1->uuid_high) && > > + (afu_id0->port == afu_id1->port)) { > > + return 0; > > + } else > > + return 1; > > +} > > You used the exact same check in the ifpga_bus.c file, why not call this > function instead? > > > +int ifpga_pci_addr_cmp(const struct rte_device *dev, > > + const void *_pci_addr) > > +{ > > + struct rte_pci_device *pdev; > > + const struct rte_pci_addr *paddr = _pci_addr; > > + > > + pdev = RTE_DEV_TO_PCI(*(struct rte_device **)(void *)&dev); > > + return rte_eal_compare_pci_addr(&pdev->addr, paddr); > > This function is deprecated (I should mark is as so to forbid its use). > Use rte_pci_addr_cmp() instead. > > > +} > > diff --git a/drivers/bus/ifpga/ifpga_common.h > > b/drivers/bus/ifpga/ifpga_common.h > > new file mode 100644 > > index 0000000..48a5012 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_common.h > > @@ -0,0 +1,22 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2017 Intel Corporation */ > > + > > +#ifndef _IFPGA_COMMON_H_ > > +#define _IFPGA_COMMON_H_ > > + > > +int ifpga_get_string_arg(const char *key __rte_unused, > > + const char *value, void *extra_args); int > > +ifpga_get_integer32_arg(const char *key __rte_unused, > > + const char *value, void *extra_args); int > > +ifpga_get_integer64_arg(const char *key __rte_unused, > > + const char *value, void *extra_args); int > > +ifpga_get_unsigned_long(const char *str, int base); int > > +ifpga_get_bdf_arg(const char *key __rte_unused, > > + const char *value, void *extra_args); int ifpga_afu_id_cmp(const > > +struct rte_afu_id *afu_id0, > > + const struct rte_afu_id *afu_id1); > > +int ifpga_pci_addr_cmp(const struct rte_device *dev, > > + const void *_pci_addr); > > + > > +#endif /* _IFPGA_COMMON_H_ */ > > diff --git a/drivers/bus/ifpga/ifpga_logs.h > > b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index > > 0000000..e3f4849 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_logs.h > > @@ -0,0 +1,31 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2017 Intel Corporation */ > > + > > +#ifndef _IFPGA_LOGS_H_ > > +#define _IFPGA_LOGS_H_ > > + > > +#include <rte_log.h> > > + > > +extern int ifpga_bus_logtype; > > + > > +#define IFPGA_LOG(level, fmt, args...) \ > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > + __func__, ##args) > > + > > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > + __func__, ##args) > > + > > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > > + > > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) > > +#define IFPGA_BUS_INFO(fmt, args...) \ > > + IFPGA_BUS_LOG(INFO, fmt, ## args) > > +#define IFPGA_BUS_ERR(fmt, args...) \ > > + IFPGA_BUS_LOG(ERR, fmt, ## args) > > +#define IFPGA_BUS_WARN(fmt, args...) \ > > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > > + > > +#endif /* _IFPGA_BUS_LOGS_H_ */ > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h > > b/drivers/bus/ifpga/rte_bus_ifpga.h > > new file mode 100644 > > index 0000000..7290149 > > --- /dev/null > > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > > @@ -0,0 +1,140 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2017 Intel Corporation */ > > + > > +#ifndef _RTE_BUS_IFPGA_H_ > > +#define _RTE_BUS_IFPGA_H_ > > + > > +/** > > + * @file > > + * > > + * RTE PCI Bus Interface > > + */ > > + > > +#ifdef __cplusplus > > +extern "C" { > > +#endif > > + > > +#include <rte_bus.h> > > +#include <rte_pci.h> > > + > > +/** Name of Intel FPGA Bus */ > > +#define IFPGA_BUS_NAME ifpga > > + > > +/* Forward declarations */ > > +struct rte_ifpga_device; > > +struct rte_afu_device; > > +struct rte_afu_driver; > > + > > +/** List of Intel FPGA devices */ > > +TAILQ_HEAD(rte_ifpga_device_list, rte_ifpga_device); > > +/** List of Intel AFU devices */ > > +TAILQ_HEAD(rte_afu_device_list, rte_afu_device); > > +/** List of AFU drivers */ > > +TAILQ_HEAD(rte_afu_driver_list, rte_afu_driver); > > Is there a reason for you to expose your lists publicly? > These symbols should be made private to your bus unless necessary. > > > + > > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > > + > > +/** > > + * A structure describing an ID for a AFU driver. Each driver > > +provides a > > + * table of these IDs for each device that it supports. > > + */ > > +struct rte_afu_id { > > + struct rte_pci_addr pci_addr; > > You use a symbol from librte_pci, without linking it. > > > + uint64_t uuid_low; > > + uint64_t uuid_high; > > + int port; > > +} __attribute__ ((packed)); > > + > > +/** > > + * A structure pr configuration AFU driver. > > + */ > > + > > +struct rte_afu_pr_conf { > > + struct rte_afu_id afu_id; > > + int pr_enable; > > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > +}; > > + > > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > > + > > +/** > > + * A structure describing a fpga device. > > + */ > > +struct rte_ifpga_device { > > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ > > + struct rte_pci_addr pci_addr; > > + struct rte_rawdev *rdev; > > + struct rte_afu_device_list afu_list; /**< List of AFU devices */ }; > > + > > +/** > > + * A structure describing a AFU device. > > + */ > > +struct rte_afu_device { > > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ > > + struct rte_device device; /**< Inherit core device */ > > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > > + struct rte_afu_id id; /**< AFU id within FPGA. */ > > + uint32_t num_region; /**< number of regions found */ > > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > > + /**< PCI Memory Resource > */ > > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > > + struct rte_afu_driver *driver; /**< Associated driver */ > > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > +} __attribute__ ((packed)); > > + > > +/** > > + * @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) > > + > > +/** > > + * Initialisation function for the driver called during PCI probing. > > + */ > > +typedef int (afu_probe_t)(struct rte_afu_device *); > > + > > +/** > > + * Uninitialisation function for the driver called during hotplugging. > > + */ > > +typedef int (afu_remove_t)(struct rte_afu_device *); > > + > > +/** > > + * A structure describing a PCI device. > > + */ > > +struct rte_afu_driver { > > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > > + struct rte_driver driver; /**< Inherit core driver. */ > > + afu_probe_t *probe; /**< Device Probe function. */ > > + afu_remove_t *remove; /**< Device Remove function. */ > > + struct rte_afu_id id; /**< AFU id within FPGA. */ > > + uint32_t drv_flags; /**< Flags contolling handling of device. */ > > +}; > > + > > +/** > > + * Structure describing the Intel FPGA bus */ struct rte_ifpga_bus { > > + struct rte_bus bus; /**< Inherit the generic class */ > > + struct rte_ifpga_device_list ifpga_list; /**< List of FPGA devices */ > > + struct rte_afu_driver_list driver_list; /**< List of FPGA drivers > > +*/ }; > > + > > +static inline const char * > > +rte_ifpga_device_name(const struct rte_afu_device *afu) { > > + if (afu && afu->device.name) > > + return afu->device.name; > > + return NULL; > > +} > > + > > +extern struct rte_ifpga_bus rte_ifpga_bus; > > + > > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); void > > +rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > > + > > + > > +#endif /* _RTE_BUS_IFPGA_H_ */ > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map > > b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > new file mode 100644 > > index 0000000..4edc9c0 > > --- /dev/null > > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > @@ -0,0 +1,8 @@ > > +DPDK_18.05 { > > + global: > > + > > + rte_ifpga_driver_register; > > + rte_ifpga_driver_unregister; > > Wrong indentation. > It should be one tabulation, not 4 spaces. > > > + > > + local: *; > > +}; > > -- > > 1.8.3.1 > > > > -- > Gaëtan Rivet > 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code 2018-03-31 16:31 ` Xu, Rosen @ 2018-04-02 4:25 ` Xu, Rosen 2018-04-02 4:31 ` Xu, Rosen 1 sibling, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-04-02 4:25 UTC (permalink / raw) To: 'gaetan.rivet@6wind.com' Cc: 'dev@dpdk.org', Doherty, Declan, Richardson, Bruce, 'shreyansh.jain@nxp.com', Zhang, Tianfei, Wu, Hao > -----Original Message----- > From: Xu, Rosen > Sent: Sunday, April 01, 2018 0:31 > To: gaetan.rivet@6wind.com > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com> > Subject: RE: [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code > > > > > -----Original Message----- > > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com] > > Sent: Wednesday, March 28, 2018 21:52 > > To: Xu, Rosen <rosen.xu@intel.com> > > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > > Richardson, Bruce <bruce.richardson@intel.com>; > > shreyansh.jain@nxp.com; Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, > > Hao <hao.wu@intel.com> > > Subject: Re: [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code > > > > On Wed, Mar 28, 2018 at 05:29:54PM +0800, Rosen Xu wrote: > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > > --- > > > drivers/bus/Makefile | 1 + > > > drivers/bus/ifpga/Makefile | 33 ++ > > > drivers/bus/ifpga/ifpga_bus.c | 562 > > ++++++++++++++++++++++++++++ > > > drivers/bus/ifpga/ifpga_common.c | 141 +++++++ > > > drivers/bus/ifpga/ifpga_common.h | 22 ++ > > > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > > > drivers/bus/ifpga/rte_bus_ifpga.h | 140 +++++++ > > > drivers/bus/ifpga/rte_bus_ifpga_version.map | 8 + > > > 8 files changed, 938 insertions(+) > > > create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 > > > drivers/bus/ifpga/ifpga_bus.c create mode 100644 > > > drivers/bus/ifpga/ifpga_common.c create mode 100644 > > > drivers/bus/ifpga/ifpga_common.h create mode 100644 > > > drivers/bus/ifpga/ifpga_logs.h create mode 100644 > > > drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 > > > drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > > > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index > > > 7ef2593..55d2dfe 100644 > > > --- a/drivers/bus/Makefile > > > +++ b/drivers/bus/Makefile > > > @@ -7,5 +7,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa > > > DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc > > > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > > > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > > > > > > include $(RTE_SDK)/mk/rte.subdir.mk diff --git > > > a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile new file > > > mode 100644 index 0000000..e611950 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/Makefile > > > @@ -0,0 +1,33 @@ > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel > > > +Corporation > > > > Copyrigth 2018 (same comment for most SPDX tags, I think I saw 2017 or > > a variation of it everywhere I think). > > It's done by PATCH v4. > > > > + > > > +include $(RTE_SDK)/mk/rte.vars.mk > > > + > > > +# > > > +# library name > > > +# > > > +LIB = librte_bus_ifpga.a > > > + > > > +CFLAGS += -O3 > > > +CFLAGS += $(WERROR_FLAGS) > > > + > > > +# versioning export map > > > +EXPORT_MAP := rte_bus_ifpga_version.map > > > + > > > +# library version > > > +LIBABIVER := 1 > > > + > > > +VPATH += $(SRCDIR)/base > > > + > > > +SRCS-y += \ > > > + ifpga_bus.c \ > > > + ifpga_common.c > > > + > > > +LDLIBS += -lrte_eal > > > > you should probably load librte_pci. > > You use afterward functions (at least address comparison). > > I haven't tested the SHARED build, but my guess is that it would break. > > The FPGA BUS is based PCI(IFPGA is probed by PCI), do you think so users to > add it? > > > On that note, you haven't acted on my previous remarks to use the > > common PCI utilities provided. > > It's done in PATCH v4. > > > > + > > > +# > > > +# Export include files > > > +# > > > +SYMLINK-y-include += rte_bus_ifpga.h > > > + > > > +include $(RTE_SDK)/mk/rte.lib.mk > > > diff --git a/drivers/bus/ifpga/ifpga_bus.c > > > b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index > > > 0000000..092be65 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/ifpga_bus.c > > > @@ -0,0 +1,562 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2017 Intel Corporation */ > > > + > > > +#include <string.h> > > > +#include <inttypes.h> > > > +#include <stdint.h> > > > +#include <stdlib.h> > > > +#include <stdio.h> > > > +#include <sys/queue.h> > > > +#include <sys/mman.h> > > > +#include <sys/types.h> > > > +#include <unistd.h> > > > +#include <fcntl.h> > > > + > > > +#include <rte_errno.h> > > > +#include <rte_bus.h> > > > +#include <rte_per_lcore.h> > > > +#include <rte_memory.h> > > > +#include <rte_memzone.h> > > > +#include <rte_eal.h> > > > +#include <rte_common.h> > > > + > > > +#include <rte_devargs.h> > > > +#include <rte_pci.h> > > > +#include <rte_bus_pci.h> > > > +#include <rte_kvargs.h> > > > +#include <rte_alarm.h> > > > + > > > +#include "rte_rawdev.h" > > > +#include "rte_rawdev_pmd.h" > > > +#include "rte_bus_ifpga.h" > > > +#include "ifpga_logs.h" > > > +#include "ifpga_common.h" > > > + > > > +int ifpga_bus_logtype; > > > + > > > +/* register a ifpga bus based driver */ void > > > +rte_ifpga_driver_register(struct rte_afu_driver *driver) { > > > + RTE_VERIFY(driver); > > > + > > > + TAILQ_INSERT_TAIL(&rte_ifpga_bus.driver_list, driver, next); } > > > + > > > +/* un-register a fpga bus based driver */ void > > > +rte_ifpga_driver_unregister(struct rte_afu_driver *driver) { > > > + TAILQ_REMOVE(&rte_ifpga_bus.driver_list, driver, next); } > > > + > > > +static struct rte_ifpga_device * > > > +ifpga_find_ifpga_dev(const struct rte_pci_addr *pci_addr) { > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > + > > > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > > > + if (!rte_pci_addr_cmp(&ifpga_dev->pci_addr, pci_addr)) > > > + return ifpga_dev; > > > + } > > > + return NULL; > > > +} > > > + > > > +static struct rte_afu_device * > > > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > > > + const struct rte_afu_id *afu_id) > > > +{ > > > + struct rte_afu_device *afu_dev = NULL; > > > + > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > > > + return afu_dev; > > > + } > > > + return NULL; > > > +} > > > + > > > +static const char * const valid_args[] = { > > > +#define IFPGA_ARG_BDF "bdf" > > > + IFPGA_ARG_BDF, > > > +#define IFPGA_ARG_PORT "port" > > > + IFPGA_ARG_PORT, > > > +#define IFPGA_ARG_PATH "path" > > > + IFPGA_ARG_PATH, > > > +#define IFPGA_ARG_UUID_HIGH "uuid_high" > > > + IFPGA_ARG_UUID_HIGH, > > > +#define IFPGA_ARG_UUID_LOW "uuid_low" > > > + IFPGA_ARG_UUID_LOW, > > > +#define IFPGA_ARG_PR_ENABLE "pr_enable" > > > + IFPGA_ARG_PR_ENABLE, > > > +#define IFPGA_ARG_DEBUG "debug" > > > + IFPGA_ARG_DEBUG, > > > + NULL > > > +}; > > > > So these parameters are parsed during scan afterward, taken from the > > PCI device that was probed. > > > > Given the kerfuffle of the VIRTUAL devtype in the EAL option, I'm not > > sure how the PCI bus would react with your IFPGA PCI device being > > probed by its blacklist operation: the devargs would be null. Do you > > segfault during your scan? Have you tested this? > > > > Why are those parameters parsed again here on this note? Shouldn't > > they be parsed by the PCI device being probed with a custome PCI > > driver that you would have added (and I think you provide it > > afterward), that would spawn the rawdev with the relevant metadata? > > Then you could scan this rawdev here and have all these parameters > already parsed? > > > > Is there a reason that you did all this in this order? (specific > > initialization step for example?) > Pls see PATCH v4 and my reply for your email of PATCH v3 1/6. The command line is in that email. For PATCH v4 I have removed all modification from eal library. I use vdev driver to take parameter configuration, and this vdev driver call rte_eal_hotplug_add() to add afu device and trigger scan/probe. > > > + > > > +/* > > > + * Scan the content of the FPGA bus, and the devices in the devices > > > + * list > > > + */ > > > +static struct rte_afu_device * > > > +rte_ifpga_scan_one(struct rte_devargs *devargs, > > > + struct rte_ifpga_device *ifpga_dev) { > > > + struct rte_kvargs *kvlist = NULL; > > > + struct rte_bus *pci_bus = NULL; > > > + struct rte_device *dev = NULL; > > > + struct rte_rawdev *rawdev = NULL; > > > + struct rte_afu_device *afu_dev = NULL; > > > + struct rte_afu_pr_conf afu_pr_conf; > > > + int ret = 0; > > > + char *path = NULL; > > > + int pr_enable = 1; > > > + int debug = 0; > > > + > > > + memset((char *)(&afu_pr_conf), 0, sizeof(struct rte_afu_pr_conf)); > > > + > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > + if (!kvlist) { > > > + IFPGA_BUS_ERR("error when parsing param"); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, > > > + &ifpga_get_bdf_arg, &afu_pr_conf.afu_id.pci_addr) > > < 0) { > > > + IFPGA_BUS_ERR("error to parse %s", > > IFPGA_ARG_BDF); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > + IFPGA_ARG_PATH); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, > > > + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { > > > + IFPGA_BUS_ERR("error to parse %s", > > > + IFPGA_ARG_PORT); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > + IFPGA_ARG_PATH); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PATH) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PATH, > > > + &ifpga_get_string_arg, &path) < 0) { > > > + IFPGA_BUS_ERR("error to parse %s", > > > + IFPGA_ARG_PATH); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > + IFPGA_ARG_PATH); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_UUID_HIGH) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_UUID_HIGH, > > > + &ifpga_get_integer64_arg, &afu_pr_conf.afu_id.uuid_high) > > < 0) { > > > + IFPGA_BUS_ERR("error to parse %s", > > > + IFPGA_ARG_UUID_HIGH); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > + IFPGA_ARG_PATH); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_UUID_LOW) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_UUID_LOW, > > > + &ifpga_get_integer64_arg, &afu_pr_conf.afu_id.uuid_low) < > > 0) { > > > + IFPGA_BUS_ERR("error to parse %s", > > > + IFPGA_ARG_UUID_LOW); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > + IFPGA_ARG_PATH); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PR_ENABLE) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PR_ENABLE, > > > + &ifpga_get_integer32_arg, &pr_enable) < 0) { > > > + IFPGA_BUS_ERR("error to parse %s", > > > + IFPGA_ARG_UUID_HIGH); > > > + goto end; > > > + } > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_DEBUG) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_DEBUG, > > > + &ifpga_get_integer32_arg, &debug) < 0) { > > > + IFPGA_BUS_ERR("error to parse %s", > > > + IFPGA_ARG_UUID_HIGH); > > > + goto end; > > > + } > > > + } > > > + > > > + if (!debug) { > > > + pci_bus = rte_bus_find_by_name("pci"); > > > + if (pci_bus == NULL) { > > > + IFPGA_BUS_ERR("unable to find PCI bus\n"); > > > + goto end; > > > + } > > > + > > > + dev = pci_bus->find_device(NULL, > > > + ifpga_pci_addr_cmp, > > > + &afu_pr_conf.afu_id.pci_addr); > > > + if (dev == NULL) { > > > + IFPGA_BUS_ERR("unable to find PCI device\n"); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_BUS_DEBUG("pci_addr domain : %x\n", > > > + afu_pr_conf.afu_id.pci_addr.domain); > > > + IFPGA_BUS_DEBUG("pci_addr bus : %x\n", > > > + afu_pr_conf.afu_id.pci_addr.bus); > > > + IFPGA_BUS_DEBUG("pci_addr devid : %x\n", > > > + afu_pr_conf.afu_id.pci_addr.devid); > > > + IFPGA_BUS_DEBUG("pci_addr function : %x\n", > > > + afu_pr_conf.afu_id.pci_addr.function); > > > + IFPGA_BUS_DEBUG("uuid_low : %lx\n", > > > + afu_pr_conf.afu_id.uuid_low); > > > + IFPGA_BUS_DEBUG("uuid_high : %lx\n", > > > + afu_pr_conf.afu_id.uuid_high); > > > + IFPGA_BUS_DEBUG("afu port : %x\n", > > > + afu_pr_conf.afu_id.port); > > > + } > > > + > > > + rawdev = ifpga_dev->rdev; > > > + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) > > > + goto end; > > > + > > > + afu_dev = calloc(1, sizeof(*afu_dev)); > > > + if (!afu_dev) > > > + goto end; > > > + > > > + afu_dev->device.devargs = devargs; > > > + afu_dev->device.numa_node = SOCKET_ID_ANY; > > > + afu_dev->device.name = devargs->name; > > > + afu_dev->rawdev = rawdev; > > > + afu_dev->id.pci_addr.domain = afu_pr_conf.afu_id.pci_addr.domain; > > > + afu_dev->id.pci_addr.bus = afu_pr_conf.afu_id.pci_addr.bus; > > > + afu_dev->id.pci_addr.devid = afu_pr_conf.afu_id.pci_addr.devid; > > > + afu_dev->id.pci_addr.function = > > > +afu_pr_conf.afu_id.pci_addr.function; > > > > Can you add a function called rte_pci_addr_cpy in librte_pci and use > > it instead of doing this by hand here? Others would benefit from this. > > > > > + afu_dev->id.uuid_low = afu_pr_conf.afu_id.uuid_low; > > > + afu_dev->id.uuid_high = afu_pr_conf.afu_id.uuid_high; > > > + afu_dev->id.port = afu_pr_conf.afu_id.port; > > > + afu_dev->ifpga_dev = ifpga_dev; > > > + > > > + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) > > > + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); > > > + > > > + if (rawdev->dev_ops && > > > + rawdev->dev_ops->dev_start && > > > + rawdev->dev_ops->dev_start(rawdev)) > > > + goto free_dev; > > > + if (pr_enable) { > > > + strncpy(afu_pr_conf.bs_path, path, strlen(path)); > > > > strncpy is dangerous here, please use strlcpy or snprintf. > > (And your use of strncpy is dangerous, you are limitting the write to > > the length of the source, not to the size of the destination.) > > > > > + if (rawdev->dev_ops->firmware_load && > > > + rawdev->dev_ops->firmware_load(rawdev, > > > + &afu_pr_conf)){ > > > + printf("firmware load error %d\n", ret); > > > + goto free_dev; > > > + } > > > + } > > > + > > > + return afu_dev; > > > + > > > +free_dev: > > > + free(afu_dev); > > > +end: > > > + if (kvlist) > > > + rte_kvargs_free(kvlist); > > > + if (path) > > > + free(path); > > > + > > > + return NULL; > > > +} > > > + > > > +/* > > > + * Scan the content of the FPGA bus, and the devices in the devices > > > + * list > > > + */ > > > +static int > > > +rte_ifpga_scan(void) > > > +{ > > > + struct rte_ifpga_device *ifpga_dev; > > > + struct rte_devargs *devargs; > > > + struct rte_kvargs *kvlist = NULL; > > > + struct rte_pci_addr pci_addr; > > > + struct rte_rawdev *rawdev = NULL; > > > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > > > + struct rte_afu_device *afu_dev = NULL; > > > + > > > + /* for FPGA devices we scan the devargs_list populated via cmdline > > */ > > > + TAILQ_FOREACH(devargs, &devargs_list, next) { > > > + if (devargs->bus != &rte_ifpga_bus.bus) > > > + continue; > > > + > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > + if (!kvlist) { > > > + IFPGA_BUS_ERR("error when parsing param"); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, > > > + &ifpga_get_bdf_arg, &pci_addr) < 0) { > > > + IFPGA_BUS_ERR("error to parse %s", > > > + IFPGA_ARG_BDF); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > + IFPGA_ARG_PATH); > > > + goto end; > > > + } > > > + > > > + memset(name, 0, sizeof(name)); > > > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, > > "IFPGA:%x:%x:%x", > > > + pci_addr.bus, pci_addr.devid, pci_addr.function); > > > + > > > + rawdev = rte_rawdev_pmd_get_named_dev(name); > > > + if (!rawdev) > > > + goto end; > > > + > > > + if (ifpga_find_ifpga_dev(&pci_addr)) > > > + goto end; > > > + > > > + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); > > > + if (!ifpga_dev) > > > + goto end; > > > + > > > + ifpga_dev->pci_addr.domain = pci_addr.domain; > > > + ifpga_dev->pci_addr.bus = pci_addr.bus; > > > + ifpga_dev->pci_addr.devid = pci_addr.devid; > > > + ifpga_dev->pci_addr.function = pci_addr.function; > > > > Again, PCI copy would be nice instead of doing it by hand. > > > > > + ifpga_dev->rdev = rawdev; > > > + TAILQ_INIT(&ifpga_dev->afu_list); > > > + > > > + TAILQ_INSERT_TAIL(&rte_ifpga_bus.ifpga_list, ifpga_dev, > > next); > > > + afu_dev = rte_ifpga_scan_one(devargs, ifpga_dev); > > > + if (afu_dev != NULL) > > > + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, > > next); > > > + } > > > + > > > +end: > > > + if (kvlist) > > > + rte_kvargs_free(kvlist); > > > + > > > + return 0; > > > +} > > > + > > > +static int > > > +ifpga_probe_one_driver(struct rte_afu_driver *drv, > > > + struct rte_afu_device *afu_dev) > > > +{ > > > + int ret; > > > + > > > + if ((drv->id.pci_addr.bus == afu_dev->id.pci_addr.bus) && > > > + (drv->id.pci_addr.devid == afu_dev->id.pci_addr.devid) && > > > + (drv->id.pci_addr.function == afu_dev->id.pci_addr.function) > > && > > > > There is the rte_pci_addr_cmp function that should be used here instead. > > Additionally, you haven't responded to my comment about ignoring the > > Domain part of the address. Why? Is there a reason for this? Is the > > domain irrelevant? If so, it should be documented. If not, please use > > the relevant function instead. > > > > > + (drv->id.uuid_low == afu_dev->id.uuid_low) && > > > + (drv->id.uuid_high == afu_dev->id.uuid_high) && > > > + (drv->id.port == afu_dev->id.port)) { > > > + > > > + afu_dev->driver = drv; > > > + > > > + /* call the driver probe() function */ > > > + ret = drv->probe(afu_dev); > > > + if (ret) > > > + afu_dev->driver = NULL; > > > + return ret; > > > + } > > > + > > > + /* return positive value if driver doesn't support this device */ > > > + return 1; > > > +} > > > + > > > +static int > > > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) { > > > + const char *name; > > > + struct rte_afu_driver *drv = NULL; > > > + int rc; > > > + > > > + if (afu_dev == NULL) > > > + return -1; > > > + > > > + /* Check if a driver is already loaded */ > > > + if (afu_dev->driver != NULL) > > > + return 0; > > > + > > > + name = rte_ifpga_device_name(afu_dev); > > > + IFPGA_BUS_DEBUG("Search driver %s to probe device %s\n", name, > > > + rte_ifpga_device_name(afu_dev)); > > > + > > > + TAILQ_FOREACH(drv, &rte_ifpga_bus.driver_list, next) { > > > + rc = ifpga_probe_one_driver(drv, afu_dev); > > > + if (rc < 0) > > > + /* negative value is an error */ > > > + return -1; > > > + if (rc > 0) > > > + /* positive value means driver doesn't support it */ > > > + continue; > > > + return 0; > > > + } > > > + return 1; > > > +} > > > + > > > +/* > > > + * Scan the content of the PCI bus, and call the probe() function > > > +for > > > > One should read IFPGA bus here I guess. > > > > > + * all registered drivers that have a matching entry in its > > > +id_table > > > + * for discovered devices. > > > + */ > > > +static int > > > +rte_ifpga_probe(void) > > > +{ > > > + struct rte_ifpga_device *ifpga_dev; > > > + struct rte_afu_device *afu_dev = NULL; > > > + int ret = 0; > > > + > > > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > + > > > + if (afu_dev->device.driver) > > > + continue; > > > + > > > + ret = ifpga_probe_all_drivers(afu_dev); > > > + if (ret < 0) > > > + IFPGA_BUS_ERR("failed to initialize %s > > device\n", > > > + rte_ifpga_device_name(afu_dev)); > > > + } > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +static int > > > +rte_ifpga_plug(struct rte_device *dev) { > > > + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); > > > +} > > > + > > > +static int ifpga_remove_driver(struct rte_afu_device *afu_dev) { > > > + const char *name; > > > + const struct rte_afu_driver *driver; > > > + > > > + name = rte_ifpga_device_name(afu_dev); > > > + if (!afu_dev->device.driver) { > > > + IFPGA_BUS_DEBUG("no driver attach to device %s\n", > > name); > > > + return 1; > > > + } > > > + > > > + driver = container_of(afu_dev->device.driver, > > > + const struct rte_afu_driver, > > > + driver); > > > > No RTE_DRV_TO_AFU_CONST? It would be easier to read. > > > > > + return driver->remove(afu_dev); > > > +} > > > + > > > +static int > > > +rte_ifpga_unplug(struct rte_device *dev) { > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > + struct rte_afu_device *afu_dev = NULL; > > > + struct rte_devargs *devargs = NULL; > > > + int ret; > > > + > > > + if (dev == NULL) > > > + return -EINVAL; > > > + > > > + afu_dev = RTE_DEV_TO_AFU(dev); > > > + if (!dev) > > > + return -ENOENT; > > > + > > > + ifpga_dev = afu_dev->ifpga_dev; > > > + devargs = dev->devargs; > > > + > > > + ret = ifpga_remove_driver(afu_dev); > > > + if (ret) > > > + return ret; > > > + > > > + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); > > > + > > > + TAILQ_REMOVE(&devargs_list, devargs, next); > > > + > > > + free(devargs->args); > > > + free(devargs); > > > + free(afu_dev); > > > + return 0; > > > + > > > +} > > > + > > > +static struct rte_device * > > > +rte_ifpga_find_device(const struct rte_device *start, > > > + rte_dev_cmp_t cmp, const void *data) { > > > + struct rte_ifpga_device *ifpga_dev; > > > + struct rte_afu_device *afu_dev; > > > + > > > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > + if (start && &afu_dev->device == start) { > > > + start = NULL; > > > + continue; > > > + } > > > + if (cmp(&afu_dev->device, data) == 0) > > > + return &afu_dev->device; > > > + } > > > + } > > > + return NULL; > > > +} > > > +static int > > > +rte_ifpga_parse(const char *name, void *addr) { > > > + struct rte_afu_driver **out = addr; > > > + struct rte_afu_driver *driver = NULL; > > > + > > > + TAILQ_FOREACH(driver, &rte_ifpga_bus.driver_list, next) { > > > + if (strncmp(driver->driver.name, name, > > > + strlen(driver->driver.name)) == 0) > > > + break; > > > + if (driver->driver.alias && > > > + strncmp(driver->driver.alias, name, > > > + strlen(driver->driver.alias)) == 0) > > > + break; > > > + } > > > + if (driver != NULL && > > > + addr != NULL) > > > + *out = driver; > > > + return driver == NULL; > > > +} > > > + > > > +struct rte_ifpga_bus rte_ifpga_bus = { > > > + .bus = { > > > + .scan = rte_ifpga_scan, > > > + .probe = rte_ifpga_probe, > > > + .find_device = rte_ifpga_find_device, > > > > Wrong indentation (2 tabs instead of one). > > > > > + .plug = rte_ifpga_plug, > > > + .unplug = rte_ifpga_unplug, > > > + .parse = rte_ifpga_parse, > > > + }, > > > + .ifpga_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.ifpga_list), > > > + .driver_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.driver_list), > > > > Why are those lists part of the bus definition? Can you do the same as > > the vdev bus and have them statically declared in your source file only? > > > > Is there a reason you want them part of the bus, do you need to access > > it somewhere? > > > > > +}; > > > + > > > +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus.bus); > > > + > > > +RTE_INIT(ifpga_init_log) > > > +{ > > > + ifpga_bus_logtype = rte_log_register("bus.ifpga"); > > > + if (ifpga_bus_logtype >= 0) > > > + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); } > > > + > > > diff --git a/drivers/bus/ifpga/ifpga_common.c > > > b/drivers/bus/ifpga/ifpga_common.c > > > new file mode 100644 > > > index 0000000..03a8d48 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/ifpga_common.c > > > @@ -0,0 +1,141 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2017 Intel Corporation */ > > > + > > > +#include <string.h> > > > +#include <inttypes.h> > > > +#include <stdint.h> > > > +#include <stdlib.h> > > > +#include <stdio.h> > > > +#include <sys/queue.h> > > > +#include <sys/mman.h> > > > +#include <sys/types.h> > > > +#include <unistd.h> > > > +#include <fcntl.h> > > > + > > > +#include <rte_errno.h> > > > +#include <rte_bus.h> > > > +#include <rte_per_lcore.h> > > > +#include <rte_memory.h> > > > +#include <rte_memzone.h> > > > +#include <rte_eal.h> > > > +#include <rte_common.h> > > > + > > > +#include <rte_devargs.h> > > > +#include <rte_pci.h> > > > +#include <rte_bus_pci.h> > > > +#include <rte_kvargs.h> > > > +#include <rte_alarm.h> > > > + > > > +#include "rte_bus_ifpga.h" > > > +#include "ifpga_logs.h" > > > +#include "ifpga_common.h" > > > + > > > +int ifpga_get_string_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args) { > > > + if (!value || !extra_args) > > > + return -EINVAL; > > > + > > > + *(char **)extra_args = strdup(value); > > > + > > > + if (!*(char **)extra_args) > > > + return -ENOMEM; > > > + > > > + return 0; > > > +} > > > +int ifpga_get_integer32_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args) { > > > + if (!value || !extra_args) > > > + return -EINVAL; > > > + > > > + *(int *)extra_args = strtoull(value, NULL, 0); > > > + > > > + return 0; > > > +} > > > +int ifpga_get_integer64_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args) { > > > + if (!value || !extra_args) > > > + return -EINVAL; > > > + > > > + *(uint64_t *)extra_args = strtoull(value, NULL, 0); > > > + > > > + return 0; > > > +} > > > +int ifpga_get_unsigned_long(const char *str, int base) { > > > + unsigned long num; > > > + char *end = NULL; > > > + > > > + errno = 0; > > > + > > > + num = strtoul(str, &end, base); > > > + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) > > > + return -1; > > > + > > > + return num; > > > + > > > +} > > > > Missing newline here. > > > > > +int ifpga_get_bdf_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args) { #define MAX_PATH_LEN 1024 > > > + struct rte_pci_addr *addr; > > > + int num[4]; > > > + char str[MAX_PATH_LEN]; > > > + int i, j; > > > + > > > + if (!value || !extra_args) > > > + return -EINVAL; > > > + > > > + addr = (struct rte_pci_addr *)extra_args; > > > + strcpy(str, value); > > > + memset(num, 0, 4 * sizeof(num[0])); > > > + i = strlen(str) - 1; > > > + j = 3; > > > + while (i > 0 && j >= 0) { > > > + while ((str[i - 1] != ':' && str[i - 1] != '.') && i > 0) > > > + i--; > > > + num[j--] = ifpga_get_unsigned_long(&str[i], 16); > > > + i--; > > > + if (i >= 0) > > > + str[i] = '\0'; > > > + } > > > + addr->domain = num[0]; > > > + addr->bus = num[1]; > > > + addr->devid = num[2]; > > > + addr->function = num[3]; > > > + printf("[%s]: bdf %04d:%02d:%02d.%02d\n", > > > + __func__, > > > + addr->domain, > > > + addr->bus, > > > + addr->devid, > > > + addr->function); > > > + > > > + return 0; > > > +} > > > > Use rte_pci_addr_parse instead of rewriting it please. > > > > > + > > > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > > + const struct rte_afu_id *afu_id1) > > > +{ > > > + if ((afu_id0->pci_addr.bus == afu_id1->pci_addr.bus) && > > > + (afu_id0->pci_addr.devid == afu_id1->pci_addr.devid) && > > > + (afu_id0->pci_addr.function == afu_id1->pci_addr.function) > > && > > > + (afu_id0->uuid_low == afu_id1->uuid_low) && > > > + (afu_id0->uuid_high == afu_id1->uuid_high) && > > > + (afu_id0->port == afu_id1->port)) { > > > + return 0; > > > + } else > > > + return 1; > > > +} > > > > You used the exact same check in the ifpga_bus.c file, why not call > > this function instead? > > > > > +int ifpga_pci_addr_cmp(const struct rte_device *dev, > > > + const void *_pci_addr) > > > +{ > > > + struct rte_pci_device *pdev; > > > + const struct rte_pci_addr *paddr = _pci_addr; > > > + > > > + pdev = RTE_DEV_TO_PCI(*(struct rte_device **)(void *)&dev); > > > + return rte_eal_compare_pci_addr(&pdev->addr, paddr); > > > > This function is deprecated (I should mark is as so to forbid its use). > > Use rte_pci_addr_cmp() instead. > > > > > +} > > > diff --git a/drivers/bus/ifpga/ifpga_common.h > > > b/drivers/bus/ifpga/ifpga_common.h > > > new file mode 100644 > > > index 0000000..48a5012 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/ifpga_common.h > > > @@ -0,0 +1,22 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2017 Intel Corporation */ > > > + > > > +#ifndef _IFPGA_COMMON_H_ > > > +#define _IFPGA_COMMON_H_ > > > + > > > +int ifpga_get_string_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args); int > > > +ifpga_get_integer32_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args); int > > > +ifpga_get_integer64_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args); int > > > +ifpga_get_unsigned_long(const char *str, int base); int > > > +ifpga_get_bdf_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args); int ifpga_afu_id_cmp(const > > > +struct rte_afu_id *afu_id0, > > > + const struct rte_afu_id *afu_id1); int ifpga_pci_addr_cmp(const > > > +struct rte_device *dev, > > > + const void *_pci_addr); > > > + > > > +#endif /* _IFPGA_COMMON_H_ */ > > > diff --git a/drivers/bus/ifpga/ifpga_logs.h > > > b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index > > > 0000000..e3f4849 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/ifpga_logs.h > > > @@ -0,0 +1,31 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2017 Intel Corporation */ > > > + > > > +#ifndef _IFPGA_LOGS_H_ > > > +#define _IFPGA_LOGS_H_ > > > + > > > +#include <rte_log.h> > > > + > > > +extern int ifpga_bus_logtype; > > > + > > > +#define IFPGA_LOG(level, fmt, args...) \ > > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > > + __func__, ##args) > > > + > > > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > > + __func__, ##args) > > > + > > > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > > > + > > > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > > > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) #define > IFPGA_BUS_INFO(fmt, > > > +args...) \ > > > + IFPGA_BUS_LOG(INFO, fmt, ## args) > > > +#define IFPGA_BUS_ERR(fmt, args...) \ > > > + IFPGA_BUS_LOG(ERR, fmt, ## args) > > > +#define IFPGA_BUS_WARN(fmt, args...) \ > > > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > > > + > > > +#endif /* _IFPGA_BUS_LOGS_H_ */ > > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h > > > b/drivers/bus/ifpga/rte_bus_ifpga.h > > > new file mode 100644 > > > index 0000000..7290149 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > > > @@ -0,0 +1,140 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2017 Intel Corporation */ > > > + > > > +#ifndef _RTE_BUS_IFPGA_H_ > > > +#define _RTE_BUS_IFPGA_H_ > > > + > > > +/** > > > + * @file > > > + * > > > + * RTE PCI Bus Interface > > > + */ > > > + > > > +#ifdef __cplusplus > > > +extern "C" { > > > +#endif > > > + > > > +#include <rte_bus.h> > > > +#include <rte_pci.h> > > > + > > > +/** Name of Intel FPGA Bus */ > > > +#define IFPGA_BUS_NAME ifpga > > > + > > > +/* Forward declarations */ > > > +struct rte_ifpga_device; > > > +struct rte_afu_device; > > > +struct rte_afu_driver; > > > + > > > +/** List of Intel FPGA devices */ > > > +TAILQ_HEAD(rte_ifpga_device_list, rte_ifpga_device); > > > +/** List of Intel AFU devices */ > > > +TAILQ_HEAD(rte_afu_device_list, rte_afu_device); > > > +/** List of AFU drivers */ > > > +TAILQ_HEAD(rte_afu_driver_list, rte_afu_driver); > > > > Is there a reason for you to expose your lists publicly? > > These symbols should be made private to your bus unless necessary. > > > > > + > > > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > > > + > > > +/** > > > + * A structure describing an ID for a AFU driver. Each driver > > > +provides a > > > + * table of these IDs for each device that it supports. > > > + */ > > > +struct rte_afu_id { > > > + struct rte_pci_addr pci_addr; > > > > You use a symbol from librte_pci, without linking it. > > > > > + uint64_t uuid_low; > > > + uint64_t uuid_high; > > > + int port; > > > +} __attribute__ ((packed)); > > > + > > > +/** > > > + * A structure pr configuration AFU driver. > > > + */ > > > + > > > +struct rte_afu_pr_conf { > > > + struct rte_afu_id afu_id; > > > + int pr_enable; > > > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > > +}; > > > + > > > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > > > + > > > +/** > > > + * A structure describing a fpga device. > > > + */ > > > +struct rte_ifpga_device { > > > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ > > > + struct rte_pci_addr pci_addr; > > > + struct rte_rawdev *rdev; > > > + struct rte_afu_device_list afu_list; /**< List of AFU devices */ > > > +}; > > > + > > > +/** > > > + * A structure describing a AFU device. > > > + */ > > > +struct rte_afu_device { > > > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ > > > + struct rte_device device; /**< Inherit core device */ > > > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > > > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > > > + struct rte_afu_id id; /**< AFU id within FPGA. */ > > > + uint32_t num_region; /**< number of regions found */ > > > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > > > + /**< PCI Memory Resource > > */ > > > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > > > + struct rte_afu_driver *driver; /**< Associated driver */ > > > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > > +} __attribute__ ((packed)); > > > + > > > +/** > > > + * @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) > > > + > > > +/** > > > + * Initialisation function for the driver called during PCI probing. > > > + */ > > > +typedef int (afu_probe_t)(struct rte_afu_device *); > > > + > > > +/** > > > + * Uninitialisation function for the driver called during hotplugging. > > > + */ > > > +typedef int (afu_remove_t)(struct rte_afu_device *); > > > + > > > +/** > > > + * A structure describing a PCI device. > > > + */ > > > +struct rte_afu_driver { > > > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > > > + struct rte_driver driver; /**< Inherit core driver. */ > > > + afu_probe_t *probe; /**< Device Probe function. */ > > > + afu_remove_t *remove; /**< Device Remove function. */ > > > + struct rte_afu_id id; /**< AFU id within FPGA. */ > > > + uint32_t drv_flags; /**< Flags contolling handling of device. */ > > > +}; > > > + > > > +/** > > > + * Structure describing the Intel FPGA bus */ struct rte_ifpga_bus { > > > + struct rte_bus bus; /**< Inherit the generic class */ > > > + struct rte_ifpga_device_list ifpga_list; /**< List of FPGA devices */ > > > + struct rte_afu_driver_list driver_list; /**< List of FPGA drivers > > > +*/ }; > > > + > > > +static inline const char * > > > +rte_ifpga_device_name(const struct rte_afu_device *afu) { > > > + if (afu && afu->device.name) > > > + return afu->device.name; > > > + return NULL; > > > +} > > > + > > > +extern struct rte_ifpga_bus rte_ifpga_bus; > > > + > > > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); void > > > +rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > > > + > > > + > > > +#endif /* _RTE_BUS_IFPGA_H_ */ > > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > new file mode 100644 > > > index 0000000..4edc9c0 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > @@ -0,0 +1,8 @@ > > > +DPDK_18.05 { > > > + global: > > > + > > > + rte_ifpga_driver_register; > > > + rte_ifpga_driver_unregister; > > > > Wrong indentation. > > It should be one tabulation, not 4 spaces. > > > > > + > > > + local: *; > > > +}; > > > -- > > > 1.8.3.1 > > > > > > > -- > > Gaëtan Rivet > > 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code 2018-03-31 16:31 ` Xu, Rosen 2018-04-02 4:25 ` Xu, Rosen @ 2018-04-02 4:31 ` Xu, Rosen 1 sibling, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-04-02 4:31 UTC (permalink / raw) To: 'gaetan.rivet@6wind.com' Cc: 'dev@dpdk.org', Doherty, Declan, Richardson, Bruce, 'shreyansh.jain@nxp.com', Zhang, Tianfei, Wu, Hao > -----Original Message----- > From: Xu, Rosen > Sent: Monday, April 02, 2018 12:26 > To: 'gaetan.rivet@6wind.com' <gaetan.rivet@6wind.com> > Cc: 'dev@dpdk.org' <dev@dpdk.org>; Doherty, Declan > <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; 'shreyansh.jain@nxp.com' > <shreyansh.jain@nxp.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, > Hao <hao.wu@intel.com> > Subject: RE: [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code > > > > > -----Original Message----- > > From: Xu, Rosen > > Sent: Sunday, April 01, 2018 0:31 > > To: gaetan.rivet@6wind.com > > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > > Richardson, Bruce <bruce.richardson@intel.com>; > > shreyansh.jain@nxp.com; Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, > > Hao <hao.wu@intel.com> > > Subject: RE: [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code > > > > > > > > > -----Original Message----- > > > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com] > > > Sent: Wednesday, March 28, 2018 21:52 > > > To: Xu, Rosen <rosen.xu@intel.com> > > > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > > > Richardson, Bruce <bruce.richardson@intel.com>; > > > shreyansh.jain@nxp.com; Zhang, Tianfei <tianfei.zhang@intel.com>; > > > Wu, Hao <hao.wu@intel.com> > > > Subject: Re: [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code > > > > > > On Wed, Mar 28, 2018 at 05:29:54PM +0800, Rosen Xu wrote: > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > > > --- > > > > drivers/bus/Makefile | 1 + > > > > drivers/bus/ifpga/Makefile | 33 ++ > > > > drivers/bus/ifpga/ifpga_bus.c | 562 > > > ++++++++++++++++++++++++++++ > > > > drivers/bus/ifpga/ifpga_common.c | 141 +++++++ > > > > drivers/bus/ifpga/ifpga_common.h | 22 ++ > > > > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > > > > drivers/bus/ifpga/rte_bus_ifpga.h | 140 +++++++ > > > > drivers/bus/ifpga/rte_bus_ifpga_version.map | 8 + > > > > 8 files changed, 938 insertions(+) create mode 100644 > > > > drivers/bus/ifpga/Makefile create mode 100644 > > > > drivers/bus/ifpga/ifpga_bus.c create mode 100644 > > > > drivers/bus/ifpga/ifpga_common.c create mode 100644 > > > > drivers/bus/ifpga/ifpga_common.h create mode 100644 > > > > drivers/bus/ifpga/ifpga_logs.h create mode 100644 > > > > drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 > > > > drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > > > > > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index > > > > 7ef2593..55d2dfe 100644 > > > > --- a/drivers/bus/Makefile > > > > +++ b/drivers/bus/Makefile > > > > @@ -7,5 +7,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa > > > > DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc > > > > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > > > > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > > > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > > > > > > > > include $(RTE_SDK)/mk/rte.subdir.mk diff --git > > > > a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile new file > > > > mode 100644 index 0000000..e611950 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/Makefile > > > > @@ -0,0 +1,33 @@ > > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel > > > > +Corporation > > > > > > Copyrigth 2018 (same comment for most SPDX tags, I think I saw 2017 > > > or a variation of it everywhere I think). > > > > It's done by PATCH v4. > > > > > > + > > > > +include $(RTE_SDK)/mk/rte.vars.mk > > > > + > > > > +# > > > > +# library name > > > > +# > > > > +LIB = librte_bus_ifpga.a > > > > + > > > > +CFLAGS += -O3 > > > > +CFLAGS += $(WERROR_FLAGS) > > > > + > > > > +# versioning export map > > > > +EXPORT_MAP := rte_bus_ifpga_version.map > > > > + > > > > +# library version > > > > +LIBABIVER := 1 > > > > + > > > > +VPATH += $(SRCDIR)/base > > > > + > > > > +SRCS-y += \ > > > > + ifpga_bus.c \ > > > > + ifpga_common.c > > > > + > > > > +LDLIBS += -lrte_eal > > > > > > you should probably load librte_pci. > > > You use afterward functions (at least address comparison). > > > I haven't tested the SHARED build, but my guess is that it would break. > > > > The FPGA BUS is based PCI(IFPGA is probed by PCI), do you think so > > users to add it? > > > > > On that note, you haven't acted on my previous remarks to use the > > > common PCI utilities provided. > > > > It's done in PATCH v4. > > > > > > + > > > > +# > > > > +# Export include files > > > > +# > > > > +SYMLINK-y-include += rte_bus_ifpga.h > > > > + > > > > +include $(RTE_SDK)/mk/rte.lib.mk > > > > diff --git a/drivers/bus/ifpga/ifpga_bus.c > > > > b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index > > > > 0000000..092be65 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/ifpga_bus.c > > > > @@ -0,0 +1,562 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2017 Intel Corporation */ > > > > + > > > > +#include <string.h> > > > > +#include <inttypes.h> > > > > +#include <stdint.h> > > > > +#include <stdlib.h> > > > > +#include <stdio.h> > > > > +#include <sys/queue.h> > > > > +#include <sys/mman.h> > > > > +#include <sys/types.h> > > > > +#include <unistd.h> > > > > +#include <fcntl.h> > > > > + > > > > +#include <rte_errno.h> > > > > +#include <rte_bus.h> > > > > +#include <rte_per_lcore.h> > > > > +#include <rte_memory.h> > > > > +#include <rte_memzone.h> > > > > +#include <rte_eal.h> > > > > +#include <rte_common.h> > > > > + > > > > +#include <rte_devargs.h> > > > > +#include <rte_pci.h> > > > > +#include <rte_bus_pci.h> > > > > +#include <rte_kvargs.h> > > > > +#include <rte_alarm.h> > > > > + > > > > +#include "rte_rawdev.h" > > > > +#include "rte_rawdev_pmd.h" > > > > +#include "rte_bus_ifpga.h" > > > > +#include "ifpga_logs.h" > > > > +#include "ifpga_common.h" > > > > + > > > > +int ifpga_bus_logtype; > > > > + > > > > +/* register a ifpga bus based driver */ void > > > > +rte_ifpga_driver_register(struct rte_afu_driver *driver) { > > > > + RTE_VERIFY(driver); > > > > + > > > > + TAILQ_INSERT_TAIL(&rte_ifpga_bus.driver_list, driver, next); } > > > > + > > > > +/* un-register a fpga bus based driver */ void > > > > +rte_ifpga_driver_unregister(struct rte_afu_driver *driver) { > > > > + TAILQ_REMOVE(&rte_ifpga_bus.driver_list, driver, next); } > > > > + > > > > +static struct rte_ifpga_device * > > > > +ifpga_find_ifpga_dev(const struct rte_pci_addr *pci_addr) { > > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > > + > > > > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > > > > + if (!rte_pci_addr_cmp(&ifpga_dev->pci_addr, pci_addr)) > > > > + return ifpga_dev; > > > > + } > > > > + return NULL; > > > > +} > > > > + > > > > +static struct rte_afu_device * > > > > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > > > > + const struct rte_afu_id *afu_id) { > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + > > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > > > > + return afu_dev; > > > > + } > > > > + return NULL; > > > > +} > > > > + > > > > +static const char * const valid_args[] = { > > > > +#define IFPGA_ARG_BDF "bdf" > > > > + IFPGA_ARG_BDF, > > > > +#define IFPGA_ARG_PORT "port" > > > > + IFPGA_ARG_PORT, > > > > +#define IFPGA_ARG_PATH "path" > > > > + IFPGA_ARG_PATH, > > > > +#define IFPGA_ARG_UUID_HIGH "uuid_high" > > > > + IFPGA_ARG_UUID_HIGH, > > > > +#define IFPGA_ARG_UUID_LOW "uuid_low" > > > > + IFPGA_ARG_UUID_LOW, > > > > +#define IFPGA_ARG_PR_ENABLE "pr_enable" > > > > + IFPGA_ARG_PR_ENABLE, > > > > +#define IFPGA_ARG_DEBUG "debug" > > > > + IFPGA_ARG_DEBUG, > > > > + NULL > > > > +}; > > > > > > So these parameters are parsed during scan afterward, taken from the > > > PCI device that was probed. > > > > > > Given the kerfuffle of the VIRTUAL devtype in the EAL option, I'm > > > not sure how the PCI bus would react with your IFPGA PCI device > > > being probed by its blacklist operation: the devargs would be null. > > > Do you segfault during your scan? Have you tested this? > > > > > > Why are those parameters parsed again here on this note? Shouldn't > > > they be parsed by the PCI device being probed with a custome PCI > > > driver that you would have added (and I think you provide it > > > afterward), that would spawn the rawdev with the relevant metadata? > > > Then you could scan this rawdev here and have all these parameters > > already parsed? > > > > > > Is there a reason that you did all this in this order? (specific > > > initialization step for example?) > > > Pls see PATCH v4 and my reply for your email of PATCH v3 1/6. > The command line is in that email. > > For PATCH v4 I have removed all modification from eal library. > I use vdev driver to take parameter configuration, and this vdev driver call > rte_eal_hotplug_add() to add afu device and trigger scan/probe. This is the run command example(take 2 afu device for example): testpmd -c 0x3 -n 4 --socket-mem 1024,0 --huge-dir=/mnt/huge \ --vdev 'net_ifpga_cfg0,bdf=5e:00.0,port=0,afu_bts=./afu_1.gbs' \ --vdev 'net_ifpga_cfg1,bdf=be:00.0,port=0,afu_bts=./afu_2.gbs' -- -i --no-numa > > > > + > > > > +/* > > > > + * Scan the content of the FPGA bus, and the devices in the > > > > +devices > > > > + * list > > > > + */ > > > > +static struct rte_afu_device * > > > > +rte_ifpga_scan_one(struct rte_devargs *devargs, > > > > + struct rte_ifpga_device *ifpga_dev) { > > > > + struct rte_kvargs *kvlist = NULL; > > > > + struct rte_bus *pci_bus = NULL; > > > > + struct rte_device *dev = NULL; > > > > + struct rte_rawdev *rawdev = NULL; > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + struct rte_afu_pr_conf afu_pr_conf; > > > > + int ret = 0; > > > > + char *path = NULL; > > > > + int pr_enable = 1; > > > > + int debug = 0; > > > > + > > > > + memset((char *)(&afu_pr_conf), 0, sizeof(struct > > > > +rte_afu_pr_conf)); > > > > + > > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > > + if (!kvlist) { > > > > + IFPGA_BUS_ERR("error when parsing param"); > > > > + goto end; > > > > + } > > > > + > > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { > > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, > > > > + &ifpga_get_bdf_arg, &afu_pr_conf.afu_id.pci_addr) > > > < 0) { > > > > + IFPGA_BUS_ERR("error to parse %s", > > > IFPGA_ARG_BDF); > > > > + goto end; > > > > + } > > > > + } else { > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > + IFPGA_ARG_PATH); > > > > + goto end; > > > > + } > > > > + > > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, > > > > + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { > > > > + IFPGA_BUS_ERR("error to parse %s", > > > > + IFPGA_ARG_PORT); > > > > + goto end; > > > > + } > > > > + } else { > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > + IFPGA_ARG_PATH); > > > > + goto end; > > > > + } > > > > + > > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PATH) == 1) { > > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PATH, > > > > + &ifpga_get_string_arg, &path) < 0) { > > > > + IFPGA_BUS_ERR("error to parse %s", > > > > + IFPGA_ARG_PATH); > > > > + goto end; > > > > + } > > > > + } else { > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > + IFPGA_ARG_PATH); > > > > + goto end; > > > > + } > > > > + > > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_UUID_HIGH) == 1) { > > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_UUID_HIGH, > > > > + &ifpga_get_integer64_arg, &afu_pr_conf.afu_id.uuid_high) > > > < 0) { > > > > + IFPGA_BUS_ERR("error to parse %s", > > > > + IFPGA_ARG_UUID_HIGH); > > > > + goto end; > > > > + } > > > > + } else { > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > + IFPGA_ARG_PATH); > > > > + goto end; > > > > + } > > > > + > > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_UUID_LOW) == 1) { > > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_UUID_LOW, > > > > + &ifpga_get_integer64_arg, &afu_pr_conf.afu_id.uuid_low) < > > > 0) { > > > > + IFPGA_BUS_ERR("error to parse %s", > > > > + IFPGA_ARG_UUID_LOW); > > > > + goto end; > > > > + } > > > > + } else { > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > + IFPGA_ARG_PATH); > > > > + goto end; > > > > + } > > > > + > > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PR_ENABLE) == 1) { > > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PR_ENABLE, > > > > + &ifpga_get_integer32_arg, &pr_enable) < 0) { > > > > + IFPGA_BUS_ERR("error to parse %s", > > > > + IFPGA_ARG_UUID_HIGH); > > > > + goto end; > > > > + } > > > > + } > > > > + > > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_DEBUG) == 1) { > > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_DEBUG, > > > > + &ifpga_get_integer32_arg, &debug) < 0) { > > > > + IFPGA_BUS_ERR("error to parse %s", > > > > + IFPGA_ARG_UUID_HIGH); > > > > + goto end; > > > > + } > > > > + } > > > > + > > > > + if (!debug) { > > > > + pci_bus = rte_bus_find_by_name("pci"); > > > > + if (pci_bus == NULL) { > > > > + IFPGA_BUS_ERR("unable to find PCI bus\n"); > > > > + goto end; > > > > + } > > > > + > > > > + dev = pci_bus->find_device(NULL, > > > > + ifpga_pci_addr_cmp, > > > > + &afu_pr_conf.afu_id.pci_addr); > > > > + if (dev == NULL) { > > > > + IFPGA_BUS_ERR("unable to find PCI device\n"); > > > > + goto end; > > > > + } > > > > + } else { > > > > + IFPGA_BUS_DEBUG("pci_addr domain : %x\n", > > > > + afu_pr_conf.afu_id.pci_addr.domain); > > > > + IFPGA_BUS_DEBUG("pci_addr bus : %x\n", > > > > + afu_pr_conf.afu_id.pci_addr.bus); > > > > + IFPGA_BUS_DEBUG("pci_addr devid : %x\n", > > > > + afu_pr_conf.afu_id.pci_addr.devid); > > > > + IFPGA_BUS_DEBUG("pci_addr function : %x\n", > > > > + afu_pr_conf.afu_id.pci_addr.function); > > > > + IFPGA_BUS_DEBUG("uuid_low : %lx\n", > > > > + afu_pr_conf.afu_id.uuid_low); > > > > + IFPGA_BUS_DEBUG("uuid_high : %lx\n", > > > > + afu_pr_conf.afu_id.uuid_high); > > > > + IFPGA_BUS_DEBUG("afu port : %x\n", > > > > + afu_pr_conf.afu_id.port); > > > > + } > > > > + > > > > + rawdev = ifpga_dev->rdev; > > > > + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) > > > > + goto end; > > > > + > > > > + afu_dev = calloc(1, sizeof(*afu_dev)); > > > > + if (!afu_dev) > > > > + goto end; > > > > + > > > > + afu_dev->device.devargs = devargs; > > > > + afu_dev->device.numa_node = SOCKET_ID_ANY; > > > > + afu_dev->device.name = devargs->name; > > > > + afu_dev->rawdev = rawdev; > > > > + afu_dev->id.pci_addr.domain = afu_pr_conf.afu_id.pci_addr.domain; > > > > + afu_dev->id.pci_addr.bus = afu_pr_conf.afu_id.pci_addr.bus; > > > > + afu_dev->id.pci_addr.devid = afu_pr_conf.afu_id.pci_addr.devid; > > > > + afu_dev->id.pci_addr.function = > > > > +afu_pr_conf.afu_id.pci_addr.function; > > > > > > Can you add a function called rte_pci_addr_cpy in librte_pci and use > > > it instead of doing this by hand here? Others would benefit from this. > > > > > > > + afu_dev->id.uuid_low = afu_pr_conf.afu_id.uuid_low; > > > > + afu_dev->id.uuid_high = afu_pr_conf.afu_id.uuid_high; > > > > + afu_dev->id.port = afu_pr_conf.afu_id.port; > > > > + afu_dev->ifpga_dev = ifpga_dev; > > > > + > > > > + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) > > > > + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); > > > > + > > > > + if (rawdev->dev_ops && > > > > + rawdev->dev_ops->dev_start && > > > > + rawdev->dev_ops->dev_start(rawdev)) > > > > + goto free_dev; > > > > + if (pr_enable) { > > > > + strncpy(afu_pr_conf.bs_path, path, strlen(path)); > > > > > > strncpy is dangerous here, please use strlcpy or snprintf. > > > (And your use of strncpy is dangerous, you are limitting the write > > > to the length of the source, not to the size of the destination.) > > > > > > > + if (rawdev->dev_ops->firmware_load && > > > > + rawdev->dev_ops->firmware_load(rawdev, > > > > + &afu_pr_conf)){ > > > > + printf("firmware load error %d\n", ret); > > > > + goto free_dev; > > > > + } > > > > + } > > > > + > > > > + return afu_dev; > > > > + > > > > +free_dev: > > > > + free(afu_dev); > > > > +end: > > > > + if (kvlist) > > > > + rte_kvargs_free(kvlist); > > > > + if (path) > > > > + free(path); > > > > + > > > > + return NULL; > > > > +} > > > > + > > > > +/* > > > > + * Scan the content of the FPGA bus, and the devices in the > > > > +devices > > > > + * list > > > > + */ > > > > +static int > > > > +rte_ifpga_scan(void) > > > > +{ > > > > + struct rte_ifpga_device *ifpga_dev; > > > > + struct rte_devargs *devargs; > > > > + struct rte_kvargs *kvlist = NULL; > > > > + struct rte_pci_addr pci_addr; > > > > + struct rte_rawdev *rawdev = NULL; > > > > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + > > > > + /* for FPGA devices we scan the devargs_list populated via > > > > +cmdline > > > */ > > > > + TAILQ_FOREACH(devargs, &devargs_list, next) { > > > > + if (devargs->bus != &rte_ifpga_bus.bus) > > > > + continue; > > > > + > > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > > + if (!kvlist) { > > > > + IFPGA_BUS_ERR("error when parsing param"); > > > > + goto end; > > > > + } > > > > + > > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { > > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, > > > > + &ifpga_get_bdf_arg, &pci_addr) < 0) { > > > > + IFPGA_BUS_ERR("error to parse %s", > > > > + IFPGA_ARG_BDF); > > > > + goto end; > > > > + } > > > > + } else { > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > + IFPGA_ARG_PATH); > > > > + goto end; > > > > + } > > > > + > > > > + memset(name, 0, sizeof(name)); > > > > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, > > > "IFPGA:%x:%x:%x", > > > > + pci_addr.bus, pci_addr.devid, pci_addr.function); > > > > + > > > > + rawdev = rte_rawdev_pmd_get_named_dev(name); > > > > + if (!rawdev) > > > > + goto end; > > > > + > > > > + if (ifpga_find_ifpga_dev(&pci_addr)) > > > > + goto end; > > > > + > > > > + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); > > > > + if (!ifpga_dev) > > > > + goto end; > > > > + > > > > + ifpga_dev->pci_addr.domain = pci_addr.domain; > > > > + ifpga_dev->pci_addr.bus = pci_addr.bus; > > > > + ifpga_dev->pci_addr.devid = pci_addr.devid; > > > > + ifpga_dev->pci_addr.function = pci_addr.function; > > > > > > Again, PCI copy would be nice instead of doing it by hand. > > > > > > > + ifpga_dev->rdev = rawdev; > > > > + TAILQ_INIT(&ifpga_dev->afu_list); > > > > + > > > > + TAILQ_INSERT_TAIL(&rte_ifpga_bus.ifpga_list, ifpga_dev, > > > next); > > > > + afu_dev = rte_ifpga_scan_one(devargs, ifpga_dev); > > > > + if (afu_dev != NULL) > > > > + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, > > > next); > > > > + } > > > > + > > > > +end: > > > > + if (kvlist) > > > > + rte_kvargs_free(kvlist); > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int > > > > +ifpga_probe_one_driver(struct rte_afu_driver *drv, > > > > + struct rte_afu_device *afu_dev) { > > > > + int ret; > > > > + > > > > + if ((drv->id.pci_addr.bus == afu_dev->id.pci_addr.bus) && > > > > + (drv->id.pci_addr.devid == afu_dev->id.pci_addr.devid) && > > > > + (drv->id.pci_addr.function == afu_dev->id.pci_addr.function) > > > && > > > > > > There is the rte_pci_addr_cmp function that should be used here instead. > > > Additionally, you haven't responded to my comment about ignoring the > > > Domain part of the address. Why? Is there a reason for this? Is the > > > domain irrelevant? If so, it should be documented. If not, please > > > use the relevant function instead. > > > > > > > + (drv->id.uuid_low == afu_dev->id.uuid_low) && > > > > + (drv->id.uuid_high == afu_dev->id.uuid_high) && > > > > + (drv->id.port == afu_dev->id.port)) { > > > > + > > > > + afu_dev->driver = drv; > > > > + > > > > + /* call the driver probe() function */ > > > > + ret = drv->probe(afu_dev); > > > > + if (ret) > > > > + afu_dev->driver = NULL; > > > > + return ret; > > > > + } > > > > + > > > > + /* return positive value if driver doesn't support this device */ > > > > + return 1; > > > > +} > > > > + > > > > +static int > > > > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) { > > > > + const char *name; > > > > + struct rte_afu_driver *drv = NULL; > > > > + int rc; > > > > + > > > > + if (afu_dev == NULL) > > > > + return -1; > > > > + > > > > + /* Check if a driver is already loaded */ > > > > + if (afu_dev->driver != NULL) > > > > + return 0; > > > > + > > > > + name = rte_ifpga_device_name(afu_dev); > > > > + IFPGA_BUS_DEBUG("Search driver %s to probe device %s\n", name, > > > > + rte_ifpga_device_name(afu_dev)); > > > > + > > > > + TAILQ_FOREACH(drv, &rte_ifpga_bus.driver_list, next) { > > > > + rc = ifpga_probe_one_driver(drv, afu_dev); > > > > + if (rc < 0) > > > > + /* negative value is an error */ > > > > + return -1; > > > > + if (rc > 0) > > > > + /* positive value means driver doesn't support it */ > > > > + continue; > > > > + return 0; > > > > + } > > > > + return 1; > > > > +} > > > > + > > > > +/* > > > > + * Scan the content of the PCI bus, and call the probe() function > > > > +for > > > > > > One should read IFPGA bus here I guess. > > > > > > > + * all registered drivers that have a matching entry in its > > > > +id_table > > > > + * for discovered devices. > > > > + */ > > > > +static int > > > > +rte_ifpga_probe(void) > > > > +{ > > > > + struct rte_ifpga_device *ifpga_dev; > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + int ret = 0; > > > > + > > > > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > > + > > > > + if (afu_dev->device.driver) > > > > + continue; > > > > + > > > > + ret = ifpga_probe_all_drivers(afu_dev); > > > > + if (ret < 0) > > > > + IFPGA_BUS_ERR("failed to initialize %s > > > device\n", > > > > + rte_ifpga_device_name(afu_dev)); > > > > + } > > > > + } > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int > > > > +rte_ifpga_plug(struct rte_device *dev) { > > > > + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); > > > > +} > > > > + > > > > +static int ifpga_remove_driver(struct rte_afu_device *afu_dev) { > > > > + const char *name; > > > > + const struct rte_afu_driver *driver; > > > > + > > > > + name = rte_ifpga_device_name(afu_dev); > > > > + if (!afu_dev->device.driver) { > > > > + IFPGA_BUS_DEBUG("no driver attach to device %s\n", > > > name); > > > > + return 1; > > > > + } > > > > + > > > > + driver = container_of(afu_dev->device.driver, > > > > + const struct rte_afu_driver, > > > > + driver); > > > > > > No RTE_DRV_TO_AFU_CONST? It would be easier to read. > > > > > > > + return driver->remove(afu_dev); > > > > +} > > > > + > > > > +static int > > > > +rte_ifpga_unplug(struct rte_device *dev) { > > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + struct rte_devargs *devargs = NULL; > > > > + int ret; > > > > + > > > > + if (dev == NULL) > > > > + return -EINVAL; > > > > + > > > > + afu_dev = RTE_DEV_TO_AFU(dev); > > > > + if (!dev) > > > > + return -ENOENT; > > > > + > > > > + ifpga_dev = afu_dev->ifpga_dev; > > > > + devargs = dev->devargs; > > > > + > > > > + ret = ifpga_remove_driver(afu_dev); > > > > + if (ret) > > > > + return ret; > > > > + > > > > + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); > > > > + > > > > + TAILQ_REMOVE(&devargs_list, devargs, next); > > > > + > > > > + free(devargs->args); > > > > + free(devargs); > > > > + free(afu_dev); > > > > + return 0; > > > > + > > > > +} > > > > + > > > > +static struct rte_device * > > > > +rte_ifpga_find_device(const struct rte_device *start, > > > > + rte_dev_cmp_t cmp, const void *data) { > > > > + struct rte_ifpga_device *ifpga_dev; > > > > + struct rte_afu_device *afu_dev; > > > > + > > > > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > > + if (start && &afu_dev->device == start) { > > > > + start = NULL; > > > > + continue; > > > > + } > > > > + if (cmp(&afu_dev->device, data) == 0) > > > > + return &afu_dev->device; > > > > + } > > > > + } > > > > + return NULL; > > > > +} > > > > +static int > > > > +rte_ifpga_parse(const char *name, void *addr) { > > > > + struct rte_afu_driver **out = addr; > > > > + struct rte_afu_driver *driver = NULL; > > > > + > > > > + TAILQ_FOREACH(driver, &rte_ifpga_bus.driver_list, next) { > > > > + if (strncmp(driver->driver.name, name, > > > > + strlen(driver->driver.name)) == 0) > > > > + break; > > > > + if (driver->driver.alias && > > > > + strncmp(driver->driver.alias, name, > > > > + strlen(driver->driver.alias)) == 0) > > > > + break; > > > > + } > > > > + if (driver != NULL && > > > > + addr != NULL) > > > > + *out = driver; > > > > + return driver == NULL; > > > > +} > > > > + > > > > +struct rte_ifpga_bus rte_ifpga_bus = { > > > > + .bus = { > > > > + .scan = rte_ifpga_scan, > > > > + .probe = rte_ifpga_probe, > > > > + .find_device = rte_ifpga_find_device, > > > > > > Wrong indentation (2 tabs instead of one). > > > > > > > + .plug = rte_ifpga_plug, > > > > + .unplug = rte_ifpga_unplug, > > > > + .parse = rte_ifpga_parse, > > > > + }, > > > > + .ifpga_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.ifpga_list), > > > > + .driver_list = > > > > +TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.driver_list), > > > > > > Why are those lists part of the bus definition? Can you do the same > > > as the vdev bus and have them statically declared in your source file only? > > > > > > Is there a reason you want them part of the bus, do you need to > > > access it somewhere? > > > > > > > +}; > > > > + > > > > +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus.bus); > > > > + > > > > +RTE_INIT(ifpga_init_log) > > > > +{ > > > > + ifpga_bus_logtype = rte_log_register("bus.ifpga"); > > > > + if (ifpga_bus_logtype >= 0) > > > > + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); } > > > > + > > > > diff --git a/drivers/bus/ifpga/ifpga_common.c > > > > b/drivers/bus/ifpga/ifpga_common.c > > > > new file mode 100644 > > > > index 0000000..03a8d48 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/ifpga_common.c > > > > @@ -0,0 +1,141 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2017 Intel Corporation */ > > > > + > > > > +#include <string.h> > > > > +#include <inttypes.h> > > > > +#include <stdint.h> > > > > +#include <stdlib.h> > > > > +#include <stdio.h> > > > > +#include <sys/queue.h> > > > > +#include <sys/mman.h> > > > > +#include <sys/types.h> > > > > +#include <unistd.h> > > > > +#include <fcntl.h> > > > > + > > > > +#include <rte_errno.h> > > > > +#include <rte_bus.h> > > > > +#include <rte_per_lcore.h> > > > > +#include <rte_memory.h> > > > > +#include <rte_memzone.h> > > > > +#include <rte_eal.h> > > > > +#include <rte_common.h> > > > > + > > > > +#include <rte_devargs.h> > > > > +#include <rte_pci.h> > > > > +#include <rte_bus_pci.h> > > > > +#include <rte_kvargs.h> > > > > +#include <rte_alarm.h> > > > > + > > > > +#include "rte_bus_ifpga.h" > > > > +#include "ifpga_logs.h" > > > > +#include "ifpga_common.h" > > > > + > > > > +int ifpga_get_string_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args) { > > > > + if (!value || !extra_args) > > > > + return -EINVAL; > > > > + > > > > + *(char **)extra_args = strdup(value); > > > > + > > > > + if (!*(char **)extra_args) > > > > + return -ENOMEM; > > > > + > > > > + return 0; > > > > +} > > > > +int ifpga_get_integer32_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args) { > > > > + if (!value || !extra_args) > > > > + return -EINVAL; > > > > + > > > > + *(int *)extra_args = strtoull(value, NULL, 0); > > > > + > > > > + return 0; > > > > +} > > > > +int ifpga_get_integer64_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args) { > > > > + if (!value || !extra_args) > > > > + return -EINVAL; > > > > + > > > > + *(uint64_t *)extra_args = strtoull(value, NULL, 0); > > > > + > > > > + return 0; > > > > +} > > > > +int ifpga_get_unsigned_long(const char *str, int base) { > > > > + unsigned long num; > > > > + char *end = NULL; > > > > + > > > > + errno = 0; > > > > + > > > > + num = strtoul(str, &end, base); > > > > + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) > > > > + return -1; > > > > + > > > > + return num; > > > > + > > > > +} > > > > > > Missing newline here. > > > > > > > +int ifpga_get_bdf_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args) { #define MAX_PATH_LEN 1024 > > > > + struct rte_pci_addr *addr; > > > > + int num[4]; > > > > + char str[MAX_PATH_LEN]; > > > > + int i, j; > > > > + > > > > + if (!value || !extra_args) > > > > + return -EINVAL; > > > > + > > > > + addr = (struct rte_pci_addr *)extra_args; > > > > + strcpy(str, value); > > > > + memset(num, 0, 4 * sizeof(num[0])); > > > > + i = strlen(str) - 1; > > > > + j = 3; > > > > + while (i > 0 && j >= 0) { > > > > + while ((str[i - 1] != ':' && str[i - 1] != '.') && i > 0) > > > > + i--; > > > > + num[j--] = ifpga_get_unsigned_long(&str[i], 16); > > > > + i--; > > > > + if (i >= 0) > > > > + str[i] = '\0'; > > > > + } > > > > + addr->domain = num[0]; > > > > + addr->bus = num[1]; > > > > + addr->devid = num[2]; > > > > + addr->function = num[3]; > > > > + printf("[%s]: bdf %04d:%02d:%02d.%02d\n", > > > > + __func__, > > > > + addr->domain, > > > > + addr->bus, > > > > + addr->devid, > > > > + addr->function); > > > > + > > > > + return 0; > > > > +} > > > > > > Use rte_pci_addr_parse instead of rewriting it please. > > > > > > > + > > > > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > > > + const struct rte_afu_id *afu_id1) { > > > > + if ((afu_id0->pci_addr.bus == afu_id1->pci_addr.bus) && > > > > + (afu_id0->pci_addr.devid == afu_id1->pci_addr.devid) && > > > > + (afu_id0->pci_addr.function == afu_id1->pci_addr.function) > > > && > > > > + (afu_id0->uuid_low == afu_id1->uuid_low) && > > > > + (afu_id0->uuid_high == afu_id1->uuid_high) && > > > > + (afu_id0->port == afu_id1->port)) { > > > > + return 0; > > > > + } else > > > > + return 1; > > > > +} > > > > > > You used the exact same check in the ifpga_bus.c file, why not call > > > this function instead? > > > > > > > +int ifpga_pci_addr_cmp(const struct rte_device *dev, > > > > + const void *_pci_addr) > > > > +{ > > > > + struct rte_pci_device *pdev; > > > > + const struct rte_pci_addr *paddr = _pci_addr; > > > > + > > > > + pdev = RTE_DEV_TO_PCI(*(struct rte_device **)(void *)&dev); > > > > + return rte_eal_compare_pci_addr(&pdev->addr, paddr); > > > > > > This function is deprecated (I should mark is as so to forbid its use). > > > Use rte_pci_addr_cmp() instead. > > > > > > > +} > > > > diff --git a/drivers/bus/ifpga/ifpga_common.h > > > > b/drivers/bus/ifpga/ifpga_common.h > > > > new file mode 100644 > > > > index 0000000..48a5012 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/ifpga_common.h > > > > @@ -0,0 +1,22 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2017 Intel Corporation */ > > > > + > > > > +#ifndef _IFPGA_COMMON_H_ > > > > +#define _IFPGA_COMMON_H_ > > > > + > > > > +int ifpga_get_string_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args); int > > > > +ifpga_get_integer32_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args); int > > > > +ifpga_get_integer64_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args); int > > > > +ifpga_get_unsigned_long(const char *str, int base); int > > > > +ifpga_get_bdf_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args); int ifpga_afu_id_cmp(const > > > > +struct rte_afu_id *afu_id0, > > > > + const struct rte_afu_id *afu_id1); int ifpga_pci_addr_cmp(const > > > > +struct rte_device *dev, > > > > + const void *_pci_addr); > > > > + > > > > +#endif /* _IFPGA_COMMON_H_ */ > > > > diff --git a/drivers/bus/ifpga/ifpga_logs.h > > > > b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index > > > > 0000000..e3f4849 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/ifpga_logs.h > > > > @@ -0,0 +1,31 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2017 Intel Corporation */ > > > > + > > > > +#ifndef _IFPGA_LOGS_H_ > > > > +#define _IFPGA_LOGS_H_ > > > > + > > > > +#include <rte_log.h> > > > > + > > > > +extern int ifpga_bus_logtype; > > > > + > > > > +#define IFPGA_LOG(level, fmt, args...) \ > > > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > > > + __func__, ##args) > > > > + > > > > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > > > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > > > + __func__, ##args) > > > > + > > > > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > > > > + > > > > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > > > > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) #define > > IFPGA_BUS_INFO(fmt, > > > > +args...) \ > > > > + IFPGA_BUS_LOG(INFO, fmt, ## args) #define IFPGA_BUS_ERR(fmt, > > > > +args...) \ > > > > + IFPGA_BUS_LOG(ERR, fmt, ## args) #define IFPGA_BUS_WARN(fmt, > > > > +args...) \ > > > > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > > > > + > > > > +#endif /* _IFPGA_BUS_LOGS_H_ */ > > > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h > > > > b/drivers/bus/ifpga/rte_bus_ifpga.h > > > > new file mode 100644 > > > > index 0000000..7290149 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > > > > @@ -0,0 +1,140 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2017 Intel Corporation */ > > > > + > > > > +#ifndef _RTE_BUS_IFPGA_H_ > > > > +#define _RTE_BUS_IFPGA_H_ > > > > + > > > > +/** > > > > + * @file > > > > + * > > > > + * RTE PCI Bus Interface > > > > + */ > > > > + > > > > +#ifdef __cplusplus > > > > +extern "C" { > > > > +#endif > > > > + > > > > +#include <rte_bus.h> > > > > +#include <rte_pci.h> > > > > + > > > > +/** Name of Intel FPGA Bus */ > > > > +#define IFPGA_BUS_NAME ifpga > > > > + > > > > +/* Forward declarations */ > > > > +struct rte_ifpga_device; > > > > +struct rte_afu_device; > > > > +struct rte_afu_driver; > > > > + > > > > +/** List of Intel FPGA devices */ > > > > +TAILQ_HEAD(rte_ifpga_device_list, rte_ifpga_device); > > > > +/** List of Intel AFU devices */ > > > > +TAILQ_HEAD(rte_afu_device_list, rte_afu_device); > > > > +/** List of AFU drivers */ > > > > +TAILQ_HEAD(rte_afu_driver_list, rte_afu_driver); > > > > > > Is there a reason for you to expose your lists publicly? > > > These symbols should be made private to your bus unless necessary. > > > > > > > + > > > > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > > > > + > > > > +/** > > > > + * A structure describing an ID for a AFU driver. Each driver > > > > +provides a > > > > + * table of these IDs for each device that it supports. > > > > + */ > > > > +struct rte_afu_id { > > > > + struct rte_pci_addr pci_addr; > > > > > > You use a symbol from librte_pci, without linking it. > > > > > > > + uint64_t uuid_low; > > > > + uint64_t uuid_high; > > > > + int port; > > > > +} __attribute__ ((packed)); > > > > + > > > > +/** > > > > + * A structure pr configuration AFU driver. > > > > + */ > > > > + > > > > +struct rte_afu_pr_conf { > > > > + struct rte_afu_id afu_id; > > > > + int pr_enable; > > > > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > > > +}; > > > > + > > > > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > > > > + > > > > +/** > > > > + * A structure describing a fpga device. > > > > + */ > > > > +struct rte_ifpga_device { > > > > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ > > > > + struct rte_pci_addr pci_addr; > > > > + struct rte_rawdev *rdev; > > > > + struct rte_afu_device_list afu_list; /**< List of AFU devices > > > > +*/ }; > > > > + > > > > +/** > > > > + * A structure describing a AFU device. > > > > + */ > > > > +struct rte_afu_device { > > > > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ > > > > + struct rte_device device; /**< Inherit core device */ > > > > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > > > > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > > > > + struct rte_afu_id id; /**< AFU id within FPGA. */ > > > > + uint32_t num_region; /**< number of regions found */ > > > > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > > > > + /**< PCI Memory Resource > > > */ > > > > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > > > > + struct rte_afu_driver *driver; /**< Associated driver */ > > > > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > > > +} __attribute__ ((packed)); > > > > + > > > > +/** > > > > + * @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) > > > > + > > > > +/** > > > > + * Initialisation function for the driver called during PCI probing. > > > > + */ > > > > +typedef int (afu_probe_t)(struct rte_afu_device *); > > > > + > > > > +/** > > > > + * Uninitialisation function for the driver called during hotplugging. > > > > + */ > > > > +typedef int (afu_remove_t)(struct rte_afu_device *); > > > > + > > > > +/** > > > > + * A structure describing a PCI device. > > > > + */ > > > > +struct rte_afu_driver { > > > > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > > > > + struct rte_driver driver; /**< Inherit core driver. */ > > > > + afu_probe_t *probe; /**< Device Probe function. */ > > > > + afu_remove_t *remove; /**< Device Remove function. */ > > > > + struct rte_afu_id id; /**< AFU id within FPGA. */ > > > > + uint32_t drv_flags; /**< Flags contolling handling of device. */ > > > > +}; > > > > + > > > > +/** > > > > + * Structure describing the Intel FPGA bus */ struct rte_ifpga_bus { > > > > + struct rte_bus bus; /**< Inherit the generic class */ > > > > + struct rte_ifpga_device_list ifpga_list; /**< List of FPGA devices */ > > > > + struct rte_afu_driver_list driver_list; /**< List of FPGA > > > > +drivers */ }; > > > > + > > > > +static inline const char * > > > > +rte_ifpga_device_name(const struct rte_afu_device *afu) { > > > > + if (afu && afu->device.name) > > > > + return afu->device.name; > > > > + return NULL; > > > > +} > > > > + > > > > +extern struct rte_ifpga_bus rte_ifpga_bus; > > > > + > > > > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); > > > > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > > > > + > > > > + > > > > +#endif /* _RTE_BUS_IFPGA_H_ */ > > > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > new file mode 100644 > > > > index 0000000..4edc9c0 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > @@ -0,0 +1,8 @@ > > > > +DPDK_18.05 { > > > > + global: > > > > + > > > > + rte_ifpga_driver_register; > > > > + rte_ifpga_driver_unregister; > > > > > > Wrong indentation. > > > It should be one tabulation, not 4 spaces. > > > > > > > + > > > > + local: *; > > > > +}; > > > > -- > > > > 1.8.3.1 > > > > > > > > > > -- > > > Gaëtan Rivet > > > 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code 2018-03-28 13:52 ` Gaëtan Rivet 2018-03-31 16:31 ` Xu, Rosen @ 2018-04-04 4:01 ` Xu, Rosen 1 sibling, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-04-04 4:01 UTC (permalink / raw) To: gaetan.rivet Cc: dev, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Zhang, Tianfei, Wu, Hao Hi Gaetan, > -----Original Message----- > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com] > Sent: Wednesday, March 28, 2018 21:52 > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com> > Subject: Re: [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code > > On Wed, Mar 28, 2018 at 05:29:54PM +0800, Rosen Xu wrote: > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > --- > > drivers/bus/Makefile | 1 + > > drivers/bus/ifpga/Makefile | 33 ++ > > drivers/bus/ifpga/ifpga_bus.c | 562 > ++++++++++++++++++++++++++++ > > drivers/bus/ifpga/ifpga_common.c | 141 +++++++ > > drivers/bus/ifpga/ifpga_common.h | 22 ++ > > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > > drivers/bus/ifpga/rte_bus_ifpga.h | 140 +++++++ > > drivers/bus/ifpga/rte_bus_ifpga_version.map | 8 + > > 8 files changed, 938 insertions(+) > > create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 > > drivers/bus/ifpga/ifpga_bus.c create mode 100644 > > drivers/bus/ifpga/ifpga_common.c create mode 100644 > > drivers/bus/ifpga/ifpga_common.h create mode 100644 > > drivers/bus/ifpga/ifpga_logs.h create mode 100644 > > drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 > > drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index > > 7ef2593..55d2dfe 100644 > > --- a/drivers/bus/Makefile > > +++ b/drivers/bus/Makefile > > @@ -7,5 +7,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa > > DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc > > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > > > > include $(RTE_SDK)/mk/rte.subdir.mk > > diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile > > new file mode 100644 index 0000000..e611950 > > --- /dev/null > > +++ b/drivers/bus/ifpga/Makefile > > @@ -0,0 +1,33 @@ > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel > > +Corporation > > Copyrigth 2018 (same comment for most SPDX tags, I think I saw 2017 or a > variation of it everywhere I think). For PATCH v4 and later patches, I have change all the Copyright 2017 to Copyright 2018. > > + > > +include $(RTE_SDK)/mk/rte.vars.mk > > + > > +# > > +# library name > > +# > > +LIB = librte_bus_ifpga.a > > + > > +CFLAGS += -O3 > > +CFLAGS += $(WERROR_FLAGS) > > + > > +# versioning export map > > +EXPORT_MAP := rte_bus_ifpga_version.map > > + > > +# library version > > +LIBABIVER := 1 > > + > > +VPATH += $(SRCDIR)/base > > + > > +SRCS-y += \ > > + ifpga_bus.c \ > > + ifpga_common.c > > + > > +LDLIBS += -lrte_eal > > you should probably load librte_pci. > You use afterward functions (at least address comparison). > I haven't tested the SHARED build, but my guess is that it would break. Yes, I have fixed it and test with SHARED build in PATCH v5. > On that note, you haven't acted on my previous remarks to use the common > PCI utilities provided. To be honest, FPGA BUS only need IFPGA_Rawdev name not pci_addr, so I have removed all pci_addr and pci common function in PATCH v5. > > + > > +# > > +# Export include files > > +# > > +SYMLINK-y-include += rte_bus_ifpga.h > > + > > +include $(RTE_SDK)/mk/rte.lib.mk > > diff --git a/drivers/bus/ifpga/ifpga_bus.c > > b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index > > 0000000..092be65 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_bus.c > > @@ -0,0 +1,562 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2017 Intel Corporation */ > > + > > +#include <string.h> > > +#include <inttypes.h> > > +#include <stdint.h> > > +#include <stdlib.h> > > +#include <stdio.h> > > +#include <sys/queue.h> > > +#include <sys/mman.h> > > +#include <sys/types.h> > > +#include <unistd.h> > > +#include <fcntl.h> > > + > > +#include <rte_errno.h> > > +#include <rte_bus.h> > > +#include <rte_per_lcore.h> > > +#include <rte_memory.h> > > +#include <rte_memzone.h> > > +#include <rte_eal.h> > > +#include <rte_common.h> > > + > > +#include <rte_devargs.h> > > +#include <rte_pci.h> > > +#include <rte_bus_pci.h> > > +#include <rte_kvargs.h> > > +#include <rte_alarm.h> > > + > > +#include "rte_rawdev.h" > > +#include "rte_rawdev_pmd.h" > > +#include "rte_bus_ifpga.h" > > +#include "ifpga_logs.h" > > +#include "ifpga_common.h" > > + > > +int ifpga_bus_logtype; > > + > > +/* register a ifpga bus based driver */ void > > +rte_ifpga_driver_register(struct rte_afu_driver *driver) { > > + RTE_VERIFY(driver); > > + > > + TAILQ_INSERT_TAIL(&rte_ifpga_bus.driver_list, driver, next); } > > + > > +/* un-register a fpga bus based driver */ void > > +rte_ifpga_driver_unregister(struct rte_afu_driver *driver) { > > + TAILQ_REMOVE(&rte_ifpga_bus.driver_list, driver, next); } > > + > > +static struct rte_ifpga_device * > > +ifpga_find_ifpga_dev(const struct rte_pci_addr *pci_addr) { > > + struct rte_ifpga_device *ifpga_dev = NULL; > > + > > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > > + if (!rte_pci_addr_cmp(&ifpga_dev->pci_addr, pci_addr)) > > + return ifpga_dev; > > + } > > + return NULL; > > +} > > + > > +static struct rte_afu_device * > > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > > + const struct rte_afu_id *afu_id) > > +{ > > + struct rte_afu_device *afu_dev = NULL; > > + > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > > + return afu_dev; > > + } > > + return NULL; > > +} > > + > > +static const char * const valid_args[] = { > > +#define IFPGA_ARG_BDF "bdf" > > + IFPGA_ARG_BDF, > > +#define IFPGA_ARG_PORT "port" > > + IFPGA_ARG_PORT, > > +#define IFPGA_ARG_PATH "path" > > + IFPGA_ARG_PATH, > > +#define IFPGA_ARG_UUID_HIGH "uuid_high" > > + IFPGA_ARG_UUID_HIGH, > > +#define IFPGA_ARG_UUID_LOW "uuid_low" > > + IFPGA_ARG_UUID_LOW, > > +#define IFPGA_ARG_PR_ENABLE "pr_enable" > > + IFPGA_ARG_PR_ENABLE, > > +#define IFPGA_ARG_DEBUG "debug" > > + IFPGA_ARG_DEBUG, > > + NULL > > +}; > > So these parameters are parsed during scan afterward, taken from the PCI > device that was probed. > > Given the kerfuffle of the VIRTUAL devtype in the EAL option, I'm not sure > how the PCI bus would react with your IFPGA PCI device being probed by its > blacklist operation: the devargs would be null. Do you segfault during your > scan? Have you tested this? > > Why are those parameters parsed again here on this note? Shouldn't they be > parsed by the PCI device being probed with a custome PCI driver that you > would have added (and I think you provide it afterward), that would spawn > the rawdev with the relevant metadata? Then you could scan this rawdev > here and have all these parameters already parsed? > > Is there a reason that you did all this in this order? (specific initialization step > for example?) For PATCH v4 and later patches, I have remove all the modifications from eal library, is it ok? > > + > > +/* > > + * Scan the content of the FPGA bus, and the devices in the devices > > + * list > > + */ > > +static struct rte_afu_device * > > +rte_ifpga_scan_one(struct rte_devargs *devargs, > > + struct rte_ifpga_device *ifpga_dev) > > +{ > > + struct rte_kvargs *kvlist = NULL; > > + struct rte_bus *pci_bus = NULL; > > + struct rte_device *dev = NULL; > > + struct rte_rawdev *rawdev = NULL; > > + struct rte_afu_device *afu_dev = NULL; > > + struct rte_afu_pr_conf afu_pr_conf; > > + int ret = 0; > > + char *path = NULL; > > + int pr_enable = 1; > > + int debug = 0; > > + > > + memset((char *)(&afu_pr_conf), 0, sizeof(struct rte_afu_pr_conf)); > > + > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > + if (!kvlist) { > > + IFPGA_BUS_ERR("error when parsing param"); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, > > + &ifpga_get_bdf_arg, &afu_pr_conf.afu_id.pci_addr) > < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > IFPGA_ARG_BDF); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PATH); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, > > + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_PORT); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PATH); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PATH) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PATH, > > + &ifpga_get_string_arg, &path) < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_PATH); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PATH); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_UUID_HIGH) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_UUID_HIGH, > > + &ifpga_get_integer64_arg, &afu_pr_conf.afu_id.uuid_high) > < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_UUID_HIGH); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PATH); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_UUID_LOW) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_UUID_LOW, > > + &ifpga_get_integer64_arg, &afu_pr_conf.afu_id.uuid_low) < > 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_UUID_LOW); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PATH); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PR_ENABLE) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PR_ENABLE, > > + &ifpga_get_integer32_arg, &pr_enable) < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_UUID_HIGH); > > + goto end; > > + } > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_DEBUG) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_DEBUG, > > + &ifpga_get_integer32_arg, &debug) < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_UUID_HIGH); > > + goto end; > > + } > > + } > > + > > + if (!debug) { > > + pci_bus = rte_bus_find_by_name("pci"); > > + if (pci_bus == NULL) { > > + IFPGA_BUS_ERR("unable to find PCI bus\n"); > > + goto end; > > + } > > + > > + dev = pci_bus->find_device(NULL, > > + ifpga_pci_addr_cmp, > > + &afu_pr_conf.afu_id.pci_addr); > > + if (dev == NULL) { > > + IFPGA_BUS_ERR("unable to find PCI device\n"); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_DEBUG("pci_addr domain : %x\n", > > + afu_pr_conf.afu_id.pci_addr.domain); > > + IFPGA_BUS_DEBUG("pci_addr bus : %x\n", > > + afu_pr_conf.afu_id.pci_addr.bus); > > + IFPGA_BUS_DEBUG("pci_addr devid : %x\n", > > + afu_pr_conf.afu_id.pci_addr.devid); > > + IFPGA_BUS_DEBUG("pci_addr function : %x\n", > > + afu_pr_conf.afu_id.pci_addr.function); > > + IFPGA_BUS_DEBUG("uuid_low : %lx\n", > > + afu_pr_conf.afu_id.uuid_low); > > + IFPGA_BUS_DEBUG("uuid_high : %lx\n", > > + afu_pr_conf.afu_id.uuid_high); > > + IFPGA_BUS_DEBUG("afu port : %x\n", > > + afu_pr_conf.afu_id.port); > > + } > > + > > + rawdev = ifpga_dev->rdev; > > + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) > > + goto end; > > + > > + afu_dev = calloc(1, sizeof(*afu_dev)); > > + if (!afu_dev) > > + goto end; > > + > > + afu_dev->device.devargs = devargs; > > + afu_dev->device.numa_node = SOCKET_ID_ANY; > > + afu_dev->device.name = devargs->name; > > + afu_dev->rawdev = rawdev; > > + afu_dev->id.pci_addr.domain = afu_pr_conf.afu_id.pci_addr.domain; > > + afu_dev->id.pci_addr.bus = afu_pr_conf.afu_id.pci_addr.bus; > > + afu_dev->id.pci_addr.devid = afu_pr_conf.afu_id.pci_addr.devid; > > + afu_dev->id.pci_addr.function = > > +afu_pr_conf.afu_id.pci_addr.function; > > Can you add a function called rte_pci_addr_cpy in librte_pci and use it > instead of doing this by hand here? Others would benefit from this. To be honest, FPGA BUS only need IFPGA_Rawdev name not pci_addr, so I have remove all pci_addr and pci common function in PATCH v5. So these copy may no need. > > + afu_dev->id.uuid_low = afu_pr_conf.afu_id.uuid_low; > > + afu_dev->id.uuid_high = afu_pr_conf.afu_id.uuid_high; > > + afu_dev->id.port = afu_pr_conf.afu_id.port; > > + afu_dev->ifpga_dev = ifpga_dev; > > + > > + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) > > + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); > > + > > + if (rawdev->dev_ops && > > + rawdev->dev_ops->dev_start && > > + rawdev->dev_ops->dev_start(rawdev)) > > + goto free_dev; > > + if (pr_enable) { > > + strncpy(afu_pr_conf.bs_path, path, strlen(path)); > > strncpy is dangerous here, please use strlcpy or snprintf. > (And your use of strncpy is dangerous, you are limitting the write to the > length of the source, not to the size of the destination.) Fixed in PATCH v5. > > + if (rawdev->dev_ops->firmware_load && > > + rawdev->dev_ops->firmware_load(rawdev, > > + &afu_pr_conf)){ > > + printf("firmware load error %d\n", ret); > > + goto free_dev; > > + } > > + } > > + > > + return afu_dev; > > + > > +free_dev: > > + free(afu_dev); > > +end: > > + if (kvlist) > > + rte_kvargs_free(kvlist); > > + if (path) > > + free(path); > > + > > + return NULL; > > +} > > + > > +/* > > + * Scan the content of the FPGA bus, and the devices in the devices > > + * list > > + */ > > +static int > > +rte_ifpga_scan(void) > > +{ > > + struct rte_ifpga_device *ifpga_dev; > > + struct rte_devargs *devargs; > > + struct rte_kvargs *kvlist = NULL; > > + struct rte_pci_addr pci_addr; > > + struct rte_rawdev *rawdev = NULL; > > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > > + struct rte_afu_device *afu_dev = NULL; > > + > > + /* for FPGA devices we scan the devargs_list populated via cmdline > */ > > + TAILQ_FOREACH(devargs, &devargs_list, next) { > > + if (devargs->bus != &rte_ifpga_bus.bus) > > + continue; > > + > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > + if (!kvlist) { > > + IFPGA_BUS_ERR("error when parsing param"); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, > > + &ifpga_get_bdf_arg, &pci_addr) < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_BDF); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PATH); > > + goto end; > > + } > > + > > + memset(name, 0, sizeof(name)); > > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, > "IFPGA:%x:%x:%x", > > + pci_addr.bus, pci_addr.devid, pci_addr.function); > > + > > + rawdev = rte_rawdev_pmd_get_named_dev(name); > > + if (!rawdev) > > + goto end; > > + > > + if (ifpga_find_ifpga_dev(&pci_addr)) > > + goto end; > > + > > + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); > > + if (!ifpga_dev) > > + goto end; > > + > > + ifpga_dev->pci_addr.domain = pci_addr.domain; > > + ifpga_dev->pci_addr.bus = pci_addr.bus; > > + ifpga_dev->pci_addr.devid = pci_addr.devid; > > + ifpga_dev->pci_addr.function = pci_addr.function; > > Again, PCI copy would be nice instead of doing it by hand. > > > + ifpga_dev->rdev = rawdev; > > + TAILQ_INIT(&ifpga_dev->afu_list); > > + > > + TAILQ_INSERT_TAIL(&rte_ifpga_bus.ifpga_list, ifpga_dev, > next); > > + afu_dev = rte_ifpga_scan_one(devargs, ifpga_dev); > > + if (afu_dev != NULL) > > + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, > next); > > + } > > + > > +end: > > + if (kvlist) > > + rte_kvargs_free(kvlist); > > + > > + return 0; > > +} > > + > > +static int > > +ifpga_probe_one_driver(struct rte_afu_driver *drv, > > + struct rte_afu_device *afu_dev) > > +{ > > + int ret; > > + > > + if ((drv->id.pci_addr.bus == afu_dev->id.pci_addr.bus) && > > + (drv->id.pci_addr.devid == afu_dev->id.pci_addr.devid) && > > + (drv->id.pci_addr.function == afu_dev->id.pci_addr.function) > && > > There is the rte_pci_addr_cmp function that should be used here instead. > Additionally, you haven't responded to my comment about ignoring the > Domain part of the address. Why? Is there a reason for this? Is the domain > irrelevant? If so, it should be documented. If not, please use the relevant > function instead. To be honest, FPGA BUS only need IFPGA_Rawdev name not pci_addr, so I have removed all pci_addr and pci common function in PATCH v5. > > + (drv->id.uuid_low == afu_dev->id.uuid_low) && > > + (drv->id.uuid_high == afu_dev->id.uuid_high) && > > + (drv->id.port == afu_dev->id.port)) { > > + > > + afu_dev->driver = drv; > > + > > + /* call the driver probe() function */ > > + ret = drv->probe(afu_dev); > > + if (ret) > > + afu_dev->driver = NULL; > > + return ret; > > + } > > + > > + /* return positive value if driver doesn't support this device */ > > + return 1; > > +} > > + > > +static int > > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) { > > + const char *name; > > + struct rte_afu_driver *drv = NULL; > > + int rc; > > + > > + if (afu_dev == NULL) > > + return -1; > > + > > + /* Check if a driver is already loaded */ > > + if (afu_dev->driver != NULL) > > + return 0; > > + > > + name = rte_ifpga_device_name(afu_dev); > > + IFPGA_BUS_DEBUG("Search driver %s to probe device %s\n", name, > > + rte_ifpga_device_name(afu_dev)); > > + > > + TAILQ_FOREACH(drv, &rte_ifpga_bus.driver_list, next) { > > + rc = ifpga_probe_one_driver(drv, afu_dev); > > + if (rc < 0) > > + /* negative value is an error */ > > + return -1; > > + if (rc > 0) > > + /* positive value means driver doesn't support it */ > > + continue; > > + return 0; > > + } > > + return 1; > > +} > > + > > +/* > > + * Scan the content of the PCI bus, and call the probe() function for > > One should read IFPGA bus here I guess. I have fixed it in PATCH v5. > > + * all registered drivers that have a matching entry in its id_table > > + * for discovered devices. > > + */ > > +static int > > +rte_ifpga_probe(void) > > +{ > > + struct rte_ifpga_device *ifpga_dev; > > + struct rte_afu_device *afu_dev = NULL; > > + int ret = 0; > > + > > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > + > > + if (afu_dev->device.driver) > > + continue; > > + > > + ret = ifpga_probe_all_drivers(afu_dev); > > + if (ret < 0) > > + IFPGA_BUS_ERR("failed to initialize %s > device\n", > > + rte_ifpga_device_name(afu_dev)); > > + } > > + } > > + > > + return 0; > > +} > > + > > +static int > > +rte_ifpga_plug(struct rte_device *dev) { > > + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); > > +} > > + > > +static int ifpga_remove_driver(struct rte_afu_device *afu_dev) { > > + const char *name; > > + const struct rte_afu_driver *driver; > > + > > + name = rte_ifpga_device_name(afu_dev); > > + if (!afu_dev->device.driver) { > > + IFPGA_BUS_DEBUG("no driver attach to device %s\n", > name); > > + return 1; > > + } > > + > > + driver = container_of(afu_dev->device.driver, > > + const struct rte_afu_driver, > > + driver); > > No RTE_DRV_TO_AFU_CONST? It would be easier to read. I have add RTE_DRV_TO_AFU_CONST macro in PATCH v5. > > + return driver->remove(afu_dev); > > +} > > + > > +static int > > +rte_ifpga_unplug(struct rte_device *dev) { > > + struct rte_ifpga_device *ifpga_dev = NULL; > > + struct rte_afu_device *afu_dev = NULL; > > + struct rte_devargs *devargs = NULL; > > + int ret; > > + > > + if (dev == NULL) > > + return -EINVAL; > > + > > + afu_dev = RTE_DEV_TO_AFU(dev); > > + if (!dev) > > + return -ENOENT; > > + > > + ifpga_dev = afu_dev->ifpga_dev; > > + devargs = dev->devargs; > > + > > + ret = ifpga_remove_driver(afu_dev); > > + if (ret) > > + return ret; > > + > > + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); > > + > > + TAILQ_REMOVE(&devargs_list, devargs, next); > > + > > + free(devargs->args); > > + free(devargs); > > + free(afu_dev); > > + return 0; > > + > > +} > > + > > +static struct rte_device * > > +rte_ifpga_find_device(const struct rte_device *start, > > + rte_dev_cmp_t cmp, const void *data) { > > + struct rte_ifpga_device *ifpga_dev; > > + struct rte_afu_device *afu_dev; > > + > > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > + if (start && &afu_dev->device == start) { > > + start = NULL; > > + continue; > > + } > > + if (cmp(&afu_dev->device, data) == 0) > > + return &afu_dev->device; > > + } > > + } > > + return NULL; > > +} > > +static int > > +rte_ifpga_parse(const char *name, void *addr) { > > + struct rte_afu_driver **out = addr; > > + struct rte_afu_driver *driver = NULL; > > + > > + TAILQ_FOREACH(driver, &rte_ifpga_bus.driver_list, next) { > > + if (strncmp(driver->driver.name, name, > > + strlen(driver->driver.name)) == 0) > > + break; > > + if (driver->driver.alias && > > + strncmp(driver->driver.alias, name, > > + strlen(driver->driver.alias)) == 0) > > + break; > > + } > > + if (driver != NULL && > > + addr != NULL) > > + *out = driver; > > + return driver == NULL; > > +} > > + > > +struct rte_ifpga_bus rte_ifpga_bus = { > > + .bus = { > > + .scan = rte_ifpga_scan, > > + .probe = rte_ifpga_probe, > > + .find_device = rte_ifpga_find_device, > > Wrong indentation (2 tabs instead of one). Yes, I have fixed it in PATCH v5. > > + .plug = rte_ifpga_plug, > > + .unplug = rte_ifpga_unplug, > > + .parse = rte_ifpga_parse, > > + }, > > + .ifpga_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.ifpga_list), > > + .driver_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.driver_list), > > Why are those lists part of the bus definition? Can you do the same as the > vdev bus and have them statically declared in your source file only? > > Is there a reason you want them part of the bus, do you need to access it > somewhere? I have fixed it and do the same as the vdev bus in PATCH v5. > > +}; > > + > > +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus.bus); > > + > > +RTE_INIT(ifpga_init_log) > > +{ > > + ifpga_bus_logtype = rte_log_register("bus.ifpga"); > > + if (ifpga_bus_logtype >= 0) > > + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); } > > + > > diff --git a/drivers/bus/ifpga/ifpga_common.c > > b/drivers/bus/ifpga/ifpga_common.c > > new file mode 100644 > > index 0000000..03a8d48 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_common.c > > @@ -0,0 +1,141 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2017 Intel Corporation */ > > + > > +#include <string.h> > > +#include <inttypes.h> > > +#include <stdint.h> > > +#include <stdlib.h> > > +#include <stdio.h> > > +#include <sys/queue.h> > > +#include <sys/mman.h> > > +#include <sys/types.h> > > +#include <unistd.h> > > +#include <fcntl.h> > > + > > +#include <rte_errno.h> > > +#include <rte_bus.h> > > +#include <rte_per_lcore.h> > > +#include <rte_memory.h> > > +#include <rte_memzone.h> > > +#include <rte_eal.h> > > +#include <rte_common.h> > > + > > +#include <rte_devargs.h> > > +#include <rte_pci.h> > > +#include <rte_bus_pci.h> > > +#include <rte_kvargs.h> > > +#include <rte_alarm.h> > > + > > +#include "rte_bus_ifpga.h" > > +#include "ifpga_logs.h" > > +#include "ifpga_common.h" > > + > > +int ifpga_get_string_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) { > > + if (!value || !extra_args) > > + return -EINVAL; > > + > > + *(char **)extra_args = strdup(value); > > + > > + if (!*(char **)extra_args) > > + return -ENOMEM; > > + > > + return 0; > > +} > > +int ifpga_get_integer32_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) { > > + if (!value || !extra_args) > > + return -EINVAL; > > + > > + *(int *)extra_args = strtoull(value, NULL, 0); > > + > > + return 0; > > +} > > +int ifpga_get_integer64_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) { > > + if (!value || !extra_args) > > + return -EINVAL; > > + > > + *(uint64_t *)extra_args = strtoull(value, NULL, 0); > > + > > + return 0; > > +} > > +int ifpga_get_unsigned_long(const char *str, int base) { > > + unsigned long num; > > + char *end = NULL; > > + > > + errno = 0; > > + > > + num = strtoul(str, &end, base); > > + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) > > + return -1; > > + > > + return num; > > + > > +} > > Missing newline here. Fixe in PATCH v5. > > +int ifpga_get_bdf_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) { #define MAX_PATH_LEN 1024 > > + struct rte_pci_addr *addr; > > + int num[4]; > > + char str[MAX_PATH_LEN]; > > + int i, j; > > + > > + if (!value || !extra_args) > > + return -EINVAL; > > + > > + addr = (struct rte_pci_addr *)extra_args; > > + strcpy(str, value); > > + memset(num, 0, 4 * sizeof(num[0])); > > + i = strlen(str) - 1; > > + j = 3; > > + while (i > 0 && j >= 0) { > > + while ((str[i - 1] != ':' && str[i - 1] != '.') && i > 0) > > + i--; > > + num[j--] = ifpga_get_unsigned_long(&str[i], 16); > > + i--; > > + if (i >= 0) > > + str[i] = '\0'; > > + } > > + addr->domain = num[0]; > > + addr->bus = num[1]; > > + addr->devid = num[2]; > > + addr->function = num[3]; > > + printf("[%s]: bdf %04d:%02d:%02d.%02d\n", > > + __func__, > > + addr->domain, > > + addr->bus, > > + addr->devid, > > + addr->function); > > + > > + return 0; > > +} > > Use rte_pci_addr_parse instead of rewriting it please. To be honest, FPGA BUS only need IFPGA_Rawdev name not pci_addr, so I have remove All pci_addr and pci common function such as ifpga_get_bdf_arg in PATCH v5. > > + > > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > + const struct rte_afu_id *afu_id1) > > +{ > > + if ((afu_id0->pci_addr.bus == afu_id1->pci_addr.bus) && > > + (afu_id0->pci_addr.devid == afu_id1->pci_addr.devid) && > > + (afu_id0->pci_addr.function == afu_id1->pci_addr.function) > && > > + (afu_id0->uuid_low == afu_id1->uuid_low) && > > + (afu_id0->uuid_high == afu_id1->uuid_high) && > > + (afu_id0->port == afu_id1->port)) { > > + return 0; > > + } else > > + return 1; > > +} > > You used the exact same check in the ifpga_bus.c file, why not call this > function instead? To be honest, FPGA BUS only need IFPGA_Rawdev name not pci_addr, so I have remove All pci_addr and pci common function such ifpga_pci_addr_cmp in PATCH v5. > > +int ifpga_pci_addr_cmp(const struct rte_device *dev, > > + const void *_pci_addr) > > +{ > > + struct rte_pci_device *pdev; > > + const struct rte_pci_addr *paddr = _pci_addr; > > + > > + pdev = RTE_DEV_TO_PCI(*(struct rte_device **)(void *)&dev); > > + return rte_eal_compare_pci_addr(&pdev->addr, paddr); > > This function is deprecated (I should mark is as so to forbid its use). > Use rte_pci_addr_cmp() instead. To be honest, FPGA BUS only need IFPGA_Rawdev name not pci_addr, so I have remove All pci_addr and pci common function such ifpga_pci_addr_cmp in PATCH v5. > > +} > > diff --git a/drivers/bus/ifpga/ifpga_common.h > > b/drivers/bus/ifpga/ifpga_common.h > > new file mode 100644 > > index 0000000..48a5012 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_common.h > > @@ -0,0 +1,22 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2017 Intel Corporation */ > > + > > +#ifndef _IFPGA_COMMON_H_ > > +#define _IFPGA_COMMON_H_ > > + > > +int ifpga_get_string_arg(const char *key __rte_unused, > > + const char *value, void *extra_args); int > > +ifpga_get_integer32_arg(const char *key __rte_unused, > > + const char *value, void *extra_args); int > > +ifpga_get_integer64_arg(const char *key __rte_unused, > > + const char *value, void *extra_args); int > > +ifpga_get_unsigned_long(const char *str, int base); int > > +ifpga_get_bdf_arg(const char *key __rte_unused, > > + const char *value, void *extra_args); int ifpga_afu_id_cmp(const > > +struct rte_afu_id *afu_id0, > > + const struct rte_afu_id *afu_id1); > > +int ifpga_pci_addr_cmp(const struct rte_device *dev, > > + const void *_pci_addr); > > + > > +#endif /* _IFPGA_COMMON_H_ */ > > diff --git a/drivers/bus/ifpga/ifpga_logs.h > > b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index > > 0000000..e3f4849 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_logs.h > > @@ -0,0 +1,31 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2017 Intel Corporation */ > > + > > +#ifndef _IFPGA_LOGS_H_ > > +#define _IFPGA_LOGS_H_ > > + > > +#include <rte_log.h> > > + > > +extern int ifpga_bus_logtype; > > + > > +#define IFPGA_LOG(level, fmt, args...) \ > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > + __func__, ##args) > > + > > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > + __func__, ##args) > > + > > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > > + > > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) > > +#define IFPGA_BUS_INFO(fmt, args...) \ > > + IFPGA_BUS_LOG(INFO, fmt, ## args) > > +#define IFPGA_BUS_ERR(fmt, args...) \ > > + IFPGA_BUS_LOG(ERR, fmt, ## args) > > +#define IFPGA_BUS_WARN(fmt, args...) \ > > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > > + > > +#endif /* _IFPGA_BUS_LOGS_H_ */ > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h > > b/drivers/bus/ifpga/rte_bus_ifpga.h > > new file mode 100644 > > index 0000000..7290149 > > --- /dev/null > > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > > @@ -0,0 +1,140 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2017 Intel Corporation */ > > + > > +#ifndef _RTE_BUS_IFPGA_H_ > > +#define _RTE_BUS_IFPGA_H_ > > + > > +/** > > + * @file > > + * > > + * RTE PCI Bus Interface > > + */ > > + > > +#ifdef __cplusplus > > +extern "C" { > > +#endif > > + > > +#include <rte_bus.h> > > +#include <rte_pci.h> > > + > > +/** Name of Intel FPGA Bus */ > > +#define IFPGA_BUS_NAME ifpga > > + > > +/* Forward declarations */ > > +struct rte_ifpga_device; > > +struct rte_afu_device; > > +struct rte_afu_driver; > > + > > +/** List of Intel FPGA devices */ > > +TAILQ_HEAD(rte_ifpga_device_list, rte_ifpga_device); > > +/** List of Intel AFU devices */ > > +TAILQ_HEAD(rte_afu_device_list, rte_afu_device); > > +/** List of AFU drivers */ > > +TAILQ_HEAD(rte_afu_driver_list, rte_afu_driver); > > Is there a reason for you to expose your lists publicly? > These symbols should be made private to your bus unless necessary. Yes, it should be private, and I have fix3e it in PATCH v5. > > + > > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > > + > > +/** > > + * A structure describing an ID for a AFU driver. Each driver > > +provides a > > + * table of these IDs for each device that it supports. > > + */ > > +struct rte_afu_id { > > + struct rte_pci_addr pci_addr; > > You use a symbol from librte_pci, without linking it. To be honest, FPGA BUS only need IFPGA_Rawdev name not pci_addr, so I have remove All pci_addr and pci common function in PATCH v5. > > + uint64_t uuid_low; > > + uint64_t uuid_high; > > + int port; > > +} __attribute__ ((packed)); > > + > > +/** > > + * A structure pr configuration AFU driver. > > + */ > > + > > +struct rte_afu_pr_conf { > > + struct rte_afu_id afu_id; > > + int pr_enable; > > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > +}; > > + > > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > > + > > +/** > > + * A structure describing a fpga device. > > + */ > > +struct rte_ifpga_device { > > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ > > + struct rte_pci_addr pci_addr; > > + struct rte_rawdev *rdev; > > + struct rte_afu_device_list afu_list; /**< List of AFU devices */ }; > > + > > +/** > > + * A structure describing a AFU device. > > + */ > > +struct rte_afu_device { > > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ > > + struct rte_device device; /**< Inherit core device */ > > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > > + struct rte_afu_id id; /**< AFU id within FPGA. */ > > + uint32_t num_region; /**< number of regions found */ > > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > > + /**< PCI Memory Resource > */ > > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > > + struct rte_afu_driver *driver; /**< Associated driver */ > > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > +} __attribute__ ((packed)); > > + > > +/** > > + * @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) > > + > > +/** > > + * Initialisation function for the driver called during PCI probing. > > + */ > > +typedef int (afu_probe_t)(struct rte_afu_device *); > > + > > +/** > > + * Uninitialisation function for the driver called during hotplugging. > > + */ > > +typedef int (afu_remove_t)(struct rte_afu_device *); > > + > > +/** > > + * A structure describing a PCI device. > > + */ > > +struct rte_afu_driver { > > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > > + struct rte_driver driver; /**< Inherit core driver. */ > > + afu_probe_t *probe; /**< Device Probe function. */ > > + afu_remove_t *remove; /**< Device Remove function. */ > > + struct rte_afu_id id; /**< AFU id within FPGA. */ > > + uint32_t drv_flags; /**< Flags contolling handling of device. */ > > +}; > > + > > +/** > > + * Structure describing the Intel FPGA bus */ struct rte_ifpga_bus { > > + struct rte_bus bus; /**< Inherit the generic class */ > > + struct rte_ifpga_device_list ifpga_list; /**< List of FPGA devices */ > > + struct rte_afu_driver_list driver_list; /**< List of FPGA drivers > > +*/ }; > > + > > +static inline const char * > > +rte_ifpga_device_name(const struct rte_afu_device *afu) { > > + if (afu && afu->device.name) > > + return afu->device.name; > > + return NULL; > > +} > > + > > +extern struct rte_ifpga_bus rte_ifpga_bus; > > + > > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); void > > +rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > > + > > + > > +#endif /* _RTE_BUS_IFPGA_H_ */ > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map > > b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > new file mode 100644 > > index 0000000..4edc9c0 > > --- /dev/null > > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > @@ -0,0 +1,8 @@ > > +DPDK_18.05 { > > + global: > > + > > + rte_ifpga_driver_register; > > + rte_ifpga_driver_unregister; > > Wrong indentation. > It should be one tabulation, not 4 spaces. Fixed in PATCH v5. > > + > > + local: *; > > +}; > > -- > > 1.8.3.1 > > > > -- > Gaëtan Rivet > 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v3 5/6] drivers/raw/ifpga_rawdev: Add Intel FPGA Rawdev Driver Code 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 0/6] " Rosen Xu ` (3 preceding siblings ...) 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code Rosen Xu @ 2018-03-28 9:29 ` Rosen Xu 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 6/6] drivers/raw/ifpga_rawdev: Add Intel FPGA OPAE Share Code Rosen Xu ` (2 subsequent siblings) 7 siblings, 0 replies; 149+ messages in thread From: Rosen Xu @ 2018-03-28 9:29 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu, gaetan.rivet, Yanglong Wu Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> --- drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 35 ++ drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 492 +++++++++++++++++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c | 98 ++++ .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + 6 files changed, 667 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c create mode 100644 drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index da7c8b4..6fc8f2f 100644 --- a/drivers/raw/Makefile +++ b/drivers/raw/Makefile @@ -5,5 +5,6 @@ include $(RTE_SDK)/mk/rte.vars.mk # DIRS-$(<configuration>) += <directory> DIRS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += skeleton_rawdev +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/raw/ifpga_rawdev/Makefile b/drivers/raw/ifpga_rawdev/Makefile new file mode 100644 index 0000000..b3d1bdb --- /dev/null +++ b/drivers/raw/ifpga_rawdev/Makefile @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2017 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_ifpga_rawdev.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_bus_vdev +LDLIBS += -lrte_kvargs + +EXPORT_MAP := rte_ifpga_rawdev_version.map + +LIBABIVER := 1 + +VPATH += $(SRCDIR)/base + +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev.c +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev_example.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c new file mode 100644 index 0000000..1ce959a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c @@ -0,0 +1,492 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2017 Intel Corporation + */ + +#include <string.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <rte_log.h> +#include <rte_bus.h> +#include <rte_eal_memconfig.h> +#include <rte_malloc.h> +#include <rte_devargs.h> +#include <rte_memcpy.h> +#include <rte_ethdev.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include <rte_errno.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include "base/opae_hw_api.h" +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_common.h" +#include "ifpga_logs.h" +#include "ifpga_rawdev.h" + +int ifpga_rawdev_logtype; + +#define PCI_VENDOR_ID_INTEL 0x8086 +/* PCI Device ID */ +#define PCIe_DEVICE_ID_RCiEP0_MCP 0xBCBD +#define PCIe_DEVICE_ID_RCiEP0_SKX_P 0xBCC0 +#define PCIe_DEVICE_ID_RCiEP0_DCP 0x09C4 +/* VF Device */ +#define PCIe_DEVICE_ID_VF_MCP 0xBCBF +#define PCIe_DEVICE_ID_VF_SKX_P 0xBCC1 +#define PCIe_DEVICE_ID_VF_DCP 0x09C5 +#define RTE_MAX_RAW_DEVICE 10 + +static const struct rte_pci_id pci_ifpga_map[] = { + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIe_DEVICE_ID_RCiEP0_MCP) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIe_DEVICE_ID_VF_MCP) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIe_DEVICE_ID_RCiEP0_SKX_P) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIe_DEVICE_ID_VF_SKX_P) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIe_DEVICE_ID_RCiEP0_DCP) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIe_DEVICE_ID_VF_DCP) }, + { .vendor_id = 0, /* sentinel */ }, +}; + +static int ifpga_fill_afu_dev(struct opae_accelerator *acc, + struct rte_afu_device *afu_dev) +{ + struct rte_mem_resource *res = afu_dev->mem_resource; + struct opae_acc_region_info region_info; + struct opae_acc_info info; + unsigned long i; + int ret; + + ret = opae_acc_get_info(acc, &info); + if (ret) + return ret; + + if (info.num_regions > PCI_MAX_RESOURCE) + return -EFAULT; + + afu_dev->num_region = info.num_regions; + + for (i = 0; i < info.num_regions; i++) { + region_info.index = i; + ret = opae_acc_get_region_info(acc, ®ion_info); + if (ret) + return ret; + + if ((region_info.flags & ACC_REGION_MMIO) && + (region_info.flags & ACC_REGION_READ) && + (region_info.flags & ACC_REGION_WRITE)) { + res[i].phys_addr = region_info.phys_addr; + res[i].len = region_info.len; + res[i].addr = region_info.addr; + } else + return -EFAULT; + } + + return 0; +} + +static void ifpga_rawdev_info_get(struct rte_rawdev *dev, + rte_rawdev_obj_t dev_info) +{ + struct opae_adapter *adapter; + struct opae_accelerator *acc; + struct rte_afu_device *afu_dev; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + if (!dev_info) { + IFPGA_RAWDEV_PMD_ERR("Invalid request"); + return; + } + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return; + + afu_dev = dev_info; + afu_dev->rawdev = dev; + + /* find opae_accelerator and fill info into afu_device */ + opae_adapter_for_each_acc(adapter, acc) { + if (acc->index != afu_dev->id.port) + continue; + + if (ifpga_fill_afu_dev(acc, afu_dev)) { + IFPGA_RAWDEV_PMD_ERR("cannot get info\n"); + return; + } + } +} + +static int ifpga_rawdev_start(struct rte_rawdev *dev) +{ + int ret = 0; + struct opae_adapter *adapter; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + return ret; +} + +static void ifpga_rawdev_stop(struct rte_rawdev *dev) +{ + dev->started = 0; +} + +static int ifpga_rawdev_close(struct rte_rawdev *dev) +{ + if (!dev) + return 1; + else + return 0; +} + +static int ifpga_rawdev_reset(struct rte_rawdev *dev) +{ + if (!dev) + return 1; + else + return 0; +} + +static int +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, + u64 *status){ + + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_accelerator *acc; + struct opae_bridge *br; + int ret; + + adapter = ifpga_rawdev_get_priv(raw_dev); + if (!adapter) + return -ENODEV; + + mgr = opae_adapter_get_mgr(adapter); + if (!mgr) + return -ENODEV; + + acc = opae_adapter_get_acc(adapter, port_id); + if (!acc) + return -ENODEV; + + br = opae_acc_get_br(acc); + if (!br) + return -ENODEV; + + ret = opae_manager_flash(mgr, port_id, buffer, size, status); + if (ret) { + printf("%s pr error %d\n", __func__, ret); + return ret; + } + + usleep(100); + ret = opae_bridge_reset(br); + if (ret) { + printf("%s reset port:%d error %d\n", __func__, port_id, ret); + return ret; + } + + return ret; +} + +static int rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, + const char *file_name) +{ + struct stat file_stat; + int file_fd; + int ret = 0; + u32 buffer_size; + void *buffer; + u64 pr_error; + + if (!file_name) + return -EINVAL; + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + printf("%s: open file error: %s\n", __func__, file_name); + printf("Message : %s\n", strerror(errno)); + return -EINVAL; + } + ret = stat(file_name, &file_stat); + if (ret) { + printf("stat on bitstream file failed: %s\n", file_name); + return -EINVAL; + } + buffer_size = file_stat.st_size; + printf("bitstream file size: %u\n", buffer_size); + buffer = rte_malloc(NULL, buffer_size, 0); + if (!buffer) { + ret = -ENOMEM; + goto close_fd; + } + + /*read the raw data*/ + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { + ret = -EINVAL; + goto free_buffer; + } + + /*do PR now*/ + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); + printf("downloading to device port %d....%s.\n", port_id, + ret ? "failed" : "success"); + if (ret) { + ret = -EINVAL; + //raw_dev->ops->show_pr_error(pr_error); + goto free_buffer; + } + +free_buffer: + if (buffer) + rte_free(buffer); +close_fd: + close(file_fd); + file_fd = 0; + return ret; +} + +static int ifpga_rawdev_pr(struct rte_rawdev *dev, + rte_rawdev_obj_t pr_conf) +{ + struct opae_adapter *adapter; + struct rte_afu_pr_conf *afu_pr_conf; + int ret; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + if (!pr_conf) + return -EINVAL; + + afu_pr_conf = pr_conf; + + ret = rte_fpga_do_pr(dev, afu_pr_conf->afu_id.port, + afu_pr_conf->bs_path); + if (ret) { + printf("===do pr error %d\n", ret); + return ret; + } + + return 0; +} + +static const struct rte_rawdev_ops ifpga_rawdev_ops = { + .dev_info_get = ifpga_rawdev_info_get, + .dev_configure = NULL, + .dev_start = ifpga_rawdev_start, + .dev_stop = ifpga_rawdev_stop, + .dev_close = ifpga_rawdev_close, + .dev_reset = ifpga_rawdev_reset, + + .queue_def_conf = NULL, + .queue_setup = NULL, + .queue_release = NULL, + + .attr_get = NULL, + .attr_set = NULL, + + .enqueue_bufs = NULL, + .dequeue_bufs = NULL, + + .dump = NULL, + + .xstats_get = NULL, + .xstats_get_names = NULL, + .xstats_get_by_name = NULL, + .xstats_reset = NULL, + + .firmware_status_get = NULL, + .firmware_version_get = NULL, + .firmware_load = ifpga_rawdev_pr, + .firmware_unload = NULL, + + .dev_selftest = NULL, +}; + +static int +ifpga_rawdev_create(struct rte_pci_device *pci_dev, + int socket_id) +{ + int ret = 0; + struct rte_devargs *devargs; + struct rte_rawdev *rawdev = NULL; + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_adapter_data_pci *data; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + int i; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + goto cleanup; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%x:%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id()); + + /* Allocate device structure */ + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct opae_adapter), + socket_id); + if (rawdev == NULL) { + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); + ret = -EINVAL; + goto cleanup; + } + + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API */ + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); + if (!data) + return -ENOMEM; + + /* init opae_adapter_data_pci for device specific information */ + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + data->region[i].phys_addr = pci_dev->mem_resource[i].phys_addr; + data->region[i].len = pci_dev->mem_resource[i].len; + data->region[i].addr = pci_dev->mem_resource[i].addr; + } + data->device_id = pci_dev->id.device_id; + data->vendor_id = pci_dev->id.vendor_id; + + /* create a opae_adapter based on above device data */ + adapter = opae_adapter_alloc(pci_dev->device.name, data); + if (!adapter) { + opae_adapter_data_free(data); + return -ENOMEM; + } + + rawdev->dev_ops = &ifpga_rawdev_ops; + rawdev->device = &pci_dev->device; + rawdev->driver_name = pci_dev->device.driver->name; + + rawdev->dev_private = adapter; + + /* must enumerate the adapter before use it */ + ret = opae_adapter_enumerate(adapter); + if (ret) + return ret; + + /* set opae_manager to rawdev */ + mgr = opae_adapter_get_mgr(adapter); + if (mgr) { + /*PF function*/ + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); + } + + TAILQ_FOREACH(devargs, &devargs_list, next) { + if (strcmp(devargs->bus->name, RTE_STR(IFPGA_BUS_NAME))) + continue; + ret = rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), + devargs->name, + devargs->args); + } + + return ret; + +cleanup: + if (rawdev) + rte_rawdev_pmd_release(rawdev); + + return ret; +} + +static int +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) +{ + int ret; + struct rte_rawdev *rawdev; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + struct opae_adapter *adapter; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + return ret; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%x:%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", + name, rte_socket_id()); + + rawdev = rte_rawdev_pmd_get_named_dev(name); + if (!rawdev) { + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name); + return -EINVAL; + } + + adapter = ifpga_rawdev_get_priv(rawdev); + if (!adapter) + return -ENODEV; + + opae_adapter_data_free(adapter->data); + opae_adapter_free(adapter); + + /* rte_rawdev_close is called by pmd_release */ + ret = rte_rawdev_pmd_release(rawdev); + if (ret) + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); + + return 0; +} + +static int +ifpga_rawdev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, + struct rte_pci_device *pci_dev) +{ + + printf("## %s\n", __func__); + return ifpga_rawdev_create(pci_dev, rte_socket_id()); +} + +static int ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) +{ + return ifpga_rawdev_destroy(pci_dev); +} + +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { + .id_table = pci_ifpga_map, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, + .probe = ifpga_rawdev_pci_probe, + .remove = ifpga_rawdev_pci_remove, +}; + +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | uio_pci_generic | vfio-pci"); + +RTE_INIT(ifpga_rawdev_init_log); +static void +ifpga_rawdev_init_log(void) +{ + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); + if (ifpga_rawdev_logtype >= 0) + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); +} diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h new file mode 100644 index 0000000..f262180 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2017 Intel Corporation + */ + +#ifndef _IFPGA_RAWDEV_H_ +#define _IFPGA_RAWDEV_H_ + +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) + +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") + +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) +#define IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) +#define IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) +#define IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) + +enum ifpga_rawdev_device_state { + IFPGA_IDLE, + IFPGA_READY, + IFPGA_ERROR +}; + +static inline struct opae_adapter * +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) +{ + return rawdev->dev_private; +} + +#endif /* _IFPGA_RAWDEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c b/drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c new file mode 100644 index 0000000..5f8d78f --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev_example.c @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2017 Intel Corporation + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <inttypes.h> +#include <sys/types.h> +#include <sys/queue.h> +#include <netinet/in.h> +#include <setjmp.h> +#include <stdarg.h> +#include <ctype.h> +#include <errno.h> +#include <getopt.h> +#include <signal.h> +#include <stdbool.h> + +#include <rte_common.h> +#include <rte_log.h> +#include <rte_malloc.h> +#include <rte_memory.h> +#include <rte_memcpy.h> +#include <rte_eal.h> +#include <rte_launch.h> +#include <rte_atomic.h> +#include <rte_cycles.h> +#include <rte_prefetch.h> +#include <rte_lcore.h> +#include <rte_per_lcore.h> +#include <rte_branch_prediction.h> +#include <rte_interrupts.h> +#include <rte_random.h> +#include <rte_debug.h> +#include <rte_ether.h> +#include <rte_ethdev.h> +#include <rte_mempool.h> +#include <rte_mbuf.h> +#include <rte_io.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_memzone.h> + +#include <rte_devargs.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_alarm.h> + +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" + +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ +RTE_INIT(afudrvinitfn_ ##afudrv);\ +static const char *afudrvinit_ ## nm ## _alias;\ +static void afudrvinitfn_ ##afudrv(void)\ +{\ + (afudrv).driver.name = RTE_STR(nm);\ + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ + rte_ifpga_driver_register(&afudrv);\ +} \ +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) + +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ +static const char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) + +static int afu_dev_probe(struct rte_afu_device *afu_dev) +{ + if (!afu_dev) + return 1; + else + return 0; +} +static int afu_dev_remove(struct rte_afu_device *afu_dev) +{ + if (!afu_dev) + return 1; + else + return 0; +} + +static struct rte_afu_driver afu_dev_driver = { + .probe = afu_dev_probe, + .remove = afu_dev_remove, +}; + +RTE_PMD_REGISTER_AFU(net_afu_drv_example, afu_dev_driver); +RTE_PMD_REGISTER_AFU_ALIAS(net_afu_drv_example, afu_dev); +RTE_PMD_REGISTER_PARAM_STRING(net_afu_drv_example, + "bdf=<string> " + "port=<int> " + "uudi_high=<int64> " + "uuid_low=<int64> " + "path=<string> " + "pr_enable=<int>" + "debug=<int>"); diff --git a/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map new file mode 100644 index 0000000..9b9ab1a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map @@ -0,0 +1,4 @@ +DPDK_18.05 { + + local: *; +}; -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v3 6/6] drivers/raw/ifpga_rawdev: Add Intel FPGA OPAE Share Code 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 0/6] " Rosen Xu ` (4 preceding siblings ...) 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 5/6] drivers/raw/ifpga_rawdev: Add Intel FPGA Rawdev Driver Code Rosen Xu @ 2018-03-28 9:29 ` Rosen Xu 2018-03-28 9:37 ` [dpdk-dev] [PATCH v3 0/6] Introduce Intel FPGA BUS Bruce Richardson 2018-03-28 13:17 ` Gaëtan Rivet 7 siblings, 0 replies; 149+ messages in thread From: Rosen Xu @ 2018-03-28 9:29 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu, gaetan.rivet Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> Signed-off-by: Wu, Hao <hao.wu@intel.com> --- drivers/raw/ifpga_rawdev/base/Makefile | 54 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 543 +++++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 77 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 84 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1696 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 861 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 38 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 340 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 197 +++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 763 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 328 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 430 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 742 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 395 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 154 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 735 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 236 +++ drivers/raw/ifpga_rawdev/base/opae_debug.c | 126 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 46 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 389 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 276 ++++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 173 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 306 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 111 ++ .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 104 ++ .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 72 + 26 files changed, 9276 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile new file mode 100644 index 0000000..9c0d64b --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -0,0 +1,54 @@ +# BSD LICENSE +# +# Copyright(c) 2017-2018 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +ifneq ($(CONFIG_RTE_LIBRTE_EAL),) +OSDEP := osdep_rte +else +OSDEP := osdep_raw +endif + +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev/base/$(OSDEP) + +SRCS-y += ifpga_api.c +SRCS-y += ifpga_enumerate.c +SRCS-y += ifpga_feature_dev.c +SRCS-y += ifpga_fme.c +SRCS-y += ifpga_fme_iperf.c +SRCS-y += ifpga_fme_dperf.c +SRCS-y += ifpga_fme_error.c +SRCS-y += ifpga_port.c +SRCS-y += ifpga_port_error.c +SRCS-y += ifpga_fme_pr.c +SRCS-y += opae_hw_api.c +SRCS-y += opae_ifpga_hw_api.c +SRCS-y += opae_debug.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 new file mode 100644 index 0000000..ffed9d3 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -0,0 +1,543 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_api.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +#include "opae_hw_api.h" + +/* Accelerator APIs */ +static int ifpga_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + struct fpga_uafu_irq_set irq_set; + + if (!br || !br->data) + return -EINVAL; + + if (start >= afu_info->num_irqs || start + count > afu_info->num_irqs) + return -EINVAL; + + port = br->data; + + irq_set.start = start; + irq_set.count = count; + irq_set.evtfds = evtfds; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_UINT, &irq_set); +} + +static int ifpga_acc_get_info(struct opae_accelerator *acc, + struct opae_acc_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -ENODEV; + + info->num_regions = afu_info->num_regions; + info->num_irqs = afu_info->num_irqs; + + return 0; +} + +static int ifpga_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -EINVAL; + + if (afu_info->num_regions >= info->index) + return -EINVAL; + + /* always one RW region only for AFU now */ + info->flags = ACC_REGION_READ | ACC_REGION_WRITE | ACC_REGION_MMIO; + info->len = afu_info->region[info->index].len; + + return 0; +} + +static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + switch (byte) { + case 8: + *(u64 *)data = opae_readq(region->addr + offset); + break; + case 4: + *(u32 *)data = opae_readl(region->addr + offset); + break; + case 2: + *(u16 *)data = opae_readw(region->addr + offset); + break; + case 1: + *(u8 *)data = opae_readb(region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ifpga_acc_write(struct opae_accelerator *acc, + unsigned int region_idx, u64 offset, + unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + /* normal mmio case */ + switch (byte) { + case 8: + opae_writeq(*(u64 *)data, region->addr + offset); + break; + case 4: + opae_writel(*(u32 *)data, region->addr + offset); + break; + case 2: + opae_writew(*(u16 *)data, region->addr + offset); + break; + case 1: + opae_writeb(*(u8 *)data, region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +struct opae_accelerator_ops ifpga_acc_ops = { + .read = ifpga_acc_read, + .write = ifpga_acc_write, + .set_irq = ifpga_acc_set_irq, + .get_info = ifpga_acc_get_info, + .get_region_info = ifpga_acc_get_region_info, +}; + +/* Bridge APIs */ + +static int ifpga_br_reset(struct opae_bridge *br) +{ + struct ifpga_port_hw *port = br->data; + + return fpga_port_reset(port); +} + +struct opae_bridge_ops ifpga_br_ops = { + .reset = ifpga_br_reset, +}; + +/* Manager APIs */ +static int ifpga_mgr_flash(struct opae_manager *mgr, int id, void *buf, + u32 size, u64 *status) +{ + struct ifpga_fme_hw *fme = mgr->data; + struct ifpga_hw *hw = fme->parent; + + return ifpga_pr(hw, id, buf, size, status); +} + +struct opae_manager_ops ifpga_mgr_ops = { + .flash = ifpga_mgr_flash, +}; + +/* Adapter APIs */ +static int ifpga_adapter_enumerate(struct opae_adapter *adapter) +{ + struct ifpga_hw *hw = malloc(sizeof(*hw)); + + if (hw) { + memset(hw, 0, sizeof(*hw)); + hw->pci_data = adapter->data; + hw->adapter = adapter; + if (ifpga_bus_enumerate(hw)) + goto error; + return ifpga_bus_init(hw); + } + +error: + return -ENOMEM; +} + +struct opae_adapter_ops ifpga_adapter_ops = { + .enumerate = ifpga_adapter_enumerate, +}; + +/** + * ifpga_enumerate - enumerate the Device Feature List + * @hw: pointer to the HW structure + * + * This function enumerate the Device Feature List to discover + * the FME and Port devices. The FME device and Port devices + * will fill into HW structure when enumerate done. + * + * @return + * - 0: Success, device enumated. + * - <0: Error code returned in enumeration. + **/ +int ifpga_enumerate(struct ifpga_hw *hw) +{ + return ifpga_bus_enumerate(hw); +} + +/** + * ifpga_reset_port - reset a port device + * @hw: pointer to the HW structure + * @port_id: port device id + * + * @return + * - 0: Success + * - <0: Failure to reset a port device. + **/ +int ifpga_reset_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return fpga_port_reset(&hw->port[port_id]); +} + +/** + * ifpga_get_afu_mmio_addr - get UAFU MMIO address + * @hw: pointer to the HW structure + * @port_id: port device id + * @mem_resource: afu mmio resource + * @num_resource: number of resource + * + * return 0 on success or error code + **/ +int ifpga_get_afu_mmio_info(struct ifpga_hw *hw, u32 port_id, + struct rte_mem_resource *mem_resource, + u32 *num_resource) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + mem_resource->addr = + hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + mem_resource->len = + hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + mem_resource->phys_addr = + hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].phys_addr; + + *num_resource = 1; + + return 0; +} + +/** + * ifpga_get_afu_uuid - get AFU uuid + * @hw: pointer to the HW structure + * @port_id: port device id + * @uuid: the AFU's uuid + * + * @return + * - 0: Success + * - <0: Failure to get uuid. + **/ +int ifpga_get_afu_uuid(struct ifpga_hw *hw, u32 port_id, struct uuid *uuid) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + if (!hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size) + return -ENODEV; + + return fpga_get_afu_uuid(&hw->port[port_id], uuid); +} + +/** + * ifpga_pr - do the partial reconfiguration for a given port device + * @hw: pointer to the HW structure + * @port_id: the port device id + * @buffer: the buffer of the bitstream + * @size: the size of the bitstream + * @status: hardware status including PR error code if return -EIO. + * + * @return + * - 0: Success, partial reconfiguration finished. + * - <0: Error code returned in partial reconfiguration. + **/ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return do_pr(hw, port_id, buffer, size, status); +} + +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_get_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_get_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set) +{ + if (!hw || !irq_set) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_irq(&hw->fme, feature_id, irq_set); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_irq(&hw->port[port_id], feature_id, irq_set); + } + + return -ENOENT; +} + +int ifpga_port_umsg_enable(struct ifpga_hw *hw, u32 port_id, bool enable) +{ + struct ifpga_port_hw *port = get_port(hw, port_id); + + if (!port) + return -ENODEV; + + spinlock_lock(&port->lock); + if (afu_port_umsg_enable(port, enable)) + return -ENODEV; + spinlock_unlock(&port->lock); + + return 0; +} + +int ifpga_port_umsg_set_mode(struct ifpga_hw *hw, u32 port_id, u32 mode) +{ + struct ifpga_port_hw *port = get_port(hw, port_id); + + if (!port) + return -ENODEV; + + spinlock_lock(&port->lock); + if (afu_port_umsg_set_mode(port, mode)) + return -ENODEV; + spinlock_unlock(&port->lock); + + return 0; +} + +void ifpga_show_pr_error(u64 pr_error) +{ +#if 0 + int i = 0; + + for_each_set_bit(i, &pr_error, PR_MAX_ERR_NUM) + printf("PR Error: %s\n", pr_err_msg[i]); +#endif + printf("PR Error: 0x%lx\n", pr_error); +} + +int ifpga_mmio64_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 *value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + *value = readq(addr + offset); + + return 0; +} + +int ifpga_mmio64_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + writeq(value, addr + offset); + + return 0; +} + +int ifpga_mmio32_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 *value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + *value = readl(addr + offset); + + return 0; +} + +int ifpga_mmio32_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + writel(value, addr + offset); + + return 0; +} + +int ifpga_fme_hw_init(struct ifpga_hw *hw) +{ + return fme_hw_init(&hw->fme); +} + +void ifpga_fme_hw_uinit(struct ifpga_hw *hw) +{ + fme_hw_uinit(&hw->fme); +} + +void ifpga_port_hw_uinit(struct ifpga_hw *hw, int port_id) +{ + struct ifpga_port_hw *port; + + if (!is_valid_port_id(hw, port_id)) + return; + + port = &hw->port[port_id]; + + if (port->state == IFPGA_PORT_ATTACHED) + port_hw_uinit(port); +} + +int ifpga_port_hw_init(struct ifpga_hw *hw, int port_id) +{ + struct ifpga_port_hw *port; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + port = &hw->port[port_id]; + + if (port->state != IFPGA_PORT_ATTACHED) + return -EINVAL; + + return port_hw_init(port); +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.h b/drivers/raw/ifpga_rawdev/base/ifpga_api.h new file mode 100644 index 0000000..f8bca80 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.h @@ -0,0 +1,77 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_API_H_ +#define _IFPGA_API_H_ + +#include "opae_hw_api.h" +#include "ifpga_hw.h" + +extern struct opae_adapter_ops ifpga_adapter_ops; +extern struct opae_manager_ops ifpga_mgr_ops; +extern struct opae_bridge_ops ifpga_br_ops; +extern struct opae_accelerator_ops ifpga_acc_ops; + +/* common APIs */ +int ifpga_enumerate(struct ifpga_hw *hw); +int ifpga_fme_hw_init(struct ifpga_hw *hw); +void ifpga_fme_hw_uinit(struct ifpga_hw *hw); +int ifpga_port_hw_init(struct ifpga_hw *hw, int port_id); +void ifpga_port_hw_uinit(struct ifpga_hw *hw, int port_id); +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set); + +/* Port/AFU APIs */ +int ifpga_reset_port(struct ifpga_hw *hw, u32 port_id); +int ifpga_get_afu_mmio_info(struct ifpga_hw *hw, u32 port_id, + struct rte_mem_resource *mem_resource, + u32 *num_resource); +int ifpga_get_afu_uuid(struct ifpga_hw *hw, u32 port_id, struct uuid *uuid); + +int ifpga_mmio64_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 *value); +int ifpga_mmio64_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 value); +int ifpga_mmio32_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 *value); +int ifpga_mmio32_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 value); + +/* FME APIs */ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); +void ifpga_show_pr_error(u64 pr_error); + +/* Port APIs */ +int ifpga_port_umsg_enable(struct ifpga_hw *hw, u32 port_id, bool enable); +int ifpga_port_umsg_set_mode(struct ifpga_hw *hw, u32 port_id, u32 mode); + +#endif /* _IFPGA_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_compat.h b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h new file mode 100644 index 0000000..6670630 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h @@ -0,0 +1,84 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_COMPAT_H_ +#define _IFPGA_COMPAT_H_ + +#include "opae_osdep.h" + +#undef container_of +#define container_of(ptr, type, member) ({ \ + typeof(((type *)0)->member)(*__mptr) = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) +#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE) + +#define readl(addr) opae_readl(addr) +#define readq(addr) opae_readq(addr) +#define writel(value, addr) opae_writel(value, addr) +#define writeq(value, addr) opae_writeq(value, addr) + +#define malloc(size) opae_malloc(size) +#define zmalloc(size) opae_zmalloc(size) +#define free(size) opae_free(size) + +/* + * Wait register's _field to be changed to the given value (_expect's _field) + * by polling with given interval and timeout. + */ +#define fpga_wait_register_field(_field, _expect, _reg_addr, _timeout, _invl)\ +({ \ + int wait = 0; \ + int ret = -ETIMEDOUT; \ + typeof(_expect) value; \ + for (; wait <= _timeout; wait += _invl) { \ + value.csr = readq(_reg_addr); \ + if (_expect._field == value._field) { \ + ret = 0; \ + break; \ + } \ + udelay(_invl); \ + } \ + ret; \ +}) + +#define __maybe_unused __attribute__((__unused__)) + +#define UNUSED(x) (void)(x) + +#endif /* _IFPGA_COMPAT_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h new file mode 100644 index 0000000..7fc99c2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -0,0 +1,1696 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_DEFINES_H_ +#define _IFPGA_DEFINES_H_ + +#include "ifpga_compat.h" + +#define MAX_FPGA_PORT_NUM 4 + +#define FME_FEATURE_HEADER "fme_hdr" +#define FME_FEATURE_THERMAL_MGMT "fme_thermal" +#define FME_FEATURE_POWER_MGMT "fme_power" +#define FME_FEATURE_GLOBAL_IPERF "fme_iperf" +#define FME_FEATURE_GLOBAL_ERR "fme_error" +#define FME_FEATURE_PR_MGMT "fme_pr" +#define FME_FEATURE_HSSI_ETH "fme_hssi" +#define FME_FEATURE_GLOBAL_DPERF "fme_dperf" +#define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" + +#define PORT_FEATURE_HEADER "port_hdr" +#define PORT_FEATURE_UAFU "port_uafu" +#define PORT_FEATURE_ERR "port_err" +#define PORT_FEATURE_UMSG "port_umsg" +#define PORT_FEATURE_PR "port_pr" +#define PORT_FEATURE_UINT "port_uint" +#define PORT_FEATURE_STP "port_stp" + +/* + * do not check the revision id as id may be dynamic under + * some cases, e.g, UAFU. + */ +#define SKIP_REVISION_CHECK 0xff + +#define FME_HEADER_REVISION 1 +#define FME_THERMAL_MGMT_REVISION 0 +#define FME_POWER_MGMT_REVISION 1 +#define FME_GLOBAL_IPERF_REVISION 1 +#define FME_GLOBAL_ERR_REVISION 1 +#define FME_PR_MGMT_REVISION 2 +#define FME_HSSI_ETH_REVISION 0 +#define FME_GLOBAL_DPERF_REVISION 0 +#define FME_QSPI_REVISION 0 + +#define PORT_HEADER_REVISION 0 +/* UAFU's header info depends on the downloaded GBS */ +#define PORT_UAFU_REVISION SKIP_REVISION_CHECK +#define PORT_ERR_REVISION 1 +#define PORT_UMSG_REVISION 0 +#define PORT_UINT_REVISION 0 +#define PORT_STP_REVISION 1 + +#define FEATURE_TYPE_AFU 0x1 +#define FEATURE_TYPE_BBB 0x2 +#define FEATURE_TYPE_PRIVATE 0x3 +#define FEATURE_TYPE_FIU 0x4 + +#define FEATURE_FIU_ID_FME 0x0 +#define FEATURE_FIU_ID_PORT 0x1 + +#define FEATURE_ID_HEADER 0x0 +#define FEATURE_ID_AFU 0xff + +enum fpga_id_type { + FME_ID, + PORT_ID, + 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, +}; + +struct uuid { + u8 b[16]; +}; + +/* + * All headers and structures must be byte-packed to match the + * SAS spec. + */ +#pragma pack(1) + +struct feature_header { + union { + u64 csr; + struct { + u16 id:12; + u8 revision:4; + u32 next_header_offset:24; + u8 end_of_list:1; + u32 reserved:19; + u8 type:4; + }; + }; +}; + +struct feature_bbb_header { + struct uuid guid; +}; + +struct feature_afu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fiu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fme_capability { + union { + u64 csr; + struct { + u8 fabric_verid; /* Fabric version ID */ + u8 socket_id:1; /* Socket id */ + u8 rsvd1:3; /* Reserved */ + /* pci0 link available yes /no */ + u8 pci0_link_avile:1; + /* pci1 link available yes /no */ + u8 pci1_link_avile:1; + /* Coherent (QPI/UPI) link available yes /no */ + u8 qpi_link_avile:1; + u8 rsvd2:1; /* Reserved */ + /* IOMMU or VT-d supported yes/no */ + u8 iommu_support:1; + u8 num_ports:3; /* Number of ports */ + u8 sf_fab_ctl:1; /* Internal validation bit */ + u8 rsvd3:3; /* Reserved */ + /* + * Address width supported in bits + * BXT -0x26 , SKX -0x30 + */ + u8 address_width_bits:6; + u8 rsvd4:2; /* Reserved */ + /* Size of cache supported in kb */ + u16 cache_size:12; + u8 cache_assoc:4; /* Cache Associativity */ + u16 rsvd5:15; /* Reserved */ + u8 lock_bit:1; /* Lock bit */ + }; + }; +}; + +#define FME_AFU_ACCESS_PF 0 +#define FME_AFU_ACCESS_VF 1 + +struct feature_fme_port { + union { + u64 csr; + struct { + u32 port_offset:24; + u8 reserved1; + u8 port_bar:3; + u32 reserved2:20; + u8 afu_access_control:1; + u8 reserved3:4; + u8 port_implemented:1; + u8 reserved4:3; + }; + }; +}; + +struct feature_fme_fab_status { + union { + u64 csr; + struct { + u8 upilink_status:4; /* UPI Link Status */ + u8 rsvd1:4; /* Reserved */ + u8 pci0link_status:1; /* pci0 link status */ + u8 rsvd2:3; /* Reserved */ + u8 pci1link_status:1; /* pci1 link status */ + u64 rsvd3:51; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_base { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Base Address of memory range */ + u8 protected_base_addrss:4; + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_limit { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Limit Address of memory range */ + u8 protected_limit_addrss:4; + u16 rsvd2:11; /* Reserved */ + u8 enable:1; /* Enable GENPROTRANGE check */ + u32 rsvd3; /* Reserved */ + }; + }; +}; + +struct feature_fme_dxe_lock { + union { + u64 csr; + struct { + /* + * Determines write access to the DXE region CSRs + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_early_lock:1; + /* + * Determines write access to the HSSI CSR + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_late_lock:1; + u64 rsvd:62; + }; + }; +}; + +#define HSSI_ID_NO_HASSI 0 +#define HSSI_ID_PCIE_RP 1 +#define HSSI_ID_ETHERNET 2 + +struct feature_fme_bitstream_id { + union { + u64 csr; + struct { + u32 gitrepo_hash:32; /* GIT repository hash */ + /* + * HSSI configuration identifier: + * 0 - No HSSI + * 1 - PCIe-RP + * 2 - Ethernet + */ + u8 hssi_id:4; + u16 rsvd1:12; /* Reserved */ + /* Bitstream version patch number */ + u8 bs_verpatch:4; + /* Bitstream version minor number */ + u8 bs_verminor:4; + /* Bitstream version major number */ + u8 bs_vermajor:4; + /* Bitstream version debug number */ + u8 bs_verdebug:4; + }; + }; +}; + +struct feature_fme_bitstream_md { + union { + u64 csr; + struct { + /* Seed number userd for synthesis flow */ + u8 synth_seed:4; + /* Synthesis date(day number - 2 digits) */ + u8 synth_day:8; + /* Synthesis date(month number - 2 digits) */ + u8 synth_month:8; + /* Synthesis date(year number - 2 digits) */ + u8 synth_year:8; + u64 rsvd:36; /* Reserved */ + }; + }; +}; + +struct feature_fme_iommu_ctrl { + union { + u64 csr; + struct { + /* Disables IOMMU prefetcher for C0 channel */ + u8 prefetch_disableC0:1; + /* Disables IOMMU prefetcher for C1 channel */ + u8 prefetch_disableC1:1; + /* Disables IOMMU partial cache line writes */ + u8 prefetch_wrdisable:1; + u8 rsvd1:1; /* Reserved */ + /* + * Select counter and read value from register + * iommu_stat.dbg_counters + * 0 - Number of 4K page translation response + * 1 - Number of 2M page translation response + * 2 - Number of 1G page translation response + */ + u8 counter_sel:2; + u32 rsvd2:26; /* Reserved */ + /* Connected to IOMMU SIP Capabilities */ + u32 capecap_defeature; + }; + }; +}; + +struct feature_fme_iommu_stat { + union { + u64 csr; + struct { + /* Translation Enable bit from IOMMU SIP */ + u8 translation_enable:1; + /* Drain request in progress */ + u8 drain_req_inprog:1; + /* Invalidation current state */ + u8 inv_state:3; + /* C0 Response Buffer current state */ + u8 respbuffer_stateC0:3; + /* C1 Response Buffer current state */ + u8 respbuffer_stateC1:3; + /* Last request ID to IOMMU SIP */ + u8 last_reqID:4; + /* Last IOMMU SIP response ID value */ + u8 last_respID:4; + /* Last IOMMU SIP response status value */ + u8 last_respstatus:3; + /* C0 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC0:1; + /* C1 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC1:1; + /* C0 Request FIFO is not empty */ + u8 reqFIFO_notemptyC0:1; + /* C1 Request FIFO is not empty */ + u8 reqFIFO_notemptyC1:1; + /* C0 Response FIFO is not empty */ + u8 respFIFO_notemptyC0:1; + /* C1 Response FIFO is not empty */ + u8 respFIFO_notemptyC1:1; + /* C0 Response FIFO overflow detected */ + u8 respFIFO_overflowC0:1; + /* C1 Response FIFO overflow detected */ + u8 respFIFO_overflowC1:1; + /* C0 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC0:1; + /* C1 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC1:1; + /* Request FIFO overflow detected */ + u8 reqFIFO_overflow:1; + /* IOMMU memory read in progress */ + u8 memrd_inprog:1; + /* IOMMU memory write in progress */ + u8 memwr_inprog:1; + u8 rsvd1:1; /* Reserved */ + /* Value of counter selected by iommu_ctl.counter_sel */ + u16 dbg_counters:16; + u16 rsvd2:12; /* Reserved */ + }; + }; +}; + +struct feature_fme_pcie0_ctrl { + union { + u64 csr; + struct { + u64 vtd_bar_lock:1; /* Lock VT-D BAR register */ + u64 rsvd1:3; + u64 rciep:1; /* Configure PCIE0 as RCiEP */ + u64 rsvd2:59; + }; + }; +}; + +struct feature_fme_llpr_smrr_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR rule is valid or not */ + /* + * SMRR memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR2 rule is valid or not */ + /* + * SMRR2 memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_meseg_base { + union { + u64 csr; + struct { + /* A[45:19] of base address memory range */ + u64 me_base:27; + u64 rsvd:37; + }; + }; +}; + +struct feature_fme_llpr_meseg_limit { + union { + u64 csr; + struct { + /* A[45:19] of limit address memory range */ + u64 me_limit:27; + u64 rsvd1:4; + u64 enable:1; /* Enable LLPR MESEG rule */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 reserved; + u64 scratchpad; + struct feature_fme_capability capability; + struct feature_fme_port port[MAX_FPGA_PORT_NUM]; + struct feature_fme_fab_status fab_status; + struct feature_fme_bitstream_id bitstream_id; + struct feature_fme_bitstream_md bitstream_md; + struct feature_fme_genprotrange2_base genprotrange2_base; + struct feature_fme_genprotrange2_limit genprotrange2_limit; + struct feature_fme_dxe_lock dxe_lock; + struct feature_fme_iommu_ctrl iommu_ctrl; + struct feature_fme_iommu_stat iommu_stat; + struct feature_fme_pcie0_ctrl pcie0_control; + struct feature_fme_llpr_smrr_base smrr_base; + struct feature_fme_llpr_smrr_mask smrr_mask; + struct feature_fme_llpr_smrr2_base smrr2_base; + struct feature_fme_llpr_smrr2_mask smrr2_mask; + struct feature_fme_llpr_meseg_base meseg_base; + struct feature_fme_llpr_meseg_limit meseg_limit; +}; + +struct feature_port_capability { + union { + u64 csr; + struct { + u8 port_number:2; /* Port Number 0-3 */ + u8 rsvd1:6; /* Reserved */ + u16 mmio_size; /* User MMIO size in KB */ + u8 rsvd2; /* Reserved */ + u8 sp_intr_num:4; /* Supported interrupts num */ + u32 rsvd3:28; /* Reserved */ + }; + }; +}; + +struct feature_port_control { + union { + u64 csr; + struct { + u8 port_sftrst:1; /* Port Soft Reset */ + u8 rsvd1:1; /* Reserved */ + u8 latency_tolerance:1;/* '1' >= 40us, '0' < 40us */ + u8 rsvd2:1; /* Reserved */ + u8 port_sftrst_ack:1; /* HW ACK for Soft Reset */ + u64 rsvd3:59; /* Reserved */ + }; + }; +}; + +#define PORT_POWER_STATE_NORMAL 0 +#define PORT_POWER_STATE_AP1 1 +#define PORT_POWER_STATE_AP2 2 +#define PORT_POWER_STATE_AP6 6 + +struct feature_port_status { + union { + u64 csr; + struct { + u8 port_freeze:1; /* '1' - freezed '0' - normal */ + u8 rsvd1:7; /* Reserved */ + u8 power_state:4; /* Power State */ + u8 ap1_event:1; /* AP1 event was detected */ + u8 ap2_event:1; /* AP2 event was detected */ + u64 rsvd2:50; /* Reserved */ + }; + }; +}; + +/* Port Header Register Set */ +struct feature_port_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 port_mailbox; + u64 scratchpad; + struct feature_port_capability capability; + struct feature_port_control control; + struct feature_port_status status; + u64 rsvd2; + u64 user_clk_freq_cmd0; + u64 user_clk_freq_cmd1; + u64 user_clk_freq_sts0; + u64 user_clk_freq_sts1; +}; + +struct feature_fme_tmp_threshold { + union { + u64 csr; + struct { + u8 tmp_thshold1:7; /* temperature Threshold 1 */ + /* temperature Threshold 1 enable/disable */ + u8 tmp_thshold1_enable:1; + u8 tmp_thshold2:7; /* temperature Threshold 2 */ + /* temperature Threshold 2 enable /disable */ + u8 tmp_thshold2_enable:1; + u8 pro_hot_setpoint:7; /* Proc Hot set point */ + u8 rsvd4:1; /* Reserved */ + u8 therm_trip_thshold:7; /* Thermeal Trip Threshold */ + u8 rsvd3:1; /* Reserved */ + u8 thshold1_status:1; /* Threshold 1 Status */ + u8 thshold2_status:1; /* Threshold 2 Status */ + u8 rsvd5:1; /* Reserved */ + /* Thermeal Trip Threshold status */ + u8 therm_trip_thshold_status:1; + u8 rsvd6:4; /* Reserved */ + /* Validation mode- Force Proc Hot */ + u8 valmodeforce:1; + /* Validation mode - Therm trip Hot */ + u8 valmodetherm:1; + u8 rsvd2:2; /* Reserved */ + u8 thshold_policy:1; /* threshold policy */ + u32 rsvd:19; /* Reserved */ + }; + }; +}; + +/* Temperature Sensor Read values format 1 */ +struct feature_fme_temp_rdsensor_fmt1 { + union { + u64 csr; + struct { + /* Reads out FPGA temperature in celsius */ + u8 fpga_temp:7; + u8 rsvd0:1; /* Reserved */ + /* Temperature reading sequence number */ + u16 tmp_reading_seq_num; + /* Temperature reading is valid */ + u8 tmp_reading_valid:1; + u8 rsvd1:7; /* Reserved */ + u16 dbg_mode:10; /* Debug mode */ + u32 rsvd2:22; /* Reserved */ + }; + }; +}; + +/* Temperature sensor read values format 2 */ +struct feature_fme_temp_rdsensor_fmt2 { + u64 rsvd; /* Reserved */ +}; + +/* Temperature Threshold Capability Register */ +struct feature_fme_tmp_threshold_cap { + union { + u64 csr; + struct { + /* Temperature Threshold Unsupported */ + u8 tmp_thshold_disabled:1; + u64 rsvd:63; /* Reserved */ + }; + }; +}; + +/* FME THERNAL FEATURE */ +struct feature_fme_thermal { + struct feature_header header; + struct feature_fme_tmp_threshold threshold; + struct feature_fme_temp_rdsensor_fmt1 rdsensor_fm1; + struct feature_fme_temp_rdsensor_fmt2 rdsensor_fm2; + struct feature_fme_tmp_threshold_cap threshold_cap; +}; + +/* Power Status register */ +struct feature_fme_pm_status { + union { + u64 csr; + struct { + /* FPGA Power consumed, The format is to be defined */ + u32 pwr_consumed:18; + /* FPGA Latency Tolerance Reporting */ + u8 fpga_latency_report:1; + u64 rsvd:45; /* Reserved */ + }; + }; +}; + +/* AP Thresholds */ +struct feature_fme_pm_ap_threshold { + union { + u64 csr; + struct { + /* + * Number of clocks (5ns period) for assertion + * of FME_data + */ + u8 threshold1:7; + u8 rsvd1:1; + u8 threshold2:7; + u8 rsvd2:1; + u8 threshold1_status:1; + u8 threshold2_status:1; + u64 rsvd3:46; /* Reserved */ + }; + }; +}; + +/* Xeon Power Limit */ +struct feature_fme_pm_xeon_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* MCP Power Limit */ +struct feature_fme_pm_fpga_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FME POWER FEATURE */ +struct feature_fme_power { + struct feature_header header; + struct feature_fme_pm_status status; + struct feature_fme_pm_ap_threshold threshold; + struct feature_fme_pm_xeon_limit xeon_limit; + struct feature_fme_pm_fpga_limit fpga_limit; +}; + +#define CACHE_CHANNEL_RD 0 +#define CACHE_CHANNEL_WR 1 + +enum iperf_cache_events { + IPERF_CACHE_RD_HIT, + IPERF_CACHE_WR_HIT, + IPERF_CACHE_RD_MISS, + IPERF_CACHE_WR_MISS, + IPERF_CACHE_RSVD, /* reserved */ + IPERF_CACHE_HOLD_REQ, + IPERF_CACHE_DATA_WR_PORT_CONTEN, + IPERF_CACHE_TAG_WR_PORT_CONTEN, + IPERF_CACHE_TX_REQ_STALL, + IPERF_CACHE_RX_REQ_STALL, + IPERF_CACHE_EVICTIONS, +}; + +/* FPMON Cache Control */ +struct feature_fme_ifpmon_ch_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd1:7; /* Reserved */ + u8 freeze:1; /* Freeze if set to 1 */ + u8 rsvd2:7; /* Reserved */ + u8 cache_event:4; /* Select the cache event */ + u8 cci_chsel:1; /* Select the channel */ + u64 rsvd3:43; /* Reserved */ + }; + }; +}; + +/* FPMON Cache Counter */ +struct feature_fme_ifpmon_ch_ctr { + union { + u64 csr; + struct { + /* Cache Counter for even addresse */ + u64 cache_counter:48; + u16 rsvd:12; /* Reserved */ + /* Cache Event being reported */ + u8 event_code:4; + }; + }; +}; + +enum iperf_fab_events { + IPERF_FAB_PCIE0_RD, + IPERF_FAB_PCIE0_WR, + IPERF_FAB_PCIE1_RD, + IPERF_FAB_PCIE1_WR, + IPERF_FAB_UPI_RD, + IPERF_FAB_UPI_WR, + IPERF_FAB_MMIO_RD, + IPERF_FAB_MMIO_WR, +}; + +#define FAB_DISABLE_FILTER 0 +#define FAB_ENABLE_FILTER 1 + +/* FPMON FAB Control */ +struct feature_fme_ifpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_ifpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_ifpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +enum iperf_vtd_events { + IPERF_VTD_AFU_MEM_RD_TRANS, + IPERF_VTD_AFU_MEM_WR_TRANS, + IPERF_VTD_AFU_DEVTLB_RD_HIT, + IPERF_VTD_AFU_DEVTLB_WR_HIT, + IPERF_VTD_DEVTLB_4K_FILL, + IPERF_VTD_DEVTLB_2M_FILL, + IPERF_VTD_DEVTLB_1G_FILL, +}; + +/* VT-d control register */ +struct feature_fme_ifpmon_vtd_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d event counter */ +struct feature_fme_ifpmon_vtd_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +enum iperf_vtd_sip_events { + IPERF_VTD_SIP_IOTLB_4K_HIT, + IPERF_VTD_SIP_IOTLB_2M_HIT, + IPERF_VTD_SIP_IOTLB_1G_HIT, + IPERF_VTD_SIP_SLPWC_L3_HIT, + IPERF_VTD_SIP_SLPWC_L4_HIT, + IPERF_VTD_SIP_RCC_HIT, + IPERF_VTD_SIP_IOTLB_4K_MISS, + IPERF_VTD_SIP_IOTLB_2M_MISS, + IPERF_VTD_SIP_IOTLB_1G_MISS, + IPERF_VTD_SIP_SLPWC_L3_MISS, + IPERF_VTD_SIP_SLPWC_L4_MISS, + IPERF_VTD_SIP_RCC_MISS, +}; + +/* VT-d SIP control register */ +struct feature_fme_ifpmon_vtd_sip_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d SIP event counter */ +struct feature_fme_ifpmon_vtd_sip_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +/* FME IPERF FEATURE */ +struct feature_fme_iperf { + struct feature_header header; + struct feature_fme_ifpmon_ch_ctl ch_ctl; + struct feature_fme_ifpmon_ch_ctr ch_ctr0; + struct feature_fme_ifpmon_ch_ctr ch_ctr1; + struct feature_fme_ifpmon_fab_ctl fab_ctl; + struct feature_fme_ifpmon_fab_ctr fab_ctr; + struct feature_fme_ifpmon_clk_ctr clk; + struct feature_fme_ifpmon_vtd_ctl vtd_ctl; + struct feature_fme_ifpmon_vtd_ctr vtd_ctr; + struct feature_fme_ifpmon_vtd_sip_ctl vtd_sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr vtd_sip_ctr; +}; + +enum dperf_fab_events { + DPERF_FAB_PCIE0_RD, + DPERF_FAB_PCIE0_WR, + DPERF_FAB_MMIO_RD = 6, + DPERF_FAB_MMIO_WR, +}; + +#define DCP_FAB_DISABLE_FILTER 0 +#define DCP_FAB_ENABLE_FILTER 1 + +/* FPMON FAB Control */ +struct feature_fme_dfpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_dfpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_dfpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +/* FME DPERF FEATURE */ +struct feature_fme_dperf { + struct feature_header header; + u64 rsvd[3]; + struct feature_fme_dfpmon_fab_ctl fab_ctl; + struct feature_fme_dfpmon_fab_ctr fab_ctr; + struct feature_fme_dfpmon_clk_ctr clk; +}; + +struct feature_fme_error0 { +#define FME_ERROR0_MASK 0xFFUL +#define FME_ERROR0_MASK_DEFAULT 0x40UL /* pcode workaround */ + union { + u64 csr; + struct { + u8 fabric_err:1; /* Fabric error */ + u8 fabfifo_overflow:1; /* Fabric fifo overflow */ + u8 kticdc_parity_err:2;/* KTI CDC Parity Error */ + u8 iommu_parity_err:1; /* IOMMU Parity error */ + /* AFU PF/VF access mismatch detected */ + u8 afu_acc_mode_err:1; + u8 mbp_err:1; /* Indicates an MBP event */ + /* PCIE0 CDC Parity Error */ + u8 pcie0cdc_parity_err:5; + /* PCIE1 CDC Parity Error */ + u8 pcie1cdc_parity_err:5; + /* CVL CDC Parity Error */ + u8 cvlcdc_parity_err:3; + u64 rsvd:44; /* Reserved */ + }; + }; +}; + +/* PCIe0 Error Status register */ +struct feature_fme_pcie0_error { +#define FME_PCIE0_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:52; /* Reserved */ + u8 vfnumb_err:1; /* Number of error VF */ + u8 funct_type_err:1; /* Virtual (1) or Physical */ + }; + }; +}; + +/* PCIe1 Error Status register */ +struct feature_fme_pcie1_error { +#define FME_PCIE1_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:54; /* Reserved */ + }; + }; +}; + +/* FME First Error register */ +struct feature_fme_first_error { +#define FME_FIRST_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered first + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered first + */ + u8 errReg_id:4; + }; + }; +}; + +/* FME Next Error register */ +struct feature_fme_next_error { +#define FME_NEXT_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered second + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered second + */ + u8 errReg_id:4; + }; + }; +}; + +/* RAS Non Fatal Error Status register */ +struct feature_fme_ras_nonfaterror { + union { + u64 csr; + struct { + /* thremal threshold AP1 */ + u8 temp_thresh_ap1:1; + /* thremal threshold AP2 */ + u8 temp_thresh_ap2:1; + u8 pcie_error:1; /* pcie Error */ + u8 portfatal_error:1; /* port fatal error */ + u8 proc_hot:1; /* Indicates a ProcHot event */ + /* Indicates an AFU PF/VF access mismatch */ + u8 afu_acc_mode_err:1; + /* Injected nonfata Error */ + u8 injected_nonfata_err:1; + u8 rsvd1:2; + /* Temperature threshold triggered AP6*/ + u8 temp_thresh_AP6:1; + /* Power threshold triggered AP1 */ + u8 power_thresh_AP1:1; + /* Power threshold triggered AP2 */ + u8 power_thresh_AP2:1; + /* Indicates a MBP event */ + u8 mbp_err:1; + u64 rsvd2:51; /* Reserved */ + }; + }; +}; + +/* RAS Catastrophic Fatal Error Status register */ +struct feature_fme_ras_catfaterror { + union { + u64 csr; + struct { + /* KTI Link layer error detected */ + u8 ktilink_fatal_err:1; + /* tag-n-cache error detected */ + u8 tagcch_fatal_err:1; + /* CCI error detected */ + u8 cci_fatal_err:1; + /* KTI Protocol error detected */ + u8 ktiprpto_fatal_err:1; + /* Fatal DRAM error detected */ + u8 dram_fatal_err:1; + /* IOMMU detected */ + u8 iommu_fatal_err:1; + /* Fabric Fatal Error */ + u8 fabric_fatal_err:1; + /* PCIe possion Error */ + u8 pcie_poison_err:1; + /* Injected fatal Error */ + u8 inject_fata_err:1; + /* Catastrophic CRC Error */ + u8 crc_catast_err:1; + /* Catastrophic Thermal Error */ + u8 therm_catast_err:1; + /* Injected Catastrophic Error */ + u8 injected_catast_err:1; + u64 rsvd:52; + }; + }; +}; + +/* RAS Error injection register */ +struct feature_fme_ras_error_inj { +#define FME_RAS_ERROR_INJ_MASK 0x7UL + union { + u64 csr; + struct { + u8 catast_error:1; /* Catastrophic error flag */ + u8 fatal_error:1; /* Fatal error flag */ + u8 nonfatal_error:1; /* NonFatal error flag */ + u64 rsvd:61; /* Reserved */ + }; + }; +}; + +/* FME error capabilities */ +struct feature_fme_error_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* FME ERR FEATURE */ +struct feature_fme_err { + struct feature_header header; + struct feature_fme_error0 fme_err_mask; + struct feature_fme_error0 fme_err; + struct feature_fme_pcie0_error pcie0_err_mask; + struct feature_fme_pcie0_error pcie0_err; + struct feature_fme_pcie1_error pcie1_err_mask; + struct feature_fme_pcie1_error pcie1_err; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + struct feature_fme_ras_nonfaterror ras_nonfat_mask; + struct feature_fme_ras_nonfaterror ras_nonfaterr; + struct feature_fme_ras_catfaterror ras_catfat_mask; + struct feature_fme_ras_catfaterror ras_catfaterr; + struct feature_fme_ras_error_inj ras_error_inj; + struct feature_fme_error_capability fme_err_capability; +}; + +/* FME Partial Reconfiguration Control */ +struct feature_fme_pr_ctl { + union { + u64 csr; + struct { + u8 pr_reset:1; /* Reset PR Engine */ + u8 rsvd3:3; /* Reserved */ + u8 pr_reset_ack:1; /* Reset PR Engine Ack */ + u8 rsvd4:3; /* Reserved */ + u8 pr_regionid:2; /* PR Region ID */ + u8 rsvd1:2; /* Reserved */ + u8 pr_start_req:1; /* PR Start Request */ + u8 pr_push_complete:1; /* PR Data push complete */ + u8 pr_kind:1; /* PR Data push complete */ + u32 rsvd:17; /* Reserved */ + u32 config_data; /* Config data TBD */ + }; + }; +}; + +/* FME Partial Reconfiguration Status */ +struct feature_fme_pr_status { + union { + u64 csr; + struct { + u16 pr_credit:9; /* PR Credits */ + u8 rsvd2:7; /* Reserved */ + u8 pr_status:1; /* PR status */ + u8 rsvd:3; /* Reserved */ + /* Altra PR Controller Block status */ + u8 pr_controller_status:3; + u8 rsvd1:1; /* Reserved */ + u8 pr_host_status:4; /* PR Host status */ + u8 rsvd3:4; /* Reserved */ + /* Security Block Status fields (TBD) */ + u32 security_bstatus; + }; + }; +}; + +/* FME Partial Reconfiguration Data */ +struct feature_fme_pr_data { + union { + u64 csr; /* PR data from the raw-binary file */ + struct { + /* PR data from the raw-binary file */ + u32 pr_data_raw; + u32 rsvd; + }; + }; +}; + +/* FME PR Public Key */ +struct feature_fme_pr_key { + u64 key; /* FME PR Public Hash */ +}; + +/* FME PR FEATURE */ +struct feature_fme_pr { + struct feature_header header; + /*Partial Reconfiguration control */ + struct feature_fme_pr_ctl ccip_fme_pr_control; + + /* Partial Reconfiguration Status */ + struct feature_fme_pr_status ccip_fme_pr_status; + + /* Partial Reconfiguration data */ + struct feature_fme_pr_data ccip_fme_pr_data; + + /* Partial Reconfiguration data */ + u64 ccip_fme_pr_err; + + u64 rsvd1[3]; + + /* Partial Reconfiguration data registers */ + u64 fme_pr_data1; + u64 fme_pr_data2; + u64 fme_pr_data3; + u64 fme_pr_data4; + u64 fme_pr_data5; + u64 fme_pr_data6; + u64 fme_pr_data7; + u64 fme_pr_data8; + + u64 rsvd2[5]; + + /* PR Interface ID */ + u64 fme_pr_intfc_id_l; + u64 fme_pr_intfc_id_h; + + /* MSIX filed to be Added */ +}; + +/* FME HSSI Control */ +struct feature_fme_hssi_eth_ctrl { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u16 address:16; /* HSSI address */ + /* + * HSSI comamnd + * 0x0 - No request + * 0x08 - SW register RD request + * 0x10 - SW register WR request + * 0x40 - Auxiliar bus RD request + * 0x80 - Auxiliar bus WR request + */ + u16 cmd:16; + }; + }; +}; + +/* FME HSSI Status */ +struct feature_fme_hssi_eth_stat { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u8 acknowledge:1; /* HSSI acknowledge */ + u8 spare:1; /* HSSI spare */ + u32 rsvd:30; /* Reserved */ + }; + }; +}; + +/* FME HSSI FEATURE */ +struct feature_fme_hssi { + struct feature_header header; + struct feature_fme_hssi_eth_ctrl hssi_control; + struct feature_fme_hssi_eth_stat hssi_status; +}; + +#define PORT_ERR_MASK 0xfff0703ff001f +struct feature_port_err_key { + union { + u64 csr; + struct { + /* Tx Channel0: Overflow */ + u8 tx_ch0_overflow:1; + /* Tx Channel0: Invalid request encoding */ + u8 tx_ch0_invaldreq :1; + /* Tx Channel0: Request with cl_len=3 not supported */ + u8 tx_ch0_cl_len3:1; + /* Tx Channel0: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch0_cl_len2:1; + /* Tx Channel0: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch0_cl_len4:1; + + u16 rsvd1:4; /* Reserved */ + + /* AFU MMIO RD received while PORT is in reset */ + u8 mmio_rd_whilerst:1; + /* AFU MMIO WR received while PORT is in reset */ + u8 mmio_wr_whilerst:1; + + u16 rsvd2:5; /* Reserved */ + + /* Tx Channel1: Overflow */ + u8 tx_ch1_overflow:1; + /* Tx Channel1: Invalid request encoding */ + u8 tx_ch1_invaldreq:1; + /* Tx Channel1: Request with cl_len=3 not supported */ + u8 tx_ch1_cl_len3:1; + /* Tx Channel1: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch1_cl_len2:1; + /* Tx Channel1: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch1_cl_len4:1; + + /* Tx Channel1: Insufficient data payload */ + u8 tx_ch1_insuff_data:1; + /* Tx Channel1: Data payload overrun */ + u8 tx_ch1_data_overrun:1; + /* Tx Channel1 : Incorrect address */ + u8 tx_ch1_incorr_addr:1; + /* Tx Channel1 : NON-Zero SOP Detected */ + u8 tx_ch1_nzsop:1; + /* Tx Channel1 : Illegal VC_SEL, atomic request VLO */ + u8 tx_ch1_illegal_vcsel:1; + + u8 rsvd3:6; /* Reserved */ + + /* MMIO Read Timeout in AFU */ + u8 mmioread_timeout:1; + + /* Tx Channel2: FIFO Overflow */ + u8 tx_ch2_fifo_overflow:1; + + /* MMIO read is not matching pending request */ + u8 unexp_mmio_resp:1; + + u8 rsvd4:5; /* Reserved */ + + /* Number of pending Requests: counter overflow */ + u8 tx_req_counter_overflow:1; + /* Req with Address violating SMM Range */ + u8 llpr_smrr_err:1; + /* Req with Address violating second SMM Range */ + u8 llpr_smrr2_err:1; + /* Req with Address violating ME Stolen message */ + u8 llpr_mesg_err:1; + /* Req with Address violating Generic Protected Range */ + u8 genprot_range_err:1; + /* Req with Address violating Legacy Range low */ + u8 legrange_low_err:1; + /* Req with Address violating Legacy Range High */ + u8 legrange_high_err:1; + /* Req with Address violating VGA memory range */ + u8 vgmem_range_err:1; + u8 page_fault_err:1; /* Page fault */ + u8 pmr_err:1; /* PMR Error */ + u8 ap6_event:1; /* AP6 event */ + /* VF FLR detected on Port with PF access control */ + u8 vfflr_access_err:1; + u16 rsvd5:12; /* Reserved */ + }; + }; +}; + +/* Port first error register, not contain all error bits in error register. */ +struct feature_port_first_err_key { + union { + u64 csr; + struct { + u8 tx_ch0_overflow:1; + u8 tx_ch0_invaldreq :1; + u8 tx_ch0_cl_len3:1; + u8 tx_ch0_cl_len2:1; + u8 tx_ch0_cl_len4:1; + u8 rsvd1:4; /* Reserved */ + u8 mmio_rd_whilerst:1; + u8 mmio_wr_whilerst:1; + u8 rsvd2:5; /* Reserved */ + u8 tx_ch1_overflow:1; + u8 tx_ch1_invaldreq:1; + u8 tx_ch1_cl_len3:1; + u8 tx_ch1_cl_len2:1; + u8 tx_ch1_cl_len4:1; + u8 tx_ch1_insuff_data:1; + u8 tx_ch1_data_overrun:1; + u8 tx_ch1_incorr_addr:1; + u8 tx_ch1_nzsop:1; + u8 tx_ch1_illegal_vcsel:1; + u8 rsvd3:6; /* Reserved */ + u8 mmioread_timeout:1; + u8 tx_ch2_fifo_overflow:1; + u8 rsvd4:6; /* Reserved */ + u8 tx_req_counter_overflow:1; + u32 rsvd5:23; /* Reserved */ + }; + }; +}; + +/* Port malformed Req0 */ +struct feature_port_malformed_req0 { + u64 header_lsb; +}; + +/* Port malformed Req1 */ +struct feature_port_malformed_req1 { + u64 header_msb; +}; + +/* Port debug register */ +struct feature_port_debug { + u64 port_debug; +}; + +/* Port error capabilities */ +struct feature_port_err_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE ERROR */ +struct feature_port_error { + struct feature_header header; + struct feature_port_err_key error_mask; + struct feature_port_err_key port_error; + struct feature_port_first_err_key port_first_error; + struct feature_port_malformed_req0 malreq0; + struct feature_port_malformed_req1 malreq1; + struct feature_port_debug port_debug; + struct feature_port_err_capability error_capability; +}; + +/* Port UMSG Capability */ +struct feature_port_umsg_cap { + union { + u64 csr; + struct { + /* Number of umsg allocated to this port */ + u8 umsg_allocated; + /* Enable / Disable UMsg engine for this port */ + u8 umsg_enable:1; + /* Usmg initialization status */ + u8 umsg_init_complete:1; + /* IOMMU can not translate the umsg base address */ + u8 umsg_trans_error:1; + u64 rsvd:53; /* Reserved */ + }; + }; +}; + +/* Port UMSG base address */ +struct feature_port_umsg_baseaddr { + union { + u64 csr; + struct { + u64 base_addr:48; /* 48 bit physical address */ + u16 rsvd; /* Reserved */ + }; + }; +}; + +struct feature_port_umsg_mode { + union { + u64 csr; + struct { + u32 umsg_hint_enable; /* UMSG hint enable/disable */ + u32 rsvd; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE UMSG */ +struct feature_port_umsg { + struct feature_header header; + struct feature_port_umsg_cap capability; + struct feature_port_umsg_baseaddr baseaddr; + struct feature_port_umsg_mode mode; +}; + +#define UMSG_EN_POLL_INVL 10 /* us */ +#define UMSG_EN_POLL_TIMEOUT 1000 /* us */ + +/* Port UINT Capability */ +struct feature_port_uint_cap { + union { + u64 csr; + struct { + u16 intr_num:12; /* Supported interrupts num */ + /* First MSI-X vector table entry number */ + u16 first_vec_num:12; + u64 rsvd:40; + }; + }; +}; + +/* PORT FEATURE UINT */ +struct feature_port_uint { + struct feature_header header; + struct feature_port_uint_cap capability; +}; + +/* STP region supports mmap operation, so use page aligned size. */ +#define PORT_FEATURE_STP_REGION_SIZE PAGE_ALIGN(sizeof(struct feature_port_stp)) + +/* Port STP status register (for debug only)*/ +struct feature_port_stp_status { + union { + u64 csr; + struct { + /* SLD Hub end-point read/write timeout */ + u8 sld_ep_timeout:1; + /* Remote STP in reset/disable */ + u8 rstp_disabled:1; + u8 unsupported_read:1; + /* MMIO timeout detected and faked with a response */ + u8 mmio_timeout:1; + u8 txfifo_count:4; + u8 rxfifo_count:4; + u8 txfifo_overflow:1; + u8 txfifo_underflow:1; + u8 rxfifo_overflow:1; + u8 rxfifo_underflow:1; + /* Number of MMIO write requests */ + u16 write_requests; + /* Number of MMIO read requests */ + u16 read_requests; + /* Number of MMIO read responses */ + u16 read_responses; + }; + }; +}; + +/* + * PORT FEATURE STP + * Most registers in STP region are not touched by driver, but mmapped to user + * space. So they are not defined in below data structure, as its actual size + * is 0x18c per spec. + */ +struct feature_port_stp { + struct feature_header header; + struct feature_port_stp_status stp_status; +}; + +/** + * enum fpga_pr_states - fpga PR states + * @FPGA_PR_STATE_UNKNOWN: can't determine state + * @FPGA_PR_STATE_WRITE_INIT: preparing FPGA for programming + * @FPGA_PR_STATE_WRITE_INIT_ERR: Error during WRITE_INIT stage + * @FPGA_PR_STATE_WRITE: writing image to FPGA + * @FPGA_PR_STATE_WRITE_ERR: Error while writing FPGA + * @FPGA_PR_STATE_WRITE_COMPLETE: Doing post programming steps + * @FPGA_PR_STATE_WRITE_COMPLETE_ERR: Error during WRITE_COMPLETE + * @FPGA_PR_STATE_OPERATING: FPGA PR done + */ +enum fpga_pr_states { + /* canot determine state states */ + FPGA_PR_STATE_UNKNOWN, + + /* write sequence: init, write, complete */ + FPGA_PR_STATE_WRITE_INIT, + FPGA_PR_STATE_WRITE_INIT_ERR, + FPGA_PR_STATE_WRITE, + FPGA_PR_STATE_WRITE_ERR, + FPGA_PR_STATE_WRITE_COMPLETE, + FPGA_PR_STATE_WRITE_COMPLETE_ERR, + + /* FPGA PR done */ + FPGA_PR_STATE_DONE, +}; + +/* + * FPGA Manager flags + * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported + */ +#define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + +/** + * struct fpga_pr_info - specific information to a FPGA PR + * @flags: boolean flags as defined above + * @pr_err: PR error code + * @state: fpga manager state + * @port_id: port id + */ +struct fpga_pr_info { + u32 flags; + u64 pr_err; + enum fpga_pr_states state; + int port_id; +}; + +#define DEFINE_FPGA_PR_ERR_MSG(_name_) \ +static const char * const _name_[] = { \ + "PR operation error detected", \ + "PR CRC error detected", \ + "PR incompatiable bitstream error detected", \ + "PR IP protocol error detected", \ + "PR FIFO overflow error detected", \ + "PR timeout error detected", \ + "PR secure load error detected", \ +} + +#define RST_POLL_INVL 10 /* us */ +#define RST_POLL_TIMEOUT 1000 /* us */ + +#define PR_WAIT_TIMEOUT 15000000 + +#define PR_HOST_STATUS_IDLE 0 +#define PR_MAX_ERR_NUM 7 + +DEFINE_FPGA_PR_ERR_MSG(pr_err_msg); + +/* + * green bitstream header must be byte-packed to match the + * real file format. + */ +struct bts_header { + u64 guid_h; + u64 guid_l; + u32 metadata_len; +}; + +#define GBS_GUID_H 0x414750466e6f6558 +#define GBS_GUID_L 0x31303076534247b7 +#define is_valid_bts(bts_hdr) \ + (((bts_hdr)->guid_h == GBS_GUID_H) && \ + ((bts_hdr)->guid_l == GBS_GUID_L)) + +#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 new file mode 100644 index 0000000..c6c081a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -0,0 +1,861 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "opae_hw_api.h" +#include "ifpga_api.h" + +#include "ifpga_hw.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +struct build_feature_devs_info { + struct opae_adapter_data_pci *pci_data; + + struct ifpga_afu_info *acc_info; + + void *fiu; + enum fpga_id_type current_type; + int current_port_id; + + void *ioaddr; + void *ioend; + uint64_t phys_addr; + int current_bar; + + void *pfme_hdr; + + struct ifpga_hw *hw; +}; + +struct feature_info { + const char *name; + uint32_t resource_size; + int feature_index; + int revision_id; + unsigned int vec_start; + unsigned int vec_cnt; + + struct feature_ops *ops; +}; + +/* 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, + } +}; + +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 = &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 = &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, + .ops = &port_umsg_ops, + }, + { + .name = PORT_FEATURE_UINT, + .resource_size = sizeof(struct feature_port_uint), + .feature_index = PORT_FEATURE_ID_UINT, + .revision_id = PORT_UINT_REVISION, + .ops = &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 = &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 + }, +}; + +static u64 feature_id(void __iomem *start) +{ + struct feature_header header; + + header.csr = readq(start); + + switch (header.type) { + case FEATURE_TYPE_FIU: + return FEATURE_ID_HEADER; + case FEATURE_TYPE_PRIVATE: + return header.id; + case FEATURE_TYPE_AFU: + return FEATURE_ID_AFU; + } + + WARN_ON(1); + return 0; +} + +static int +build_info_add_sub_feature(struct build_feature_devs_info *binfo, + struct feature_info *finfo, void __iomem *start) +{ + 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; + } + + 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->phys_addr = binfo->phys_addr + + ((u8 *)start - (u8 *)binfo->ioaddr); + + if (vec_cnt) { + if (vec_start + vec_cnt <= vec_start) + return -EINVAL; + + ctx = zmalloc(sizeof(*ctx) * vec_cnt); + if (!ctx) + return -ENOMEM; + + for (i = 0; i < vec_cnt; i++) { + ctx[i].eventfd = -1; + ctx[i].idx = vec_start + i; + } + } + + feature->ctx = ctx; + feature->ctx_num = vec_cnt; + feature->vfio_dev_fd = binfo->pci_data->vfio_dev_fd; + + return ret; +} + +static int +create_feature_instance(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + struct feature_header *hdr = start; + + if (((u8 *)binfo->ioend - (u8 *)start) < finfo->resource_size) + return -EINVAL; + + 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); +} + +/* + * UAFU GUID is dynamic as it can be changed after FME downloads different + * Green Bitstream to the port, so we treat the unknown GUIDs which are + * attached on port's feature list as UAFU. + */ +static bool feature_is_UAFU(struct build_feature_devs_info *binfo) +{ + if (binfo->current_type != PORT_ID) + return false; + + return true; +} + +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; + struct ifpga_afu_info *info; + void *start = (void *)hdr; + int ret; + + if (port_features[id].resource_size) { + ret = create_feature_instance(binfo, hdr, &port_features[id]); + //port_features[id].resource_size = 0; + } else { + dev_err(binfo, "the uafu feature header is mis-configured.\n"); + ret = -EINVAL; + } + + if (ret) + return ret; + + /* FIXME: need to figure out a better name */ + info = 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->num_regions = 1; + + binfo->acc_info = info; + + return ret; +} + +static int parse_feature_afus(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + int ret; + struct feature_afu_header *afu_hdr, header; + u8 __iomem *start; + u8 __iomem *end = binfo->ioend; + + start = (u8 __iomem *)hdr; + for (; start < end; start += header.next_afu) { + if (end - start < + (unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr))) + return -EINVAL; + + hdr = (struct feature_header *)start; + afu_hdr = (struct feature_afu_header *)(hdr + 1); + header.csr = readq(&afu_hdr->csr); + + if (feature_is_UAFU(binfo)) + ret = parse_feature_port_uafu(binfo, hdr); + if (ret) + return ret; + + if (!header.next_afu) + break; + } + + return 0; +} + +/* create and register proper private data */ +static int build_info_commit_dev(struct build_feature_devs_info *binfo) +{ + struct ifpga_afu_info *info = binfo->acc_info; + struct ifpga_hw *hw = binfo->hw; + struct opae_manager *mgr; + struct opae_bridge *br; + struct opae_accelerator *acc; + + if (!binfo->fiu) + return 0; + + if (binfo->current_type == PORT_ID) { + /* return error if no valid acc info data structure */ + if (!info) + return -EFAULT; + + br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops, + binfo->fiu); + if (!br) + return -ENOMEM; + + br->id = binfo->current_port_id; + + /* update irq info */ + info->num_irqs = port_features[PORT_FEATURE_ID_UINT].vec_cnt; + + acc = opae_accelerator_alloc(hw->adapter->name, + &ifpga_acc_ops, info); + if (!acc) { + opae_bridge_free(br); + return -ENOMEM; + } + + acc->br = br; + acc->index = br->id; + + opae_adapter_add_acc(hw->adapter, acc); + + } else if (binfo->current_type == FME_ID) { + mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops, + binfo->fiu); + if (!mgr) + return -ENOMEM; + + mgr->adapter = hw->adapter; + hw->adapter->mgr = mgr; + } + + binfo->fiu = NULL; + + return 0; +} + +static int +build_info_create_dev(struct build_feature_devs_info *binfo, + enum fpga_id_type type, unsigned int index) +{ + int ret; + + ret = build_info_commit_dev(binfo); + if (ret) + return ret; + + binfo->current_type = type; + + if (type == FME_ID) { + binfo->fiu = &binfo->hw->fme; + } else if (type == PORT_ID) { + binfo->fiu = &binfo->hw->port[index]; + binfo->current_port_id = index; + } + + return 0; +} + +static int parse_feature_fme(struct build_feature_devs_info *binfo, + struct feature_header *start) +{ + struct ifpga_hw *hw = binfo->hw; + struct ifpga_fme_hw *fme = &hw->fme; + int ret; + + ret = build_info_create_dev(binfo, FME_ID, 0); + if (ret) + return ret; + + /* Update FME states */ + fme->state = IFPGA_FME_IMPLEMENTED; + fme->parent = hw; + spinlock_init(&fme->lock); + + return create_feature_instance(binfo, start, + &fme_features[FME_FEATURE_ID_HEADER]); +} + +static int parse_feature_port(struct build_feature_devs_info *binfo, + void __iomem *start) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + struct ifpga_hw *hw = binfo->hw; + struct ifpga_port_hw *port; + unsigned int port_id; + int ret; + + /* Get current port's id */ + port_hdr = (struct feature_port_header *)start; + capability.csr = readq(&port_hdr->capability); + port_id = capability.port_number; + + ret = build_info_create_dev(binfo, PORT_ID, port_id); + if (ret) + return ret; + + /*found a Port device*/ + port = &hw->port[port_id]; + port->port_id = binfo->current_port_id; + port->parent = hw; + port->state = IFPGA_PORT_ATTACHED; + spinlock_init(&port->lock); + + return create_feature_instance(binfo, start, + &port_features[PORT_FEATURE_ID_HEADER]); +} + +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 SAS 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); +} + +static int parse_feature_fiu(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + struct feature_fiu_header *fiu_hdr, fiu_header; + u8 __iomem *start = (u8 __iomem *)hdr; + int ret; + + header.csr = readq(hdr); + + switch (header.id) { + case FEATURE_FIU_ID_FME: + ret = parse_feature_fme(binfo, hdr); + //check_features_header(binfo->pdev, hdr, FPGA_DEVT_FME, 0); + binfo->pfme_hdr = hdr; + if (ret) + return ret; + break; + case FEATURE_FIU_ID_PORT: + ret = parse_feature_port(binfo, hdr); + //check_features_header(binfo->pdev, hdr, FPGA_DEVT_PORT, 0); + enable_port_uafu(binfo, hdr); + if (ret) + return ret; + + /* Check Port FIU's next_afu pointer to User AFU DFH */ + fiu_hdr = (struct feature_fiu_header *)(hdr + 1); + fiu_header.csr = readq(&fiu_hdr->csr); + + if (fiu_header.next_afu) { + start += fiu_header.next_afu; + ret = parse_feature_afus(binfo, + (struct feature_header *)start); + if (ret) + return ret; + } else { + dev_info(binfo, "No AFUs detected on Port\n"); + } + + break; + default: + dev_info(binfo, "FIU TYPE %d is not supported yet.\n", + header.id); + } + + return 0; +} + +static void parse_feature_irqs(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + finfo->vec_start = 0; + finfo->vec_cnt = 0; + + UNUSED(binfo); + + if (!strcmp(finfo->name, PORT_FEATURE_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; + } else { + dev_debug(binfo, "UAFU doesn't support interrupt\n"); + } + + } else if (!strcmp(finfo->name, PORT_FEATURE_ERR)) { + 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; + } else + dev_debug(&binfo, "Port error doesn't support interrupt\n"); + + } else if (!strcmp(finfo->name, FME_FEATURE_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; + } else + dev_debug(&binfo, "FME error doesn't support interrupt\n"); + } +} + +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; + } + + parse_feature_irqs(binfo, hdr, &fme_features[header.id]); + + //check_features_header(binfo->pdev, hdr, FPGA_DEVT_FME, header.id); + + return create_feature_instance(binfo, hdr, &fme_features[header.id]); +} + +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; + + 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]); + + //check_features_header(binfo->pdev, hdr, FPGA_DEVT_PORT, id); + + return create_feature_instance(binfo, hdr, &port_features[id]); +} + +static int parse_feature_private(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + + header.csr = readq(hdr); + + switch (binfo->current_type) { + case FME_ID: + return parse_feature_fme_private(binfo, hdr); + case PORT_ID: + return parse_feature_port_private(binfo, hdr); + default: + dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n", + header.id, binfo->current_type); + } + return 0; +} + +static int parse_feature(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + int ret = 0; + + header.csr = readq(hdr); + + switch (header.type) { + case FEATURE_TYPE_AFU: + ret = parse_feature_afus(binfo, hdr); + break; + case FEATURE_TYPE_PRIVATE: + ret = parse_feature_private(binfo, hdr); + break; + case FEATURE_TYPE_FIU: + ret = parse_feature_fiu(binfo, hdr); + break; + default: + dev_err(binfo, "Feature Type %x is not supported.\n", + hdr->type); + }; + + return ret; +} + +static int +parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start) +{ + struct feature_header *hdr, header; + u8 __iomem *end = (u8 __iomem *)binfo->ioend; + int ret = 0; + + for (; start < end; start += header.next_header_offset) { + if (end - start < (unsigned int)sizeof(*hdr)) { + dev_err(binfo, "The region is too small to contain a feature.\n"); + ret = -EINVAL; + break; + } + + hdr = (struct feature_header *)start; + ret = parse_feature(binfo, hdr); + if (ret) + return ret; + + header.csr = readq(hdr); + if (!header.next_header_offset) + break; + } + + return build_info_commit_dev(binfo); +} + +/* switch the memory mapping to BAR# @bar */ +static int parse_switch_to(struct build_feature_devs_info *binfo, int bar) +{ + struct opae_adapter_data_pci *pci_data = binfo->pci_data; + + if (!pci_data->region[bar].addr) + return -ENOMEM; + + binfo->ioaddr = pci_data->region[bar].addr; + binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len; + binfo->phys_addr = pci_data->region[bar].phys_addr; + binfo->current_bar = bar; + + return 0; +} + +static int parse_ports_from_fme(struct build_feature_devs_info *binfo) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_port port; + int i = 0, ret = 0; + + if (!binfo->pfme_hdr) { + dev_info(binfo, "VF is detected.\n"); + return ret; + } + + fme_hdr = binfo->pfme_hdr; + + do { + port.csr = readq(&fme_hdr->port[i]); + if (!port.port_implemented) + break; + + /* skip port which only could be accessed via VF */ + if (port.afu_access_control == FME_AFU_ACCESS_VF) + continue; + + ret = parse_switch_to(binfo, port.port_bar); + if (ret) + break; + + ret = parse_feature_list(binfo, + (u8 __iomem *)binfo->ioaddr + port.port_offset); + if (ret) + break; + } while (++i < MAX_FPGA_PORT_NUM); + + return ret; +} + +static struct build_feature_devs_info * +build_info_alloc_and_init(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + + binfo = zmalloc(sizeof(*binfo)); + if (!binfo) + return binfo; + + binfo->hw = hw; + binfo->pci_data = hw->pci_data; + + /* fpga feature list starts from BAR 0 */ + if (parse_switch_to(binfo, 0)) { + free(binfo); + return NULL; + } + + return binfo; +} + +static void build_info_free(struct build_feature_devs_info *binfo) +{ + free(binfo); +} + +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; + +#if 0 + dev_info(hw, "found a fpga device : %x:%x.%x\n", pci->addr.bus, + pci->addr.devid, pci->addr.function); +#endif + + 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]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr: 0x%lx\n", + feature->name, (unsigned long long)feature->addr, + (unsigned long long)feature->addr + feature->size - 1, + feature->phys_addr); + } + + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) { + port = &hw->port[i]; + + if (port->state != IFPGA_PORT_ATTACHED) + continue; + + dev_info(hw, "port device: %d\n", port->port_id); + + for (j = 0; j < PORT_FEATURE_ID_MAX; j++) { + feature = &port->sub_feature[j]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr:0x%lx\n", + feature->name, + (unsigned long long)feature->addr, + (unsigned long long)feature->addr + + feature->size - 1, + feature->phys_addr); + } + } +} + +int ifpga_bus_enumerate(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + int ret; + + binfo = build_info_alloc_and_init(hw); + if (!binfo) + return -ENOMEM; + + ret = parse_feature_list(binfo, binfo->ioaddr); + if (ret) + goto exit; + + ret = parse_ports_from_fme(binfo); + if (ret) + goto exit; + + ifpga_print_device_feature_list(hw); + +exit: + build_info_free(binfo); + return ret; +} + +int ifpga_bus_init(struct ifpga_hw *hw) +{ + int i; + + fme_hw_init(&hw->fme); + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) + port_hw_init(&hw->port[i]); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h new file mode 100644 index 0000000..0df7b2f --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h @@ -0,0 +1,38 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_ENUMERATE_H_ +#define _IFPGA_ENUMERATE_H_ + +int ifpga_bus_init(struct ifpga_hw *hw); +int ifpga_bus_enumerate(struct ifpga_hw *hw); + +#endif /* _IFPGA_ENUMERATE_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c new file mode 100644 index 0000000..6bc8b90 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -0,0 +1,340 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include <linux/vfio.h> +#include <sys/ioctl.h> + +#include "ifpga_feature_dev.h" + +/* + * Enable Port by clear the port soft reset bit, which is set by default. + * The AFU is unable to respond to any MMIO access while in reset. + * __fpga_port_enable function should only be used after __fpga_port_disable + * function. + */ +void __fpga_port_enable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + WARN_ON(!port->disable_count); + + if (--port->disable_count != 0) + return; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x0; + writeq(control.csr, &port_hdr->control); +} + +int __fpga_port_disable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + if (port->disable_count++ != 0) + return 0; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + /* Set port soft reset */ + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x1; + writeq(control.csr, &port_hdr->control); + + /* + * HW sets ack bit to 1 when all outstanding requests have been drained + * on this port and minimum soft reset pulse width has elapsed. + * Driver polls port_soft_reset_ack to determine if reset done by HW. + */ + control.port_sftrst_ack = 1; + + if (fpga_wait_register_field(port_sftrst_ack, control, + &port_hdr->control, RST_POLL_TIMEOUT, + RST_POLL_INVL)) { + dev_err(port, "timeout, fail to reset device\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) +{ + struct feature_port_header *port_hdr; + u64 guidl, guidh; + + port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU); + + spinlock_lock(&port->lock); + guidl = readq(&port_hdr->afu_header.guid.b[0]); + guidh = readq(&port_hdr->afu_header.guid.b[8]); + spinlock_unlock(&port->lock); + + printf("%s: guidl=0x%lx, guidh=0x%lx\n", __func__, guidl, guidh); + + memcpy(uuid->b, &guidl, sizeof(u64)); + memcpy(uuid->b + 8, &guidh, sizeof(u64)); + + return 0; +} + +/* Mask / Unmask Port Errors by the Error Mask register. */ +void port_err_mask(struct ifpga_port_hw *port, bool mask) +{ + struct feature_port_error *port_err; + struct feature_port_err_key err_mask; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + if (mask) + err_mask.csr = PORT_ERR_MASK; + else + err_mask.csr = 0; + + writeq(err_mask.csr, &port_err->error_mask); +} + +/* Clear All Port Errors. */ +int port_err_clear(struct ifpga_port_hw *port, u64 err) +{ + struct feature_port_header *port_hdr; + struct feature_port_error *port_err; + struct feature_port_err_key mask; + struct feature_port_first_err_key first; + struct feature_port_status status; + int ret = 0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + /* + * Clear All Port Errors + * + * - Check for AP6 State + * - Halt Port by keeping Port in reset + * - Set PORT Error mask to all 1 to mask errors + * - Clear all errors + * - Set Port mask to all 0 to enable errors + * - All errors start capturing new errors + * - Enable Port by pulling the port out of reset + */ + + /* If device is still in AP6 state, can not clear any error.*/ + status.csr = readq(&port_hdr->status); + if (status.power_state == PORT_POWER_STATE_AP6) { + dev_err(dev, "Could not clear errors, device in AP6 state.\n"); + return -EBUSY; + } + + /* Halt Port by keeping Port in reset */ + ret = __fpga_port_disable(port); + if (ret) + return ret; + + /* Mask all errors */ + port_err_mask(port, true); + + /* Clear errors if err input matches with current port errors.*/ + mask.csr = readq(&port_err->port_error); + + if (mask.csr == err) { + writeq(mask.csr, &port_err->port_error); + + first.csr = readq(&port_err->port_first_error); + writeq(first.csr, &port_err->port_first_error); + } else + ret = -EBUSY; + + /* Clear mask */ + port_err_mask(port, false); + + /* Enable the Port by clear the reset */ + __fpga_port_enable(port); + + return ret; +} + +int port_clear_error(struct ifpga_port_hw *port) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + u64 port_error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + port_error = error.csr = readq(&port_err->port_error); + + dev_info(port, "read port error: 0x%lx\n", port_error); + + return port_err_clear(port, port_error); +} + +void fme_hw_uinit(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return; + + 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); + } +} + +int fme_hw_init(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i, ret; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + 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; + } + } + } + + return 0; +} + +void port_hw_uinit(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i; + + 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); + } +} + +int port_hw_init(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i, 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; + } + } + + return 0; +} + +/* + * FIXME: we should get msix vec count during pci enumeration instead of + * below hardcode value. + */ +#define FPGA_MSIX_VEC_COUNT 20 +/* irq set buffer length for interrupt */ +#define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \ + sizeof(int) * FPGA_MSIX_VEC_COUNT) + +/* only support msix for now*/ +static int vfio_msix_enable_block(s32 vfio_dev_fd, unsigned int vec_start, + unsigned int count, s32 *fds) +{ + char irq_set_buf[MSIX_IRQ_SET_BUF_LEN]; + struct vfio_irq_set *irq_set; + int len, ret; + int *fd_ptr; + + len = sizeof(irq_set_buf); + + irq_set = (struct vfio_irq_set *)irq_set_buf; + irq_set->argsz = len; + irq_set->count = count; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; + irq_set->start = vec_start; + + fd_ptr = (int *)&irq_set->data; + memcpy(fd_ptr, fds, sizeof(int) * count); + + ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set); + if (ret) + printf("Error enabling MSI-X interrupts\n"); + + return ret; +} + +int fpga_msix_set_block(struct feature *feature, unsigned int start, + unsigned int count, s32 *fds) +{ + struct feature_irq_ctx *ctx = feature->ctx; + unsigned int i; + int ret; + + if (start >= feature->ctx_num || start + count > feature->ctx_num) + return -EINVAL; + + /* assume that each feature has continuous vector space in msix*/ + ret = vfio_msix_enable_block(feature->vfio_dev_fd, + ctx[start].idx, count, fds); + if (!ret) { + for (i = 0; i < count; i++) + ctx[i].eventfd = fds[i]; + } + + return ret; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h new file mode 100644 index 0000000..1dc6eff --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -0,0 +1,197 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_FEATURE_DEV_H_ +#define _IFPGA_FEATURE_DEV_H_ + +#include "ifpga_hw.h" + +static inline struct ifpga_port_hw * +get_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return NULL; + + return &hw->port[port_id]; +} + +#define ifpga_for_each_feature(hw, feature) \ + for ((feature) = (hw)->sub_feature; \ + (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++) + +static inline struct feature * +get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(fme, feature) { + if (feature->id == id) + return feature; + } + + return NULL; +} + +static inline struct feature * +get_port_feature_by_id(struct ifpga_port_hw *port, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(port, feature) { + 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; +} + +static inline void * +get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index) +{ + return port->sub_feature[index].addr; +} + +static inline bool +is_fme_feature_present(struct ifpga_fme_hw *fme, int index) +{ + return !!get_fme_feature_ioaddr_by_index(fme, index); +} + +static inline bool +is_port_feature_present(struct ifpga_port_hw *port, int index) +{ + return !!get_port_feature_ioaddr_by_index(port, index); +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid); + +int __fpga_port_disable(struct ifpga_port_hw *port); +void __fpga_port_enable(struct ifpga_port_hw *port); + +static inline int fpga_port_disable(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_disable(port); + spinlock_unlock(&port->lock); + return ret; +} + +static inline int fpga_port_enable(struct ifpga_port_hw *port) +{ + spinlock_lock(&port->lock); + __fpga_port_enable(port); + spinlock_unlock(&port->lock); + + return 0; +} + +static inline int __fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + ret = __fpga_port_disable(port); + if (ret) + return ret; + + __fpga_port_enable(port); + + return 0; +} + +static inline int fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_reset(port); + spinlock_unlock(&port->lock); + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +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); +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set); + +int fme_hw_init(struct ifpga_fme_hw *fme); +void fme_hw_uinit(struct ifpga_fme_hw *fme); +void port_hw_uinit(struct ifpga_port_hw *port); +int port_hw_init(struct ifpga_port_hw *port); +int port_clear_error(struct ifpga_port_hw *port); +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; + +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); + +/* This struct is used when parsing uafu irq_set */ +struct fpga_uafu_irq_set { + u32 start; + u32 count; + s32 *evtfds; +}; + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set); + +extern struct feature_ops port_hdr_ops; +extern struct feature_ops port_error_ops; +extern struct feature_ops port_stp_ops; +extern struct feature_ops port_umsg_ops; +extern struct feature_ops port_uint_ops; + +int afu_port_umsg_enable(struct ifpga_port_hw *port, bool enable); +int afu_port_umsg_set_mode(struct ifpga_port_hw *port, u32 mode); + +/* help functions for feature ops */ +int fpga_msix_set_block(struct feature *feature, unsigned int start, + unsigned int count, s32 *fds); +void port_check_reg(void __iomem *addr, const char *reg_name, u64 dflt); + + +#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 new file mode 100644 index 0000000..ecfddfc --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -0,0 +1,763 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +#define PWR_THRESHOLD_MAX 0x7F + +int fme_get_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +/* fme private feature head */ +static int fme_hdr_init(struct feature *feature) +{ + struct feature_fme_header *fme_hdr; + + fme_hdr = (struct feature_fme_header *)feature->addr; + + dev_info(NULL, "FME HDR Init.\n"); + dev_info(NULL, "FME cap %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + return 0; +} + +static void fme_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME HDR UInit.\n"); +} + +static int fme_hdr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&fme_hdr->header); + *revision = header.revision; + + return 0; +} + +static int fme_hdr_get_ports_num(struct ifpga_fme_hw *fme, u64 *ports_num) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *ports_num = fme_capability.num_ports; + + return 0; +} + +static int fme_hdr_get_cache_size(struct ifpga_fme_hw *fme, u64 *cache_size) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *cache_size = fme_capability.cache_size; + + return 0; +} + +static int fme_hdr_get_version(struct ifpga_fme_hw *fme, u64 *version) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *version = fme_capability.fabric_verid; + + return 0; +} + +static int fme_hdr_get_socket_id(struct ifpga_fme_hw *fme, u64 *socket_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *socket_id = fme_capability.socket_id; + + return 0; +} + +static int fme_hdr_get_bitstream_id(struct ifpga_fme_hw *fme, + u64 *bitstream_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_id = readq(&fme_hdr->bitstream_id); + + return 0; +} + +static int fme_hdr_get_bitstream_metadata(struct ifpga_fme_hw *fme, + u64 *bitstream_metadata) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_metadata = readq(&fme_hdr->bitstream_md); + + return 0; +} + +static int +fme_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_HDR_PROP_REVISION: + return fme_hdr_get_revision(fme, &prop->data); + case FME_HDR_PROP_PORTS_NUM: + return fme_hdr_get_ports_num(fme, &prop->data); + case FME_HDR_PROP_CACHE_SIZE: + return fme_hdr_get_cache_size(fme, &prop->data); + case FME_HDR_PROP_VERSION: + return fme_hdr_get_version(fme, &prop->data); + case FME_HDR_PROP_SOCKET_ID: + return fme_hdr_get_socket_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_ID: + return fme_hdr_get_bitstream_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_METADATA: + return fme_hdr_get_bitstream_metadata(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_hdr_ops = { + .init = fme_hdr_init, + .uinit = fme_hdr_uinit, + .get_prop = fme_hdr_get_prop, +}; + +/* thermal management */ +static int fme_thermal_get_threshold1(struct ifpga_fme_hw *fme, u64 *thres1) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold temp_threshold; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&fme_thermal->threshold); + *thres1 = temp_threshold.tmp_thshold1; + + return 0; +} + +static int fme_thermal_set_threshold1(struct ifpga_fme_hw *fme, u64 thres1) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&fme_thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres1 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres1 == 0) { + tmp_threshold.tmp_thshold1_enable = 0; + tmp_threshold.tmp_thshold1 = thres1; + } else { + tmp_threshold.tmp_thshold1_enable = 1; + tmp_threshold.tmp_thshold1 = thres1; + } + + writeq(tmp_threshold.csr, &fme_thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold2(struct ifpga_fme_hw *fme, u64 *thres2) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold temp_threshold; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&fme_thermal->threshold); + *thres2 = temp_threshold.tmp_thshold2; + + return 0; +} + +static int fme_thermal_set_threshold2(struct ifpga_fme_hw *fme, u64 thres2) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&fme_thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres2 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres2 == 0) { + tmp_threshold.tmp_thshold2_enable = 0; + tmp_threshold.tmp_thshold2 = thres2; + } else { + tmp_threshold.tmp_thshold2_enable = 1; + tmp_threshold.tmp_thshold2 = thres2; + } + + writeq(tmp_threshold.csr, &fme_thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold_trip(struct ifpga_fme_hw *fme, + u64 *thres_trip) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold temp_threshold; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&fme_thermal->threshold); + *thres_trip = temp_threshold.therm_trip_thshold; + + return 0; +} + +static int fme_thermal_get_threshold1_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold temp_threshold; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&fme_thermal->threshold); + *thres1_reached = temp_threshold.thshold1_status; + + return 0; +} + +static int fme_thermal_get_threshold2_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold temp_threshold; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&fme_thermal->threshold); + *thres1_reached = temp_threshold.thshold2_status; + + return 0; +} + +static int fme_thermal_get_threshold1_policy(struct ifpga_fme_hw *fme, + u64 *thres1_policy) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold temp_threshold; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&fme_thermal->threshold); + *thres1_policy = temp_threshold.thshold_policy; + + return 0; +} + +static int fme_thermal_set_threshold1_policy(struct ifpga_fme_hw *fme, + u64 thres1_policy) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold tmp_threshold; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&fme_thermal->threshold); + + if (thres1_policy == 0) + tmp_threshold.thshold_policy = 0; + else if (thres1_policy == 1) + tmp_threshold.thshold_policy = 1; + else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(tmp_threshold.csr, &fme_thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_temperature(struct ifpga_fme_hw *fme, u64 *temp) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_temp_rdsensor_fmt1 temp_rdsensor_fmt1; + + fme_thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_rdsensor_fmt1.csr = readq(&fme_thermal->rdsensor_fm1); + *temp = temp_rdsensor_fmt1.fpga_temp; + + return 0; +} + +static int fme_thermal_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_thermal *fme_thermal + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + struct feature_header header; + + header.csr = readq(&fme_thermal->header); + *revision = header.revision; + + return 0; +} + +#define FME_THERMAL_CAP_NO_TMP_THRESHOLD 0x1 + +static int fme_thermal_mgmt_init(struct feature *feature) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold_cap thermal_cap; + + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt Init.\n"); + + fme_thermal = (struct feature_fme_thermal *)feature->addr; + thermal_cap.csr = readq(&fme_thermal->threshold_cap); + + dev_info(NULL, "FME thermal cap %llx.\n", + (unsigned long long)fme_thermal->threshold_cap.csr); + + if (thermal_cap.tmp_thshold_disabled) + feature->cap |= FME_THERMAL_CAP_NO_TMP_THRESHOLD; + + return 0; +} + +static void fme_thermal_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt UInit.\n"); +} + +static int +fme_thermal_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_set_threshold1(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_set_threshold2(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_set_threshold1_policy(fme, prop->data); + } + + return -ENOENT; +} + +static int +fme_thermal_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD && + prop->prop_id != FME_THERMAL_PROP_TEMPERATURE && + prop->prop_id != FME_THERMAL_PROP_REVISION) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_get_threshold1(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_get_threshold2(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD_TRIP: + return fme_thermal_get_threshold_trip(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_REACHED: + return fme_thermal_get_threshold1_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2_REACHED: + return fme_thermal_get_threshold2_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_get_threshold1_policy(fme, &prop->data); + case FME_THERMAL_PROP_TEMPERATURE: + return fme_thermal_get_temperature(fme, &prop->data); + case FME_THERMAL_PROP_REVISION: + return fme_thermal_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_thermal_mgmt_ops = { + .init = fme_thermal_mgmt_init, + .uinit = fme_thermal_mgmt_uinit, + .get_prop = fme_thermal_get_prop, + .set_prop = fme_thermal_set_prop, +}; + + +static int fme_pwr_get_consumed(struct ifpga_fme_hw *fme, u64 *consumed) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *consumed = pm_status.pwr_consumed; + + return 0; +} + +static int fme_pwr_get_threshold1(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold1; + + return 0; +} + +static int fme_pwr_set_threshold1(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) + pm_ap_threshold.threshold1 = threshold; + else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold2(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold2; + + return 0; +} + +static int fme_pwr_set_threshold2(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) + pm_ap_threshold.threshold2 = threshold; + else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold1_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold1_status; + + return 0; +} + +static int fme_pwr_get_threshold2_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold2_status; + + return 0; +} + +static int fme_pwr_get_rtl(struct ifpga_fme_hw *fme, u64 *rtl) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *rtl = pm_status.fpga_latency_report; + + return 0; +} + +static int fme_pwr_get_xeon_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_xeon_limit xeon_limit; + + xeon_limit.csr = readq(&fme_power->xeon_limit); + + if (!xeon_limit.enable) + xeon_limit.pwr_limit = 0; + + *limit = xeon_limit.pwr_limit; + + return 0; + +} + +static int fme_pwr_get_fpga_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_fpga_limit fpga_limit; + + fpga_limit.csr = readq(&fme_power->fpga_limit); + + if (!fpga_limit.enable) + fpga_limit.pwr_limit = 0; + + *limit = fpga_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_header header; + + header.csr = readq(&fme_power->header); + *revision = header.revision; + + return 0; +} + +static int fme_power_mgmt_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt Init.\n"); + + return 0; +} + +static void fme_power_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt UInit.\n"); +} + +static int fme_power_mgmt_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_CONSUMED: + return fme_pwr_get_consumed(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_get_threshold1(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_get_threshold2(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1_STATUS: + return fme_pwr_get_threshold1_status(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2_STATUS: + return fme_pwr_get_threshold2_status(fme, &prop->data); + case FME_PWR_PROP_RTL: + return fme_pwr_get_rtl(fme, &prop->data); + case FME_PWR_PROP_XEON_LIMIT: + return fme_pwr_get_xeon_limit(fme, &prop->data); + case FME_PWR_PROP_FPGA_LIMIT: + return fme_pwr_get_fpga_limit(fme, &prop->data); + case FME_PWR_PROP_REVISION: + return fme_pwr_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_power_mgmt_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_set_threshold1(fme, prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_set_threshold2(fme, prop->data); + } + + return -ENOENT; +} + +struct 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, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c new file mode 100644 index 0000000..dbbd564 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c @@ -0,0 +1,328 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_dperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_clk_ctr clk; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + clk.afu_interf_clock = readq(&dperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_dperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_dperf *dperf; + struct feature_header header; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + header.csr = readq(&dperf->header); + *revision = header.revision; + + return 0; +} + +#define DPERF_TIMEOUT 30 + +static bool fabric_pobj_is_enabled(int port_id, + struct feature_fme_dperf *dperf) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + + ctl.csr = readq(&dperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum dperf_fab_events fab_event) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dfpmon_fab_ctr ctr; + struct feature_fme_dperf *dperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, dperf)) + goto exit; + + ctl.csr = readq(&dperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &dperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &dperf->fab_ctr, DPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&dperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_dperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, DPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, DPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(mmio_read, DPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, DPERF_FAB_MMIO_WR); + +static int fme_dperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_dperf *dperf; + int status; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + status = fabric_pobj_is_enabled(port_id, dperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_dperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dperf *dperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, dperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&dperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) + ctl.port_filter = FAB_DISABLE_FILTER; + else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_dperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_dperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 + +static int fme_global_dperf_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf Init.\n"); + + return 0; +} + +static void fme_global_dperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf UInit.\n"); +} + +static int fme_dperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_dperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_dperf_get_fab_port_pcie0_read(fme, sub, &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_dperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* MMIO_READ */ + return fme_dperf_get_fab_port_mmio_read(fme, sub, &prop->data); + case 0x5: /* MMIO_WRITE */ + return fme_dperf_get_fab_port_mmio_write(fme, sub, &prop->data); + case 0x6: /* ENABLE */ + return fme_dperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_dperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_dperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_dperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_dperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_dperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE - fab root only prop */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_dperf_set_fab_freeze(fme, prop->data); + case 0x6: /* ENABLE - fab both root and sub */ + return fme_dperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_dperf_ops = { + .init = fme_global_dperf_init, + .uinit = fme_global_dperf_uinit, + .get_prop = fme_global_dperf_get_prop, + .set_prop = fme_global_dperf_set_prop, + +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c new file mode 100644 index 0000000..a8a6a3c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c @@ -0,0 +1,430 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +static int fme_err_get_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + + fme_error0.csr = readq(&fme_err->fme_err); + *val = fme_error0.csr; + + return 0; +} + +static int fme_err_get_first_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_first_error fme_first_err; + + fme_first_err.csr = readq(&fme_err->fme_first_err); + *val = fme_first_err.err_reg_status; + + return 0; +} + +static int fme_err_get_next_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_next_error fme_next_err; + + fme_next_err.csr = readq(&fme_err->fme_next_err); + *val = fme_next_err.err_reg_status; + + return 0; +} + +static int fme_err_set_clear(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_ERROR0_MASK, &fme_err->fme_err_mask); + + fme_error0.csr = readq(&fme_err->fme_err); + if (val != fme_error0.csr) { + ret = -EBUSY; + goto exit; + } + + fme_first_err.csr = readq(&fme_err->fme_first_err); + fme_next_err.csr = readq(&fme_err->fme_next_err); + + writeq(fme_error0.csr & FME_ERROR0_MASK, &fme_err->fme_err); + writeq(fme_first_err.csr & FME_FIRST_ERROR_MASK, + &fme_err->fme_first_err); + writeq(fme_next_err.csr & FME_NEXT_ERROR_MASK, + &fme_err->fme_next_err); + +exit: + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_revision(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_header header; + + header.csr = readq(&fme_err->header); + *val = header.revision; + + return 0; +} + +static int fme_err_get_pcie0_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + + pcie0_err.csr = readq(&fme_err->pcie0_err); + *val = pcie0_err.csr; + + return 0; +} + +static int fme_err_set_pcie0_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE0_ERROR_MASK, &fme_err->pcie0_err_mask); + + pcie0_err.csr = readq(&fme_err->pcie0_err); + if (val != pcie0_err.csr) + ret = -EBUSY; + else + writeq(pcie0_err.csr & FME_PCIE0_ERROR_MASK, + &fme_err->pcie0_err); + + writeq(0UL, &fme_err->pcie0_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_pcie1_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + + pcie1_err.csr = readq(&fme_err->pcie1_err); + *val = pcie1_err.csr; + + return 0; +} + +static int fme_err_set_pcie1_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE1_ERROR_MASK, &fme_err->pcie1_err_mask); + + pcie1_err.csr = readq(&fme_err->pcie1_err); + if (val != pcie1_err.csr) + ret = -EBUSY; + else + writeq(pcie1_err.csr & FME_PCIE1_ERROR_MASK, + &fme_err->pcie1_err); + + writeq(0UL, &fme_err->pcie1_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_nonfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_nonfaterror ras_nonfaterr; + + ras_nonfaterr.csr = readq(&fme_err->ras_nonfaterr); + *val = ras_nonfaterr.csr; + + return 0; +} + +static int fme_err_get_catfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_catfaterror ras_catfaterr; + + ras_catfaterr.csr = readq(&fme_err->ras_catfaterr); + *val = ras_catfaterr.csr; + + return 0; +} + +static int fme_err_get_inject_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + *val = ras_error_inj.csr & FME_RAS_ERROR_INJ_MASK; + + return 0; +} + +static int fme_err_set_inject_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + spinlock_lock(&fme->lock); + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + + if (val <= FME_RAS_ERROR_INJ_MASK) { + ras_error_inj.csr = val; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(ras_error_inj.csr, &fme_err->ras_error_inj); + spinlock_unlock(&fme->lock); + + return 0; +} + +static void fme_error_enable(struct ifpga_fme_hw *fme) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + writeq(0UL, &fme_err->pcie0_err_mask); + writeq(0UL, &fme_err->pcie1_err_mask); + writeq(0UL, &fme_err->ras_nonfat_mask); + writeq(0UL, &fme_err->ras_catfat_mask); +} + +static int fme_global_error_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = feature->parent; + + fme_error_enable(fme); + + if (feature->ctx_num) + fme->capability |= FPGA_FME_CAP_ERR_IRQ; + + return 0; +} + +static void fme_global_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int fme_err_fme_err_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* ERRORS */ + return fme_err_get_errors(fme, &prop->data); + case 0x2: /* FIRST_ERROR */ + return fme_err_get_first_error(fme, &prop->data); + case 0x3: /* NEXT_ERROR */ + return fme_err_get_next_error(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x5: /* REVISION */ + return fme_err_get_revision(fme, &prop->data); + case 0x6: /* PCIE0_ERRORS */ + return fme_err_get_pcie0_errors(fme, &prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_get_pcie1_errors(fme, &prop->data); + case 0x8: /* NONFATAL_ERRORS */ + return fme_err_get_nonfatal_errors(fme, &prop->data); + case 0x9: /* CATFATAL_ERRORS */ + return fme_err_get_catfatal_errors(fme, &prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_get_inject_errors(fme, &prop->data); + case 0xb: /* REVISION*/ + return fme_err_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_get_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_err_fme_err_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x4: /* CLEAR */ + return fme_err_set_clear(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x6: /* PCIE0_ERRORS */ + return fme_err_set_pcie0_errors(fme, prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_set_pcie1_errors(fme, prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_set_inject_errors(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_set_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_set_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_global_err_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_fme_err_irq_set *err_irq_set = + (struct fpga_fme_err_irq_set *)irq_set; + struct ifpga_fme_hw *fme; + int ret; + + fme = (struct ifpga_fme_hw *)feature->parent; + + spinlock_lock(&fme->lock); + if (!(fme->capability & FPGA_FME_CAP_ERR_IRQ)) { + spinlock_unlock(&fme->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&fme->lock); + + return ret; +} + +struct feature_ops fme_global_err_ops = { + .init = fme_global_error_init, + .uinit = fme_global_error_uinit, + .get_prop = fme_global_error_get_prop, + .set_prop = fme_global_error_set_prop, + .set_irq = fme_global_err_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c new file mode 100644 index 0000000..33c3598 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c @@ -0,0 +1,742 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_iperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_clk_ctr clk; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + clk.afu_interf_clock = readq(&iperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_iperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_iperf *iperf; + struct feature_header header; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + header.csr = readq(&iperf->header); + *revision = header.revision; + + return 0; +} + +static int fme_iperf_get_cache_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + *freeze = (u64)ctl.freeze; + return 0; +} + +static int fme_iperf_set_cache_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->ch_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define IPERF_TIMEOUT 30 + +static u64 read_cache_counter(struct ifpga_fme_hw *fme, + u8 channel, enum iperf_cache_events event) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + struct feature_fme_ifpmon_ch_ctr ctr0, ctr1; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* set channel access type and cache event code. */ + ctl.csr = readq(&iperf->ch_ctl); + ctl.cci_chsel = channel; + ctl.cache_event = event; + writeq(ctl.csr, &iperf->ch_ctl); + + /* check the event type in the counter registers */ + ctr0.event_code = event; + + if (fpga_wait_register_field(event_code, ctr0, + &iperf->ch_ctr0, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched cache event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr0.csr = readq(&iperf->ch_ctr0); + ctr1.csr = readq(&iperf->ch_ctr1); + counter = ctr0.cache_counter + ctr1.cache_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define CACHE_SHOW(name, type, event) \ +static int fme_iperf_get_cache_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_cache_counter(fme, type, event); \ + return 0; \ +} + +CACHE_SHOW(read_hit, CACHE_CHANNEL_RD, IPERF_CACHE_RD_HIT); +CACHE_SHOW(read_miss, CACHE_CHANNEL_RD, IPERF_CACHE_RD_MISS); +CACHE_SHOW(write_hit, CACHE_CHANNEL_WR, IPERF_CACHE_WR_HIT); +CACHE_SHOW(write_miss, CACHE_CHANNEL_WR, IPERF_CACHE_WR_MISS); +CACHE_SHOW(hold_request, CACHE_CHANNEL_RD, IPERF_CACHE_HOLD_REQ); +CACHE_SHOW(tx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_TX_REQ_STALL); +CACHE_SHOW(rx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_RX_REQ_STALL); +CACHE_SHOW(rx_eviction, CACHE_CHANNEL_RD, IPERF_CACHE_EVICTIONS); +CACHE_SHOW(data_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_DATA_WR_PORT_CONTEN); +CACHE_SHOW(tag_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_TAG_WR_PORT_CONTEN); + +static int fme_iperf_get_vtd_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_vtd_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->vtd_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static u64 read_iommu_sip_counter(struct ifpga_fme_hw *fme, + enum iperf_vtd_sip_events event) +{ + struct feature_fme_ifpmon_vtd_sip_ctl sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr sip_ctr; + struct feature_fme_iperf *iperf; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + sip_ctl.csr = readq(&iperf->vtd_sip_ctl); + sip_ctl.vtd_evtcode = event; + writeq(sip_ctl.csr, &iperf->vtd_sip_ctl); + + sip_ctr.event_code = event; + + if (fpga_wait_register_field(event_code, sip_ctr, + &iperf->vtd_sip_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd SIP event type in counter registers\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + sip_ctr.csr = readq(&iperf->vtd_sip_ctr); + counter = sip_ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_SIP_SHOW(name, event) \ +static int fme_iperf_get_vtd_sip_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_iommu_sip_counter(fme, event); \ + return 0; \ +} + +VTD_SIP_SHOW(iotlb_4k_hit, IPERF_VTD_SIP_IOTLB_4K_HIT); +VTD_SIP_SHOW(iotlb_2m_hit, IPERF_VTD_SIP_IOTLB_2M_HIT); +VTD_SIP_SHOW(iotlb_1g_hit, IPERF_VTD_SIP_IOTLB_1G_HIT); +VTD_SIP_SHOW(slpwc_l3_hit, IPERF_VTD_SIP_SLPWC_L3_HIT); +VTD_SIP_SHOW(slpwc_l4_hit, IPERF_VTD_SIP_SLPWC_L4_HIT); +VTD_SIP_SHOW(rcc_hit, IPERF_VTD_SIP_RCC_HIT); +VTD_SIP_SHOW(iotlb_4k_miss, IPERF_VTD_SIP_IOTLB_4K_MISS); +VTD_SIP_SHOW(iotlb_2m_miss, IPERF_VTD_SIP_IOTLB_2M_MISS); +VTD_SIP_SHOW(iotlb_1g_miss, IPERF_VTD_SIP_IOTLB_1G_MISS); +VTD_SIP_SHOW(slpwc_l3_miss, IPERF_VTD_SIP_SLPWC_L3_MISS); +VTD_SIP_SHOW(slpwc_l4_miss, IPERF_VTD_SIP_SLPWC_L4_MISS); +VTD_SIP_SHOW(rcc_miss, IPERF_VTD_SIP_RCC_MISS); + +static u64 read_iommu_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_vtd_events base_event) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_ifpmon_vtd_ctr ctr; + struct feature_fme_iperf *iperf; + enum iperf_vtd_events event = base_event + port_id; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.vtd_evtcode = event; + writeq(ctl.csr, &iperf->vtd_ctl); + + ctr.event_code = event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->vtd_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->vtd_ctr); + counter = ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_PORT_SHOW(name, base_event) \ +static int fme_iperf_get_vtd_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_iommu_counter(fme, port_id, base_event); \ + return 0; \ +} + +VTD_PORT_SHOW(read_transaction, IPERF_VTD_AFU_MEM_RD_TRANS); +VTD_PORT_SHOW(write_transaction, IPERF_VTD_AFU_MEM_WR_TRANS); +VTD_PORT_SHOW(devtlb_read_hit, IPERF_VTD_AFU_DEVTLB_RD_HIT); +VTD_PORT_SHOW(devtlb_write_hit, IPERF_VTD_AFU_DEVTLB_WR_HIT); +VTD_PORT_SHOW(devtlb_4k_fill, IPERF_VTD_DEVTLB_4K_FILL); +VTD_PORT_SHOW(devtlb_2m_fill, IPERF_VTD_DEVTLB_2M_FILL); +VTD_PORT_SHOW(devtlb_1g_fill, IPERF_VTD_DEVTLB_1G_FILL); + +static bool fabric_pobj_is_enabled(u8 port_id, struct feature_fme_iperf *iperf) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + + ctl.csr = readq(&iperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_fab_events fab_event) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_ifpmon_fab_ctr ctr; + struct feature_fme_iperf *iperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, iperf)) + goto exit; + + ctl.csr = readq(&iperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &iperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->fab_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_iperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, IPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, IPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(pcie1_read, IPERF_FAB_PCIE1_RD); +FAB_PORT_SHOW(pcie1_write, IPERF_FAB_PCIE1_WR); +FAB_PORT_SHOW(upi_read, IPERF_FAB_UPI_RD); +FAB_PORT_SHOW(upi_write, IPERF_FAB_UPI_WR); +FAB_PORT_SHOW(mmio_read, IPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, IPERF_FAB_MMIO_WR); + +static int fme_iperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_iperf *iperf; + int status; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + status = fabric_pobj_is_enabled(port_id, iperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_iperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, iperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&iperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) + ctl.port_filter = FAB_DISABLE_FILTER; + else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_iperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 +#define FME_IPERF_CAP_IOMMU 0x1 + +static int fme_global_iperf_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme; + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + + dev_info(NULL, "FME global_iperf Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + /* check if iommu is not supported on this device. */ + fme_capability.csr = readq(&fme_hdr->capability); + dev_info(NULL, "FME HEAD fme_capability %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + if (fme_capability.iommu_support) + feature->cap |= FME_IPERF_CAP_IOMMU; + + return 0; +} + +static void fme_global_iperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_iperf UInit.\n"); +} + +static int fme_iperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_iperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_iperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_cache_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_cache_freeze(fme, &prop->data); + case 0x2: /* READ_HIT */ + return fme_iperf_get_cache_read_hit(fme, &prop->data); + case 0x3: /* READ_MISS */ + return fme_iperf_get_cache_read_miss(fme, &prop->data); + case 0x4: /* WRITE_HIT */ + return fme_iperf_get_cache_write_hit(fme, &prop->data); + case 0x5: /* WRITE_MISS */ + return fme_iperf_get_cache_write_miss(fme, &prop->data); + case 0x6: /* HOLD_REQUEST */ + return fme_iperf_get_cache_hold_request(fme, &prop->data); + case 0x7: /* TX_REQ_STALL */ + return fme_iperf_get_cache_tx_req_stall(fme, &prop->data); + case 0x8: /* RX_REQ_STALL */ + return fme_iperf_get_cache_rx_req_stall(fme, &prop->data); + case 0x9: /* RX_EVICTION */ + return fme_iperf_get_cache_rx_eviction(fme, &prop->data); + case 0xa: /* DATA_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_data_write_port_contention(fme, + &prop->data); + case 0xb: /* TAG_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_tag_write_port_contention(fme, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_vtd_freeze(fme, &prop->data); + case 0x2: /* IOTLB_4K_HIT */ + return fme_iperf_get_vtd_sip_iotlb_4k_hit(fme, &prop->data); + case 0x3: /* IOTLB_2M_HIT */ + return fme_iperf_get_vtd_sip_iotlb_2m_hit(fme, &prop->data); + case 0x4: /* IOTLB_1G_HIT */ + return fme_iperf_get_vtd_sip_iotlb_1g_hit(fme, &prop->data); + case 0x5: /* SLPWC_L3_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l3_hit(fme, &prop->data); + case 0x6: /* SLPWC_L4_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l4_hit(fme, &prop->data); + case 0x7: /* RCC_HIT */ + return fme_iperf_get_vtd_sip_rcc_hit(fme, &prop->data); + case 0x8: /* IOTLB_4K_MISS */ + return fme_iperf_get_vtd_sip_iotlb_4k_miss(fme, &prop->data); + case 0x9: /* IOTLB_2M_MISS */ + return fme_iperf_get_vtd_sip_iotlb_2m_miss(fme, &prop->data); + case 0xa: /* IOTLB_1G_MISS */ + return fme_iperf_get_vtd_sip_iotlb_1g_miss(fme, &prop->data); + case 0xb: /* SLPWC_L3_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l3_miss(fme, &prop->data); + case 0xc: /* SLPWC_L4_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l4_miss(fme, &prop->data); + case 0xd: /* RCC_MISS */ + return fme_iperf_get_vtd_sip_rcc_miss(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_sub_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub > PERF_MAX_PORT_NUM) + return -ENOENT; + + switch (id) { + case 0xe: /* READ_TRANSACTION */ + return fme_iperf_get_vtd_port_read_transaction(fme, sub, + &prop->data); + case 0xf: /* WRITE_TRANSACTION */ + return fme_iperf_get_vtd_port_write_transaction(fme, sub, + &prop->data); + case 0x10: /* DEVTLB_READ_HIT */ + return fme_iperf_get_vtd_port_devtlb_read_hit(fme, sub, + &prop->data); + case 0x11: /* DEVTLB_WRITE_HIT */ + return fme_iperf_get_vtd_port_devtlb_write_hit(fme, sub, + &prop->data); + case 0x12: /* DEVTLB_4K_FILL */ + return fme_iperf_get_vtd_port_devtlb_4k_fill(fme, sub, + &prop->data); + case 0x13: /* DEVTLB_2M_FILL */ + return fme_iperf_get_vtd_port_devtlb_2m_fill(fme, sub, + &prop->data); + case 0x14: /* DEVTLB_1G_FILL */ + return fme_iperf_get_vtd_port_devtlb_1g_fill(fme, sub, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED) + return fme_iperf_vtd_root_get_prop(feature, prop); + + return fme_iperf_vtd_sub_get_prop(feature, prop); +} + +static int fme_iperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + /* Other properties are present for both top and sub levels */ + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_iperf_get_fab_port_pcie0_read(fme, sub, + &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_iperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* PCIE1_READ */ + return fme_iperf_get_fab_port_pcie1_read(fme, sub, + &prop->data); + case 0x5: /* PCIE1_WRITE */ + return fme_iperf_get_fab_port_pcie1_write(fme, sub, + &prop->data); + case 0x6: /* UPI_READ */ + return fme_iperf_get_fab_port_upi_read(fme, sub, + &prop->data); + case 0x7: /* UPI_WRITE */ + return fme_iperf_get_fab_port_upi_write(fme, sub, + &prop->data); + case 0x8: /* MMIO_READ */ + return fme_iperf_get_fab_port_mmio_read(fme, sub, + &prop->data); + case 0x9: /* MMIO_WRITE */ + return fme_iperf_get_fab_port_mmio_write(fme, sub, + &prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_get_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_get_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_iperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_iperf_cache_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_cache_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_vtd_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_vtd_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_set_fab_freeze(fme, prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_set_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_set_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_iperf_ops = { + .init = fme_global_iperf_init, + .uinit = fme_global_iperf_uinit, + .get_prop = fme_global_iperf_get_prop, + .set_prop = fme_global_iperf_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c new file mode 100644 index 0000000..fec6013 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c @@ -0,0 +1,395 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +//#if defined(RTE_ARCH_X86) && defined(RTE_MACHINE_CPUFLAG_AVX512F) +#if 1 +static inline void copy512(const void *src, void *dst) +{ + asm volatile("vmovdqu64 (%0), %%zmm0;" + "vmovntdq %%zmm0, (%1);" + : + : "r"(src), "r"(dst)); +} +#else +static inline void copy512(void *src, void *dst) +{ + WARN_ON(1); +} +#endif + +static u64 +pr_err_handle(struct feature_fme_pr *fme_pr) +{ + struct feature_fme_pr_status fme_pr_status; + unsigned long err_code; + u64 fme_pr_error; +#if 0 + int i = 0; +#endif + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + if (!fme_pr_status.pr_status) + return 0; + + err_code = readq(&fme_pr->ccip_fme_pr_err); + fme_pr_error = err_code; +#if 0 + for_each_set_bit(i, &err_code, PR_MAX_ERR_NUM) + dev_info(NULL, "%s\n", pr_err_msg[i]); +#endif + writeq(fme_pr_error, &fme_pr->ccip_fme_pr_err); + return fme_pr_error; +} + +static int fme_pr_write_init(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + if (info->flags != FPGA_MGR_PARTIAL_RECONFIG) + return -EINVAL; + + dev_info(fme_dev, "resetting PR before initiated PR\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + fme_pr_ctl.pr_reset_ack = 1; + + if (fpga_wait_register_field(pr_reset_ack, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 0; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "waiting for PR resource in HW to be initialized and ready\n"); + + fme_pr_status.pr_host_status = PR_HOST_STATUS_IDLE; + + if (fpga_wait_register_field(pr_host_status, fme_pr_status, + &fme_pr->ccip_fme_pr_status, PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "check if have any previous PR error\n"); + pr_err_handle(fme_pr); + return 0; +} + +static int fme_pr_write(struct ifpga_fme_hw *fme_dev, + int port_id, const char *buf, size_t count, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + struct feature_fme_pr_data fme_pr_data; + int delay, pr_credit; + int ret = 0; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + dev_info(fme_dev, "set PR port ID and start request\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_regionid = port_id; + fme_pr_ctl.pr_start_req = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "pushing data from bitstream to HW\n"); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + + while (count > 0) { + delay = 0; + while (pr_credit <= 1) { + if (delay++ > PR_WAIT_TIMEOUT) { + dev_err(fme_dev, "maximum try\n"); + + info->pr_err = pr_err_handle(fme_pr); + return info->pr_err ? -EIO : -ETIMEDOUT; + } + udelay(1); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + }; + + if (count >= fme_dev->pr_bandwidth) { + switch (fme_dev->pr_bandwidth) { + case 4: + fme_pr_data.rsvd = 0; + fme_pr_data.pr_data_raw = *((const u32 *)buf); + writeq(fme_pr_data.csr, + &fme_pr->ccip_fme_pr_data); + break; + case 64: + copy512(buf, &fme_pr->fme_pr_data1); + break; + default: + ret = -EFAULT; + goto done; + } + + buf += fme_dev->pr_bandwidth; + count -= fme_dev->pr_bandwidth; + pr_credit--; + } else { + WARN_ON(1); + return -EINVAL; + goto done; + } + } + +done: + return ret; +} + +static int fme_pr_write_complete(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_push_complete = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "green bitstream push complete\n"); + dev_info(fme_dev, "waiting for HW to release PR resource\n"); + + fme_pr_ctl.pr_start_req = 0; + + if (fpga_wait_register_field(pr_start_req, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, PR_WAIT_TIMEOUT, 1)) { + printf("maximum try.\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "PR operation complete, checking status\n"); + info->pr_err = pr_err_handle(fme_pr); + if (info->pr_err) + return -EIO; + + dev_info(fme_dev, "PR done successfully\n"); + return 0; +} + +static int fpga_pr_buf_load(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info, const char *buf, + size_t count) +{ + int ret; + + info->state = FPGA_PR_STATE_WRITE_INIT; + ret = fme_pr_write_init(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error preparing FPGA for writing\n"); + info->state = FPGA_PR_STATE_WRITE_INIT_ERR; + return ret; + } + + /* + * Write the FPGA image to the FPGA. + */ + info->state = FPGA_PR_STATE_WRITE; + ret = fme_pr_write(fme_dev, info->port_id, buf, count, info); + if (ret) { + dev_err(fme_dev, "Error while writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_ERR; + return ret; + } + + /* + * After all the FPGA image has been written, do the device specific + * steps to finish and set the FPGA into operating mode. + */ + info->state = FPGA_PR_STATE_WRITE_COMPLETE; + ret = fme_pr_write_complete(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error after writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_COMPLETE_ERR; + return ret; + } + info->state = FPGA_PR_STATE_DONE; + + return 0; +} + +static int fme_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + struct ifpga_fme_hw *fme = &hw->fme; + struct fpga_pr_info info; + struct ifpga_port_hw *port; + int ret = 0; + + if (!buffer || size == 0) + return -EINVAL; + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + /* + * Padding extra zeros to align PR buffer with PR bandwidth, HW will + * ignore these zeros automatically. + */ + size = ALIGN(size, fme->pr_bandwidth); + + /* get fme header region */ + fme_hdr = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_HEADER); + if (!fme_hdr) + return -EINVAL; + + /* check port id */ + fme_capability.csr = readq(&fme_hdr->capability); + if (port_id >= fme_capability.num_ports) { + dev_err(fme, "port number more than maximum\n"); + return -EINVAL; + } + + memset(&info, 0, sizeof(struct fpga_pr_info)); + info.flags = FPGA_MGR_PARTIAL_RECONFIG; + info.port_id = port_id; + + spinlock_lock(&fme->lock); + + /* get port device by port_id */ + port = &hw->port[port_id]; + + /* Disable Port before PR */ + fpga_port_disable(port); + + ret = fpga_pr_buf_load(fme, &info, (void *)buffer, size); + + *status = info.pr_err; + + /* Re-enable Port after PR finished */ + fpga_port_enable(port); + spinlock_unlock(&fme->lock); + + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, u64 *status) +{ + struct bts_header *bts_hdr; + void *buf; + struct ifpga_port_hw *port; + int ret; + + if (!buffer || size == 0) { + dev_err(hw, "invalid parameter\n"); + return -EINVAL; + } + + bts_hdr = (struct bts_header *)buffer; + + if (is_valid_bts(bts_hdr)) { + dev_info(hw, "this is a valid bitsteam..\n"); + size -= (sizeof(struct bts_header) + + bts_hdr->metadata_len); + buf = (u8 *)buffer + sizeof(struct bts_header) + + bts_hdr->metadata_len; + } else { + return -EINVAL; + } + + /* clean port error before do PR */ + port = &hw->port[port_id]; + ret = port_clear_error(port); + if (ret) { + dev_err(hw, "port cannot clear error\n"); + return -EINVAL; + } + + return fme_pr(hw, port_id, buf, size, status); +} + +static int fme_pr_mgmt_init(struct feature *feature) +{ + struct feature_fme_pr *fme_pr; + struct feature_header fme_pr_header; + struct ifpga_fme_hw *fme; + + dev_info(NULL, "FME PR MGMT Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + + fme_pr = (struct feature_fme_pr *)feature->addr; + + fme_pr_header.csr = readq(&fme_pr->header); + if (fme_pr_header.revision == 2) { + dev_info(NULL, "using 512-bit PR\n"); + fme->pr_bandwidth = 64; + } else { + dev_info(NULL, "using 32-bit PR\n"); + fme->pr_bandwidth = 4; + } + + return 0; +} + +static void fme_pr_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME PR MGMT UInit.\n"); +} + +struct 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 new file mode 100644 index 0000000..4b6eb5d --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -0,0 +1,154 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_HW_H_ +#define _IFPGA_HW_H_ + +#include "ifpga_defines.h" +#include "opae_ifpga_hw_api.h" + +enum ifpga_feature_state { + IFPGA_FEATURE_UNUSED = 0, + IFPGA_FEATURE_ATTACHED, +}; + +struct feature_irq_ctx { + int eventfd; + int idx; +}; + +struct feature { + enum ifpga_feature_state state; + const char *name; + u64 id; + u8 *addr; + uint64_t phys_addr; + u32 size; + int revision; + u64 cap; + int vfio_dev_fd; + struct feature_irq_ctx *ctx; + unsigned int ctx_num; + + void *parent; /* to parent hw data structure */ + + struct feature_ops *ops;/* callback to this private feature */ +}; + +struct feature_ops { + int (*init)(struct feature *feature); + void (*uinit)(struct feature *feature); + int (*test)(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); +}; + +enum ifpga_fme_state { + IFPGA_FME_UNUSED = 0, + IFPGA_FME_IMPLEMENTED, +}; + +struct ifpga_fme_hw { + enum ifpga_fme_state state; + + struct feature sub_feature[FME_FEATURE_ID_MAX]; + spinlock_t lock; /* protect hardware access */ + + void *parent; /* pointer to ifpga_hw */ + + /* provied by HEADER feature */ + u32 port_num; + struct uuid bitstream_id; + u64 bitstream_md; + size_t pr_bandwidth; + u32 socket_id; + u32 fabric_version_id; + u32 cache_size; + + u32 capability; +}; + +enum ifpga_port_state { + IFPGA_PORT_UNUSED = 0, + IFPGA_PORT_ATTACHED, + IFPGA_PORT_DETACHED, +}; + +struct ifpga_port_hw { + enum ifpga_port_state state; + + struct feature sub_feature[PORT_FEATURE_ID_MAX]; + spinlock_t lock; /* protect access to hw */ + + void *parent; /* pointer to ifpga_hw */ + + int port_id; /* provied by HEADER feature */ + struct uuid afu_id; /* provied by User AFU feature */ + + unsigned int disable_count; + + u32 capability; + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ + u8 *stp_addr; + u32 stp_size; +}; + +#define AFU_MAX_REGION 1 + +struct ifpga_afu_info { + struct opae_reg_region region[AFU_MAX_REGION]; + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct ifpga_hw { + struct opae_adapter *adapter; + struct opae_adapter_data_pci *pci_data; + + struct ifpga_fme_hw fme; + struct ifpga_port_hw port[MAX_FPGA_PORT_NUM]; +}; + +static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) +{ + return hw->fme.state != IFPGA_FME_UNUSED; +} + +static inline bool is_valid_port_id(struct ifpga_hw *hw, u32 port_id) +{ + if (port_id >= MAX_FPGA_PORT_NUM || + (hw->port[port_id].state != IFPGA_PORT_ATTACHED)) + return false; + return true; +} +#endif /* _IFPGA_HW_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c new file mode 100644 index 0000000..d8cdd22 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c @@ -0,0 +1,735 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + + +void port_check_reg(void __iomem *addr, + const char *reg_name, u64 dflt) +{ + u64 value = readq(addr); + + UNUSED(reg_name); + + if (value != dflt) + dev_debug(NULL, "%s: incorrect value 0x%llx vs defautl 0x%llx\n", + reg_name, (unsigned long long)value, + (unsigned long long)dflt); +} + +static int port_get_revision(struct ifpga_port_hw *port, u64 *revision) +{ + struct feature_port_header *port_hdr + = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&port_hdr->header); + + *revision = header.revision; + + return 0; +} + +static int port_get_portidx(struct ifpga_port_hw *port, u64 *idx) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + capability.csr = readq(&port_hdr->capability); + *idx = capability.port_number; + + return 0; +} + +static int port_get_latency_tolerance(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + control.csr = readq(&port_hdr->control); + *val = control.latency_tolerance; + + return 0; +} + +static int port_get_ap1_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap1_event; + + return 0; +} + +static int port_set_ap1_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap1_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_ap2_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap2_event; + + return 0; +} + +static int port_set_ap2_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap2_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_power_state(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.power_state; + + return 0; +} + +static int port_get_userclk_freqcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts1); + spinlock_unlock(&port->lock); + + return 0; +} + +static struct feature_port_header hdr_dflt = { + .port_mailbox = 0x0000000000000000, + .scratchpad = 0x0000000000000000, + .capability = { + .csr = 0x0000000100010000, + }, + .control = { + /* Port Reset Bit is cleared in PCIe driver */ + .csr = 0x0000000000000004, + }, + .status = { + .csr = 0x0000000000000000, + }, + .rsvd2 = 0x0000000000000000, + .user_clk_freq_cmd0 = 0x0000000000000000, + .user_clk_freq_cmd1 = 0x0000000000000000, + .user_clk_freq_sts0 = 0x0000000000000000, + .user_clk_freq_sts1 = 0x0000000000000000, +}; + +static int port_hdr_test(struct feature *feature) +{ + struct feature_port_header *port_hdr = + (struct feature_port_header *)feature->addr; + + /* Check if default value of hardware registers matches with spec */ + port_check_reg(&port_hdr->port_mailbox, + "hdr:port_mailbox", hdr_dflt.port_mailbox); + port_check_reg(&port_hdr->scratchpad, + "hdr:scratchpad", hdr_dflt.scratchpad); + port_check_reg(&port_hdr->capability, + "hdr:capability", hdr_dflt.capability.csr); + port_check_reg(&port_hdr->control, + "hdr:control", hdr_dflt.control.csr); + port_check_reg(&port_hdr->status, + "hdr:status", hdr_dflt.status.csr); + port_check_reg(&port_hdr->rsvd2, + "hdr:rsvd2", hdr_dflt.rsvd2); + port_check_reg(&port_hdr->user_clk_freq_cmd0, + "hdr:user_clk_cmd0", hdr_dflt.user_clk_freq_cmd0); + port_check_reg(&port_hdr->user_clk_freq_cmd1, + "hdr:user_clk_cmd1", hdr_dflt.user_clk_freq_cmd1); + port_check_reg(&port_hdr->user_clk_freq_sts0, + "hdr:user_clk_sts0", hdr_dflt.user_clk_freq_sts0); + port_check_reg(&port_hdr->user_clk_freq_sts1, + "hdr:user_clk_sts1", hdr_dflt.user_clk_freq_sts1); + + dev_debug(NULL, "%s finished\n", __func__); + + return 0; +} + +static int port_hdr_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port hdr Init.\n"); + + fpga_port_reset(port); + + return 0; +} + +static void port_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port hdr uinit.\n"); +} + +static int port_hdr_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_REVISION: + return port_get_revision(port, &prop->data); + case PORT_HDR_PROP_PORTIDX: + return port_get_portidx(port, &prop->data); + case PORT_HDR_PROP_LATENCY_TOLERANCE: + return port_get_latency_tolerance(port, &prop->data); + case PORT_HDR_PROP_AP1_EVENT: + return port_get_ap1_event(port, &prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_get_ap2_event(port, &prop->data); + case PORT_HDR_PROP_POWER_STATE: + return port_get_power_state(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_get_userclk_freqcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_get_userclk_freqcntrcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQSTS: + return port_get_userclk_freqsts(port, &prop->data); + case PORT_HDR_PROP_USERCLK_CNTRSTS: + return port_get_userclk_freqcntrsts(port, &prop->data); + } + + return -ENOENT; +} + +static int port_hdr_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_AP1_EVENT: + return port_set_ap1_event(port, prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_set_ap2_event(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_set_userclk_freqcmd(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_set_userclk_freqcntrcmd(port, prop->data); + } + + return -ENOENT; +} + +struct feature_ops port_hdr_ops = { + .init = port_hdr_init, + .uinit = port_hdr_uinit, + .test = port_hdr_test, + .get_prop = port_hdr_get_prop, + .set_prop = port_hdr_set_prop, +}; + +static struct feature_port_umsg umsg_dflt = { + .capability = { + .csr = 0x0000000000000008, + }, + .baseaddr = { + .csr = 0x0000000000000000, + }, + .mode = { + .csr = 0x0000000000000000, + }, +}; + +static int port_umsg_test(struct feature *feature) +{ + struct feature_port_umsg *port_umsg = + (struct feature_port_umsg *)feature->addr; + + port_check_reg(&port_umsg->capability, + "umsg:capaiblity", umsg_dflt.capability.csr); + port_check_reg(&port_umsg->baseaddr, + "umsg:baseaddr", umsg_dflt.baseaddr.csr); + port_check_reg(&port_umsg->mode, + "umsg:mode", umsg_dflt.mode.csr); + + dev_debug(NULL, "%s finished\n", __func__); + return 0; +} + +static u8 port_umsg_get_num(struct ifpga_port_hw *port) +{ + struct feature_port_umsg *port_umsg; + struct feature_port_umsg_cap capability; + + port_umsg = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_UMSG); + + capability.csr = readq(&port_umsg->capability); + + return capability.umsg_allocated; +} + +static u64 port_umsg_get_addr(struct ifpga_port_hw *port) +{ + struct feature_port_umsg *port_umsg; + struct feature_port_umsg_baseaddr baseaddr; + + port_umsg = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_UMSG); + + baseaddr.csr = readq(&port_umsg->baseaddr); + + return baseaddr.base_addr; +} + +static int port_umsg_enable(struct ifpga_port_hw *port, bool enable) +{ + struct feature_port_umsg *port_umsg; + struct feature_port_umsg_cap capability; + + port_umsg = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_UMSG); + + capability.csr = readq(&port_umsg->capability); + + /* Return directly if UMSG is already enabled/disabled */ + if ((enable && capability.umsg_enable) || + !(enable || capability.umsg_enable)) + return 0; + + capability.umsg_enable = enable; + writeq(capability.csr, &port_umsg->capability); + + /* + * Each time umsg engine enabled/disabled, driver polls the + * init_complete bit for confirmation. + */ + capability.umsg_init_complete = !!enable; + + if (fpga_wait_register_field(umsg_init_complete, capability, + &port_umsg->capability, + UMSG_EN_POLL_TIMEOUT, UMSG_EN_POLL_INVL)) { + dev_err(dev, "timeout, fail to %s umsg\n", + enable ? "enable" : "disable"); + return -ETIMEDOUT; + } + + return 0; +} + +static bool port_umsg_is_enabled(struct ifpga_port_hw *port) +{ + struct feature_port_umsg *port_umsg; + struct feature_port_umsg_cap capability; + + port_umsg = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_UMSG); + + capability.csr = readq(&port_umsg->capability); + + return capability.umsg_enable; +} + +static void port_umsg_set_mode(struct ifpga_port_hw *port, u32 mode) +{ + struct feature_port_umsg *port_umsg; + struct feature_port_umsg_mode umode; + + port_umsg = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_UMSG); + + umode.csr = readq(&port_umsg->mode); + umode.umsg_hint_enable = mode; + writeq(umode.csr, &port_umsg->mode); +} + +static void port_umsg_set_addr(struct ifpga_port_hw *port, u64 iova) +{ + struct feature_port_umsg *port_umsg; + struct feature_port_umsg_baseaddr baseaddr; + + port_umsg = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_UMSG); + + baseaddr.csr = readq(&port_umsg->baseaddr); + baseaddr.base_addr = iova; + writeq(baseaddr.csr, &port_umsg->baseaddr); +} + +int afu_port_umsg_enable(struct ifpga_port_hw *port, bool enable) +{ + if (enable && port_umsg_get_addr(port)) + return -EIO; + if (port_umsg_enable(port, enable)) + return -ENODEV; + + return 0; +} + +int afu_port_umsg_set_mode(struct ifpga_port_hw *port, u32 mode) +{ + u8 num_umsgs = port_umsg_get_num(port); + + if (mode >> num_umsgs) { + dev_err(port, "invaild UMsg config hint_bitmap\n"); + return -EINVAL; + } + + port_umsg_set_mode(port, mode); + + return 0; +} + +static int __maybe_unused afu_port_umsg_set_addr(struct ifpga_port_hw *port, + u64 iova) +{ + u8 num_umsgs = port_umsg_get_num(port); + u64 size = num_umsgs * PAGE_SIZE; + + /* Make sure base addr is configured only when umsg is disabled */ + if (port_umsg_is_enabled(port)) { + dev_err(port, "umsg is still enabled\n"); + return -EIO; + } + + if (iova) { + /* Check input, only accept page-aligned region for umsg */ + if (!PAGE_ALIGNED(iova)) + return -EINVAL; + + /* Check overflow */ + if (iova + size < iova) + return -EINVAL; + + port_umsg_set_addr(port, iova); + } else { + /* Read current iova from hardware */ + iova = port_umsg_get_addr(port); + if (!iova) + return 0; + + /* Check overflow */ + if ((iova + size < iova)) + return -EINVAL; + + port_umsg_set_addr(port, 0); + } + + return 0; +} + +static int port_umsg_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port umsg Init.\n"); + + return 0; +} + +static void port_umsg_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port umsg uinit.\n"); +} + +struct feature_ops port_umsg_ops = { + .init = port_umsg_init, + .uinit = port_umsg_uinit, + .test = port_umsg_test, +}; + +static struct feature_port_stp stp_dflt = { + .stp_status = { + .csr = 0x0000000000000000, + }, +}; + +static int port_stp_test(struct feature *feature) +{ + struct feature_port_stp *port_stp = + (struct feature_port_stp *)feature->addr; + + port_check_reg(&port_stp->stp_status, + "stp:stp_csr", stp_dflt.stp_status.csr); + + dev_debug(NULL, "%s finished\n", __func__); + return 0; +} + +static int port_stp_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port stp Init.\n"); + + spinlock_lock(&port->lock); + port->stp_addr = feature->addr; + port->stp_size = feature->size; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_stp_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port stp uinit.\n"); +} + +struct feature_ops port_stp_ops = { + .init = port_stp_init, + .uinit = port_stp_uinit, + .test = port_stp_test, +}; + +static int port_uint_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "PORT UINT Init.\n"); + + spinlock_lock(&port->lock); + if (feature->ctx_num) { + port->capability |= FPGA_PORT_CAP_UAFU_IRQ; + port->num_uafu_irqs = feature->ctx_num; + } + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_uint_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT UINT UInit.\n"); +} + +static int port_uint_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_uafu_irq_set *uafu_irq_set = irq_set; + struct ifpga_port_hw *port = feature->parent; + int ret; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_UAFU_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, uafu_irq_set->start, + uafu_irq_set->count, uafu_irq_set->evtfds); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_uint_ops = { + .init = port_uint_init, + .uinit = port_uint_uinit, + .set_irq = port_uint_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c new file mode 100644 index 0000000..1a55155 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c @@ -0,0 +1,236 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +static int port_err_get_revision(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_header header; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + header.csr = readq(&port_err->header); + *val = header.revision; + + return 0; +} + +static int port_err_get_errors(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + *val = error.csr; + + return 0; +} + +static int port_err_get_first_error(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_first_err_key first_error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + first_error.csr = readq(&port_err->port_first_error); + *val = first_error.csr; + + return 0; +} + +static int port_err_get_first_malformed_req_lsb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req0 malreq0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq0.header_lsb = readq(&port_err->malreq0); + *val = malreq0.header_lsb; + + return 0; +} + +static int port_err_get_first_malformed_req_msb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req1 malreq1; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq1.header_msb = readq(&port_err->malreq1); + *val = malreq1.header_msb; + + return 0; +} + +static int port_err_set_clear(struct ifpga_port_hw *port, u64 val) +{ + int ret; + + spinlock_lock(&port->lock); + ret = port_err_clear(port, val); + spinlock_unlock(&port->lock); + + return ret; +} + +static struct feature_port_error err_dflt = { + .error_mask = { + .csr = 0x0000000000000000, + }, + .port_error = { + .csr = 0x0000000000000000, + }, + .port_first_error = { + .csr = 0x0000000000000000, + }, + .malreq0 = { + .header_lsb = 0x0000000000000000, + }, + .malreq1 = { + .header_msb = 0x0000000000000000, + }, + .port_debug = { + .port_debug = 0x0000000000000000, + }, +}; + +static int port_err_test(struct feature *feature) +{ + struct feature_port_error *port_err = + (struct feature_port_error *)feature->addr; + + port_check_reg(&port_err->error_mask, + "err:error_mask", err_dflt.error_mask.csr); + port_check_reg(&port_err->port_error, + "err:port_error", err_dflt.port_error.csr); + port_check_reg(&port_err->port_first_error, + "err:port_first_err", err_dflt.port_first_error.csr); + port_check_reg(&port_err->malreq0, + "err:malreq0", err_dflt.malreq0.header_lsb); + port_check_reg(&port_err->malreq1, + "err:malreq1", err_dflt.malreq1.header_msb); + port_check_reg(&port_err->port_debug, + "err:port_debug", err_dflt.port_debug.port_debug); + + dev_debug(NULL, "%s finished\n", __func__); + return 0; +} + +static int port_error_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port error Init.\n"); + + spinlock_lock(&port->lock); + port_err_mask(port, false); + if (feature->ctx_num) + port->capability |= FPGA_PORT_CAP_ERR_IRQ; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int port_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_ERR_PROP_REVISION: + return port_err_get_revision(port, &prop->data); + case PORT_ERR_PROP_ERRORS: + return port_err_get_errors(port, &prop->data); + case PORT_ERR_PROP_FIRST_ERROR: + return port_err_get_first_error(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB: + return port_err_get_first_malformed_req_lsb(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB: + return port_err_get_first_malformed_req_msb(port, &prop->data); + } + + return -ENOENT; +} + +static int port_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + if (prop->prop_id == PORT_ERR_PROP_CLEAR) + return port_err_set_clear(port, prop->data); + + return -ENOENT; +} + +static int port_error_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_port_err_irq_set *err_irq_set = irq_set; + struct ifpga_port_hw *port; + int ret; + + port = feature->parent; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_ERR_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_error_ops = { + .init = port_error_init, + .uinit = port_error_uinit, + .test = port_err_test, + .get_prop = port_error_get_prop, + .set_prop = port_error_set_prop, + .set_irq = port_error_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.c b/drivers/raw/ifpga_rawdev/base/opae_debug.c new file mode 100644 index 0000000..07935e7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.c @@ -0,0 +1,126 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#define OPAE_HW_DEBUG + +#include "opae_hw_api.h" +#include "opae_debug.h" + +void opae_manager_dump(struct opae_manager *mgr) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Manger %s\n", mgr->name); + opae_log("OPAE Manger OPs = %p\n", mgr->ops); + opae_log("OPAE Manager Private Data = %p\n", mgr->data); + opae_log("OPAE Adapter(parent) = %p\n", mgr->adapter); + opae_log("==========================\n"); +} + +void opae_bridge_dump(struct opae_bridge *br) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Bridge %s\n", br->name); + opae_log("OPAE Bridge ID = %d\n", br->id); + opae_log("OPAE Bridge OPs = %p\n", br->ops); + opae_log("OPAE Bridge Private Data = %p\n", br->data); + opae_log("OPAE Accelerator(under this bridge) = %p\n", br->acc); + opae_log("==========================\n"); +} + +void opae_accelerator_dump(struct opae_accelerator *acc) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Accelerator %s\n", acc->name); + opae_log("OPAE Accelerator Index = %d\n", acc->index); + opae_log("OPAE Accelerator OPs = %p\n", acc->ops); + opae_log("OPAE Accelerator Private Data = %p\n", acc->data); + opae_log("OPAE Bridge (upstream) = %p\n", acc->br); + opae_log("OPAE Manager (upstream) = %p\n", acc->mgr); + opae_log("==========================\n"); + + if (acc->br) + opae_bridge_dump(acc->br); +} + +static void opae_adapter_data_dump(void *data) +{ + struct opae_adapter_data *d = data; + struct opae_adapter_data_pci *d_pci; + struct opae_reg_region *r; + int i; + + opae_log("=====%s=====\n", __func__); + + switch (d->type) { + case OPAE_FPGA_PCI: + d_pci = (struct opae_adapter_data_pci *)d; + + opae_log("OPAE Adapter Type = PCI\n"); + opae_log("PCI Device ID: 0x%04x\n", d_pci->device_id); + opae_log("PCI Vendor ID: 0x%04x\n", d_pci->vendor_id); + + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + r = &d_pci->region[i]; + opae_log("PCI Bar %d: phy(%llx) len(%llx) addr(%p)\n", + i, (unsigned long long)r->phys_addr, + (unsigned long long)r->len, r->addr); + } + break; + case OPAE_FPGA_NET: + break; + } + + opae_log("==========================\n"); +} + +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) { + if (adapter->mgr) + opae_manager_dump(adapter->mgr); + + opae_adapter_for_each_acc(adapter, acc) + opae_accelerator_dump(acc); + + if (adapter->data) + opae_adapter_data_dump(adapter->data); + } + + opae_log("==========================\n"); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.h b/drivers/raw/ifpga_rawdev/base/opae_debug.h new file mode 100644 index 0000000..ceddf9d --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.h @@ -0,0 +1,46 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_DEBUG_H_ +#define _OPAE_DEBUG_H_ + +#ifdef OPAE_HW_DEBUG +#define opae_log(fmt, args...) printf(fmt, ## args) +#else +#define opae_log(fme, args...) do {} while (0) +#endif + +void opae_manager_dump(struct opae_manager *mgr); +void opae_bridge_dump(struct opae_bridge *br); +void opae_accelerator_dump(struct opae_accelerator *acc); +void opae_adapter_dump(struct opae_adapter *adapter, int verbose); + +#endif /* _OPAE_DEBUG_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c new file mode 100644 index 0000000..fad1f46 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -0,0 +1,389 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "opae_hw_api.h" +#include "opae_debug.h" +#include "ifpga_api.h" + +/* OPAE Bridge Functions */ + +/** + * opae_bridge_alloc - alloc opae_bridge data structure + * @name: bridge name. + * @ops: ops of this bridge. + * @data: private data of this bridge. + * + * Return opae_bridge on success, otherwise NULL. + */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data) +{ + struct opae_bridge *br = opae_zmalloc(sizeof(*br)); + + if (!br) + return NULL; + + br->name = name; + br->ops = ops; + br->data = data; + + opae_log("%s %p\n", __func__, br); + + return br; +} + +/** + * opae_bridge_reset - reset opae_bridge + * @br: bridge to be reset. + * + * Return: 0 on success, otherwise error code. + */ +int opae_bridge_reset(struct opae_bridge *br) +{ + if (!br) + return -EINVAL; + + if (br->ops && br->ops->reset) + return br->ops->reset(br); + + opae_log("%s no ops\n", __func__); + + return -ENOENT; +} + +/* Accelerator Functions */ + +/** + * opae_accelerator_alloc - alloc opae_accelerator data structure + * @name: accelerator name. + * @ops: ops of this accelerator. + * @data: private data of this accelerator. + * + * Return: opae_accelerator on success, otherwise NULL. + */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data) +{ + struct opae_accelerator *acc = opae_zmalloc(sizeof(*acc)); + + if (!acc) + return NULL; + + acc->name = name; + acc->ops = ops; + acc->data = data; + + opae_log("%s %p\n", __func__, acc); + + return acc; +} + +/** + * opae_acc_reg_read - read accelerator's register from its reg region. + * @acc: accelerator to read. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: read operation width, e.g 4 byte = 32bit read. + * @data: data to store the value read from the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->read) + return acc->ops->read(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_reg_write - write to accelerator's register from its reg region. + * @acc: accelerator to write. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: write operation width, e.g 4 byte = 32bit write. + * @data: data stored the value to write to the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->write) + return acc->ops->write(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_get_info - get information of an accelerator. + * @acc: targeted accelerator + * @info: accelerator info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_info) + return acc->ops->get_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_get_region_info - get information of an accelerator register region. + * @acc: targeted accelerator + * @info: accelerator region info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_region_info) + return acc->ops->get_region_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_set_irq - set an accelerator's irq. + * @acc: targeted accelerator + * @start: start vector number + * @count: count of vectors to be set from the start vector + * @evtfds: event fds to be notified when corresponding irqs happens + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + if (!acc || !acc->data) + return -EINVAL; + + if (start + count <= start) + return -EINVAL; + + if (acc->ops && acc->ops->set_irq) + return acc->ops->set_irq(acc, start, count, evtfds); + + return -ENOENT; +} + +/* Manager Functions */ + +/** + * opae_manager_alloc - alloc opae_manager data structure + * @name: manager name. + * @ops: ops of this manager. + * @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) +{ + struct opae_manager *mgr = opae_zmalloc(sizeof(*mgr)); + + if (!mgr) + return NULL; + + mgr->name = name; + mgr->ops = ops; + mgr->data = data; + + opae_log("%s %p\n", __func__, mgr); + + return mgr; +} + +/** + * opae_manager_flash - flash a reconfiguration image via opae_manager + * @mgr: opae_manager for flash. + * @id: id of target region (accelerator). + * @buf: image data buffer. + * @size: buffer size. + * @status: status to store flash result. + * + * Return: 0 on success, otherwise error code. + */ +int opae_manager_flash(struct opae_manager *mgr, int id, void *buf, u32 size, + u64 *status) +{ + if (!mgr) + return -EINVAL; + + if (mgr && mgr->ops && mgr->ops->flash) + return mgr->ops->flash(mgr, id, buf, size, status); + + return -ENOENT; +} + +/* Adapter Functions */ + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @type: opae_adapter_type. + * + * Return: opae_adapter_data on success, otherwise NULL. + */ +void *opae_adapter_data_alloc(enum opae_adapter_type type) +{ + struct opae_adapter_data *data; + int size; + + switch (type) { + case OPAE_FPGA_PCI: + size = sizeof(struct opae_adapter_data_pci); + break; + case OPAE_FPGA_NET: + size = sizeof(struct opae_adapter_data_net); + break; + default: + size = sizeof(struct opae_adapter_data); + break; + } + + data = opae_zmalloc(size); + if (!data) + return NULL; + + data->type = type; + + return data; +} + +static struct opae_adapter_ops *match_ops(struct opae_adapter *adapter) +{ + struct opae_adapter_data *data; + + if (!adapter || !adapter->data) + return NULL; + + data = adapter->data; + + if (data->type == OPAE_FPGA_PCI) + return &ifpga_adapter_ops; + + return NULL; +} + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @name: adapter name. + * @data: private data of this adapter. + * + * Return: opae_adapter on success, otherwise NULL. + */ +struct opae_adapter *opae_adapter_alloc(const char *name, void *data) +{ + struct opae_adapter *adapter = opae_zmalloc(sizeof(*adapter)); + + if (!adapter) + return NULL; + + TAILQ_INIT(&adapter->acc_list); + adapter->data = data; + adapter->name = name; + adapter->ops = match_ops(adapter); + + return adapter; +} + +/** + * opae_adapter_enumerate - enumerate this adapter + * @adapter: adapter to enumerate. + * + * Return: 0 on success, otherwise error code. + */ +int opae_adapter_enumerate(struct opae_adapter *adapter) +{ + int ret = -ENOENT; + + if (!adapter) + return -EINVAL; + + if (adapter->ops && adapter->ops->enumerate) + ret = adapter->ops->enumerate(adapter); + + if (!ret) + opae_adapter_dump(adapter, 1); + + return ret; +} + +/** + * opae_adapter_destroy - destroy this adapter + * @adapter: adapter to destroy. + * + * destroy things allocated during adapter enumeration. + */ +void opae_adapter_destroy(struct opae_adapter *adapter) +{ + if (adapter && adapter->ops && adapter->ops->destroy) + adapter->ops->destroy(adapter); +} + +/** + * opae_adapter_get_acc - find and return accelerator with matched id + * @adapter: adapter to find the accelerator. + * @acc_id: id (index) of the accelerator. + * + * destroy things allocated during adapter enumeration. + */ +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id) +{ + struct opae_accelerator *acc = NULL; + + if (!adapter) + return NULL; + + opae_adapter_for_each_acc(adapter, acc) + if (acc->index == acc_id) + return acc; + + return NULL; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h new file mode 100644 index 0000000..1f2391c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -0,0 +1,276 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_HW_API_H_ +#define _OPAE_HW_API_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> + +#include "opae_osdep.h" + +#ifndef PCI_MAX_RESOURCE +#define PCI_MAX_RESOURCE 6 +#endif + +struct opae_adapter; + +enum opae_adapter_type { + OPAE_FPGA_PCI, + OPAE_FPGA_NET, +}; + +/* OPAE Manager Data Structure */ +struct opae_manager_ops; + +/* + * opae_manager has pointer to its parent adapter, as it could be able to manage + * all components on this FPGA device (adapter). If not the case, don't set this + * adapter, which limit opae_manager ops to manager itself. + */ +struct opae_manager { + const char *name; + struct opae_adapter *adapter; + struct opae_manager_ops *ops; + void *data; +}; + +/* FIXME: add more management ops, e.g power/thermal and etc */ +struct opae_manager_ops { + int (*flash)(struct opae_manager *mgr, int id, void *buffer, + u32 size, u64 *status); +}; + +/* OPAE Manager APIs */ +struct opae_manager * +opae_manager_alloc(const char *name, struct opae_manager_ops *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); + +/* OPAE Bridge Data Structure */ +struct opae_bridge_ops; + +/* + * opae_bridge only has pointer to its downstream accelerator. + */ +struct opae_bridge { + const char *name; + int id; + struct opae_accelerator *acc; + struct opae_bridge_ops *ops; + void *data; +}; + +struct opae_bridge_ops { + int (*reset)(struct opae_bridge *br); +}; + +/* OPAE Bridge APIs */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data); +int opae_bridge_reset(struct opae_bridge *br); +#define opae_bridge_free(br) opae_free(br) + +/* OPAE Acceleraotr Data Structure */ +struct opae_accelerator_ops; + +/* + * opae_accelerator has pointer to its upstream bridge(port). + * In some cases, if we allow same user to do PR on its own accelerator, then + * set the manager pointer during the enumeration. But in other cases, the PR + * functions only could be done via manager in another module / thread / service + * / application for better protection. + */ +struct opae_accelerator { + TAILQ_ENTRY(opae_accelerator) node; + const char *name; + int index; + struct opae_bridge *br; + struct opae_manager *mgr; + struct opae_accelerator_ops *ops; + void *data; +}; + +struct opae_acc_info { + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct opae_acc_region_info { + u32 flags; +#define ACC_REGION_READ (1 << 0) +#define ACC_REGION_WRITE (1 << 1) +#define ACC_REGION_MMIO (1 << 2) + u32 index; + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_accelerator_ops { + int (*read)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*write)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*get_info)(struct opae_accelerator *acc, + struct opae_acc_info *info); + int (*get_region_info)(struct opae_accelerator *acc, + struct opae_acc_region_info *info); + int (*set_irq)(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); +}; + +/* OPAE accelerator APIs */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data); +#define opae_accelerator_free(acc) opae_free(acc) +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info); +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info); +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); + +static inline struct opae_bridge * +opae_acc_get_br(struct opae_accelerator *acc) +{ + return acc ? acc->br : NULL; +} + +static inline struct opae_manager * +opae_acc_get_mgr(struct opae_accelerator *acc) +{ + return acc ? acc->mgr : NULL; +} + +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + +#define opae_acc_reg_read64(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 8, data) +#define opae_acc_reg_write64(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 8, data) +#define opae_acc_reg_read32(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 4, data) +#define opae_acc_reg_write32(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 4, data) +#define opae_acc_reg_read16(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 2, data) +#define opae_acc_reg_write16(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 2, data) +#define opae_acc_reg_read8(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 1, data) +#define opae_acc_reg_write8(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 1, data) + +/*for data stream read/write*/ +int opae_acc_data_read(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); +int opae_acc_data_write(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); + +/* OPAE Adapter Data Structure */ +struct opae_adapter_data { + enum opae_adapter_type type; +}; + +struct opae_reg_region { + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_adapter_data_pci { + enum opae_adapter_type type; + u16 device_id; + u16 vendor_id; + struct opae_reg_region region[PCI_MAX_RESOURCE]; + int vfio_dev_fd; /* VFIO device file descriptor */ +}; + +/* FIXME: OPAE_FPGA_NET type */ +struct opae_adapter_data_net { + enum opae_adapter_type type; +}; + +struct opae_adapter_ops { + int (*enumerate)(struct opae_adapter *adapter); + void (*destroy)(struct opae_adapter *adapter); +}; + +TAILQ_HEAD(opae_accelerator_list, opae_accelerator); + +#define opae_adapter_for_each_acc(adatper, acc) \ + TAILQ_FOREACH(acc, &adapter->acc_list, node) + +struct opae_adapter { + const char *name; + struct opae_manager *mgr; + struct opae_accelerator_list acc_list; + struct opae_adapter_ops *ops; + void *data; +}; + +/* OPAE Adapter APIs */ +void *opae_adapter_data_alloc(enum opae_adapter_type type); +#define opae_adapter_data_free(data) opae_free(data) + +struct opae_adapter *opae_adapter_alloc(const char *name, void *data); +#define opae_adapter_free(adapter) opae_free(adapter) + +int opae_adapter_enumerate(struct opae_adapter *adapter); +void opae_adapter_destroy(struct opae_adapter *adapter); +static inline struct opae_manager * +opae_adapter_get_mgr(struct opae_adapter *adapter) +{ + return adapter ? adapter->mgr : NULL; +} + +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id); + +static inline void opae_adapter_add_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_INSERT_TAIL(&adapter->acc_list, acc, node); +} + +static inline void opae_adapter_remove_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_REMOVE(&adapter->acc_list, acc, node); +} +#endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c new file mode 100644 index 0000000..3993b17 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c @@ -0,0 +1,173 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "opae_ifpga_hw_api.h" +#include "ifpga_api.h" + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data || !fme_info) + return -EINVAL; + + fme = mgr->data; + + spinlock_lock(&fme->lock); + fme_info->capability = fme->capability; + spinlock_unlock(&fme->lock); + + return 0; +} + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_irq(fme->parent, FEATURE_FIU_ID_FME, 0, + IFPGA_FME_FEATURE_ID_GLOBAL_ERR, err_irq_set); +} + +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_get_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !port_info) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + port_info->capability = port->capability; + port_info->num_umsgs = port->num_umsgs; + port_info->num_uafu_irqs = port->num_uafu_irqs; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !info) + return -EINVAL; + + /* Only support STP region now */ + if (info->index != PORT_REGION_INDEX_STP) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + info->addr = (u64)port->stp_addr; + info->size = port->stp_size; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_ERROR, err_irq_set); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h new file mode 100644 index 0000000..20e114c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h @@ -0,0 +1,306 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_IFPGA_HW_API_H_ +#define _OPAE_IFPGA_HW_API_H_ + +#include "opae_hw_api.h" + +/** + * struct feature_prop - data structure for feature property + * @feature_id: id of this feature. + * @prop_id: id of this property under this feature. + * @data: property value to set/get. + */ +struct feature_prop { + u64 feature_id; + u64 prop_id; + u64 data; +}; + +#define IFPGA_FIU_ID_FME 0x0 +#define IFPGA_FIU_ID_PORT 0x1 + +#define IFPGA_FME_FEATURE_ID_HEADER 0x0 +#define IFPGA_FME_FEATURE_ID_THERMAL_MGMT 0x1 +#define IFPGA_FME_FEATURE_ID_POWER_MGMT 0x2 +#define IFPGA_FME_FEATURE_ID_GLOBAL_IPERF 0x3 +#define IFPGA_FME_FEATURE_ID_GLOBAL_ERR 0x4 +#define IFPGA_FME_FEATURE_ID_PR_MGMT 0x5 +#define IFPGA_FME_FEATURE_ID_HSSI 0x6 +#define IFPGA_FME_FEATURE_ID_GLOBAL_DPERF 0x7 + +#define IFPGA_PORT_FEATURE_ID_HEADER 0x0 +#define IFPGA_PORT_FEATURE_ID_AFU 0xff +#define IFPGA_PORT_FEATURE_ID_ERROR 0x10 +#define IFPGA_PORT_FEATURE_ID_UMSG 0x11 +#define IFPGA_PORT_FEATURE_ID_UINT 0x12 +#define IFPGA_PORT_FEATURE_ID_STP 0x13 + +/* + * PROP format (TOP + SUB + ID) + * + * (~0x0) means this field is unused. + */ +#define PROP_TOP GENMASK(31, 24) +#define PROP_TOP_UNUSED 0xff +#define PROP_SUB GENMASK(23, 16) +#define PROP_SUB_UNUSED 0xff +#define PROP_ID GENMASK(15, 0) + +#define PROP(_top, _sub, _id) \ + (SET_FIELD(PROP_TOP, _top) | SET_FIELD(PROP_SUB, _sub) |\ + SET_FIELD(PROP_ID, _id)) + +/* FME head feature's properties*/ +#define FME_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define FME_HDR_PROP_PORTS_NUM 0x2 /* RDONLY */ +#define FME_HDR_PROP_CACHE_SIZE 0x3 /* RDONLY */ +#define FME_HDR_PROP_VERSION 0x4 /* RDONLY */ +#define FME_HDR_PROP_SOCKET_ID 0x5 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_ID 0x6 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_METADATA 0x7 /* RDONLY */ + +/* FME error reporting feature's properties */ +/* FME error reporting properties format */ +#define ERR_PROP(_top, _id) PROP(_top, 0xff, _id) +#define ERR_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define ERR_PROP_TOP_FME_ERR 0x1 +#define ERR_PROP_ROOT(_id) ERR_PROP(0xff, _id) +#define ERR_PROP_FME_ERR(_id) ERR_PROP(ERR_PROP_TOP_FME_ERR, _id) + +#define FME_ERR_PROP_ERRORS ERR_PROP_FME_ERR(0x1) +#define FME_ERR_PROP_FIRST_ERROR ERR_PROP_FME_ERR(0x2) +#define FME_ERR_PROP_NEXT_ERROR ERR_PROP_FME_ERR(0x3) +#define FME_ERR_PROP_CLEAR ERR_PROP_FME_ERR(0x4) /* WO */ +#define FME_ERR_PROP_REVISION ERR_PROP_ROOT(0x5) +#define FME_ERR_PROP_PCIE0_ERRORS ERR_PROP_ROOT(0x6) /* RW */ +#define FME_ERR_PROP_PCIE1_ERRORS ERR_PROP_ROOT(0x7) /* RW */ +#define FME_ERR_PROP_NONFATAL_ERRORS ERR_PROP_ROOT(0x8) +#define FME_ERR_PROP_CATFATAL_ERRORS ERR_PROP_ROOT(0x9) +#define FME_ERR_PROP_INJECT_ERRORS ERR_PROP_ROOT(0xa) /* RW */ + +/* FME thermal feature's properties */ +#define FME_THERMAL_PROP_THRESHOLD1 0x1 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD2 0x2 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD_TRIP 0x3 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_REACHED 0x4 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD2_REACHED 0x5 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_POLICY 0x6 /* RW */ +#define FME_THERMAL_PROP_TEMPERATURE 0x7 /* RDONLY */ +#define FME_THERMAL_PROP_REVISION 0x8 /* RDONLY */ + +/* FME power feature's properties */ +#define FME_PWR_PROP_CONSUMED 0x1 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD1 0x2 /* RW */ +#define FME_PWR_PROP_THRESHOLD2 0x3 /* RW */ +#define FME_PWR_PROP_THRESHOLD1_STATUS 0x4 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD2_STATUS 0x5 /* RDONLY */ +#define FME_PWR_PROP_RTL 0x6 /* RDONLY */ +#define FME_PWR_PROP_XEON_LIMIT 0x7 /* RDONLY */ +#define FME_PWR_PROP_FPGA_LIMIT 0x8 /* RDONLY */ +#define FME_PWR_PROP_REVISION 0x9 /* RDONLY */ + +/* FME iperf/dperf PROP format */ +#define PERF_PROP_TOP_CACHE 0x1 +#define PERF_PROP_TOP_VTD 0x2 +#define PERF_PROP_TOP_FAB 0x3 +#define PERF_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define PERF_PROP_SUB_UNUSED PROP_SUB_UNUSED + +#define PERF_PROP_ROOT(_id) PROP(0xff, 0xff, _id) +#define PERF_PROP_CACHE(_id) PROP(PERF_PROP_TOP_CACHE, 0xff, _id) +#define PERF_PROP_VTD(_sub, _id) PROP(PERF_PROP_TOP_VTD, _sub, _id) +#define PERF_PROP_VTD_ROOT(_id) PROP(PERF_PROP_TOP_VTD, 0xff, _id) +#define PERF_PROP_FAB(_sub, _id) PROP(PERF_PROP_TOP_FAB, _sub, _id) +#define PERF_PROP_FAB_ROOT(_id) PROP(PERF_PROP_TOP_FAB, 0xff, _id) + +/* FME iperf feature's properties */ +#define FME_IPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_IPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* iperf CACHE properties */ +#define FME_IPERF_PROP_CACHE_FREEZE PERF_PROP_CACHE(0x1) /* RW */ +#define FME_IPERF_PROP_CACHE_READ_HIT PERF_PROP_CACHE(0x2) +#define FME_IPERF_PROP_CACHE_READ_MISS PERF_PROP_CACHE(0x3) +#define FME_IPERF_PROP_CACHE_WRITE_HIT PERF_PROP_CACHE(0x4) +#define FME_IPERF_PROP_CACHE_WRITE_MISS PERF_PROP_CACHE(0x5) +#define FME_IPERF_PROP_CACHE_HOLD_REQUEST PERF_PROP_CACHE(0x6) +#define FME_IPERF_PROP_CACHE_TX_REQ_STALL PERF_PROP_CACHE(0x7) +#define FME_IPERF_PROP_CACHE_RX_REQ_STALL PERF_PROP_CACHE(0x8) +#define FME_IPERF_PROP_CACHE_RX_EVICTION PERF_PROP_CACHE(0x9) +#define FME_IPERF_PROP_CACHE_DATA_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xa) +#define FME_IPERF_PROP_CACHE_TAG_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xb) +/* iperf VTD properties */ +#define FME_IPERF_PROP_VTD_FREEZE PERF_PROP_VTD_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_HIT PERF_PROP_VTD_ROOT(0x2) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_HIT PERF_PROP_VTD_ROOT(0x3) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_HIT PERF_PROP_VTD_ROOT(0x4) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_HIT PERF_PROP_VTD_ROOT(0x5) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_HIT PERF_PROP_VTD_ROOT(0x6) +#define FME_IPERF_PROP_VTD_SIP_RCC_HIT PERF_PROP_VTD_ROOT(0x7) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_MISS PERF_PROP_VTD_ROOT(0x8) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_MISS PERF_PROP_VTD_ROOT(0x9) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_MISS PERF_PROP_VTD_ROOT(0xa) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_MISS PERF_PROP_VTD_ROOT(0xb) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_MISS PERF_PROP_VTD_ROOT(0xc) +#define FME_IPERF_PROP_VTD_SIP_RCC_MISS PERF_PROP_VTD_ROOT(0xd) +#define FME_IPERF_PROP_VTD_PORT_READ_TRANSACTION(n) PERF_PROP_VTD(n, 0xe) +#define FME_IPERF_PROP_VTD_PORT_WRITE_TRANSACTION(n) PERF_PROP_VTD(n, 0xf) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_READ_HIT(n) PERF_PROP_VTD(n, 0x10) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_WRITE_HIT(n) PERF_PROP_VTD(n, 0x11) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_4K_FILL(n) PERF_PROP_VTD(n, 0x12) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_2M_FILL(n) PERF_PROP_VTD(n, 0x13) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_1G_FILL(n) PERF_PROP_VTD(n, 0x14) +/* iperf FAB properties */ +#define FME_IPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_IPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_IPERF_PROP_FAB_PCIE1_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_IPERF_PROP_FAB_PCIE1_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_IPERF_PROP_FAB_UPI_READ PERF_PROP_FAB_ROOT(0x6) +#define FME_IPERF_PROP_FAB_PORT_UPI_READ(n) PERF_PROP_FAB(n, 0x6) +#define FME_IPERF_PROP_FAB_UPI_WRITE PERF_PROP_FAB_ROOT(0x7) +#define FME_IPERF_PROP_FAB_PORT_UPI_WRITE(n) PERF_PROP_FAB(n, 0x7) +#define FME_IPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x8) +#define FME_IPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x8) +#define FME_IPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x9) +#define FME_IPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x9) +#define FME_IPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0xa) /* RW */ +#define FME_IPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0xa) /* RW */ + +/* FME dperf properties */ +#define FME_DPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_DPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* dperf FAB properties */ +#define FME_DPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_DPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_DPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_DPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_DPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_DPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_DPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_DPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0x6) /* RW */ +#define FME_DPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0x6) /* RW */ + +/*PORT hdr feature's properties*/ +#define PORT_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_HDR_PROP_PORTIDX 0x2 /* RDONLY */ +#define PORT_HDR_PROP_LATENCY_TOLERANCE 0x3 /* RDONLY */ +#define PORT_HDR_PROP_AP1_EVENT 0x4 /* RW */ +#define PORT_HDR_PROP_AP2_EVENT 0x5 /* RW */ +#define PORT_HDR_PROP_POWER_STATE 0x6 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_FREQCMD 0x7 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQCNTRCMD 0x8 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQSTS 0x9 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_CNTRSTS 0xa /* RDONLY */ + +/*PORT error feature's properties*/ +#define PORT_ERR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_ERR_PROP_ERRORS 0x2 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_ERROR 0x3 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB 0x4 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB 0x5 /* RDONLY */ +#define PORT_ERR_PROP_CLEAR 0x6 /* WRONLY */ + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop); +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop); + +/* + * Retrieve information about the fpga fme. + * Driver fills the info in provided struct fpga_fme_info. + */ +struct fpga_fme_info { + u32 capability; /* The capability of FME device */ +#define FPGA_FME_CAP_ERR_IRQ (1 << 0) /* Support fme error interrupt */ +}; + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info); + +/* Set eventfd information for ifpga FME error interrupt */ +struct fpga_fme_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set); + +/* + * Retrieve information about the fpga port. + * Driver fills the info in provided struct fpga_port_info. + */ +struct fpga_port_info { + u32 capability; /* The capability of port device */ +#define FPGA_PORT_CAP_ERR_IRQ (1 << 0) /* Support port error interrupt */ +#define FPGA_PORT_CAP_UAFU_IRQ (1 << 1) /* Support uafu error interrupt */ + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ +}; + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info); +/* + * Retrieve region information about the fpga port. + * Driver needs to fill the index of struct fpga_port_region_info. + */ +struct fpga_port_region_info { + u32 index; +#define PORT_REGION_INDEX_STP (1 << 1) /* Signal Tap Region */ + u64 size; /* Region Size */ + u64 addr; /* Base address of the region */ +}; + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info); + +/* Set eventfd information for ifpga port error interrupt */ +struct fpga_port_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set); + +#endif /* _OPAE_IFPGA_HW_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h new file mode 100644 index 0000000..00d3736 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -0,0 +1,111 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_OSDEP_H +#define _OPAE_OSDEP_H + +#include <string.h> +#include <stdbool.h> + +#ifdef RTE_LIBRTE_EAL +#include "osdep_rte/osdep_generic.h" +#else +#include "osdep_raw/osdep_generic.h" +#endif + +#include <asm/types.h> + +#define __iomem + +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef uint64_t dma_addr_t; + +#ifndef LINUX_MACROS +#ifndef BITS_PER_LONG +#define BITS_PER_LONG (__SIZEOF_LONG__ * 8) +#endif +#ifndef BIT +#define BIT(a) (1UL << (a)) +#endif /* BIT */ +#ifndef BIT_ULL +#define BIT_ULL(a) (1ULL << (a)) +#endif /* BIT_ULL */ +#ifndef GENMASK +#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#endif /* GENMASK */ +#ifndef GENMASK_ULL +#define GENMASK_ULL(h, l) (((U64_C(1) << ((h) - (l) + 1)) - 1) << (l)) +#endif /* GENMASK_ULL */ +#endif /* LINUX_MACROS */ + +#define SET_FIELD(m, v) (((v) << (__builtin_ffsll(m) - 1)) & (m)) +#define GET_FIELD(m, v) (((v) & (m)) >> (__builtin_ffsll(m) - 1)) + +#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) +#define pr_info(y, args...) dev_info(0, y, ##args) +#define BUG() pr_err("BUG at %s:%d", __func__, __LINE__) + +#define ASSERT(x) do {\ + if (!(x)) \ + osdep_panic("osdep_panic: x"); \ +} while (0) +#define BUG_ON(x) ASSERT(!(x)) + +#ifndef WARN_ON +#define WARN_ON(x) do { \ + int ret = !!(x); \ + if (unlikely(ret)) \ + pr_warn("WARN_ON: \"" #x "\" at %s:%d\n", __func__, __LINE__); \ +} while (0) +#endif + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define udelay(x) opae_udelay(x) +#define msleep(x) opae_udelay(1000 * (x)) +#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000)) + +#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 new file mode 100644 index 0000000..12ad018 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h @@ -0,0 +1,104 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OSDEP_RAW_GENERIC_H +#define _OSDEP_RAW_GENERIC_H + +#define compiler_barrier() do { \ + asm volatile ("" : : : "memory"); \ +} while (0) + +#define io_wmb() compiler_barrier() +#define io_rmb() compiler_barrier() + +static inline uint8_t opae_readb(const volatile void *addr) +{ + uint8_t val; + + val = *(const volatile uint8_t *)addr; + io_rmb(); + return val; +} + +static inline uint16_t opae_readw(const volatile void *addr) +{ + uint16_t val; + + val = *(const volatile uint16_t *)addr; + io_rmb(); + return val; +} + +static inline uint32_t opae_readl(const volatile void *addr) +{ + uint32_t val; + + val = *(const volatile uint32_t *)addr; + io_rmb(); + return val; +} + +static inline uint64_t opae_readq(const volatile void *addr) +{ + uint64_t val; + + val = *(const volatile uint64_t *)addr; + io_rmb(); + return val; +} + +static inline void opae_writeb(uint8_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint8_t *)addr = value; +} + +static inline void opae_writew(uint16_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint16_t *)addr = value; +} + +static inline void opae_writel(uint32_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint32_t *)addr = value; +} + +static inline void opae_writeq(uint64_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint64_t *)addr = value; +} + +#define opae_free(addr) free(addr) + +#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 new file mode 100644 index 0000000..9ff580e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h @@ -0,0 +1,72 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OSDEP_RTE_GENERIC_H +#define _OSDEP_RTE_GENERIC_H + +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_spinlock.h> +#include <rte_log.h> +#include <rte_io.h> +#include <rte_malloc.h> + +#define dev_printf(level, fmt, args...) \ + RTE_LOG(level, PMD, "osdep_rte: " fmt, ## args) + +#define osdep_panic(...) rte_panic(...) + +#define opae_udelay(x) rte_delay_us(x) + +#define opae_readb(addr) rte_read8(addr) +#define opae_readw(addr) rte_read16(addr) +#define opae_readl(addr) rte_read32(addr) +#define opae_readq(addr) rte_read64(addr) +#define opae_writeb(value, addr) rte_write8(value, addr) +#define opae_writew(value, addr) rte_write16(value, addr) +#define opae_writel(value, addr) rte_write32(value, addr) +#define opae_writeq(value, addr) rte_write64(value, addr) + +#define opae_malloc(size) rte_malloc(NULL, size, 0) +#define opae_zmalloc(size) rte_zmalloc(NULL, size, 0) +#define opae_free(addr) rte_free(addr) + +#define ARRAY_SIZE(arr) RTE_DIM(arr) + +#define min(a, b) RTE_MIN(a, b) +#define max(a, b) RTE_MAX(a, b) + +#define spinlock_t rte_spinlock_t +#define spinlock_init(x) rte_spinlock_init(x) +#define spinlock_lock(x) rte_spinlock_lock(x) +#define spinlock_unlock(x) rte_spinlock_unlock(x) + +#endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 0/6] Introduce Intel FPGA BUS 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 0/6] " Rosen Xu ` (5 preceding siblings ...) 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 6/6] drivers/raw/ifpga_rawdev: Add Intel FPGA OPAE Share Code Rosen Xu @ 2018-03-28 9:37 ` Bruce Richardson 2018-03-28 13:17 ` Gaëtan Rivet 7 siblings, 0 replies; 149+ messages in thread From: Bruce Richardson @ 2018-03-28 9:37 UTC (permalink / raw) To: Rosen Xu Cc: dev, declan.doherty, shreyansh.jain, tianfei.zhang, hao.wu, gaetan.rivet [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset=utf-8, Size: 2981 bytes --] On Wed, Mar 28, 2018 at 05:29:50PM +0800, Rosen Xu wrote: > Intel FPGA BUS in DPDK > ------------------------- > > This patch set introduces Intel FPGA BUS support in DPDK. > > v3 updates: > =========== > - Remove all modifications of bus scan and probe > - FPGA BUS Scan is trigged by hotplug of Rawdev > - Took Modifications of comments > - Move AFU Device to IFPGA > - FPGA BUS Scan depend on it¡¯s IFPGA Rawdev > - Add Build Macros for FPGA BUS and IFPGA Rawdev > > Questions > ========= > Why not PCI Bus? > All of the AFUs of one FPGA may share same PCI BDF. > Why not vdev Bus? > Because AFUs depend on Rawdev, and it's hardware specpic. > > Motivation > ========== > FPGA is used more and more widely in Cloud and NFV, one primary reason is > that FPGA not only provide ASIC performance but also it's more flexible > than ASIC. FPGA use Partial Reconfigure(PR) Parts of Bitstream to achieve > its flexibility. Another reason is that one FPGA can be shared > by different Users, and each User can use some of AFUs of One FPGA. > > That means One FPGA Device Bitstream is divided into many Parts of > Bitstream(each Part of Bitstream is defined as AFU-Accelerated > Function Unit), and each AFU is a Hardware Acceleration Unit and > it can dynamically Reload respectively. > > Proposed Solution > ================= > - Involve Rawdev to take FPGA Partial Configuration(Download/PR) > - Defined FPGA-BUS for Acceleration Drivers of AFUs > - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, > probe Intel FPGA Rawdev Driver. FPGA-BUS scan is called, but AFU > depend on Rawdev, so this scan doesn't trig AFU device create. > - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream. > This scan is trigged by hotplug of IFPGA Rawdev probe, in this > scan the AFUs will be created and their dirves are also probed. > > Scope > ===== > The Intel FPGA BUS implementation is target towards various FPGA Devices > use PR to provide many Acceleration Function. Specific PMDs may also > bind to its AFU. And Applications don't care they are using ASIC > Acceleration or FPGA AFU Acceleration. > > > Status > ===== > With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable > Acceleration Engine) Share Code, Intel FPGA BUS runs well in > Intel PSG FPGA Cards. > > > Rosen Xu (6): > Add Intel FPGA BUS Command Parse Code > config/common_base: Add Intel FPGA Build Configuration Macro > mk/rte.app.mk: Add Intel FPGA Bus Build Configuration Macro To App > Script > drivers/bus: Add Intel FPGA Bus Lib Code > drivers/raw/ifpga_rawdev: Add Intel FPGA Rawdev Driver Code > drivers/raw/ifpga_rawdev: Add Intel FPGA OPAE Share Code > > config/common_base | 6 + > drivers/bus/Makefile | 1 + Forgot to mention this on previous versions, but please also include changes to add this to the meson build too. /Bruce ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 0/6] Introduce Intel FPGA BUS 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 0/6] " Rosen Xu ` (6 preceding siblings ...) 2018-03-28 9:37 ` [dpdk-dev] [PATCH v3 0/6] Introduce Intel FPGA BUS Bruce Richardson @ 2018-03-28 13:17 ` Gaëtan Rivet 2018-03-28 16:15 ` Zhang, Tianfei 2018-04-04 1:57 ` Xu, Rosen 7 siblings, 2 replies; 149+ messages in thread From: Gaëtan Rivet @ 2018-03-28 13:17 UTC (permalink / raw) To: Rosen Xu Cc: dev, declan.doherty, bruce.richardson, shreyansh.jain, tianfei.zhang, hao.wu Hi Rosen, On Wed, Mar 28, 2018 at 05:29:50PM +0800, Rosen Xu wrote: > Intel FPGA BUS in DPDK > ------------------------- > > This patch set introduces Intel FPGA BUS support in DPDK. > > v3 updates: > =========== > - Remove all modifications of bus scan and probe > - FPGA BUS Scan is trigged by hotplug of Rawdev > - Took Modifications of comments > - Move AFU Device to IFPGA > - FPGA BUS Scan depend on it¡¯s IFPGA Rawdev > - Add Build Macros for FPGA BUS and IFPGA Rawdev > > Questions > ========= > Why not PCI Bus? > All of the AFUs of one FPGA may share same PCI BDF. > Why not vdev Bus? > Because AFUs depend on Rawdev, and it's hardware specpic. > > Motivation > ========== > FPGA is used more and more widely in Cloud and NFV, one primary reason is > that FPGA not only provide ASIC performance but also it's more flexible > than ASIC. FPGA use Partial Reconfigure(PR) Parts of Bitstream to achieve > its flexibility. Another reason is that one FPGA can be shared > by different Users, and each User can use some of AFUs of One FPGA. > > That means One FPGA Device Bitstream is divided into many Parts of > Bitstream(each Part of Bitstream is defined as AFU-Accelerated > Function Unit), and each AFU is a Hardware Acceleration Unit and > it can dynamically Reload respectively. > > Proposed Solution > ================= > - Involve Rawdev to take FPGA Partial Configuration(Download/PR) > - Defined FPGA-BUS for Acceleration Drivers of AFUs > - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, > probe Intel FPGA Rawdev Driver. FPGA-BUS scan is called, but AFU > depend on Rawdev, so this scan doesn't trig AFU device create. > - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream. > This scan is trigged by hotplug of IFPGA Rawdev probe, in this > scan the AFUs will be created and their dirves are also probed. > > Scope > ===== > The Intel FPGA BUS implementation is target towards various FPGA Devices > use PR to provide many Acceleration Function. Specific PMDs may also > bind to its AFU. And Applications don't care they are using ASIC > Acceleration or FPGA AFU Acceleration. > > > Status > ===== > With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable > Acceleration Engine) Share Code, Intel FPGA BUS runs well in > Intel PSG FPGA Cards. > Which compiler did you use and in which version? With GCC 6.3 I got these errors: == Build drivers/raw/ifpga_rawdev CC skeleton_rawdev.o CC skeleton_rawdev_test.o CC ifpga_api.o CC ifpga_enumerate.o /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c: In function ‘parse_feature_afus’: /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c:334:3: error: this ‘if’ clause does not guard... [-Werror=misleading-indentation] if (feature_is_UAFU(binfo)) ^~ /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c:336:4: note: ...this statement, but the latter is misleadinglyindented as if it is guarded by the ‘if’ if (ret) ^~ CC ifpga_feature_dev.o /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c: In function ‘port_hw_init’: /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c:272:3: error: this ‘if’ clause does not guard... [-Werror=misleading-indentation] if (feature->ops && feature->ops->init) ^~ /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c:274:4: note: ...this statement, but the latter is misleadingly indented as if it is guarded by the ‘if’ if (ret) { ^~ cc1: all warnings being treated as errors -- Gaëtan Rivet 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 0/6] Introduce Intel FPGA BUS 2018-03-28 13:17 ` Gaëtan Rivet @ 2018-03-28 16:15 ` Zhang, Tianfei 2018-04-04 1:57 ` Xu, Rosen 1 sibling, 0 replies; 149+ messages in thread From: Zhang, Tianfei @ 2018-03-28 16:15 UTC (permalink / raw) To: gaetan.rivet, Xu, Rosen Cc: dev, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Wu, Hao > -----Original Message----- > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com] > Sent: Wednesday, March 28, 2018 6:18 AM > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com> > Subject: Re: [PATCH v3 0/6] Introduce Intel FPGA BUS > > Hi Rosen, > > On Wed, Mar 28, 2018 at 05:29:50PM +0800, Rosen Xu wrote: > > Intel FPGA BUS in DPDK > > ------------------------- > > > > This patch set introduces Intel FPGA BUS support in DPDK. > > > > v3 updates: > > =========== > > - Remove all modifications of bus scan and probe > > - FPGA BUS Scan is trigged by hotplug of Rawdev > > - Took Modifications of comments > > - Move AFU Device to IFPGA > > - FPGA BUS Scan depend on it¡¯s IFPGA Rawdev > > - Add Build Macros for FPGA BUS and IFPGA Rawdev > > > > Questions > > ========= > > Why not PCI Bus? > > All of the AFUs of one FPGA may share same PCI BDF. > > Why not vdev Bus? > > Because AFUs depend on Rawdev, and it's hardware specpic. > > > > Motivation > > ========== > > FPGA is used more and more widely in Cloud and NFV, one primary reason > > is that FPGA not only provide ASIC performance but also it's more > > flexible than ASIC. FPGA use Partial Reconfigure(PR) Parts of > > Bitstream to achieve its flexibility. Another reason is that one FPGA > > can be shared by different Users, and each User can use some of AFUs of > One FPGA. > > > > That means One FPGA Device Bitstream is divided into many Parts of > > Bitstream(each Part of Bitstream is defined as AFU-Accelerated > > Function Unit), and each AFU is a Hardware Acceleration Unit and it > > can dynamically Reload respectively. > > > > Proposed Solution > > ================= > > - Involve Rawdev to take FPGA Partial Configuration(Download/PR) > > - Defined FPGA-BUS for Acceleration Drivers of AFUs > > - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, > > probe Intel FPGA Rawdev Driver. FPGA-BUS scan is called, but AFU > > depend on Rawdev, so this scan doesn't trig AFU device create. > > - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream. > > This scan is trigged by hotplug of IFPGA Rawdev probe, in this > > scan the AFUs will be created and their dirves are also probed. > > > > Scope > > ===== > > The Intel FPGA BUS implementation is target towards various FPGA > > Devices use PR to provide many Acceleration Function. Specific PMDs > > may also bind to its AFU. And Applications don't care they are using > > ASIC Acceleration or FPGA AFU Acceleration. > > > > > > Status > > ===== > > With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable > > Acceleration Engine) Share Code, Intel FPGA BUS runs well in Intel PSG > > FPGA Cards. > > > > Which compiler did you use and in which version? With GCC 6.3 I got these > errors: We build it on Ubuntu 16.04 and RHEL 7.4, the compiler is : GCC 5.4 and GCC 4.8.5. We will check the GCC 6.3 later. > > == Build drivers/raw/ifpga_rawdev > CC skeleton_rawdev.o > CC skeleton_rawdev_test.o > CC ifpga_api.o > CC ifpga_enumerate.o > /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_enumerat > e.c: In function ‘parse_feature_afus’: > /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_enumerat > e.c:334:3: error: this ‘if’ clause does not guard... > [-Werror=misleading-indentation] > if (feature_is_UAFU(binfo)) > ^~ > /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_enumerat > e.c:336:4: note: ...this statement, but the latter is misleadinglyindented as if > it is guarded by the ‘if’ > if (ret) > ^~ > CC ifpga_feature_dev.o > /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_feature_d > ev.c: In function ‘port_hw_init’: > /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_feature_d > ev.c:272:3: error: this ‘if’ clause does not guard... > [-Werror=misleading-indentation] > if (feature->ops && feature->ops->init) > ^~ > /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_feature_d > ev.c:274:4: note: ...this statement, but the latter is misleadingly indented as > if it is guarded by the ‘if’ > if (ret) { > ^~ > cc1: all warnings being treated as errors > > -- > Gaëtan Rivet > 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v3 0/6] Introduce Intel FPGA BUS 2018-03-28 13:17 ` Gaëtan Rivet 2018-03-28 16:15 ` Zhang, Tianfei @ 2018-04-04 1:57 ` Xu, Rosen 1 sibling, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-04-04 1:57 UTC (permalink / raw) To: gaetan.rivet Cc: dev, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Zhang, Tianfei, Wu, Hao Hi Gaetan, > -----Original Message----- > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com] > Sent: Wednesday, March 28, 2018 21:18 > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Zhang, Tianfei <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com> > Subject: Re: [PATCH v3 0/6] Introduce Intel FPGA BUS > > Hi Rosen, > > On Wed, Mar 28, 2018 at 05:29:50PM +0800, Rosen Xu wrote: > > Intel FPGA BUS in DPDK > > ------------------------- > > > > This patch set introduces Intel FPGA BUS support in DPDK. > > > > v3 updates: > > =========== > > - Remove all modifications of bus scan and probe > > - FPGA BUS Scan is trigged by hotplug of Rawdev > > - Took Modifications of comments > > - Move AFU Device to IFPGA > > - FPGA BUS Scan depend on it¡¯s IFPGA Rawdev > > - Add Build Macros for FPGA BUS and IFPGA Rawdev > > > > Questions > > ========= > > Why not PCI Bus? > > All of the AFUs of one FPGA may share same PCI BDF. > > Why not vdev Bus? > > Because AFUs depend on Rawdev, and it's hardware specpic. > > > > Motivation > > ========== > > FPGA is used more and more widely in Cloud and NFV, one primary reason > > is that FPGA not only provide ASIC performance but also it's more > > flexible than ASIC. FPGA use Partial Reconfigure(PR) Parts of > > Bitstream to achieve its flexibility. Another reason is that one FPGA > > can be shared by different Users, and each User can use some of AFUs of > One FPGA. > > > > That means One FPGA Device Bitstream is divided into many Parts of > > Bitstream(each Part of Bitstream is defined as AFU-Accelerated > > Function Unit), and each AFU is a Hardware Acceleration Unit and it > > can dynamically Reload respectively. > > > > Proposed Solution > > ================= > > - Involve Rawdev to take FPGA Partial Configuration(Download/PR) > > - Defined FPGA-BUS for Acceleration Drivers of AFUs > > - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, > > probe Intel FPGA Rawdev Driver. FPGA-BUS scan is called, but AFU > > depend on Rawdev, so this scan doesn't trig AFU device create. > > - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream. > > This scan is trigged by hotplug of IFPGA Rawdev probe, in this > > scan the AFUs will be created and their dirves are also probed. > > > > Scope > > ===== > > The Intel FPGA BUS implementation is target towards various FPGA > > Devices use PR to provide many Acceleration Function. Specific PMDs > > may also bind to its AFU. And Applications don't care they are using > > ASIC Acceleration or FPGA AFU Acceleration. > > > > > > Status > > ===== > > With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable > > Acceleration Engine) Share Code, Intel FPGA BUS runs well in Intel PSG > > FPGA Cards. > > > > Which compiler did you use and in which version? With GCC 6.3 I got these > errors: > > == Build drivers/raw/ifpga_rawdev > CC skeleton_rawdev.o > CC skeleton_rawdev_test.o > CC ifpga_api.o > CC ifpga_enumerate.o > /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_enumera > te.c: In function ‘parse_feature_afus’: > /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_enumera > te.c:334:3: error: this ‘if’ clause does not guard... [-Werror=misleading- > indentation] > if (feature_is_UAFU(binfo)) > ^~ > /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_enumera > te.c:336:4: note: ...this statement, but the latter is misleadinglyindented as if > it is guarded by the ‘if’ > if (ret) > ^~ > CC ifpga_feature_dev.o > /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_feature_ > dev.c: In function ‘port_hw_init’: > /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_feature_ > dev.c:272:3: error: this ‘if’ clause does not guard... [-Werror=misleading- > indentation] > if (feature->ops && feature->ops->init) > ^~ > /home/rivet/dev/dpdk.org/drivers/raw/ifpga_rawdev/base/ifpga_feature_ > dev.c:274:4: note: ...this statement, but the latter is misleadingly indented as > if it is guarded by the ‘if’ > if (ret) { > ^~ > cc1: all warnings being treated as errors For PATCH v4, we have fixed it, and try it by GCC 6.4, is it ok in your server? > -- > Gaëtan Rivet > 6WIND ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v4 0/3] Introduce Intel FPGA BUS 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (6 preceding siblings ...) 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 0/6] " Rosen Xu @ 2018-03-31 16:02 ` Rosen Xu 2018-03-31 16:03 ` [dpdk-dev] [PATCH v4 1/3] Add Intel FPGA BUS Lib Code Rosen Xu ` (2 more replies) 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS Rosen Xu ` (9 subsequent siblings) 17 siblings, 3 replies; 149+ messages in thread From: Rosen Xu @ 2018-03-31 16:02 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset=y, Size: 7498 bytes --] Intel FPGA BUS in DPDK ------------------------- This patch set introduces Intel FPGA BUS support in DPDK. v4 updates: =========== - Remove all modifications from eal - Create vdev to take IFPGA parameters configuration - AFU Device Driver bind to AFU Device by uuid - Take more test in scenario of Multi-FPGA System v3 updates: =========== - Remove all modifications of bus scan and probe - FPGA BUS Scan is trigged by hotplug of Rawdev - Took Modifications of comments - Move AFU Device to IFPGA - FPGA BUS Scan depend on it¡¯s IFPGA Rawdev - Add Build Macros for FPGA BUS and IFPGA Rawdev Questions ========= Why not PCI Bus? All of the AFUs of one FPGA may share same PCI BDF. Why not vdev Bus? Because AFUs depend on Rawdev, and it's hardware specpic. Motivation ========== FPGA is used more and more widely in Cloud and NFV, one primary reason is that FPGA not only provide ASIC performance but also it's more flexible than ASIC. FPGA use Partial Reconfigure(PR) Parts of Bitstream to achieve its flexibility. Another reason is that one FPGA can be shared by different Users, and each User can use some of AFUs of One FPGA. That means One FPGA Device Bitstream is divided into many Parts of Bitstream(each Part of Bitstream is defined as AFU-Accelerated Function Unit), and each AFU is a Hardware Acceleration Unit and it can dynamically Reload respectively. Proposed Solution ================= - Involve Rawdev to take FPGA Partial Configuration(Download/PR) - Defined FPGA-BUS for Acceleration Drivers of AFUs - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver. FPGA-BUS scan is called, but AFU depend on Rawdev, so this scan doesn't trig AFU device create. - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their dirves are also probed. Scope ===== The Intel FPGA BUS implementation is target towards various FPGA Devices use PR to provide many Acceleration Function. Specific PMDs may also bind to its AFU. And Applications don't care they are using ASIC Acceleration or FPGA AFU Acceleration. Status ===== With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable Acceleration Engine) Share Code, Intel FPGA BUS runs well in Intel PSG FPGA Cards. Rosen Xu (3): Add Intel FPGA BUS Lib Code Add Intel FPGA BUS Rawdev Driver Add Intel FPGA OPAE Share Code config/common_base | 6 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 33 + drivers/bus/ifpga/ifpga_bus.c | 517 ++++++ drivers/bus/ifpga/ifpga_common.c | 141 ++ drivers/bus/ifpga/ifpga_common.h | 22 + drivers/bus/ifpga/ifpga_logs.h | 31 + drivers/bus/ifpga/rte_bus_ifpga.h | 175 ++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 8 + drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 34 + drivers/raw/ifpga_rawdev/base/Makefile | 54 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 529 ++++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 73 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 84 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1688 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 851 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 38 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 341 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 191 +++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 761 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 328 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 430 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 742 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 399 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 154 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 435 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 192 +++ drivers/raw/ifpga_rawdev/base/opae_debug.c | 126 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 46 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 408 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 280 ++++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 172 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 306 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 115 ++ .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 104 ++ .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 72 + drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 594 +++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 + .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + mk/rte.app.mk | 3 + 41 files changed, 10526 insertions(+) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v4 1/3] Add Intel FPGA BUS Lib Code 2018-03-31 16:02 ` [dpdk-dev] [PATCH v4 0/3] " Rosen Xu @ 2018-03-31 16:03 ` Rosen Xu 2018-04-03 9:25 ` Shreyansh Jain 2018-03-31 16:03 ` [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev Driver Rosen Xu 2018-03-31 16:03 ` [dpdk-dev] [PATCH v4 3/3] Add Intel FPGA OPAE Share Code Rosen Xu 2 siblings, 1 reply; 149+ messages in thread From: Rosen Xu @ 2018-03-31 16:03 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet Signed-off-by: Rosen Xu <rosen.xu@intel.com> --- config/common_base | 5 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 33 ++ drivers/bus/ifpga/ifpga_bus.c | 517 ++++++++++++++++++++++++++++ drivers/bus/ifpga/ifpga_common.c | 141 ++++++++ drivers/bus/ifpga/ifpga_common.h | 22 ++ drivers/bus/ifpga/ifpga_logs.h | 31 ++ drivers/bus/ifpga/rte_bus_ifpga.h | 175 ++++++++++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 8 + mk/rte.app.mk | 2 + 10 files changed, 935 insertions(+) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map diff --git a/config/common_base b/config/common_base index ad03cf4..49f6b09 100644 --- a/config/common_base +++ b/config/common_base @@ -134,6 +134,11 @@ CONFIG_RTE_LIBRTE_PCI_BUS=y CONFIG_RTE_LIBRTE_VDEV_BUS=y # +# Compile the Intel FPGA bus +# +CONFIG_RTE_LIBRTE_IFPGA_BUS=y + +# # Compile ARK PMD # CONFIG_RTE_LIBRTE_ARK_PMD=y diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index 7ef2593..55d2dfe 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -7,5 +7,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile new file mode 100644 index 0000000..1b569af --- /dev/null +++ b/drivers/bus/ifpga/Makefile @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_bus_ifpga.a + +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) + +# versioning export map +EXPORT_MAP := rte_bus_ifpga_version.map + +# library version +LIBABIVER := 1 + +VPATH += $(SRCDIR)/base + +SRCS-y += \ + ifpga_bus.c \ + ifpga_common.c + +LDLIBS += -lrte_eal + +# +# Export include files +# +SYMLINK-y-include += rte_bus_ifpga.h + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index 0000000..eba2615 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -0,0 +1,517 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_bus_logtype; + +/* register a ifpga bus based driver */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver) +{ + RTE_VERIFY(driver); + + TAILQ_INSERT_TAIL(&rte_ifpga_bus.driver_list, driver, next); +} + +/* un-register a fpga bus based driver */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) +{ + TAILQ_REMOVE(&rte_ifpga_bus.driver_list, driver, next); +} + +static struct rte_ifpga_device * +ifpga_find_ifpga_dev(const struct rte_pci_addr *pci_addr) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { + if (!rte_pci_addr_cmp(&ifpga_dev->pci_addr, pci_addr)) + return ifpga_dev; + } + return NULL; +} + +static struct rte_afu_device * +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, + const struct rte_afu_id *afu_id) +{ + struct rte_afu_device *afu_dev = NULL; + + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) + return afu_dev; + } + return NULL; +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_BDF "bdf" + IFPGA_ARG_BDF, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static struct rte_afu_device * +rte_ifpga_scan_one(struct rte_devargs *devargs, + struct rte_ifpga_device *ifpga_dev) +{ + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_afu_pr_conf afu_pr_conf; + int ret = 0; + char *path = NULL; + + memset((char *)(&afu_pr_conf), 0, sizeof(struct rte_afu_pr_conf)); + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, + &ifpga_get_bdf_arg, &afu_pr_conf.afu_id.pci_addr) < 0) { + IFPGA_BUS_ERR("error to parse %s", IFPGA_ARG_BDF); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_BDF); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, + &ifpga_get_string_arg, &path) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_AFU_BTS); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_AFU_BTS); + goto end; + } + + afu_pr_conf.afu_id.uuid_low = 0; + afu_pr_conf.afu_id.uuid_high = 0; + afu_pr_conf.pr_enable = path?1:0; + + rawdev = ifpga_dev->rdev; + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) + goto end; + + afu_dev = calloc(1, sizeof(*afu_dev)); + if (!afu_dev) + goto end; + + afu_dev->device.devargs = devargs; + afu_dev->device.numa_node = SOCKET_ID_ANY; + afu_dev->device.name = devargs->name; + afu_dev->rawdev = rawdev; + afu_dev->id.pci_addr.domain = afu_pr_conf.afu_id.pci_addr.domain; + afu_dev->id.pci_addr.bus = afu_pr_conf.afu_id.pci_addr.bus; + afu_dev->id.pci_addr.devid = afu_pr_conf.afu_id.pci_addr.devid; + afu_dev->id.pci_addr.function = afu_pr_conf.afu_id.pci_addr.function; + afu_dev->id.uuid_low = 0; + afu_dev->id.uuid_high = 0; + afu_dev->id.port = afu_pr_conf.afu_id.port; + afu_dev->ifpga_dev = ifpga_dev; + + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); + + if (rawdev->dev_ops && + rawdev->dev_ops->dev_start && + rawdev->dev_ops->dev_start(rawdev)) + goto free_dev; + if (path) { + strncpy(afu_pr_conf.bs_path, path, strlen(path)); + if (rawdev->dev_ops->firmware_load && + rawdev->dev_ops->firmware_load(rawdev, + &afu_pr_conf)){ + printf("firmware load error %d\n", ret); + goto free_dev; + } + afu_dev->id.uuid_low = afu_pr_conf.afu_id.uuid_low; + afu_dev->id.uuid_high = afu_pr_conf.afu_id.uuid_high; + } + + return afu_dev; + +free_dev: + free(afu_dev); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (path) + free(path); + + return NULL; +} + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static int +rte_ifpga_scan(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + struct rte_pci_addr pci_addr; + struct rte_rawdev *rawdev = NULL; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + struct rte_afu_device *afu_dev = NULL; + + /* for FPGA devices we scan the devargs_list populated via cmdline */ + TAILQ_FOREACH(devargs, &devargs_list, next) { + if (devargs->bus != &rte_ifpga_bus.bus) + continue; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, + &ifpga_get_bdf_arg, &pci_addr) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_BDF); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_BDF); + goto end; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%x:%x", + pci_addr.bus, pci_addr.devid, pci_addr.function); + + rawdev = rte_rawdev_pmd_get_named_dev(name); + if (!rawdev) + goto end; + + if (ifpga_find_ifpga_dev(&pci_addr)) + continue; + + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); + if (!ifpga_dev) + goto end; + + ifpga_dev->pci_addr.domain = pci_addr.domain; + ifpga_dev->pci_addr.bus = pci_addr.bus; + ifpga_dev->pci_addr.devid = pci_addr.devid; + ifpga_dev->pci_addr.function = pci_addr.function; + ifpga_dev->rdev = rawdev; + TAILQ_INIT(&ifpga_dev->afu_list); + + TAILQ_INSERT_TAIL(&rte_ifpga_bus.ifpga_list, ifpga_dev, next); + afu_dev = rte_ifpga_scan_one(devargs, ifpga_dev); + if (afu_dev != NULL) + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, next); + } + +end: + if (kvlist) + rte_kvargs_free(kvlist); + + return 0; +} + +/* + * Match the AFU Driver and AFU Device using the ID Table + */ +static int +rte_afu_match(const struct rte_afu_driver *afu_drv, + const struct rte_afu_device *afu_dev) +{ + const struct rte_afu_uuid *id_table; + + for (id_table = afu_drv->id_table; + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); + id_table++) { + /* check if device's identifiers match the driver's ones */ + if ((id_table->uuid_low != afu_dev->id.uuid_low) || + (id_table->uuid_high != afu_dev->id.uuid_high)) + continue; + + return 1; + } + + return 0; +} + +static int +ifpga_probe_one_driver(struct rte_afu_driver *drv, + struct rte_afu_device *afu_dev) +{ + int ret; + + if (!rte_afu_match(drv, afu_dev)) + /* Match of device and driver failed */ + return 1; + + /* reference driver structure */ + afu_dev->driver = drv; + afu_dev->device.driver = &drv->driver; + + /* call the driver probe() function */ + ret = drv->probe(afu_dev); + if (ret) { + afu_dev->driver = NULL; + afu_dev->device.driver = NULL; + } + + /* return positive value if driver doesn't support this device */ + return 0; +} + +static int +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) +{ + struct rte_afu_driver *drv = NULL; + int rc; + + if (afu_dev == NULL) + return -1; + + /* Check if a driver is already loaded */ + if (afu_dev->driver != NULL) + return 0; + + TAILQ_FOREACH(drv, &rte_ifpga_bus.driver_list, next) { + rc = ifpga_probe_one_driver(drv, afu_dev); + if (rc < 0) + /* negative value is an error */ + return -1; + if (rc > 0) + /* positive value means driver doesn't support it */ + continue; + return 0; + } + return 1; +} + +/* + * Scan the content of the PCI bus, and call the probe() function for + * all registered drivers that have a matching entry in its id_table + * for discovered devices. + */ +static int +rte_ifpga_probe(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev = NULL; + int ret = 0; + + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + + if (afu_dev->device.driver) + continue; + + ret = ifpga_probe_all_drivers(afu_dev); + if (ret < 0) + IFPGA_BUS_ERR("failed to initialize %s device\n", + rte_ifpga_device_name(afu_dev)); + } + } + + return 0; +} + +static int +rte_ifpga_plug(struct rte_device *dev) +{ + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); +} + +static int ifpga_remove_driver(struct rte_afu_device *afu_dev) +{ + const char *name; + const struct rte_afu_driver *driver; + + name = rte_ifpga_device_name(afu_dev); + if (!afu_dev->device.driver) { + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); + return 1; + } + + driver = container_of(afu_dev->device.driver, + const struct rte_afu_driver, + driver); + return driver->remove(afu_dev); +} + +static int +rte_ifpga_unplug(struct rte_device *dev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_devargs *devargs = NULL; + int ret; + + if (dev == NULL) + return -EINVAL; + + afu_dev = RTE_DEV_TO_AFU(dev); + if (!dev) + return -ENOENT; + + ifpga_dev = afu_dev->ifpga_dev; + devargs = dev->devargs; + + ret = ifpga_remove_driver(afu_dev); + if (ret) + return ret; + + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); + + TAILQ_REMOVE(&devargs_list, devargs, next); + + free(devargs->args); + free(devargs); + free(afu_dev); + return 0; + +} + +static struct rte_device * +rte_ifpga_find_device(const struct rte_device *start, + rte_dev_cmp_t cmp, const void *data) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev; + + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (start && &afu_dev->device == start) { + start = NULL; + continue; + } + if (cmp(&afu_dev->device, data) == 0) + return &afu_dev->device; + } + } + return NULL; +} +static int +rte_ifpga_parse(const char *name, void *addr) +{ + int *out = addr; + struct rte_rawdev *rawdev = NULL; + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; + char *c1 = NULL, *c2 = NULL; + int port = IFPGA_BUS_DEV_PORT_MAX; + char str_port[8]; + int str_port_len = 0; + + memset(str_port, 0, 8); + c1 = strchr(name, '|'); + if (c1 != NULL) { + str_port_len = c1-name; + c2 = c1+1; + } + + if (str_port_len < 8 && + str_port_len > 0) { + memcpy(str_port, name, str_port_len); + sscanf(str_port, "%d", &port); + } + + memset(rawdev_name, 0, sizeof(rawdev_name)); + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", c2); + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev && + (addr != NULL)) + *out = port; + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev) + return 0; + else + return 1; +} + +struct rte_ifpga_bus rte_ifpga_bus = { + .bus = { + .scan = rte_ifpga_scan, + .probe = rte_ifpga_probe, + .find_device = rte_ifpga_find_device, + .plug = rte_ifpga_plug, + .unplug = rte_ifpga_unplug, + .parse = rte_ifpga_parse, + }, + .ifpga_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.ifpga_list), + .driver_list = TAILQ_HEAD_INITIALIZER(rte_ifpga_bus.driver_list), +}; + +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus.bus); + +RTE_INIT(ifpga_init_log) +{ + ifpga_bus_logtype = rte_log_register("bus.ifpga"); + if (ifpga_bus_logtype >= 0) + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); +} + diff --git a/drivers/bus/ifpga/ifpga_common.c b/drivers/bus/ifpga/ifpga_common.c new file mode 100644 index 0000000..124ffd2 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.c @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(char **)extra_args = strdup(value); + + if (!*(char **)extra_args) + return -ENOMEM; + + return 0; +} +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(int *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(uint64_t *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_unsigned_long(const char *str, int base) +{ + unsigned long num; + char *end = NULL; + + errno = 0; + + num = strtoul(str, &end, base); + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) + return -1; + + return num; + +} +int ifpga_get_bdf_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ +#define MAX_PATH_LEN 1024 + struct rte_pci_addr *addr; + int num[4]; + char str[MAX_PATH_LEN]; + int i, j; + + if (!value || !extra_args) + return -EINVAL; + + addr = (struct rte_pci_addr *)extra_args; + strcpy(str, value); + memset(num, 0, 4 * sizeof(num[0])); + i = strlen(str) - 1; + j = 3; + while (i > 0 && j >= 0) { + while ((str[i - 1] != ':' && str[i - 1] != '.') && i > 0) + i--; + num[j--] = ifpga_get_unsigned_long(&str[i], 16); + i--; + if (i >= 0) + str[i] = '\0'; + } + addr->domain = num[0]; + addr->bus = num[1]; + addr->devid = num[2]; + addr->function = num[3]; + printf("[%s]: bdf %04d:%02d:%02d.%02d\n", + __func__, + addr->domain, + addr->bus, + addr->devid, + addr->function); + + return 0; +} + +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1) +{ + if ((afu_id0->pci_addr.bus == afu_id1->pci_addr.bus) && + (afu_id0->pci_addr.devid == afu_id1->pci_addr.devid) && + (afu_id0->pci_addr.function == afu_id1->pci_addr.function) && + (afu_id0->uuid_low == afu_id1->uuid_low) && + (afu_id0->uuid_high == afu_id1->uuid_high) && + (afu_id0->port == afu_id1->port)) { + return 0; + } else + return 1; +} +int ifpga_pci_addr_cmp(const struct rte_device *dev, + const void *_pci_addr) +{ + struct rte_pci_device *pdev; + const struct rte_pci_addr *paddr = _pci_addr; + + pdev = RTE_DEV_TO_PCI(*(struct rte_device **)(void *)&dev); + return rte_eal_compare_pci_addr(&pdev->addr, paddr); +} diff --git a/drivers/bus/ifpga/ifpga_common.h b/drivers/bus/ifpga/ifpga_common.h new file mode 100644 index 0000000..1c85bd3 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMMON_H_ +#define _IFPGA_COMMON_H_ + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_unsigned_long(const char *str, int base); +int ifpga_get_bdf_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1); +int ifpga_pci_addr_cmp(const struct rte_device *dev, + const void *_pci_addr); + +#endif /* _IFPGA_COMMON_H_ */ diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index 0000000..873e0a4 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_logs.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_LOGS_H_ +#define _IFPGA_LOGS_H_ + +#include <rte_log.h> + +extern int ifpga_bus_logtype; + +#define IFPGA_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") + +#define IFPGA_BUS_DEBUG(fmt, args...) \ + IFPGA_BUS_LOG(DEBUG, fmt, ## args) +#define IFPGA_BUS_INFO(fmt, args...) \ + IFPGA_BUS_LOG(INFO, fmt, ## args) +#define IFPGA_BUS_ERR(fmt, args...) \ + IFPGA_BUS_LOG(ERR, fmt, ## args) +#define IFPGA_BUS_WARN(fmt, args...) \ + IFPGA_BUS_LOG(WARNING, fmt, ## args) + +#endif /* _IFPGA_BUS_LOGS_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h new file mode 100644 index 0000000..e22ab4e --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _RTE_BUS_IFPGA_H_ +#define _RTE_BUS_IFPGA_H_ + +/** + * @file + * + * RTE PCI Bus Interface + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_bus.h> +#include <rte_pci.h> + +/** Name of Intel FPGA Bus */ +#define IFPGA_BUS_NAME ifpga + +/* Forward declarations */ +struct rte_ifpga_device; +struct rte_afu_device; +struct rte_afu_driver; + +/** List of Intel FPGA devices */ +TAILQ_HEAD(rte_ifpga_device_list, rte_ifpga_device); +/** List of Intel AFU devices */ +TAILQ_HEAD(rte_afu_device_list, rte_afu_device); +/** List of AFU drivers */ +TAILQ_HEAD(rte_afu_driver_list, rte_afu_driver); + +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 + +struct rte_afu_uuid { + uint64_t uuid_low; + uint64_t uuid_high; +} __attribute__ ((packed)); + +#define IFPGA_BUS_DEV_PORT_MAX 4 + +/** + * A structure describing an ID for a AFU driver. Each driver provides a + * table of these IDs for each device that it supports. + */ +struct rte_afu_id { + struct rte_pci_addr pci_addr; + uint64_t uuid_low; + uint64_t uuid_high; + int port; +} __attribute__ ((packed)); + +/** + * A structure pr configuration AFU driver. + */ + +struct rte_afu_pr_conf { + struct rte_afu_id afu_id; + int pr_enable; + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +}; + +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) + +/** + * A structure describing a fpga device. + */ +struct rte_ifpga_device { + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ + struct rte_pci_addr pci_addr; + struct rte_rawdev *rdev; + struct rte_afu_device_list afu_list; /**< List of AFU devices */ +}; + +/** + * A structure describing a AFU device. + */ +struct rte_afu_device { + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ + struct rte_device device; /**< Inherit core device */ + struct rte_rawdev *rawdev; /**< Point Rawdev */ + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ + struct rte_afu_id id; /**< AFU id within FPGA. */ + uint32_t num_region; /**< number of regions found */ + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; + /**< PCI Memory Resource */ + struct rte_intr_handle intr_handle; /**< Interrupt handle */ + struct rte_afu_driver *driver; /**< Associated driver */ + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +} __attribute__ ((packed)); + +/** + * @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) + +/** + * Initialisation function for the driver called during PCI probing. + */ +typedef int (afu_probe_t)(struct rte_afu_device *); + +/** + * Uninitialisation function for the driver called during hotplugging. + */ +typedef int (afu_remove_t)(struct rte_afu_device *); + +/** + * A structure describing a PCI device. + */ +struct rte_afu_driver { + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ + struct rte_driver driver; /**< Inherit core driver. */ + afu_probe_t *probe; /**< Device Probe function. */ + afu_remove_t *remove; /**< Device Remove function. */ + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ + uint32_t drv_flags; /**< Flags contolling handling of device. */ +}; + +/** + * Structure describing the Intel FPGA bus + */ +struct rte_ifpga_bus { + struct rte_bus bus; /**< Inherit the generic class */ + struct rte_ifpga_device_list ifpga_list; /**< List of FPGA devices */ + struct rte_afu_driver_list driver_list; /**< List of FPGA drivers */ +}; + +static inline const char * +rte_ifpga_device_name(const struct rte_afu_device *afu) +{ + if (afu && afu->device.name) + return afu->device.name; + return NULL; +} + +extern struct rte_ifpga_bus rte_ifpga_bus; + +/** + * Register a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be registered. + */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver); + +/** + * Unregister a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be unregistered. + */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); + +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ +RTE_INIT(afudrvinitfn_ ##afudrv);\ +static const char *afudrvinit_ ## nm ## _alias;\ +static void afudrvinitfn_ ##afudrv(void)\ +{\ + (afudrv).driver.name = RTE_STR(nm);\ + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ + rte_ifpga_driver_register(&afudrv);\ +} \ +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) + +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ +static const char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) + +#endif /* _RTE_BUS_IFPGA_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map new file mode 100644 index 0000000..4edc9c0 --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map @@ -0,0 +1,8 @@ +DPDK_18.05 { + global: + + rte_ifpga_driver_register; + rte_ifpga_driver_unregister; + + local: *; +}; diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 3eb41d1..929c3d8 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -107,6 +107,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE) += -lrte_cmdline _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrte_sched +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga + ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v4 1/3] Add Intel FPGA BUS Lib Code 2018-03-31 16:03 ` [dpdk-dev] [PATCH v4 1/3] Add Intel FPGA BUS Lib Code Rosen Xu @ 2018-04-03 9:25 ` Shreyansh Jain 2018-04-04 1:44 ` Xu, Rosen 0 siblings, 1 reply; 149+ messages in thread From: Shreyansh Jain @ 2018-04-03 9:25 UTC (permalink / raw) To: Rosen Xu Cc: dev, declan.doherty, bruce.richardson, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet Hello Rosen, On Saturday 31 March 2018 09:33 PM, Rosen Xu wrote: > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > --- > config/common_base | 5 + > drivers/bus/Makefile | 1 + > drivers/bus/ifpga/Makefile | 33 ++ > drivers/bus/ifpga/ifpga_bus.c | 517 ++++++++++++++++++++++++++++ > drivers/bus/ifpga/ifpga_common.c | 141 ++++++++ > drivers/bus/ifpga/ifpga_common.h | 22 ++ > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > drivers/bus/ifpga/rte_bus_ifpga.h | 175 ++++++++++ > drivers/bus/ifpga/rte_bus_ifpga_version.map | 8 + > mk/rte.app.mk | 2 + > 10 files changed, 935 insertions(+) > create mode 100644 drivers/bus/ifpga/Makefile > create mode 100644 drivers/bus/ifpga/ifpga_bus.c > create mode 100644 drivers/bus/ifpga/ifpga_common.c > create mode 100644 drivers/bus/ifpga/ifpga_common.h > create mode 100644 drivers/bus/ifpga/ifpga_logs.h > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map > > diff --git a/config/common_base b/config/common_base > index ad03cf4..49f6b09 100644 > --- a/config/common_base > +++ b/config/common_base > @@ -134,6 +134,11 @@ CONFIG_RTE_LIBRTE_PCI_BUS=y > CONFIG_RTE_LIBRTE_VDEV_BUS=y > > # > +# Compile the Intel FPGA bus > +# > +CONFIG_RTE_LIBRTE_IFPGA_BUS=y > + > +# > # Compile ARK PMD > # > CONFIG_RTE_LIBRTE_ARK_PMD=y > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile > index 7ef2593..55d2dfe 100644 > --- a/drivers/bus/Makefile > +++ b/drivers/bus/Makefile > @@ -7,5 +7,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa > DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga When I attempted to compile the above using SHARED_LIB=y, this is what I got: --->8--- LD librte_bus_ifpga.so.1.1 ifpga_bus.o: In function `rte_ifpga_parse': ifpga_bus.c:(.text+0x2eb): undefined reference to `rte_rawdevs' ifpga_bus.o: In function `rte_ifpga_scan': ifpga_bus.c:(.text+0x53e): undefined reference to `rte_kvargs_parse' ifpga_bus.c:(.text+0x55e): undefined reference to `rte_kvargs_count' ifpga_bus.c:(.text+0x580): undefined reference to `rte_kvargs_process' ifpga_bus.c:(.text+0x5e0): undefined reference to `rte_rawdevs' ifpga_bus.c:(.text+0x746): undefined reference to `rte_kvargs_free' ifpga_bus.c:(.text+0x7b8): undefined reference to `rte_pci_addr_cmp' ifpga_bus.c:(.text+0x858): undefined reference to `rte_kvargs_parse' ifpga_bus.c:(.text+0x878): undefined reference to `rte_kvargs_count' ifpga_bus.c:(.text+0x89c): undefined reference to `rte_kvargs_process' ifpga_bus.c:(.text+0x8b8): undefined reference to `rte_kvargs_count' ifpga_bus.c:(.text+0x8dc): undefined reference to `rte_kvargs_process' ifpga_bus.c:(.text+0x8f8): undefined reference to `rte_kvargs_count' ifpga_bus.c:(.text+0x91c): undefined reference to `rte_kvargs_process' ifpga_bus.c:(.text+0x981): undefined reference to `rte_kvargs_free' ifpga_common.o: In function `ifpga_pci_addr_cmp': ifpga_common.c:(.text+0x2c5): undefined reference to `rte_eal_compare_pci_addr' collect2: error: ld returned 1 exit status /home/shreyansh/build/DPDK/00_dpdk/mk/rte.lib.mk:98: recipe for target 'librte_bus_ifpga.so.1.1' failed make[6]: *** [librte_bus_ifpga.so.1.1] Error 1 /home/shreyansh/build/DPDK/00_dpdk/mk/rte.subdir.mk:35: recipe for target 'ifpga' failed make[5]: *** [ifpga] Error 2 --->8--- Essentially, you are dependent on librte_kvargs but you have not declared that in your Makefile. Same for lib_rawdev. > > include $(RTE_SDK)/mk/rte.subdir.mk > diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile > new file mode 100644 > index 0000000..1b569af > --- /dev/null > +++ b/drivers/bus/ifpga/Makefile > @@ -0,0 +1,33 @@ > +# SPDX-License-Identifier: BSD-3-Clause > +# Copyright(c) 2018 Intel Corporation > + > +include $(RTE_SDK)/mk/rte.vars.mk > + > +# > +# library name > +# > +LIB = librte_bus_ifpga.a > + > +CFLAGS += -O3 > +CFLAGS += $(WERROR_FLAGS) > + > +# versioning export map > +EXPORT_MAP := rte_bus_ifpga_version.map > + > +# library version > +LIBABIVER := 1 > + > +VPATH += $(SRCDIR)/base > + > +SRCS-y += \ > + ifpga_bus.c \ > + ifpga_common.c > + > +LDLIBS += -lrte_eal > + > +# > +# Export include files > +# > +SYMLINK-y-include += rte_bus_ifpga.h > + > +include $(RTE_SDK)/mk/rte.lib.mk > diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c > new file mode 100644 > index 0000000..eba2615 > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_bus.c > @@ -0,0 +1,517 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation > + */ > + [...] > + > + if (rawdev->dev_ops && > + rawdev->dev_ops->dev_start && > + rawdev->dev_ops->dev_start(rawdev)) > + goto free_dev; > + if (path) { > + strncpy(afu_pr_conf.bs_path, path, strlen(path)); strncpy with demarcation based on source is not right. strlen(path) can be larger than afu_pr_conf.bs_path I saw some comment from Gaetan in previous version, if I recall correctly. > + if (rawdev->dev_ops->firmware_load && > + rawdev->dev_ops->firmware_load(rawdev, > + &afu_pr_conf)){ > + printf("firmware load error %d\n", ret); > + goto free_dev; > + } > + afu_dev->id.uuid_low = afu_pr_conf.afu_id.uuid_low; > + afu_dev->id.uuid_high = afu_pr_conf.afu_id.uuid_high; > + } > + > + return afu_dev; > + > +free_dev: > + free(afu_dev); > +end: > + if (kvlist) > + rte_kvargs_free(kvlist); > + if (path) > + free(path); > + > + return NULL; > +} > + > +/* > + * Scan the content of the FPGA bus, and the devices in the devices > + * list > + */ > +static int > +rte_ifpga_scan(void) > +{ [...] > + > +static int > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) > +{ > + struct rte_afu_driver *drv = NULL; > + int rc; > + > + if (afu_dev == NULL) > + return -1; > + > + /* Check if a driver is already loaded */ > + if (afu_dev->driver != NULL) > + return 0; > + > + TAILQ_FOREACH(drv, &rte_ifpga_bus.driver_list, next) { > + rc = ifpga_probe_one_driver(drv, afu_dev); > + if (rc < 0) > + /* negative value is an error */ > + return -1; > + if (rc > 0) > + /* positive value means driver doesn't support it */ > + continue; > + return 0; > + } > + return 1; > +} > + > +/* > + * Scan the content of the PCI bus, and call the probe() function for I think you are not moving on PCI bus elements. You are looping on rte_ifpga_bus. > + * all registered drivers that have a matching entry in its id_table > + * for discovered devices. > + */ > +static int > +rte_ifpga_probe(void) > +{ > + struct rte_ifpga_device *ifpga_dev; > + struct rte_afu_device *afu_dev = NULL; > + int ret = 0; > + > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > + > + if (afu_dev->device.driver) > + continue; > + > + ret = ifpga_probe_all_drivers(afu_dev); > + if (ret < 0) > + IFPGA_BUS_ERR("failed to initialize %s device\n", > + rte_ifpga_device_name(afu_dev)); > + } > + } > + > + return 0; > +} > + [...] > diff --git a/drivers/bus/ifpga/ifpga_common.c b/drivers/bus/ifpga/ifpga_common.c > new file mode 100644 > index 0000000..124ffd2 > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_common.c > @@ -0,0 +1,141 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation > + */ > + [...] > + > +} > +int ifpga_get_bdf_arg(const char *key __rte_unused, > + const char *value, void *extra_args) > +{ > +#define MAX_PATH_LEN 1024 Is this max len of a file path or a max len of the value string (BDF). Can you rename this? Just a trivial comment, though. [...] > diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h > new file mode 100644 > index 0000000..873e0a4 > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_logs.h > @@ -0,0 +1,31 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation > + */ > + > +#ifndef _IFPGA_LOGS_H_ > +#define _IFPGA_LOGS_H_ > + > +#include <rte_log.h> > + > +extern int ifpga_bus_logtype; > + > +#define IFPGA_LOG(level, fmt, args...) \ > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > + __func__, ##args) I don't see macro above being used. Would you be using this in later patches? (But, i think they might have their own logging definitions). > + > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > + __func__, ##args) > + > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > + > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) > +#define IFPGA_BUS_INFO(fmt, args...) \ > + IFPGA_BUS_LOG(INFO, fmt, ## args) > +#define IFPGA_BUS_ERR(fmt, args...) \ > + IFPGA_BUS_LOG(ERR, fmt, ## args) > +#define IFPGA_BUS_WARN(fmt, args...) \ > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > + > +#endif /* _IFPGA_BUS_LOGS_H_ */ > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h > new file mode 100644 > index 0000000..e22ab4e > --- /dev/null > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > @@ -0,0 +1,175 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation > + */ > + > +#ifndef _RTE_BUS_IFPGA_H_ > +#define _RTE_BUS_IFPGA_H_ > + > +/** > + * @file > + * > + * RTE PCI Bus Interface This is not a "RTE PCI Bus Interface" - It should be AFU/IFPA Bus interface file There are some comments which were given in early versions. Like this one. Please do respond to those individually if you are not fixing them. (Also, it is nice to get acknowledgment of those which are being fixed). > + */ > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include <rte_bus.h> > +#include <rte_pci.h> > + > +/** Name of Intel FPGA Bus */ > +#define IFPGA_BUS_NAME ifpga > + > +/* Forward declarations */ > +struct rte_ifpga_device; > +struct rte_afu_device; > +struct rte_afu_driver; > + > +/** List of Intel FPGA devices */ > +TAILQ_HEAD(rte_ifpga_device_list, rte_ifpga_device); > +/** List of Intel AFU devices */ > +TAILQ_HEAD(rte_afu_device_list, rte_afu_device); > +/** List of AFU drivers */ > +TAILQ_HEAD(rte_afu_driver_list, rte_afu_driver); > + > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > + > +struct rte_afu_uuid { > + uint64_t uuid_low; > + uint64_t uuid_high; > +} __attribute__ ((packed)); > + > +#define IFPGA_BUS_DEV_PORT_MAX 4 > + > +/** > + * A structure describing an ID for a AFU driver. Each driver provides a > + * table of these IDs for each device that it supports. > + */ > +struct rte_afu_id { > + struct rte_pci_addr pci_addr; > + uint64_t uuid_low; > + uint64_t uuid_high; > + int port; > +} __attribute__ ((packed)); > + > +/** > + * A structure pr configuration AFU driver. > + */ > + > +struct rte_afu_pr_conf { > + struct rte_afu_id afu_id; > + int pr_enable; > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; ^^^^^^^^^^^ Some stray indentation issue, it seems > +}; > + > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > + > +/** > + * A structure describing a fpga device. > + */ > +struct rte_ifpga_device { > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ > + struct rte_pci_addr pci_addr; > + struct rte_rawdev *rdev; > + struct rte_afu_device_list afu_list; /**< List of AFU devices */ > +}; > + > +/** > + * A structure describing a AFU device. > + */ > +struct rte_afu_device { > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ > + struct rte_device device; /**< Inherit core device */ > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > + struct rte_afu_id id; /**< AFU id within FPGA. */ > + uint32_t num_region; /**< number of regions found */ > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > + /**< PCI Memory Resource */ > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > + struct rte_afu_driver *driver; /**< Associated driver */ > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > +} __attribute__ ((packed)); > + > +/** > + * @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) > + > +/** > + * Initialisation function for the driver called during PCI probing. PCI Probing would have already been done through the PCI bus. I think this is probing of the AFU devices (based on the PCI already probed). > + */ > +typedef int (afu_probe_t)(struct rte_afu_device *); > + > +/** > + * Uninitialisation function for the driver called during hotplugging. > + */ > +typedef int (afu_remove_t)(struct rte_afu_device *); > + > +/** > + * A structure describing a PCI device. ^^^^ Structure describing an AFU device. > + */ > +struct rte_afu_driver { > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > + struct rte_driver driver; /**< Inherit core driver. */ > + afu_probe_t *probe; /**< Device Probe function. */ > + afu_remove_t *remove; /**< Device Remove function. */ > + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ > + uint32_t drv_flags; /**< Flags contolling handling of device. */ > +}; > + > +/** > + * Structure describing the Intel FPGA bus > + */ > +struct rte_ifpga_bus { > + struct rte_bus bus; /**< Inherit the generic class */ > + struct rte_ifpga_device_list ifpga_list; /**< List of FPGA devices */ > + struct rte_afu_driver_list driver_list; /**< List of FPGA drivers */ > +}; > + > +static inline const char * > +rte_ifpga_device_name(const struct rte_afu_device *afu) > +{ > + if (afu && afu->device.name) > + return afu->device.name; > + return NULL; > +} > + > +extern struct rte_ifpga_bus rte_ifpga_bus; > + > +/** > + * Register a ifpga afu device driver. > + * > + * @param driver > + * A pointer to a rte_afu_driver structure describing the driver > + * to be registered. > + */ > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); > + > +/** > + * Unregister a ifpga afu device driver. > + * > + * @param driver > + * A pointer to a rte_afu_driver structure describing the driver > + * to be unregistered. > + */ > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > + > +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ > +RTE_INIT(afudrvinitfn_ ##afudrv);\ > +static const char *afudrvinit_ ## nm ## _alias;\ > +static void afudrvinitfn_ ##afudrv(void)\ > +{\ > + (afudrv).driver.name = RTE_STR(nm);\ > + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ > + rte_ifpga_driver_register(&afudrv);\ > +} \ > +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) > + > +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ > +static const char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) > + > +#endif /* _RTE_BUS_IFPGA_H_ */ > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map > new file mode 100644 > index 0000000..4edc9c0 > --- /dev/null > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > @@ -0,0 +1,8 @@ > +DPDK_18.05 { > + global: > + > + rte_ifpga_driver_register; > + rte_ifpga_driver_unregister; Should be tab indented > + > + local: *; > +}; [...] One suggestion: I think a lot of comments were provided by Gaetan in the previous version. I see some that some of them are still not fixed in this version. I suggest you individually reply to his comments if you are not going to fix, with reason. He put quite an effort to go through your patches. That would help you track comments as well as not discount a reviewers effort. - Shreyansh ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v4 1/3] Add Intel FPGA BUS Lib Code 2018-04-03 9:25 ` Shreyansh Jain @ 2018-04-04 1:44 ` Xu, Rosen 0 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-04-04 1:44 UTC (permalink / raw) To: Shreyansh Jain Cc: dev, Doherty, Declan, Richardson, Bruce, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Wu, Hao, gaetan.rivet Hello Shreyansh, > -----Original Message----- > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > Sent: Tuesday, April 03, 2018 17:25 > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; Yigit, Ferruh > <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Wu, Hao <hao.wu@intel.com>; gaetan.rivet@6wind.com > Subject: Re: [dpdk-dev] [PATCH v4 1/3] Add Intel FPGA BUS Lib Code > > Hello Rosen, > > On Saturday 31 March 2018 09:33 PM, Rosen Xu wrote: > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > --- > > config/common_base | 5 + > > drivers/bus/Makefile | 1 + > > drivers/bus/ifpga/Makefile | 33 ++ > > drivers/bus/ifpga/ifpga_bus.c | 517 > ++++++++++++++++++++++++++++ > > drivers/bus/ifpga/ifpga_common.c | 141 ++++++++ > > drivers/bus/ifpga/ifpga_common.h | 22 ++ > > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > > drivers/bus/ifpga/rte_bus_ifpga.h | 175 ++++++++++ > > drivers/bus/ifpga/rte_bus_ifpga_version.map | 8 + > > mk/rte.app.mk | 2 + > > 10 files changed, 935 insertions(+) > > create mode 100644 drivers/bus/ifpga/Makefile > > create mode 100644 drivers/bus/ifpga/ifpga_bus.c > > create mode 100644 drivers/bus/ifpga/ifpga_common.c > > create mode 100644 drivers/bus/ifpga/ifpga_common.h > > create mode 100644 drivers/bus/ifpga/ifpga_logs.h > > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h > > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > diff --git a/config/common_base b/config/common_base index > > ad03cf4..49f6b09 100644 > > --- a/config/common_base > > +++ b/config/common_base > > @@ -134,6 +134,11 @@ CONFIG_RTE_LIBRTE_PCI_BUS=y > > CONFIG_RTE_LIBRTE_VDEV_BUS=y > > > > # > > +# Compile the Intel FPGA bus > > +# > > +CONFIG_RTE_LIBRTE_IFPGA_BUS=y > > + > > +# > > # Compile ARK PMD > > # > > CONFIG_RTE_LIBRTE_ARK_PMD=y > > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index > > 7ef2593..55d2dfe 100644 > > --- a/drivers/bus/Makefile > > +++ b/drivers/bus/Makefile > > @@ -7,5 +7,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa > > DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc > > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > > When I attempted to compile the above using SHARED_LIB=y, this is what I > got: > > --->8--- > LD librte_bus_ifpga.so.1.1 > ifpga_bus.o: In function `rte_ifpga_parse': > ifpga_bus.c:(.text+0x2eb): undefined reference to `rte_rawdevs' > ifpga_bus.o: In function `rte_ifpga_scan': > ifpga_bus.c:(.text+0x53e): undefined reference to `rte_kvargs_parse' > ifpga_bus.c:(.text+0x55e): undefined reference to `rte_kvargs_count' > ifpga_bus.c:(.text+0x580): undefined reference to `rte_kvargs_process' > ifpga_bus.c:(.text+0x5e0): undefined reference to `rte_rawdevs' > ifpga_bus.c:(.text+0x746): undefined reference to `rte_kvargs_free' > ifpga_bus.c:(.text+0x7b8): undefined reference to `rte_pci_addr_cmp' > ifpga_bus.c:(.text+0x858): undefined reference to `rte_kvargs_parse' > ifpga_bus.c:(.text+0x878): undefined reference to `rte_kvargs_count' > ifpga_bus.c:(.text+0x89c): undefined reference to `rte_kvargs_process' > ifpga_bus.c:(.text+0x8b8): undefined reference to `rte_kvargs_count' > ifpga_bus.c:(.text+0x8dc): undefined reference to `rte_kvargs_process' > ifpga_bus.c:(.text+0x8f8): undefined reference to `rte_kvargs_count' > ifpga_bus.c:(.text+0x91c): undefined reference to `rte_kvargs_process' > ifpga_bus.c:(.text+0x981): undefined reference to `rte_kvargs_free' > ifpga_common.o: In function `ifpga_pci_addr_cmp': > ifpga_common.c:(.text+0x2c5): undefined reference to > `rte_eal_compare_pci_addr' > collect2: error: ld returned 1 exit status > /home/shreyansh/build/DPDK/00_dpdk/mk/rte.lib.mk:98: recipe for target > 'librte_bus_ifpga.so.1.1' failed > make[6]: *** [librte_bus_ifpga.so.1.1] Error 1 > /home/shreyansh/build/DPDK/00_dpdk/mk/rte.subdir.mk:35: recipe for > target 'ifpga' failed > make[5]: *** [ifpga] Error 2 > --->8--- I have fixed it to modify Makefile in my PATCH v5. > Essentially, you are dependent on librte_kvargs but you have not declared > that in your Makefile. Same for lib_rawdev. I have declared it in my PATCH v5. > > > > include $(RTE_SDK)/mk/rte.subdir.mk > > diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile > > new file mode 100644 index 0000000..1b569af > > --- /dev/null > > +++ b/drivers/bus/ifpga/Makefile > > @@ -0,0 +1,33 @@ > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > > +Corporation > > + > > +include $(RTE_SDK)/mk/rte.vars.mk > > + > > +# > > +# library name > > +# > > +LIB = librte_bus_ifpga.a > > + > > +CFLAGS += -O3 > > +CFLAGS += $(WERROR_FLAGS) > > + > > +# versioning export map > > +EXPORT_MAP := rte_bus_ifpga_version.map > > + > > +# library version > > +LIBABIVER := 1 > > + > > +VPATH += $(SRCDIR)/base > > + > > +SRCS-y += \ > > + ifpga_bus.c \ > > + ifpga_common.c > > + > > +LDLIBS += -lrte_eal > > + > > +# > > +# Export include files > > +# > > +SYMLINK-y-include += rte_bus_ifpga.h > > + > > +include $(RTE_SDK)/mk/rte.lib.mk > > diff --git a/drivers/bus/ifpga/ifpga_bus.c > > b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index > > 0000000..eba2615 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_bus.c > > @@ -0,0 +1,517 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > [...] > > > + > > + if (rawdev->dev_ops && > > + rawdev->dev_ops->dev_start && > > + rawdev->dev_ops->dev_start(rawdev)) > > + goto free_dev; > > + if (path) { > > + strncpy(afu_pr_conf.bs_path, path, strlen(path)); > > strncpy with demarcation based on source is not right. strlen(path) can be > larger than afu_pr_conf.bs_path I have changed to destination string in PATCH v5. > I saw some comment from Gaetan in previous version, if I recall correctly. > > > + if (rawdev->dev_ops->firmware_load && > > + rawdev->dev_ops->firmware_load(rawdev, > > + &afu_pr_conf)){ > > + printf("firmware load error %d\n", ret); > > + goto free_dev; > > + } > > + afu_dev->id.uuid_low = afu_pr_conf.afu_id.uuid_low; > > + afu_dev->id.uuid_high = afu_pr_conf.afu_id.uuid_high; > > + } > > + > > + return afu_dev; > > + > > +free_dev: > > + free(afu_dev); > > +end: > > + if (kvlist) > > + rte_kvargs_free(kvlist); > > + if (path) > > + free(path); > > + > > + return NULL; > > +} > > + > > +/* > > + * Scan the content of the FPGA bus, and the devices in the devices > > + * list > > + */ > > +static int > > +rte_ifpga_scan(void) > > +{ > > [...] > > > + > > +static int > > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) { > > + struct rte_afu_driver *drv = NULL; > > + int rc; > > + > > + if (afu_dev == NULL) > > + return -1; > > + > > + /* Check if a driver is already loaded */ > > + if (afu_dev->driver != NULL) > > + return 0; > > + > > + TAILQ_FOREACH(drv, &rte_ifpga_bus.driver_list, next) { > > + rc = ifpga_probe_one_driver(drv, afu_dev); > > + if (rc < 0) > > + /* negative value is an error */ > > + return -1; > > + if (rc > 0) > > + /* positive value means driver doesn't support it */ > > + continue; > > + return 0; > > + } > > + return 1; > > +} > > + > > +/* > > + * Scan the content of the PCI bus, and call the probe() function for > > I think you are not moving on PCI bus elements. You are looping on > rte_ifpga_bus. I have modified all PCI bus elements to FPGA BUS in my PATCH v5. > > + * all registered drivers that have a matching entry in its id_table > > + * for discovered devices. > > + */ > > +static int > > +rte_ifpga_probe(void) > > +{ > > + struct rte_ifpga_device *ifpga_dev; > > + struct rte_afu_device *afu_dev = NULL; > > + int ret = 0; > > + > > + TAILQ_FOREACH(ifpga_dev, &rte_ifpga_bus.ifpga_list, next) { > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > + > > + if (afu_dev->device.driver) > > + continue; > > + > > + ret = ifpga_probe_all_drivers(afu_dev); > > + if (ret < 0) > > + IFPGA_BUS_ERR("failed to initialize %s > device\n", > > + rte_ifpga_device_name(afu_dev)); > > + } > > + } > > + > > + return 0; > > +} > > + > > [...] > > > diff --git a/drivers/bus/ifpga/ifpga_common.c > > b/drivers/bus/ifpga/ifpga_common.c > > new file mode 100644 > > index 0000000..124ffd2 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_common.c > > @@ -0,0 +1,141 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > [...] > > > + > > +} > > +int ifpga_get_bdf_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) { #define MAX_PATH_LEN 1024 > > Is this max len of a file path or a max len of the value string (BDF). > Can you rename this? I will rename it to IFPGA_MAX_BDF_LEN in my PATCH v5. > Just a trivial comment, though. > > [...] > > > diff --git a/drivers/bus/ifpga/ifpga_logs.h > > b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index > > 0000000..873e0a4 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_logs.h > > @@ -0,0 +1,31 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > +#ifndef _IFPGA_LOGS_H_ > > +#define _IFPGA_LOGS_H_ > > + > > +#include <rte_log.h> > > + > > +extern int ifpga_bus_logtype; > > + > > +#define IFPGA_LOG(level, fmt, args...) \ > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > + __func__, ##args) > > I don't see macro above being used. Would you be using this in later patches? > (But, i think they might have their own logging definitions). Yes, they will be used in later patches. For FPGA BUS is a common module, so we need to provide all macros will be used. > > + > > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > + __func__, ##args) > > + > > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > > + > > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) > > +#define IFPGA_BUS_INFO(fmt, args...) \ > > + IFPGA_BUS_LOG(INFO, fmt, ## args) > > +#define IFPGA_BUS_ERR(fmt, args...) \ > > + IFPGA_BUS_LOG(ERR, fmt, ## args) > > +#define IFPGA_BUS_WARN(fmt, args...) \ > > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > > + > > +#endif /* _IFPGA_BUS_LOGS_H_ */ > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h > > b/drivers/bus/ifpga/rte_bus_ifpga.h > > new file mode 100644 > > index 0000000..e22ab4e > > --- /dev/null > > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > > @@ -0,0 +1,175 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > +#ifndef _RTE_BUS_IFPGA_H_ > > +#define _RTE_BUS_IFPGA_H_ > > + > > +/** > > + * @file > > + * > > + * RTE PCI Bus Interface > > This is not a "RTE PCI Bus Interface" - It should be AFU/IFPA Bus interface file I will modify it in PATCH v5. > There are some comments which were given in early versions. Like this one. > Please do respond to those individually if you are not fixing them. > (Also, it is nice to get acknowledgment of those which are being fixed). I have fix those comments and I also will reply it to those individually. > > + */ > > + > > +#ifdef __cplusplus > > +extern "C" { > > +#endif > > + > > +#include <rte_bus.h> > > +#include <rte_pci.h> > > + > > +/** Name of Intel FPGA Bus */ > > +#define IFPGA_BUS_NAME ifpga > > + > > +/* Forward declarations */ > > +struct rte_ifpga_device; > > +struct rte_afu_device; > > +struct rte_afu_driver; > > + > > +/** List of Intel FPGA devices */ > > +TAILQ_HEAD(rte_ifpga_device_list, rte_ifpga_device); > > +/** List of Intel AFU devices */ > > +TAILQ_HEAD(rte_afu_device_list, rte_afu_device); > > +/** List of AFU drivers */ > > +TAILQ_HEAD(rte_afu_driver_list, rte_afu_driver); > > + > > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > > + > > +struct rte_afu_uuid { > > + uint64_t uuid_low; > > + uint64_t uuid_high; > > +} __attribute__ ((packed)); > > + > > +#define IFPGA_BUS_DEV_PORT_MAX 4 > > + > > +/** > > + * A structure describing an ID for a AFU driver. Each driver > > +provides a > > + * table of these IDs for each device that it supports. > > + */ > > +struct rte_afu_id { > > + struct rte_pci_addr pci_addr; > > + uint64_t uuid_low; > > + uint64_t uuid_high; > > + int port; > > +} __attribute__ ((packed)); > > + > > +/** > > + * A structure pr configuration AFU driver. > > + */ > > + > > +struct rte_afu_pr_conf { > > + struct rte_afu_id afu_id; > > + int pr_enable; > > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > ^^^^^^^^^^^ > Some stray indentation issue, it seems Do you means to change it to: char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN];? If so I have fixed it in my PATCH v5. > > +}; > > + > > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > > + > > +/** > > + * A structure describing a fpga device. > > + */ > > +struct rte_ifpga_device { > > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ > > + struct rte_pci_addr pci_addr; > > + struct rte_rawdev *rdev; > > + struct rte_afu_device_list afu_list; /**< List of AFU devices */ }; > > + > > +/** > > + * A structure describing a AFU device. > > + */ > > +struct rte_afu_device { > > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ > > + struct rte_device device; /**< Inherit core device */ > > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > > + struct rte_afu_id id; /**< AFU id within FPGA. */ > > + uint32_t num_region; /**< number of regions found */ > > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > > + /**< PCI Memory Resource > */ > > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > > + struct rte_afu_driver *driver; /**< Associated driver */ > > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > +} __attribute__ ((packed)); > > + > > +/** > > + * @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) > > + > > +/** > > + * Initialisation function for the driver called during PCI probing. > > PCI Probing would have already been done through the PCI bus. I think this is > probing of the AFU devices (based on the PCI already probed). rte_ifpga_plug()/rte_ifpga_unplug() will use this macro. > > + */ > > +typedef int (afu_probe_t)(struct rte_afu_device *); > > + > > +/** > > + * Uninitialisation function for the driver called during hotplugging. > > + */ > > +typedef int (afu_remove_t)(struct rte_afu_device *); > > + > > +/** > > + * A structure describing a PCI device. > ^^^^ > Structure describing an AFU device. Yes, it should be AFU device, and I have fixed it in my PATCH v5. > > + */ > > +struct rte_afu_driver { > > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > > + struct rte_driver driver; /**< Inherit core driver. */ > > + afu_probe_t *probe; /**< Device Probe function. */ > > + afu_remove_t *remove; /**< Device Remove function. */ > > + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ > > + uint32_t drv_flags; /**< Flags contolling handling of device. */ > > +}; > > + > > +/** > > + * Structure describing the Intel FPGA bus */ struct rte_ifpga_bus { > > + struct rte_bus bus; /**< Inherit the generic class */ > > + struct rte_ifpga_device_list ifpga_list; /**< List of FPGA devices */ > > + struct rte_afu_driver_list driver_list; /**< List of FPGA drivers > > +*/ }; > > + > > +static inline const char * > > +rte_ifpga_device_name(const struct rte_afu_device *afu) { > > + if (afu && afu->device.name) > > + return afu->device.name; > > + return NULL; > > +} > > + > > +extern struct rte_ifpga_bus rte_ifpga_bus; > > + > > +/** > > + * Register a ifpga afu device driver. > > + * > > + * @param driver > > + * A pointer to a rte_afu_driver structure describing the driver > > + * to be registered. > > + */ > > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); > > + > > +/** > > + * Unregister a ifpga afu device driver. > > + * > > + * @param driver > > + * A pointer to a rte_afu_driver structure describing the driver > > + * to be unregistered. > > + */ > > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > > + > > +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ RTE_INIT(afudrvinitfn_ > > +##afudrv);\ static const char *afudrvinit_ ## nm ## _alias;\ static > > +void afudrvinitfn_ ##afudrv(void)\ {\ > > + (afudrv).driver.name = RTE_STR(nm);\ > > + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ > > + rte_ifpga_driver_register(&afudrv);\ > > +} \ > > +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) > > + > > +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ static const char > > +*afudrvinit_ ## nm ## _alias = RTE_STR(alias) > > + > > +#endif /* _RTE_BUS_IFPGA_H_ */ > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map > > b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > new file mode 100644 > > index 0000000..4edc9c0 > > --- /dev/null > > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > @@ -0,0 +1,8 @@ > > +DPDK_18.05 { > > + global: > > + > > + rte_ifpga_driver_register; > > + rte_ifpga_driver_unregister; > > Should be tab indented Yes, I will fix them. > > + > > + local: *; > > +}; > > [...] > > One suggestion: > > I think a lot of comments were provided by Gaetan in the previous version. I > see some that some of them are still not fixed in this version. > > I suggest you individually reply to his comments if you are not going to fix, > with reason. He put quite an effort to go through your patches. > > That would help you track comments as well as not discount a reviewers > effort. OK, I will individually reply to Gaetan's comments. > - > Shreyansh ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev Driver 2018-03-31 16:02 ` [dpdk-dev] [PATCH v4 0/3] " Rosen Xu 2018-03-31 16:03 ` [dpdk-dev] [PATCH v4 1/3] Add Intel FPGA BUS Lib Code Rosen Xu @ 2018-03-31 16:03 ` Rosen Xu 2018-04-03 9:34 ` Shreyansh Jain 2018-03-31 16:03 ` [dpdk-dev] [PATCH v4 3/3] Add Intel FPGA OPAE Share Code Rosen Xu 2 siblings, 1 reply; 149+ messages in thread From: Rosen Xu @ 2018-03-31 16:03 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet, Yanglong Wu Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> --- config/common_base | 1 + drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 34 ++ drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 594 +++++++++++++++++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + mk/rte.app.mk | 1 + 7 files changed, 672 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map diff --git a/config/common_base b/config/common_base index 49f6b09..08b7cce 100644 --- a/config/common_base +++ b/config/common_base @@ -137,6 +137,7 @@ CONFIG_RTE_LIBRTE_VDEV_BUS=y # Compile the Intel FPGA bus # CONFIG_RTE_LIBRTE_IFPGA_BUS=y +CONFIG_RTE_LIBRTE_IFPGA_RAWDEV=y # # Compile ARK PMD diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index da7c8b4..6fc8f2f 100644 --- a/drivers/raw/Makefile +++ b/drivers/raw/Makefile @@ -5,5 +5,6 @@ include $(RTE_SDK)/mk/rte.vars.mk # DIRS-$(<configuration>) += <directory> DIRS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += skeleton_rawdev +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/raw/ifpga_rawdev/Makefile b/drivers/raw/ifpga_rawdev/Makefile new file mode 100644 index 0000000..118c729 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/Makefile @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_ifpga_rawdev.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_bus_vdev +LDLIBS += -lrte_kvargs + +EXPORT_MAP := rte_ifpga_rawdev_version.map + +LIBABIVER := 1 + +VPATH += $(SRCDIR)/base + +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c new file mode 100644 index 0000000..e46c014 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c @@ -0,0 +1,594 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <rte_log.h> +#include <rte_bus.h> +#include <rte_eal_memconfig.h> +#include <rte_malloc.h> +#include <rte_devargs.h> +#include <rte_memcpy.h> +#include <rte_ethdev.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include <rte_errno.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> +#include <rte_bus_vdev.h> + +#include "base/opae_hw_api.h" +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_common.h" +#include "ifpga_logs.h" +#include "ifpga_rawdev.h" + +int ifpga_rawdev_logtype; + +#define PCI_VENDOR_ID_INTEL 0x8086 +/* PCI Device ID */ +#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 +/* 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 RTE_MAX_RAW_DEVICE 10 + +static const struct rte_pci_id pci_ifpga_map[] = { + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_6_X) }, + { 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) }, + { .vendor_id = 0, /* sentinel */ }, +}; + +static int ifpga_fill_afu_dev(struct opae_accelerator *acc, + struct rte_afu_device *afu_dev) +{ + struct rte_mem_resource *res = afu_dev->mem_resource; + struct opae_acc_region_info region_info; + struct opae_acc_info info; + unsigned long i; + int ret; + + ret = opae_acc_get_info(acc, &info); + if (ret) + return ret; + + if (info.num_regions > PCI_MAX_RESOURCE) + return -EFAULT; + + afu_dev->num_region = info.num_regions; + + for (i = 0; i < info.num_regions; i++) { + region_info.index = i; + ret = opae_acc_get_region_info(acc, ®ion_info); + if (ret) + return ret; + + if ((region_info.flags & ACC_REGION_MMIO) && + (region_info.flags & ACC_REGION_READ) && + (region_info.flags & ACC_REGION_WRITE)) { + res[i].phys_addr = region_info.phys_addr; + res[i].len = region_info.len; + res[i].addr = region_info.addr; + } else + return -EFAULT; + } + + return 0; +} + +static void ifpga_rawdev_info_get(struct rte_rawdev *dev, + rte_rawdev_obj_t dev_info) +{ + struct opae_adapter *adapter; + struct opae_accelerator *acc; + struct rte_afu_device *afu_dev; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + if (!dev_info) { + IFPGA_RAWDEV_PMD_ERR("Invalid request"); + return; + } + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return; + + afu_dev = dev_info; + afu_dev->rawdev = dev; + + /* find opae_accelerator and fill info into afu_device */ + opae_adapter_for_each_acc(adapter, acc) { + if (acc->index != afu_dev->id.port) + continue; + + if (ifpga_fill_afu_dev(acc, afu_dev)) { + IFPGA_RAWDEV_PMD_ERR("cannot get info\n"); + return; + } + } +} + +static int ifpga_rawdev_start(struct rte_rawdev *dev) +{ + int ret = 0; + struct opae_adapter *adapter; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + return ret; +} + +static void ifpga_rawdev_stop(struct rte_rawdev *dev) +{ + dev->started = 0; +} + +static int ifpga_rawdev_close(struct rte_rawdev *dev) +{ + if (!dev) + return 1; + else + return 0; +} + +static int ifpga_rawdev_reset(struct rte_rawdev *dev) +{ + if (!dev) + return 1; + else + return 0; +} + +static int +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, + u64 *status){ + + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_accelerator *acc; + struct opae_bridge *br; + int ret; + + adapter = ifpga_rawdev_get_priv(raw_dev); + if (!adapter) + return -ENODEV; + + mgr = opae_adapter_get_mgr(adapter); + if (!mgr) + return -ENODEV; + + acc = opae_adapter_get_acc(adapter, port_id); + if (!acc) + return -ENODEV; + + br = opae_acc_get_br(acc); + if (!br) + return -ENODEV; + + ret = opae_manager_flash(mgr, port_id, buffer, size, status); + if (ret) { + printf("%s pr error %d\n", __func__, ret); + return ret; + } + + usleep(100); + ret = opae_bridge_reset(br); + if (ret) { + printf("%s reset port:%d error %d\n", __func__, port_id, ret); + return ret; + } + + return ret; +} + +static int rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, + const char *file_name) +{ + struct stat file_stat; + int file_fd; + int ret = 0; + u32 buffer_size; + void *buffer; + u64 pr_error; + + if (!file_name) + return -EINVAL; + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + printf("%s: open file error: %s\n", __func__, file_name); + printf("Message : %s\n", strerror(errno)); + return -EINVAL; + } + ret = stat(file_name, &file_stat); + if (ret) { + printf("stat on bitstream file failed: %s\n", file_name); + return -EINVAL; + } + buffer_size = file_stat.st_size; + printf("bitstream file size: %u\n", buffer_size); + buffer = rte_malloc(NULL, buffer_size, 0); + if (!buffer) { + ret = -ENOMEM; + goto close_fd; + } + + /*read the raw data*/ + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { + ret = -EINVAL; + goto free_buffer; + } + + /*do PR now*/ + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); + printf("downloading to device port %d....%s.\n", port_id, + ret ? "failed" : "success"); + if (ret) { + ret = -EINVAL; + //raw_dev->ops->show_pr_error(pr_error); + goto free_buffer; + } + +free_buffer: + if (buffer) + rte_free(buffer); +close_fd: + close(file_fd); + file_fd = 0; + return ret; +} + +static int ifpga_rawdev_pr(struct rte_rawdev *dev, + rte_rawdev_obj_t pr_conf) +{ + struct opae_adapter *adapter; + struct rte_afu_pr_conf *afu_pr_conf; + int ret; + struct uuid uuid; + struct opae_accelerator *acc; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + if (!pr_conf) + return -EINVAL; + + afu_pr_conf = pr_conf; + + ret = rte_fpga_do_pr(dev, afu_pr_conf->afu_id.port, + afu_pr_conf->bs_path); + if (ret) { + printf("do pr error %d\n", ret); + return ret; + } + + acc = opae_adapter_get_acc(adapter, afu_pr_conf->afu_id.port); + if (!acc) + return -ENODEV; + + ret = opae_acc_get_uuid(acc, &uuid); + if (ret) + return ret; + + memcpy(&afu_pr_conf->afu_id.uuid_low, uuid.b, sizeof(u64)); + memcpy(&afu_pr_conf->afu_id.uuid_high, uuid.b + 8, sizeof(64)); + + printf("%s: uuid_l=0x%lx, uuid_h=0x%lx\n", __func__, + (u64)afu_pr_conf->afu_id.uuid_low, + (u64)afu_pr_conf->afu_id.uuid_high); + + return 0; +} + +static const struct rte_rawdev_ops ifpga_rawdev_ops = { + .dev_info_get = ifpga_rawdev_info_get, + .dev_configure = NULL, + .dev_start = ifpga_rawdev_start, + .dev_stop = ifpga_rawdev_stop, + .dev_close = ifpga_rawdev_close, + .dev_reset = ifpga_rawdev_reset, + + .queue_def_conf = NULL, + .queue_setup = NULL, + .queue_release = NULL, + + .attr_get = NULL, + .attr_set = NULL, + + .enqueue_bufs = NULL, + .dequeue_bufs = NULL, + + .dump = NULL, + + .xstats_get = NULL, + .xstats_get_names = NULL, + .xstats_get_by_name = NULL, + .xstats_reset = NULL, + + .firmware_status_get = NULL, + .firmware_version_get = NULL, + .firmware_load = ifpga_rawdev_pr, + .firmware_unload = NULL, + + .dev_selftest = NULL, +}; + +static int +ifpga_rawdev_create(struct rte_pci_device *pci_dev, + int socket_id) +{ + int ret = 0; + struct rte_rawdev *rawdev = NULL; + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_adapter_data_pci *data; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + int i; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + goto cleanup; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%x:%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id()); + + /* Allocate device structure */ + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct opae_adapter), + socket_id); + if (rawdev == NULL) { + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); + ret = -EINVAL; + goto cleanup; + } + + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API */ + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); + if (!data) + return -ENOMEM; + + /* init opae_adapter_data_pci for device specific information */ + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + data->region[i].phys_addr = pci_dev->mem_resource[i].phys_addr; + data->region[i].len = pci_dev->mem_resource[i].len; + data->region[i].addr = pci_dev->mem_resource[i].addr; + } + data->device_id = pci_dev->id.device_id; + data->vendor_id = pci_dev->id.vendor_id; + + /* create a opae_adapter based on above device data */ + adapter = opae_adapter_alloc(pci_dev->device.name, data); + if (!adapter) { + opae_adapter_data_free(data); + return -ENOMEM; + } + + rawdev->dev_ops = &ifpga_rawdev_ops; + rawdev->device = &pci_dev->device; + rawdev->driver_name = pci_dev->device.driver->name; + + rawdev->dev_private = adapter; + + /* must enumerate the adapter before use it */ + ret = opae_adapter_enumerate(adapter); + if (ret) + return ret; + + /* set opae_manager to rawdev */ + mgr = opae_adapter_get_mgr(adapter); + if (mgr) { + /*PF function*/ + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); + } + + return ret; + +cleanup: + if (rawdev) + rte_rawdev_pmd_release(rawdev); + + return ret; +} + +static int +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) +{ + int ret; + struct rte_rawdev *rawdev; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + struct opae_adapter *adapter; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + return ret; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%x:%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", + name, rte_socket_id()); + + rawdev = rte_rawdev_pmd_get_named_dev(name); + if (!rawdev) { + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name); + return -EINVAL; + } + + adapter = ifpga_rawdev_get_priv(rawdev); + if (!adapter) + return -ENODEV; + + opae_adapter_data_free(adapter->data); + opae_adapter_free(adapter); + + /* rte_rawdev_close is called by pmd_release */ + ret = rte_rawdev_pmd_release(rawdev); + if (ret) + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); + + return 0; +} + +static int +ifpga_rawdev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, + struct rte_pci_device *pci_dev) +{ + + printf("## %s\n", __func__); + return ifpga_rawdev_create(pci_dev, rte_socket_id()); +} + +static int ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) +{ + return ifpga_rawdev_destroy(pci_dev); +} + +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { + .id_table = pci_ifpga_map, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, + .probe = ifpga_rawdev_pci_probe, + .remove = ifpga_rawdev_pci_remove, +}; + +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | uio_pci_generic | vfio-pci"); + +RTE_INIT(ifpga_rawdev_init_log); +static void +ifpga_rawdev_init_log(void) +{ + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); + if (ifpga_rawdev_logtype >= 0) + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_BDF "bdf" + IFPGA_ARG_BDF, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +static int +ifpga_cfg_probe(struct rte_vdev_device *dev) +{ + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + struct rte_pci_addr pci_addr; + int port; + char dev_name[RTE_RAWDEV_NAME_MAX_LEN+8]; + + devargs = dev->device.devargs; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_BDF) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_BDF, + &ifpga_get_bdf_arg, &pci_addr) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_BDF); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_BDF); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, + &ifpga_get_integer32_arg, &port) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + memset(dev_name, 0, sizeof(dev_name)); + snprintf(dev_name, (RTE_RAWDEV_NAME_MAX_LEN+8), "%d|%x:%x:%x", + port, pci_addr.bus, pci_addr.devid, pci_addr.function); + + rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), + dev_name, + devargs->args); +end: + if (kvlist) + rte_kvargs_free(kvlist); + + return 0; +} + +static int +ifpga_cfg_remove(struct rte_vdev_device *vdev) +{ + IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p", + vdev); + + return 0; +} + +static struct rte_vdev_driver ifpga_cfg_driver = { + .probe = ifpga_cfg_probe, + .remove = ifpga_cfg_remove, +}; + +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, + "bdf=<string> " + "port=<int> " + "uuid_high=<int64> " + "uuid_low=<int64> " + "path=<path> " + "pr_enable=<int> " + "debug=<int>"); + diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h new file mode 100644 index 0000000..169dc1d --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_RAWDEV_H_ +#define _IFPGA_RAWDEV_H_ + +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) + +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") + +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) +#define IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) +#define IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) +#define IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) + +enum ifpga_rawdev_device_state { + IFPGA_IDLE, + IFPGA_READY, + IFPGA_ERROR +}; + +static inline struct opae_adapter * +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) +{ + return rawdev->dev_private; +} + +#endif /* _IFPGA_RAWDEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map new file mode 100644 index 0000000..9b9ab1a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map @@ -0,0 +1,4 @@ +DPDK_18.05 { + + local: *; +}; diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 929c3d8..958b6b5 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -108,6 +108,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrte_sched _LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += -lrte_ifpga_rawdev ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev Driver 2018-03-31 16:03 ` [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev Driver Rosen Xu @ 2018-04-03 9:34 ` Shreyansh Jain 2018-04-04 1:49 ` Xu, Rosen 0 siblings, 1 reply; 149+ messages in thread From: Shreyansh Jain @ 2018-04-03 9:34 UTC (permalink / raw) To: Rosen Xu Cc: dev, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet, Yanglong Wu On Saturday 31 March 2018 09:33 PM, Rosen Xu wrote: > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > --- > config/common_base | 1 + > drivers/raw/Makefile | 1 + > drivers/raw/ifpga_rawdev/Makefile | 34 ++ > drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 594 +++++++++++++++++++++ > drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ > .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + > mk/rte.app.mk | 1 + > 7 files changed, 672 insertions(+) > create mode 100644 drivers/raw/ifpga_rawdev/Makefile > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h > create mode 100644 drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map > > diff --git a/config/common_base b/config/common_base > index 49f6b09..08b7cce 100644 > --- a/config/common_base > +++ b/config/common_base > @@ -137,6 +137,7 @@ CONFIG_RTE_LIBRTE_VDEV_BUS=y > # Compile the Intel FPGA bus > # > CONFIG_RTE_LIBRTE_IFPGA_BUS=y > +CONFIG_RTE_LIBRTE_IFPGA_RAWDEV=y > > # > # Compile ARK PMD > diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile > index da7c8b4..6fc8f2f 100644 > --- a/drivers/raw/Makefile > +++ b/drivers/raw/Makefile > @@ -5,5 +5,6 @@ include $(RTE_SDK)/mk/rte.vars.mk > > # DIRS-$(<configuration>) += <directory> > DIRS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += skeleton_rawdev > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev > > include $(RTE_SDK)/mk/rte.subdir.mk > diff --git a/drivers/raw/ifpga_rawdev/Makefile b/drivers/raw/ifpga_rawdev/Makefile > new file mode 100644 > index 0000000..118c729 > --- /dev/null > +++ b/drivers/raw/ifpga_rawdev/Makefile > @@ -0,0 +1,34 @@ > +# SPDX-License-Identifier: BSD-3-Clause > +# Copyright(c) 2018 Intel Corporation > + > +include $(RTE_SDK)/mk/rte.vars.mk > + > +# > +# library name > +# > +LIB = librte_ifpga_rawdev.a > + > +CFLAGS += -DALLOW_EXPERIMENTAL_API > +CFLAGS += -O3 > +CFLAGS += $(WERROR_FLAGS) > +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga > +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev > +LDLIBS += -lrte_eal > +LDLIBS += -lrte_rawdev > +LDLIBS += -lrte_bus_vdev > +LDLIBS += -lrte_kvargs > + > +EXPORT_MAP := rte_ifpga_rawdev_version.map > + > +LIBABIVER := 1 > + > +VPATH += $(SRCDIR)/base > + > +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile > + > +# > +# all source are stored in SRCS-y > +# > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev.c > + > +include $(RTE_SDK)/mk/rte.lib.mk [...] Your patch doesn't compile at this point: (Static build; Shared is still stuck on patch [1/3]). --->8--- == Build drivers/raw/ifpga_rawdev /home/shreyansh/build/DPDK/00_dpdk/drivers/raw/ifpga_rawdev/Makefile:27: /home/shreyansh/build/DPDK/00_dpdk/drivers/raw/ifpga_rawdev/base/Makefile: No such file or directory make[6]: *** No rule to make target '/home/shreyansh/build/DPDK/00_dpdk/drivers/raw/ifpga_rawdev/base/Makefile'. Stop. /home/shreyansh/build/DPDK/00_dpdk/mk/rte.subdir.mk:35: recipe for target 'ifpga_rawdev' failed make[5]: *** [ifpga_rawdev] Error 2 make[5]: *** Waiting for unfinished jobs.... --->8--- Which is because your patch [3/3] contains various definitions which are being used in this patch. Am I missing something? - Shreyansh ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev Driver 2018-04-03 9:34 ` Shreyansh Jain @ 2018-04-04 1:49 ` Xu, Rosen 2018-04-04 11:31 ` Shreyansh Jain 0 siblings, 1 reply; 149+ messages in thread From: Xu, Rosen @ 2018-04-04 1:49 UTC (permalink / raw) To: Shreyansh Jain Cc: dev, Doherty, Declan, Richardson, Bruce, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Wu, Hao, gaetan.rivet, Wu, Yanglong > -----Original Message----- > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > Sent: Tuesday, April 03, 2018 17:35 > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Wu, Hao <hao.wu@intel.com>; gaetan.rivet@6wind.com; Wu, Yanglong > <yanglong.wu@intel.com> > Subject: Re: [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev Driver > > On Saturday 31 March 2018 09:33 PM, Rosen Xu wrote: > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > > --- > > config/common_base | 1 + > > drivers/raw/Makefile | 1 + > > drivers/raw/ifpga_rawdev/Makefile | 34 ++ > > drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 594 > +++++++++++++++++++++ > > drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ > > .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + > > mk/rte.app.mk | 1 + > > 7 files changed, 672 insertions(+) > > create mode 100644 drivers/raw/ifpga_rawdev/Makefile > > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c > > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > create mode 100644 > > drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map > > > > diff --git a/config/common_base b/config/common_base index > > 49f6b09..08b7cce 100644 > > --- a/config/common_base > > +++ b/config/common_base > > @@ -137,6 +137,7 @@ CONFIG_RTE_LIBRTE_VDEV_BUS=y > > # Compile the Intel FPGA bus > > # > > CONFIG_RTE_LIBRTE_IFPGA_BUS=y > > +CONFIG_RTE_LIBRTE_IFPGA_RAWDEV=y > > > > # > > # Compile ARK PMD > > diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index > > da7c8b4..6fc8f2f 100644 > > --- a/drivers/raw/Makefile > > +++ b/drivers/raw/Makefile > > @@ -5,5 +5,6 @@ include $(RTE_SDK)/mk/rte.vars.mk > > > > # DIRS-$(<configuration>) += <directory> > > DIRS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += > skeleton_rawdev > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev > > > > include $(RTE_SDK)/mk/rte.subdir.mk > > diff --git a/drivers/raw/ifpga_rawdev/Makefile > > b/drivers/raw/ifpga_rawdev/Makefile > > new file mode 100644 > > index 0000000..118c729 > > --- /dev/null > > +++ b/drivers/raw/ifpga_rawdev/Makefile > > @@ -0,0 +1,34 @@ > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > > +Corporation > > + > > +include $(RTE_SDK)/mk/rte.vars.mk > > + > > +# > > +# library name > > +# > > +LIB = librte_ifpga_rawdev.a > > + > > +CFLAGS += -DALLOW_EXPERIMENTAL_API > > +CFLAGS += -O3 > > +CFLAGS += $(WERROR_FLAGS) > > +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga CFLAGS += > > +-I$(RTE_SDK)/drivers/raw/ifpga_rawdev > > +LDLIBS += -lrte_eal > > +LDLIBS += -lrte_rawdev > > +LDLIBS += -lrte_bus_vdev > > +LDLIBS += -lrte_kvargs > > + > > +EXPORT_MAP := rte_ifpga_rawdev_version.map > > + > > +LIBABIVER := 1 > > + > > +VPATH += $(SRCDIR)/base > > + > > +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile > > + > > +# > > +# all source are stored in SRCS-y > > +# > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev.c > > + > > +include $(RTE_SDK)/mk/rte.lib.mk > > [...] > Your patch doesn't compile at this point: (Static build; Shared is still stuck on > patch [1/3]). > > --->8--- > == Build drivers/raw/ifpga_rawdev > /home/shreyansh/build/DPDK/00_dpdk/drivers/raw/ifpga_rawdev/Makefil > e:27: > /home/shreyansh/build/DPDK/00_dpdk/drivers/raw/ifpga_rawdev/base/M > akefile: > No such file or directory > make[6]: *** No rule to make target > '/home/shreyansh/build/DPDK/00_dpdk/drivers/raw/ifpga_rawdev/base/M > akefile'. > Stop. > /home/shreyansh/build/DPDK/00_dpdk/mk/rte.subdir.mk:35: recipe for > target 'ifpga_rawdev' failed > make[5]: *** [ifpga_rawdev] Error 2 > make[5]: *** Waiting for unfinished jobs.... > --->8--- > > Which is because your patch [3/3] contains various definitions which are > being used in this patch. > > Am I missing something? I have fixed it and try to build it after CONFIG_RTE_BUILD_SHARED_LIB = y, And it build and link well. Is this answer to your comments? > - > Shreyansh ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev Driver 2018-04-04 1:49 ` Xu, Rosen @ 2018-04-04 11:31 ` Shreyansh Jain 2018-04-26 10:47 ` Xu, Rosen 0 siblings, 1 reply; 149+ messages in thread From: Shreyansh Jain @ 2018-04-04 11:31 UTC (permalink / raw) To: Xu, Rosen Cc: dev, Doherty, Declan, Richardson, Bruce, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Wu, Hao, gaetan.rivet, Wu, Yanglong Hello Rosen, > -----Original Message----- > From: Xu, Rosen [mailto:rosen.xu@intel.com] > Sent: Wednesday, April 4, 2018 7:20 AM > To: Shreyansh Jain <shreyansh.jain@nxp.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; Yigit, Ferruh > <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei > <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com; Wu, Yanglong <yanglong.wu@intel.com> > Subject: RE: [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev Driver > > > > > -----Original Message----- > > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > > Sent: Tuesday, April 03, 2018 17:35 > > To: Xu, Rosen <rosen.xu@intel.com> > > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > > Richardson, Bruce <bruce.richardson@intel.com>; > shreyansh.jain@nxp.com; > > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > <tianfei.zhang@intel.com>; > > Wu, Hao <hao.wu@intel.com>; gaetan.rivet@6wind.com; Wu, Yanglong > > <yanglong.wu@intel.com> > > Subject: Re: [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev > Driver > > > > On Saturday 31 March 2018 09:33 PM, Rosen Xu wrote: > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > > > --- > > > config/common_base | 1 + > > > drivers/raw/Makefile | 1 + > > > drivers/raw/ifpga_rawdev/Makefile | 34 ++ > > > drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 594 > > +++++++++++++++++++++ > > > drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ > > > .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + > > > mk/rte.app.mk | 1 + > > > 7 files changed, 672 insertions(+) > > > create mode 100644 drivers/raw/ifpga_rawdev/Makefile > > > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c > > > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > > create mode 100644 > > > drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map > > > > > > diff --git a/config/common_base b/config/common_base index > > > 49f6b09..08b7cce 100644 > > > --- a/config/common_base > > > +++ b/config/common_base > > > @@ -137,6 +137,7 @@ CONFIG_RTE_LIBRTE_VDEV_BUS=y > > > # Compile the Intel FPGA bus > > > # > > > CONFIG_RTE_LIBRTE_IFPGA_BUS=y > > > +CONFIG_RTE_LIBRTE_IFPGA_RAWDEV=y > > > > > > # > > > # Compile ARK PMD > > > diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index > > > da7c8b4..6fc8f2f 100644 > > > --- a/drivers/raw/Makefile > > > +++ b/drivers/raw/Makefile > > > @@ -5,5 +5,6 @@ include $(RTE_SDK)/mk/rte.vars.mk > > > > > > # DIRS-$(<configuration>) += <directory> > > > DIRS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += > > skeleton_rawdev > > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev > > > > > > include $(RTE_SDK)/mk/rte.subdir.mk > > > diff --git a/drivers/raw/ifpga_rawdev/Makefile > > > b/drivers/raw/ifpga_rawdev/Makefile > > > new file mode 100644 > > > index 0000000..118c729 > > > --- /dev/null > > > +++ b/drivers/raw/ifpga_rawdev/Makefile > > > @@ -0,0 +1,34 @@ > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > > > +Corporation > > > + > > > +include $(RTE_SDK)/mk/rte.vars.mk > > > + > > > +# > > > +# library name > > > +# > > > +LIB = librte_ifpga_rawdev.a > > > + > > > +CFLAGS += -DALLOW_EXPERIMENTAL_API > > > +CFLAGS += -O3 > > > +CFLAGS += $(WERROR_FLAGS) > > > +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga CFLAGS += > > > +-I$(RTE_SDK)/drivers/raw/ifpga_rawdev > > > +LDLIBS += -lrte_eal > > > +LDLIBS += -lrte_rawdev > > > +LDLIBS += -lrte_bus_vdev > > > +LDLIBS += -lrte_kvargs > > > + > > > +EXPORT_MAP := rte_ifpga_rawdev_version.map > > > + > > > +LIBABIVER := 1 > > > + > > > +VPATH += $(SRCDIR)/base > > > + > > > +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile > > > + > > > +# > > > +# all source are stored in SRCS-y > > > +# > > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev.c > > > + > > > +include $(RTE_SDK)/mk/rte.lib.mk > > > > [...] > > Your patch doesn't compile at this point: (Static build; Shared is > still stuck on > > patch [1/3]). > > > > --->8--- > > == Build drivers/raw/ifpga_rawdev > > /home/shreyansh/build/DPDK/00_dpdk/drivers/raw/ifpga_rawdev/Makefil > > e:27: > > /home/shreyansh/build/DPDK/00_dpdk/drivers/raw/ifpga_rawdev/base/M > > akefile: > > No such file or directory > > make[6]: *** No rule to make target > > '/home/shreyansh/build/DPDK/00_dpdk/drivers/raw/ifpga_rawdev/base/M > > akefile'. > > Stop. > > /home/shreyansh/build/DPDK/00_dpdk/mk/rte.subdir.mk:35: recipe for > > target 'ifpga_rawdev' failed > > make[5]: *** [ifpga_rawdev] Error 2 > > make[5]: *** Waiting for unfinished jobs.... > > --->8--- > > > > Which is because your patch [3/3] contains various definitions which > are > > being used in this patch. > > > > Am I missing something? > > I have fixed it and try to build it after CONFIG_RTE_BUILD_SHARED_LIB = > y, > And it build and link well. > Is this answer to your comments? Yes, and no. I get that there was an issue with shared compilation so, yes, your response has fixed that. But, I still see the issue of patch being dependent. I think you compiled everything together (all patches combined) - so, no, that is not the expectation. All patches should be compliable separately, shared or static. > > > - > > Shreyansh ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev Driver 2018-04-04 11:31 ` Shreyansh Jain @ 2018-04-26 10:47 ` Xu, Rosen 0 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-04-26 10:47 UTC (permalink / raw) To: Shreyansh Jain Cc: dev, Doherty, Declan, Richardson, Bruce, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Wu, Hao, gaetan.rivet, Wu, Yanglong Hi Shreyansh, > -----Original Message----- > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > Sent: Wednesday, April 04, 2018 19:31 > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; Yigit, Ferruh > <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Wu, Hao <hao.wu@intel.com>; gaetan.rivet@6wind.com; Wu, Yanglong > <yanglong.wu@intel.com> > Subject: RE: [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev Driver > > Hello Rosen, > > > -----Original Message----- > > From: Xu, Rosen [mailto:rosen.xu@intel.com] > > Sent: Wednesday, April 4, 2018 7:20 AM > > To: Shreyansh Jain <shreyansh.jain@nxp.com> > > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > > Richardson, Bruce <bruce.richardson@intel.com>; Yigit, Ferruh > > <ferruh.yigit@intel.com>; Ananyev, Konstantin > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com>; > > gaetan.rivet@6wind.com; Wu, Yanglong <yanglong.wu@intel.com> > > Subject: RE: [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev > > Driver > > > > > > > > > -----Original Message----- > > > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > > > Sent: Tuesday, April 03, 2018 17:35 > > > To: Xu, Rosen <rosen.xu@intel.com> > > > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > > > Richardson, Bruce <bruce.richardson@intel.com>; > > shreyansh.jain@nxp.com; > > > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > <tianfei.zhang@intel.com>; > > > Wu, Hao <hao.wu@intel.com>; gaetan.rivet@6wind.com; Wu, Yanglong > > > <yanglong.wu@intel.com> > > > Subject: Re: [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev > > Driver > > > > > > On Saturday 31 March 2018 09:33 PM, Rosen Xu wrote: > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > > > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > > > > --- > > > > config/common_base | 1 + > > > > drivers/raw/Makefile | 1 + > > > > drivers/raw/ifpga_rawdev/Makefile | 34 ++ > > > > drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 594 > > > +++++++++++++++++++++ > > > > drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ > > > > .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + > > > > mk/rte.app.mk | 1 + > > > > 7 files changed, 672 insertions(+) > > > > create mode 100644 drivers/raw/ifpga_rawdev/Makefile > > > > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c > > > > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > > > create mode 100644 > > > > drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map > > > > > > > > diff --git a/config/common_base b/config/common_base index > > > > 49f6b09..08b7cce 100644 > > > > --- a/config/common_base > > > > +++ b/config/common_base > > > > @@ -137,6 +137,7 @@ CONFIG_RTE_LIBRTE_VDEV_BUS=y > > > > # Compile the Intel FPGA bus > > > > # > > > > CONFIG_RTE_LIBRTE_IFPGA_BUS=y > > > > +CONFIG_RTE_LIBRTE_IFPGA_RAWDEV=y > > > > > > > > # > > > > # Compile ARK PMD > > > > diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index > > > > da7c8b4..6fc8f2f 100644 > > > > --- a/drivers/raw/Makefile > > > > +++ b/drivers/raw/Makefile > > > > @@ -5,5 +5,6 @@ include $(RTE_SDK)/mk/rte.vars.mk > > > > > > > > # DIRS-$(<configuration>) += <directory> > > > > DIRS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += > > > skeleton_rawdev > > > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev > > > > > > > > include $(RTE_SDK)/mk/rte.subdir.mk diff --git > > > > a/drivers/raw/ifpga_rawdev/Makefile > > > > b/drivers/raw/ifpga_rawdev/Makefile > > > > new file mode 100644 > > > > index 0000000..118c729 > > > > --- /dev/null > > > > +++ b/drivers/raw/ifpga_rawdev/Makefile > > > > @@ -0,0 +1,34 @@ > > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > > > > +Corporation > > > > + > > > > +include $(RTE_SDK)/mk/rte.vars.mk > > > > + > > > > +# > > > > +# library name > > > > +# > > > > +LIB = librte_ifpga_rawdev.a > > > > + > > > > +CFLAGS += -DALLOW_EXPERIMENTAL_API CFLAGS += -O3 CFLAGS += > > > > +$(WERROR_FLAGS) CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga CFLAGS > > > > ++= -I$(RTE_SDK)/drivers/raw/ifpga_rawdev > > > > +LDLIBS += -lrte_eal > > > > +LDLIBS += -lrte_rawdev > > > > +LDLIBS += -lrte_bus_vdev > > > > +LDLIBS += -lrte_kvargs > > > > + > > > > +EXPORT_MAP := rte_ifpga_rawdev_version.map > > > > + > > > > +LIBABIVER := 1 > > > > + > > > > +VPATH += $(SRCDIR)/base > > > > + > > > > +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile > > > > + > > > > +# > > > > +# all source are stored in SRCS-y # > > > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev.c > > > > + > > > > +include $(RTE_SDK)/mk/rte.lib.mk > > > > > > [...] > > > Your patch doesn't compile at this point: (Static build; Shared is > > still stuck on > > > patch [1/3]). > > > > > > --->8--- > > > == Build drivers/raw/ifpga_rawdev > > > > /home/shreyansh/build/DPDK/00_dpdk/drivers/raw/ifpga_rawdev/Makefil > > > e:27: > > > > /home/shreyansh/build/DPDK/00_dpdk/drivers/raw/ifpga_rawdev/base/M > > > akefile: > > > No such file or directory > > > make[6]: *** No rule to make target > > > > '/home/shreyansh/build/DPDK/00_dpdk/drivers/raw/ifpga_rawdev/base/M > > > akefile'. > > > Stop. > > > /home/shreyansh/build/DPDK/00_dpdk/mk/rte.subdir.mk:35: recipe for > > > target 'ifpga_rawdev' failed > > > make[5]: *** [ifpga_rawdev] Error 2 > > > make[5]: *** Waiting for unfinished jobs.... > > > --->8--- > > > > > > Which is because your patch [3/3] contains various definitions which > > are > > > being used in this patch. > > > > > > Am I missing something? > > > > I have fixed it and try to build it after CONFIG_RTE_BUILD_SHARED_LIB > > = y, And it build and link well. > > Is this answer to your comments? > > Yes, and no. > I get that there was an issue with shared compilation so, yes, your response > has fixed that. > But, I still see the issue of patch being dependent. I think you compiled > everything together (all patches combined) - so, no, that is not the > expectation. > > All patches should be compliable separately, shared or static. It's fixed, pls see my PATCH v6. > > > > > - > > > Shreyansh ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v4 3/3] Add Intel FPGA OPAE Share Code 2018-03-31 16:02 ` [dpdk-dev] [PATCH v4 0/3] " Rosen Xu 2018-03-31 16:03 ` [dpdk-dev] [PATCH v4 1/3] Add Intel FPGA BUS Lib Code Rosen Xu 2018-03-31 16:03 ` [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev Driver Rosen Xu @ 2018-03-31 16:03 ` Rosen Xu 2 siblings, 0 replies; 149+ messages in thread From: Rosen Xu @ 2018-03-31 16:03 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> Signed-off-by: Wu, Hao <hao.wu@intel.com> --- drivers/raw/ifpga_rawdev/base/Makefile | 54 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 529 ++++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 73 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 84 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1688 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 851 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 38 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 341 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 191 +++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 761 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 328 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 430 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 742 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 399 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 154 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 435 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 192 +++ drivers/raw/ifpga_rawdev/base/opae_debug.c | 126 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 46 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 408 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 280 ++++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 172 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 306 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 115 ++ .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 104 ++ .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 72 + 26 files changed, 8919 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile new file mode 100644 index 0000000..9c0d64b --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -0,0 +1,54 @@ +# BSD LICENSE +# +# Copyright(c) 2017-2018 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +ifneq ($(CONFIG_RTE_LIBRTE_EAL),) +OSDEP := osdep_rte +else +OSDEP := osdep_raw +endif + +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev/base/$(OSDEP) + +SRCS-y += ifpga_api.c +SRCS-y += ifpga_enumerate.c +SRCS-y += ifpga_feature_dev.c +SRCS-y += ifpga_fme.c +SRCS-y += ifpga_fme_iperf.c +SRCS-y += ifpga_fme_dperf.c +SRCS-y += ifpga_fme_error.c +SRCS-y += ifpga_port.c +SRCS-y += ifpga_port_error.c +SRCS-y += ifpga_fme_pr.c +SRCS-y += opae_hw_api.c +SRCS-y += opae_ifpga_hw_api.c +SRCS-y += opae_debug.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 new file mode 100644 index 0000000..9ce4b60 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -0,0 +1,529 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_api.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +#include "opae_hw_api.h" + +/* Accelerator APIs */ +static int ifpga_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return fpga_get_afu_uuid(port, uuid); +} + +static int ifpga_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + struct fpga_uafu_irq_set irq_set; + + if (!br || !br->data) + return -EINVAL; + + if (start >= afu_info->num_irqs || start + count > afu_info->num_irqs) + return -EINVAL; + + port = br->data; + + irq_set.start = start; + irq_set.count = count; + irq_set.evtfds = evtfds; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_UINT, &irq_set); +} + +static int ifpga_acc_get_info(struct opae_accelerator *acc, + struct opae_acc_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -ENODEV; + + info->num_regions = afu_info->num_regions; + info->num_irqs = afu_info->num_irqs; + + return 0; +} + +static int ifpga_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -EINVAL; + + if (info->index >= afu_info->num_regions) + return -EINVAL; + + /* always one RW region only for AFU now */ + info->flags = ACC_REGION_READ | ACC_REGION_WRITE | ACC_REGION_MMIO; + info->len = afu_info->region[info->index].len; + + return 0; +} + +static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + switch (byte) { + case 8: + *(u64 *)data = opae_readq(region->addr + offset); + break; + case 4: + *(u32 *)data = opae_readl(region->addr + offset); + break; + case 2: + *(u16 *)data = opae_readw(region->addr + offset); + break; + case 1: + *(u8 *)data = opae_readb(region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ifpga_acc_write(struct opae_accelerator *acc, + unsigned int region_idx, u64 offset, + unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + /* normal mmio case */ + switch (byte) { + case 8: + opae_writeq(*(u64 *)data, region->addr + offset); + break; + case 4: + opae_writel(*(u32 *)data, region->addr + offset); + break; + case 2: + opae_writew(*(u16 *)data, region->addr + offset); + break; + case 1: + opae_writeb(*(u8 *)data, region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +struct opae_accelerator_ops ifpga_acc_ops = { + .read = ifpga_acc_read, + .write = ifpga_acc_write, + .set_irq = ifpga_acc_set_irq, + .get_info = ifpga_acc_get_info, + .get_region_info = ifpga_acc_get_region_info, + .get_uuid = ifpga_acc_get_uuid, +}; + +/* Bridge APIs */ + +static int ifpga_br_reset(struct opae_bridge *br) +{ + struct ifpga_port_hw *port = br->data; + + return fpga_port_reset(port); +} + +struct opae_bridge_ops ifpga_br_ops = { + .reset = ifpga_br_reset, +}; + +/* Manager APIs */ +static int ifpga_mgr_flash(struct opae_manager *mgr, int id, void *buf, + u32 size, u64 *status) +{ + struct ifpga_fme_hw *fme = mgr->data; + struct ifpga_hw *hw = fme->parent; + + return ifpga_pr(hw, id, buf, size, status); +} + +struct opae_manager_ops ifpga_mgr_ops = { + .flash = ifpga_mgr_flash, +}; + +/* Adapter APIs */ +static int ifpga_adapter_enumerate(struct opae_adapter *adapter) +{ + struct ifpga_hw *hw = malloc(sizeof(*hw)); + + if (hw) { + memset(hw, 0, sizeof(*hw)); + hw->pci_data = adapter->data; + hw->adapter = adapter; + if (ifpga_bus_enumerate(hw)) + goto error; + return ifpga_bus_init(hw); + } + +error: + return -ENOMEM; +} + +struct opae_adapter_ops ifpga_adapter_ops = { + .enumerate = ifpga_adapter_enumerate, +}; + +/** + * ifpga_enumerate - enumerate the Device Feature List + * @hw: pointer to the HW structure + * + * This function enumerate the Device Feature List to discover + * the FME and Port devices. The FME device and Port devices + * will fill into HW structure when enumerate done. + * + * @return + * - 0: Success, device enumated. + * - <0: Error code returned in enumeration. + **/ +int ifpga_enumerate(struct ifpga_hw *hw) +{ + return ifpga_bus_enumerate(hw); +} + +/** + * ifpga_reset_port - reset a port device + * @hw: pointer to the HW structure + * @port_id: port device id + * + * @return + * - 0: Success + * - <0: Failure to reset a port device. + **/ +int ifpga_reset_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return fpga_port_reset(&hw->port[port_id]); +} + +/** + * ifpga_get_afu_mmio_addr - get UAFU MMIO address + * @hw: pointer to the HW structure + * @port_id: port device id + * @mem_resource: afu mmio resource + * @num_resource: number of resource + * + * return 0 on success or error code + **/ +int ifpga_get_afu_mmio_info(struct ifpga_hw *hw, u32 port_id, + struct rte_mem_resource *mem_resource, + u32 *num_resource) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + mem_resource->addr = + hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + mem_resource->len = + hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + mem_resource->phys_addr = + hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].phys_addr; + + *num_resource = 1; + + return 0; +} + +/** + * ifpga_get_afu_uuid - get AFU uuid + * @hw: pointer to the HW structure + * @port_id: port device id + * @uuid: the AFU's uuid + * + * @return + * - 0: Success + * - <0: Failure to get uuid. + **/ +int ifpga_get_afu_uuid(struct ifpga_hw *hw, u32 port_id, struct uuid *uuid) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + if (!hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size) + return -ENODEV; + + return fpga_get_afu_uuid(&hw->port[port_id], uuid); +} + +/** + * ifpga_pr - do the partial reconfiguration for a given port device + * @hw: pointer to the HW structure + * @port_id: the port device id + * @buffer: the buffer of the bitstream + * @size: the size of the bitstream + * @status: hardware status including PR error code if return -EIO. + * + * @return + * - 0: Success, partial reconfiguration finished. + * - <0: Error code returned in partial reconfiguration. + **/ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return do_pr(hw, port_id, buffer, size, status); +} + +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_get_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_get_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set) +{ + if (!hw || !irq_set) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_irq(&hw->fme, feature_id, irq_set); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_irq(&hw->port[port_id], feature_id, irq_set); + } + + return -ENOENT; +} + +void ifpga_show_pr_error(u64 pr_error) +{ + int i; + + for (i = 0; i < PR_MAX_ERR_NUM; i++) { + if (pr_error & (1 << i)) + printf("PR Error: %s\n", pr_err_msg[i]); + } + + printf("PR Error: 0x%lx\n", pr_error); +} + +int ifpga_mmio64_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 *value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + *value = readq(addr + offset); + + return 0; +} + +int ifpga_mmio64_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + writeq(value, addr + offset); + + return 0; +} + +int ifpga_mmio32_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 *value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + *value = readl(addr + offset); + + return 0; +} + +int ifpga_mmio32_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + writel(value, addr + offset); + + return 0; +} + +int ifpga_fme_hw_init(struct ifpga_hw *hw) +{ + return fme_hw_init(&hw->fme); +} + +void ifpga_fme_hw_uinit(struct ifpga_hw *hw) +{ + fme_hw_uinit(&hw->fme); +} + +void ifpga_port_hw_uinit(struct ifpga_hw *hw, int port_id) +{ + struct ifpga_port_hw *port; + + if (!is_valid_port_id(hw, port_id)) + return; + + port = &hw->port[port_id]; + + if (port->state == IFPGA_PORT_ATTACHED) + port_hw_uinit(port); +} + +int ifpga_port_hw_init(struct ifpga_hw *hw, int port_id) +{ + struct ifpga_port_hw *port; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + port = &hw->port[port_id]; + + if (port->state != IFPGA_PORT_ATTACHED) + return -EINVAL; + + return port_hw_init(port); +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.h b/drivers/raw/ifpga_rawdev/base/ifpga_api.h new file mode 100644 index 0000000..e762390 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.h @@ -0,0 +1,73 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_API_H_ +#define _IFPGA_API_H_ + +#include "opae_hw_api.h" +#include "ifpga_hw.h" + +extern struct opae_adapter_ops ifpga_adapter_ops; +extern struct opae_manager_ops ifpga_mgr_ops; +extern struct opae_bridge_ops ifpga_br_ops; +extern struct opae_accelerator_ops ifpga_acc_ops; + +/* common APIs */ +int ifpga_enumerate(struct ifpga_hw *hw); +int ifpga_fme_hw_init(struct ifpga_hw *hw); +void ifpga_fme_hw_uinit(struct ifpga_hw *hw); +int ifpga_port_hw_init(struct ifpga_hw *hw, int port_id); +void ifpga_port_hw_uinit(struct ifpga_hw *hw, int port_id); +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set); + +/* Port/AFU APIs */ +int ifpga_reset_port(struct ifpga_hw *hw, u32 port_id); +int ifpga_get_afu_mmio_info(struct ifpga_hw *hw, u32 port_id, + struct rte_mem_resource *mem_resource, + u32 *num_resource); +int ifpga_get_afu_uuid(struct ifpga_hw *hw, u32 port_id, struct uuid *uuid); + +int ifpga_mmio64_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 *value); +int ifpga_mmio64_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 value); +int ifpga_mmio32_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 *value); +int ifpga_mmio32_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 value); + +/* FME APIs */ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); +void ifpga_show_pr_error(u64 pr_error); + +#endif /* _IFPGA_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_compat.h b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h new file mode 100644 index 0000000..6670630 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h @@ -0,0 +1,84 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_COMPAT_H_ +#define _IFPGA_COMPAT_H_ + +#include "opae_osdep.h" + +#undef container_of +#define container_of(ptr, type, member) ({ \ + typeof(((type *)0)->member)(*__mptr) = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) +#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE) + +#define readl(addr) opae_readl(addr) +#define readq(addr) opae_readq(addr) +#define writel(value, addr) opae_writel(value, addr) +#define writeq(value, addr) opae_writeq(value, addr) + +#define malloc(size) opae_malloc(size) +#define zmalloc(size) opae_zmalloc(size) +#define free(size) opae_free(size) + +/* + * Wait register's _field to be changed to the given value (_expect's _field) + * by polling with given interval and timeout. + */ +#define fpga_wait_register_field(_field, _expect, _reg_addr, _timeout, _invl)\ +({ \ + int wait = 0; \ + int ret = -ETIMEDOUT; \ + typeof(_expect) value; \ + for (; wait <= _timeout; wait += _invl) { \ + value.csr = readq(_reg_addr); \ + if (_expect._field == value._field) { \ + ret = 0; \ + break; \ + } \ + udelay(_invl); \ + } \ + ret; \ +}) + +#define __maybe_unused __attribute__((__unused__)) + +#define UNUSED(x) (void)(x) + +#endif /* _IFPGA_COMPAT_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h new file mode 100644 index 0000000..d0fabe7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -0,0 +1,1688 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_DEFINES_H_ +#define _IFPGA_DEFINES_H_ + +#include "ifpga_compat.h" + +#define MAX_FPGA_PORT_NUM 4 + +#define FME_FEATURE_HEADER "fme_hdr" +#define FME_FEATURE_THERMAL_MGMT "fme_thermal" +#define FME_FEATURE_POWER_MGMT "fme_power" +#define FME_FEATURE_GLOBAL_IPERF "fme_iperf" +#define FME_FEATURE_GLOBAL_ERR "fme_error" +#define FME_FEATURE_PR_MGMT "fme_pr" +#define FME_FEATURE_HSSI_ETH "fme_hssi" +#define FME_FEATURE_GLOBAL_DPERF "fme_dperf" +#define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" + +#define PORT_FEATURE_HEADER "port_hdr" +#define PORT_FEATURE_UAFU "port_uafu" +#define PORT_FEATURE_ERR "port_err" +#define PORT_FEATURE_UMSG "port_umsg" +#define PORT_FEATURE_PR "port_pr" +#define PORT_FEATURE_UINT "port_uint" +#define PORT_FEATURE_STP "port_stp" + +/* + * do not check the revision id as id may be dynamic under + * some cases, e.g, UAFU. + */ +#define SKIP_REVISION_CHECK 0xff + +#define FME_HEADER_REVISION 1 +#define FME_THERMAL_MGMT_REVISION 0 +#define FME_POWER_MGMT_REVISION 1 +#define FME_GLOBAL_IPERF_REVISION 1 +#define FME_GLOBAL_ERR_REVISION 1 +#define FME_PR_MGMT_REVISION 2 +#define FME_HSSI_ETH_REVISION 0 +#define FME_GLOBAL_DPERF_REVISION 0 +#define FME_QSPI_REVISION 0 + +#define PORT_HEADER_REVISION 0 +/* UAFU's header info depends on the downloaded GBS */ +#define PORT_UAFU_REVISION SKIP_REVISION_CHECK +#define PORT_ERR_REVISION 1 +#define PORT_UMSG_REVISION 0 +#define PORT_UINT_REVISION 0 +#define PORT_STP_REVISION 1 + +#define FEATURE_TYPE_AFU 0x1 +#define FEATURE_TYPE_BBB 0x2 +#define FEATURE_TYPE_PRIVATE 0x3 +#define FEATURE_TYPE_FIU 0x4 + +#define FEATURE_FIU_ID_FME 0x0 +#define FEATURE_FIU_ID_PORT 0x1 + +#define FEATURE_ID_HEADER 0x0 +#define FEATURE_ID_AFU 0xff + +enum fpga_id_type { + FME_ID, + PORT_ID, + 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, +}; + +/* + * All headers and structures must be byte-packed to match the spec. + */ +#pragma pack(1) + +struct feature_header { + union { + u64 csr; + struct { + u16 id:12; + u8 revision:4; + u32 next_header_offset:24; + u8 end_of_list:1; + u32 reserved:19; + u8 type:4; + }; + }; +}; + +struct feature_bbb_header { + struct uuid guid; +}; + +struct feature_afu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fiu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fme_capability { + union { + u64 csr; + struct { + u8 fabric_verid; /* Fabric version ID */ + u8 socket_id:1; /* Socket id */ + u8 rsvd1:3; /* Reserved */ + /* pci0 link available yes /no */ + u8 pci0_link_avile:1; + /* pci1 link available yes /no */ + u8 pci1_link_avile:1; + /* Coherent (QPI/UPI) link available yes /no */ + u8 qpi_link_avile:1; + u8 rsvd2:1; /* Reserved */ + /* IOMMU or VT-d supported yes/no */ + u8 iommu_support:1; + u8 num_ports:3; /* Number of ports */ + u8 sf_fab_ctl:1; /* Internal validation bit */ + u8 rsvd3:3; /* Reserved */ + /* + * Address width supported in bits + * BXT -0x26 , SKX -0x30 + */ + u8 address_width_bits:6; + u8 rsvd4:2; /* Reserved */ + /* Size of cache supported in kb */ + u16 cache_size:12; + u8 cache_assoc:4; /* Cache Associativity */ + u16 rsvd5:15; /* Reserved */ + u8 lock_bit:1; /* Lock bit */ + }; + }; +}; + +#define FME_AFU_ACCESS_PF 0 +#define FME_AFU_ACCESS_VF 1 + +struct feature_fme_port { + union { + u64 csr; + struct { + u32 port_offset:24; + u8 reserved1; + u8 port_bar:3; + u32 reserved2:20; + u8 afu_access_control:1; + u8 reserved3:4; + u8 port_implemented:1; + u8 reserved4:3; + }; + }; +}; + +struct feature_fme_fab_status { + union { + u64 csr; + struct { + u8 upilink_status:4; /* UPI Link Status */ + u8 rsvd1:4; /* Reserved */ + u8 pci0link_status:1; /* pci0 link status */ + u8 rsvd2:3; /* Reserved */ + u8 pci1link_status:1; /* pci1 link status */ + u64 rsvd3:51; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_base { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Base Address of memory range */ + u8 protected_base_addrss:4; + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_limit { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Limit Address of memory range */ + u8 protected_limit_addrss:4; + u16 rsvd2:11; /* Reserved */ + u8 enable:1; /* Enable GENPROTRANGE check */ + u32 rsvd3; /* Reserved */ + }; + }; +}; + +struct feature_fme_dxe_lock { + union { + u64 csr; + struct { + /* + * Determines write access to the DXE region CSRs + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_early_lock:1; + /* + * Determines write access to the HSSI CSR + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_late_lock:1; + u64 rsvd:62; + }; + }; +}; + +#define HSSI_ID_NO_HASSI 0 +#define HSSI_ID_PCIE_RP 1 +#define HSSI_ID_ETHERNET 2 + +struct feature_fme_bitstream_id { + union { + u64 csr; + struct { + u32 gitrepo_hash:32; /* GIT repository hash */ + /* + * HSSI configuration identifier: + * 0 - No HSSI + * 1 - PCIe-RP + * 2 - Ethernet + */ + u8 hssi_id:4; + u16 rsvd1:12; /* Reserved */ + /* Bitstream version patch number */ + u8 bs_verpatch:4; + /* Bitstream version minor number */ + u8 bs_verminor:4; + /* Bitstream version major number */ + u8 bs_vermajor:4; + /* Bitstream version debug number */ + u8 bs_verdebug:4; + }; + }; +}; + +struct feature_fme_bitstream_md { + union { + u64 csr; + struct { + /* Seed number userd for synthesis flow */ + u8 synth_seed:4; + /* Synthesis date(day number - 2 digits) */ + u8 synth_day:8; + /* Synthesis date(month number - 2 digits) */ + u8 synth_month:8; + /* Synthesis date(year number - 2 digits) */ + u8 synth_year:8; + u64 rsvd:36; /* Reserved */ + }; + }; +}; + +struct feature_fme_iommu_ctrl { + union { + u64 csr; + struct { + /* Disables IOMMU prefetcher for C0 channel */ + u8 prefetch_disableC0:1; + /* Disables IOMMU prefetcher for C1 channel */ + u8 prefetch_disableC1:1; + /* Disables IOMMU partial cache line writes */ + u8 prefetch_wrdisable:1; + u8 rsvd1:1; /* Reserved */ + /* + * Select counter and read value from register + * iommu_stat.dbg_counters + * 0 - Number of 4K page translation response + * 1 - Number of 2M page translation response + * 2 - Number of 1G page translation response + */ + u8 counter_sel:2; + u32 rsvd2:26; /* Reserved */ + /* Connected to IOMMU SIP Capabilities */ + u32 capecap_defeature; + }; + }; +}; + +struct feature_fme_iommu_stat { + union { + u64 csr; + struct { + /* Translation Enable bit from IOMMU SIP */ + u8 translation_enable:1; + /* Drain request in progress */ + u8 drain_req_inprog:1; + /* Invalidation current state */ + u8 inv_state:3; + /* C0 Response Buffer current state */ + u8 respbuffer_stateC0:3; + /* C1 Response Buffer current state */ + u8 respbuffer_stateC1:3; + /* Last request ID to IOMMU SIP */ + u8 last_reqID:4; + /* Last IOMMU SIP response ID value */ + u8 last_respID:4; + /* Last IOMMU SIP response status value */ + u8 last_respstatus:3; + /* C0 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC0:1; + /* C1 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC1:1; + /* C0 Request FIFO is not empty */ + u8 reqFIFO_notemptyC0:1; + /* C1 Request FIFO is not empty */ + u8 reqFIFO_notemptyC1:1; + /* C0 Response FIFO is not empty */ + u8 respFIFO_notemptyC0:1; + /* C1 Response FIFO is not empty */ + u8 respFIFO_notemptyC1:1; + /* C0 Response FIFO overflow detected */ + u8 respFIFO_overflowC0:1; + /* C1 Response FIFO overflow detected */ + u8 respFIFO_overflowC1:1; + /* C0 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC0:1; + /* C1 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC1:1; + /* Request FIFO overflow detected */ + u8 reqFIFO_overflow:1; + /* IOMMU memory read in progress */ + u8 memrd_inprog:1; + /* IOMMU memory write in progress */ + u8 memwr_inprog:1; + u8 rsvd1:1; /* Reserved */ + /* Value of counter selected by iommu_ctl.counter_sel */ + u16 dbg_counters:16; + u16 rsvd2:12; /* Reserved */ + }; + }; +}; + +struct feature_fme_pcie0_ctrl { + union { + u64 csr; + struct { + u64 vtd_bar_lock:1; /* Lock VT-D BAR register */ + u64 rsvd1:3; + u64 rciep:1; /* Configure PCIE0 as RCiEP */ + u64 rsvd2:59; + }; + }; +}; + +struct feature_fme_llpr_smrr_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR rule is valid or not */ + /* + * SMRR memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR2 rule is valid or not */ + /* + * SMRR2 memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_meseg_base { + union { + u64 csr; + struct { + /* A[45:19] of base address memory range */ + u64 me_base:27; + u64 rsvd:37; + }; + }; +}; + +struct feature_fme_llpr_meseg_limit { + union { + u64 csr; + struct { + /* A[45:19] of limit address memory range */ + u64 me_limit:27; + u64 rsvd1:4; + u64 enable:1; /* Enable LLPR MESEG rule */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 reserved; + u64 scratchpad; + struct feature_fme_capability capability; + struct feature_fme_port port[MAX_FPGA_PORT_NUM]; + struct feature_fme_fab_status fab_status; + struct feature_fme_bitstream_id bitstream_id; + struct feature_fme_bitstream_md bitstream_md; + struct feature_fme_genprotrange2_base genprotrange2_base; + struct feature_fme_genprotrange2_limit genprotrange2_limit; + struct feature_fme_dxe_lock dxe_lock; + struct feature_fme_iommu_ctrl iommu_ctrl; + struct feature_fme_iommu_stat iommu_stat; + struct feature_fme_pcie0_ctrl pcie0_control; + struct feature_fme_llpr_smrr_base smrr_base; + struct feature_fme_llpr_smrr_mask smrr_mask; + struct feature_fme_llpr_smrr2_base smrr2_base; + struct feature_fme_llpr_smrr2_mask smrr2_mask; + struct feature_fme_llpr_meseg_base meseg_base; + struct feature_fme_llpr_meseg_limit meseg_limit; +}; + +struct feature_port_capability { + union { + u64 csr; + struct { + u8 port_number:2; /* Port Number 0-3 */ + u8 rsvd1:6; /* Reserved */ + u16 mmio_size; /* User MMIO size in KB */ + u8 rsvd2; /* Reserved */ + u8 sp_intr_num:4; /* Supported interrupts num */ + u32 rsvd3:28; /* Reserved */ + }; + }; +}; + +struct feature_port_control { + union { + u64 csr; + struct { + u8 port_sftrst:1; /* Port Soft Reset */ + u8 rsvd1:1; /* Reserved */ + u8 latency_tolerance:1;/* '1' >= 40us, '0' < 40us */ + u8 rsvd2:1; /* Reserved */ + u8 port_sftrst_ack:1; /* HW ACK for Soft Reset */ + u64 rsvd3:59; /* Reserved */ + }; + }; +}; + +#define PORT_POWER_STATE_NORMAL 0 +#define PORT_POWER_STATE_AP1 1 +#define PORT_POWER_STATE_AP2 2 +#define PORT_POWER_STATE_AP6 6 + +struct feature_port_status { + union { + u64 csr; + struct { + u8 port_freeze:1; /* '1' - freezed '0' - normal */ + u8 rsvd1:7; /* Reserved */ + u8 power_state:4; /* Power State */ + u8 ap1_event:1; /* AP1 event was detected */ + u8 ap2_event:1; /* AP2 event was detected */ + u64 rsvd2:50; /* Reserved */ + }; + }; +}; + +/* Port Header Register Set */ +struct feature_port_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 port_mailbox; + u64 scratchpad; + struct feature_port_capability capability; + struct feature_port_control control; + struct feature_port_status status; + u64 rsvd2; + u64 user_clk_freq_cmd0; + u64 user_clk_freq_cmd1; + u64 user_clk_freq_sts0; + u64 user_clk_freq_sts1; +}; + +struct feature_fme_tmp_threshold { + union { + u64 csr; + struct { + u8 tmp_thshold1:7; /* temperature Threshold 1 */ + /* temperature Threshold 1 enable/disable */ + u8 tmp_thshold1_enable:1; + u8 tmp_thshold2:7; /* temperature Threshold 2 */ + /* temperature Threshold 2 enable /disable */ + u8 tmp_thshold2_enable:1; + u8 pro_hot_setpoint:7; /* Proc Hot set point */ + u8 rsvd4:1; /* Reserved */ + u8 therm_trip_thshold:7; /* Thermeal Trip Threshold */ + u8 rsvd3:1; /* Reserved */ + u8 thshold1_status:1; /* Threshold 1 Status */ + u8 thshold2_status:1; /* Threshold 2 Status */ + u8 rsvd5:1; /* Reserved */ + /* Thermeal Trip Threshold status */ + u8 therm_trip_thshold_status:1; + u8 rsvd6:4; /* Reserved */ + /* Validation mode- Force Proc Hot */ + u8 valmodeforce:1; + /* Validation mode - Therm trip Hot */ + u8 valmodetherm:1; + u8 rsvd2:2; /* Reserved */ + u8 thshold_policy:1; /* threshold policy */ + u32 rsvd:19; /* Reserved */ + }; + }; +}; + +/* Temperature Sensor Read values format 1 */ +struct feature_fme_temp_rdsensor_fmt1 { + union { + u64 csr; + struct { + /* Reads out FPGA temperature in celsius */ + u8 fpga_temp:7; + u8 rsvd0:1; /* Reserved */ + /* Temperature reading sequence number */ + u16 tmp_reading_seq_num; + /* Temperature reading is valid */ + u8 tmp_reading_valid:1; + u8 rsvd1:7; /* Reserved */ + u16 dbg_mode:10; /* Debug mode */ + u32 rsvd2:22; /* Reserved */ + }; + }; +}; + +/* Temperature sensor read values format 2 */ +struct feature_fme_temp_rdsensor_fmt2 { + u64 rsvd; /* Reserved */ +}; + +/* Temperature Threshold Capability Register */ +struct feature_fme_tmp_threshold_cap { + union { + u64 csr; + struct { + /* Temperature Threshold Unsupported */ + u8 tmp_thshold_disabled:1; + u64 rsvd:63; /* Reserved */ + }; + }; +}; + +/* FME THERNAL FEATURE */ +struct feature_fme_thermal { + struct feature_header header; + struct feature_fme_tmp_threshold threshold; + struct feature_fme_temp_rdsensor_fmt1 rdsensor_fm1; + struct feature_fme_temp_rdsensor_fmt2 rdsensor_fm2; + struct feature_fme_tmp_threshold_cap threshold_cap; +}; + +/* Power Status register */ +struct feature_fme_pm_status { + union { + u64 csr; + struct { + /* FPGA Power consumed, The format is to be defined */ + u32 pwr_consumed:18; + /* FPGA Latency Tolerance Reporting */ + u8 fpga_latency_report:1; + u64 rsvd:45; /* Reserved */ + }; + }; +}; + +/* AP Thresholds */ +struct feature_fme_pm_ap_threshold { + union { + u64 csr; + struct { + /* + * Number of clocks (5ns period) for assertion + * of FME_data + */ + u8 threshold1:7; + u8 rsvd1:1; + u8 threshold2:7; + u8 rsvd2:1; + u8 threshold1_status:1; + u8 threshold2_status:1; + u64 rsvd3:46; /* Reserved */ + }; + }; +}; + +/* Xeon Power Limit */ +struct feature_fme_pm_xeon_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FPGA Power Limit */ +struct feature_fme_pm_fpga_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FME POWER FEATURE */ +struct feature_fme_power { + struct feature_header header; + struct feature_fme_pm_status status; + struct feature_fme_pm_ap_threshold threshold; + struct feature_fme_pm_xeon_limit xeon_limit; + struct feature_fme_pm_fpga_limit fpga_limit; +}; + +#define CACHE_CHANNEL_RD 0 +#define CACHE_CHANNEL_WR 1 + +enum iperf_cache_events { + IPERF_CACHE_RD_HIT, + IPERF_CACHE_WR_HIT, + IPERF_CACHE_RD_MISS, + IPERF_CACHE_WR_MISS, + IPERF_CACHE_RSVD, /* reserved */ + IPERF_CACHE_HOLD_REQ, + IPERF_CACHE_DATA_WR_PORT_CONTEN, + IPERF_CACHE_TAG_WR_PORT_CONTEN, + IPERF_CACHE_TX_REQ_STALL, + IPERF_CACHE_RX_REQ_STALL, + IPERF_CACHE_EVICTIONS, +}; + +/* FPMON Cache Control */ +struct feature_fme_ifpmon_ch_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd1:7; /* Reserved */ + u8 freeze:1; /* Freeze if set to 1 */ + u8 rsvd2:7; /* Reserved */ + u8 cache_event:4; /* Select the cache event */ + u8 cci_chsel:1; /* Select the channel */ + u64 rsvd3:43; /* Reserved */ + }; + }; +}; + +/* FPMON Cache Counter */ +struct feature_fme_ifpmon_ch_ctr { + union { + u64 csr; + struct { + /* Cache Counter for even addresse */ + u64 cache_counter:48; + u16 rsvd:12; /* Reserved */ + /* Cache Event being reported */ + u8 event_code:4; + }; + }; +}; + +enum iperf_fab_events { + IPERF_FAB_PCIE0_RD, + IPERF_FAB_PCIE0_WR, + IPERF_FAB_PCIE1_RD, + IPERF_FAB_PCIE1_WR, + IPERF_FAB_UPI_RD, + IPERF_FAB_UPI_WR, + IPERF_FAB_MMIO_RD, + IPERF_FAB_MMIO_WR, +}; + +#define FAB_DISABLE_FILTER 0 +#define FAB_ENABLE_FILTER 1 + +/* FPMON FAB Control */ +struct feature_fme_ifpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_ifpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_ifpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +enum iperf_vtd_events { + IPERF_VTD_AFU_MEM_RD_TRANS, + IPERF_VTD_AFU_MEM_WR_TRANS, + IPERF_VTD_AFU_DEVTLB_RD_HIT, + IPERF_VTD_AFU_DEVTLB_WR_HIT, + IPERF_VTD_DEVTLB_4K_FILL, + IPERF_VTD_DEVTLB_2M_FILL, + IPERF_VTD_DEVTLB_1G_FILL, +}; + +/* VT-d control register */ +struct feature_fme_ifpmon_vtd_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d event counter */ +struct feature_fme_ifpmon_vtd_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +enum iperf_vtd_sip_events { + IPERF_VTD_SIP_IOTLB_4K_HIT, + IPERF_VTD_SIP_IOTLB_2M_HIT, + IPERF_VTD_SIP_IOTLB_1G_HIT, + IPERF_VTD_SIP_SLPWC_L3_HIT, + IPERF_VTD_SIP_SLPWC_L4_HIT, + IPERF_VTD_SIP_RCC_HIT, + IPERF_VTD_SIP_IOTLB_4K_MISS, + IPERF_VTD_SIP_IOTLB_2M_MISS, + IPERF_VTD_SIP_IOTLB_1G_MISS, + IPERF_VTD_SIP_SLPWC_L3_MISS, + IPERF_VTD_SIP_SLPWC_L4_MISS, + IPERF_VTD_SIP_RCC_MISS, +}; + +/* VT-d SIP control register */ +struct feature_fme_ifpmon_vtd_sip_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d SIP event counter */ +struct feature_fme_ifpmon_vtd_sip_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +/* FME IPERF FEATURE */ +struct feature_fme_iperf { + struct feature_header header; + struct feature_fme_ifpmon_ch_ctl ch_ctl; + struct feature_fme_ifpmon_ch_ctr ch_ctr0; + struct feature_fme_ifpmon_ch_ctr ch_ctr1; + struct feature_fme_ifpmon_fab_ctl fab_ctl; + struct feature_fme_ifpmon_fab_ctr fab_ctr; + struct feature_fme_ifpmon_clk_ctr clk; + struct feature_fme_ifpmon_vtd_ctl vtd_ctl; + struct feature_fme_ifpmon_vtd_ctr vtd_ctr; + struct feature_fme_ifpmon_vtd_sip_ctl vtd_sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr vtd_sip_ctr; +}; + +enum dperf_fab_events { + DPERF_FAB_PCIE0_RD, + DPERF_FAB_PCIE0_WR, + DPERF_FAB_MMIO_RD = 6, + DPERF_FAB_MMIO_WR, +}; + +/* FPMON FAB Control */ +struct feature_fme_dfpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_dfpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_dfpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +/* FME DPERF FEATURE */ +struct feature_fme_dperf { + struct feature_header header; + u64 rsvd[3]; + struct feature_fme_dfpmon_fab_ctl fab_ctl; + struct feature_fme_dfpmon_fab_ctr fab_ctr; + struct feature_fme_dfpmon_clk_ctr clk; +}; + +struct feature_fme_error0 { +#define FME_ERROR0_MASK 0xFFUL +#define FME_ERROR0_MASK_DEFAULT 0x40UL /* pcode workaround */ + union { + u64 csr; + struct { + u8 fabric_err:1; /* Fabric error */ + u8 fabfifo_overflow:1; /* Fabric fifo overflow */ + u8 kticdc_parity_err:2;/* KTI CDC Parity Error */ + u8 iommu_parity_err:1; /* IOMMU Parity error */ + /* AFU PF/VF access mismatch detected */ + u8 afu_acc_mode_err:1; + u8 mbp_err:1; /* Indicates an MBP event */ + /* PCIE0 CDC Parity Error */ + u8 pcie0cdc_parity_err:5; + /* PCIE1 CDC Parity Error */ + u8 pcie1cdc_parity_err:5; + /* CVL CDC Parity Error */ + u8 cvlcdc_parity_err:3; + u64 rsvd:44; /* Reserved */ + }; + }; +}; + +/* PCIe0 Error Status register */ +struct feature_fme_pcie0_error { +#define FME_PCIE0_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:52; /* Reserved */ + u8 vfnumb_err:1; /* Number of error VF */ + u8 funct_type_err:1; /* Virtual (1) or Physical */ + }; + }; +}; + +/* PCIe1 Error Status register */ +struct feature_fme_pcie1_error { +#define FME_PCIE1_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:54; /* Reserved */ + }; + }; +}; + +/* FME First Error register */ +struct feature_fme_first_error { +#define FME_FIRST_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered first + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered first + */ + u8 errReg_id:4; + }; + }; +}; + +/* FME Next Error register */ +struct feature_fme_next_error { +#define FME_NEXT_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered second + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered second + */ + u8 errReg_id:4; + }; + }; +}; + +/* RAS Non Fatal Error Status register */ +struct feature_fme_ras_nonfaterror { + union { + u64 csr; + struct { + /* thremal threshold AP1 */ + u8 temp_thresh_ap1:1; + /* thremal threshold AP2 */ + u8 temp_thresh_ap2:1; + u8 pcie_error:1; /* pcie Error */ + u8 portfatal_error:1; /* port fatal error */ + u8 proc_hot:1; /* Indicates a ProcHot event */ + /* Indicates an AFU PF/VF access mismatch */ + u8 afu_acc_mode_err:1; + /* Injected nonfata Error */ + u8 injected_nonfata_err:1; + u8 rsvd1:2; + /* Temperature threshold triggered AP6*/ + u8 temp_thresh_AP6:1; + /* Power threshold triggered AP1 */ + u8 power_thresh_AP1:1; + /* Power threshold triggered AP2 */ + u8 power_thresh_AP2:1; + /* Indicates a MBP event */ + u8 mbp_err:1; + u64 rsvd2:51; /* Reserved */ + }; + }; +}; + +/* RAS Catastrophic Fatal Error Status register */ +struct feature_fme_ras_catfaterror { + union { + u64 csr; + struct { + /* KTI Link layer error detected */ + u8 ktilink_fatal_err:1; + /* tag-n-cache error detected */ + u8 tagcch_fatal_err:1; + /* CCI error detected */ + u8 cci_fatal_err:1; + /* KTI Protocol error detected */ + u8 ktiprpto_fatal_err:1; + /* Fatal DRAM error detected */ + u8 dram_fatal_err:1; + /* IOMMU detected */ + u8 iommu_fatal_err:1; + /* Fabric Fatal Error */ + u8 fabric_fatal_err:1; + /* PCIe possion Error */ + u8 pcie_poison_err:1; + /* Injected fatal Error */ + u8 inject_fata_err:1; + /* Catastrophic CRC Error */ + u8 crc_catast_err:1; + /* Catastrophic Thermal Error */ + u8 therm_catast_err:1; + /* Injected Catastrophic Error */ + u8 injected_catast_err:1; + u64 rsvd:52; + }; + }; +}; + +/* RAS Error injection register */ +struct feature_fme_ras_error_inj { +#define FME_RAS_ERROR_INJ_MASK 0x7UL + union { + u64 csr; + struct { + u8 catast_error:1; /* Catastrophic error flag */ + u8 fatal_error:1; /* Fatal error flag */ + u8 nonfatal_error:1; /* NonFatal error flag */ + u64 rsvd:61; /* Reserved */ + }; + }; +}; + +/* FME error capabilities */ +struct feature_fme_error_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* FME ERR FEATURE */ +struct feature_fme_err { + struct feature_header header; + struct feature_fme_error0 fme_err_mask; + struct feature_fme_error0 fme_err; + struct feature_fme_pcie0_error pcie0_err_mask; + struct feature_fme_pcie0_error pcie0_err; + struct feature_fme_pcie1_error pcie1_err_mask; + struct feature_fme_pcie1_error pcie1_err; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + struct feature_fme_ras_nonfaterror ras_nonfat_mask; + struct feature_fme_ras_nonfaterror ras_nonfaterr; + struct feature_fme_ras_catfaterror ras_catfat_mask; + struct feature_fme_ras_catfaterror ras_catfaterr; + struct feature_fme_ras_error_inj ras_error_inj; + struct feature_fme_error_capability fme_err_capability; +}; + +/* FME Partial Reconfiguration Control */ +struct feature_fme_pr_ctl { + union { + u64 csr; + struct { + u8 pr_reset:1; /* Reset PR Engine */ + u8 rsvd3:3; /* Reserved */ + u8 pr_reset_ack:1; /* Reset PR Engine Ack */ + u8 rsvd4:3; /* Reserved */ + u8 pr_regionid:2; /* PR Region ID */ + u8 rsvd1:2; /* Reserved */ + u8 pr_start_req:1; /* PR Start Request */ + u8 pr_push_complete:1; /* PR Data push complete */ + u8 pr_kind:1; /* PR Data push complete */ + u32 rsvd:17; /* Reserved */ + u32 config_data; /* Config data TBD */ + }; + }; +}; + +/* FME Partial Reconfiguration Status */ +struct feature_fme_pr_status { + union { + u64 csr; + struct { + u16 pr_credit:9; /* PR Credits */ + u8 rsvd2:7; /* Reserved */ + u8 pr_status:1; /* PR status */ + u8 rsvd:3; /* Reserved */ + /* Altra PR Controller Block status */ + u8 pr_controller_status:3; + u8 rsvd1:1; /* Reserved */ + u8 pr_host_status:4; /* PR Host status */ + u8 rsvd3:4; /* Reserved */ + /* Security Block Status fields (TBD) */ + u32 security_bstatus; + }; + }; +}; + +/* FME Partial Reconfiguration Data */ +struct feature_fme_pr_data { + union { + u64 csr; /* PR data from the raw-binary file */ + struct { + /* PR data from the raw-binary file */ + u32 pr_data_raw; + u32 rsvd; + }; + }; +}; + +/* FME PR Public Key */ +struct feature_fme_pr_key { + u64 key; /* FME PR Public Hash */ +}; + +/* FME PR FEATURE */ +struct feature_fme_pr { + struct feature_header header; + /*Partial Reconfiguration control */ + struct feature_fme_pr_ctl ccip_fme_pr_control; + + /* Partial Reconfiguration Status */ + struct feature_fme_pr_status ccip_fme_pr_status; + + /* Partial Reconfiguration data */ + struct feature_fme_pr_data ccip_fme_pr_data; + + /* Partial Reconfiguration data */ + u64 ccip_fme_pr_err; + + u64 rsvd1[3]; + + /* Partial Reconfiguration data registers */ + u64 fme_pr_data1; + u64 fme_pr_data2; + u64 fme_pr_data3; + u64 fme_pr_data4; + u64 fme_pr_data5; + u64 fme_pr_data6; + u64 fme_pr_data7; + u64 fme_pr_data8; + + u64 rsvd2[5]; + + /* PR Interface ID */ + u64 fme_pr_intfc_id_l; + u64 fme_pr_intfc_id_h; + + /* MSIX filed to be Added */ +}; + +/* FME HSSI Control */ +struct feature_fme_hssi_eth_ctrl { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u16 address:16; /* HSSI address */ + /* + * HSSI comamnd + * 0x0 - No request + * 0x08 - SW register RD request + * 0x10 - SW register WR request + * 0x40 - Auxiliar bus RD request + * 0x80 - Auxiliar bus WR request + */ + u16 cmd:16; + }; + }; +}; + +/* FME HSSI Status */ +struct feature_fme_hssi_eth_stat { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u8 acknowledge:1; /* HSSI acknowledge */ + u8 spare:1; /* HSSI spare */ + u32 rsvd:30; /* Reserved */ + }; + }; +}; + +/* FME HSSI FEATURE */ +struct feature_fme_hssi { + struct feature_header header; + struct feature_fme_hssi_eth_ctrl hssi_control; + struct feature_fme_hssi_eth_stat hssi_status; +}; + +#define PORT_ERR_MASK 0xfff0703ff001f +struct feature_port_err_key { + union { + u64 csr; + struct { + /* Tx Channel0: Overflow */ + u8 tx_ch0_overflow:1; + /* Tx Channel0: Invalid request encoding */ + u8 tx_ch0_invaldreq :1; + /* Tx Channel0: Request with cl_len=3 not supported */ + u8 tx_ch0_cl_len3:1; + /* Tx Channel0: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch0_cl_len2:1; + /* Tx Channel0: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch0_cl_len4:1; + + u16 rsvd1:4; /* Reserved */ + + /* AFU MMIO RD received while PORT is in reset */ + u8 mmio_rd_whilerst:1; + /* AFU MMIO WR received while PORT is in reset */ + u8 mmio_wr_whilerst:1; + + u16 rsvd2:5; /* Reserved */ + + /* Tx Channel1: Overflow */ + u8 tx_ch1_overflow:1; + /* Tx Channel1: Invalid request encoding */ + u8 tx_ch1_invaldreq:1; + /* Tx Channel1: Request with cl_len=3 not supported */ + u8 tx_ch1_cl_len3:1; + /* Tx Channel1: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch1_cl_len2:1; + /* Tx Channel1: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch1_cl_len4:1; + + /* Tx Channel1: Insufficient data payload */ + u8 tx_ch1_insuff_data:1; + /* Tx Channel1: Data payload overrun */ + u8 tx_ch1_data_overrun:1; + /* Tx Channel1 : Incorrect address */ + u8 tx_ch1_incorr_addr:1; + /* Tx Channel1 : NON-Zero SOP Detected */ + u8 tx_ch1_nzsop:1; + /* Tx Channel1 : Illegal VC_SEL, atomic request VLO */ + u8 tx_ch1_illegal_vcsel:1; + + u8 rsvd3:6; /* Reserved */ + + /* MMIO Read Timeout in AFU */ + u8 mmioread_timeout:1; + + /* Tx Channel2: FIFO Overflow */ + u8 tx_ch2_fifo_overflow:1; + + /* MMIO read is not matching pending request */ + u8 unexp_mmio_resp:1; + + u8 rsvd4:5; /* Reserved */ + + /* Number of pending Requests: counter overflow */ + u8 tx_req_counter_overflow:1; + /* Req with Address violating SMM Range */ + u8 llpr_smrr_err:1; + /* Req with Address violating second SMM Range */ + u8 llpr_smrr2_err:1; + /* Req with Address violating ME Stolen message */ + u8 llpr_mesg_err:1; + /* Req with Address violating Generic Protected Range */ + u8 genprot_range_err:1; + /* Req with Address violating Legacy Range low */ + u8 legrange_low_err:1; + /* Req with Address violating Legacy Range High */ + u8 legrange_high_err:1; + /* Req with Address violating VGA memory range */ + u8 vgmem_range_err:1; + u8 page_fault_err:1; /* Page fault */ + u8 pmr_err:1; /* PMR Error */ + u8 ap6_event:1; /* AP6 event */ + /* VF FLR detected on Port with PF access control */ + u8 vfflr_access_err:1; + u16 rsvd5:12; /* Reserved */ + }; + }; +}; + +/* Port first error register, not contain all error bits in error register. */ +struct feature_port_first_err_key { + union { + u64 csr; + struct { + u8 tx_ch0_overflow:1; + u8 tx_ch0_invaldreq :1; + u8 tx_ch0_cl_len3:1; + u8 tx_ch0_cl_len2:1; + u8 tx_ch0_cl_len4:1; + u8 rsvd1:4; /* Reserved */ + u8 mmio_rd_whilerst:1; + u8 mmio_wr_whilerst:1; + u8 rsvd2:5; /* Reserved */ + u8 tx_ch1_overflow:1; + u8 tx_ch1_invaldreq:1; + u8 tx_ch1_cl_len3:1; + u8 tx_ch1_cl_len2:1; + u8 tx_ch1_cl_len4:1; + u8 tx_ch1_insuff_data:1; + u8 tx_ch1_data_overrun:1; + u8 tx_ch1_incorr_addr:1; + u8 tx_ch1_nzsop:1; + u8 tx_ch1_illegal_vcsel:1; + u8 rsvd3:6; /* Reserved */ + u8 mmioread_timeout:1; + u8 tx_ch2_fifo_overflow:1; + u8 rsvd4:6; /* Reserved */ + u8 tx_req_counter_overflow:1; + u32 rsvd5:23; /* Reserved */ + }; + }; +}; + +/* Port malformed Req0 */ +struct feature_port_malformed_req0 { + u64 header_lsb; +}; + +/* Port malformed Req1 */ +struct feature_port_malformed_req1 { + u64 header_msb; +}; + +/* Port debug register */ +struct feature_port_debug { + u64 port_debug; +}; + +/* Port error capabilities */ +struct feature_port_err_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE ERROR */ +struct feature_port_error { + struct feature_header header; + struct feature_port_err_key error_mask; + struct feature_port_err_key port_error; + struct feature_port_first_err_key port_first_error; + struct feature_port_malformed_req0 malreq0; + struct feature_port_malformed_req1 malreq1; + struct feature_port_debug port_debug; + struct feature_port_err_capability error_capability; +}; + +/* Port UMSG Capability */ +struct feature_port_umsg_cap { + union { + u64 csr; + struct { + /* Number of umsg allocated to this port */ + u8 umsg_allocated; + /* Enable / Disable UMsg engine for this port */ + u8 umsg_enable:1; + /* Usmg initialization status */ + u8 umsg_init_complete:1; + /* IOMMU can not translate the umsg base address */ + u8 umsg_trans_error:1; + u64 rsvd:53; /* Reserved */ + }; + }; +}; + +/* Port UMSG base address */ +struct feature_port_umsg_baseaddr { + union { + u64 csr; + struct { + u64 base_addr:48; /* 48 bit physical address */ + u16 rsvd; /* Reserved */ + }; + }; +}; + +struct feature_port_umsg_mode { + union { + u64 csr; + struct { + u32 umsg_hint_enable; /* UMSG hint enable/disable */ + u32 rsvd; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE UMSG */ +struct feature_port_umsg { + struct feature_header header; + struct feature_port_umsg_cap capability; + struct feature_port_umsg_baseaddr baseaddr; + struct feature_port_umsg_mode mode; +}; + +#define UMSG_EN_POLL_INVL 10 /* us */ +#define UMSG_EN_POLL_TIMEOUT 1000 /* us */ + +/* Port UINT Capability */ +struct feature_port_uint_cap { + union { + u64 csr; + struct { + u16 intr_num:12; /* Supported interrupts num */ + /* First MSI-X vector table entry number */ + u16 first_vec_num:12; + u64 rsvd:40; + }; + }; +}; + +/* PORT FEATURE UINT */ +struct feature_port_uint { + struct feature_header header; + struct feature_port_uint_cap capability; +}; + +/* STP region supports mmap operation, so use page aligned size. */ +#define PORT_FEATURE_STP_REGION_SIZE PAGE_ALIGN(sizeof(struct feature_port_stp)) + +/* Port STP status register (for debug only)*/ +struct feature_port_stp_status { + union { + u64 csr; + struct { + /* SLD Hub end-point read/write timeout */ + u8 sld_ep_timeout:1; + /* Remote STP in reset/disable */ + u8 rstp_disabled:1; + u8 unsupported_read:1; + /* MMIO timeout detected and faked with a response */ + u8 mmio_timeout:1; + u8 txfifo_count:4; + u8 rxfifo_count:4; + u8 txfifo_overflow:1; + u8 txfifo_underflow:1; + u8 rxfifo_overflow:1; + u8 rxfifo_underflow:1; + /* Number of MMIO write requests */ + u16 write_requests; + /* Number of MMIO read requests */ + u16 read_requests; + /* Number of MMIO read responses */ + u16 read_responses; + }; + }; +}; + +/* + * PORT FEATURE STP + * Most registers in STP region are not touched by driver, but mmapped to user + * space. So they are not defined in below data structure, as its actual size + * is 0x18c per spec. + */ +struct feature_port_stp { + struct feature_header header; + struct feature_port_stp_status stp_status; +}; + +/** + * enum fpga_pr_states - fpga PR states + * @FPGA_PR_STATE_UNKNOWN: can't determine state + * @FPGA_PR_STATE_WRITE_INIT: preparing FPGA for programming + * @FPGA_PR_STATE_WRITE_INIT_ERR: Error during WRITE_INIT stage + * @FPGA_PR_STATE_WRITE: writing image to FPGA + * @FPGA_PR_STATE_WRITE_ERR: Error while writing FPGA + * @FPGA_PR_STATE_WRITE_COMPLETE: Doing post programming steps + * @FPGA_PR_STATE_WRITE_COMPLETE_ERR: Error during WRITE_COMPLETE + * @FPGA_PR_STATE_OPERATING: FPGA PR done + */ +enum fpga_pr_states { + /* canot determine state states */ + FPGA_PR_STATE_UNKNOWN, + + /* write sequence: init, write, complete */ + FPGA_PR_STATE_WRITE_INIT, + FPGA_PR_STATE_WRITE_INIT_ERR, + FPGA_PR_STATE_WRITE, + FPGA_PR_STATE_WRITE_ERR, + FPGA_PR_STATE_WRITE_COMPLETE, + FPGA_PR_STATE_WRITE_COMPLETE_ERR, + + /* FPGA PR done */ + FPGA_PR_STATE_DONE, +}; + +/* + * FPGA Manager flags + * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported + */ +#define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + +/** + * struct fpga_pr_info - specific information to a FPGA PR + * @flags: boolean flags as defined above + * @pr_err: PR error code + * @state: fpga manager state + * @port_id: port id + */ +struct fpga_pr_info { + u32 flags; + u64 pr_err; + enum fpga_pr_states state; + int port_id; +}; + +#define DEFINE_FPGA_PR_ERR_MSG(_name_) \ +static const char * const _name_[] = { \ + "PR operation error detected", \ + "PR CRC error detected", \ + "PR incompatiable bitstream error detected", \ + "PR IP protocol error detected", \ + "PR FIFO overflow error detected", \ + "PR timeout error detected", \ + "PR secure load error detected", \ +} + +#define RST_POLL_INVL 10 /* us */ +#define RST_POLL_TIMEOUT 1000 /* us */ + +#define PR_WAIT_TIMEOUT 15000000 + +#define PR_HOST_STATUS_IDLE 0 +#define PR_MAX_ERR_NUM 7 + +DEFINE_FPGA_PR_ERR_MSG(pr_err_msg); + +/* + * green bitstream header must be byte-packed to match the + * real file format. + */ +struct bts_header { + u64 guid_h; + u64 guid_l; + u32 metadata_len; +}; + +#define GBS_GUID_H 0x414750466e6f6558 +#define GBS_GUID_L 0x31303076534247b7 +#define is_valid_bts(bts_hdr) \ + (((bts_hdr)->guid_h == GBS_GUID_H) && \ + ((bts_hdr)->guid_l == GBS_GUID_L)) + +#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 new file mode 100644 index 0000000..b7e73d8 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -0,0 +1,851 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "opae_hw_api.h" +#include "ifpga_api.h" + +#include "ifpga_hw.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +struct build_feature_devs_info { + struct opae_adapter_data_pci *pci_data; + + struct ifpga_afu_info *acc_info; + + void *fiu; + enum fpga_id_type current_type; + int current_port_id; + + void *ioaddr; + void *ioend; + uint64_t phys_addr; + int current_bar; + + void *pfme_hdr; + + struct ifpga_hw *hw; +}; + +struct feature_info { + const char *name; + uint32_t resource_size; + int feature_index; + int revision_id; + unsigned int vec_start; + unsigned int vec_cnt; + + struct feature_ops *ops; +}; + +/* 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, + } +}; + +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 = &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 = &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 = &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 = &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 + }, +}; + +static u64 feature_id(void __iomem *start) +{ + struct feature_header header; + + header.csr = readq(start); + + switch (header.type) { + case FEATURE_TYPE_FIU: + return FEATURE_ID_HEADER; + case FEATURE_TYPE_PRIVATE: + return header.id; + case FEATURE_TYPE_AFU: + return FEATURE_ID_AFU; + } + + WARN_ON(1); + return 0; +} + +static int +build_info_add_sub_feature(struct build_feature_devs_info *binfo, + struct feature_info *finfo, void __iomem *start) +{ + 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; + } + + 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->phys_addr = binfo->phys_addr + + ((u8 *)start - (u8 *)binfo->ioaddr); + + if (vec_cnt) { + if (vec_start + vec_cnt <= vec_start) + return -EINVAL; + + ctx = zmalloc(sizeof(*ctx) * vec_cnt); + if (!ctx) + return -ENOMEM; + + for (i = 0; i < vec_cnt; i++) { + ctx[i].eventfd = -1; + ctx[i].idx = vec_start + i; + } + } + + feature->ctx = ctx; + feature->ctx_num = vec_cnt; + feature->vfio_dev_fd = binfo->pci_data->vfio_dev_fd; + + return ret; +} + +static int +create_feature_instance(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + struct feature_header *hdr = start; + + if (((u8 *)binfo->ioend - (u8 *)start) < finfo->resource_size) + return -EINVAL; + + 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); +} + +/* + * UAFU GUID is dynamic as it can be changed after FME downloads different + * Green Bitstream to the port, so we treat the unknown GUIDs which are + * attached on port's feature list as UAFU. + */ +static bool feature_is_UAFU(struct build_feature_devs_info *binfo) +{ + if (binfo->current_type != PORT_ID) + return false; + + return true; +} + +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; + struct ifpga_afu_info *info; + void *start = (void *)hdr; + int ret; + + 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; + } + + if (ret) + return ret; + + /* FIXME: need to figure out a better name */ + info = 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->num_regions = 1; + + binfo->acc_info = info; + + return ret; +} + +static int parse_feature_afus(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + int ret; + struct feature_afu_header *afu_hdr, header; + u8 __iomem *start; + u8 __iomem *end = binfo->ioend; + + start = (u8 __iomem *)hdr; + for (; start < end; start += header.next_afu) { + if (end - start < + (unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr))) + return -EINVAL; + + hdr = (struct feature_header *)start; + afu_hdr = (struct feature_afu_header *)(hdr + 1); + header.csr = readq(&afu_hdr->csr); + + if (feature_is_UAFU(binfo)) { + ret = parse_feature_port_uafu(binfo, hdr); + if (ret) + return ret; + } + + if (!header.next_afu) + break; + } + + return 0; +} + +/* create and register proper private data */ +static int build_info_commit_dev(struct build_feature_devs_info *binfo) +{ + struct ifpga_afu_info *info = binfo->acc_info; + struct ifpga_hw *hw = binfo->hw; + struct opae_manager *mgr; + struct opae_bridge *br; + struct opae_accelerator *acc; + + if (!binfo->fiu) + return 0; + + if (binfo->current_type == PORT_ID) { + /* return error if no valid acc info data structure */ + if (!info) + return -EFAULT; + + br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops, + binfo->fiu); + if (!br) + return -ENOMEM; + + br->id = binfo->current_port_id; + + /* update irq info */ + info->num_irqs = port_features[PORT_FEATURE_ID_UINT].vec_cnt; + + acc = opae_accelerator_alloc(hw->adapter->name, + &ifpga_acc_ops, info); + if (!acc) { + opae_bridge_free(br); + return -ENOMEM; + } + + acc->br = br; + acc->index = br->id; + + opae_adapter_add_acc(hw->adapter, acc); + + } else if (binfo->current_type == FME_ID) { + mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops, + binfo->fiu); + if (!mgr) + return -ENOMEM; + + mgr->adapter = hw->adapter; + hw->adapter->mgr = mgr; + } + + binfo->fiu = NULL; + + return 0; +} + +static int +build_info_create_dev(struct build_feature_devs_info *binfo, + enum fpga_id_type type, unsigned int index) +{ + int ret; + + ret = build_info_commit_dev(binfo); + if (ret) + return ret; + + binfo->current_type = type; + + if (type == FME_ID) { + binfo->fiu = &binfo->hw->fme; + } else if (type == PORT_ID) { + binfo->fiu = &binfo->hw->port[index]; + binfo->current_port_id = index; + } + + return 0; +} + +static int parse_feature_fme(struct build_feature_devs_info *binfo, + struct feature_header *start) +{ + struct ifpga_hw *hw = binfo->hw; + struct ifpga_fme_hw *fme = &hw->fme; + int ret; + + ret = build_info_create_dev(binfo, FME_ID, 0); + if (ret) + return ret; + + /* Update FME states */ + fme->state = IFPGA_FME_IMPLEMENTED; + fme->parent = hw; + spinlock_init(&fme->lock); + + return create_feature_instance(binfo, start, + &fme_features[FME_FEATURE_ID_HEADER]); +} + +static int parse_feature_port(struct build_feature_devs_info *binfo, + void __iomem *start) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + struct ifpga_hw *hw = binfo->hw; + struct ifpga_port_hw *port; + unsigned int port_id; + int ret; + + /* Get current port's id */ + port_hdr = (struct feature_port_header *)start; + capability.csr = readq(&port_hdr->capability); + port_id = capability.port_number; + + ret = build_info_create_dev(binfo, PORT_ID, port_id); + if (ret) + return ret; + + /*found a Port device*/ + port = &hw->port[port_id]; + port->port_id = binfo->current_port_id; + port->parent = hw; + port->state = IFPGA_PORT_ATTACHED; + spinlock_init(&port->lock); + + return create_feature_instance(binfo, start, + &port_features[PORT_FEATURE_ID_HEADER]); +} + +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); +} + +static int parse_feature_fiu(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + struct feature_fiu_header *fiu_hdr, fiu_header; + u8 __iomem *start = (u8 __iomem *)hdr; + int ret; + + header.csr = readq(hdr); + + switch (header.id) { + case FEATURE_FIU_ID_FME: + ret = parse_feature_fme(binfo, hdr); + binfo->pfme_hdr = hdr; + if (ret) + return ret; + break; + case FEATURE_FIU_ID_PORT: + ret = parse_feature_port(binfo, hdr); + enable_port_uafu(binfo, hdr); + if (ret) + return ret; + + /* Check Port FIU's next_afu pointer to User AFU DFH */ + fiu_hdr = (struct feature_fiu_header *)(hdr + 1); + fiu_header.csr = readq(&fiu_hdr->csr); + + if (fiu_header.next_afu) { + start += fiu_header.next_afu; + ret = parse_feature_afus(binfo, + (struct feature_header *)start); + if (ret) + return ret; + } else { + dev_info(binfo, "No AFUs detected on Port\n"); + } + + break; + default: + dev_info(binfo, "FIU TYPE %d is not supported yet.\n", + header.id); + } + + return 0; +} + +static void parse_feature_irqs(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + finfo->vec_start = 0; + finfo->vec_cnt = 0; + + UNUSED(binfo); + + if (!strcmp(finfo->name, PORT_FEATURE_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; + } else { + dev_debug(binfo, "UAFU doesn't support interrupt\n"); + } + } else if (!strcmp(finfo->name, PORT_FEATURE_ERR)) { + 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; + } else { + dev_debug(&binfo, "Port error doesn't support interrupt\n"); + } + + } else if (!strcmp(finfo->name, FME_FEATURE_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; + } else { + dev_debug(&binfo, "FME error doesn't support interrupt\n"); + } + } +} + +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; + } + + parse_feature_irqs(binfo, hdr, &fme_features[header.id]); + + return create_feature_instance(binfo, hdr, &fme_features[header.id]); +} + +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; + + 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]); + + return create_feature_instance(binfo, hdr, &port_features[id]); +} + +static int parse_feature_private(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + + header.csr = readq(hdr); + + switch (binfo->current_type) { + case FME_ID: + return parse_feature_fme_private(binfo, hdr); + case PORT_ID: + return parse_feature_port_private(binfo, hdr); + default: + dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n", + header.id, binfo->current_type); + } + return 0; +} + +static int parse_feature(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + int ret = 0; + + header.csr = readq(hdr); + + switch (header.type) { + case FEATURE_TYPE_AFU: + ret = parse_feature_afus(binfo, hdr); + break; + case FEATURE_TYPE_PRIVATE: + ret = parse_feature_private(binfo, hdr); + break; + case FEATURE_TYPE_FIU: + ret = parse_feature_fiu(binfo, hdr); + break; + default: + dev_err(binfo, "Feature Type %x is not supported.\n", + hdr->type); + }; + + return ret; +} + +static int +parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start) +{ + struct feature_header *hdr, header; + u8 __iomem *end = (u8 __iomem *)binfo->ioend; + int ret = 0; + + for (; start < end; start += header.next_header_offset) { + if (end - start < (unsigned int)sizeof(*hdr)) { + dev_err(binfo, "The region is too small to contain a feature.\n"); + ret = -EINVAL; + break; + } + + hdr = (struct feature_header *)start; + ret = parse_feature(binfo, hdr); + if (ret) + return ret; + + header.csr = readq(hdr); + if (!header.next_header_offset) + break; + } + + return build_info_commit_dev(binfo); +} + +/* switch the memory mapping to BAR# @bar */ +static int parse_switch_to(struct build_feature_devs_info *binfo, int bar) +{ + struct opae_adapter_data_pci *pci_data = binfo->pci_data; + + if (!pci_data->region[bar].addr) + return -ENOMEM; + + binfo->ioaddr = pci_data->region[bar].addr; + binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len; + binfo->phys_addr = pci_data->region[bar].phys_addr; + binfo->current_bar = bar; + + return 0; +} + +static int parse_ports_from_fme(struct build_feature_devs_info *binfo) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_port port; + int i = 0, ret = 0; + + if (!binfo->pfme_hdr) { + dev_info(binfo, "VF is detected.\n"); + return ret; + } + + fme_hdr = binfo->pfme_hdr; + + do { + port.csr = readq(&fme_hdr->port[i]); + if (!port.port_implemented) + break; + + /* skip port which only could be accessed via VF */ + if (port.afu_access_control == FME_AFU_ACCESS_VF) + continue; + + ret = parse_switch_to(binfo, port.port_bar); + if (ret) + break; + + ret = parse_feature_list(binfo, + (u8 __iomem *)binfo->ioaddr + + port.port_offset); + if (ret) + break; + } while (++i < MAX_FPGA_PORT_NUM); + + return ret; +} + +static struct build_feature_devs_info * +build_info_alloc_and_init(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + + binfo = zmalloc(sizeof(*binfo)); + if (!binfo) + return binfo; + + binfo->hw = hw; + binfo->pci_data = hw->pci_data; + + /* fpga feature list starts from BAR 0 */ + if (parse_switch_to(binfo, 0)) { + free(binfo); + return NULL; + } + + return binfo; +} + +static void build_info_free(struct build_feature_devs_info *binfo) +{ + free(binfo); +} + +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; + + 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]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr: 0x%lx\n", + feature->name, (unsigned long long)feature->addr, + (unsigned long long)feature->addr + feature->size - 1, + feature->phys_addr); + } + + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) { + port = &hw->port[i]; + + if (port->state != IFPGA_PORT_ATTACHED) + continue; + + dev_info(hw, "port device: %d\n", port->port_id); + + for (j = 0; j < PORT_FEATURE_ID_MAX; j++) { + feature = &port->sub_feature[j]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr:0x%lx\n", + feature->name, + (unsigned long long)feature->addr, + (unsigned long long)feature->addr + + feature->size - 1, + feature->phys_addr); + } + } +} + +int ifpga_bus_enumerate(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + int ret; + + binfo = build_info_alloc_and_init(hw); + if (!binfo) + return -ENOMEM; + + ret = parse_feature_list(binfo, binfo->ioaddr); + if (ret) + goto exit; + + ret = parse_ports_from_fme(binfo); + if (ret) + goto exit; + + ifpga_print_device_feature_list(hw); + +exit: + build_info_free(binfo); + return ret; +} + +int ifpga_bus_init(struct ifpga_hw *hw) +{ + int i; + + fme_hw_init(&hw->fme); + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) + port_hw_init(&hw->port[i]); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h new file mode 100644 index 0000000..0df7b2f --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h @@ -0,0 +1,38 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_ENUMERATE_H_ +#define _IFPGA_ENUMERATE_H_ + +int ifpga_bus_init(struct ifpga_hw *hw); +int ifpga_bus_enumerate(struct ifpga_hw *hw); + +#endif /* _IFPGA_ENUMERATE_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c new file mode 100644 index 0000000..0c632e6 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -0,0 +1,341 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include <linux/vfio.h> +#include <sys/ioctl.h> + +#include "ifpga_feature_dev.h" + +/* + * Enable Port by clear the port soft reset bit, which is set by default. + * The AFU is unable to respond to any MMIO access while in reset. + * __fpga_port_enable function should only be used after __fpga_port_disable + * function. + */ +void __fpga_port_enable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + WARN_ON(!port->disable_count); + + if (--port->disable_count != 0) + return; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x0; + writeq(control.csr, &port_hdr->control); +} + +int __fpga_port_disable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + if (port->disable_count++ != 0) + return 0; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + /* Set port soft reset */ + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x1; + writeq(control.csr, &port_hdr->control); + + /* + * HW sets ack bit to 1 when all outstanding requests have been drained + * on this port and minimum soft reset pulse width has elapsed. + * Driver polls port_soft_reset_ack to determine if reset done by HW. + */ + control.port_sftrst_ack = 1; + + if (fpga_wait_register_field(port_sftrst_ack, control, + &port_hdr->control, RST_POLL_TIMEOUT, + RST_POLL_INVL)) { + dev_err(port, "timeout, fail to reset device\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) +{ + struct feature_port_header *port_hdr; + u64 guidl, guidh; + + port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU); + + spinlock_lock(&port->lock); + guidl = readq(&port_hdr->afu_header.guid.b[0]); + guidh = readq(&port_hdr->afu_header.guid.b[8]); + spinlock_unlock(&port->lock); + + printf("%s: guidl=0x%lx, guidh=0x%lx\n", __func__, guidl, guidh); + + memcpy(uuid->b, &guidl, sizeof(u64)); + memcpy(uuid->b + 8, &guidh, sizeof(u64)); + + return 0; +} + +/* Mask / Unmask Port Errors by the Error Mask register. */ +void port_err_mask(struct ifpga_port_hw *port, bool mask) +{ + struct feature_port_error *port_err; + struct feature_port_err_key err_mask; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + if (mask) + err_mask.csr = PORT_ERR_MASK; + else + err_mask.csr = 0; + + writeq(err_mask.csr, &port_err->error_mask); +} + +/* Clear All Port Errors. */ +int port_err_clear(struct ifpga_port_hw *port, u64 err) +{ + struct feature_port_header *port_hdr; + struct feature_port_error *port_err; + struct feature_port_err_key mask; + struct feature_port_first_err_key first; + struct feature_port_status status; + int ret = 0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + /* + * Clear All Port Errors + * + * - Check for AP6 State + * - Halt Port by keeping Port in reset + * - Set PORT Error mask to all 1 to mask errors + * - Clear all errors + * - Set Port mask to all 0 to enable errors + * - All errors start capturing new errors + * - Enable Port by pulling the port out of reset + */ + + /* If device is still in AP6 state, can not clear any error.*/ + status.csr = readq(&port_hdr->status); + if (status.power_state == PORT_POWER_STATE_AP6) { + dev_err(dev, "Could not clear errors, device in AP6 state.\n"); + return -EBUSY; + } + + /* Halt Port by keeping Port in reset */ + ret = __fpga_port_disable(port); + if (ret) + return ret; + + /* Mask all errors */ + port_err_mask(port, true); + + /* Clear errors if err input matches with current port errors.*/ + mask.csr = readq(&port_err->port_error); + + if (mask.csr == err) { + writeq(mask.csr, &port_err->port_error); + + first.csr = readq(&port_err->port_first_error); + writeq(first.csr, &port_err->port_first_error); + } else { + ret = -EBUSY; + } + + /* Clear mask */ + port_err_mask(port, false); + + /* Enable the Port by clear the reset */ + __fpga_port_enable(port); + + return ret; +} + +int port_clear_error(struct ifpga_port_hw *port) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + + dev_info(port, "read port error: 0x%lx\n", error.csr); + + return port_err_clear(port, error.csr); +} + +void fme_hw_uinit(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return; + + 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); + } +} + +int fme_hw_init(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i, ret; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + 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; + } + } + } + + return 0; +} + +void port_hw_uinit(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i; + + 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); + } +} + +int port_hw_init(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i, 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; + } + } + } + + return 0; +} + +/* + * FIXME: we should get msix vec count during pci enumeration instead of + * below hardcode value. + */ +#define FPGA_MSIX_VEC_COUNT 20 +/* irq set buffer length for interrupt */ +#define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \ + sizeof(int) * FPGA_MSIX_VEC_COUNT) + +/* only support msix for now*/ +static int vfio_msix_enable_block(s32 vfio_dev_fd, unsigned int vec_start, + unsigned int count, s32 *fds) +{ + char irq_set_buf[MSIX_IRQ_SET_BUF_LEN]; + struct vfio_irq_set *irq_set; + int len, ret; + int *fd_ptr; + + len = sizeof(irq_set_buf); + + irq_set = (struct vfio_irq_set *)irq_set_buf; + irq_set->argsz = len; + irq_set->count = count; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; + irq_set->start = vec_start; + + fd_ptr = (int *)&irq_set->data; + memcpy(fd_ptr, fds, sizeof(int) * count); + + ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set); + if (ret) + printf("Error enabling MSI-X interrupts\n"); + + return ret; +} + +int fpga_msix_set_block(struct feature *feature, unsigned int start, + unsigned int count, s32 *fds) +{ + struct feature_irq_ctx *ctx = feature->ctx; + unsigned int i; + int ret; + + if (start >= feature->ctx_num || start + count > feature->ctx_num) + return -EINVAL; + + /* assume that each feature has continuous vector space in msix*/ + ret = vfio_msix_enable_block(feature->vfio_dev_fd, + ctx[start].idx, count, fds); + if (!ret) { + for (i = 0; i < count; i++) + ctx[i].eventfd = fds[i]; + } + + return ret; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h new file mode 100644 index 0000000..715975c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -0,0 +1,191 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_FEATURE_DEV_H_ +#define _IFPGA_FEATURE_DEV_H_ + +#include "ifpga_hw.h" + +static inline struct ifpga_port_hw * +get_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return NULL; + + return &hw->port[port_id]; +} + +#define ifpga_for_each_feature(hw, feature) \ + for ((feature) = (hw)->sub_feature; \ + (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++) + +static inline struct feature * +get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(fme, feature) { + if (feature->id == id) + return feature; + } + + return NULL; +} + +static inline struct feature * +get_port_feature_by_id(struct ifpga_port_hw *port, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(port, feature) { + 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; +} + +static inline void * +get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index) +{ + return port->sub_feature[index].addr; +} + +static inline bool +is_fme_feature_present(struct ifpga_fme_hw *fme, int index) +{ + return !!get_fme_feature_ioaddr_by_index(fme, index); +} + +static inline bool +is_port_feature_present(struct ifpga_port_hw *port, int index) +{ + return !!get_port_feature_ioaddr_by_index(port, index); +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid); + +int __fpga_port_disable(struct ifpga_port_hw *port); +void __fpga_port_enable(struct ifpga_port_hw *port); + +static inline int fpga_port_disable(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_disable(port); + spinlock_unlock(&port->lock); + return ret; +} + +static inline int fpga_port_enable(struct ifpga_port_hw *port) +{ + spinlock_lock(&port->lock); + __fpga_port_enable(port); + spinlock_unlock(&port->lock); + + return 0; +} + +static inline int __fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + ret = __fpga_port_disable(port); + if (ret) + return ret; + + __fpga_port_enable(port); + + return 0; +} + +static inline int fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_reset(port); + spinlock_unlock(&port->lock); + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +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); +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set); + +int fme_hw_init(struct ifpga_fme_hw *fme); +void fme_hw_uinit(struct ifpga_fme_hw *fme); +void port_hw_uinit(struct ifpga_port_hw *port); +int port_hw_init(struct ifpga_port_hw *port); +int port_clear_error(struct ifpga_port_hw *port); +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; + +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); + +/* This struct is used when parsing uafu irq_set */ +struct fpga_uafu_irq_set { + u32 start; + u32 count; + s32 *evtfds; +}; + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set); + +extern struct feature_ops port_hdr_ops; +extern struct feature_ops port_error_ops; +extern struct feature_ops port_stp_ops; +extern struct feature_ops port_uint_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 new file mode 100644 index 0000000..43a0a1c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -0,0 +1,761 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +#define PWR_THRESHOLD_MAX 0x7F + +int fme_get_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +/* fme private feature head */ +static int fme_hdr_init(struct feature *feature) +{ + struct feature_fme_header *fme_hdr; + + fme_hdr = (struct feature_fme_header *)feature->addr; + + dev_info(NULL, "FME HDR Init.\n"); + dev_info(NULL, "FME cap %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + return 0; +} + +static void fme_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME HDR UInit.\n"); +} + +static int fme_hdr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&fme_hdr->header); + *revision = header.revision; + + return 0; +} + +static int fme_hdr_get_ports_num(struct ifpga_fme_hw *fme, u64 *ports_num) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *ports_num = fme_capability.num_ports; + + return 0; +} + +static int fme_hdr_get_cache_size(struct ifpga_fme_hw *fme, u64 *cache_size) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *cache_size = fme_capability.cache_size; + + return 0; +} + +static int fme_hdr_get_version(struct ifpga_fme_hw *fme, u64 *version) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *version = fme_capability.fabric_verid; + + return 0; +} + +static int fme_hdr_get_socket_id(struct ifpga_fme_hw *fme, u64 *socket_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *socket_id = fme_capability.socket_id; + + return 0; +} + +static int fme_hdr_get_bitstream_id(struct ifpga_fme_hw *fme, + u64 *bitstream_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_id = readq(&fme_hdr->bitstream_id); + + return 0; +} + +static int fme_hdr_get_bitstream_metadata(struct ifpga_fme_hw *fme, + u64 *bitstream_metadata) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_metadata = readq(&fme_hdr->bitstream_md); + + return 0; +} + +static int +fme_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_HDR_PROP_REVISION: + return fme_hdr_get_revision(fme, &prop->data); + case FME_HDR_PROP_PORTS_NUM: + return fme_hdr_get_ports_num(fme, &prop->data); + case FME_HDR_PROP_CACHE_SIZE: + return fme_hdr_get_cache_size(fme, &prop->data); + case FME_HDR_PROP_VERSION: + return fme_hdr_get_version(fme, &prop->data); + case FME_HDR_PROP_SOCKET_ID: + return fme_hdr_get_socket_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_ID: + return fme_hdr_get_bitstream_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_METADATA: + return fme_hdr_get_bitstream_metadata(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_hdr_ops = { + .init = fme_hdr_init, + .uinit = fme_hdr_uinit, + .get_prop = fme_hdr_get_prop, +}; + +/* thermal management */ +static int fme_thermal_get_threshold1(struct ifpga_fme_hw *fme, u64 *thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1 = temp_threshold.tmp_thshold1; + + return 0; +} + +static int fme_thermal_set_threshold1(struct ifpga_fme_hw *fme, u64 thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres1 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres1 == 0) { + tmp_threshold.tmp_thshold1_enable = 0; + tmp_threshold.tmp_thshold1 = thres1; + } else { + tmp_threshold.tmp_thshold1_enable = 1; + tmp_threshold.tmp_thshold1 = thres1; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold2(struct ifpga_fme_hw *fme, u64 *thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres2 = temp_threshold.tmp_thshold2; + + return 0; +} + +static int fme_thermal_set_threshold2(struct ifpga_fme_hw *fme, u64 thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres2 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres2 == 0) { + tmp_threshold.tmp_thshold2_enable = 0; + tmp_threshold.tmp_thshold2 = thres2; + } else { + tmp_threshold.tmp_thshold2_enable = 1; + tmp_threshold.tmp_thshold2 = thres2; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold_trip(struct ifpga_fme_hw *fme, + u64 *thres_trip) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres_trip = temp_threshold.therm_trip_thshold; + + return 0; +} + +static int fme_thermal_get_threshold1_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold1_status; + + return 0; +} + +static int fme_thermal_get_threshold2_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold2_status; + + return 0; +} + +static int fme_thermal_get_threshold1_policy(struct ifpga_fme_hw *fme, + u64 *thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_policy = temp_threshold.thshold_policy; + + return 0; +} + +static int fme_thermal_set_threshold1_policy(struct ifpga_fme_hw *fme, + u64 thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold tmp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + + if (thres1_policy == 0) { + tmp_threshold.thshold_policy = 0; + } else if (thres1_policy == 1) { + tmp_threshold.thshold_policy = 1; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_temperature(struct ifpga_fme_hw *fme, u64 *temp) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_temp_rdsensor_fmt1 temp_rdsensor_fmt1; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_rdsensor_fmt1.csr = readq(&thermal->rdsensor_fm1); + *temp = temp_rdsensor_fmt1.fpga_temp; + + return 0; +} + +static int fme_thermal_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_thermal *fme_thermal + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + struct feature_header header; + + header.csr = readq(&fme_thermal->header); + *revision = header.revision; + + return 0; +} + +#define FME_THERMAL_CAP_NO_TMP_THRESHOLD 0x1 + +static int fme_thermal_mgmt_init(struct feature *feature) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold_cap thermal_cap; + + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt Init.\n"); + + fme_thermal = (struct feature_fme_thermal *)feature->addr; + thermal_cap.csr = readq(&fme_thermal->threshold_cap); + + dev_info(NULL, "FME thermal cap %llx.\n", + (unsigned long long)fme_thermal->threshold_cap.csr); + + if (thermal_cap.tmp_thshold_disabled) + feature->cap |= FME_THERMAL_CAP_NO_TMP_THRESHOLD; + + return 0; +} + +static void fme_thermal_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt UInit.\n"); +} + +static int +fme_thermal_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_set_threshold1(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_set_threshold2(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_set_threshold1_policy(fme, prop->data); + } + + return -ENOENT; +} + +static int +fme_thermal_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD && + prop->prop_id != FME_THERMAL_PROP_TEMPERATURE && + prop->prop_id != FME_THERMAL_PROP_REVISION) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_get_threshold1(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_get_threshold2(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD_TRIP: + return fme_thermal_get_threshold_trip(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_REACHED: + return fme_thermal_get_threshold1_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2_REACHED: + return fme_thermal_get_threshold2_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_get_threshold1_policy(fme, &prop->data); + case FME_THERMAL_PROP_TEMPERATURE: + return fme_thermal_get_temperature(fme, &prop->data); + case FME_THERMAL_PROP_REVISION: + return fme_thermal_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_thermal_mgmt_ops = { + .init = fme_thermal_mgmt_init, + .uinit = fme_thermal_mgmt_uinit, + .get_prop = fme_thermal_get_prop, + .set_prop = fme_thermal_set_prop, +}; + +static int fme_pwr_get_consumed(struct ifpga_fme_hw *fme, u64 *consumed) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *consumed = pm_status.pwr_consumed; + + return 0; +} + +static int fme_pwr_get_threshold1(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold1; + + return 0; +} + +static int fme_pwr_set_threshold1(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold1 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold2(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold2; + + return 0; +} + +static int fme_pwr_set_threshold2(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold2 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold1_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold1_status; + + return 0; +} + +static int fme_pwr_get_threshold2_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold2_status; + + return 0; +} + +static int fme_pwr_get_rtl(struct ifpga_fme_hw *fme, u64 *rtl) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *rtl = pm_status.fpga_latency_report; + + return 0; +} + +static int fme_pwr_get_xeon_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_xeon_limit xeon_limit; + + xeon_limit.csr = readq(&fme_power->xeon_limit); + + if (!xeon_limit.enable) + xeon_limit.pwr_limit = 0; + + *limit = xeon_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_fpga_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_fpga_limit fpga_limit; + + fpga_limit.csr = readq(&fme_power->fpga_limit); + + if (!fpga_limit.enable) + fpga_limit.pwr_limit = 0; + + *limit = fpga_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_header header; + + header.csr = readq(&fme_power->header); + *revision = header.revision; + + return 0; +} + +static int fme_power_mgmt_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt Init.\n"); + + return 0; +} + +static void fme_power_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt UInit.\n"); +} + +static int fme_power_mgmt_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_CONSUMED: + return fme_pwr_get_consumed(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_get_threshold1(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_get_threshold2(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1_STATUS: + return fme_pwr_get_threshold1_status(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2_STATUS: + return fme_pwr_get_threshold2_status(fme, &prop->data); + case FME_PWR_PROP_RTL: + return fme_pwr_get_rtl(fme, &prop->data); + case FME_PWR_PROP_XEON_LIMIT: + return fme_pwr_get_xeon_limit(fme, &prop->data); + case FME_PWR_PROP_FPGA_LIMIT: + return fme_pwr_get_fpga_limit(fme, &prop->data); + case FME_PWR_PROP_REVISION: + return fme_pwr_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_power_mgmt_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_set_threshold1(fme, prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_set_threshold2(fme, prop->data); + } + + return -ENOENT; +} + +struct 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, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c new file mode 100644 index 0000000..ae064ff --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c @@ -0,0 +1,328 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_dperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_clk_ctr clk; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + clk.afu_interf_clock = readq(&dperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_dperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_dperf *dperf; + struct feature_header header; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + header.csr = readq(&dperf->header); + *revision = header.revision; + + return 0; +} + +#define DPERF_TIMEOUT 30 + +static bool fabric_pobj_is_enabled(int port_id, + struct feature_fme_dperf *dperf) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + + ctl.csr = readq(&dperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum dperf_fab_events fab_event) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dfpmon_fab_ctr ctr; + struct feature_fme_dperf *dperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, dperf)) + goto exit; + + ctl.csr = readq(&dperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &dperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &dperf->fab_ctr, DPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&dperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_dperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, DPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, DPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(mmio_read, DPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, DPERF_FAB_MMIO_WR); + +static int fme_dperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_dperf *dperf; + int status; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + status = fabric_pobj_is_enabled(port_id, dperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_dperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dperf *dperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, dperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&dperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_dperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_dperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 + +static int fme_global_dperf_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf Init.\n"); + + return 0; +} + +static void fme_global_dperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf UInit.\n"); +} + +static int fme_dperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_dperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_dperf_get_fab_port_pcie0_read(fme, sub, &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_dperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* MMIO_READ */ + return fme_dperf_get_fab_port_mmio_read(fme, sub, &prop->data); + case 0x5: /* MMIO_WRITE */ + return fme_dperf_get_fab_port_mmio_write(fme, sub, &prop->data); + case 0x6: /* ENABLE */ + return fme_dperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_dperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_dperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_dperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_dperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_dperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE - fab root only prop */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_dperf_set_fab_freeze(fme, prop->data); + case 0x6: /* ENABLE - fab both root and sub */ + return fme_dperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_dperf_ops = { + .init = fme_global_dperf_init, + .uinit = fme_global_dperf_uinit, + .get_prop = fme_global_dperf_get_prop, + .set_prop = fme_global_dperf_set_prop, + +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c new file mode 100644 index 0000000..a8a6a3c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c @@ -0,0 +1,430 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +static int fme_err_get_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + + fme_error0.csr = readq(&fme_err->fme_err); + *val = fme_error0.csr; + + return 0; +} + +static int fme_err_get_first_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_first_error fme_first_err; + + fme_first_err.csr = readq(&fme_err->fme_first_err); + *val = fme_first_err.err_reg_status; + + return 0; +} + +static int fme_err_get_next_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_next_error fme_next_err; + + fme_next_err.csr = readq(&fme_err->fme_next_err); + *val = fme_next_err.err_reg_status; + + return 0; +} + +static int fme_err_set_clear(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_ERROR0_MASK, &fme_err->fme_err_mask); + + fme_error0.csr = readq(&fme_err->fme_err); + if (val != fme_error0.csr) { + ret = -EBUSY; + goto exit; + } + + fme_first_err.csr = readq(&fme_err->fme_first_err); + fme_next_err.csr = readq(&fme_err->fme_next_err); + + writeq(fme_error0.csr & FME_ERROR0_MASK, &fme_err->fme_err); + writeq(fme_first_err.csr & FME_FIRST_ERROR_MASK, + &fme_err->fme_first_err); + writeq(fme_next_err.csr & FME_NEXT_ERROR_MASK, + &fme_err->fme_next_err); + +exit: + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_revision(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_header header; + + header.csr = readq(&fme_err->header); + *val = header.revision; + + return 0; +} + +static int fme_err_get_pcie0_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + + pcie0_err.csr = readq(&fme_err->pcie0_err); + *val = pcie0_err.csr; + + return 0; +} + +static int fme_err_set_pcie0_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE0_ERROR_MASK, &fme_err->pcie0_err_mask); + + pcie0_err.csr = readq(&fme_err->pcie0_err); + if (val != pcie0_err.csr) + ret = -EBUSY; + else + writeq(pcie0_err.csr & FME_PCIE0_ERROR_MASK, + &fme_err->pcie0_err); + + writeq(0UL, &fme_err->pcie0_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_pcie1_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + + pcie1_err.csr = readq(&fme_err->pcie1_err); + *val = pcie1_err.csr; + + return 0; +} + +static int fme_err_set_pcie1_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE1_ERROR_MASK, &fme_err->pcie1_err_mask); + + pcie1_err.csr = readq(&fme_err->pcie1_err); + if (val != pcie1_err.csr) + ret = -EBUSY; + else + writeq(pcie1_err.csr & FME_PCIE1_ERROR_MASK, + &fme_err->pcie1_err); + + writeq(0UL, &fme_err->pcie1_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_nonfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_nonfaterror ras_nonfaterr; + + ras_nonfaterr.csr = readq(&fme_err->ras_nonfaterr); + *val = ras_nonfaterr.csr; + + return 0; +} + +static int fme_err_get_catfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_catfaterror ras_catfaterr; + + ras_catfaterr.csr = readq(&fme_err->ras_catfaterr); + *val = ras_catfaterr.csr; + + return 0; +} + +static int fme_err_get_inject_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + *val = ras_error_inj.csr & FME_RAS_ERROR_INJ_MASK; + + return 0; +} + +static int fme_err_set_inject_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + spinlock_lock(&fme->lock); + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + + if (val <= FME_RAS_ERROR_INJ_MASK) { + ras_error_inj.csr = val; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(ras_error_inj.csr, &fme_err->ras_error_inj); + spinlock_unlock(&fme->lock); + + return 0; +} + +static void fme_error_enable(struct ifpga_fme_hw *fme) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + writeq(0UL, &fme_err->pcie0_err_mask); + writeq(0UL, &fme_err->pcie1_err_mask); + writeq(0UL, &fme_err->ras_nonfat_mask); + writeq(0UL, &fme_err->ras_catfat_mask); +} + +static int fme_global_error_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = feature->parent; + + fme_error_enable(fme); + + if (feature->ctx_num) + fme->capability |= FPGA_FME_CAP_ERR_IRQ; + + return 0; +} + +static void fme_global_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int fme_err_fme_err_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* ERRORS */ + return fme_err_get_errors(fme, &prop->data); + case 0x2: /* FIRST_ERROR */ + return fme_err_get_first_error(fme, &prop->data); + case 0x3: /* NEXT_ERROR */ + return fme_err_get_next_error(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x5: /* REVISION */ + return fme_err_get_revision(fme, &prop->data); + case 0x6: /* PCIE0_ERRORS */ + return fme_err_get_pcie0_errors(fme, &prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_get_pcie1_errors(fme, &prop->data); + case 0x8: /* NONFATAL_ERRORS */ + return fme_err_get_nonfatal_errors(fme, &prop->data); + case 0x9: /* CATFATAL_ERRORS */ + return fme_err_get_catfatal_errors(fme, &prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_get_inject_errors(fme, &prop->data); + case 0xb: /* REVISION*/ + return fme_err_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_get_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_err_fme_err_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x4: /* CLEAR */ + return fme_err_set_clear(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x6: /* PCIE0_ERRORS */ + return fme_err_set_pcie0_errors(fme, prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_set_pcie1_errors(fme, prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_set_inject_errors(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_set_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_set_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_global_err_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_fme_err_irq_set *err_irq_set = + (struct fpga_fme_err_irq_set *)irq_set; + struct ifpga_fme_hw *fme; + int ret; + + fme = (struct ifpga_fme_hw *)feature->parent; + + spinlock_lock(&fme->lock); + if (!(fme->capability & FPGA_FME_CAP_ERR_IRQ)) { + spinlock_unlock(&fme->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&fme->lock); + + return ret; +} + +struct feature_ops fme_global_err_ops = { + .init = fme_global_error_init, + .uinit = fme_global_error_uinit, + .get_prop = fme_global_error_get_prop, + .set_prop = fme_global_error_set_prop, + .set_irq = fme_global_err_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c new file mode 100644 index 0000000..6db2f45 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c @@ -0,0 +1,742 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_iperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_clk_ctr clk; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + clk.afu_interf_clock = readq(&iperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_iperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_iperf *iperf; + struct feature_header header; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + header.csr = readq(&iperf->header); + *revision = header.revision; + + return 0; +} + +static int fme_iperf_get_cache_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + *freeze = (u64)ctl.freeze; + return 0; +} + +static int fme_iperf_set_cache_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->ch_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define IPERF_TIMEOUT 30 + +static u64 read_cache_counter(struct ifpga_fme_hw *fme, + u8 channel, enum iperf_cache_events event) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + struct feature_fme_ifpmon_ch_ctr ctr0, ctr1; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* set channel access type and cache event code. */ + ctl.csr = readq(&iperf->ch_ctl); + ctl.cci_chsel = channel; + ctl.cache_event = event; + writeq(ctl.csr, &iperf->ch_ctl); + + /* check the event type in the counter registers */ + ctr0.event_code = event; + + if (fpga_wait_register_field(event_code, ctr0, + &iperf->ch_ctr0, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched cache event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr0.csr = readq(&iperf->ch_ctr0); + ctr1.csr = readq(&iperf->ch_ctr1); + counter = ctr0.cache_counter + ctr1.cache_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define CACHE_SHOW(name, type, event) \ +static int fme_iperf_get_cache_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_cache_counter(fme, type, event); \ + return 0; \ +} + +CACHE_SHOW(read_hit, CACHE_CHANNEL_RD, IPERF_CACHE_RD_HIT); +CACHE_SHOW(read_miss, CACHE_CHANNEL_RD, IPERF_CACHE_RD_MISS); +CACHE_SHOW(write_hit, CACHE_CHANNEL_WR, IPERF_CACHE_WR_HIT); +CACHE_SHOW(write_miss, CACHE_CHANNEL_WR, IPERF_CACHE_WR_MISS); +CACHE_SHOW(hold_request, CACHE_CHANNEL_RD, IPERF_CACHE_HOLD_REQ); +CACHE_SHOW(tx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_TX_REQ_STALL); +CACHE_SHOW(rx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_RX_REQ_STALL); +CACHE_SHOW(rx_eviction, CACHE_CHANNEL_RD, IPERF_CACHE_EVICTIONS); +CACHE_SHOW(data_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_DATA_WR_PORT_CONTEN); +CACHE_SHOW(tag_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_TAG_WR_PORT_CONTEN); + +static int fme_iperf_get_vtd_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_vtd_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->vtd_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static u64 read_iommu_sip_counter(struct ifpga_fme_hw *fme, + enum iperf_vtd_sip_events event) +{ + struct feature_fme_ifpmon_vtd_sip_ctl sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr sip_ctr; + struct feature_fme_iperf *iperf; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + sip_ctl.csr = readq(&iperf->vtd_sip_ctl); + sip_ctl.vtd_evtcode = event; + writeq(sip_ctl.csr, &iperf->vtd_sip_ctl); + + sip_ctr.event_code = event; + + if (fpga_wait_register_field(event_code, sip_ctr, + &iperf->vtd_sip_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd SIP event type in counter registers\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + sip_ctr.csr = readq(&iperf->vtd_sip_ctr); + counter = sip_ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_SIP_SHOW(name, event) \ +static int fme_iperf_get_vtd_sip_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_iommu_sip_counter(fme, event); \ + return 0; \ +} + +VTD_SIP_SHOW(iotlb_4k_hit, IPERF_VTD_SIP_IOTLB_4K_HIT); +VTD_SIP_SHOW(iotlb_2m_hit, IPERF_VTD_SIP_IOTLB_2M_HIT); +VTD_SIP_SHOW(iotlb_1g_hit, IPERF_VTD_SIP_IOTLB_1G_HIT); +VTD_SIP_SHOW(slpwc_l3_hit, IPERF_VTD_SIP_SLPWC_L3_HIT); +VTD_SIP_SHOW(slpwc_l4_hit, IPERF_VTD_SIP_SLPWC_L4_HIT); +VTD_SIP_SHOW(rcc_hit, IPERF_VTD_SIP_RCC_HIT); +VTD_SIP_SHOW(iotlb_4k_miss, IPERF_VTD_SIP_IOTLB_4K_MISS); +VTD_SIP_SHOW(iotlb_2m_miss, IPERF_VTD_SIP_IOTLB_2M_MISS); +VTD_SIP_SHOW(iotlb_1g_miss, IPERF_VTD_SIP_IOTLB_1G_MISS); +VTD_SIP_SHOW(slpwc_l3_miss, IPERF_VTD_SIP_SLPWC_L3_MISS); +VTD_SIP_SHOW(slpwc_l4_miss, IPERF_VTD_SIP_SLPWC_L4_MISS); +VTD_SIP_SHOW(rcc_miss, IPERF_VTD_SIP_RCC_MISS); + +static u64 read_iommu_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_vtd_events base_event) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_ifpmon_vtd_ctr ctr; + struct feature_fme_iperf *iperf; + enum iperf_vtd_events event = base_event + port_id; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.vtd_evtcode = event; + writeq(ctl.csr, &iperf->vtd_ctl); + + ctr.event_code = event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->vtd_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->vtd_ctr); + counter = ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_PORT_SHOW(name, base_event) \ +static int fme_iperf_get_vtd_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_iommu_counter(fme, port_id, base_event); \ + return 0; \ +} + +VTD_PORT_SHOW(read_transaction, IPERF_VTD_AFU_MEM_RD_TRANS); +VTD_PORT_SHOW(write_transaction, IPERF_VTD_AFU_MEM_WR_TRANS); +VTD_PORT_SHOW(devtlb_read_hit, IPERF_VTD_AFU_DEVTLB_RD_HIT); +VTD_PORT_SHOW(devtlb_write_hit, IPERF_VTD_AFU_DEVTLB_WR_HIT); +VTD_PORT_SHOW(devtlb_4k_fill, IPERF_VTD_DEVTLB_4K_FILL); +VTD_PORT_SHOW(devtlb_2m_fill, IPERF_VTD_DEVTLB_2M_FILL); +VTD_PORT_SHOW(devtlb_1g_fill, IPERF_VTD_DEVTLB_1G_FILL); + +static bool fabric_pobj_is_enabled(u8 port_id, struct feature_fme_iperf *iperf) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + + ctl.csr = readq(&iperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_fab_events fab_event) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_ifpmon_fab_ctr ctr; + struct feature_fme_iperf *iperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, iperf)) + goto exit; + + ctl.csr = readq(&iperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &iperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->fab_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_iperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, IPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, IPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(pcie1_read, IPERF_FAB_PCIE1_RD); +FAB_PORT_SHOW(pcie1_write, IPERF_FAB_PCIE1_WR); +FAB_PORT_SHOW(upi_read, IPERF_FAB_UPI_RD); +FAB_PORT_SHOW(upi_write, IPERF_FAB_UPI_WR); +FAB_PORT_SHOW(mmio_read, IPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, IPERF_FAB_MMIO_WR); + +static int fme_iperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_iperf *iperf; + int status; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + status = fabric_pobj_is_enabled(port_id, iperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_iperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, iperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&iperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_iperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 +#define FME_IPERF_CAP_IOMMU 0x1 + +static int fme_global_iperf_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme; + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + + dev_info(NULL, "FME global_iperf Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + /* check if iommu is not supported on this device. */ + fme_capability.csr = readq(&fme_hdr->capability); + dev_info(NULL, "FME HEAD fme_capability %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + if (fme_capability.iommu_support) + feature->cap |= FME_IPERF_CAP_IOMMU; + + return 0; +} + +static void fme_global_iperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_iperf UInit.\n"); +} + +static int fme_iperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_iperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_iperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_cache_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_cache_freeze(fme, &prop->data); + case 0x2: /* READ_HIT */ + return fme_iperf_get_cache_read_hit(fme, &prop->data); + case 0x3: /* READ_MISS */ + return fme_iperf_get_cache_read_miss(fme, &prop->data); + case 0x4: /* WRITE_HIT */ + return fme_iperf_get_cache_write_hit(fme, &prop->data); + case 0x5: /* WRITE_MISS */ + return fme_iperf_get_cache_write_miss(fme, &prop->data); + case 0x6: /* HOLD_REQUEST */ + return fme_iperf_get_cache_hold_request(fme, &prop->data); + case 0x7: /* TX_REQ_STALL */ + return fme_iperf_get_cache_tx_req_stall(fme, &prop->data); + case 0x8: /* RX_REQ_STALL */ + return fme_iperf_get_cache_rx_req_stall(fme, &prop->data); + case 0x9: /* RX_EVICTION */ + return fme_iperf_get_cache_rx_eviction(fme, &prop->data); + case 0xa: /* DATA_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_data_write_port_contention(fme, + &prop->data); + case 0xb: /* TAG_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_tag_write_port_contention(fme, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_vtd_freeze(fme, &prop->data); + case 0x2: /* IOTLB_4K_HIT */ + return fme_iperf_get_vtd_sip_iotlb_4k_hit(fme, &prop->data); + case 0x3: /* IOTLB_2M_HIT */ + return fme_iperf_get_vtd_sip_iotlb_2m_hit(fme, &prop->data); + case 0x4: /* IOTLB_1G_HIT */ + return fme_iperf_get_vtd_sip_iotlb_1g_hit(fme, &prop->data); + case 0x5: /* SLPWC_L3_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l3_hit(fme, &prop->data); + case 0x6: /* SLPWC_L4_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l4_hit(fme, &prop->data); + case 0x7: /* RCC_HIT */ + return fme_iperf_get_vtd_sip_rcc_hit(fme, &prop->data); + case 0x8: /* IOTLB_4K_MISS */ + return fme_iperf_get_vtd_sip_iotlb_4k_miss(fme, &prop->data); + case 0x9: /* IOTLB_2M_MISS */ + return fme_iperf_get_vtd_sip_iotlb_2m_miss(fme, &prop->data); + case 0xa: /* IOTLB_1G_MISS */ + return fme_iperf_get_vtd_sip_iotlb_1g_miss(fme, &prop->data); + case 0xb: /* SLPWC_L3_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l3_miss(fme, &prop->data); + case 0xc: /* SLPWC_L4_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l4_miss(fme, &prop->data); + case 0xd: /* RCC_MISS */ + return fme_iperf_get_vtd_sip_rcc_miss(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_sub_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub > PERF_MAX_PORT_NUM) + return -ENOENT; + + switch (id) { + case 0xe: /* READ_TRANSACTION */ + return fme_iperf_get_vtd_port_read_transaction(fme, sub, + &prop->data); + case 0xf: /* WRITE_TRANSACTION */ + return fme_iperf_get_vtd_port_write_transaction(fme, sub, + &prop->data); + case 0x10: /* DEVTLB_READ_HIT */ + return fme_iperf_get_vtd_port_devtlb_read_hit(fme, sub, + &prop->data); + case 0x11: /* DEVTLB_WRITE_HIT */ + return fme_iperf_get_vtd_port_devtlb_write_hit(fme, sub, + &prop->data); + case 0x12: /* DEVTLB_4K_FILL */ + return fme_iperf_get_vtd_port_devtlb_4k_fill(fme, sub, + &prop->data); + case 0x13: /* DEVTLB_2M_FILL */ + return fme_iperf_get_vtd_port_devtlb_2m_fill(fme, sub, + &prop->data); + case 0x14: /* DEVTLB_1G_FILL */ + return fme_iperf_get_vtd_port_devtlb_1g_fill(fme, sub, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED) + return fme_iperf_vtd_root_get_prop(feature, prop); + + return fme_iperf_vtd_sub_get_prop(feature, prop); +} + +static int fme_iperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + /* Other properties are present for both top and sub levels */ + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_iperf_get_fab_port_pcie0_read(fme, sub, + &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_iperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* PCIE1_READ */ + return fme_iperf_get_fab_port_pcie1_read(fme, sub, + &prop->data); + case 0x5: /* PCIE1_WRITE */ + return fme_iperf_get_fab_port_pcie1_write(fme, sub, + &prop->data); + case 0x6: /* UPI_READ */ + return fme_iperf_get_fab_port_upi_read(fme, sub, + &prop->data); + case 0x7: /* UPI_WRITE */ + return fme_iperf_get_fab_port_upi_write(fme, sub, + &prop->data); + case 0x8: /* MMIO_READ */ + return fme_iperf_get_fab_port_mmio_read(fme, sub, + &prop->data); + case 0x9: /* MMIO_WRITE */ + return fme_iperf_get_fab_port_mmio_write(fme, sub, + &prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_get_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_get_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_iperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_iperf_cache_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_cache_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_vtd_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_vtd_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_set_fab_freeze(fme, prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_set_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_set_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_iperf_ops = { + .init = fme_global_iperf_init, + .uinit = fme_global_iperf_uinit, + .get_prop = fme_global_iperf_get_prop, + .set_prop = fme_global_iperf_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c new file mode 100644 index 0000000..2a988c4 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c @@ -0,0 +1,399 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +#if defined(RTE_ARCH_X86_64) +static inline void copy512(const void *src, void *dst) +{ + asm volatile("vmovdqu64 (%0), %%zmm0;" + "vmovntdq %%zmm0, (%1);" + : + : "r"(src), "r"(dst)); +} +#else +static inline void copy512(const void *src, void *dst) +{ + UNUSED(src); + UNUSED(dst); + WARN_ON(1); +} +#endif + +static u64 +pr_err_handle(struct feature_fme_pr *fme_pr) +{ + struct feature_fme_pr_status fme_pr_status; + unsigned long err_code; + u64 fme_pr_error; + int i; + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + if (!fme_pr_status.pr_status) + return 0; + + err_code = readq(&fme_pr->ccip_fme_pr_err); + fme_pr_error = err_code; + + for (i = 0; i < PR_MAX_ERR_NUM; i++) { + if (err_code & (1 << i)) + dev_info(NULL, "%s\n", pr_err_msg[i]); + } + + writeq(fme_pr_error, &fme_pr->ccip_fme_pr_err); + return fme_pr_error; +} + +static int fme_pr_write_init(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + if (info->flags != FPGA_MGR_PARTIAL_RECONFIG) + return -EINVAL; + + dev_info(fme_dev, "resetting PR before initiated PR\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + fme_pr_ctl.pr_reset_ack = 1; + + if (fpga_wait_register_field(pr_reset_ack, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 0; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "waiting for PR resource in HW to be initialized and ready\n"); + + fme_pr_status.pr_host_status = PR_HOST_STATUS_IDLE; + + if (fpga_wait_register_field(pr_host_status, fme_pr_status, + &fme_pr->ccip_fme_pr_status, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "check if have any previous PR error\n"); + pr_err_handle(fme_pr); + return 0; +} + +static int fme_pr_write(struct ifpga_fme_hw *fme_dev, + int port_id, const char *buf, size_t count, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + struct feature_fme_pr_data fme_pr_data; + int delay, pr_credit; + int ret = 0; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + dev_info(fme_dev, "set PR port ID and start request\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_regionid = port_id; + fme_pr_ctl.pr_start_req = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "pushing data from bitstream to HW\n"); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + + while (count > 0) { + delay = 0; + while (pr_credit <= 1) { + if (delay++ > PR_WAIT_TIMEOUT) { + dev_err(fme_dev, "maximum try\n"); + + info->pr_err = pr_err_handle(fme_pr); + return info->pr_err ? -EIO : -ETIMEDOUT; + } + udelay(1); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + }; + + if (count >= fme_dev->pr_bandwidth) { + switch (fme_dev->pr_bandwidth) { + case 4: + fme_pr_data.rsvd = 0; + fme_pr_data.pr_data_raw = *((const u32 *)buf); + writeq(fme_pr_data.csr, + &fme_pr->ccip_fme_pr_data); + break; + case 64: + copy512(buf, &fme_pr->fme_pr_data1); + break; + default: + ret = -EFAULT; + goto done; + } + + buf += fme_dev->pr_bandwidth; + count -= fme_dev->pr_bandwidth; + pr_credit--; + } else { + WARN_ON(1); + return -EINVAL; + goto done; + } + } + +done: + return ret; +} + +static int fme_pr_write_complete(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_push_complete = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "green bitstream push complete\n"); + dev_info(fme_dev, "waiting for HW to release PR resource\n"); + + fme_pr_ctl.pr_start_req = 0; + + if (fpga_wait_register_field(pr_start_req, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + printf("maximum try.\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "PR operation complete, checking status\n"); + info->pr_err = pr_err_handle(fme_pr); + if (info->pr_err) + return -EIO; + + dev_info(fme_dev, "PR done successfully\n"); + return 0; +} + +static int fpga_pr_buf_load(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info, const char *buf, + size_t count) +{ + int ret; + + info->state = FPGA_PR_STATE_WRITE_INIT; + ret = fme_pr_write_init(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error preparing FPGA for writing\n"); + info->state = FPGA_PR_STATE_WRITE_INIT_ERR; + return ret; + } + + /* + * Write the FPGA image to the FPGA. + */ + info->state = FPGA_PR_STATE_WRITE; + ret = fme_pr_write(fme_dev, info->port_id, buf, count, info); + if (ret) { + dev_err(fme_dev, "Error while writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_ERR; + return ret; + } + + /* + * After all the FPGA image has been written, do the device specific + * steps to finish and set the FPGA into operating mode. + */ + info->state = FPGA_PR_STATE_WRITE_COMPLETE; + ret = fme_pr_write_complete(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error after writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_COMPLETE_ERR; + return ret; + } + info->state = FPGA_PR_STATE_DONE; + + return 0; +} + +static int fme_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + struct ifpga_fme_hw *fme = &hw->fme; + struct fpga_pr_info info; + struct ifpga_port_hw *port; + int ret = 0; + + if (!buffer || size == 0) + return -EINVAL; + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + /* + * Padding extra zeros to align PR buffer with PR bandwidth, HW will + * ignore these zeros automatically. + */ + size = ALIGN(size, fme->pr_bandwidth); + + /* get fme header region */ + fme_hdr = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_HEADER); + if (!fme_hdr) + return -EINVAL; + + /* check port id */ + fme_capability.csr = readq(&fme_hdr->capability); + if (port_id >= fme_capability.num_ports) { + dev_err(fme, "port number more than maximum\n"); + return -EINVAL; + } + + memset(&info, 0, sizeof(struct fpga_pr_info)); + info.flags = FPGA_MGR_PARTIAL_RECONFIG; + info.port_id = port_id; + + spinlock_lock(&fme->lock); + + /* get port device by port_id */ + port = &hw->port[port_id]; + + /* Disable Port before PR */ + fpga_port_disable(port); + + ret = fpga_pr_buf_load(fme, &info, (void *)buffer, size); + + *status = info.pr_err; + + /* Re-enable Port after PR finished */ + fpga_port_enable(port); + spinlock_unlock(&fme->lock); + + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, u64 *status) +{ + struct bts_header *bts_hdr; + void *buf; + struct ifpga_port_hw *port; + int ret; + + if (!buffer || size == 0) { + dev_err(hw, "invalid parameter\n"); + return -EINVAL; + } + + bts_hdr = (struct bts_header *)buffer; + + if (is_valid_bts(bts_hdr)) { + dev_info(hw, "this is a valid bitsteam..\n"); + size -= (sizeof(struct bts_header) + + bts_hdr->metadata_len); + buf = (u8 *)buffer + sizeof(struct bts_header) + + bts_hdr->metadata_len; + } else { + return -EINVAL; + } + + /* clean port error before do PR */ + port = &hw->port[port_id]; + ret = port_clear_error(port); + if (ret) { + dev_err(hw, "port cannot clear error\n"); + return -EINVAL; + } + + return fme_pr(hw, port_id, buf, size, status); +} + +static int fme_pr_mgmt_init(struct feature *feature) +{ + struct feature_fme_pr *fme_pr; + struct feature_header fme_pr_header; + struct ifpga_fme_hw *fme; + + dev_info(NULL, "FME PR MGMT Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + + fme_pr = (struct feature_fme_pr *)feature->addr; + + fme_pr_header.csr = readq(&fme_pr->header); + if (fme_pr_header.revision == 2) { + dev_info(NULL, "using 512-bit PR\n"); + fme->pr_bandwidth = 64; + } else { + dev_info(NULL, "using 32-bit PR\n"); + fme->pr_bandwidth = 4; + } + + return 0; +} + +static void fme_pr_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME PR MGMT UInit.\n"); +} + +struct 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 new file mode 100644 index 0000000..482779d --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -0,0 +1,154 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_HW_H_ +#define _IFPGA_HW_H_ + +#include "ifpga_defines.h" +#include "opae_ifpga_hw_api.h" + +enum ifpga_feature_state { + IFPGA_FEATURE_UNUSED = 0, + IFPGA_FEATURE_ATTACHED, +}; + +struct feature_irq_ctx { + int eventfd; + int idx; +}; + +struct feature { + enum ifpga_feature_state state; + const char *name; + u64 id; + u8 *addr; + uint64_t phys_addr; + u32 size; + int revision; + u64 cap; + int vfio_dev_fd; + struct feature_irq_ctx *ctx; + unsigned int ctx_num; + + void *parent; /* to parent hw data structure */ + + struct feature_ops *ops;/* callback to this private feature */ +}; + +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); +}; + +enum ifpga_fme_state { + IFPGA_FME_UNUSED = 0, + IFPGA_FME_IMPLEMENTED, +}; + +struct ifpga_fme_hw { + enum ifpga_fme_state state; + + struct feature sub_feature[FME_FEATURE_ID_MAX]; + spinlock_t lock; /* protect hardware access */ + + void *parent; /* pointer to ifpga_hw */ + + /* provied by HEADER feature */ + u32 port_num; + struct uuid bitstream_id; + u64 bitstream_md; + size_t pr_bandwidth; + u32 socket_id; + u32 fabric_version_id; + u32 cache_size; + + u32 capability; +}; + +enum ifpga_port_state { + IFPGA_PORT_UNUSED = 0, + IFPGA_PORT_ATTACHED, + IFPGA_PORT_DETACHED, +}; + +struct ifpga_port_hw { + enum ifpga_port_state state; + + struct feature sub_feature[PORT_FEATURE_ID_MAX]; + spinlock_t lock; /* protect access to hw */ + + void *parent; /* pointer to ifpga_hw */ + + int port_id; /* provied by HEADER feature */ + struct uuid afu_id; /* provied by User AFU feature */ + + unsigned int disable_count; + + u32 capability; + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ + u8 *stp_addr; + u32 stp_size; +}; + +#define AFU_MAX_REGION 1 + +struct ifpga_afu_info { + struct opae_reg_region region[AFU_MAX_REGION]; + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct ifpga_hw { + struct opae_adapter *adapter; + struct opae_adapter_data_pci *pci_data; + + struct ifpga_fme_hw fme; + struct ifpga_port_hw port[MAX_FPGA_PORT_NUM]; +}; + +static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) +{ + return hw->fme.state != IFPGA_FME_UNUSED; +} + +static inline bool is_valid_port_id(struct ifpga_hw *hw, u32 port_id) +{ + if (port_id >= MAX_FPGA_PORT_NUM || + hw->port[port_id].state != IFPGA_PORT_ATTACHED) + return false; + + return true; +} +#endif /* _IFPGA_HW_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c new file mode 100644 index 0000000..1dab201 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c @@ -0,0 +1,435 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +static int port_get_revision(struct ifpga_port_hw *port, u64 *revision) +{ + struct feature_port_header *port_hdr + = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&port_hdr->header); + + *revision = header.revision; + + return 0; +} + +static int port_get_portidx(struct ifpga_port_hw *port, u64 *idx) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + capability.csr = readq(&port_hdr->capability); + *idx = capability.port_number; + + return 0; +} + +static int port_get_latency_tolerance(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + control.csr = readq(&port_hdr->control); + *val = control.latency_tolerance; + + return 0; +} + +static int port_get_ap1_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap1_event; + + return 0; +} + +static int port_set_ap1_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap1_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_ap2_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap2_event; + + return 0; +} + +static int port_set_ap2_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap2_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_power_state(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.power_state; + + return 0; +} + +static int port_get_userclk_freqcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_hdr_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port hdr Init.\n"); + + fpga_port_reset(port); + + return 0; +} + +static void port_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port hdr uinit.\n"); +} + +static int port_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_REVISION: + return port_get_revision(port, &prop->data); + case PORT_HDR_PROP_PORTIDX: + return port_get_portidx(port, &prop->data); + case PORT_HDR_PROP_LATENCY_TOLERANCE: + return port_get_latency_tolerance(port, &prop->data); + case PORT_HDR_PROP_AP1_EVENT: + return port_get_ap1_event(port, &prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_get_ap2_event(port, &prop->data); + case PORT_HDR_PROP_POWER_STATE: + return port_get_power_state(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_get_userclk_freqcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_get_userclk_freqcntrcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQSTS: + return port_get_userclk_freqsts(port, &prop->data); + case PORT_HDR_PROP_USERCLK_CNTRSTS: + return port_get_userclk_freqcntrsts(port, &prop->data); + } + + return -ENOENT; +} + +static int port_hdr_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_AP1_EVENT: + return port_set_ap1_event(port, prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_set_ap2_event(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_set_userclk_freqcmd(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_set_userclk_freqcntrcmd(port, prop->data); + } + + return -ENOENT; +} + +struct feature_ops 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) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port stp Init.\n"); + + spinlock_lock(&port->lock); + port->stp_addr = feature->addr; + port->stp_size = feature->size; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_stp_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port stp uinit.\n"); +} + +struct feature_ops port_stp_ops = { + .init = port_stp_init, + .uinit = port_stp_uinit, +}; + +static int port_uint_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "PORT UINT Init.\n"); + + spinlock_lock(&port->lock); + if (feature->ctx_num) { + port->capability |= FPGA_PORT_CAP_UAFU_IRQ; + port->num_uafu_irqs = feature->ctx_num; + } + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_uint_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT UINT UInit.\n"); +} + +static int port_uint_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_uafu_irq_set *uafu_irq_set = irq_set; + struct ifpga_port_hw *port = feature->parent; + int ret; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_UAFU_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, uafu_irq_set->start, + uafu_irq_set->count, uafu_irq_set->evtfds); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_uint_ops = { + .init = port_uint_init, + .uinit = port_uint_uinit, + .set_irq = port_uint_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c new file mode 100644 index 0000000..100009e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c @@ -0,0 +1,192 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +static int port_err_get_revision(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_header header; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + header.csr = readq(&port_err->header); + *val = header.revision; + + return 0; +} + +static int port_err_get_errors(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + *val = error.csr; + + return 0; +} + +static int port_err_get_first_error(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_first_err_key first_error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + first_error.csr = readq(&port_err->port_first_error); + *val = first_error.csr; + + return 0; +} + +static int port_err_get_first_malformed_req_lsb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req0 malreq0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq0.header_lsb = readq(&port_err->malreq0); + *val = malreq0.header_lsb; + + return 0; +} + +static int port_err_get_first_malformed_req_msb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req1 malreq1; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq1.header_msb = readq(&port_err->malreq1); + *val = malreq1.header_msb; + + return 0; +} + +static int port_err_set_clear(struct ifpga_port_hw *port, u64 val) +{ + int ret; + + spinlock_lock(&port->lock); + ret = port_err_clear(port, val); + spinlock_unlock(&port->lock); + + return ret; +} + +static int port_error_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port error Init.\n"); + + spinlock_lock(&port->lock); + port_err_mask(port, false); + if (feature->ctx_num) + port->capability |= FPGA_PORT_CAP_ERR_IRQ; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int port_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_ERR_PROP_REVISION: + return port_err_get_revision(port, &prop->data); + case PORT_ERR_PROP_ERRORS: + return port_err_get_errors(port, &prop->data); + case PORT_ERR_PROP_FIRST_ERROR: + return port_err_get_first_error(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB: + return port_err_get_first_malformed_req_lsb(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB: + return port_err_get_first_malformed_req_msb(port, &prop->data); + } + + return -ENOENT; +} + +static int port_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + if (prop->prop_id == PORT_ERR_PROP_CLEAR) + return port_err_set_clear(port, prop->data); + + return -ENOENT; +} + +static int port_error_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_port_err_irq_set *err_irq_set = irq_set; + struct ifpga_port_hw *port; + int ret; + + port = feature->parent; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_ERR_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_error_ops = { + .init = port_error_init, + .uinit = port_error_uinit, + .get_prop = port_error_get_prop, + .set_prop = port_error_set_prop, + .set_irq = port_error_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.c b/drivers/raw/ifpga_rawdev/base/opae_debug.c new file mode 100644 index 0000000..07935e7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.c @@ -0,0 +1,126 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#define OPAE_HW_DEBUG + +#include "opae_hw_api.h" +#include "opae_debug.h" + +void opae_manager_dump(struct opae_manager *mgr) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Manger %s\n", mgr->name); + opae_log("OPAE Manger OPs = %p\n", mgr->ops); + opae_log("OPAE Manager Private Data = %p\n", mgr->data); + opae_log("OPAE Adapter(parent) = %p\n", mgr->adapter); + opae_log("==========================\n"); +} + +void opae_bridge_dump(struct opae_bridge *br) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Bridge %s\n", br->name); + opae_log("OPAE Bridge ID = %d\n", br->id); + opae_log("OPAE Bridge OPs = %p\n", br->ops); + opae_log("OPAE Bridge Private Data = %p\n", br->data); + opae_log("OPAE Accelerator(under this bridge) = %p\n", br->acc); + opae_log("==========================\n"); +} + +void opae_accelerator_dump(struct opae_accelerator *acc) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Accelerator %s\n", acc->name); + opae_log("OPAE Accelerator Index = %d\n", acc->index); + opae_log("OPAE Accelerator OPs = %p\n", acc->ops); + opae_log("OPAE Accelerator Private Data = %p\n", acc->data); + opae_log("OPAE Bridge (upstream) = %p\n", acc->br); + opae_log("OPAE Manager (upstream) = %p\n", acc->mgr); + opae_log("==========================\n"); + + if (acc->br) + opae_bridge_dump(acc->br); +} + +static void opae_adapter_data_dump(void *data) +{ + struct opae_adapter_data *d = data; + struct opae_adapter_data_pci *d_pci; + struct opae_reg_region *r; + int i; + + opae_log("=====%s=====\n", __func__); + + switch (d->type) { + case OPAE_FPGA_PCI: + d_pci = (struct opae_adapter_data_pci *)d; + + opae_log("OPAE Adapter Type = PCI\n"); + opae_log("PCI Device ID: 0x%04x\n", d_pci->device_id); + opae_log("PCI Vendor ID: 0x%04x\n", d_pci->vendor_id); + + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + r = &d_pci->region[i]; + opae_log("PCI Bar %d: phy(%llx) len(%llx) addr(%p)\n", + i, (unsigned long long)r->phys_addr, + (unsigned long long)r->len, r->addr); + } + break; + case OPAE_FPGA_NET: + break; + } + + opae_log("==========================\n"); +} + +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) { + if (adapter->mgr) + opae_manager_dump(adapter->mgr); + + opae_adapter_for_each_acc(adapter, acc) + opae_accelerator_dump(acc); + + if (adapter->data) + opae_adapter_data_dump(adapter->data); + } + + opae_log("==========================\n"); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.h b/drivers/raw/ifpga_rawdev/base/opae_debug.h new file mode 100644 index 0000000..ceddf9d --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.h @@ -0,0 +1,46 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_DEBUG_H_ +#define _OPAE_DEBUG_H_ + +#ifdef OPAE_HW_DEBUG +#define opae_log(fmt, args...) printf(fmt, ## args) +#else +#define opae_log(fme, args...) do {} while (0) +#endif + +void opae_manager_dump(struct opae_manager *mgr); +void opae_bridge_dump(struct opae_bridge *br); +void opae_accelerator_dump(struct opae_accelerator *acc); +void opae_adapter_dump(struct opae_adapter *adapter, int verbose); + +#endif /* _OPAE_DEBUG_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c new file mode 100644 index 0000000..7fb90c5 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -0,0 +1,408 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "opae_hw_api.h" +#include "opae_debug.h" +#include "ifpga_api.h" + +/* OPAE Bridge Functions */ + +/** + * opae_bridge_alloc - alloc opae_bridge data structure + * @name: bridge name. + * @ops: ops of this bridge. + * @data: private data of this bridge. + * + * Return opae_bridge on success, otherwise NULL. + */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data) +{ + struct opae_bridge *br = opae_zmalloc(sizeof(*br)); + + if (!br) + return NULL; + + br->name = name; + br->ops = ops; + br->data = data; + + opae_log("%s %p\n", __func__, br); + + return br; +} + +/** + * opae_bridge_reset - reset opae_bridge + * @br: bridge to be reset. + * + * Return: 0 on success, otherwise error code. + */ +int opae_bridge_reset(struct opae_bridge *br) +{ + if (!br) + return -EINVAL; + + if (br->ops && br->ops->reset) + return br->ops->reset(br); + + opae_log("%s no ops\n", __func__); + + return -ENOENT; +} + +/* Accelerator Functions */ + +/** + * opae_accelerator_alloc - alloc opae_accelerator data structure + * @name: accelerator name. + * @ops: ops of this accelerator. + * @data: private data of this accelerator. + * + * Return: opae_accelerator on success, otherwise NULL. + */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data) +{ + struct opae_accelerator *acc = opae_zmalloc(sizeof(*acc)); + + if (!acc) + return NULL; + + acc->name = name; + acc->ops = ops; + acc->data = data; + + opae_log("%s %p\n", __func__, acc); + + return acc; +} + +/** + * opae_acc_reg_read - read accelerator's register from its reg region. + * @acc: accelerator to read. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: read operation width, e.g 4 byte = 32bit read. + * @data: data to store the value read from the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->read) + return acc->ops->read(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_reg_write - write to accelerator's register from its reg region. + * @acc: accelerator to write. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: write operation width, e.g 4 byte = 32bit write. + * @data: data stored the value to write to the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->write) + return acc->ops->write(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_get_info - get information of an accelerator. + * @acc: targeted accelerator + * @info: accelerator info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_info) + return acc->ops->get_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_get_region_info - get information of an accelerator register region. + * @acc: targeted accelerator + * @info: accelerator region info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_region_info) + return acc->ops->get_region_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_set_irq - set an accelerator's irq. + * @acc: targeted accelerator + * @start: start vector number + * @count: count of vectors to be set from the start vector + * @evtfds: event fds to be notified when corresponding irqs happens + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + if (!acc || !acc->data) + return -EINVAL; + + if (start + count <= start) + return -EINVAL; + + if (acc->ops && acc->ops->set_irq) + return acc->ops->set_irq(acc, start, count, evtfds); + + return -ENOENT; +} + +/** + * opae_acc_get_uuid - get accelerator's UUID. + * @acc: targeted accelerator + * @uuid: a pointer to UUID + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + if (!acc || !uuid) + return -EINVAL; + + if (acc->ops && acc->ops->get_uuid) + return acc->ops->get_uuid(acc, uuid); + + return -ENOENT; +} + +/* Manager Functions */ + +/** + * opae_manager_alloc - alloc opae_manager data structure + * @name: manager name. + * @ops: ops of this manager. + * @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) +{ + struct opae_manager *mgr = opae_zmalloc(sizeof(*mgr)); + + if (!mgr) + return NULL; + + mgr->name = name; + mgr->ops = ops; + mgr->data = data; + + opae_log("%s %p\n", __func__, mgr); + + return mgr; +} + +/** + * opae_manager_flash - flash a reconfiguration image via opae_manager + * @mgr: opae_manager for flash. + * @id: id of target region (accelerator). + * @buf: image data buffer. + * @size: buffer size. + * @status: status to store flash result. + * + * Return: 0 on success, otherwise error code. + */ +int opae_manager_flash(struct opae_manager *mgr, int id, void *buf, u32 size, + u64 *status) +{ + if (!mgr) + return -EINVAL; + + if (mgr && mgr->ops && mgr->ops->flash) + return mgr->ops->flash(mgr, id, buf, size, status); + + return -ENOENT; +} + +/* Adapter Functions */ + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @type: opae_adapter_type. + * + * Return: opae_adapter_data on success, otherwise NULL. + */ +void *opae_adapter_data_alloc(enum opae_adapter_type type) +{ + struct opae_adapter_data *data; + int size; + + switch (type) { + case OPAE_FPGA_PCI: + size = sizeof(struct opae_adapter_data_pci); + break; + case OPAE_FPGA_NET: + size = sizeof(struct opae_adapter_data_net); + break; + default: + size = sizeof(struct opae_adapter_data); + break; + } + + data = opae_zmalloc(size); + if (!data) + return NULL; + + data->type = type; + + return data; +} + +static struct opae_adapter_ops *match_ops(struct opae_adapter *adapter) +{ + struct opae_adapter_data *data; + + if (!adapter || !adapter->data) + return NULL; + + data = adapter->data; + + if (data->type == OPAE_FPGA_PCI) + return &ifpga_adapter_ops; + + return NULL; +} + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @name: adapter name. + * @data: private data of this adapter. + * + * Return: opae_adapter on success, otherwise NULL. + */ +struct opae_adapter *opae_adapter_alloc(const char *name, void *data) +{ + struct opae_adapter *adapter = opae_zmalloc(sizeof(*adapter)); + + if (!adapter) + return NULL; + + TAILQ_INIT(&adapter->acc_list); + adapter->data = data; + adapter->name = name; + adapter->ops = match_ops(adapter); + + return adapter; +} + +/** + * opae_adapter_enumerate - enumerate this adapter + * @adapter: adapter to enumerate. + * + * Return: 0 on success, otherwise error code. + */ +int opae_adapter_enumerate(struct opae_adapter *adapter) +{ + int ret = -ENOENT; + + if (!adapter) + return -EINVAL; + + if (adapter->ops && adapter->ops->enumerate) + ret = adapter->ops->enumerate(adapter); + + if (!ret) + opae_adapter_dump(adapter, 1); + + return ret; +} + +/** + * opae_adapter_destroy - destroy this adapter + * @adapter: adapter to destroy. + * + * destroy things allocated during adapter enumeration. + */ +void opae_adapter_destroy(struct opae_adapter *adapter) +{ + if (adapter && adapter->ops && adapter->ops->destroy) + adapter->ops->destroy(adapter); +} + +/** + * opae_adapter_get_acc - find and return accelerator with matched id + * @adapter: adapter to find the accelerator. + * @acc_id: id (index) of the accelerator. + * + * destroy things allocated during adapter enumeration. + */ +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id) +{ + struct opae_accelerator *acc = NULL; + + if (!adapter) + return NULL; + + opae_adapter_for_each_acc(adapter, acc) + if (acc->index == acc_id) + return acc; + + return NULL; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h new file mode 100644 index 0000000..6b5300f --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -0,0 +1,280 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_HW_API_H_ +#define _OPAE_HW_API_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> + +#include "opae_osdep.h" + +#ifndef PCI_MAX_RESOURCE +#define PCI_MAX_RESOURCE 6 +#endif + +struct opae_adapter; + +enum opae_adapter_type { + OPAE_FPGA_PCI, + OPAE_FPGA_NET, +}; + +/* OPAE Manager Data Structure */ +struct opae_manager_ops; + +/* + * opae_manager has pointer to its parent adapter, as it could be able to manage + * all components on this FPGA device (adapter). If not the case, don't set this + * adapter, which limit opae_manager ops to manager itself. + */ +struct opae_manager { + const char *name; + struct opae_adapter *adapter; + struct opae_manager_ops *ops; + void *data; +}; + +/* FIXME: add more management ops, e.g power/thermal and etc */ +struct opae_manager_ops { + int (*flash)(struct opae_manager *mgr, int id, void *buffer, + u32 size, u64 *status); +}; + +/* OPAE Manager APIs */ +struct opae_manager * +opae_manager_alloc(const char *name, struct opae_manager_ops *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); + +/* OPAE Bridge Data Structure */ +struct opae_bridge_ops; + +/* + * opae_bridge only has pointer to its downstream accelerator. + */ +struct opae_bridge { + const char *name; + int id; + struct opae_accelerator *acc; + struct opae_bridge_ops *ops; + void *data; +}; + +struct opae_bridge_ops { + int (*reset)(struct opae_bridge *br); +}; + +/* OPAE Bridge APIs */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data); +int opae_bridge_reset(struct opae_bridge *br); +#define opae_bridge_free(br) opae_free(br) + +/* OPAE Acceleraotr Data Structure */ +struct opae_accelerator_ops; + +/* + * opae_accelerator has pointer to its upstream bridge(port). + * In some cases, if we allow same user to do PR on its own accelerator, then + * set the manager pointer during the enumeration. But in other cases, the PR + * functions only could be done via manager in another module / thread / service + * / application for better protection. + */ +struct opae_accelerator { + TAILQ_ENTRY(opae_accelerator) node; + const char *name; + int index; + struct opae_bridge *br; + struct opae_manager *mgr; + struct opae_accelerator_ops *ops; + void *data; +}; + +struct opae_acc_info { + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct opae_acc_region_info { + u32 flags; +#define ACC_REGION_READ (1 << 0) +#define ACC_REGION_WRITE (1 << 1) +#define ACC_REGION_MMIO (1 << 2) + u32 index; + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_accelerator_ops { + int (*read)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*write)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*get_info)(struct opae_accelerator *acc, + struct opae_acc_info *info); + int (*get_region_info)(struct opae_accelerator *acc, + struct opae_acc_region_info *info); + int (*set_irq)(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); + int (*get_uuid)(struct opae_accelerator *acc, + struct uuid *uuid); +}; + +/* OPAE accelerator APIs */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data); +#define opae_accelerator_free(acc) opae_free(acc) +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info); +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info); +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid); + +static inline struct opae_bridge * +opae_acc_get_br(struct opae_accelerator *acc) +{ + return acc ? acc->br : NULL; +} + +static inline struct opae_manager * +opae_acc_get_mgr(struct opae_accelerator *acc) +{ + return acc ? acc->mgr : NULL; +} + +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + +#define opae_acc_reg_read64(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 8, data) +#define opae_acc_reg_write64(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 8, data) +#define opae_acc_reg_read32(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 4, data) +#define opae_acc_reg_write32(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 4, data) +#define opae_acc_reg_read16(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 2, data) +#define opae_acc_reg_write16(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 2, data) +#define opae_acc_reg_read8(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 1, data) +#define opae_acc_reg_write8(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 1, data) + +/*for data stream read/write*/ +int opae_acc_data_read(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); +int opae_acc_data_write(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); + +/* OPAE Adapter Data Structure */ +struct opae_adapter_data { + enum opae_adapter_type type; +}; + +struct opae_reg_region { + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_adapter_data_pci { + enum opae_adapter_type type; + u16 device_id; + u16 vendor_id; + struct opae_reg_region region[PCI_MAX_RESOURCE]; + int vfio_dev_fd; /* VFIO device file descriptor */ +}; + +/* FIXME: OPAE_FPGA_NET type */ +struct opae_adapter_data_net { + enum opae_adapter_type type; +}; + +struct opae_adapter_ops { + int (*enumerate)(struct opae_adapter *adapter); + void (*destroy)(struct opae_adapter *adapter); +}; + +TAILQ_HEAD(opae_accelerator_list, opae_accelerator); + +#define opae_adapter_for_each_acc(adatper, acc) \ + TAILQ_FOREACH(acc, &adapter->acc_list, node) + +struct opae_adapter { + const char *name; + struct opae_manager *mgr; + struct opae_accelerator_list acc_list; + struct opae_adapter_ops *ops; + void *data; +}; + +/* OPAE Adapter APIs */ +void *opae_adapter_data_alloc(enum opae_adapter_type type); +#define opae_adapter_data_free(data) opae_free(data) + +struct opae_adapter *opae_adapter_alloc(const char *name, void *data); +#define opae_adapter_free(adapter) opae_free(adapter) + +int opae_adapter_enumerate(struct opae_adapter *adapter); +void opae_adapter_destroy(struct opae_adapter *adapter); +static inline struct opae_manager * +opae_adapter_get_mgr(struct opae_adapter *adapter) +{ + return adapter ? adapter->mgr : NULL; +} + +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id); + +static inline void opae_adapter_add_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_INSERT_TAIL(&adapter->acc_list, acc, node); +} + +static inline void opae_adapter_remove_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_REMOVE(&adapter->acc_list, acc, node); +} +#endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c new file mode 100644 index 0000000..1dd54d9 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c @@ -0,0 +1,172 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "opae_ifpga_hw_api.h" +#include "ifpga_api.h" + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data || !fme_info) + return -EINVAL; + + fme = mgr->data; + + spinlock_lock(&fme->lock); + fme_info->capability = fme->capability; + spinlock_unlock(&fme->lock); + + return 0; +} + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_irq(fme->parent, FEATURE_FIU_ID_FME, 0, + IFPGA_FME_FEATURE_ID_GLOBAL_ERR, err_irq_set); +} + +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_get_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !port_info) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + port_info->capability = port->capability; + port_info->num_uafu_irqs = port->num_uafu_irqs; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !info) + return -EINVAL; + + /* Only support STP region now */ + if (info->index != PORT_REGION_INDEX_STP) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + info->addr = (u64)port->stp_addr; + info->size = port->stp_size; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_ERROR, err_irq_set); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h new file mode 100644 index 0000000..20e114c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h @@ -0,0 +1,306 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_IFPGA_HW_API_H_ +#define _OPAE_IFPGA_HW_API_H_ + +#include "opae_hw_api.h" + +/** + * struct feature_prop - data structure for feature property + * @feature_id: id of this feature. + * @prop_id: id of this property under this feature. + * @data: property value to set/get. + */ +struct feature_prop { + u64 feature_id; + u64 prop_id; + u64 data; +}; + +#define IFPGA_FIU_ID_FME 0x0 +#define IFPGA_FIU_ID_PORT 0x1 + +#define IFPGA_FME_FEATURE_ID_HEADER 0x0 +#define IFPGA_FME_FEATURE_ID_THERMAL_MGMT 0x1 +#define IFPGA_FME_FEATURE_ID_POWER_MGMT 0x2 +#define IFPGA_FME_FEATURE_ID_GLOBAL_IPERF 0x3 +#define IFPGA_FME_FEATURE_ID_GLOBAL_ERR 0x4 +#define IFPGA_FME_FEATURE_ID_PR_MGMT 0x5 +#define IFPGA_FME_FEATURE_ID_HSSI 0x6 +#define IFPGA_FME_FEATURE_ID_GLOBAL_DPERF 0x7 + +#define IFPGA_PORT_FEATURE_ID_HEADER 0x0 +#define IFPGA_PORT_FEATURE_ID_AFU 0xff +#define IFPGA_PORT_FEATURE_ID_ERROR 0x10 +#define IFPGA_PORT_FEATURE_ID_UMSG 0x11 +#define IFPGA_PORT_FEATURE_ID_UINT 0x12 +#define IFPGA_PORT_FEATURE_ID_STP 0x13 + +/* + * PROP format (TOP + SUB + ID) + * + * (~0x0) means this field is unused. + */ +#define PROP_TOP GENMASK(31, 24) +#define PROP_TOP_UNUSED 0xff +#define PROP_SUB GENMASK(23, 16) +#define PROP_SUB_UNUSED 0xff +#define PROP_ID GENMASK(15, 0) + +#define PROP(_top, _sub, _id) \ + (SET_FIELD(PROP_TOP, _top) | SET_FIELD(PROP_SUB, _sub) |\ + SET_FIELD(PROP_ID, _id)) + +/* FME head feature's properties*/ +#define FME_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define FME_HDR_PROP_PORTS_NUM 0x2 /* RDONLY */ +#define FME_HDR_PROP_CACHE_SIZE 0x3 /* RDONLY */ +#define FME_HDR_PROP_VERSION 0x4 /* RDONLY */ +#define FME_HDR_PROP_SOCKET_ID 0x5 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_ID 0x6 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_METADATA 0x7 /* RDONLY */ + +/* FME error reporting feature's properties */ +/* FME error reporting properties format */ +#define ERR_PROP(_top, _id) PROP(_top, 0xff, _id) +#define ERR_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define ERR_PROP_TOP_FME_ERR 0x1 +#define ERR_PROP_ROOT(_id) ERR_PROP(0xff, _id) +#define ERR_PROP_FME_ERR(_id) ERR_PROP(ERR_PROP_TOP_FME_ERR, _id) + +#define FME_ERR_PROP_ERRORS ERR_PROP_FME_ERR(0x1) +#define FME_ERR_PROP_FIRST_ERROR ERR_PROP_FME_ERR(0x2) +#define FME_ERR_PROP_NEXT_ERROR ERR_PROP_FME_ERR(0x3) +#define FME_ERR_PROP_CLEAR ERR_PROP_FME_ERR(0x4) /* WO */ +#define FME_ERR_PROP_REVISION ERR_PROP_ROOT(0x5) +#define FME_ERR_PROP_PCIE0_ERRORS ERR_PROP_ROOT(0x6) /* RW */ +#define FME_ERR_PROP_PCIE1_ERRORS ERR_PROP_ROOT(0x7) /* RW */ +#define FME_ERR_PROP_NONFATAL_ERRORS ERR_PROP_ROOT(0x8) +#define FME_ERR_PROP_CATFATAL_ERRORS ERR_PROP_ROOT(0x9) +#define FME_ERR_PROP_INJECT_ERRORS ERR_PROP_ROOT(0xa) /* RW */ + +/* FME thermal feature's properties */ +#define FME_THERMAL_PROP_THRESHOLD1 0x1 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD2 0x2 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD_TRIP 0x3 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_REACHED 0x4 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD2_REACHED 0x5 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_POLICY 0x6 /* RW */ +#define FME_THERMAL_PROP_TEMPERATURE 0x7 /* RDONLY */ +#define FME_THERMAL_PROP_REVISION 0x8 /* RDONLY */ + +/* FME power feature's properties */ +#define FME_PWR_PROP_CONSUMED 0x1 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD1 0x2 /* RW */ +#define FME_PWR_PROP_THRESHOLD2 0x3 /* RW */ +#define FME_PWR_PROP_THRESHOLD1_STATUS 0x4 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD2_STATUS 0x5 /* RDONLY */ +#define FME_PWR_PROP_RTL 0x6 /* RDONLY */ +#define FME_PWR_PROP_XEON_LIMIT 0x7 /* RDONLY */ +#define FME_PWR_PROP_FPGA_LIMIT 0x8 /* RDONLY */ +#define FME_PWR_PROP_REVISION 0x9 /* RDONLY */ + +/* FME iperf/dperf PROP format */ +#define PERF_PROP_TOP_CACHE 0x1 +#define PERF_PROP_TOP_VTD 0x2 +#define PERF_PROP_TOP_FAB 0x3 +#define PERF_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define PERF_PROP_SUB_UNUSED PROP_SUB_UNUSED + +#define PERF_PROP_ROOT(_id) PROP(0xff, 0xff, _id) +#define PERF_PROP_CACHE(_id) PROP(PERF_PROP_TOP_CACHE, 0xff, _id) +#define PERF_PROP_VTD(_sub, _id) PROP(PERF_PROP_TOP_VTD, _sub, _id) +#define PERF_PROP_VTD_ROOT(_id) PROP(PERF_PROP_TOP_VTD, 0xff, _id) +#define PERF_PROP_FAB(_sub, _id) PROP(PERF_PROP_TOP_FAB, _sub, _id) +#define PERF_PROP_FAB_ROOT(_id) PROP(PERF_PROP_TOP_FAB, 0xff, _id) + +/* FME iperf feature's properties */ +#define FME_IPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_IPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* iperf CACHE properties */ +#define FME_IPERF_PROP_CACHE_FREEZE PERF_PROP_CACHE(0x1) /* RW */ +#define FME_IPERF_PROP_CACHE_READ_HIT PERF_PROP_CACHE(0x2) +#define FME_IPERF_PROP_CACHE_READ_MISS PERF_PROP_CACHE(0x3) +#define FME_IPERF_PROP_CACHE_WRITE_HIT PERF_PROP_CACHE(0x4) +#define FME_IPERF_PROP_CACHE_WRITE_MISS PERF_PROP_CACHE(0x5) +#define FME_IPERF_PROP_CACHE_HOLD_REQUEST PERF_PROP_CACHE(0x6) +#define FME_IPERF_PROP_CACHE_TX_REQ_STALL PERF_PROP_CACHE(0x7) +#define FME_IPERF_PROP_CACHE_RX_REQ_STALL PERF_PROP_CACHE(0x8) +#define FME_IPERF_PROP_CACHE_RX_EVICTION PERF_PROP_CACHE(0x9) +#define FME_IPERF_PROP_CACHE_DATA_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xa) +#define FME_IPERF_PROP_CACHE_TAG_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xb) +/* iperf VTD properties */ +#define FME_IPERF_PROP_VTD_FREEZE PERF_PROP_VTD_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_HIT PERF_PROP_VTD_ROOT(0x2) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_HIT PERF_PROP_VTD_ROOT(0x3) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_HIT PERF_PROP_VTD_ROOT(0x4) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_HIT PERF_PROP_VTD_ROOT(0x5) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_HIT PERF_PROP_VTD_ROOT(0x6) +#define FME_IPERF_PROP_VTD_SIP_RCC_HIT PERF_PROP_VTD_ROOT(0x7) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_MISS PERF_PROP_VTD_ROOT(0x8) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_MISS PERF_PROP_VTD_ROOT(0x9) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_MISS PERF_PROP_VTD_ROOT(0xa) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_MISS PERF_PROP_VTD_ROOT(0xb) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_MISS PERF_PROP_VTD_ROOT(0xc) +#define FME_IPERF_PROP_VTD_SIP_RCC_MISS PERF_PROP_VTD_ROOT(0xd) +#define FME_IPERF_PROP_VTD_PORT_READ_TRANSACTION(n) PERF_PROP_VTD(n, 0xe) +#define FME_IPERF_PROP_VTD_PORT_WRITE_TRANSACTION(n) PERF_PROP_VTD(n, 0xf) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_READ_HIT(n) PERF_PROP_VTD(n, 0x10) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_WRITE_HIT(n) PERF_PROP_VTD(n, 0x11) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_4K_FILL(n) PERF_PROP_VTD(n, 0x12) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_2M_FILL(n) PERF_PROP_VTD(n, 0x13) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_1G_FILL(n) PERF_PROP_VTD(n, 0x14) +/* iperf FAB properties */ +#define FME_IPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_IPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_IPERF_PROP_FAB_PCIE1_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_IPERF_PROP_FAB_PCIE1_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_IPERF_PROP_FAB_UPI_READ PERF_PROP_FAB_ROOT(0x6) +#define FME_IPERF_PROP_FAB_PORT_UPI_READ(n) PERF_PROP_FAB(n, 0x6) +#define FME_IPERF_PROP_FAB_UPI_WRITE PERF_PROP_FAB_ROOT(0x7) +#define FME_IPERF_PROP_FAB_PORT_UPI_WRITE(n) PERF_PROP_FAB(n, 0x7) +#define FME_IPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x8) +#define FME_IPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x8) +#define FME_IPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x9) +#define FME_IPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x9) +#define FME_IPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0xa) /* RW */ +#define FME_IPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0xa) /* RW */ + +/* FME dperf properties */ +#define FME_DPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_DPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* dperf FAB properties */ +#define FME_DPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_DPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_DPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_DPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_DPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_DPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_DPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_DPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0x6) /* RW */ +#define FME_DPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0x6) /* RW */ + +/*PORT hdr feature's properties*/ +#define PORT_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_HDR_PROP_PORTIDX 0x2 /* RDONLY */ +#define PORT_HDR_PROP_LATENCY_TOLERANCE 0x3 /* RDONLY */ +#define PORT_HDR_PROP_AP1_EVENT 0x4 /* RW */ +#define PORT_HDR_PROP_AP2_EVENT 0x5 /* RW */ +#define PORT_HDR_PROP_POWER_STATE 0x6 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_FREQCMD 0x7 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQCNTRCMD 0x8 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQSTS 0x9 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_CNTRSTS 0xa /* RDONLY */ + +/*PORT error feature's properties*/ +#define PORT_ERR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_ERR_PROP_ERRORS 0x2 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_ERROR 0x3 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB 0x4 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB 0x5 /* RDONLY */ +#define PORT_ERR_PROP_CLEAR 0x6 /* WRONLY */ + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop); +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop); + +/* + * Retrieve information about the fpga fme. + * Driver fills the info in provided struct fpga_fme_info. + */ +struct fpga_fme_info { + u32 capability; /* The capability of FME device */ +#define FPGA_FME_CAP_ERR_IRQ (1 << 0) /* Support fme error interrupt */ +}; + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info); + +/* Set eventfd information for ifpga FME error interrupt */ +struct fpga_fme_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set); + +/* + * Retrieve information about the fpga port. + * Driver fills the info in provided struct fpga_port_info. + */ +struct fpga_port_info { + u32 capability; /* The capability of port device */ +#define FPGA_PORT_CAP_ERR_IRQ (1 << 0) /* Support port error interrupt */ +#define FPGA_PORT_CAP_UAFU_IRQ (1 << 1) /* Support uafu error interrupt */ + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ +}; + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info); +/* + * Retrieve region information about the fpga port. + * Driver needs to fill the index of struct fpga_port_region_info. + */ +struct fpga_port_region_info { + u32 index; +#define PORT_REGION_INDEX_STP (1 << 1) /* Signal Tap Region */ + u64 size; /* Region Size */ + u64 addr; /* Base address of the region */ +}; + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info); + +/* Set eventfd information for ifpga port error interrupt */ +struct fpga_port_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set); + +#endif /* _OPAE_IFPGA_HW_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h new file mode 100644 index 0000000..6557623 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -0,0 +1,115 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_OSDEP_H +#define _OPAE_OSDEP_H + +#include <string.h> +#include <stdbool.h> + +#ifdef RTE_LIBRTE_EAL +#include "osdep_rte/osdep_generic.h" +#else +#include "osdep_raw/osdep_generic.h" +#endif + +#include <asm/types.h> + +#define __iomem + +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef uint64_t dma_addr_t; + +struct uuid { + u8 b[16]; +}; + +#ifndef LINUX_MACROS +#ifndef BITS_PER_LONG +#define BITS_PER_LONG (__SIZEOF_LONG__ * 8) +#endif +#ifndef BIT +#define BIT(a) (1UL << (a)) +#endif /* BIT */ +#ifndef BIT_ULL +#define BIT_ULL(a) (1ULL << (a)) +#endif /* BIT_ULL */ +#ifndef GENMASK +#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#endif /* GENMASK */ +#ifndef GENMASK_ULL +#define GENMASK_ULL(h, l) (((U64_C(1) << ((h) - (l) + 1)) - 1) << (l)) +#endif /* GENMASK_ULL */ +#endif /* LINUX_MACROS */ + +#define SET_FIELD(m, v) (((v) << (__builtin_ffsll(m) - 1)) & (m)) +#define GET_FIELD(m, v) (((v) & (m)) >> (__builtin_ffsll(m) - 1)) + +#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) +#define pr_info(y, args...) dev_info(0, y, ##args) +#define BUG() pr_err("BUG at %s:%d", __func__, __LINE__) + +#define ASSERT(x) do {\ + if (!(x)) \ + osdep_panic("osdep_panic: x"); \ +} while (0) +#define BUG_ON(x) ASSERT(!(x)) + +#ifndef WARN_ON +#define WARN_ON(x) do { \ + int ret = !!(x); \ + if (unlikely(ret)) \ + pr_warn("WARN_ON: \"" #x "\" at %s:%d\n", __func__, __LINE__); \ +} while (0) +#endif + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define udelay(x) opae_udelay(x) +#define msleep(x) opae_udelay(1000 * (x)) +#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000)) + +#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 new file mode 100644 index 0000000..12ad018 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h @@ -0,0 +1,104 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OSDEP_RAW_GENERIC_H +#define _OSDEP_RAW_GENERIC_H + +#define compiler_barrier() do { \ + asm volatile ("" : : : "memory"); \ +} while (0) + +#define io_wmb() compiler_barrier() +#define io_rmb() compiler_barrier() + +static inline uint8_t opae_readb(const volatile void *addr) +{ + uint8_t val; + + val = *(const volatile uint8_t *)addr; + io_rmb(); + return val; +} + +static inline uint16_t opae_readw(const volatile void *addr) +{ + uint16_t val; + + val = *(const volatile uint16_t *)addr; + io_rmb(); + return val; +} + +static inline uint32_t opae_readl(const volatile void *addr) +{ + uint32_t val; + + val = *(const volatile uint32_t *)addr; + io_rmb(); + return val; +} + +static inline uint64_t opae_readq(const volatile void *addr) +{ + uint64_t val; + + val = *(const volatile uint64_t *)addr; + io_rmb(); + return val; +} + +static inline void opae_writeb(uint8_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint8_t *)addr = value; +} + +static inline void opae_writew(uint16_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint16_t *)addr = value; +} + +static inline void opae_writel(uint32_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint32_t *)addr = value; +} + +static inline void opae_writeq(uint64_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint64_t *)addr = value; +} + +#define opae_free(addr) free(addr) + +#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 new file mode 100644 index 0000000..9ff580e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h @@ -0,0 +1,72 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OSDEP_RTE_GENERIC_H +#define _OSDEP_RTE_GENERIC_H + +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_spinlock.h> +#include <rte_log.h> +#include <rte_io.h> +#include <rte_malloc.h> + +#define dev_printf(level, fmt, args...) \ + RTE_LOG(level, PMD, "osdep_rte: " fmt, ## args) + +#define osdep_panic(...) rte_panic(...) + +#define opae_udelay(x) rte_delay_us(x) + +#define opae_readb(addr) rte_read8(addr) +#define opae_readw(addr) rte_read16(addr) +#define opae_readl(addr) rte_read32(addr) +#define opae_readq(addr) rte_read64(addr) +#define opae_writeb(value, addr) rte_write8(value, addr) +#define opae_writew(value, addr) rte_write16(value, addr) +#define opae_writel(value, addr) rte_write32(value, addr) +#define opae_writeq(value, addr) rte_write64(value, addr) + +#define opae_malloc(size) rte_malloc(NULL, size, 0) +#define opae_zmalloc(size) rte_zmalloc(NULL, size, 0) +#define opae_free(addr) rte_free(addr) + +#define ARRAY_SIZE(arr) RTE_DIM(arr) + +#define min(a, b) RTE_MIN(a, b) +#define max(a, b) RTE_MAX(a, b) + +#define spinlock_t rte_spinlock_t +#define spinlock_init(x) rte_spinlock_init(x) +#define spinlock_lock(x) rte_spinlock_lock(x) +#define spinlock_unlock(x) rte_spinlock_unlock(x) + +#endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (7 preceding siblings ...) 2018-03-31 16:02 ` [dpdk-dev] [PATCH v4 0/3] " Rosen Xu @ 2018-04-04 6:51 ` Rosen Xu 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 1/3] Add Intel FPGA BUS Library Rosen Xu ` (3 more replies) 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 0/5] " Xu, Rosen ` (8 subsequent siblings) 17 siblings, 4 replies; 149+ messages in thread From: Rosen Xu @ 2018-04-04 6:51 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset=y, Size: 7683 bytes --] Intel FPGA BUS in DPDK ------------------------- This patch set introduces Intel FPGA BUS support in DPDK. v5 updates: =========== - Fixed SHARED LIB Build issue - Changed command name to IFPGA Rawdev name, so remove pci library datastruct and function. - Fixed PATCH v2/v3/v4 comments v4 updates: =========== - Remove all modifications from eal - Create vdev to take IFPGA parameters configuration - AFU Device Driver bind to AFU Device by uuid - Take more test in scenario of Multi-FPGA System v3 updates: =========== - Remove all modifications of bus scan and probe - FPGA BUS Scan is trigged by hotplug of Rawdev - Took Modifications of comments - Move AFU Device to IFPGA - FPGA BUS Scan depend on it¡¯s IFPGA Rawdev - Add Build Macros for FPGA BUS and IFPGA Rawdev Questions ========= Why not PCI Bus? All of the AFUs of one FPGA may share same PCI BDF. Why not vdev Bus? Because AFUs depend on Rawdev, and it's hardware specpic. Motivation ========== FPGA is used more and more widely in Cloud and NFV, one primary reason is that FPGA not only provide ASIC performance but also it's more flexible than ASIC. FPGA use Partial Reconfigure(PR) Parts of Bitstream to achieve its flexibility. Another reason is that one FPGA can be shared by different Users, and each User can use some of AFUs of One FPGA. That means One FPGA Device Bitstream is divided into many Parts of Bitstream(each Part of Bitstream is defined as AFU-Accelerated Function Unit), and each AFU is a Hardware Acceleration Unit and it can dynamically Reload respectively. Proposed Solution ================= - Involve Rawdev to take FPGA Partial Configuration(Download/PR) - Defined FPGA-BUS for Acceleration Drivers of AFUs - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver. FPGA-BUS scan is called, but AFU depend on Rawdev, so this scan doesn't trig AFU device create. - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their dirves are also probed. Scope ===== The Intel FPGA BUS implementation is target towards various FPGA Devices use PR to provide many Acceleration Function. Specific PMDs may also bind to its AFU. And Applications don't care they are using ASIC Acceleration or FPGA AFU Acceleration. Status ===== With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable Acceleration Engine) Share Code, Intel FPGA BUS runs well in Intel PSG FPGA Cards. Rosen Xu (3): Add Intel FPGA BUS Library Add Intel FPGA BUS Rawdev Driver Add Intel FPGA OPAE Share Code config/common_base | 6 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 + drivers/bus/ifpga/ifpga_bus.c | 504 ++++++ drivers/bus/ifpga/ifpga_common.c | 88 + drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 + drivers/bus/ifpga/rte_bus_ifpga.h | 168 ++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 + drivers/raw/ifpga_rawdev/base/Makefile | 54 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 529 ++++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 73 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 84 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1688 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 851 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 38 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 341 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 191 +++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 761 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 328 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 430 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 742 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 399 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 154 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 435 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 192 +++ drivers/raw/ifpga_rawdev/base/opae_debug.c | 126 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 46 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 408 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 280 ++++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 172 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 306 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 115 ++ .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 104 ++ .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 72 + drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 592 +++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 + .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + mk/rte.app.mk | 3 + 41 files changed, 10450 insertions(+) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v5 1/3] Add Intel FPGA BUS Library 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS Rosen Xu @ 2018-04-04 6:51 ` Rosen Xu 2018-04-04 9:55 ` Bruce Richardson 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 2/3] Add Intel FPGA BUS Rawdev Driver Rosen Xu ` (2 subsequent siblings) 3 siblings, 1 reply; 149+ messages in thread From: Rosen Xu @ 2018-04-04 6:51 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet Signed-off-by: Rosen Xu <rosen.xu@intel.com> --- config/common_base | 5 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 ++ drivers/bus/ifpga/ifpga_bus.c | 504 ++++++++++++++++++++++++++++ drivers/bus/ifpga/ifpga_common.c | 88 +++++ drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 ++ drivers/bus/ifpga/rte_bus_ifpga.h | 168 ++++++++++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + mk/rte.app.mk | 2 + 10 files changed, 859 insertions(+) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map diff --git a/config/common_base b/config/common_base index ad03cf4..49f6b09 100644 --- a/config/common_base +++ b/config/common_base @@ -134,6 +134,11 @@ CONFIG_RTE_LIBRTE_PCI_BUS=y CONFIG_RTE_LIBRTE_VDEV_BUS=y # +# Compile the Intel FPGA bus +# +CONFIG_RTE_LIBRTE_IFPGA_BUS=y + +# # Compile ARK PMD # CONFIG_RTE_LIBRTE_ARK_PMD=y diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index 7ef2593..55d2dfe 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -7,5 +7,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile new file mode 100644 index 0000000..3ff3bdb --- /dev/null +++ b/drivers/bus/ifpga/Makefile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_bus_ifpga.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_kvargs + +# versioning export map +EXPORT_MAP := rte_bus_ifpga_version.map + +# library version +LIBABIVER := 1 + +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c + +# +# Export include files +# +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index 0000000..84d32ad --- /dev/null +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -0,0 +1,504 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_bus_logtype; + +/* Forward declare to access Intel FPGA bus name */ +static struct rte_bus rte_ifpga_bus; + +/** Double linked list of IFPGA device. */ +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); + +static struct ifpga_device_list ifpga_device_list = + TAILQ_HEAD_INITIALIZER(ifpga_device_list); +struct afu_driver_list afu_driver_list = + TAILQ_HEAD_INITIALIZER(afu_driver_list); + + +/* register a ifpga bus based driver */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver) +{ + RTE_VERIFY(driver); + + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); +} + +/* un-register a fpga bus based driver */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) +{ + TAILQ_REMOVE(&afu_driver_list, driver, next); +} + +static struct rte_ifpga_device * +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + if (rdev && + ifpga_dev->rdev && + ifpga_dev->rdev == rdev) + return ifpga_dev; + } + return NULL; +} + +static struct rte_afu_device * +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, + const struct rte_afu_id *afu_id) +{ + struct rte_afu_device *afu_dev = NULL; + + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) + return afu_dev; + } + return NULL; +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static struct rte_afu_device * +rte_ifpga_scan_one(struct rte_devargs *devargs, + struct rte_ifpga_device *ifpga_dev) +{ + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_afu_pr_conf afu_pr_conf; + int ret = 0; + char *path = NULL; + + memset((char *)(&afu_pr_conf), 0, sizeof(struct rte_afu_pr_conf)); + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, + &ifpga_get_string_arg, &path) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_AFU_BTS); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_AFU_BTS); + goto end; + } + + afu_pr_conf.afu_id.uuid_low = 0; + afu_pr_conf.afu_id.uuid_high = 0; + afu_pr_conf.pr_enable = path?1:0; + + rawdev = ifpga_dev->rdev; + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) + goto end; + + afu_dev = calloc(1, sizeof(*afu_dev)); + if (!afu_dev) + goto end; + + afu_dev->device.devargs = devargs; + afu_dev->device.numa_node = SOCKET_ID_ANY; + afu_dev->device.name = devargs->name; + afu_dev->rawdev = rawdev; + afu_dev->id.uuid_low = 0; + afu_dev->id.uuid_high = 0; + afu_dev->id.port = afu_pr_conf.afu_id.port; + afu_dev->ifpga_dev = ifpga_dev; + + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); + + if (rawdev->dev_ops && + rawdev->dev_ops->dev_start && + rawdev->dev_ops->dev_start(rawdev)) + goto free_dev; + + strncpy(afu_pr_conf.bs_path, path, strlen(afu_pr_conf.bs_path)); + if (rawdev->dev_ops->firmware_load && + rawdev->dev_ops->firmware_load(rawdev, + &afu_pr_conf)){ + printf("firmware load error %d\n", ret); + goto free_dev; + } + afu_dev->id.uuid_low = afu_pr_conf.afu_id.uuid_low; + afu_dev->id.uuid_high = afu_pr_conf.afu_id.uuid_high; + + + return afu_dev; + +free_dev: + free(afu_dev); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (path) + free(path); + + return NULL; +} + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static int +rte_ifpga_scan(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + char *name = NULL; + char name1[RTE_RAWDEV_NAME_MAX_LEN]; + struct rte_afu_device *afu_dev = NULL; + + /* for FPGA devices we scan the devargs_list populated via cmdline */ + TAILQ_FOREACH(devargs, &devargs_list, next) { + if (devargs->bus != &rte_ifpga_bus) + continue; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &ifpga_get_string_arg, &name) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + memset(name1, 0, sizeof(name1)); + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", name); + + rawdev = rte_rawdev_pmd_get_named_dev(name1); + if (!rawdev) + goto end; + + if (ifpga_find_ifpga_dev(rawdev)) + continue; + + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); + if (!ifpga_dev) + goto end; + + ifpga_dev->rdev = rawdev; + TAILQ_INIT(&ifpga_dev->afu_list); + + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); + afu_dev = rte_ifpga_scan_one(devargs, ifpga_dev); + if (afu_dev != NULL) + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, next); + } + +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +/* + * Match the AFU Driver and AFU Device using the ID Table + */ +static int +rte_afu_match(const struct rte_afu_driver *afu_drv, + const struct rte_afu_device *afu_dev) +{ + const struct rte_afu_uuid *id_table; + + for (id_table = afu_drv->id_table; + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); + id_table++) { + /* check if device's identifiers match the driver's ones */ + if ((id_table->uuid_low != afu_dev->id.uuid_low) || + (id_table->uuid_high != afu_dev->id.uuid_high)) + continue; + + return 1; + } + + return 0; +} + +static int +ifpga_probe_one_driver(struct rte_afu_driver *drv, + struct rte_afu_device *afu_dev) +{ + int ret; + + if (!rte_afu_match(drv, afu_dev)) + /* Match of device and driver failed */ + return 1; + + /* reference driver structure */ + afu_dev->driver = drv; + afu_dev->device.driver = &drv->driver; + + /* call the driver probe() function */ + ret = drv->probe(afu_dev); + if (ret) { + afu_dev->driver = NULL; + afu_dev->device.driver = NULL; + } + + /* return positive value if driver doesn't support this device */ + return 0; +} + +static int +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) +{ + struct rte_afu_driver *drv = NULL; + int rc; + + if (afu_dev == NULL) + return -1; + + /* Check if a driver is already loaded */ + if (afu_dev->driver != NULL) + return 0; + + TAILQ_FOREACH(drv, &afu_driver_list, next) { + rc = ifpga_probe_one_driver(drv, afu_dev); + if (rc < 0) + /* negative value is an error */ + return -1; + if (rc > 0) + /* positive value means driver doesn't support it */ + continue; + return 0; + } + return 1; +} + +/* + * Scan the content of the Intel FPGA bus, and call the probe() function for + * all registered drivers that have a matching entry in its id_table + * for discovered devices. + */ +static int +rte_ifpga_probe(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev = NULL; + int ret = 0; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + + if (afu_dev->device.driver) + continue; + + ret = ifpga_probe_all_drivers(afu_dev); + if (ret < 0) + IFPGA_BUS_ERR("failed to initialize %s device\n", + rte_ifpga_device_name(afu_dev)); + } + } + + return 0; +} + +static int +rte_ifpga_plug(struct rte_device *dev) +{ + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); +} + +static int ifpga_remove_driver(struct rte_afu_device *afu_dev) +{ + const char *name; + const struct rte_afu_driver *driver; + + name = rte_ifpga_device_name(afu_dev); + if (!afu_dev->device.driver) { + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); + return 1; + } + + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); + return driver->remove(afu_dev); +} + +static int +rte_ifpga_unplug(struct rte_device *dev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_devargs *devargs = NULL; + int ret; + + if (dev == NULL) + return -EINVAL; + + afu_dev = RTE_DEV_TO_AFU(dev); + if (!dev) + return -ENOENT; + + ifpga_dev = afu_dev->ifpga_dev; + devargs = dev->devargs; + + ret = ifpga_remove_driver(afu_dev); + if (ret) + return ret; + + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); + + TAILQ_REMOVE(&devargs_list, devargs, next); + + free(devargs->args); + free(devargs); + free(afu_dev); + return 0; + +} + +static struct rte_device * +rte_ifpga_find_device(const struct rte_device *start, + rte_dev_cmp_t cmp, const void *data) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (start && &afu_dev->device == start) { + start = NULL; + continue; + } + if (cmp(&afu_dev->device, data) == 0) + return &afu_dev->device; + } + } + return NULL; +} +static int +rte_ifpga_parse(const char *name, void *addr) +{ + int *out = addr; + struct rte_rawdev *rawdev = NULL; + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; + char *c1 = NULL, *c2 = NULL; + int port = IFPGA_BUS_DEV_PORT_MAX; + char str_port[8]; + int str_port_len = 0; + + memset(str_port, 0, 8); + c1 = strchr(name, '|'); + if (c1 != NULL) { + str_port_len = c1-name; + c2 = c1+1; + } + + if (str_port_len < 8 && + str_port_len > 0) { + memcpy(str_port, name, str_port_len); + sscanf(str_port, "%d", &port); + } + + memset(rawdev_name, 0, sizeof(rawdev_name)); + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", c2); + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev && + (addr != NULL)) + *out = port; + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev) + return 0; + else + return 1; +} + +static struct rte_bus rte_ifpga_bus = { + .scan = rte_ifpga_scan, + .probe = rte_ifpga_probe, + .find_device = rte_ifpga_find_device, + .plug = rte_ifpga_plug, + .unplug = rte_ifpga_unplug, + .parse = rte_ifpga_parse, +}; + +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); + +RTE_INIT(ifpga_init_log) +{ + ifpga_bus_logtype = rte_log_register("bus.ifpga"); + if (ifpga_bus_logtype >= 0) + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); +} + diff --git a/drivers/bus/ifpga/ifpga_common.c b/drivers/bus/ifpga/ifpga_common.c new file mode 100644 index 0000000..26fee27 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(char **)extra_args = strdup(value); + + if (!*(char **)extra_args) + return -ENOMEM; + + return 0; +} +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(int *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(uint64_t *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_unsigned_long(const char *str, int base) +{ + unsigned long num; + char *end = NULL; + + errno = 0; + + num = strtoul(str, &end, base); + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) + return -1; + + return num; +} + +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1) +{ + if ((afu_id0->uuid_low == afu_id1->uuid_low) && + (afu_id0->uuid_high == afu_id1->uuid_high) && + (afu_id0->port == afu_id1->port)) { + return 0; + } else + return 1; +} diff --git a/drivers/bus/ifpga/ifpga_common.h b/drivers/bus/ifpga/ifpga_common.h new file mode 100644 index 0000000..b6662c8 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMMON_H_ +#define _IFPGA_COMMON_H_ + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_unsigned_long(const char *str, int base); +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1); + +#endif /* _IFPGA_COMMON_H_ */ diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index 0000000..873e0a4 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_logs.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_LOGS_H_ +#define _IFPGA_LOGS_H_ + +#include <rte_log.h> + +extern int ifpga_bus_logtype; + +#define IFPGA_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") + +#define IFPGA_BUS_DEBUG(fmt, args...) \ + IFPGA_BUS_LOG(DEBUG, fmt, ## args) +#define IFPGA_BUS_INFO(fmt, args...) \ + IFPGA_BUS_LOG(INFO, fmt, ## args) +#define IFPGA_BUS_ERR(fmt, args...) \ + IFPGA_BUS_LOG(ERR, fmt, ## args) +#define IFPGA_BUS_WARN(fmt, args...) \ + IFPGA_BUS_LOG(WARNING, fmt, ## args) + +#endif /* _IFPGA_BUS_LOGS_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h new file mode 100644 index 0000000..53e7183 --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga.h @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _RTE_BUS_IFPGA_H_ +#define _RTE_BUS_IFPGA_H_ + +/** + * @file + * + * RTE Intel FPGA Bus Interface + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_bus.h> +#include <rte_pci.h> + +/** Name of Intel FPGA Bus */ +#define IFPGA_BUS_NAME ifpga + +/* Forward declarations */ +struct rte_afu_device; + +/** List of Intel AFU devices */ +TAILQ_HEAD(afu_device_list, rte_afu_device); +/** Double linked list of AFU device drivers. */ +TAILQ_HEAD(afu_driver_list, rte_afu_driver); + +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 + +struct rte_afu_uuid { + uint64_t uuid_low; + uint64_t uuid_high; +} __attribute__ ((packed)); + +#define IFPGA_BUS_DEV_PORT_MAX 4 + +/** + * A structure describing an ID for a AFU driver. Each driver provides a + * table of these IDs for each device that it supports. + */ +struct rte_afu_id { + uint64_t uuid_low; + uint64_t uuid_high; + int port; +} __attribute__ ((packed)); + +/** + * A structure pr configuration AFU driver. + */ + +struct rte_afu_pr_conf { + struct rte_afu_id afu_id; + int pr_enable; + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +}; + +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) + +/** + * A structure describing a fpga device. + */ +struct rte_ifpga_device { + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ + struct rte_rawdev *rdev; + struct afu_device_list afu_list; /**< List of AFU devices */ +}; + +/** + * A structure describing a AFU device. + */ +struct rte_afu_device { + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ + struct rte_device device; /**< Inherit core device */ + struct rte_rawdev *rawdev; /**< Point Rawdev */ + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ + struct rte_afu_id id; /**< AFU id within FPGA. */ + uint32_t num_region; /**< number of regions found */ + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; + /**< AFU Memory Resource */ + struct rte_intr_handle intr_handle; /**< Interrupt handle */ + struct rte_afu_driver *driver; /**< Associated driver */ + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +} __attribute__ ((packed)); + +/** + * @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_DRV_TO_AFU_CONST(ptr) \ + container_of(ptr, const struct rte_afu_driver, driver) + +/** + * Initialisation function for the driver called during FPGA BUS probing. + */ +typedef int (afu_probe_t)(struct rte_afu_device *); + +/** + * Uninitialisation function for the driver called during hotplugging. + */ +typedef int (afu_remove_t)(struct rte_afu_device *); + +/** + * A structure describing a AFU device. + */ +struct rte_afu_driver { + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ + struct rte_driver driver; /**< Inherit core driver. */ + afu_probe_t *probe; /**< Device Probe function. */ + afu_remove_t *remove; /**< Device Remove function. */ + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ + uint32_t drv_flags; /**< Flags contolling handling of device. */ +}; + +/** + * Structure describing the Intel FPGA bus + */ +struct rte_ifpga_bus { + struct rte_bus bus; /**< Inherit the generic class */ +}; + +static inline const char * +rte_ifpga_device_name(const struct rte_afu_device *afu) +{ + if (afu && afu->device.name) + return afu->device.name; + return NULL; +} + +/** + * Register a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be registered. + */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver); + +/** + * Unregister a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be unregistered. + */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); + +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ +RTE_INIT(afudrvinitfn_ ##afudrv);\ +static const char *afudrvinit_ ## nm ## _alias;\ +static void afudrvinitfn_ ##afudrv(void)\ +{\ + (afudrv).driver.name = RTE_STR(nm);\ + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ + rte_ifpga_driver_register(&afudrv);\ +} \ +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) + +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ +static const char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) + +#endif /* _RTE_BUS_IFPGA_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map new file mode 100644 index 0000000..7e46261 --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map @@ -0,0 +1,10 @@ +DPDK_18.05 { + global: + + rte_ifpga_driver_register; + rte_ifpga_driver_unregister; + ifpga_get_string_arg; + ifpga_get_integer32_arg; + + local: *; +}; diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 3eb41d1..929c3d8 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -107,6 +107,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE) += -lrte_cmdline _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrte_sched +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga + ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v5 1/3] Add Intel FPGA BUS Library 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 1/3] Add Intel FPGA BUS Library Rosen Xu @ 2018-04-04 9:55 ` Bruce Richardson 0 siblings, 0 replies; 149+ messages in thread From: Bruce Richardson @ 2018-04-04 9:55 UTC (permalink / raw) To: Rosen Xu Cc: dev, declan.doherty, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet On Wed, Apr 04, 2018 at 02:51:15PM +0800, Rosen Xu wrote: > Signed-off-by: Rosen Xu <rosen.xu@intel.com> Please include a description of this patch in the commit message. The cover letter is not going to be part of the commit history, after all. Therefore, move or copy relevant parts of the cover letter to the commit message here, so that someone viewing the git log gets a good overview of this work. > --- > config/common_base | 5 + > drivers/bus/Makefile | 1 + > drivers/bus/ifpga/Makefile | 32 ++ > drivers/bus/ifpga/ifpga_bus.c | 504 ++++++++++++++++++++++++++++ > drivers/bus/ifpga/ifpga_common.c | 88 +++++ > drivers/bus/ifpga/ifpga_common.h | 18 + > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > drivers/bus/ifpga/rte_bus_ifpga.h | 168 ++++++++++ > drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + > mk/rte.app.mk | 2 + Need to add this to the meson build too. If you are unfamiliar with building DPDK with meson see "doc/build-sdk-meson.txt". /Bruce ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v5 2/3] Add Intel FPGA BUS Rawdev Driver 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS Rosen Xu 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 1/3] Add Intel FPGA BUS Library Rosen Xu @ 2018-04-04 6:51 ` Rosen Xu 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 3/3] Add Intel FPGA OPAE Share Code Rosen Xu 2018-04-04 10:14 ` [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS Shreyansh Jain 3 siblings, 0 replies; 149+ messages in thread From: Rosen Xu @ 2018-04-04 6:51 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet, Yanglong Wu Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> --- config/common_base | 1 + drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 ++ drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 592 +++++++++++++++++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + mk/rte.app.mk | 1 + 7 files changed, 672 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map diff --git a/config/common_base b/config/common_base index 49f6b09..08b7cce 100644 --- a/config/common_base +++ b/config/common_base @@ -137,6 +137,7 @@ CONFIG_RTE_LIBRTE_VDEV_BUS=y # Compile the Intel FPGA bus # CONFIG_RTE_LIBRTE_IFPGA_BUS=y +CONFIG_RTE_LIBRTE_IFPGA_RAWDEV=y # # Compile ARK PMD diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index da7c8b4..6fc8f2f 100644 --- a/drivers/raw/Makefile +++ b/drivers/raw/Makefile @@ -5,5 +5,6 @@ include $(RTE_SDK)/mk/rte.vars.mk # DIRS-$(<configuration>) += <directory> DIRS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += skeleton_rawdev +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/raw/ifpga_rawdev/Makefile b/drivers/raw/ifpga_rawdev/Makefile new file mode 100644 index 0000000..66e2e34 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/Makefile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_ifpga_rawdev.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_bus_vdev +LDLIBS += -lrte_kvargs +LDLIBS += -lrte_bus_pci +LDLIBS += -lrte_bus_ifpga + +EXPORT_MAP := rte_ifpga_rawdev_version.map + +LIBABIVER := 1 + +VPATH += $(SRCDIR)/base + +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c new file mode 100644 index 0000000..110b709 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c @@ -0,0 +1,592 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <rte_log.h> +#include <rte_bus.h> +#include <rte_eal_memconfig.h> +#include <rte_malloc.h> +#include <rte_devargs.h> +#include <rte_memcpy.h> +#include <rte_ethdev.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include <rte_errno.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> +#include <rte_bus_vdev.h> + +#include "base/opae_hw_api.h" +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_common.h" +#include "ifpga_logs.h" +#include "ifpga_rawdev.h" + +int ifpga_rawdev_logtype; + +#define PCI_VENDOR_ID_INTEL 0x8086 +/* PCI Device ID */ +#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 +/* 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 RTE_MAX_RAW_DEVICE 10 + +static const struct rte_pci_id pci_ifpga_map[] = { + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_6_X) }, + { 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) }, + { .vendor_id = 0, /* sentinel */ }, +}; + +static int ifpga_fill_afu_dev(struct opae_accelerator *acc, + struct rte_afu_device *afu_dev) +{ + struct rte_mem_resource *res = afu_dev->mem_resource; + struct opae_acc_region_info region_info; + struct opae_acc_info info; + unsigned long i; + int ret; + + ret = opae_acc_get_info(acc, &info); + if (ret) + return ret; + + if (info.num_regions > PCI_MAX_RESOURCE) + return -EFAULT; + + afu_dev->num_region = info.num_regions; + + for (i = 0; i < info.num_regions; i++) { + region_info.index = i; + ret = opae_acc_get_region_info(acc, ®ion_info); + if (ret) + return ret; + + if ((region_info.flags & ACC_REGION_MMIO) && + (region_info.flags & ACC_REGION_READ) && + (region_info.flags & ACC_REGION_WRITE)) { + res[i].phys_addr = region_info.phys_addr; + res[i].len = region_info.len; + res[i].addr = region_info.addr; + } else + return -EFAULT; + } + + return 0; +} + +static void ifpga_rawdev_info_get(struct rte_rawdev *dev, + rte_rawdev_obj_t dev_info) +{ + struct opae_adapter *adapter; + struct opae_accelerator *acc; + struct rte_afu_device *afu_dev; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + if (!dev_info) { + IFPGA_RAWDEV_PMD_ERR("Invalid request"); + return; + } + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return; + + afu_dev = dev_info; + afu_dev->rawdev = dev; + + /* find opae_accelerator and fill info into afu_device */ + opae_adapter_for_each_acc(adapter, acc) { + if (acc->index != afu_dev->id.port) + continue; + + if (ifpga_fill_afu_dev(acc, afu_dev)) { + IFPGA_RAWDEV_PMD_ERR("cannot get info\n"); + return; + } + } +} + +static int ifpga_rawdev_start(struct rte_rawdev *dev) +{ + int ret = 0; + struct opae_adapter *adapter; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + return ret; +} + +static void ifpga_rawdev_stop(struct rte_rawdev *dev) +{ + dev->started = 0; +} + +static int ifpga_rawdev_close(struct rte_rawdev *dev) +{ + if (!dev) + return 1; + else + return 0; +} + +static int ifpga_rawdev_reset(struct rte_rawdev *dev) +{ + if (!dev) + return 1; + else + return 0; +} + +static int +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, + u64 *status){ + + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_accelerator *acc; + struct opae_bridge *br; + int ret; + + adapter = ifpga_rawdev_get_priv(raw_dev); + if (!adapter) + return -ENODEV; + + mgr = opae_adapter_get_mgr(adapter); + if (!mgr) + return -ENODEV; + + acc = opae_adapter_get_acc(adapter, port_id); + if (!acc) + return -ENODEV; + + br = opae_acc_get_br(acc); + if (!br) + return -ENODEV; + + ret = opae_manager_flash(mgr, port_id, buffer, size, status); + if (ret) { + printf("%s pr error %d\n", __func__, ret); + return ret; + } + + usleep(100); + ret = opae_bridge_reset(br); + if (ret) { + printf("%s reset port:%d error %d\n", __func__, port_id, ret); + return ret; + } + + return ret; +} + +static int rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, + const char *file_name) +{ + struct stat file_stat; + int file_fd; + int ret = 0; + u32 buffer_size; + void *buffer; + u64 pr_error; + + if (!file_name) + return -EINVAL; + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + printf("%s: open file error: %s\n", __func__, file_name); + printf("Message : %s\n", strerror(errno)); + return -EINVAL; + } + ret = stat(file_name, &file_stat); + if (ret) { + printf("stat on bitstream file failed: %s\n", file_name); + return -EINVAL; + } + buffer_size = file_stat.st_size; + printf("bitstream file size: %u\n", buffer_size); + buffer = rte_malloc(NULL, buffer_size, 0); + if (!buffer) { + ret = -ENOMEM; + goto close_fd; + } + + /*read the raw data*/ + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { + ret = -EINVAL; + goto free_buffer; + } + + /*do PR now*/ + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); + printf("downloading to device port %d....%s.\n", port_id, + ret ? "failed" : "success"); + if (ret) { + ret = -EINVAL; + //raw_dev->ops->show_pr_error(pr_error); + goto free_buffer; + } + +free_buffer: + if (buffer) + rte_free(buffer); +close_fd: + close(file_fd); + file_fd = 0; + return ret; +} + +static int ifpga_rawdev_pr(struct rte_rawdev *dev, + rte_rawdev_obj_t pr_conf) +{ + struct opae_adapter *adapter; + struct rte_afu_pr_conf *afu_pr_conf; + int ret; + struct uuid uuid; + struct opae_accelerator *acc; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + if (!pr_conf) + return -EINVAL; + + afu_pr_conf = pr_conf; + + ret = rte_fpga_do_pr(dev, afu_pr_conf->afu_id.port, + afu_pr_conf->bs_path); + if (ret) { + printf("do pr error %d\n", ret); + return ret; + } + + acc = opae_adapter_get_acc(adapter, afu_pr_conf->afu_id.port); + if (!acc) + return -ENODEV; + + ret = opae_acc_get_uuid(acc, &uuid); + if (ret) + return ret; + + memcpy(&afu_pr_conf->afu_id.uuid_low, uuid.b, sizeof(u64)); + memcpy(&afu_pr_conf->afu_id.uuid_high, uuid.b + 8, sizeof(u64)); + + printf("%s: uuid_l=0x%lx, uuid_h=0x%lx\n", __func__, + (u64)afu_pr_conf->afu_id.uuid_low, + (u64)afu_pr_conf->afu_id.uuid_high); + + return 0; +} + +static const struct rte_rawdev_ops ifpga_rawdev_ops = { + .dev_info_get = ifpga_rawdev_info_get, + .dev_configure = NULL, + .dev_start = ifpga_rawdev_start, + .dev_stop = ifpga_rawdev_stop, + .dev_close = ifpga_rawdev_close, + .dev_reset = ifpga_rawdev_reset, + + .queue_def_conf = NULL, + .queue_setup = NULL, + .queue_release = NULL, + + .attr_get = NULL, + .attr_set = NULL, + + .enqueue_bufs = NULL, + .dequeue_bufs = NULL, + + .dump = NULL, + + .xstats_get = NULL, + .xstats_get_names = NULL, + .xstats_get_by_name = NULL, + .xstats_reset = NULL, + + .firmware_status_get = NULL, + .firmware_version_get = NULL, + .firmware_load = ifpga_rawdev_pr, + .firmware_unload = NULL, + + .dev_selftest = NULL, +}; + +static int +ifpga_rawdev_create(struct rte_pci_device *pci_dev, + int socket_id) +{ + int ret = 0; + struct rte_rawdev *rawdev = NULL; + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_adapter_data_pci *data; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + int i; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + goto cleanup; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x:%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id()); + + /* Allocate device structure */ + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct opae_adapter), + socket_id); + if (rawdev == NULL) { + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); + ret = -EINVAL; + goto cleanup; + } + + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API */ + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); + if (!data) + return -ENOMEM; + + /* init opae_adapter_data_pci for device specific information */ + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + data->region[i].phys_addr = pci_dev->mem_resource[i].phys_addr; + data->region[i].len = pci_dev->mem_resource[i].len; + data->region[i].addr = pci_dev->mem_resource[i].addr; + } + data->device_id = pci_dev->id.device_id; + data->vendor_id = pci_dev->id.vendor_id; + + /* create a opae_adapter based on above device data */ + adapter = opae_adapter_alloc(pci_dev->device.name, data); + if (!adapter) { + opae_adapter_data_free(data); + return -ENOMEM; + } + + rawdev->dev_ops = &ifpga_rawdev_ops; + rawdev->device = &pci_dev->device; + rawdev->driver_name = pci_dev->device.driver->name; + + rawdev->dev_private = adapter; + + /* must enumerate the adapter before use it */ + ret = opae_adapter_enumerate(adapter); + if (ret) + return ret; + + /* set opae_manager to rawdev */ + mgr = opae_adapter_get_mgr(adapter); + if (mgr) { + /*PF function*/ + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); + } + + return ret; + +cleanup: + if (rawdev) + rte_rawdev_pmd_release(rawdev); + + return ret; +} + +static int +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) +{ + int ret; + struct rte_rawdev *rawdev; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + struct opae_adapter *adapter; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + return ret; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", + name, rte_socket_id()); + + rawdev = rte_rawdev_pmd_get_named_dev(name); + if (!rawdev) { + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name); + return -EINVAL; + } + + adapter = ifpga_rawdev_get_priv(rawdev); + if (!adapter) + return -ENODEV; + + opae_adapter_data_free(adapter->data); + opae_adapter_free(adapter); + + /* rte_rawdev_close is called by pmd_release */ + ret = rte_rawdev_pmd_release(rawdev); + if (ret) + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); + + return 0; +} + +static int +ifpga_rawdev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, + struct rte_pci_device *pci_dev) +{ + + printf("## %s\n", __func__); + return ifpga_rawdev_create(pci_dev, rte_socket_id()); +} + +static int ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) +{ + return ifpga_rawdev_destroy(pci_dev); +} + +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { + .id_table = pci_ifpga_map, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, + .probe = ifpga_rawdev_pci_probe, + .remove = ifpga_rawdev_pci_remove, +}; + +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | uio_pci_generic | vfio-pci"); + +RTE_INIT(ifpga_rawdev_init_log); +static void +ifpga_rawdev_init_log(void) +{ + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); + if (ifpga_rawdev_logtype >= 0) + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +static int +ifpga_cfg_probe(struct rte_vdev_device *dev) +{ + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + int port; + char *name = NULL; + char dev_name[RTE_RAWDEV_NAME_MAX_LEN+8]; + + devargs = dev->device.devargs; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &ifpga_get_string_arg, &name) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, + &ifpga_get_integer32_arg, &port) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + memset(dev_name, 0, sizeof(dev_name)); + snprintf(dev_name, (RTE_RAWDEV_NAME_MAX_LEN+8), "%d|%s", + port, name); + + rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), + dev_name, + devargs->args); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +static int +ifpga_cfg_remove(struct rte_vdev_device *vdev) +{ + IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p", + vdev); + + return 0; +} + +static struct rte_vdev_driver ifpga_cfg_driver = { + .probe = ifpga_cfg_probe, + .remove = ifpga_cfg_remove, +}; + +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, + "bdf=<string> " + "port=<int> " + "afu_bts=<path>"); + diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h new file mode 100644 index 0000000..169dc1d --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_RAWDEV_H_ +#define _IFPGA_RAWDEV_H_ + +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) + +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") + +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) +#define IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) +#define IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) +#define IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) + +enum ifpga_rawdev_device_state { + IFPGA_IDLE, + IFPGA_READY, + IFPGA_ERROR +}; + +static inline struct opae_adapter * +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) +{ + return rawdev->dev_private; +} + +#endif /* _IFPGA_RAWDEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map new file mode 100644 index 0000000..9b9ab1a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map @@ -0,0 +1,4 @@ +DPDK_18.05 { + + local: *; +}; diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 929c3d8..d4c014a 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -232,6 +232,7 @@ endif # CONFIG_RTE_LIBRTE_EVENTDEV ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += -lrte_pmd_skeleton_rawdev +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += -lrte_ifpga_rawdev endif # CONFIG_RTE_LIBRTE_RAWDEV ifeq ($(CONFIG_RTE_LIBRTE_DPAA2_PMD),y) -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v5 3/3] Add Intel FPGA OPAE Share Code 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS Rosen Xu 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 1/3] Add Intel FPGA BUS Library Rosen Xu 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 2/3] Add Intel FPGA BUS Rawdev Driver Rosen Xu @ 2018-04-04 6:51 ` Rosen Xu 2018-04-04 11:59 ` Hemant Agrawal 2018-04-04 10:14 ` [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS Shreyansh Jain 3 siblings, 1 reply; 149+ messages in thread From: Rosen Xu @ 2018-04-04 6:51 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet, Xu, Yilun Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> Signed-off-by: Wu, Hao <hao.wu@intel.com> Signed-off-by: Xu, Yilun <yilun.xu@intel.com> --- drivers/raw/ifpga_rawdev/base/Makefile | 54 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 529 ++++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 73 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 84 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1688 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 851 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 38 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 341 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 191 +++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 761 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 328 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 430 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 742 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 399 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 154 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 435 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 192 +++ drivers/raw/ifpga_rawdev/base/opae_debug.c | 126 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 46 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 408 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 280 ++++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 172 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 306 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 115 ++ .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 104 ++ .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 72 + 26 files changed, 8919 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile new file mode 100644 index 0000000..9c0d64b --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -0,0 +1,54 @@ +# BSD LICENSE +# +# Copyright(c) 2017-2018 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +ifneq ($(CONFIG_RTE_LIBRTE_EAL),) +OSDEP := osdep_rte +else +OSDEP := osdep_raw +endif + +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev/base/$(OSDEP) + +SRCS-y += ifpga_api.c +SRCS-y += ifpga_enumerate.c +SRCS-y += ifpga_feature_dev.c +SRCS-y += ifpga_fme.c +SRCS-y += ifpga_fme_iperf.c +SRCS-y += ifpga_fme_dperf.c +SRCS-y += ifpga_fme_error.c +SRCS-y += ifpga_port.c +SRCS-y += ifpga_port_error.c +SRCS-y += ifpga_fme_pr.c +SRCS-y += opae_hw_api.c +SRCS-y += opae_ifpga_hw_api.c +SRCS-y += opae_debug.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 new file mode 100644 index 0000000..9ce4b60 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -0,0 +1,529 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_api.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +#include "opae_hw_api.h" + +/* Accelerator APIs */ +static int ifpga_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return fpga_get_afu_uuid(port, uuid); +} + +static int ifpga_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + struct fpga_uafu_irq_set irq_set; + + if (!br || !br->data) + return -EINVAL; + + if (start >= afu_info->num_irqs || start + count > afu_info->num_irqs) + return -EINVAL; + + port = br->data; + + irq_set.start = start; + irq_set.count = count; + irq_set.evtfds = evtfds; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_UINT, &irq_set); +} + +static int ifpga_acc_get_info(struct opae_accelerator *acc, + struct opae_acc_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -ENODEV; + + info->num_regions = afu_info->num_regions; + info->num_irqs = afu_info->num_irqs; + + return 0; +} + +static int ifpga_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -EINVAL; + + if (info->index >= afu_info->num_regions) + return -EINVAL; + + /* always one RW region only for AFU now */ + info->flags = ACC_REGION_READ | ACC_REGION_WRITE | ACC_REGION_MMIO; + info->len = afu_info->region[info->index].len; + + return 0; +} + +static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + switch (byte) { + case 8: + *(u64 *)data = opae_readq(region->addr + offset); + break; + case 4: + *(u32 *)data = opae_readl(region->addr + offset); + break; + case 2: + *(u16 *)data = opae_readw(region->addr + offset); + break; + case 1: + *(u8 *)data = opae_readb(region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ifpga_acc_write(struct opae_accelerator *acc, + unsigned int region_idx, u64 offset, + unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + /* normal mmio case */ + switch (byte) { + case 8: + opae_writeq(*(u64 *)data, region->addr + offset); + break; + case 4: + opae_writel(*(u32 *)data, region->addr + offset); + break; + case 2: + opae_writew(*(u16 *)data, region->addr + offset); + break; + case 1: + opae_writeb(*(u8 *)data, region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +struct opae_accelerator_ops ifpga_acc_ops = { + .read = ifpga_acc_read, + .write = ifpga_acc_write, + .set_irq = ifpga_acc_set_irq, + .get_info = ifpga_acc_get_info, + .get_region_info = ifpga_acc_get_region_info, + .get_uuid = ifpga_acc_get_uuid, +}; + +/* Bridge APIs */ + +static int ifpga_br_reset(struct opae_bridge *br) +{ + struct ifpga_port_hw *port = br->data; + + return fpga_port_reset(port); +} + +struct opae_bridge_ops ifpga_br_ops = { + .reset = ifpga_br_reset, +}; + +/* Manager APIs */ +static int ifpga_mgr_flash(struct opae_manager *mgr, int id, void *buf, + u32 size, u64 *status) +{ + struct ifpga_fme_hw *fme = mgr->data; + struct ifpga_hw *hw = fme->parent; + + return ifpga_pr(hw, id, buf, size, status); +} + +struct opae_manager_ops ifpga_mgr_ops = { + .flash = ifpga_mgr_flash, +}; + +/* Adapter APIs */ +static int ifpga_adapter_enumerate(struct opae_adapter *adapter) +{ + struct ifpga_hw *hw = malloc(sizeof(*hw)); + + if (hw) { + memset(hw, 0, sizeof(*hw)); + hw->pci_data = adapter->data; + hw->adapter = adapter; + if (ifpga_bus_enumerate(hw)) + goto error; + return ifpga_bus_init(hw); + } + +error: + return -ENOMEM; +} + +struct opae_adapter_ops ifpga_adapter_ops = { + .enumerate = ifpga_adapter_enumerate, +}; + +/** + * ifpga_enumerate - enumerate the Device Feature List + * @hw: pointer to the HW structure + * + * This function enumerate the Device Feature List to discover + * the FME and Port devices. The FME device and Port devices + * will fill into HW structure when enumerate done. + * + * @return + * - 0: Success, device enumated. + * - <0: Error code returned in enumeration. + **/ +int ifpga_enumerate(struct ifpga_hw *hw) +{ + return ifpga_bus_enumerate(hw); +} + +/** + * ifpga_reset_port - reset a port device + * @hw: pointer to the HW structure + * @port_id: port device id + * + * @return + * - 0: Success + * - <0: Failure to reset a port device. + **/ +int ifpga_reset_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return fpga_port_reset(&hw->port[port_id]); +} + +/** + * ifpga_get_afu_mmio_addr - get UAFU MMIO address + * @hw: pointer to the HW structure + * @port_id: port device id + * @mem_resource: afu mmio resource + * @num_resource: number of resource + * + * return 0 on success or error code + **/ +int ifpga_get_afu_mmio_info(struct ifpga_hw *hw, u32 port_id, + struct rte_mem_resource *mem_resource, + u32 *num_resource) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + mem_resource->addr = + hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + mem_resource->len = + hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + mem_resource->phys_addr = + hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].phys_addr; + + *num_resource = 1; + + return 0; +} + +/** + * ifpga_get_afu_uuid - get AFU uuid + * @hw: pointer to the HW structure + * @port_id: port device id + * @uuid: the AFU's uuid + * + * @return + * - 0: Success + * - <0: Failure to get uuid. + **/ +int ifpga_get_afu_uuid(struct ifpga_hw *hw, u32 port_id, struct uuid *uuid) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + if (!hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size) + return -ENODEV; + + return fpga_get_afu_uuid(&hw->port[port_id], uuid); +} + +/** + * ifpga_pr - do the partial reconfiguration for a given port device + * @hw: pointer to the HW structure + * @port_id: the port device id + * @buffer: the buffer of the bitstream + * @size: the size of the bitstream + * @status: hardware status including PR error code if return -EIO. + * + * @return + * - 0: Success, partial reconfiguration finished. + * - <0: Error code returned in partial reconfiguration. + **/ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return do_pr(hw, port_id, buffer, size, status); +} + +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_get_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_get_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set) +{ + if (!hw || !irq_set) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_irq(&hw->fme, feature_id, irq_set); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_irq(&hw->port[port_id], feature_id, irq_set); + } + + return -ENOENT; +} + +void ifpga_show_pr_error(u64 pr_error) +{ + int i; + + for (i = 0; i < PR_MAX_ERR_NUM; i++) { + if (pr_error & (1 << i)) + printf("PR Error: %s\n", pr_err_msg[i]); + } + + printf("PR Error: 0x%lx\n", pr_error); +} + +int ifpga_mmio64_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 *value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + *value = readq(addr + offset); + + return 0; +} + +int ifpga_mmio64_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + writeq(value, addr + offset); + + return 0; +} + +int ifpga_mmio32_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 *value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + *value = readl(addr + offset); + + return 0; +} + +int ifpga_mmio32_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 value) +{ + u8 *addr; + u32 size; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + addr = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].addr; + size = hw->port[port_id].sub_feature[PORT_FEATURE_ID_UAFU].size; + + if (offset > size) + return -EINVAL; + + writel(value, addr + offset); + + return 0; +} + +int ifpga_fme_hw_init(struct ifpga_hw *hw) +{ + return fme_hw_init(&hw->fme); +} + +void ifpga_fme_hw_uinit(struct ifpga_hw *hw) +{ + fme_hw_uinit(&hw->fme); +} + +void ifpga_port_hw_uinit(struct ifpga_hw *hw, int port_id) +{ + struct ifpga_port_hw *port; + + if (!is_valid_port_id(hw, port_id)) + return; + + port = &hw->port[port_id]; + + if (port->state == IFPGA_PORT_ATTACHED) + port_hw_uinit(port); +} + +int ifpga_port_hw_init(struct ifpga_hw *hw, int port_id) +{ + struct ifpga_port_hw *port; + + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + port = &hw->port[port_id]; + + if (port->state != IFPGA_PORT_ATTACHED) + return -EINVAL; + + return port_hw_init(port); +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.h b/drivers/raw/ifpga_rawdev/base/ifpga_api.h new file mode 100644 index 0000000..e762390 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.h @@ -0,0 +1,73 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_API_H_ +#define _IFPGA_API_H_ + +#include "opae_hw_api.h" +#include "ifpga_hw.h" + +extern struct opae_adapter_ops ifpga_adapter_ops; +extern struct opae_manager_ops ifpga_mgr_ops; +extern struct opae_bridge_ops ifpga_br_ops; +extern struct opae_accelerator_ops ifpga_acc_ops; + +/* common APIs */ +int ifpga_enumerate(struct ifpga_hw *hw); +int ifpga_fme_hw_init(struct ifpga_hw *hw); +void ifpga_fme_hw_uinit(struct ifpga_hw *hw); +int ifpga_port_hw_init(struct ifpga_hw *hw, int port_id); +void ifpga_port_hw_uinit(struct ifpga_hw *hw, int port_id); +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set); + +/* Port/AFU APIs */ +int ifpga_reset_port(struct ifpga_hw *hw, u32 port_id); +int ifpga_get_afu_mmio_info(struct ifpga_hw *hw, u32 port_id, + struct rte_mem_resource *mem_resource, + u32 *num_resource); +int ifpga_get_afu_uuid(struct ifpga_hw *hw, u32 port_id, struct uuid *uuid); + +int ifpga_mmio64_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 *value); +int ifpga_mmio64_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u64 value); +int ifpga_mmio32_read(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 *value); +int ifpga_mmio32_write(struct ifpga_hw *hw, u32 port_id, u64 offset, u32 value); + +/* FME APIs */ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); +void ifpga_show_pr_error(u64 pr_error); + +#endif /* _IFPGA_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_compat.h b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h new file mode 100644 index 0000000..6670630 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h @@ -0,0 +1,84 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_COMPAT_H_ +#define _IFPGA_COMPAT_H_ + +#include "opae_osdep.h" + +#undef container_of +#define container_of(ptr, type, member) ({ \ + typeof(((type *)0)->member)(*__mptr) = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) +#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE) + +#define readl(addr) opae_readl(addr) +#define readq(addr) opae_readq(addr) +#define writel(value, addr) opae_writel(value, addr) +#define writeq(value, addr) opae_writeq(value, addr) + +#define malloc(size) opae_malloc(size) +#define zmalloc(size) opae_zmalloc(size) +#define free(size) opae_free(size) + +/* + * Wait register's _field to be changed to the given value (_expect's _field) + * by polling with given interval and timeout. + */ +#define fpga_wait_register_field(_field, _expect, _reg_addr, _timeout, _invl)\ +({ \ + int wait = 0; \ + int ret = -ETIMEDOUT; \ + typeof(_expect) value; \ + for (; wait <= _timeout; wait += _invl) { \ + value.csr = readq(_reg_addr); \ + if (_expect._field == value._field) { \ + ret = 0; \ + break; \ + } \ + udelay(_invl); \ + } \ + ret; \ +}) + +#define __maybe_unused __attribute__((__unused__)) + +#define UNUSED(x) (void)(x) + +#endif /* _IFPGA_COMPAT_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h new file mode 100644 index 0000000..d0fabe7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -0,0 +1,1688 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_DEFINES_H_ +#define _IFPGA_DEFINES_H_ + +#include "ifpga_compat.h" + +#define MAX_FPGA_PORT_NUM 4 + +#define FME_FEATURE_HEADER "fme_hdr" +#define FME_FEATURE_THERMAL_MGMT "fme_thermal" +#define FME_FEATURE_POWER_MGMT "fme_power" +#define FME_FEATURE_GLOBAL_IPERF "fme_iperf" +#define FME_FEATURE_GLOBAL_ERR "fme_error" +#define FME_FEATURE_PR_MGMT "fme_pr" +#define FME_FEATURE_HSSI_ETH "fme_hssi" +#define FME_FEATURE_GLOBAL_DPERF "fme_dperf" +#define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" + +#define PORT_FEATURE_HEADER "port_hdr" +#define PORT_FEATURE_UAFU "port_uafu" +#define PORT_FEATURE_ERR "port_err" +#define PORT_FEATURE_UMSG "port_umsg" +#define PORT_FEATURE_PR "port_pr" +#define PORT_FEATURE_UINT "port_uint" +#define PORT_FEATURE_STP "port_stp" + +/* + * do not check the revision id as id may be dynamic under + * some cases, e.g, UAFU. + */ +#define SKIP_REVISION_CHECK 0xff + +#define FME_HEADER_REVISION 1 +#define FME_THERMAL_MGMT_REVISION 0 +#define FME_POWER_MGMT_REVISION 1 +#define FME_GLOBAL_IPERF_REVISION 1 +#define FME_GLOBAL_ERR_REVISION 1 +#define FME_PR_MGMT_REVISION 2 +#define FME_HSSI_ETH_REVISION 0 +#define FME_GLOBAL_DPERF_REVISION 0 +#define FME_QSPI_REVISION 0 + +#define PORT_HEADER_REVISION 0 +/* UAFU's header info depends on the downloaded GBS */ +#define PORT_UAFU_REVISION SKIP_REVISION_CHECK +#define PORT_ERR_REVISION 1 +#define PORT_UMSG_REVISION 0 +#define PORT_UINT_REVISION 0 +#define PORT_STP_REVISION 1 + +#define FEATURE_TYPE_AFU 0x1 +#define FEATURE_TYPE_BBB 0x2 +#define FEATURE_TYPE_PRIVATE 0x3 +#define FEATURE_TYPE_FIU 0x4 + +#define FEATURE_FIU_ID_FME 0x0 +#define FEATURE_FIU_ID_PORT 0x1 + +#define FEATURE_ID_HEADER 0x0 +#define FEATURE_ID_AFU 0xff + +enum fpga_id_type { + FME_ID, + PORT_ID, + 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, +}; + +/* + * All headers and structures must be byte-packed to match the spec. + */ +#pragma pack(1) + +struct feature_header { + union { + u64 csr; + struct { + u16 id:12; + u8 revision:4; + u32 next_header_offset:24; + u8 end_of_list:1; + u32 reserved:19; + u8 type:4; + }; + }; +}; + +struct feature_bbb_header { + struct uuid guid; +}; + +struct feature_afu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fiu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fme_capability { + union { + u64 csr; + struct { + u8 fabric_verid; /* Fabric version ID */ + u8 socket_id:1; /* Socket id */ + u8 rsvd1:3; /* Reserved */ + /* pci0 link available yes /no */ + u8 pci0_link_avile:1; + /* pci1 link available yes /no */ + u8 pci1_link_avile:1; + /* Coherent (QPI/UPI) link available yes /no */ + u8 qpi_link_avile:1; + u8 rsvd2:1; /* Reserved */ + /* IOMMU or VT-d supported yes/no */ + u8 iommu_support:1; + u8 num_ports:3; /* Number of ports */ + u8 sf_fab_ctl:1; /* Internal validation bit */ + u8 rsvd3:3; /* Reserved */ + /* + * Address width supported in bits + * BXT -0x26 , SKX -0x30 + */ + u8 address_width_bits:6; + u8 rsvd4:2; /* Reserved */ + /* Size of cache supported in kb */ + u16 cache_size:12; + u8 cache_assoc:4; /* Cache Associativity */ + u16 rsvd5:15; /* Reserved */ + u8 lock_bit:1; /* Lock bit */ + }; + }; +}; + +#define FME_AFU_ACCESS_PF 0 +#define FME_AFU_ACCESS_VF 1 + +struct feature_fme_port { + union { + u64 csr; + struct { + u32 port_offset:24; + u8 reserved1; + u8 port_bar:3; + u32 reserved2:20; + u8 afu_access_control:1; + u8 reserved3:4; + u8 port_implemented:1; + u8 reserved4:3; + }; + }; +}; + +struct feature_fme_fab_status { + union { + u64 csr; + struct { + u8 upilink_status:4; /* UPI Link Status */ + u8 rsvd1:4; /* Reserved */ + u8 pci0link_status:1; /* pci0 link status */ + u8 rsvd2:3; /* Reserved */ + u8 pci1link_status:1; /* pci1 link status */ + u64 rsvd3:51; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_base { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Base Address of memory range */ + u8 protected_base_addrss:4; + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_limit { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Limit Address of memory range */ + u8 protected_limit_addrss:4; + u16 rsvd2:11; /* Reserved */ + u8 enable:1; /* Enable GENPROTRANGE check */ + u32 rsvd3; /* Reserved */ + }; + }; +}; + +struct feature_fme_dxe_lock { + union { + u64 csr; + struct { + /* + * Determines write access to the DXE region CSRs + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_early_lock:1; + /* + * Determines write access to the HSSI CSR + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_late_lock:1; + u64 rsvd:62; + }; + }; +}; + +#define HSSI_ID_NO_HASSI 0 +#define HSSI_ID_PCIE_RP 1 +#define HSSI_ID_ETHERNET 2 + +struct feature_fme_bitstream_id { + union { + u64 csr; + struct { + u32 gitrepo_hash:32; /* GIT repository hash */ + /* + * HSSI configuration identifier: + * 0 - No HSSI + * 1 - PCIe-RP + * 2 - Ethernet + */ + u8 hssi_id:4; + u16 rsvd1:12; /* Reserved */ + /* Bitstream version patch number */ + u8 bs_verpatch:4; + /* Bitstream version minor number */ + u8 bs_verminor:4; + /* Bitstream version major number */ + u8 bs_vermajor:4; + /* Bitstream version debug number */ + u8 bs_verdebug:4; + }; + }; +}; + +struct feature_fme_bitstream_md { + union { + u64 csr; + struct { + /* Seed number userd for synthesis flow */ + u8 synth_seed:4; + /* Synthesis date(day number - 2 digits) */ + u8 synth_day:8; + /* Synthesis date(month number - 2 digits) */ + u8 synth_month:8; + /* Synthesis date(year number - 2 digits) */ + u8 synth_year:8; + u64 rsvd:36; /* Reserved */ + }; + }; +}; + +struct feature_fme_iommu_ctrl { + union { + u64 csr; + struct { + /* Disables IOMMU prefetcher for C0 channel */ + u8 prefetch_disableC0:1; + /* Disables IOMMU prefetcher for C1 channel */ + u8 prefetch_disableC1:1; + /* Disables IOMMU partial cache line writes */ + u8 prefetch_wrdisable:1; + u8 rsvd1:1; /* Reserved */ + /* + * Select counter and read value from register + * iommu_stat.dbg_counters + * 0 - Number of 4K page translation response + * 1 - Number of 2M page translation response + * 2 - Number of 1G page translation response + */ + u8 counter_sel:2; + u32 rsvd2:26; /* Reserved */ + /* Connected to IOMMU SIP Capabilities */ + u32 capecap_defeature; + }; + }; +}; + +struct feature_fme_iommu_stat { + union { + u64 csr; + struct { + /* Translation Enable bit from IOMMU SIP */ + u8 translation_enable:1; + /* Drain request in progress */ + u8 drain_req_inprog:1; + /* Invalidation current state */ + u8 inv_state:3; + /* C0 Response Buffer current state */ + u8 respbuffer_stateC0:3; + /* C1 Response Buffer current state */ + u8 respbuffer_stateC1:3; + /* Last request ID to IOMMU SIP */ + u8 last_reqID:4; + /* Last IOMMU SIP response ID value */ + u8 last_respID:4; + /* Last IOMMU SIP response status value */ + u8 last_respstatus:3; + /* C0 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC0:1; + /* C1 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC1:1; + /* C0 Request FIFO is not empty */ + u8 reqFIFO_notemptyC0:1; + /* C1 Request FIFO is not empty */ + u8 reqFIFO_notemptyC1:1; + /* C0 Response FIFO is not empty */ + u8 respFIFO_notemptyC0:1; + /* C1 Response FIFO is not empty */ + u8 respFIFO_notemptyC1:1; + /* C0 Response FIFO overflow detected */ + u8 respFIFO_overflowC0:1; + /* C1 Response FIFO overflow detected */ + u8 respFIFO_overflowC1:1; + /* C0 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC0:1; + /* C1 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC1:1; + /* Request FIFO overflow detected */ + u8 reqFIFO_overflow:1; + /* IOMMU memory read in progress */ + u8 memrd_inprog:1; + /* IOMMU memory write in progress */ + u8 memwr_inprog:1; + u8 rsvd1:1; /* Reserved */ + /* Value of counter selected by iommu_ctl.counter_sel */ + u16 dbg_counters:16; + u16 rsvd2:12; /* Reserved */ + }; + }; +}; + +struct feature_fme_pcie0_ctrl { + union { + u64 csr; + struct { + u64 vtd_bar_lock:1; /* Lock VT-D BAR register */ + u64 rsvd1:3; + u64 rciep:1; /* Configure PCIE0 as RCiEP */ + u64 rsvd2:59; + }; + }; +}; + +struct feature_fme_llpr_smrr_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR rule is valid or not */ + /* + * SMRR memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR2 rule is valid or not */ + /* + * SMRR2 memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_meseg_base { + union { + u64 csr; + struct { + /* A[45:19] of base address memory range */ + u64 me_base:27; + u64 rsvd:37; + }; + }; +}; + +struct feature_fme_llpr_meseg_limit { + union { + u64 csr; + struct { + /* A[45:19] of limit address memory range */ + u64 me_limit:27; + u64 rsvd1:4; + u64 enable:1; /* Enable LLPR MESEG rule */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 reserved; + u64 scratchpad; + struct feature_fme_capability capability; + struct feature_fme_port port[MAX_FPGA_PORT_NUM]; + struct feature_fme_fab_status fab_status; + struct feature_fme_bitstream_id bitstream_id; + struct feature_fme_bitstream_md bitstream_md; + struct feature_fme_genprotrange2_base genprotrange2_base; + struct feature_fme_genprotrange2_limit genprotrange2_limit; + struct feature_fme_dxe_lock dxe_lock; + struct feature_fme_iommu_ctrl iommu_ctrl; + struct feature_fme_iommu_stat iommu_stat; + struct feature_fme_pcie0_ctrl pcie0_control; + struct feature_fme_llpr_smrr_base smrr_base; + struct feature_fme_llpr_smrr_mask smrr_mask; + struct feature_fme_llpr_smrr2_base smrr2_base; + struct feature_fme_llpr_smrr2_mask smrr2_mask; + struct feature_fme_llpr_meseg_base meseg_base; + struct feature_fme_llpr_meseg_limit meseg_limit; +}; + +struct feature_port_capability { + union { + u64 csr; + struct { + u8 port_number:2; /* Port Number 0-3 */ + u8 rsvd1:6; /* Reserved */ + u16 mmio_size; /* User MMIO size in KB */ + u8 rsvd2; /* Reserved */ + u8 sp_intr_num:4; /* Supported interrupts num */ + u32 rsvd3:28; /* Reserved */ + }; + }; +}; + +struct feature_port_control { + union { + u64 csr; + struct { + u8 port_sftrst:1; /* Port Soft Reset */ + u8 rsvd1:1; /* Reserved */ + u8 latency_tolerance:1;/* '1' >= 40us, '0' < 40us */ + u8 rsvd2:1; /* Reserved */ + u8 port_sftrst_ack:1; /* HW ACK for Soft Reset */ + u64 rsvd3:59; /* Reserved */ + }; + }; +}; + +#define PORT_POWER_STATE_NORMAL 0 +#define PORT_POWER_STATE_AP1 1 +#define PORT_POWER_STATE_AP2 2 +#define PORT_POWER_STATE_AP6 6 + +struct feature_port_status { + union { + u64 csr; + struct { + u8 port_freeze:1; /* '1' - freezed '0' - normal */ + u8 rsvd1:7; /* Reserved */ + u8 power_state:4; /* Power State */ + u8 ap1_event:1; /* AP1 event was detected */ + u8 ap2_event:1; /* AP2 event was detected */ + u64 rsvd2:50; /* Reserved */ + }; + }; +}; + +/* Port Header Register Set */ +struct feature_port_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 port_mailbox; + u64 scratchpad; + struct feature_port_capability capability; + struct feature_port_control control; + struct feature_port_status status; + u64 rsvd2; + u64 user_clk_freq_cmd0; + u64 user_clk_freq_cmd1; + u64 user_clk_freq_sts0; + u64 user_clk_freq_sts1; +}; + +struct feature_fme_tmp_threshold { + union { + u64 csr; + struct { + u8 tmp_thshold1:7; /* temperature Threshold 1 */ + /* temperature Threshold 1 enable/disable */ + u8 tmp_thshold1_enable:1; + u8 tmp_thshold2:7; /* temperature Threshold 2 */ + /* temperature Threshold 2 enable /disable */ + u8 tmp_thshold2_enable:1; + u8 pro_hot_setpoint:7; /* Proc Hot set point */ + u8 rsvd4:1; /* Reserved */ + u8 therm_trip_thshold:7; /* Thermeal Trip Threshold */ + u8 rsvd3:1; /* Reserved */ + u8 thshold1_status:1; /* Threshold 1 Status */ + u8 thshold2_status:1; /* Threshold 2 Status */ + u8 rsvd5:1; /* Reserved */ + /* Thermeal Trip Threshold status */ + u8 therm_trip_thshold_status:1; + u8 rsvd6:4; /* Reserved */ + /* Validation mode- Force Proc Hot */ + u8 valmodeforce:1; + /* Validation mode - Therm trip Hot */ + u8 valmodetherm:1; + u8 rsvd2:2; /* Reserved */ + u8 thshold_policy:1; /* threshold policy */ + u32 rsvd:19; /* Reserved */ + }; + }; +}; + +/* Temperature Sensor Read values format 1 */ +struct feature_fme_temp_rdsensor_fmt1 { + union { + u64 csr; + struct { + /* Reads out FPGA temperature in celsius */ + u8 fpga_temp:7; + u8 rsvd0:1; /* Reserved */ + /* Temperature reading sequence number */ + u16 tmp_reading_seq_num; + /* Temperature reading is valid */ + u8 tmp_reading_valid:1; + u8 rsvd1:7; /* Reserved */ + u16 dbg_mode:10; /* Debug mode */ + u32 rsvd2:22; /* Reserved */ + }; + }; +}; + +/* Temperature sensor read values format 2 */ +struct feature_fme_temp_rdsensor_fmt2 { + u64 rsvd; /* Reserved */ +}; + +/* Temperature Threshold Capability Register */ +struct feature_fme_tmp_threshold_cap { + union { + u64 csr; + struct { + /* Temperature Threshold Unsupported */ + u8 tmp_thshold_disabled:1; + u64 rsvd:63; /* Reserved */ + }; + }; +}; + +/* FME THERNAL FEATURE */ +struct feature_fme_thermal { + struct feature_header header; + struct feature_fme_tmp_threshold threshold; + struct feature_fme_temp_rdsensor_fmt1 rdsensor_fm1; + struct feature_fme_temp_rdsensor_fmt2 rdsensor_fm2; + struct feature_fme_tmp_threshold_cap threshold_cap; +}; + +/* Power Status register */ +struct feature_fme_pm_status { + union { + u64 csr; + struct { + /* FPGA Power consumed, The format is to be defined */ + u32 pwr_consumed:18; + /* FPGA Latency Tolerance Reporting */ + u8 fpga_latency_report:1; + u64 rsvd:45; /* Reserved */ + }; + }; +}; + +/* AP Thresholds */ +struct feature_fme_pm_ap_threshold { + union { + u64 csr; + struct { + /* + * Number of clocks (5ns period) for assertion + * of FME_data + */ + u8 threshold1:7; + u8 rsvd1:1; + u8 threshold2:7; + u8 rsvd2:1; + u8 threshold1_status:1; + u8 threshold2_status:1; + u64 rsvd3:46; /* Reserved */ + }; + }; +}; + +/* Xeon Power Limit */ +struct feature_fme_pm_xeon_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FPGA Power Limit */ +struct feature_fme_pm_fpga_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FME POWER FEATURE */ +struct feature_fme_power { + struct feature_header header; + struct feature_fme_pm_status status; + struct feature_fme_pm_ap_threshold threshold; + struct feature_fme_pm_xeon_limit xeon_limit; + struct feature_fme_pm_fpga_limit fpga_limit; +}; + +#define CACHE_CHANNEL_RD 0 +#define CACHE_CHANNEL_WR 1 + +enum iperf_cache_events { + IPERF_CACHE_RD_HIT, + IPERF_CACHE_WR_HIT, + IPERF_CACHE_RD_MISS, + IPERF_CACHE_WR_MISS, + IPERF_CACHE_RSVD, /* reserved */ + IPERF_CACHE_HOLD_REQ, + IPERF_CACHE_DATA_WR_PORT_CONTEN, + IPERF_CACHE_TAG_WR_PORT_CONTEN, + IPERF_CACHE_TX_REQ_STALL, + IPERF_CACHE_RX_REQ_STALL, + IPERF_CACHE_EVICTIONS, +}; + +/* FPMON Cache Control */ +struct feature_fme_ifpmon_ch_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd1:7; /* Reserved */ + u8 freeze:1; /* Freeze if set to 1 */ + u8 rsvd2:7; /* Reserved */ + u8 cache_event:4; /* Select the cache event */ + u8 cci_chsel:1; /* Select the channel */ + u64 rsvd3:43; /* Reserved */ + }; + }; +}; + +/* FPMON Cache Counter */ +struct feature_fme_ifpmon_ch_ctr { + union { + u64 csr; + struct { + /* Cache Counter for even addresse */ + u64 cache_counter:48; + u16 rsvd:12; /* Reserved */ + /* Cache Event being reported */ + u8 event_code:4; + }; + }; +}; + +enum iperf_fab_events { + IPERF_FAB_PCIE0_RD, + IPERF_FAB_PCIE0_WR, + IPERF_FAB_PCIE1_RD, + IPERF_FAB_PCIE1_WR, + IPERF_FAB_UPI_RD, + IPERF_FAB_UPI_WR, + IPERF_FAB_MMIO_RD, + IPERF_FAB_MMIO_WR, +}; + +#define FAB_DISABLE_FILTER 0 +#define FAB_ENABLE_FILTER 1 + +/* FPMON FAB Control */ +struct feature_fme_ifpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_ifpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_ifpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +enum iperf_vtd_events { + IPERF_VTD_AFU_MEM_RD_TRANS, + IPERF_VTD_AFU_MEM_WR_TRANS, + IPERF_VTD_AFU_DEVTLB_RD_HIT, + IPERF_VTD_AFU_DEVTLB_WR_HIT, + IPERF_VTD_DEVTLB_4K_FILL, + IPERF_VTD_DEVTLB_2M_FILL, + IPERF_VTD_DEVTLB_1G_FILL, +}; + +/* VT-d control register */ +struct feature_fme_ifpmon_vtd_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d event counter */ +struct feature_fme_ifpmon_vtd_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +enum iperf_vtd_sip_events { + IPERF_VTD_SIP_IOTLB_4K_HIT, + IPERF_VTD_SIP_IOTLB_2M_HIT, + IPERF_VTD_SIP_IOTLB_1G_HIT, + IPERF_VTD_SIP_SLPWC_L3_HIT, + IPERF_VTD_SIP_SLPWC_L4_HIT, + IPERF_VTD_SIP_RCC_HIT, + IPERF_VTD_SIP_IOTLB_4K_MISS, + IPERF_VTD_SIP_IOTLB_2M_MISS, + IPERF_VTD_SIP_IOTLB_1G_MISS, + IPERF_VTD_SIP_SLPWC_L3_MISS, + IPERF_VTD_SIP_SLPWC_L4_MISS, + IPERF_VTD_SIP_RCC_MISS, +}; + +/* VT-d SIP control register */ +struct feature_fme_ifpmon_vtd_sip_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d SIP event counter */ +struct feature_fme_ifpmon_vtd_sip_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +/* FME IPERF FEATURE */ +struct feature_fme_iperf { + struct feature_header header; + struct feature_fme_ifpmon_ch_ctl ch_ctl; + struct feature_fme_ifpmon_ch_ctr ch_ctr0; + struct feature_fme_ifpmon_ch_ctr ch_ctr1; + struct feature_fme_ifpmon_fab_ctl fab_ctl; + struct feature_fme_ifpmon_fab_ctr fab_ctr; + struct feature_fme_ifpmon_clk_ctr clk; + struct feature_fme_ifpmon_vtd_ctl vtd_ctl; + struct feature_fme_ifpmon_vtd_ctr vtd_ctr; + struct feature_fme_ifpmon_vtd_sip_ctl vtd_sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr vtd_sip_ctr; +}; + +enum dperf_fab_events { + DPERF_FAB_PCIE0_RD, + DPERF_FAB_PCIE0_WR, + DPERF_FAB_MMIO_RD = 6, + DPERF_FAB_MMIO_WR, +}; + +/* FPMON FAB Control */ +struct feature_fme_dfpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_dfpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_dfpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +/* FME DPERF FEATURE */ +struct feature_fme_dperf { + struct feature_header header; + u64 rsvd[3]; + struct feature_fme_dfpmon_fab_ctl fab_ctl; + struct feature_fme_dfpmon_fab_ctr fab_ctr; + struct feature_fme_dfpmon_clk_ctr clk; +}; + +struct feature_fme_error0 { +#define FME_ERROR0_MASK 0xFFUL +#define FME_ERROR0_MASK_DEFAULT 0x40UL /* pcode workaround */ + union { + u64 csr; + struct { + u8 fabric_err:1; /* Fabric error */ + u8 fabfifo_overflow:1; /* Fabric fifo overflow */ + u8 kticdc_parity_err:2;/* KTI CDC Parity Error */ + u8 iommu_parity_err:1; /* IOMMU Parity error */ + /* AFU PF/VF access mismatch detected */ + u8 afu_acc_mode_err:1; + u8 mbp_err:1; /* Indicates an MBP event */ + /* PCIE0 CDC Parity Error */ + u8 pcie0cdc_parity_err:5; + /* PCIE1 CDC Parity Error */ + u8 pcie1cdc_parity_err:5; + /* CVL CDC Parity Error */ + u8 cvlcdc_parity_err:3; + u64 rsvd:44; /* Reserved */ + }; + }; +}; + +/* PCIe0 Error Status register */ +struct feature_fme_pcie0_error { +#define FME_PCIE0_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:52; /* Reserved */ + u8 vfnumb_err:1; /* Number of error VF */ + u8 funct_type_err:1; /* Virtual (1) or Physical */ + }; + }; +}; + +/* PCIe1 Error Status register */ +struct feature_fme_pcie1_error { +#define FME_PCIE1_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:54; /* Reserved */ + }; + }; +}; + +/* FME First Error register */ +struct feature_fme_first_error { +#define FME_FIRST_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered first + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered first + */ + u8 errReg_id:4; + }; + }; +}; + +/* FME Next Error register */ +struct feature_fme_next_error { +#define FME_NEXT_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered second + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered second + */ + u8 errReg_id:4; + }; + }; +}; + +/* RAS Non Fatal Error Status register */ +struct feature_fme_ras_nonfaterror { + union { + u64 csr; + struct { + /* thremal threshold AP1 */ + u8 temp_thresh_ap1:1; + /* thremal threshold AP2 */ + u8 temp_thresh_ap2:1; + u8 pcie_error:1; /* pcie Error */ + u8 portfatal_error:1; /* port fatal error */ + u8 proc_hot:1; /* Indicates a ProcHot event */ + /* Indicates an AFU PF/VF access mismatch */ + u8 afu_acc_mode_err:1; + /* Injected nonfata Error */ + u8 injected_nonfata_err:1; + u8 rsvd1:2; + /* Temperature threshold triggered AP6*/ + u8 temp_thresh_AP6:1; + /* Power threshold triggered AP1 */ + u8 power_thresh_AP1:1; + /* Power threshold triggered AP2 */ + u8 power_thresh_AP2:1; + /* Indicates a MBP event */ + u8 mbp_err:1; + u64 rsvd2:51; /* Reserved */ + }; + }; +}; + +/* RAS Catastrophic Fatal Error Status register */ +struct feature_fme_ras_catfaterror { + union { + u64 csr; + struct { + /* KTI Link layer error detected */ + u8 ktilink_fatal_err:1; + /* tag-n-cache error detected */ + u8 tagcch_fatal_err:1; + /* CCI error detected */ + u8 cci_fatal_err:1; + /* KTI Protocol error detected */ + u8 ktiprpto_fatal_err:1; + /* Fatal DRAM error detected */ + u8 dram_fatal_err:1; + /* IOMMU detected */ + u8 iommu_fatal_err:1; + /* Fabric Fatal Error */ + u8 fabric_fatal_err:1; + /* PCIe possion Error */ + u8 pcie_poison_err:1; + /* Injected fatal Error */ + u8 inject_fata_err:1; + /* Catastrophic CRC Error */ + u8 crc_catast_err:1; + /* Catastrophic Thermal Error */ + u8 therm_catast_err:1; + /* Injected Catastrophic Error */ + u8 injected_catast_err:1; + u64 rsvd:52; + }; + }; +}; + +/* RAS Error injection register */ +struct feature_fme_ras_error_inj { +#define FME_RAS_ERROR_INJ_MASK 0x7UL + union { + u64 csr; + struct { + u8 catast_error:1; /* Catastrophic error flag */ + u8 fatal_error:1; /* Fatal error flag */ + u8 nonfatal_error:1; /* NonFatal error flag */ + u64 rsvd:61; /* Reserved */ + }; + }; +}; + +/* FME error capabilities */ +struct feature_fme_error_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* FME ERR FEATURE */ +struct feature_fme_err { + struct feature_header header; + struct feature_fme_error0 fme_err_mask; + struct feature_fme_error0 fme_err; + struct feature_fme_pcie0_error pcie0_err_mask; + struct feature_fme_pcie0_error pcie0_err; + struct feature_fme_pcie1_error pcie1_err_mask; + struct feature_fme_pcie1_error pcie1_err; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + struct feature_fme_ras_nonfaterror ras_nonfat_mask; + struct feature_fme_ras_nonfaterror ras_nonfaterr; + struct feature_fme_ras_catfaterror ras_catfat_mask; + struct feature_fme_ras_catfaterror ras_catfaterr; + struct feature_fme_ras_error_inj ras_error_inj; + struct feature_fme_error_capability fme_err_capability; +}; + +/* FME Partial Reconfiguration Control */ +struct feature_fme_pr_ctl { + union { + u64 csr; + struct { + u8 pr_reset:1; /* Reset PR Engine */ + u8 rsvd3:3; /* Reserved */ + u8 pr_reset_ack:1; /* Reset PR Engine Ack */ + u8 rsvd4:3; /* Reserved */ + u8 pr_regionid:2; /* PR Region ID */ + u8 rsvd1:2; /* Reserved */ + u8 pr_start_req:1; /* PR Start Request */ + u8 pr_push_complete:1; /* PR Data push complete */ + u8 pr_kind:1; /* PR Data push complete */ + u32 rsvd:17; /* Reserved */ + u32 config_data; /* Config data TBD */ + }; + }; +}; + +/* FME Partial Reconfiguration Status */ +struct feature_fme_pr_status { + union { + u64 csr; + struct { + u16 pr_credit:9; /* PR Credits */ + u8 rsvd2:7; /* Reserved */ + u8 pr_status:1; /* PR status */ + u8 rsvd:3; /* Reserved */ + /* Altra PR Controller Block status */ + u8 pr_controller_status:3; + u8 rsvd1:1; /* Reserved */ + u8 pr_host_status:4; /* PR Host status */ + u8 rsvd3:4; /* Reserved */ + /* Security Block Status fields (TBD) */ + u32 security_bstatus; + }; + }; +}; + +/* FME Partial Reconfiguration Data */ +struct feature_fme_pr_data { + union { + u64 csr; /* PR data from the raw-binary file */ + struct { + /* PR data from the raw-binary file */ + u32 pr_data_raw; + u32 rsvd; + }; + }; +}; + +/* FME PR Public Key */ +struct feature_fme_pr_key { + u64 key; /* FME PR Public Hash */ +}; + +/* FME PR FEATURE */ +struct feature_fme_pr { + struct feature_header header; + /*Partial Reconfiguration control */ + struct feature_fme_pr_ctl ccip_fme_pr_control; + + /* Partial Reconfiguration Status */ + struct feature_fme_pr_status ccip_fme_pr_status; + + /* Partial Reconfiguration data */ + struct feature_fme_pr_data ccip_fme_pr_data; + + /* Partial Reconfiguration data */ + u64 ccip_fme_pr_err; + + u64 rsvd1[3]; + + /* Partial Reconfiguration data registers */ + u64 fme_pr_data1; + u64 fme_pr_data2; + u64 fme_pr_data3; + u64 fme_pr_data4; + u64 fme_pr_data5; + u64 fme_pr_data6; + u64 fme_pr_data7; + u64 fme_pr_data8; + + u64 rsvd2[5]; + + /* PR Interface ID */ + u64 fme_pr_intfc_id_l; + u64 fme_pr_intfc_id_h; + + /* MSIX filed to be Added */ +}; + +/* FME HSSI Control */ +struct feature_fme_hssi_eth_ctrl { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u16 address:16; /* HSSI address */ + /* + * HSSI comamnd + * 0x0 - No request + * 0x08 - SW register RD request + * 0x10 - SW register WR request + * 0x40 - Auxiliar bus RD request + * 0x80 - Auxiliar bus WR request + */ + u16 cmd:16; + }; + }; +}; + +/* FME HSSI Status */ +struct feature_fme_hssi_eth_stat { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u8 acknowledge:1; /* HSSI acknowledge */ + u8 spare:1; /* HSSI spare */ + u32 rsvd:30; /* Reserved */ + }; + }; +}; + +/* FME HSSI FEATURE */ +struct feature_fme_hssi { + struct feature_header header; + struct feature_fme_hssi_eth_ctrl hssi_control; + struct feature_fme_hssi_eth_stat hssi_status; +}; + +#define PORT_ERR_MASK 0xfff0703ff001f +struct feature_port_err_key { + union { + u64 csr; + struct { + /* Tx Channel0: Overflow */ + u8 tx_ch0_overflow:1; + /* Tx Channel0: Invalid request encoding */ + u8 tx_ch0_invaldreq :1; + /* Tx Channel0: Request with cl_len=3 not supported */ + u8 tx_ch0_cl_len3:1; + /* Tx Channel0: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch0_cl_len2:1; + /* Tx Channel0: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch0_cl_len4:1; + + u16 rsvd1:4; /* Reserved */ + + /* AFU MMIO RD received while PORT is in reset */ + u8 mmio_rd_whilerst:1; + /* AFU MMIO WR received while PORT is in reset */ + u8 mmio_wr_whilerst:1; + + u16 rsvd2:5; /* Reserved */ + + /* Tx Channel1: Overflow */ + u8 tx_ch1_overflow:1; + /* Tx Channel1: Invalid request encoding */ + u8 tx_ch1_invaldreq:1; + /* Tx Channel1: Request with cl_len=3 not supported */ + u8 tx_ch1_cl_len3:1; + /* Tx Channel1: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch1_cl_len2:1; + /* Tx Channel1: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch1_cl_len4:1; + + /* Tx Channel1: Insufficient data payload */ + u8 tx_ch1_insuff_data:1; + /* Tx Channel1: Data payload overrun */ + u8 tx_ch1_data_overrun:1; + /* Tx Channel1 : Incorrect address */ + u8 tx_ch1_incorr_addr:1; + /* Tx Channel1 : NON-Zero SOP Detected */ + u8 tx_ch1_nzsop:1; + /* Tx Channel1 : Illegal VC_SEL, atomic request VLO */ + u8 tx_ch1_illegal_vcsel:1; + + u8 rsvd3:6; /* Reserved */ + + /* MMIO Read Timeout in AFU */ + u8 mmioread_timeout:1; + + /* Tx Channel2: FIFO Overflow */ + u8 tx_ch2_fifo_overflow:1; + + /* MMIO read is not matching pending request */ + u8 unexp_mmio_resp:1; + + u8 rsvd4:5; /* Reserved */ + + /* Number of pending Requests: counter overflow */ + u8 tx_req_counter_overflow:1; + /* Req with Address violating SMM Range */ + u8 llpr_smrr_err:1; + /* Req with Address violating second SMM Range */ + u8 llpr_smrr2_err:1; + /* Req with Address violating ME Stolen message */ + u8 llpr_mesg_err:1; + /* Req with Address violating Generic Protected Range */ + u8 genprot_range_err:1; + /* Req with Address violating Legacy Range low */ + u8 legrange_low_err:1; + /* Req with Address violating Legacy Range High */ + u8 legrange_high_err:1; + /* Req with Address violating VGA memory range */ + u8 vgmem_range_err:1; + u8 page_fault_err:1; /* Page fault */ + u8 pmr_err:1; /* PMR Error */ + u8 ap6_event:1; /* AP6 event */ + /* VF FLR detected on Port with PF access control */ + u8 vfflr_access_err:1; + u16 rsvd5:12; /* Reserved */ + }; + }; +}; + +/* Port first error register, not contain all error bits in error register. */ +struct feature_port_first_err_key { + union { + u64 csr; + struct { + u8 tx_ch0_overflow:1; + u8 tx_ch0_invaldreq :1; + u8 tx_ch0_cl_len3:1; + u8 tx_ch0_cl_len2:1; + u8 tx_ch0_cl_len4:1; + u8 rsvd1:4; /* Reserved */ + u8 mmio_rd_whilerst:1; + u8 mmio_wr_whilerst:1; + u8 rsvd2:5; /* Reserved */ + u8 tx_ch1_overflow:1; + u8 tx_ch1_invaldreq:1; + u8 tx_ch1_cl_len3:1; + u8 tx_ch1_cl_len2:1; + u8 tx_ch1_cl_len4:1; + u8 tx_ch1_insuff_data:1; + u8 tx_ch1_data_overrun:1; + u8 tx_ch1_incorr_addr:1; + u8 tx_ch1_nzsop:1; + u8 tx_ch1_illegal_vcsel:1; + u8 rsvd3:6; /* Reserved */ + u8 mmioread_timeout:1; + u8 tx_ch2_fifo_overflow:1; + u8 rsvd4:6; /* Reserved */ + u8 tx_req_counter_overflow:1; + u32 rsvd5:23; /* Reserved */ + }; + }; +}; + +/* Port malformed Req0 */ +struct feature_port_malformed_req0 { + u64 header_lsb; +}; + +/* Port malformed Req1 */ +struct feature_port_malformed_req1 { + u64 header_msb; +}; + +/* Port debug register */ +struct feature_port_debug { + u64 port_debug; +}; + +/* Port error capabilities */ +struct feature_port_err_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE ERROR */ +struct feature_port_error { + struct feature_header header; + struct feature_port_err_key error_mask; + struct feature_port_err_key port_error; + struct feature_port_first_err_key port_first_error; + struct feature_port_malformed_req0 malreq0; + struct feature_port_malformed_req1 malreq1; + struct feature_port_debug port_debug; + struct feature_port_err_capability error_capability; +}; + +/* Port UMSG Capability */ +struct feature_port_umsg_cap { + union { + u64 csr; + struct { + /* Number of umsg allocated to this port */ + u8 umsg_allocated; + /* Enable / Disable UMsg engine for this port */ + u8 umsg_enable:1; + /* Usmg initialization status */ + u8 umsg_init_complete:1; + /* IOMMU can not translate the umsg base address */ + u8 umsg_trans_error:1; + u64 rsvd:53; /* Reserved */ + }; + }; +}; + +/* Port UMSG base address */ +struct feature_port_umsg_baseaddr { + union { + u64 csr; + struct { + u64 base_addr:48; /* 48 bit physical address */ + u16 rsvd; /* Reserved */ + }; + }; +}; + +struct feature_port_umsg_mode { + union { + u64 csr; + struct { + u32 umsg_hint_enable; /* UMSG hint enable/disable */ + u32 rsvd; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE UMSG */ +struct feature_port_umsg { + struct feature_header header; + struct feature_port_umsg_cap capability; + struct feature_port_umsg_baseaddr baseaddr; + struct feature_port_umsg_mode mode; +}; + +#define UMSG_EN_POLL_INVL 10 /* us */ +#define UMSG_EN_POLL_TIMEOUT 1000 /* us */ + +/* Port UINT Capability */ +struct feature_port_uint_cap { + union { + u64 csr; + struct { + u16 intr_num:12; /* Supported interrupts num */ + /* First MSI-X vector table entry number */ + u16 first_vec_num:12; + u64 rsvd:40; + }; + }; +}; + +/* PORT FEATURE UINT */ +struct feature_port_uint { + struct feature_header header; + struct feature_port_uint_cap capability; +}; + +/* STP region supports mmap operation, so use page aligned size. */ +#define PORT_FEATURE_STP_REGION_SIZE PAGE_ALIGN(sizeof(struct feature_port_stp)) + +/* Port STP status register (for debug only)*/ +struct feature_port_stp_status { + union { + u64 csr; + struct { + /* SLD Hub end-point read/write timeout */ + u8 sld_ep_timeout:1; + /* Remote STP in reset/disable */ + u8 rstp_disabled:1; + u8 unsupported_read:1; + /* MMIO timeout detected and faked with a response */ + u8 mmio_timeout:1; + u8 txfifo_count:4; + u8 rxfifo_count:4; + u8 txfifo_overflow:1; + u8 txfifo_underflow:1; + u8 rxfifo_overflow:1; + u8 rxfifo_underflow:1; + /* Number of MMIO write requests */ + u16 write_requests; + /* Number of MMIO read requests */ + u16 read_requests; + /* Number of MMIO read responses */ + u16 read_responses; + }; + }; +}; + +/* + * PORT FEATURE STP + * Most registers in STP region are not touched by driver, but mmapped to user + * space. So they are not defined in below data structure, as its actual size + * is 0x18c per spec. + */ +struct feature_port_stp { + struct feature_header header; + struct feature_port_stp_status stp_status; +}; + +/** + * enum fpga_pr_states - fpga PR states + * @FPGA_PR_STATE_UNKNOWN: can't determine state + * @FPGA_PR_STATE_WRITE_INIT: preparing FPGA for programming + * @FPGA_PR_STATE_WRITE_INIT_ERR: Error during WRITE_INIT stage + * @FPGA_PR_STATE_WRITE: writing image to FPGA + * @FPGA_PR_STATE_WRITE_ERR: Error while writing FPGA + * @FPGA_PR_STATE_WRITE_COMPLETE: Doing post programming steps + * @FPGA_PR_STATE_WRITE_COMPLETE_ERR: Error during WRITE_COMPLETE + * @FPGA_PR_STATE_OPERATING: FPGA PR done + */ +enum fpga_pr_states { + /* canot determine state states */ + FPGA_PR_STATE_UNKNOWN, + + /* write sequence: init, write, complete */ + FPGA_PR_STATE_WRITE_INIT, + FPGA_PR_STATE_WRITE_INIT_ERR, + FPGA_PR_STATE_WRITE, + FPGA_PR_STATE_WRITE_ERR, + FPGA_PR_STATE_WRITE_COMPLETE, + FPGA_PR_STATE_WRITE_COMPLETE_ERR, + + /* FPGA PR done */ + FPGA_PR_STATE_DONE, +}; + +/* + * FPGA Manager flags + * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported + */ +#define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + +/** + * struct fpga_pr_info - specific information to a FPGA PR + * @flags: boolean flags as defined above + * @pr_err: PR error code + * @state: fpga manager state + * @port_id: port id + */ +struct fpga_pr_info { + u32 flags; + u64 pr_err; + enum fpga_pr_states state; + int port_id; +}; + +#define DEFINE_FPGA_PR_ERR_MSG(_name_) \ +static const char * const _name_[] = { \ + "PR operation error detected", \ + "PR CRC error detected", \ + "PR incompatiable bitstream error detected", \ + "PR IP protocol error detected", \ + "PR FIFO overflow error detected", \ + "PR timeout error detected", \ + "PR secure load error detected", \ +} + +#define RST_POLL_INVL 10 /* us */ +#define RST_POLL_TIMEOUT 1000 /* us */ + +#define PR_WAIT_TIMEOUT 15000000 + +#define PR_HOST_STATUS_IDLE 0 +#define PR_MAX_ERR_NUM 7 + +DEFINE_FPGA_PR_ERR_MSG(pr_err_msg); + +/* + * green bitstream header must be byte-packed to match the + * real file format. + */ +struct bts_header { + u64 guid_h; + u64 guid_l; + u32 metadata_len; +}; + +#define GBS_GUID_H 0x414750466e6f6558 +#define GBS_GUID_L 0x31303076534247b7 +#define is_valid_bts(bts_hdr) \ + (((bts_hdr)->guid_h == GBS_GUID_H) && \ + ((bts_hdr)->guid_l == GBS_GUID_L)) + +#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 new file mode 100644 index 0000000..b7e73d8 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -0,0 +1,851 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "opae_hw_api.h" +#include "ifpga_api.h" + +#include "ifpga_hw.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +struct build_feature_devs_info { + struct opae_adapter_data_pci *pci_data; + + struct ifpga_afu_info *acc_info; + + void *fiu; + enum fpga_id_type current_type; + int current_port_id; + + void *ioaddr; + void *ioend; + uint64_t phys_addr; + int current_bar; + + void *pfme_hdr; + + struct ifpga_hw *hw; +}; + +struct feature_info { + const char *name; + uint32_t resource_size; + int feature_index; + int revision_id; + unsigned int vec_start; + unsigned int vec_cnt; + + struct feature_ops *ops; +}; + +/* 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, + } +}; + +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 = &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 = &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 = &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 = &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 + }, +}; + +static u64 feature_id(void __iomem *start) +{ + struct feature_header header; + + header.csr = readq(start); + + switch (header.type) { + case FEATURE_TYPE_FIU: + return FEATURE_ID_HEADER; + case FEATURE_TYPE_PRIVATE: + return header.id; + case FEATURE_TYPE_AFU: + return FEATURE_ID_AFU; + } + + WARN_ON(1); + return 0; +} + +static int +build_info_add_sub_feature(struct build_feature_devs_info *binfo, + struct feature_info *finfo, void __iomem *start) +{ + 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; + } + + 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->phys_addr = binfo->phys_addr + + ((u8 *)start - (u8 *)binfo->ioaddr); + + if (vec_cnt) { + if (vec_start + vec_cnt <= vec_start) + return -EINVAL; + + ctx = zmalloc(sizeof(*ctx) * vec_cnt); + if (!ctx) + return -ENOMEM; + + for (i = 0; i < vec_cnt; i++) { + ctx[i].eventfd = -1; + ctx[i].idx = vec_start + i; + } + } + + feature->ctx = ctx; + feature->ctx_num = vec_cnt; + feature->vfio_dev_fd = binfo->pci_data->vfio_dev_fd; + + return ret; +} + +static int +create_feature_instance(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + struct feature_header *hdr = start; + + if (((u8 *)binfo->ioend - (u8 *)start) < finfo->resource_size) + return -EINVAL; + + 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); +} + +/* + * UAFU GUID is dynamic as it can be changed after FME downloads different + * Green Bitstream to the port, so we treat the unknown GUIDs which are + * attached on port's feature list as UAFU. + */ +static bool feature_is_UAFU(struct build_feature_devs_info *binfo) +{ + if (binfo->current_type != PORT_ID) + return false; + + return true; +} + +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; + struct ifpga_afu_info *info; + void *start = (void *)hdr; + int ret; + + 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; + } + + if (ret) + return ret; + + /* FIXME: need to figure out a better name */ + info = 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->num_regions = 1; + + binfo->acc_info = info; + + return ret; +} + +static int parse_feature_afus(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + int ret; + struct feature_afu_header *afu_hdr, header; + u8 __iomem *start; + u8 __iomem *end = binfo->ioend; + + start = (u8 __iomem *)hdr; + for (; start < end; start += header.next_afu) { + if (end - start < + (unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr))) + return -EINVAL; + + hdr = (struct feature_header *)start; + afu_hdr = (struct feature_afu_header *)(hdr + 1); + header.csr = readq(&afu_hdr->csr); + + if (feature_is_UAFU(binfo)) { + ret = parse_feature_port_uafu(binfo, hdr); + if (ret) + return ret; + } + + if (!header.next_afu) + break; + } + + return 0; +} + +/* create and register proper private data */ +static int build_info_commit_dev(struct build_feature_devs_info *binfo) +{ + struct ifpga_afu_info *info = binfo->acc_info; + struct ifpga_hw *hw = binfo->hw; + struct opae_manager *mgr; + struct opae_bridge *br; + struct opae_accelerator *acc; + + if (!binfo->fiu) + return 0; + + if (binfo->current_type == PORT_ID) { + /* return error if no valid acc info data structure */ + if (!info) + return -EFAULT; + + br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops, + binfo->fiu); + if (!br) + return -ENOMEM; + + br->id = binfo->current_port_id; + + /* update irq info */ + info->num_irqs = port_features[PORT_FEATURE_ID_UINT].vec_cnt; + + acc = opae_accelerator_alloc(hw->adapter->name, + &ifpga_acc_ops, info); + if (!acc) { + opae_bridge_free(br); + return -ENOMEM; + } + + acc->br = br; + acc->index = br->id; + + opae_adapter_add_acc(hw->adapter, acc); + + } else if (binfo->current_type == FME_ID) { + mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops, + binfo->fiu); + if (!mgr) + return -ENOMEM; + + mgr->adapter = hw->adapter; + hw->adapter->mgr = mgr; + } + + binfo->fiu = NULL; + + return 0; +} + +static int +build_info_create_dev(struct build_feature_devs_info *binfo, + enum fpga_id_type type, unsigned int index) +{ + int ret; + + ret = build_info_commit_dev(binfo); + if (ret) + return ret; + + binfo->current_type = type; + + if (type == FME_ID) { + binfo->fiu = &binfo->hw->fme; + } else if (type == PORT_ID) { + binfo->fiu = &binfo->hw->port[index]; + binfo->current_port_id = index; + } + + return 0; +} + +static int parse_feature_fme(struct build_feature_devs_info *binfo, + struct feature_header *start) +{ + struct ifpga_hw *hw = binfo->hw; + struct ifpga_fme_hw *fme = &hw->fme; + int ret; + + ret = build_info_create_dev(binfo, FME_ID, 0); + if (ret) + return ret; + + /* Update FME states */ + fme->state = IFPGA_FME_IMPLEMENTED; + fme->parent = hw; + spinlock_init(&fme->lock); + + return create_feature_instance(binfo, start, + &fme_features[FME_FEATURE_ID_HEADER]); +} + +static int parse_feature_port(struct build_feature_devs_info *binfo, + void __iomem *start) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + struct ifpga_hw *hw = binfo->hw; + struct ifpga_port_hw *port; + unsigned int port_id; + int ret; + + /* Get current port's id */ + port_hdr = (struct feature_port_header *)start; + capability.csr = readq(&port_hdr->capability); + port_id = capability.port_number; + + ret = build_info_create_dev(binfo, PORT_ID, port_id); + if (ret) + return ret; + + /*found a Port device*/ + port = &hw->port[port_id]; + port->port_id = binfo->current_port_id; + port->parent = hw; + port->state = IFPGA_PORT_ATTACHED; + spinlock_init(&port->lock); + + return create_feature_instance(binfo, start, + &port_features[PORT_FEATURE_ID_HEADER]); +} + +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); +} + +static int parse_feature_fiu(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + struct feature_fiu_header *fiu_hdr, fiu_header; + u8 __iomem *start = (u8 __iomem *)hdr; + int ret; + + header.csr = readq(hdr); + + switch (header.id) { + case FEATURE_FIU_ID_FME: + ret = parse_feature_fme(binfo, hdr); + binfo->pfme_hdr = hdr; + if (ret) + return ret; + break; + case FEATURE_FIU_ID_PORT: + ret = parse_feature_port(binfo, hdr); + enable_port_uafu(binfo, hdr); + if (ret) + return ret; + + /* Check Port FIU's next_afu pointer to User AFU DFH */ + fiu_hdr = (struct feature_fiu_header *)(hdr + 1); + fiu_header.csr = readq(&fiu_hdr->csr); + + if (fiu_header.next_afu) { + start += fiu_header.next_afu; + ret = parse_feature_afus(binfo, + (struct feature_header *)start); + if (ret) + return ret; + } else { + dev_info(binfo, "No AFUs detected on Port\n"); + } + + break; + default: + dev_info(binfo, "FIU TYPE %d is not supported yet.\n", + header.id); + } + + return 0; +} + +static void parse_feature_irqs(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + finfo->vec_start = 0; + finfo->vec_cnt = 0; + + UNUSED(binfo); + + if (!strcmp(finfo->name, PORT_FEATURE_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; + } else { + dev_debug(binfo, "UAFU doesn't support interrupt\n"); + } + } else if (!strcmp(finfo->name, PORT_FEATURE_ERR)) { + 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; + } else { + dev_debug(&binfo, "Port error doesn't support interrupt\n"); + } + + } else if (!strcmp(finfo->name, FME_FEATURE_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; + } else { + dev_debug(&binfo, "FME error doesn't support interrupt\n"); + } + } +} + +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; + } + + parse_feature_irqs(binfo, hdr, &fme_features[header.id]); + + return create_feature_instance(binfo, hdr, &fme_features[header.id]); +} + +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; + + 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]); + + return create_feature_instance(binfo, hdr, &port_features[id]); +} + +static int parse_feature_private(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + + header.csr = readq(hdr); + + switch (binfo->current_type) { + case FME_ID: + return parse_feature_fme_private(binfo, hdr); + case PORT_ID: + return parse_feature_port_private(binfo, hdr); + default: + dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n", + header.id, binfo->current_type); + } + return 0; +} + +static int parse_feature(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + int ret = 0; + + header.csr = readq(hdr); + + switch (header.type) { + case FEATURE_TYPE_AFU: + ret = parse_feature_afus(binfo, hdr); + break; + case FEATURE_TYPE_PRIVATE: + ret = parse_feature_private(binfo, hdr); + break; + case FEATURE_TYPE_FIU: + ret = parse_feature_fiu(binfo, hdr); + break; + default: + dev_err(binfo, "Feature Type %x is not supported.\n", + hdr->type); + }; + + return ret; +} + +static int +parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start) +{ + struct feature_header *hdr, header; + u8 __iomem *end = (u8 __iomem *)binfo->ioend; + int ret = 0; + + for (; start < end; start += header.next_header_offset) { + if (end - start < (unsigned int)sizeof(*hdr)) { + dev_err(binfo, "The region is too small to contain a feature.\n"); + ret = -EINVAL; + break; + } + + hdr = (struct feature_header *)start; + ret = parse_feature(binfo, hdr); + if (ret) + return ret; + + header.csr = readq(hdr); + if (!header.next_header_offset) + break; + } + + return build_info_commit_dev(binfo); +} + +/* switch the memory mapping to BAR# @bar */ +static int parse_switch_to(struct build_feature_devs_info *binfo, int bar) +{ + struct opae_adapter_data_pci *pci_data = binfo->pci_data; + + if (!pci_data->region[bar].addr) + return -ENOMEM; + + binfo->ioaddr = pci_data->region[bar].addr; + binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len; + binfo->phys_addr = pci_data->region[bar].phys_addr; + binfo->current_bar = bar; + + return 0; +} + +static int parse_ports_from_fme(struct build_feature_devs_info *binfo) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_port port; + int i = 0, ret = 0; + + if (!binfo->pfme_hdr) { + dev_info(binfo, "VF is detected.\n"); + return ret; + } + + fme_hdr = binfo->pfme_hdr; + + do { + port.csr = readq(&fme_hdr->port[i]); + if (!port.port_implemented) + break; + + /* skip port which only could be accessed via VF */ + if (port.afu_access_control == FME_AFU_ACCESS_VF) + continue; + + ret = parse_switch_to(binfo, port.port_bar); + if (ret) + break; + + ret = parse_feature_list(binfo, + (u8 __iomem *)binfo->ioaddr + + port.port_offset); + if (ret) + break; + } while (++i < MAX_FPGA_PORT_NUM); + + return ret; +} + +static struct build_feature_devs_info * +build_info_alloc_and_init(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + + binfo = zmalloc(sizeof(*binfo)); + if (!binfo) + return binfo; + + binfo->hw = hw; + binfo->pci_data = hw->pci_data; + + /* fpga feature list starts from BAR 0 */ + if (parse_switch_to(binfo, 0)) { + free(binfo); + return NULL; + } + + return binfo; +} + +static void build_info_free(struct build_feature_devs_info *binfo) +{ + free(binfo); +} + +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; + + 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]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr: 0x%lx\n", + feature->name, (unsigned long long)feature->addr, + (unsigned long long)feature->addr + feature->size - 1, + feature->phys_addr); + } + + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) { + port = &hw->port[i]; + + if (port->state != IFPGA_PORT_ATTACHED) + continue; + + dev_info(hw, "port device: %d\n", port->port_id); + + for (j = 0; j < PORT_FEATURE_ID_MAX; j++) { + feature = &port->sub_feature[j]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr:0x%lx\n", + feature->name, + (unsigned long long)feature->addr, + (unsigned long long)feature->addr + + feature->size - 1, + feature->phys_addr); + } + } +} + +int ifpga_bus_enumerate(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + int ret; + + binfo = build_info_alloc_and_init(hw); + if (!binfo) + return -ENOMEM; + + ret = parse_feature_list(binfo, binfo->ioaddr); + if (ret) + goto exit; + + ret = parse_ports_from_fme(binfo); + if (ret) + goto exit; + + ifpga_print_device_feature_list(hw); + +exit: + build_info_free(binfo); + return ret; +} + +int ifpga_bus_init(struct ifpga_hw *hw) +{ + int i; + + fme_hw_init(&hw->fme); + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) + port_hw_init(&hw->port[i]); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h new file mode 100644 index 0000000..0df7b2f --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h @@ -0,0 +1,38 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_ENUMERATE_H_ +#define _IFPGA_ENUMERATE_H_ + +int ifpga_bus_init(struct ifpga_hw *hw); +int ifpga_bus_enumerate(struct ifpga_hw *hw); + +#endif /* _IFPGA_ENUMERATE_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c new file mode 100644 index 0000000..0c632e6 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -0,0 +1,341 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include <linux/vfio.h> +#include <sys/ioctl.h> + +#include "ifpga_feature_dev.h" + +/* + * Enable Port by clear the port soft reset bit, which is set by default. + * The AFU is unable to respond to any MMIO access while in reset. + * __fpga_port_enable function should only be used after __fpga_port_disable + * function. + */ +void __fpga_port_enable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + WARN_ON(!port->disable_count); + + if (--port->disable_count != 0) + return; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x0; + writeq(control.csr, &port_hdr->control); +} + +int __fpga_port_disable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + if (port->disable_count++ != 0) + return 0; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + /* Set port soft reset */ + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x1; + writeq(control.csr, &port_hdr->control); + + /* + * HW sets ack bit to 1 when all outstanding requests have been drained + * on this port and minimum soft reset pulse width has elapsed. + * Driver polls port_soft_reset_ack to determine if reset done by HW. + */ + control.port_sftrst_ack = 1; + + if (fpga_wait_register_field(port_sftrst_ack, control, + &port_hdr->control, RST_POLL_TIMEOUT, + RST_POLL_INVL)) { + dev_err(port, "timeout, fail to reset device\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) +{ + struct feature_port_header *port_hdr; + u64 guidl, guidh; + + port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU); + + spinlock_lock(&port->lock); + guidl = readq(&port_hdr->afu_header.guid.b[0]); + guidh = readq(&port_hdr->afu_header.guid.b[8]); + spinlock_unlock(&port->lock); + + printf("%s: guidl=0x%lx, guidh=0x%lx\n", __func__, guidl, guidh); + + memcpy(uuid->b, &guidl, sizeof(u64)); + memcpy(uuid->b + 8, &guidh, sizeof(u64)); + + return 0; +} + +/* Mask / Unmask Port Errors by the Error Mask register. */ +void port_err_mask(struct ifpga_port_hw *port, bool mask) +{ + struct feature_port_error *port_err; + struct feature_port_err_key err_mask; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + if (mask) + err_mask.csr = PORT_ERR_MASK; + else + err_mask.csr = 0; + + writeq(err_mask.csr, &port_err->error_mask); +} + +/* Clear All Port Errors. */ +int port_err_clear(struct ifpga_port_hw *port, u64 err) +{ + struct feature_port_header *port_hdr; + struct feature_port_error *port_err; + struct feature_port_err_key mask; + struct feature_port_first_err_key first; + struct feature_port_status status; + int ret = 0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + /* + * Clear All Port Errors + * + * - Check for AP6 State + * - Halt Port by keeping Port in reset + * - Set PORT Error mask to all 1 to mask errors + * - Clear all errors + * - Set Port mask to all 0 to enable errors + * - All errors start capturing new errors + * - Enable Port by pulling the port out of reset + */ + + /* If device is still in AP6 state, can not clear any error.*/ + status.csr = readq(&port_hdr->status); + if (status.power_state == PORT_POWER_STATE_AP6) { + dev_err(dev, "Could not clear errors, device in AP6 state.\n"); + return -EBUSY; + } + + /* Halt Port by keeping Port in reset */ + ret = __fpga_port_disable(port); + if (ret) + return ret; + + /* Mask all errors */ + port_err_mask(port, true); + + /* Clear errors if err input matches with current port errors.*/ + mask.csr = readq(&port_err->port_error); + + if (mask.csr == err) { + writeq(mask.csr, &port_err->port_error); + + first.csr = readq(&port_err->port_first_error); + writeq(first.csr, &port_err->port_first_error); + } else { + ret = -EBUSY; + } + + /* Clear mask */ + port_err_mask(port, false); + + /* Enable the Port by clear the reset */ + __fpga_port_enable(port); + + return ret; +} + +int port_clear_error(struct ifpga_port_hw *port) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + + dev_info(port, "read port error: 0x%lx\n", error.csr); + + return port_err_clear(port, error.csr); +} + +void fme_hw_uinit(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return; + + 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); + } +} + +int fme_hw_init(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i, ret; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + 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; + } + } + } + + return 0; +} + +void port_hw_uinit(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i; + + 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); + } +} + +int port_hw_init(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i, 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; + } + } + } + + return 0; +} + +/* + * FIXME: we should get msix vec count during pci enumeration instead of + * below hardcode value. + */ +#define FPGA_MSIX_VEC_COUNT 20 +/* irq set buffer length for interrupt */ +#define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \ + sizeof(int) * FPGA_MSIX_VEC_COUNT) + +/* only support msix for now*/ +static int vfio_msix_enable_block(s32 vfio_dev_fd, unsigned int vec_start, + unsigned int count, s32 *fds) +{ + char irq_set_buf[MSIX_IRQ_SET_BUF_LEN]; + struct vfio_irq_set *irq_set; + int len, ret; + int *fd_ptr; + + len = sizeof(irq_set_buf); + + irq_set = (struct vfio_irq_set *)irq_set_buf; + irq_set->argsz = len; + irq_set->count = count; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; + irq_set->start = vec_start; + + fd_ptr = (int *)&irq_set->data; + memcpy(fd_ptr, fds, sizeof(int) * count); + + ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set); + if (ret) + printf("Error enabling MSI-X interrupts\n"); + + return ret; +} + +int fpga_msix_set_block(struct feature *feature, unsigned int start, + unsigned int count, s32 *fds) +{ + struct feature_irq_ctx *ctx = feature->ctx; + unsigned int i; + int ret; + + if (start >= feature->ctx_num || start + count > feature->ctx_num) + return -EINVAL; + + /* assume that each feature has continuous vector space in msix*/ + ret = vfio_msix_enable_block(feature->vfio_dev_fd, + ctx[start].idx, count, fds); + if (!ret) { + for (i = 0; i < count; i++) + ctx[i].eventfd = fds[i]; + } + + return ret; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h new file mode 100644 index 0000000..715975c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -0,0 +1,191 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_FEATURE_DEV_H_ +#define _IFPGA_FEATURE_DEV_H_ + +#include "ifpga_hw.h" + +static inline struct ifpga_port_hw * +get_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return NULL; + + return &hw->port[port_id]; +} + +#define ifpga_for_each_feature(hw, feature) \ + for ((feature) = (hw)->sub_feature; \ + (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++) + +static inline struct feature * +get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(fme, feature) { + if (feature->id == id) + return feature; + } + + return NULL; +} + +static inline struct feature * +get_port_feature_by_id(struct ifpga_port_hw *port, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(port, feature) { + 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; +} + +static inline void * +get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index) +{ + return port->sub_feature[index].addr; +} + +static inline bool +is_fme_feature_present(struct ifpga_fme_hw *fme, int index) +{ + return !!get_fme_feature_ioaddr_by_index(fme, index); +} + +static inline bool +is_port_feature_present(struct ifpga_port_hw *port, int index) +{ + return !!get_port_feature_ioaddr_by_index(port, index); +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid); + +int __fpga_port_disable(struct ifpga_port_hw *port); +void __fpga_port_enable(struct ifpga_port_hw *port); + +static inline int fpga_port_disable(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_disable(port); + spinlock_unlock(&port->lock); + return ret; +} + +static inline int fpga_port_enable(struct ifpga_port_hw *port) +{ + spinlock_lock(&port->lock); + __fpga_port_enable(port); + spinlock_unlock(&port->lock); + + return 0; +} + +static inline int __fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + ret = __fpga_port_disable(port); + if (ret) + return ret; + + __fpga_port_enable(port); + + return 0; +} + +static inline int fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_reset(port); + spinlock_unlock(&port->lock); + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +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); +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set); + +int fme_hw_init(struct ifpga_fme_hw *fme); +void fme_hw_uinit(struct ifpga_fme_hw *fme); +void port_hw_uinit(struct ifpga_port_hw *port); +int port_hw_init(struct ifpga_port_hw *port); +int port_clear_error(struct ifpga_port_hw *port); +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; + +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); + +/* This struct is used when parsing uafu irq_set */ +struct fpga_uafu_irq_set { + u32 start; + u32 count; + s32 *evtfds; +}; + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set); + +extern struct feature_ops port_hdr_ops; +extern struct feature_ops port_error_ops; +extern struct feature_ops port_stp_ops; +extern struct feature_ops port_uint_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 new file mode 100644 index 0000000..43a0a1c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -0,0 +1,761 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +#define PWR_THRESHOLD_MAX 0x7F + +int fme_get_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +/* fme private feature head */ +static int fme_hdr_init(struct feature *feature) +{ + struct feature_fme_header *fme_hdr; + + fme_hdr = (struct feature_fme_header *)feature->addr; + + dev_info(NULL, "FME HDR Init.\n"); + dev_info(NULL, "FME cap %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + return 0; +} + +static void fme_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME HDR UInit.\n"); +} + +static int fme_hdr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&fme_hdr->header); + *revision = header.revision; + + return 0; +} + +static int fme_hdr_get_ports_num(struct ifpga_fme_hw *fme, u64 *ports_num) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *ports_num = fme_capability.num_ports; + + return 0; +} + +static int fme_hdr_get_cache_size(struct ifpga_fme_hw *fme, u64 *cache_size) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *cache_size = fme_capability.cache_size; + + return 0; +} + +static int fme_hdr_get_version(struct ifpga_fme_hw *fme, u64 *version) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *version = fme_capability.fabric_verid; + + return 0; +} + +static int fme_hdr_get_socket_id(struct ifpga_fme_hw *fme, u64 *socket_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *socket_id = fme_capability.socket_id; + + return 0; +} + +static int fme_hdr_get_bitstream_id(struct ifpga_fme_hw *fme, + u64 *bitstream_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_id = readq(&fme_hdr->bitstream_id); + + return 0; +} + +static int fme_hdr_get_bitstream_metadata(struct ifpga_fme_hw *fme, + u64 *bitstream_metadata) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_metadata = readq(&fme_hdr->bitstream_md); + + return 0; +} + +static int +fme_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_HDR_PROP_REVISION: + return fme_hdr_get_revision(fme, &prop->data); + case FME_HDR_PROP_PORTS_NUM: + return fme_hdr_get_ports_num(fme, &prop->data); + case FME_HDR_PROP_CACHE_SIZE: + return fme_hdr_get_cache_size(fme, &prop->data); + case FME_HDR_PROP_VERSION: + return fme_hdr_get_version(fme, &prop->data); + case FME_HDR_PROP_SOCKET_ID: + return fme_hdr_get_socket_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_ID: + return fme_hdr_get_bitstream_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_METADATA: + return fme_hdr_get_bitstream_metadata(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_hdr_ops = { + .init = fme_hdr_init, + .uinit = fme_hdr_uinit, + .get_prop = fme_hdr_get_prop, +}; + +/* thermal management */ +static int fme_thermal_get_threshold1(struct ifpga_fme_hw *fme, u64 *thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1 = temp_threshold.tmp_thshold1; + + return 0; +} + +static int fme_thermal_set_threshold1(struct ifpga_fme_hw *fme, u64 thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres1 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres1 == 0) { + tmp_threshold.tmp_thshold1_enable = 0; + tmp_threshold.tmp_thshold1 = thres1; + } else { + tmp_threshold.tmp_thshold1_enable = 1; + tmp_threshold.tmp_thshold1 = thres1; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold2(struct ifpga_fme_hw *fme, u64 *thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres2 = temp_threshold.tmp_thshold2; + + return 0; +} + +static int fme_thermal_set_threshold2(struct ifpga_fme_hw *fme, u64 thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres2 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres2 == 0) { + tmp_threshold.tmp_thshold2_enable = 0; + tmp_threshold.tmp_thshold2 = thres2; + } else { + tmp_threshold.tmp_thshold2_enable = 1; + tmp_threshold.tmp_thshold2 = thres2; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold_trip(struct ifpga_fme_hw *fme, + u64 *thres_trip) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres_trip = temp_threshold.therm_trip_thshold; + + return 0; +} + +static int fme_thermal_get_threshold1_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold1_status; + + return 0; +} + +static int fme_thermal_get_threshold2_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold2_status; + + return 0; +} + +static int fme_thermal_get_threshold1_policy(struct ifpga_fme_hw *fme, + u64 *thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_policy = temp_threshold.thshold_policy; + + return 0; +} + +static int fme_thermal_set_threshold1_policy(struct ifpga_fme_hw *fme, + u64 thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold tmp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + + if (thres1_policy == 0) { + tmp_threshold.thshold_policy = 0; + } else if (thres1_policy == 1) { + tmp_threshold.thshold_policy = 1; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_temperature(struct ifpga_fme_hw *fme, u64 *temp) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_temp_rdsensor_fmt1 temp_rdsensor_fmt1; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_rdsensor_fmt1.csr = readq(&thermal->rdsensor_fm1); + *temp = temp_rdsensor_fmt1.fpga_temp; + + return 0; +} + +static int fme_thermal_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_thermal *fme_thermal + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + struct feature_header header; + + header.csr = readq(&fme_thermal->header); + *revision = header.revision; + + return 0; +} + +#define FME_THERMAL_CAP_NO_TMP_THRESHOLD 0x1 + +static int fme_thermal_mgmt_init(struct feature *feature) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold_cap thermal_cap; + + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt Init.\n"); + + fme_thermal = (struct feature_fme_thermal *)feature->addr; + thermal_cap.csr = readq(&fme_thermal->threshold_cap); + + dev_info(NULL, "FME thermal cap %llx.\n", + (unsigned long long)fme_thermal->threshold_cap.csr); + + if (thermal_cap.tmp_thshold_disabled) + feature->cap |= FME_THERMAL_CAP_NO_TMP_THRESHOLD; + + return 0; +} + +static void fme_thermal_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt UInit.\n"); +} + +static int +fme_thermal_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_set_threshold1(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_set_threshold2(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_set_threshold1_policy(fme, prop->data); + } + + return -ENOENT; +} + +static int +fme_thermal_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD && + prop->prop_id != FME_THERMAL_PROP_TEMPERATURE && + prop->prop_id != FME_THERMAL_PROP_REVISION) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_get_threshold1(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_get_threshold2(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD_TRIP: + return fme_thermal_get_threshold_trip(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_REACHED: + return fme_thermal_get_threshold1_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2_REACHED: + return fme_thermal_get_threshold2_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_get_threshold1_policy(fme, &prop->data); + case FME_THERMAL_PROP_TEMPERATURE: + return fme_thermal_get_temperature(fme, &prop->data); + case FME_THERMAL_PROP_REVISION: + return fme_thermal_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_thermal_mgmt_ops = { + .init = fme_thermal_mgmt_init, + .uinit = fme_thermal_mgmt_uinit, + .get_prop = fme_thermal_get_prop, + .set_prop = fme_thermal_set_prop, +}; + +static int fme_pwr_get_consumed(struct ifpga_fme_hw *fme, u64 *consumed) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *consumed = pm_status.pwr_consumed; + + return 0; +} + +static int fme_pwr_get_threshold1(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold1; + + return 0; +} + +static int fme_pwr_set_threshold1(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold1 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold2(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold2; + + return 0; +} + +static int fme_pwr_set_threshold2(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold2 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold1_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold1_status; + + return 0; +} + +static int fme_pwr_get_threshold2_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold2_status; + + return 0; +} + +static int fme_pwr_get_rtl(struct ifpga_fme_hw *fme, u64 *rtl) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *rtl = pm_status.fpga_latency_report; + + return 0; +} + +static int fme_pwr_get_xeon_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_xeon_limit xeon_limit; + + xeon_limit.csr = readq(&fme_power->xeon_limit); + + if (!xeon_limit.enable) + xeon_limit.pwr_limit = 0; + + *limit = xeon_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_fpga_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_fpga_limit fpga_limit; + + fpga_limit.csr = readq(&fme_power->fpga_limit); + + if (!fpga_limit.enable) + fpga_limit.pwr_limit = 0; + + *limit = fpga_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_header header; + + header.csr = readq(&fme_power->header); + *revision = header.revision; + + return 0; +} + +static int fme_power_mgmt_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt Init.\n"); + + return 0; +} + +static void fme_power_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt UInit.\n"); +} + +static int fme_power_mgmt_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_CONSUMED: + return fme_pwr_get_consumed(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_get_threshold1(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_get_threshold2(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1_STATUS: + return fme_pwr_get_threshold1_status(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2_STATUS: + return fme_pwr_get_threshold2_status(fme, &prop->data); + case FME_PWR_PROP_RTL: + return fme_pwr_get_rtl(fme, &prop->data); + case FME_PWR_PROP_XEON_LIMIT: + return fme_pwr_get_xeon_limit(fme, &prop->data); + case FME_PWR_PROP_FPGA_LIMIT: + return fme_pwr_get_fpga_limit(fme, &prop->data); + case FME_PWR_PROP_REVISION: + return fme_pwr_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_power_mgmt_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_set_threshold1(fme, prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_set_threshold2(fme, prop->data); + } + + return -ENOENT; +} + +struct 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, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c new file mode 100644 index 0000000..ae064ff --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c @@ -0,0 +1,328 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_dperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_clk_ctr clk; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + clk.afu_interf_clock = readq(&dperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_dperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_dperf *dperf; + struct feature_header header; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + header.csr = readq(&dperf->header); + *revision = header.revision; + + return 0; +} + +#define DPERF_TIMEOUT 30 + +static bool fabric_pobj_is_enabled(int port_id, + struct feature_fme_dperf *dperf) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + + ctl.csr = readq(&dperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum dperf_fab_events fab_event) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dfpmon_fab_ctr ctr; + struct feature_fme_dperf *dperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, dperf)) + goto exit; + + ctl.csr = readq(&dperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &dperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &dperf->fab_ctr, DPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&dperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_dperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, DPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, DPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(mmio_read, DPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, DPERF_FAB_MMIO_WR); + +static int fme_dperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_dperf *dperf; + int status; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + status = fabric_pobj_is_enabled(port_id, dperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_dperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dperf *dperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, dperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&dperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_dperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_dperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 + +static int fme_global_dperf_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf Init.\n"); + + return 0; +} + +static void fme_global_dperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf UInit.\n"); +} + +static int fme_dperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_dperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_dperf_get_fab_port_pcie0_read(fme, sub, &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_dperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* MMIO_READ */ + return fme_dperf_get_fab_port_mmio_read(fme, sub, &prop->data); + case 0x5: /* MMIO_WRITE */ + return fme_dperf_get_fab_port_mmio_write(fme, sub, &prop->data); + case 0x6: /* ENABLE */ + return fme_dperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_dperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_dperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_dperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_dperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_dperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE - fab root only prop */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_dperf_set_fab_freeze(fme, prop->data); + case 0x6: /* ENABLE - fab both root and sub */ + return fme_dperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_dperf_ops = { + .init = fme_global_dperf_init, + .uinit = fme_global_dperf_uinit, + .get_prop = fme_global_dperf_get_prop, + .set_prop = fme_global_dperf_set_prop, + +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c new file mode 100644 index 0000000..a8a6a3c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c @@ -0,0 +1,430 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +static int fme_err_get_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + + fme_error0.csr = readq(&fme_err->fme_err); + *val = fme_error0.csr; + + return 0; +} + +static int fme_err_get_first_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_first_error fme_first_err; + + fme_first_err.csr = readq(&fme_err->fme_first_err); + *val = fme_first_err.err_reg_status; + + return 0; +} + +static int fme_err_get_next_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_next_error fme_next_err; + + fme_next_err.csr = readq(&fme_err->fme_next_err); + *val = fme_next_err.err_reg_status; + + return 0; +} + +static int fme_err_set_clear(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_ERROR0_MASK, &fme_err->fme_err_mask); + + fme_error0.csr = readq(&fme_err->fme_err); + if (val != fme_error0.csr) { + ret = -EBUSY; + goto exit; + } + + fme_first_err.csr = readq(&fme_err->fme_first_err); + fme_next_err.csr = readq(&fme_err->fme_next_err); + + writeq(fme_error0.csr & FME_ERROR0_MASK, &fme_err->fme_err); + writeq(fme_first_err.csr & FME_FIRST_ERROR_MASK, + &fme_err->fme_first_err); + writeq(fme_next_err.csr & FME_NEXT_ERROR_MASK, + &fme_err->fme_next_err); + +exit: + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_revision(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_header header; + + header.csr = readq(&fme_err->header); + *val = header.revision; + + return 0; +} + +static int fme_err_get_pcie0_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + + pcie0_err.csr = readq(&fme_err->pcie0_err); + *val = pcie0_err.csr; + + return 0; +} + +static int fme_err_set_pcie0_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE0_ERROR_MASK, &fme_err->pcie0_err_mask); + + pcie0_err.csr = readq(&fme_err->pcie0_err); + if (val != pcie0_err.csr) + ret = -EBUSY; + else + writeq(pcie0_err.csr & FME_PCIE0_ERROR_MASK, + &fme_err->pcie0_err); + + writeq(0UL, &fme_err->pcie0_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_pcie1_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + + pcie1_err.csr = readq(&fme_err->pcie1_err); + *val = pcie1_err.csr; + + return 0; +} + +static int fme_err_set_pcie1_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE1_ERROR_MASK, &fme_err->pcie1_err_mask); + + pcie1_err.csr = readq(&fme_err->pcie1_err); + if (val != pcie1_err.csr) + ret = -EBUSY; + else + writeq(pcie1_err.csr & FME_PCIE1_ERROR_MASK, + &fme_err->pcie1_err); + + writeq(0UL, &fme_err->pcie1_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_nonfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_nonfaterror ras_nonfaterr; + + ras_nonfaterr.csr = readq(&fme_err->ras_nonfaterr); + *val = ras_nonfaterr.csr; + + return 0; +} + +static int fme_err_get_catfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_catfaterror ras_catfaterr; + + ras_catfaterr.csr = readq(&fme_err->ras_catfaterr); + *val = ras_catfaterr.csr; + + return 0; +} + +static int fme_err_get_inject_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + *val = ras_error_inj.csr & FME_RAS_ERROR_INJ_MASK; + + return 0; +} + +static int fme_err_set_inject_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + spinlock_lock(&fme->lock); + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + + if (val <= FME_RAS_ERROR_INJ_MASK) { + ras_error_inj.csr = val; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(ras_error_inj.csr, &fme_err->ras_error_inj); + spinlock_unlock(&fme->lock); + + return 0; +} + +static void fme_error_enable(struct ifpga_fme_hw *fme) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + writeq(0UL, &fme_err->pcie0_err_mask); + writeq(0UL, &fme_err->pcie1_err_mask); + writeq(0UL, &fme_err->ras_nonfat_mask); + writeq(0UL, &fme_err->ras_catfat_mask); +} + +static int fme_global_error_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = feature->parent; + + fme_error_enable(fme); + + if (feature->ctx_num) + fme->capability |= FPGA_FME_CAP_ERR_IRQ; + + return 0; +} + +static void fme_global_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int fme_err_fme_err_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* ERRORS */ + return fme_err_get_errors(fme, &prop->data); + case 0x2: /* FIRST_ERROR */ + return fme_err_get_first_error(fme, &prop->data); + case 0x3: /* NEXT_ERROR */ + return fme_err_get_next_error(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x5: /* REVISION */ + return fme_err_get_revision(fme, &prop->data); + case 0x6: /* PCIE0_ERRORS */ + return fme_err_get_pcie0_errors(fme, &prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_get_pcie1_errors(fme, &prop->data); + case 0x8: /* NONFATAL_ERRORS */ + return fme_err_get_nonfatal_errors(fme, &prop->data); + case 0x9: /* CATFATAL_ERRORS */ + return fme_err_get_catfatal_errors(fme, &prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_get_inject_errors(fme, &prop->data); + case 0xb: /* REVISION*/ + return fme_err_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_get_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_err_fme_err_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x4: /* CLEAR */ + return fme_err_set_clear(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x6: /* PCIE0_ERRORS */ + return fme_err_set_pcie0_errors(fme, prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_set_pcie1_errors(fme, prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_set_inject_errors(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_set_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_set_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_global_err_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_fme_err_irq_set *err_irq_set = + (struct fpga_fme_err_irq_set *)irq_set; + struct ifpga_fme_hw *fme; + int ret; + + fme = (struct ifpga_fme_hw *)feature->parent; + + spinlock_lock(&fme->lock); + if (!(fme->capability & FPGA_FME_CAP_ERR_IRQ)) { + spinlock_unlock(&fme->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&fme->lock); + + return ret; +} + +struct feature_ops fme_global_err_ops = { + .init = fme_global_error_init, + .uinit = fme_global_error_uinit, + .get_prop = fme_global_error_get_prop, + .set_prop = fme_global_error_set_prop, + .set_irq = fme_global_err_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c new file mode 100644 index 0000000..6db2f45 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c @@ -0,0 +1,742 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_iperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_clk_ctr clk; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + clk.afu_interf_clock = readq(&iperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_iperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_iperf *iperf; + struct feature_header header; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + header.csr = readq(&iperf->header); + *revision = header.revision; + + return 0; +} + +static int fme_iperf_get_cache_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + *freeze = (u64)ctl.freeze; + return 0; +} + +static int fme_iperf_set_cache_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->ch_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define IPERF_TIMEOUT 30 + +static u64 read_cache_counter(struct ifpga_fme_hw *fme, + u8 channel, enum iperf_cache_events event) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + struct feature_fme_ifpmon_ch_ctr ctr0, ctr1; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* set channel access type and cache event code. */ + ctl.csr = readq(&iperf->ch_ctl); + ctl.cci_chsel = channel; + ctl.cache_event = event; + writeq(ctl.csr, &iperf->ch_ctl); + + /* check the event type in the counter registers */ + ctr0.event_code = event; + + if (fpga_wait_register_field(event_code, ctr0, + &iperf->ch_ctr0, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched cache event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr0.csr = readq(&iperf->ch_ctr0); + ctr1.csr = readq(&iperf->ch_ctr1); + counter = ctr0.cache_counter + ctr1.cache_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define CACHE_SHOW(name, type, event) \ +static int fme_iperf_get_cache_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_cache_counter(fme, type, event); \ + return 0; \ +} + +CACHE_SHOW(read_hit, CACHE_CHANNEL_RD, IPERF_CACHE_RD_HIT); +CACHE_SHOW(read_miss, CACHE_CHANNEL_RD, IPERF_CACHE_RD_MISS); +CACHE_SHOW(write_hit, CACHE_CHANNEL_WR, IPERF_CACHE_WR_HIT); +CACHE_SHOW(write_miss, CACHE_CHANNEL_WR, IPERF_CACHE_WR_MISS); +CACHE_SHOW(hold_request, CACHE_CHANNEL_RD, IPERF_CACHE_HOLD_REQ); +CACHE_SHOW(tx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_TX_REQ_STALL); +CACHE_SHOW(rx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_RX_REQ_STALL); +CACHE_SHOW(rx_eviction, CACHE_CHANNEL_RD, IPERF_CACHE_EVICTIONS); +CACHE_SHOW(data_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_DATA_WR_PORT_CONTEN); +CACHE_SHOW(tag_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_TAG_WR_PORT_CONTEN); + +static int fme_iperf_get_vtd_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_vtd_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->vtd_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static u64 read_iommu_sip_counter(struct ifpga_fme_hw *fme, + enum iperf_vtd_sip_events event) +{ + struct feature_fme_ifpmon_vtd_sip_ctl sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr sip_ctr; + struct feature_fme_iperf *iperf; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + sip_ctl.csr = readq(&iperf->vtd_sip_ctl); + sip_ctl.vtd_evtcode = event; + writeq(sip_ctl.csr, &iperf->vtd_sip_ctl); + + sip_ctr.event_code = event; + + if (fpga_wait_register_field(event_code, sip_ctr, + &iperf->vtd_sip_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd SIP event type in counter registers\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + sip_ctr.csr = readq(&iperf->vtd_sip_ctr); + counter = sip_ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_SIP_SHOW(name, event) \ +static int fme_iperf_get_vtd_sip_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_iommu_sip_counter(fme, event); \ + return 0; \ +} + +VTD_SIP_SHOW(iotlb_4k_hit, IPERF_VTD_SIP_IOTLB_4K_HIT); +VTD_SIP_SHOW(iotlb_2m_hit, IPERF_VTD_SIP_IOTLB_2M_HIT); +VTD_SIP_SHOW(iotlb_1g_hit, IPERF_VTD_SIP_IOTLB_1G_HIT); +VTD_SIP_SHOW(slpwc_l3_hit, IPERF_VTD_SIP_SLPWC_L3_HIT); +VTD_SIP_SHOW(slpwc_l4_hit, IPERF_VTD_SIP_SLPWC_L4_HIT); +VTD_SIP_SHOW(rcc_hit, IPERF_VTD_SIP_RCC_HIT); +VTD_SIP_SHOW(iotlb_4k_miss, IPERF_VTD_SIP_IOTLB_4K_MISS); +VTD_SIP_SHOW(iotlb_2m_miss, IPERF_VTD_SIP_IOTLB_2M_MISS); +VTD_SIP_SHOW(iotlb_1g_miss, IPERF_VTD_SIP_IOTLB_1G_MISS); +VTD_SIP_SHOW(slpwc_l3_miss, IPERF_VTD_SIP_SLPWC_L3_MISS); +VTD_SIP_SHOW(slpwc_l4_miss, IPERF_VTD_SIP_SLPWC_L4_MISS); +VTD_SIP_SHOW(rcc_miss, IPERF_VTD_SIP_RCC_MISS); + +static u64 read_iommu_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_vtd_events base_event) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_ifpmon_vtd_ctr ctr; + struct feature_fme_iperf *iperf; + enum iperf_vtd_events event = base_event + port_id; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.vtd_evtcode = event; + writeq(ctl.csr, &iperf->vtd_ctl); + + ctr.event_code = event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->vtd_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->vtd_ctr); + counter = ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_PORT_SHOW(name, base_event) \ +static int fme_iperf_get_vtd_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_iommu_counter(fme, port_id, base_event); \ + return 0; \ +} + +VTD_PORT_SHOW(read_transaction, IPERF_VTD_AFU_MEM_RD_TRANS); +VTD_PORT_SHOW(write_transaction, IPERF_VTD_AFU_MEM_WR_TRANS); +VTD_PORT_SHOW(devtlb_read_hit, IPERF_VTD_AFU_DEVTLB_RD_HIT); +VTD_PORT_SHOW(devtlb_write_hit, IPERF_VTD_AFU_DEVTLB_WR_HIT); +VTD_PORT_SHOW(devtlb_4k_fill, IPERF_VTD_DEVTLB_4K_FILL); +VTD_PORT_SHOW(devtlb_2m_fill, IPERF_VTD_DEVTLB_2M_FILL); +VTD_PORT_SHOW(devtlb_1g_fill, IPERF_VTD_DEVTLB_1G_FILL); + +static bool fabric_pobj_is_enabled(u8 port_id, struct feature_fme_iperf *iperf) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + + ctl.csr = readq(&iperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_fab_events fab_event) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_ifpmon_fab_ctr ctr; + struct feature_fme_iperf *iperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, iperf)) + goto exit; + + ctl.csr = readq(&iperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &iperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->fab_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_iperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, IPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, IPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(pcie1_read, IPERF_FAB_PCIE1_RD); +FAB_PORT_SHOW(pcie1_write, IPERF_FAB_PCIE1_WR); +FAB_PORT_SHOW(upi_read, IPERF_FAB_UPI_RD); +FAB_PORT_SHOW(upi_write, IPERF_FAB_UPI_WR); +FAB_PORT_SHOW(mmio_read, IPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, IPERF_FAB_MMIO_WR); + +static int fme_iperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_iperf *iperf; + int status; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + status = fabric_pobj_is_enabled(port_id, iperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_iperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, iperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&iperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_iperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 +#define FME_IPERF_CAP_IOMMU 0x1 + +static int fme_global_iperf_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme; + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + + dev_info(NULL, "FME global_iperf Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + /* check if iommu is not supported on this device. */ + fme_capability.csr = readq(&fme_hdr->capability); + dev_info(NULL, "FME HEAD fme_capability %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + if (fme_capability.iommu_support) + feature->cap |= FME_IPERF_CAP_IOMMU; + + return 0; +} + +static void fme_global_iperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_iperf UInit.\n"); +} + +static int fme_iperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_iperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_iperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_cache_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_cache_freeze(fme, &prop->data); + case 0x2: /* READ_HIT */ + return fme_iperf_get_cache_read_hit(fme, &prop->data); + case 0x3: /* READ_MISS */ + return fme_iperf_get_cache_read_miss(fme, &prop->data); + case 0x4: /* WRITE_HIT */ + return fme_iperf_get_cache_write_hit(fme, &prop->data); + case 0x5: /* WRITE_MISS */ + return fme_iperf_get_cache_write_miss(fme, &prop->data); + case 0x6: /* HOLD_REQUEST */ + return fme_iperf_get_cache_hold_request(fme, &prop->data); + case 0x7: /* TX_REQ_STALL */ + return fme_iperf_get_cache_tx_req_stall(fme, &prop->data); + case 0x8: /* RX_REQ_STALL */ + return fme_iperf_get_cache_rx_req_stall(fme, &prop->data); + case 0x9: /* RX_EVICTION */ + return fme_iperf_get_cache_rx_eviction(fme, &prop->data); + case 0xa: /* DATA_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_data_write_port_contention(fme, + &prop->data); + case 0xb: /* TAG_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_tag_write_port_contention(fme, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_vtd_freeze(fme, &prop->data); + case 0x2: /* IOTLB_4K_HIT */ + return fme_iperf_get_vtd_sip_iotlb_4k_hit(fme, &prop->data); + case 0x3: /* IOTLB_2M_HIT */ + return fme_iperf_get_vtd_sip_iotlb_2m_hit(fme, &prop->data); + case 0x4: /* IOTLB_1G_HIT */ + return fme_iperf_get_vtd_sip_iotlb_1g_hit(fme, &prop->data); + case 0x5: /* SLPWC_L3_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l3_hit(fme, &prop->data); + case 0x6: /* SLPWC_L4_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l4_hit(fme, &prop->data); + case 0x7: /* RCC_HIT */ + return fme_iperf_get_vtd_sip_rcc_hit(fme, &prop->data); + case 0x8: /* IOTLB_4K_MISS */ + return fme_iperf_get_vtd_sip_iotlb_4k_miss(fme, &prop->data); + case 0x9: /* IOTLB_2M_MISS */ + return fme_iperf_get_vtd_sip_iotlb_2m_miss(fme, &prop->data); + case 0xa: /* IOTLB_1G_MISS */ + return fme_iperf_get_vtd_sip_iotlb_1g_miss(fme, &prop->data); + case 0xb: /* SLPWC_L3_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l3_miss(fme, &prop->data); + case 0xc: /* SLPWC_L4_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l4_miss(fme, &prop->data); + case 0xd: /* RCC_MISS */ + return fme_iperf_get_vtd_sip_rcc_miss(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_sub_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub > PERF_MAX_PORT_NUM) + return -ENOENT; + + switch (id) { + case 0xe: /* READ_TRANSACTION */ + return fme_iperf_get_vtd_port_read_transaction(fme, sub, + &prop->data); + case 0xf: /* WRITE_TRANSACTION */ + return fme_iperf_get_vtd_port_write_transaction(fme, sub, + &prop->data); + case 0x10: /* DEVTLB_READ_HIT */ + return fme_iperf_get_vtd_port_devtlb_read_hit(fme, sub, + &prop->data); + case 0x11: /* DEVTLB_WRITE_HIT */ + return fme_iperf_get_vtd_port_devtlb_write_hit(fme, sub, + &prop->data); + case 0x12: /* DEVTLB_4K_FILL */ + return fme_iperf_get_vtd_port_devtlb_4k_fill(fme, sub, + &prop->data); + case 0x13: /* DEVTLB_2M_FILL */ + return fme_iperf_get_vtd_port_devtlb_2m_fill(fme, sub, + &prop->data); + case 0x14: /* DEVTLB_1G_FILL */ + return fme_iperf_get_vtd_port_devtlb_1g_fill(fme, sub, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED) + return fme_iperf_vtd_root_get_prop(feature, prop); + + return fme_iperf_vtd_sub_get_prop(feature, prop); +} + +static int fme_iperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + /* Other properties are present for both top and sub levels */ + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_iperf_get_fab_port_pcie0_read(fme, sub, + &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_iperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* PCIE1_READ */ + return fme_iperf_get_fab_port_pcie1_read(fme, sub, + &prop->data); + case 0x5: /* PCIE1_WRITE */ + return fme_iperf_get_fab_port_pcie1_write(fme, sub, + &prop->data); + case 0x6: /* UPI_READ */ + return fme_iperf_get_fab_port_upi_read(fme, sub, + &prop->data); + case 0x7: /* UPI_WRITE */ + return fme_iperf_get_fab_port_upi_write(fme, sub, + &prop->data); + case 0x8: /* MMIO_READ */ + return fme_iperf_get_fab_port_mmio_read(fme, sub, + &prop->data); + case 0x9: /* MMIO_WRITE */ + return fme_iperf_get_fab_port_mmio_write(fme, sub, + &prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_get_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_get_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_iperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_iperf_cache_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_cache_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_vtd_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_vtd_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_set_fab_freeze(fme, prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_set_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_set_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_iperf_ops = { + .init = fme_global_iperf_init, + .uinit = fme_global_iperf_uinit, + .get_prop = fme_global_iperf_get_prop, + .set_prop = fme_global_iperf_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c new file mode 100644 index 0000000..2a988c4 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c @@ -0,0 +1,399 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +#if defined(RTE_ARCH_X86_64) +static inline void copy512(const void *src, void *dst) +{ + asm volatile("vmovdqu64 (%0), %%zmm0;" + "vmovntdq %%zmm0, (%1);" + : + : "r"(src), "r"(dst)); +} +#else +static inline void copy512(const void *src, void *dst) +{ + UNUSED(src); + UNUSED(dst); + WARN_ON(1); +} +#endif + +static u64 +pr_err_handle(struct feature_fme_pr *fme_pr) +{ + struct feature_fme_pr_status fme_pr_status; + unsigned long err_code; + u64 fme_pr_error; + int i; + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + if (!fme_pr_status.pr_status) + return 0; + + err_code = readq(&fme_pr->ccip_fme_pr_err); + fme_pr_error = err_code; + + for (i = 0; i < PR_MAX_ERR_NUM; i++) { + if (err_code & (1 << i)) + dev_info(NULL, "%s\n", pr_err_msg[i]); + } + + writeq(fme_pr_error, &fme_pr->ccip_fme_pr_err); + return fme_pr_error; +} + +static int fme_pr_write_init(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + if (info->flags != FPGA_MGR_PARTIAL_RECONFIG) + return -EINVAL; + + dev_info(fme_dev, "resetting PR before initiated PR\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + fme_pr_ctl.pr_reset_ack = 1; + + if (fpga_wait_register_field(pr_reset_ack, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 0; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "waiting for PR resource in HW to be initialized and ready\n"); + + fme_pr_status.pr_host_status = PR_HOST_STATUS_IDLE; + + if (fpga_wait_register_field(pr_host_status, fme_pr_status, + &fme_pr->ccip_fme_pr_status, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "check if have any previous PR error\n"); + pr_err_handle(fme_pr); + return 0; +} + +static int fme_pr_write(struct ifpga_fme_hw *fme_dev, + int port_id, const char *buf, size_t count, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + struct feature_fme_pr_data fme_pr_data; + int delay, pr_credit; + int ret = 0; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + dev_info(fme_dev, "set PR port ID and start request\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_regionid = port_id; + fme_pr_ctl.pr_start_req = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "pushing data from bitstream to HW\n"); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + + while (count > 0) { + delay = 0; + while (pr_credit <= 1) { + if (delay++ > PR_WAIT_TIMEOUT) { + dev_err(fme_dev, "maximum try\n"); + + info->pr_err = pr_err_handle(fme_pr); + return info->pr_err ? -EIO : -ETIMEDOUT; + } + udelay(1); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + }; + + if (count >= fme_dev->pr_bandwidth) { + switch (fme_dev->pr_bandwidth) { + case 4: + fme_pr_data.rsvd = 0; + fme_pr_data.pr_data_raw = *((const u32 *)buf); + writeq(fme_pr_data.csr, + &fme_pr->ccip_fme_pr_data); + break; + case 64: + copy512(buf, &fme_pr->fme_pr_data1); + break; + default: + ret = -EFAULT; + goto done; + } + + buf += fme_dev->pr_bandwidth; + count -= fme_dev->pr_bandwidth; + pr_credit--; + } else { + WARN_ON(1); + return -EINVAL; + goto done; + } + } + +done: + return ret; +} + +static int fme_pr_write_complete(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_push_complete = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "green bitstream push complete\n"); + dev_info(fme_dev, "waiting for HW to release PR resource\n"); + + fme_pr_ctl.pr_start_req = 0; + + if (fpga_wait_register_field(pr_start_req, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + printf("maximum try.\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "PR operation complete, checking status\n"); + info->pr_err = pr_err_handle(fme_pr); + if (info->pr_err) + return -EIO; + + dev_info(fme_dev, "PR done successfully\n"); + return 0; +} + +static int fpga_pr_buf_load(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info, const char *buf, + size_t count) +{ + int ret; + + info->state = FPGA_PR_STATE_WRITE_INIT; + ret = fme_pr_write_init(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error preparing FPGA for writing\n"); + info->state = FPGA_PR_STATE_WRITE_INIT_ERR; + return ret; + } + + /* + * Write the FPGA image to the FPGA. + */ + info->state = FPGA_PR_STATE_WRITE; + ret = fme_pr_write(fme_dev, info->port_id, buf, count, info); + if (ret) { + dev_err(fme_dev, "Error while writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_ERR; + return ret; + } + + /* + * After all the FPGA image has been written, do the device specific + * steps to finish and set the FPGA into operating mode. + */ + info->state = FPGA_PR_STATE_WRITE_COMPLETE; + ret = fme_pr_write_complete(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error after writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_COMPLETE_ERR; + return ret; + } + info->state = FPGA_PR_STATE_DONE; + + return 0; +} + +static int fme_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + struct ifpga_fme_hw *fme = &hw->fme; + struct fpga_pr_info info; + struct ifpga_port_hw *port; + int ret = 0; + + if (!buffer || size == 0) + return -EINVAL; + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + /* + * Padding extra zeros to align PR buffer with PR bandwidth, HW will + * ignore these zeros automatically. + */ + size = ALIGN(size, fme->pr_bandwidth); + + /* get fme header region */ + fme_hdr = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_HEADER); + if (!fme_hdr) + return -EINVAL; + + /* check port id */ + fme_capability.csr = readq(&fme_hdr->capability); + if (port_id >= fme_capability.num_ports) { + dev_err(fme, "port number more than maximum\n"); + return -EINVAL; + } + + memset(&info, 0, sizeof(struct fpga_pr_info)); + info.flags = FPGA_MGR_PARTIAL_RECONFIG; + info.port_id = port_id; + + spinlock_lock(&fme->lock); + + /* get port device by port_id */ + port = &hw->port[port_id]; + + /* Disable Port before PR */ + fpga_port_disable(port); + + ret = fpga_pr_buf_load(fme, &info, (void *)buffer, size); + + *status = info.pr_err; + + /* Re-enable Port after PR finished */ + fpga_port_enable(port); + spinlock_unlock(&fme->lock); + + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, u64 *status) +{ + struct bts_header *bts_hdr; + void *buf; + struct ifpga_port_hw *port; + int ret; + + if (!buffer || size == 0) { + dev_err(hw, "invalid parameter\n"); + return -EINVAL; + } + + bts_hdr = (struct bts_header *)buffer; + + if (is_valid_bts(bts_hdr)) { + dev_info(hw, "this is a valid bitsteam..\n"); + size -= (sizeof(struct bts_header) + + bts_hdr->metadata_len); + buf = (u8 *)buffer + sizeof(struct bts_header) + + bts_hdr->metadata_len; + } else { + return -EINVAL; + } + + /* clean port error before do PR */ + port = &hw->port[port_id]; + ret = port_clear_error(port); + if (ret) { + dev_err(hw, "port cannot clear error\n"); + return -EINVAL; + } + + return fme_pr(hw, port_id, buf, size, status); +} + +static int fme_pr_mgmt_init(struct feature *feature) +{ + struct feature_fme_pr *fme_pr; + struct feature_header fme_pr_header; + struct ifpga_fme_hw *fme; + + dev_info(NULL, "FME PR MGMT Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + + fme_pr = (struct feature_fme_pr *)feature->addr; + + fme_pr_header.csr = readq(&fme_pr->header); + if (fme_pr_header.revision == 2) { + dev_info(NULL, "using 512-bit PR\n"); + fme->pr_bandwidth = 64; + } else { + dev_info(NULL, "using 32-bit PR\n"); + fme->pr_bandwidth = 4; + } + + return 0; +} + +static void fme_pr_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME PR MGMT UInit.\n"); +} + +struct 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 new file mode 100644 index 0000000..482779d --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -0,0 +1,154 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _IFPGA_HW_H_ +#define _IFPGA_HW_H_ + +#include "ifpga_defines.h" +#include "opae_ifpga_hw_api.h" + +enum ifpga_feature_state { + IFPGA_FEATURE_UNUSED = 0, + IFPGA_FEATURE_ATTACHED, +}; + +struct feature_irq_ctx { + int eventfd; + int idx; +}; + +struct feature { + enum ifpga_feature_state state; + const char *name; + u64 id; + u8 *addr; + uint64_t phys_addr; + u32 size; + int revision; + u64 cap; + int vfio_dev_fd; + struct feature_irq_ctx *ctx; + unsigned int ctx_num; + + void *parent; /* to parent hw data structure */ + + struct feature_ops *ops;/* callback to this private feature */ +}; + +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); +}; + +enum ifpga_fme_state { + IFPGA_FME_UNUSED = 0, + IFPGA_FME_IMPLEMENTED, +}; + +struct ifpga_fme_hw { + enum ifpga_fme_state state; + + struct feature sub_feature[FME_FEATURE_ID_MAX]; + spinlock_t lock; /* protect hardware access */ + + void *parent; /* pointer to ifpga_hw */ + + /* provied by HEADER feature */ + u32 port_num; + struct uuid bitstream_id; + u64 bitstream_md; + size_t pr_bandwidth; + u32 socket_id; + u32 fabric_version_id; + u32 cache_size; + + u32 capability; +}; + +enum ifpga_port_state { + IFPGA_PORT_UNUSED = 0, + IFPGA_PORT_ATTACHED, + IFPGA_PORT_DETACHED, +}; + +struct ifpga_port_hw { + enum ifpga_port_state state; + + struct feature sub_feature[PORT_FEATURE_ID_MAX]; + spinlock_t lock; /* protect access to hw */ + + void *parent; /* pointer to ifpga_hw */ + + int port_id; /* provied by HEADER feature */ + struct uuid afu_id; /* provied by User AFU feature */ + + unsigned int disable_count; + + u32 capability; + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ + u8 *stp_addr; + u32 stp_size; +}; + +#define AFU_MAX_REGION 1 + +struct ifpga_afu_info { + struct opae_reg_region region[AFU_MAX_REGION]; + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct ifpga_hw { + struct opae_adapter *adapter; + struct opae_adapter_data_pci *pci_data; + + struct ifpga_fme_hw fme; + struct ifpga_port_hw port[MAX_FPGA_PORT_NUM]; +}; + +static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) +{ + return hw->fme.state != IFPGA_FME_UNUSED; +} + +static inline bool is_valid_port_id(struct ifpga_hw *hw, u32 port_id) +{ + if (port_id >= MAX_FPGA_PORT_NUM || + hw->port[port_id].state != IFPGA_PORT_ATTACHED) + return false; + + return true; +} +#endif /* _IFPGA_HW_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c new file mode 100644 index 0000000..1dab201 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c @@ -0,0 +1,435 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +static int port_get_revision(struct ifpga_port_hw *port, u64 *revision) +{ + struct feature_port_header *port_hdr + = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&port_hdr->header); + + *revision = header.revision; + + return 0; +} + +static int port_get_portidx(struct ifpga_port_hw *port, u64 *idx) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + capability.csr = readq(&port_hdr->capability); + *idx = capability.port_number; + + return 0; +} + +static int port_get_latency_tolerance(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + control.csr = readq(&port_hdr->control); + *val = control.latency_tolerance; + + return 0; +} + +static int port_get_ap1_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap1_event; + + return 0; +} + +static int port_set_ap1_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap1_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_ap2_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap2_event; + + return 0; +} + +static int port_set_ap2_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap2_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_power_state(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.power_state; + + return 0; +} + +static int port_get_userclk_freqcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_hdr_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port hdr Init.\n"); + + fpga_port_reset(port); + + return 0; +} + +static void port_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port hdr uinit.\n"); +} + +static int port_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_REVISION: + return port_get_revision(port, &prop->data); + case PORT_HDR_PROP_PORTIDX: + return port_get_portidx(port, &prop->data); + case PORT_HDR_PROP_LATENCY_TOLERANCE: + return port_get_latency_tolerance(port, &prop->data); + case PORT_HDR_PROP_AP1_EVENT: + return port_get_ap1_event(port, &prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_get_ap2_event(port, &prop->data); + case PORT_HDR_PROP_POWER_STATE: + return port_get_power_state(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_get_userclk_freqcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_get_userclk_freqcntrcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQSTS: + return port_get_userclk_freqsts(port, &prop->data); + case PORT_HDR_PROP_USERCLK_CNTRSTS: + return port_get_userclk_freqcntrsts(port, &prop->data); + } + + return -ENOENT; +} + +static int port_hdr_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_AP1_EVENT: + return port_set_ap1_event(port, prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_set_ap2_event(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_set_userclk_freqcmd(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_set_userclk_freqcntrcmd(port, prop->data); + } + + return -ENOENT; +} + +struct feature_ops 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) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port stp Init.\n"); + + spinlock_lock(&port->lock); + port->stp_addr = feature->addr; + port->stp_size = feature->size; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_stp_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port stp uinit.\n"); +} + +struct feature_ops port_stp_ops = { + .init = port_stp_init, + .uinit = port_stp_uinit, +}; + +static int port_uint_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "PORT UINT Init.\n"); + + spinlock_lock(&port->lock); + if (feature->ctx_num) { + port->capability |= FPGA_PORT_CAP_UAFU_IRQ; + port->num_uafu_irqs = feature->ctx_num; + } + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_uint_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT UINT UInit.\n"); +} + +static int port_uint_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_uafu_irq_set *uafu_irq_set = irq_set; + struct ifpga_port_hw *port = feature->parent; + int ret; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_UAFU_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, uafu_irq_set->start, + uafu_irq_set->count, uafu_irq_set->evtfds); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_uint_ops = { + .init = port_uint_init, + .uinit = port_uint_uinit, + .set_irq = port_uint_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c new file mode 100644 index 0000000..100009e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c @@ -0,0 +1,192 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "ifpga_feature_dev.h" + +static int port_err_get_revision(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_header header; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + header.csr = readq(&port_err->header); + *val = header.revision; + + return 0; +} + +static int port_err_get_errors(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + *val = error.csr; + + return 0; +} + +static int port_err_get_first_error(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_first_err_key first_error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + first_error.csr = readq(&port_err->port_first_error); + *val = first_error.csr; + + return 0; +} + +static int port_err_get_first_malformed_req_lsb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req0 malreq0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq0.header_lsb = readq(&port_err->malreq0); + *val = malreq0.header_lsb; + + return 0; +} + +static int port_err_get_first_malformed_req_msb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req1 malreq1; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq1.header_msb = readq(&port_err->malreq1); + *val = malreq1.header_msb; + + return 0; +} + +static int port_err_set_clear(struct ifpga_port_hw *port, u64 val) +{ + int ret; + + spinlock_lock(&port->lock); + ret = port_err_clear(port, val); + spinlock_unlock(&port->lock); + + return ret; +} + +static int port_error_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port error Init.\n"); + + spinlock_lock(&port->lock); + port_err_mask(port, false); + if (feature->ctx_num) + port->capability |= FPGA_PORT_CAP_ERR_IRQ; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int port_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_ERR_PROP_REVISION: + return port_err_get_revision(port, &prop->data); + case PORT_ERR_PROP_ERRORS: + return port_err_get_errors(port, &prop->data); + case PORT_ERR_PROP_FIRST_ERROR: + return port_err_get_first_error(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB: + return port_err_get_first_malformed_req_lsb(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB: + return port_err_get_first_malformed_req_msb(port, &prop->data); + } + + return -ENOENT; +} + +static int port_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + if (prop->prop_id == PORT_ERR_PROP_CLEAR) + return port_err_set_clear(port, prop->data); + + return -ENOENT; +} + +static int port_error_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_port_err_irq_set *err_irq_set = irq_set; + struct ifpga_port_hw *port; + int ret; + + port = feature->parent; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_ERR_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_error_ops = { + .init = port_error_init, + .uinit = port_error_uinit, + .get_prop = port_error_get_prop, + .set_prop = port_error_set_prop, + .set_irq = port_error_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.c b/drivers/raw/ifpga_rawdev/base/opae_debug.c new file mode 100644 index 0000000..07935e7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.c @@ -0,0 +1,126 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#define OPAE_HW_DEBUG + +#include "opae_hw_api.h" +#include "opae_debug.h" + +void opae_manager_dump(struct opae_manager *mgr) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Manger %s\n", mgr->name); + opae_log("OPAE Manger OPs = %p\n", mgr->ops); + opae_log("OPAE Manager Private Data = %p\n", mgr->data); + opae_log("OPAE Adapter(parent) = %p\n", mgr->adapter); + opae_log("==========================\n"); +} + +void opae_bridge_dump(struct opae_bridge *br) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Bridge %s\n", br->name); + opae_log("OPAE Bridge ID = %d\n", br->id); + opae_log("OPAE Bridge OPs = %p\n", br->ops); + opae_log("OPAE Bridge Private Data = %p\n", br->data); + opae_log("OPAE Accelerator(under this bridge) = %p\n", br->acc); + opae_log("==========================\n"); +} + +void opae_accelerator_dump(struct opae_accelerator *acc) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Accelerator %s\n", acc->name); + opae_log("OPAE Accelerator Index = %d\n", acc->index); + opae_log("OPAE Accelerator OPs = %p\n", acc->ops); + opae_log("OPAE Accelerator Private Data = %p\n", acc->data); + opae_log("OPAE Bridge (upstream) = %p\n", acc->br); + opae_log("OPAE Manager (upstream) = %p\n", acc->mgr); + opae_log("==========================\n"); + + if (acc->br) + opae_bridge_dump(acc->br); +} + +static void opae_adapter_data_dump(void *data) +{ + struct opae_adapter_data *d = data; + struct opae_adapter_data_pci *d_pci; + struct opae_reg_region *r; + int i; + + opae_log("=====%s=====\n", __func__); + + switch (d->type) { + case OPAE_FPGA_PCI: + d_pci = (struct opae_adapter_data_pci *)d; + + opae_log("OPAE Adapter Type = PCI\n"); + opae_log("PCI Device ID: 0x%04x\n", d_pci->device_id); + opae_log("PCI Vendor ID: 0x%04x\n", d_pci->vendor_id); + + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + r = &d_pci->region[i]; + opae_log("PCI Bar %d: phy(%llx) len(%llx) addr(%p)\n", + i, (unsigned long long)r->phys_addr, + (unsigned long long)r->len, r->addr); + } + break; + case OPAE_FPGA_NET: + break; + } + + opae_log("==========================\n"); +} + +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) { + if (adapter->mgr) + opae_manager_dump(adapter->mgr); + + opae_adapter_for_each_acc(adapter, acc) + opae_accelerator_dump(acc); + + if (adapter->data) + opae_adapter_data_dump(adapter->data); + } + + opae_log("==========================\n"); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.h b/drivers/raw/ifpga_rawdev/base/opae_debug.h new file mode 100644 index 0000000..ceddf9d --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.h @@ -0,0 +1,46 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_DEBUG_H_ +#define _OPAE_DEBUG_H_ + +#ifdef OPAE_HW_DEBUG +#define opae_log(fmt, args...) printf(fmt, ## args) +#else +#define opae_log(fme, args...) do {} while (0) +#endif + +void opae_manager_dump(struct opae_manager *mgr); +void opae_bridge_dump(struct opae_bridge *br); +void opae_accelerator_dump(struct opae_accelerator *acc); +void opae_adapter_dump(struct opae_adapter *adapter, int verbose); + +#endif /* _OPAE_DEBUG_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c new file mode 100644 index 0000000..7fb90c5 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -0,0 +1,408 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "opae_hw_api.h" +#include "opae_debug.h" +#include "ifpga_api.h" + +/* OPAE Bridge Functions */ + +/** + * opae_bridge_alloc - alloc opae_bridge data structure + * @name: bridge name. + * @ops: ops of this bridge. + * @data: private data of this bridge. + * + * Return opae_bridge on success, otherwise NULL. + */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data) +{ + struct opae_bridge *br = opae_zmalloc(sizeof(*br)); + + if (!br) + return NULL; + + br->name = name; + br->ops = ops; + br->data = data; + + opae_log("%s %p\n", __func__, br); + + return br; +} + +/** + * opae_bridge_reset - reset opae_bridge + * @br: bridge to be reset. + * + * Return: 0 on success, otherwise error code. + */ +int opae_bridge_reset(struct opae_bridge *br) +{ + if (!br) + return -EINVAL; + + if (br->ops && br->ops->reset) + return br->ops->reset(br); + + opae_log("%s no ops\n", __func__); + + return -ENOENT; +} + +/* Accelerator Functions */ + +/** + * opae_accelerator_alloc - alloc opae_accelerator data structure + * @name: accelerator name. + * @ops: ops of this accelerator. + * @data: private data of this accelerator. + * + * Return: opae_accelerator on success, otherwise NULL. + */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data) +{ + struct opae_accelerator *acc = opae_zmalloc(sizeof(*acc)); + + if (!acc) + return NULL; + + acc->name = name; + acc->ops = ops; + acc->data = data; + + opae_log("%s %p\n", __func__, acc); + + return acc; +} + +/** + * opae_acc_reg_read - read accelerator's register from its reg region. + * @acc: accelerator to read. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: read operation width, e.g 4 byte = 32bit read. + * @data: data to store the value read from the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->read) + return acc->ops->read(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_reg_write - write to accelerator's register from its reg region. + * @acc: accelerator to write. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: write operation width, e.g 4 byte = 32bit write. + * @data: data stored the value to write to the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->write) + return acc->ops->write(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_get_info - get information of an accelerator. + * @acc: targeted accelerator + * @info: accelerator info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_info) + return acc->ops->get_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_get_region_info - get information of an accelerator register region. + * @acc: targeted accelerator + * @info: accelerator region info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_region_info) + return acc->ops->get_region_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_set_irq - set an accelerator's irq. + * @acc: targeted accelerator + * @start: start vector number + * @count: count of vectors to be set from the start vector + * @evtfds: event fds to be notified when corresponding irqs happens + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + if (!acc || !acc->data) + return -EINVAL; + + if (start + count <= start) + return -EINVAL; + + if (acc->ops && acc->ops->set_irq) + return acc->ops->set_irq(acc, start, count, evtfds); + + return -ENOENT; +} + +/** + * opae_acc_get_uuid - get accelerator's UUID. + * @acc: targeted accelerator + * @uuid: a pointer to UUID + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + if (!acc || !uuid) + return -EINVAL; + + if (acc->ops && acc->ops->get_uuid) + return acc->ops->get_uuid(acc, uuid); + + return -ENOENT; +} + +/* Manager Functions */ + +/** + * opae_manager_alloc - alloc opae_manager data structure + * @name: manager name. + * @ops: ops of this manager. + * @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) +{ + struct opae_manager *mgr = opae_zmalloc(sizeof(*mgr)); + + if (!mgr) + return NULL; + + mgr->name = name; + mgr->ops = ops; + mgr->data = data; + + opae_log("%s %p\n", __func__, mgr); + + return mgr; +} + +/** + * opae_manager_flash - flash a reconfiguration image via opae_manager + * @mgr: opae_manager for flash. + * @id: id of target region (accelerator). + * @buf: image data buffer. + * @size: buffer size. + * @status: status to store flash result. + * + * Return: 0 on success, otherwise error code. + */ +int opae_manager_flash(struct opae_manager *mgr, int id, void *buf, u32 size, + u64 *status) +{ + if (!mgr) + return -EINVAL; + + if (mgr && mgr->ops && mgr->ops->flash) + return mgr->ops->flash(mgr, id, buf, size, status); + + return -ENOENT; +} + +/* Adapter Functions */ + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @type: opae_adapter_type. + * + * Return: opae_adapter_data on success, otherwise NULL. + */ +void *opae_adapter_data_alloc(enum opae_adapter_type type) +{ + struct opae_adapter_data *data; + int size; + + switch (type) { + case OPAE_FPGA_PCI: + size = sizeof(struct opae_adapter_data_pci); + break; + case OPAE_FPGA_NET: + size = sizeof(struct opae_adapter_data_net); + break; + default: + size = sizeof(struct opae_adapter_data); + break; + } + + data = opae_zmalloc(size); + if (!data) + return NULL; + + data->type = type; + + return data; +} + +static struct opae_adapter_ops *match_ops(struct opae_adapter *adapter) +{ + struct opae_adapter_data *data; + + if (!adapter || !adapter->data) + return NULL; + + data = adapter->data; + + if (data->type == OPAE_FPGA_PCI) + return &ifpga_adapter_ops; + + return NULL; +} + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @name: adapter name. + * @data: private data of this adapter. + * + * Return: opae_adapter on success, otherwise NULL. + */ +struct opae_adapter *opae_adapter_alloc(const char *name, void *data) +{ + struct opae_adapter *adapter = opae_zmalloc(sizeof(*adapter)); + + if (!adapter) + return NULL; + + TAILQ_INIT(&adapter->acc_list); + adapter->data = data; + adapter->name = name; + adapter->ops = match_ops(adapter); + + return adapter; +} + +/** + * opae_adapter_enumerate - enumerate this adapter + * @adapter: adapter to enumerate. + * + * Return: 0 on success, otherwise error code. + */ +int opae_adapter_enumerate(struct opae_adapter *adapter) +{ + int ret = -ENOENT; + + if (!adapter) + return -EINVAL; + + if (adapter->ops && adapter->ops->enumerate) + ret = adapter->ops->enumerate(adapter); + + if (!ret) + opae_adapter_dump(adapter, 1); + + return ret; +} + +/** + * opae_adapter_destroy - destroy this adapter + * @adapter: adapter to destroy. + * + * destroy things allocated during adapter enumeration. + */ +void opae_adapter_destroy(struct opae_adapter *adapter) +{ + if (adapter && adapter->ops && adapter->ops->destroy) + adapter->ops->destroy(adapter); +} + +/** + * opae_adapter_get_acc - find and return accelerator with matched id + * @adapter: adapter to find the accelerator. + * @acc_id: id (index) of the accelerator. + * + * destroy things allocated during adapter enumeration. + */ +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id) +{ + struct opae_accelerator *acc = NULL; + + if (!adapter) + return NULL; + + opae_adapter_for_each_acc(adapter, acc) + if (acc->index == acc_id) + return acc; + + return NULL; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h new file mode 100644 index 0000000..6b5300f --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -0,0 +1,280 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_HW_API_H_ +#define _OPAE_HW_API_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> + +#include "opae_osdep.h" + +#ifndef PCI_MAX_RESOURCE +#define PCI_MAX_RESOURCE 6 +#endif + +struct opae_adapter; + +enum opae_adapter_type { + OPAE_FPGA_PCI, + OPAE_FPGA_NET, +}; + +/* OPAE Manager Data Structure */ +struct opae_manager_ops; + +/* + * opae_manager has pointer to its parent adapter, as it could be able to manage + * all components on this FPGA device (adapter). If not the case, don't set this + * adapter, which limit opae_manager ops to manager itself. + */ +struct opae_manager { + const char *name; + struct opae_adapter *adapter; + struct opae_manager_ops *ops; + void *data; +}; + +/* FIXME: add more management ops, e.g power/thermal and etc */ +struct opae_manager_ops { + int (*flash)(struct opae_manager *mgr, int id, void *buffer, + u32 size, u64 *status); +}; + +/* OPAE Manager APIs */ +struct opae_manager * +opae_manager_alloc(const char *name, struct opae_manager_ops *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); + +/* OPAE Bridge Data Structure */ +struct opae_bridge_ops; + +/* + * opae_bridge only has pointer to its downstream accelerator. + */ +struct opae_bridge { + const char *name; + int id; + struct opae_accelerator *acc; + struct opae_bridge_ops *ops; + void *data; +}; + +struct opae_bridge_ops { + int (*reset)(struct opae_bridge *br); +}; + +/* OPAE Bridge APIs */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data); +int opae_bridge_reset(struct opae_bridge *br); +#define opae_bridge_free(br) opae_free(br) + +/* OPAE Acceleraotr Data Structure */ +struct opae_accelerator_ops; + +/* + * opae_accelerator has pointer to its upstream bridge(port). + * In some cases, if we allow same user to do PR on its own accelerator, then + * set the manager pointer during the enumeration. But in other cases, the PR + * functions only could be done via manager in another module / thread / service + * / application for better protection. + */ +struct opae_accelerator { + TAILQ_ENTRY(opae_accelerator) node; + const char *name; + int index; + struct opae_bridge *br; + struct opae_manager *mgr; + struct opae_accelerator_ops *ops; + void *data; +}; + +struct opae_acc_info { + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct opae_acc_region_info { + u32 flags; +#define ACC_REGION_READ (1 << 0) +#define ACC_REGION_WRITE (1 << 1) +#define ACC_REGION_MMIO (1 << 2) + u32 index; + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_accelerator_ops { + int (*read)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*write)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*get_info)(struct opae_accelerator *acc, + struct opae_acc_info *info); + int (*get_region_info)(struct opae_accelerator *acc, + struct opae_acc_region_info *info); + int (*set_irq)(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); + int (*get_uuid)(struct opae_accelerator *acc, + struct uuid *uuid); +}; + +/* OPAE accelerator APIs */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data); +#define opae_accelerator_free(acc) opae_free(acc) +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info); +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info); +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid); + +static inline struct opae_bridge * +opae_acc_get_br(struct opae_accelerator *acc) +{ + return acc ? acc->br : NULL; +} + +static inline struct opae_manager * +opae_acc_get_mgr(struct opae_accelerator *acc) +{ + return acc ? acc->mgr : NULL; +} + +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + +#define opae_acc_reg_read64(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 8, data) +#define opae_acc_reg_write64(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 8, data) +#define opae_acc_reg_read32(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 4, data) +#define opae_acc_reg_write32(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 4, data) +#define opae_acc_reg_read16(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 2, data) +#define opae_acc_reg_write16(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 2, data) +#define opae_acc_reg_read8(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 1, data) +#define opae_acc_reg_write8(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 1, data) + +/*for data stream read/write*/ +int opae_acc_data_read(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); +int opae_acc_data_write(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); + +/* OPAE Adapter Data Structure */ +struct opae_adapter_data { + enum opae_adapter_type type; +}; + +struct opae_reg_region { + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_adapter_data_pci { + enum opae_adapter_type type; + u16 device_id; + u16 vendor_id; + struct opae_reg_region region[PCI_MAX_RESOURCE]; + int vfio_dev_fd; /* VFIO device file descriptor */ +}; + +/* FIXME: OPAE_FPGA_NET type */ +struct opae_adapter_data_net { + enum opae_adapter_type type; +}; + +struct opae_adapter_ops { + int (*enumerate)(struct opae_adapter *adapter); + void (*destroy)(struct opae_adapter *adapter); +}; + +TAILQ_HEAD(opae_accelerator_list, opae_accelerator); + +#define opae_adapter_for_each_acc(adatper, acc) \ + TAILQ_FOREACH(acc, &adapter->acc_list, node) + +struct opae_adapter { + const char *name; + struct opae_manager *mgr; + struct opae_accelerator_list acc_list; + struct opae_adapter_ops *ops; + void *data; +}; + +/* OPAE Adapter APIs */ +void *opae_adapter_data_alloc(enum opae_adapter_type type); +#define opae_adapter_data_free(data) opae_free(data) + +struct opae_adapter *opae_adapter_alloc(const char *name, void *data); +#define opae_adapter_free(adapter) opae_free(adapter) + +int opae_adapter_enumerate(struct opae_adapter *adapter); +void opae_adapter_destroy(struct opae_adapter *adapter); +static inline struct opae_manager * +opae_adapter_get_mgr(struct opae_adapter *adapter) +{ + return adapter ? adapter->mgr : NULL; +} + +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id); + +static inline void opae_adapter_add_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_INSERT_TAIL(&adapter->acc_list, acc, node); +} + +static inline void opae_adapter_remove_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_REMOVE(&adapter->acc_list, acc, node); +} +#endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c new file mode 100644 index 0000000..1dd54d9 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c @@ -0,0 +1,172 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "opae_ifpga_hw_api.h" +#include "ifpga_api.h" + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data || !fme_info) + return -EINVAL; + + fme = mgr->data; + + spinlock_lock(&fme->lock); + fme_info->capability = fme->capability; + spinlock_unlock(&fme->lock); + + return 0; +} + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_irq(fme->parent, FEATURE_FIU_ID_FME, 0, + IFPGA_FME_FEATURE_ID_GLOBAL_ERR, err_irq_set); +} + +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_get_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !port_info) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + port_info->capability = port->capability; + port_info->num_uafu_irqs = port->num_uafu_irqs; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !info) + return -EINVAL; + + /* Only support STP region now */ + if (info->index != PORT_REGION_INDEX_STP) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + info->addr = (u64)port->stp_addr; + info->size = port->stp_size; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_ERROR, err_irq_set); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h new file mode 100644 index 0000000..20e114c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h @@ -0,0 +1,306 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_IFPGA_HW_API_H_ +#define _OPAE_IFPGA_HW_API_H_ + +#include "opae_hw_api.h" + +/** + * struct feature_prop - data structure for feature property + * @feature_id: id of this feature. + * @prop_id: id of this property under this feature. + * @data: property value to set/get. + */ +struct feature_prop { + u64 feature_id; + u64 prop_id; + u64 data; +}; + +#define IFPGA_FIU_ID_FME 0x0 +#define IFPGA_FIU_ID_PORT 0x1 + +#define IFPGA_FME_FEATURE_ID_HEADER 0x0 +#define IFPGA_FME_FEATURE_ID_THERMAL_MGMT 0x1 +#define IFPGA_FME_FEATURE_ID_POWER_MGMT 0x2 +#define IFPGA_FME_FEATURE_ID_GLOBAL_IPERF 0x3 +#define IFPGA_FME_FEATURE_ID_GLOBAL_ERR 0x4 +#define IFPGA_FME_FEATURE_ID_PR_MGMT 0x5 +#define IFPGA_FME_FEATURE_ID_HSSI 0x6 +#define IFPGA_FME_FEATURE_ID_GLOBAL_DPERF 0x7 + +#define IFPGA_PORT_FEATURE_ID_HEADER 0x0 +#define IFPGA_PORT_FEATURE_ID_AFU 0xff +#define IFPGA_PORT_FEATURE_ID_ERROR 0x10 +#define IFPGA_PORT_FEATURE_ID_UMSG 0x11 +#define IFPGA_PORT_FEATURE_ID_UINT 0x12 +#define IFPGA_PORT_FEATURE_ID_STP 0x13 + +/* + * PROP format (TOP + SUB + ID) + * + * (~0x0) means this field is unused. + */ +#define PROP_TOP GENMASK(31, 24) +#define PROP_TOP_UNUSED 0xff +#define PROP_SUB GENMASK(23, 16) +#define PROP_SUB_UNUSED 0xff +#define PROP_ID GENMASK(15, 0) + +#define PROP(_top, _sub, _id) \ + (SET_FIELD(PROP_TOP, _top) | SET_FIELD(PROP_SUB, _sub) |\ + SET_FIELD(PROP_ID, _id)) + +/* FME head feature's properties*/ +#define FME_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define FME_HDR_PROP_PORTS_NUM 0x2 /* RDONLY */ +#define FME_HDR_PROP_CACHE_SIZE 0x3 /* RDONLY */ +#define FME_HDR_PROP_VERSION 0x4 /* RDONLY */ +#define FME_HDR_PROP_SOCKET_ID 0x5 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_ID 0x6 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_METADATA 0x7 /* RDONLY */ + +/* FME error reporting feature's properties */ +/* FME error reporting properties format */ +#define ERR_PROP(_top, _id) PROP(_top, 0xff, _id) +#define ERR_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define ERR_PROP_TOP_FME_ERR 0x1 +#define ERR_PROP_ROOT(_id) ERR_PROP(0xff, _id) +#define ERR_PROP_FME_ERR(_id) ERR_PROP(ERR_PROP_TOP_FME_ERR, _id) + +#define FME_ERR_PROP_ERRORS ERR_PROP_FME_ERR(0x1) +#define FME_ERR_PROP_FIRST_ERROR ERR_PROP_FME_ERR(0x2) +#define FME_ERR_PROP_NEXT_ERROR ERR_PROP_FME_ERR(0x3) +#define FME_ERR_PROP_CLEAR ERR_PROP_FME_ERR(0x4) /* WO */ +#define FME_ERR_PROP_REVISION ERR_PROP_ROOT(0x5) +#define FME_ERR_PROP_PCIE0_ERRORS ERR_PROP_ROOT(0x6) /* RW */ +#define FME_ERR_PROP_PCIE1_ERRORS ERR_PROP_ROOT(0x7) /* RW */ +#define FME_ERR_PROP_NONFATAL_ERRORS ERR_PROP_ROOT(0x8) +#define FME_ERR_PROP_CATFATAL_ERRORS ERR_PROP_ROOT(0x9) +#define FME_ERR_PROP_INJECT_ERRORS ERR_PROP_ROOT(0xa) /* RW */ + +/* FME thermal feature's properties */ +#define FME_THERMAL_PROP_THRESHOLD1 0x1 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD2 0x2 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD_TRIP 0x3 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_REACHED 0x4 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD2_REACHED 0x5 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_POLICY 0x6 /* RW */ +#define FME_THERMAL_PROP_TEMPERATURE 0x7 /* RDONLY */ +#define FME_THERMAL_PROP_REVISION 0x8 /* RDONLY */ + +/* FME power feature's properties */ +#define FME_PWR_PROP_CONSUMED 0x1 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD1 0x2 /* RW */ +#define FME_PWR_PROP_THRESHOLD2 0x3 /* RW */ +#define FME_PWR_PROP_THRESHOLD1_STATUS 0x4 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD2_STATUS 0x5 /* RDONLY */ +#define FME_PWR_PROP_RTL 0x6 /* RDONLY */ +#define FME_PWR_PROP_XEON_LIMIT 0x7 /* RDONLY */ +#define FME_PWR_PROP_FPGA_LIMIT 0x8 /* RDONLY */ +#define FME_PWR_PROP_REVISION 0x9 /* RDONLY */ + +/* FME iperf/dperf PROP format */ +#define PERF_PROP_TOP_CACHE 0x1 +#define PERF_PROP_TOP_VTD 0x2 +#define PERF_PROP_TOP_FAB 0x3 +#define PERF_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define PERF_PROP_SUB_UNUSED PROP_SUB_UNUSED + +#define PERF_PROP_ROOT(_id) PROP(0xff, 0xff, _id) +#define PERF_PROP_CACHE(_id) PROP(PERF_PROP_TOP_CACHE, 0xff, _id) +#define PERF_PROP_VTD(_sub, _id) PROP(PERF_PROP_TOP_VTD, _sub, _id) +#define PERF_PROP_VTD_ROOT(_id) PROP(PERF_PROP_TOP_VTD, 0xff, _id) +#define PERF_PROP_FAB(_sub, _id) PROP(PERF_PROP_TOP_FAB, _sub, _id) +#define PERF_PROP_FAB_ROOT(_id) PROP(PERF_PROP_TOP_FAB, 0xff, _id) + +/* FME iperf feature's properties */ +#define FME_IPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_IPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* iperf CACHE properties */ +#define FME_IPERF_PROP_CACHE_FREEZE PERF_PROP_CACHE(0x1) /* RW */ +#define FME_IPERF_PROP_CACHE_READ_HIT PERF_PROP_CACHE(0x2) +#define FME_IPERF_PROP_CACHE_READ_MISS PERF_PROP_CACHE(0x3) +#define FME_IPERF_PROP_CACHE_WRITE_HIT PERF_PROP_CACHE(0x4) +#define FME_IPERF_PROP_CACHE_WRITE_MISS PERF_PROP_CACHE(0x5) +#define FME_IPERF_PROP_CACHE_HOLD_REQUEST PERF_PROP_CACHE(0x6) +#define FME_IPERF_PROP_CACHE_TX_REQ_STALL PERF_PROP_CACHE(0x7) +#define FME_IPERF_PROP_CACHE_RX_REQ_STALL PERF_PROP_CACHE(0x8) +#define FME_IPERF_PROP_CACHE_RX_EVICTION PERF_PROP_CACHE(0x9) +#define FME_IPERF_PROP_CACHE_DATA_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xa) +#define FME_IPERF_PROP_CACHE_TAG_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xb) +/* iperf VTD properties */ +#define FME_IPERF_PROP_VTD_FREEZE PERF_PROP_VTD_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_HIT PERF_PROP_VTD_ROOT(0x2) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_HIT PERF_PROP_VTD_ROOT(0x3) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_HIT PERF_PROP_VTD_ROOT(0x4) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_HIT PERF_PROP_VTD_ROOT(0x5) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_HIT PERF_PROP_VTD_ROOT(0x6) +#define FME_IPERF_PROP_VTD_SIP_RCC_HIT PERF_PROP_VTD_ROOT(0x7) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_MISS PERF_PROP_VTD_ROOT(0x8) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_MISS PERF_PROP_VTD_ROOT(0x9) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_MISS PERF_PROP_VTD_ROOT(0xa) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_MISS PERF_PROP_VTD_ROOT(0xb) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_MISS PERF_PROP_VTD_ROOT(0xc) +#define FME_IPERF_PROP_VTD_SIP_RCC_MISS PERF_PROP_VTD_ROOT(0xd) +#define FME_IPERF_PROP_VTD_PORT_READ_TRANSACTION(n) PERF_PROP_VTD(n, 0xe) +#define FME_IPERF_PROP_VTD_PORT_WRITE_TRANSACTION(n) PERF_PROP_VTD(n, 0xf) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_READ_HIT(n) PERF_PROP_VTD(n, 0x10) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_WRITE_HIT(n) PERF_PROP_VTD(n, 0x11) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_4K_FILL(n) PERF_PROP_VTD(n, 0x12) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_2M_FILL(n) PERF_PROP_VTD(n, 0x13) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_1G_FILL(n) PERF_PROP_VTD(n, 0x14) +/* iperf FAB properties */ +#define FME_IPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_IPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_IPERF_PROP_FAB_PCIE1_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_IPERF_PROP_FAB_PCIE1_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_IPERF_PROP_FAB_UPI_READ PERF_PROP_FAB_ROOT(0x6) +#define FME_IPERF_PROP_FAB_PORT_UPI_READ(n) PERF_PROP_FAB(n, 0x6) +#define FME_IPERF_PROP_FAB_UPI_WRITE PERF_PROP_FAB_ROOT(0x7) +#define FME_IPERF_PROP_FAB_PORT_UPI_WRITE(n) PERF_PROP_FAB(n, 0x7) +#define FME_IPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x8) +#define FME_IPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x8) +#define FME_IPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x9) +#define FME_IPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x9) +#define FME_IPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0xa) /* RW */ +#define FME_IPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0xa) /* RW */ + +/* FME dperf properties */ +#define FME_DPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_DPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* dperf FAB properties */ +#define FME_DPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_DPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_DPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_DPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_DPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_DPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_DPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_DPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0x6) /* RW */ +#define FME_DPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0x6) /* RW */ + +/*PORT hdr feature's properties*/ +#define PORT_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_HDR_PROP_PORTIDX 0x2 /* RDONLY */ +#define PORT_HDR_PROP_LATENCY_TOLERANCE 0x3 /* RDONLY */ +#define PORT_HDR_PROP_AP1_EVENT 0x4 /* RW */ +#define PORT_HDR_PROP_AP2_EVENT 0x5 /* RW */ +#define PORT_HDR_PROP_POWER_STATE 0x6 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_FREQCMD 0x7 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQCNTRCMD 0x8 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQSTS 0x9 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_CNTRSTS 0xa /* RDONLY */ + +/*PORT error feature's properties*/ +#define PORT_ERR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_ERR_PROP_ERRORS 0x2 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_ERROR 0x3 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB 0x4 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB 0x5 /* RDONLY */ +#define PORT_ERR_PROP_CLEAR 0x6 /* WRONLY */ + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop); +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop); + +/* + * Retrieve information about the fpga fme. + * Driver fills the info in provided struct fpga_fme_info. + */ +struct fpga_fme_info { + u32 capability; /* The capability of FME device */ +#define FPGA_FME_CAP_ERR_IRQ (1 << 0) /* Support fme error interrupt */ +}; + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info); + +/* Set eventfd information for ifpga FME error interrupt */ +struct fpga_fme_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set); + +/* + * Retrieve information about the fpga port. + * Driver fills the info in provided struct fpga_port_info. + */ +struct fpga_port_info { + u32 capability; /* The capability of port device */ +#define FPGA_PORT_CAP_ERR_IRQ (1 << 0) /* Support port error interrupt */ +#define FPGA_PORT_CAP_UAFU_IRQ (1 << 1) /* Support uafu error interrupt */ + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ +}; + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info); +/* + * Retrieve region information about the fpga port. + * Driver needs to fill the index of struct fpga_port_region_info. + */ +struct fpga_port_region_info { + u32 index; +#define PORT_REGION_INDEX_STP (1 << 1) /* Signal Tap Region */ + u64 size; /* Region Size */ + u64 addr; /* Base address of the region */ +}; + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info); + +/* Set eventfd information for ifpga port error interrupt */ +struct fpga_port_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set); + +#endif /* _OPAE_IFPGA_HW_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h new file mode 100644 index 0000000..6557623 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -0,0 +1,115 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OPAE_OSDEP_H +#define _OPAE_OSDEP_H + +#include <string.h> +#include <stdbool.h> + +#ifdef RTE_LIBRTE_EAL +#include "osdep_rte/osdep_generic.h" +#else +#include "osdep_raw/osdep_generic.h" +#endif + +#include <asm/types.h> + +#define __iomem + +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef uint64_t dma_addr_t; + +struct uuid { + u8 b[16]; +}; + +#ifndef LINUX_MACROS +#ifndef BITS_PER_LONG +#define BITS_PER_LONG (__SIZEOF_LONG__ * 8) +#endif +#ifndef BIT +#define BIT(a) (1UL << (a)) +#endif /* BIT */ +#ifndef BIT_ULL +#define BIT_ULL(a) (1ULL << (a)) +#endif /* BIT_ULL */ +#ifndef GENMASK +#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#endif /* GENMASK */ +#ifndef GENMASK_ULL +#define GENMASK_ULL(h, l) (((U64_C(1) << ((h) - (l) + 1)) - 1) << (l)) +#endif /* GENMASK_ULL */ +#endif /* LINUX_MACROS */ + +#define SET_FIELD(m, v) (((v) << (__builtin_ffsll(m) - 1)) & (m)) +#define GET_FIELD(m, v) (((v) & (m)) >> (__builtin_ffsll(m) - 1)) + +#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) +#define pr_info(y, args...) dev_info(0, y, ##args) +#define BUG() pr_err("BUG at %s:%d", __func__, __LINE__) + +#define ASSERT(x) do {\ + if (!(x)) \ + osdep_panic("osdep_panic: x"); \ +} while (0) +#define BUG_ON(x) ASSERT(!(x)) + +#ifndef WARN_ON +#define WARN_ON(x) do { \ + int ret = !!(x); \ + if (unlikely(ret)) \ + pr_warn("WARN_ON: \"" #x "\" at %s:%d\n", __func__, __LINE__); \ +} while (0) +#endif + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define udelay(x) opae_udelay(x) +#define msleep(x) opae_udelay(1000 * (x)) +#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000)) + +#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 new file mode 100644 index 0000000..12ad018 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h @@ -0,0 +1,104 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OSDEP_RAW_GENERIC_H +#define _OSDEP_RAW_GENERIC_H + +#define compiler_barrier() do { \ + asm volatile ("" : : : "memory"); \ +} while (0) + +#define io_wmb() compiler_barrier() +#define io_rmb() compiler_barrier() + +static inline uint8_t opae_readb(const volatile void *addr) +{ + uint8_t val; + + val = *(const volatile uint8_t *)addr; + io_rmb(); + return val; +} + +static inline uint16_t opae_readw(const volatile void *addr) +{ + uint16_t val; + + val = *(const volatile uint16_t *)addr; + io_rmb(); + return val; +} + +static inline uint32_t opae_readl(const volatile void *addr) +{ + uint32_t val; + + val = *(const volatile uint32_t *)addr; + io_rmb(); + return val; +} + +static inline uint64_t opae_readq(const volatile void *addr) +{ + uint64_t val; + + val = *(const volatile uint64_t *)addr; + io_rmb(); + return val; +} + +static inline void opae_writeb(uint8_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint8_t *)addr = value; +} + +static inline void opae_writew(uint16_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint16_t *)addr = value; +} + +static inline void opae_writel(uint32_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint32_t *)addr = value; +} + +static inline void opae_writeq(uint64_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint64_t *)addr = value; +} + +#define opae_free(addr) free(addr) + +#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 new file mode 100644 index 0000000..9ff580e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h @@ -0,0 +1,72 @@ +/******************************************************************************* + * + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#ifndef _OSDEP_RTE_GENERIC_H +#define _OSDEP_RTE_GENERIC_H + +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_spinlock.h> +#include <rte_log.h> +#include <rte_io.h> +#include <rte_malloc.h> + +#define dev_printf(level, fmt, args...) \ + RTE_LOG(level, PMD, "osdep_rte: " fmt, ## args) + +#define osdep_panic(...) rte_panic(...) + +#define opae_udelay(x) rte_delay_us(x) + +#define opae_readb(addr) rte_read8(addr) +#define opae_readw(addr) rte_read16(addr) +#define opae_readl(addr) rte_read32(addr) +#define opae_readq(addr) rte_read64(addr) +#define opae_writeb(value, addr) rte_write8(value, addr) +#define opae_writew(value, addr) rte_write16(value, addr) +#define opae_writel(value, addr) rte_write32(value, addr) +#define opae_writeq(value, addr) rte_write64(value, addr) + +#define opae_malloc(size) rte_malloc(NULL, size, 0) +#define opae_zmalloc(size) rte_zmalloc(NULL, size, 0) +#define opae_free(addr) rte_free(addr) + +#define ARRAY_SIZE(arr) RTE_DIM(arr) + +#define min(a, b) RTE_MIN(a, b) +#define max(a, b) RTE_MAX(a, b) + +#define spinlock_t rte_spinlock_t +#define spinlock_init(x) rte_spinlock_init(x) +#define spinlock_lock(x) rte_spinlock_lock(x) +#define spinlock_unlock(x) rte_spinlock_unlock(x) + +#endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v5 3/3] Add Intel FPGA OPAE Share Code 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 3/3] Add Intel FPGA OPAE Share Code Rosen Xu @ 2018-04-04 11:59 ` Hemant Agrawal 2018-04-26 10:45 ` Xu, Rosen 0 siblings, 1 reply; 149+ messages in thread From: Hemant Agrawal @ 2018-04-04 11:59 UTC (permalink / raw) To: Rosen Xu, dev, bruce.richardson Cc: declan.doherty, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet, Xu, Yilun Hi Rosen/Bruce, On 4/4/2018 12:21 PM, Rosen Xu wrote: > +++ b/drivers/raw/ifpga_rawdev/base/Makefile > @@ -0,0 +1,54 @@ > +# BSD LICENSE > +# > +# Copyright(c) 2017-2018 Intel Corporation. All rights reserved. > +# All rights reserved. > +# > +# Redistribution and use in source and binary forms, with or without > +# modification, are permitted provided that the following conditions > +# are met: > +# > +# * Redistributions of source code must retain the above copyright > +# notice, this list of conditions and the following disclaimer. > +# * Redistributions in binary form must reproduce the above copyright > +# notice, this list of conditions and the following disclaimer in > +# the documentation and/or other materials provided with the > +# distribution. > +# * Neither the name of Intel Corporation nor the names of its > +# contributors may be used to endorse or promote products derived > +# from this software without specific prior written permission. > +# > +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. These files are adding the full license boiler plate. What is your plan to change it to SPDX? Bruce, may be your script can help Rosen to do it faster. Regards, Hemant ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v5 3/3] Add Intel FPGA OPAE Share Code 2018-04-04 11:59 ` Hemant Agrawal @ 2018-04-26 10:45 ` Xu, Rosen 0 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-04-26 10:45 UTC (permalink / raw) To: Hemant Agrawal, dev, Richardson, Bruce Cc: Doherty, Declan, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Wu, Hao, gaetan.rivet, Xu, Yilun Hi Hemant, > -----Original Message----- > From: Hemant Agrawal [mailto:hemant.agrawal@nxp.com] > Sent: Wednesday, April 04, 2018 20:00 > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; Richardson, Bruce > <bruce.richardson@intel.com> > Cc: Doherty, Declan <declan.doherty@intel.com>; shreyansh.jain@nxp.com; > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Wu, Hao <hao.wu@intel.com>; gaetan.rivet@6wind.com; Xu, Yilun > <yilun.xu@intel.com> > Subject: Re: [dpdk-dev] [PATCH v5 3/3] Add Intel FPGA OPAE Share Code > > > Hi Rosen/Bruce, > > On 4/4/2018 12:21 PM, Rosen Xu wrote: > > +++ b/drivers/raw/ifpga_rawdev/base/Makefile > > @@ -0,0 +1,54 @@ > > +# BSD LICENSE > > +# > > +# Copyright(c) 2017-2018 Intel Corporation. All rights reserved. > > +# All rights reserved. > > +# > > +# Redistribution and use in source and binary forms, with or without > > +# modification, are permitted provided that the following conditions > > +# are met: > > +# > > +# * Redistributions of source code must retain the above copyright > > +# notice, this list of conditions and the following disclaimer. > > +# * Redistributions in binary form must reproduce the above copyright > > +# notice, this list of conditions and the following disclaimer in > > +# the documentation and/or other materials provided with the > > +# distribution. > > +# * Neither the name of Intel Corporation nor the names of its > > +# contributors may be used to endorse or promote products derived > > +# from this software without specific prior written permission. > > +# > > +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND > CONTRIBUTORS > > +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT > NOT > > +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND > FITNESS FOR > > +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE > COPYRIGHT > > +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, > INCIDENTAL, > > +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, > BUT NOT > > +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; > LOSS OF USE, > > +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED > AND ON ANY > > +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR > TORT > > +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT > OF THE USE > > +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > DAMAGE. > > These files are adding the full license boiler plate. > What is your plan to change it to SPDX? > > > Bruce, may be your script can help Rosen to do it faster. It's fixed in PATCH v6. > Regards, > Hemant ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS Rosen Xu ` (2 preceding siblings ...) 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 3/3] Add Intel FPGA OPAE Share Code Rosen Xu @ 2018-04-04 10:14 ` Shreyansh Jain 2018-04-04 10:38 ` Richardson, Bruce 3 siblings, 1 reply; 149+ messages in thread From: Shreyansh Jain @ 2018-04-04 10:14 UTC (permalink / raw) To: Rosen Xu, dev Cc: declan.doherty, bruce.richardson, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet Hello Rosen, > -----Original Message----- > From: Rosen Xu [mailto:rosen.xu@intel.com] > Sent: Wednesday, April 4, 2018 12:21 PM > To: dev@dpdk.org > Cc: declan.doherty@intel.com; bruce.richardson@intel.com; Shreyansh Jain > <shreyansh.jain@nxp.com>; ferruh.yigit@intel.com; > konstantin.ananyev@intel.com; tianfei.zhang@intel.com; hao.wu@intel.com; > gaetan.rivet@6wind.com > Subject: [PATCH v5 0/3] Introduce Intel FPGA BUS > > Intel FPGA BUS in DPDK > ------------------------- > > This patch set introduces Intel FPGA BUS support in DPDK. > > v5 updates: > =========== > - Fixed SHARED LIB Build issue > - Changed command name to IFPGA Rawdev name, > so remove pci library datastruct and function. > - Fixed PATCH v2/v3/v4 comments > [...] Primary problems I see with your patches: 1. They are not split enough. Still the patch 2/3 is dependent on 3/3. That mean, it would break the compilation. There is no simpler way to solve this except breaking the patch into multiple patches and slowly introducing each function/feature. (One obvious way would be to have 3/3 as 2/3 and vice-versa - Not sure what that blocks). 2. Documentation - there is none right now. Being a special use case for PCI, I think a lot of people would benefit if you can explain the comments about why iFPGA bus is required through documentation. 3. Meson as requested by Bruce. Problem you will face is that rawdev doesn't yet have meson enabled. I will work on that. If you can still rework your patches for (1)+(2), I think meson enable over rawdev would be trivial. Other issues being license plate in opae code not being SPDX. But, I will leave that you and maintainers to decice. ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS 2018-04-04 10:14 ` [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS Shreyansh Jain @ 2018-04-04 10:38 ` Richardson, Bruce 2018-04-04 11:11 ` Shreyansh Jain 0 siblings, 1 reply; 149+ messages in thread From: Richardson, Bruce @ 2018-04-04 10:38 UTC (permalink / raw) To: Shreyansh Jain, Xu, Rosen, dev Cc: Doherty, Declan, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Wu, Hao, gaetan.rivet > -----Original Message----- > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > Sent: Wednesday, April 4, 2018 11:14 AM > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org > Cc: Doherty, Declan <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; Yigit, Ferruh <ferruh.yigit@intel.com>; > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Tianfei > <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: RE: [PATCH v5 0/3] Introduce Intel FPGA BUS > > Hello Rosen, > > > -----Original Message----- > > From: Rosen Xu [mailto:rosen.xu@intel.com] > > Sent: Wednesday, April 4, 2018 12:21 PM > > To: dev@dpdk.org > > Cc: declan.doherty@intel.com; bruce.richardson@intel.com; Shreyansh > > Jain <shreyansh.jain@nxp.com>; ferruh.yigit@intel.com; > > konstantin.ananyev@intel.com; tianfei.zhang@intel.com; > > hao.wu@intel.com; gaetan.rivet@6wind.com > > Subject: [PATCH v5 0/3] Introduce Intel FPGA BUS > > > > Intel FPGA BUS in DPDK > > ------------------------- > > > > This patch set introduces Intel FPGA BUS support in DPDK. > > > > v5 updates: > > =========== > > - Fixed SHARED LIB Build issue > > - Changed command name to IFPGA Rawdev name, > > so remove pci library datastruct and function. > > - Fixed PATCH v2/v3/v4 comments > > > > [...] > > Primary problems I see with your patches: > 1. They are not split enough. Still the patch 2/3 is dependent on 3/3. > That mean, it would break the compilation. There is no simpler way to > solve this except breaking the patch into multiple patches and slowly > introducing each function/feature. > (One obvious way would be to have 3/3 as 2/3 and vice-versa - Not sure > what that blocks). > > 2. Documentation - there is none right now. Being a special use case for > PCI, I think a lot of people would benefit if you can explain the comments > about why iFPGA bus is required through documentation. > > 3. Meson as requested by Bruce. Problem you will face is that rawdev > doesn't yet have meson enabled. I will work on that. If you can still > rework your patches for (1)+(2), I think meson enable over rawdev would be > trivial. I just spotted this and I've sent a patch for rawdev. It was pretty trivial. :-) Please review and ack if you have the chance. The skeleton rawdev however, I haven't done, so feel free to patch in that. /Bruce ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS 2018-04-04 10:38 ` Richardson, Bruce @ 2018-04-04 11:11 ` Shreyansh Jain 0 siblings, 0 replies; 149+ messages in thread From: Shreyansh Jain @ 2018-04-04 11:11 UTC (permalink / raw) To: Richardson, Bruce, Xu, Rosen, dev Cc: Doherty, Declan, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Wu, Hao, gaetan.rivet > -----Original Message----- > From: Richardson, Bruce [mailto:bruce.richardson@intel.com] > Sent: Wednesday, April 4, 2018 4:08 PM > To: Shreyansh Jain <shreyansh.jain@nxp.com>; Xu, Rosen > <rosen.xu@intel.com>; dev@dpdk.org > Cc: Doherty, Declan <declan.doherty@intel.com>; Yigit, Ferruh > <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei > <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: RE: [PATCH v5 0/3] Introduce Intel FPGA BUS > > > > > -----Original Message----- > > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > > Sent: Wednesday, April 4, 2018 11:14 AM > > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org > > Cc: Doherty, Declan <declan.doherty@intel.com>; Richardson, Bruce > > <bruce.richardson@intel.com>; Yigit, Ferruh <ferruh.yigit@intel.com>; > > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Tianfei > > <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com>; > > gaetan.rivet@6wind.com > > Subject: RE: [PATCH v5 0/3] Introduce Intel FPGA BUS > > > > Hello Rosen, > > > > > -----Original Message----- > > > From: Rosen Xu [mailto:rosen.xu@intel.com] > > > Sent: Wednesday, April 4, 2018 12:21 PM > > > To: dev@dpdk.org > > > Cc: declan.doherty@intel.com; bruce.richardson@intel.com; Shreyansh > > > Jain <shreyansh.jain@nxp.com>; ferruh.yigit@intel.com; > > > konstantin.ananyev@intel.com; tianfei.zhang@intel.com; > > > hao.wu@intel.com; gaetan.rivet@6wind.com > > > Subject: [PATCH v5 0/3] Introduce Intel FPGA BUS > > > > > > Intel FPGA BUS in DPDK > > > ------------------------- > > > > > > This patch set introduces Intel FPGA BUS support in DPDK. > > > > > > v5 updates: > > > =========== > > > - Fixed SHARED LIB Build issue > > > - Changed command name to IFPGA Rawdev name, > > > so remove pci library datastruct and function. > > > - Fixed PATCH v2/v3/v4 comments > > > > > > > [...] > > > > Primary problems I see with your patches: > > 1. They are not split enough. Still the patch 2/3 is dependent on 3/3. > > That mean, it would break the compilation. There is no simpler way to > > solve this except breaking the patch into multiple patches and slowly > > introducing each function/feature. > > (One obvious way would be to have 3/3 as 2/3 and vice-versa - Not > sure > > what that blocks). > > > > 2. Documentation - there is none right now. Being a special use case > for > > PCI, I think a lot of people would benefit if you can explain the > comments > > about why iFPGA bus is required through documentation. > > > > 3. Meson as requested by Bruce. Problem you will face is that rawdev > > doesn't yet have meson enabled. I will work on that. If you can still > > rework your patches for (1)+(2), I think meson enable over rawdev > would be > > trivial. > > I just spotted this and I've sent a patch for rawdev. It was pretty > trivial. :-) > Please review and ack if you have the chance. The skeleton rawdev > however, I haven't > done, so feel free to patch in that. :) Thanks. I'll review. I will push a dependent patch for skeleton_rawdev. > > /Bruce ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v6 0/5] Introduce Intel FPGA BUS 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (8 preceding siblings ...) 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS Rosen Xu @ 2018-04-26 9:43 ` Xu, Rosen 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 1/5] iFPGA: Add Intel FPGA BUS Library Xu, Rosen ` (4 more replies) 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 0/5] Introduce Intel FPGA BUS Xu, Rosen ` (7 subsequent siblings) 17 siblings, 5 replies; 149+ messages in thread From: Xu, Rosen @ 2018-04-26 9:43 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet, Xu, Rosen [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset=y, Size: 8996 bytes --] From: "Xu, Rosen" <rosen.xu@intel.com> Intel FPGA BUS in DPDK ------------------------- This patch set introduces Intel FPGA BUS support in DPDK. v6 updates: =========== - Add documentation - Add meson build script - Split new patch for OPAE share code v5 updates: =========== - Fixed SHARED LIB Build issue - Changed command name to IFPGA Rawdev name, so remove pci library datastruct and function. - Fixed PATCH v2/v3/v4 comments v4 updates: =========== - Remove all modifications from eal - Create vdev to take IFPGA parameters configuration - AFU Device Driver bind to AFU Device by uuid - Take more test in scenario of Multi-FPGA System v3 updates: =========== - Remove all modifications of bus scan and probe - FPGA BUS Scan is trigged by hotplug of Rawdev - Took Modifications of comments - Move AFU Device to IFPGA - FPGA BUS Scan depend on it¡¯s IFPGA Rawdev - Add Build Macros for FPGA BUS and IFPGA Rawdev Questions ========= Why not PCI Bus? All of the AFUs of one FPGA may share same PCI BDF. Why not vdev Bus? Because AFUs depend on Rawdev, and it's hardware specpic. Motivation ========== FPGA is used more and more widely in Cloud and NFV, one primary reason is that FPGA not only provide ASIC performance but also it's more flexible than ASIC. FPGA use Partial Reconfigure(PR) Parts of Bitstream to achieve its flexibility. Another reason is that one FPGA can be shared by different Users, and each User can use some of AFUs of One FPGA. That means One FPGA Device Bitstream is divided into many Parts of Bitstream(each Part of Bitstream is defined as AFU-Accelerated Function Unit), and each AFU is a Hardware Acceleration Unit and it can dynamically Reload respectively. Proposed Solution ================= - Involve Rawdev to take FPGA Partial Configuration(Download/PR) - Defined FPGA-BUS for Acceleration Drivers of AFUs - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver. FPGA-BUS scan is called, but AFU depend on Rawdev, so this scan doesn't trig AFU device create. - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their dirves are also probed. Scope ===== The Intel FPGA BUS implementation is target towards various FPGA Devices use PR to provide many Acceleration Function. Specific PMDs may also bind to its AFU. And Applications don't care they are using ASIC Acceleration or FPGA AFU Acceleration. Status ===== With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable Acceleration Engine) Share Code, Intel FPGA BUS runs well in Intel PSG FPGA Cards. Figo Zhang (2): iFPGA: add meson build iFPGA: add document for iFPGA driver Rosen Xu (3): iFPGA: Add Intel FPGA BUS Library iFPGA: Add Intel FPGA OPAE Share Code iFPGA: Add Intel FPGA BUS Rawdev Driver config/common_base | 6 + doc/guides/index.rst | 1 + doc/guides/rawdevs/ifpga_rawdev.rst | 112 ++ doc/guides/rawdevs/index.rst | 11 + doc/guides/rel_notes/release_18_05.rst | 13 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 + drivers/bus/ifpga/ifpga_bus.c | 503 ++++++ drivers/bus/ifpga/ifpga_common.c | 88 ++ drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 + drivers/bus/ifpga/meson.build | 6 + drivers/bus/ifpga/rte_bus_ifpga.h | 168 ++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/bus/meson.build | 2 +- drivers/meson.build | 3 +- drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 + drivers/raw/ifpga_rawdev/base/Makefile | 26 + drivers/raw/ifpga_rawdev/base/README | 31 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 294 ++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 28 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 57 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1661 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 824 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 11 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 314 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 164 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 734 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 301 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 403 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 715 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 372 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 127 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 408 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 165 ++ drivers/raw/ifpga_rawdev/base/meson.build | 34 + drivers/raw/ifpga_rawdev/base/opae_debug.c | 99 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 19 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 381 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 253 +++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 145 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 279 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 81 + .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 75 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 45 + drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 597 +++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 + drivers/raw/ifpga_rawdev/meson.build | 13 + .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + drivers/raw/meson.build | 6 + mk/rte.app.mk | 3 + 52 files changed, 9746 insertions(+), 2 deletions(-) create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst create mode 100644 doc/guides/rawdevs/index.rst create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/meson.build create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/README create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/meson.build create mode 100644 drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map create mode 100644 drivers/raw/meson.build -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v6 1/5] iFPGA: Add Intel FPGA BUS Library 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 0/5] " Xu, Rosen @ 2018-04-26 9:43 ` Xu, Rosen 2018-05-02 13:14 ` Shreyansh Jain 2018-05-03 3:58 ` Tan, Jianfeng 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 2/5] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen ` (3 subsequent siblings) 4 siblings, 2 replies; 149+ messages in thread From: Xu, Rosen @ 2018-04-26 9:43 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet, Rosen Xu From: Rosen Xu <rosen.xu@intel.com> Defined FPGA-BUS for Acceleration Drivers of AFUs 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver. 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their drivers are also probed. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Figo zhang <tianfei.zhang@intel.com> --- config/common_base | 5 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 ++ drivers/bus/ifpga/ifpga_bus.c | 503 ++++++++++++++++++++++++++++ drivers/bus/ifpga/ifpga_common.c | 88 +++++ drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 ++ drivers/bus/ifpga/meson.build | 6 + drivers/bus/ifpga/rte_bus_ifpga.h | 168 ++++++++++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/bus/meson.build | 2 +- mk/rte.app.mk | 2 + 12 files changed, 865 insertions(+), 1 deletion(-) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/meson.build create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map diff --git a/config/common_base b/config/common_base index 7e45412..b59f1de 100644 --- a/config/common_base +++ b/config/common_base @@ -148,6 +148,11 @@ CONFIG_RTE_LIBRTE_PCI_BUS=y CONFIG_RTE_LIBRTE_VDEV_BUS=y # +# Compile the Intel FPGA bus +# +CONFIG_RTE_LIBRTE_IFPGA_BUS=y + +# # Compile ARK PMD # CONFIG_RTE_LIBRTE_ARK_PMD=y diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index c251b65..cff3567 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -9,5 +9,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc endif DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile new file mode 100644 index 0000000..3ff3bdb --- /dev/null +++ b/drivers/bus/ifpga/Makefile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_bus_ifpga.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_kvargs + +# versioning export map +EXPORT_MAP := rte_bus_ifpga_version.map + +# library version +LIBABIVER := 1 + +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c + +# +# Export include files +# +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index 0000000..67c24ae --- /dev/null +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -0,0 +1,503 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_bus_logtype; + +/* Forward declare to access Intel FPGA bus name */ +static struct rte_bus rte_ifpga_bus; + +/** Double linked list of IFPGA device. */ +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); + +static struct ifpga_device_list ifpga_device_list = + TAILQ_HEAD_INITIALIZER(ifpga_device_list); +struct afu_driver_list afu_driver_list = + TAILQ_HEAD_INITIALIZER(afu_driver_list); + + +/* register a ifpga bus based driver */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver) +{ + RTE_VERIFY(driver); + + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); +} + +/* un-register a fpga bus based driver */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) +{ + TAILQ_REMOVE(&afu_driver_list, driver, next); +} + +static struct rte_ifpga_device * +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + if (rdev && + ifpga_dev->rdev && + ifpga_dev->rdev == rdev) + return ifpga_dev; + } + return NULL; +} + +static struct rte_afu_device * +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, + const struct rte_afu_id *afu_id) +{ + struct rte_afu_device *afu_dev = NULL; + + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) + return afu_dev; + } + return NULL; +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static struct rte_afu_device * +rte_ifpga_scan_one(struct rte_devargs *devargs, + struct rte_ifpga_device *ifpga_dev) +{ + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_afu_pr_conf afu_pr_conf; + int ret = 0; + char *path = NULL; + + memset((char *)(&afu_pr_conf), 0, sizeof(struct rte_afu_pr_conf)); + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, + &ifpga_get_string_arg, &path) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_AFU_BTS); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_AFU_BTS); + goto end; + } + + afu_pr_conf.afu_id.uuid_low = 0; + afu_pr_conf.afu_id.uuid_high = 0; + afu_pr_conf.pr_enable = path?1:0; + + rawdev = ifpga_dev->rdev; + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) + goto end; + + afu_dev = calloc(1, sizeof(*afu_dev)); + if (!afu_dev) + goto end; + + afu_dev->device.devargs = devargs; + afu_dev->device.numa_node = SOCKET_ID_ANY; + afu_dev->device.name = devargs->name; + afu_dev->rawdev = rawdev; + afu_dev->id.uuid_low = 0; + afu_dev->id.uuid_high = 0; + afu_dev->id.port = afu_pr_conf.afu_id.port; + afu_dev->ifpga_dev = ifpga_dev; + + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); + + if (rawdev->dev_ops && + rawdev->dev_ops->dev_start && + rawdev->dev_ops->dev_start(rawdev)) + goto free_dev; + + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); + if (rawdev->dev_ops->firmware_load && + rawdev->dev_ops->firmware_load(rawdev, + &afu_pr_conf)){ + IFPGA_BUS_ERR("firmware load error %d\n", ret); + goto free_dev; + } + afu_dev->id.uuid_low = afu_pr_conf.afu_id.uuid_low; + afu_dev->id.uuid_high = afu_pr_conf.afu_id.uuid_high; + + + return afu_dev; + +free_dev: + free(afu_dev); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (path) + free(path); + + return NULL; +} + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static int +rte_ifpga_scan(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + char *name = NULL; + char name1[RTE_RAWDEV_NAME_MAX_LEN]; + struct rte_afu_device *afu_dev = NULL; + + /* for FPGA devices we scan the devargs_list populated via cmdline */ + RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { + if (devargs->bus != &rte_ifpga_bus) + continue; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &ifpga_get_string_arg, &name) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + memset(name1, 0, sizeof(name1)); + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", name); + + rawdev = rte_rawdev_pmd_get_named_dev(name1); + if (!rawdev) + goto end; + + if (ifpga_find_ifpga_dev(rawdev)) + continue; + + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); + if (!ifpga_dev) + goto end; + + ifpga_dev->rdev = rawdev; + TAILQ_INIT(&ifpga_dev->afu_list); + + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); + afu_dev = rte_ifpga_scan_one(devargs, ifpga_dev); + if (afu_dev != NULL) + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, next); + } + +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +/* + * Match the AFU Driver and AFU Device using the ID Table + */ +static int +rte_afu_match(const struct rte_afu_driver *afu_drv, + const struct rte_afu_device *afu_dev) +{ + const struct rte_afu_uuid *id_table; + + for (id_table = afu_drv->id_table; + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); + id_table++) { + /* check if device's identifiers match the driver's ones */ + if ((id_table->uuid_low != afu_dev->id.uuid_low) || + (id_table->uuid_high != afu_dev->id.uuid_high)) + continue; + + return 1; + } + + return 0; +} + +static int +ifpga_probe_one_driver(struct rte_afu_driver *drv, + struct rte_afu_device *afu_dev) +{ + int ret; + + if (!rte_afu_match(drv, afu_dev)) + /* Match of device and driver failed */ + return 1; + + /* reference driver structure */ + afu_dev->driver = drv; + afu_dev->device.driver = &drv->driver; + + /* call the driver probe() function */ + ret = drv->probe(afu_dev); + if (ret) { + afu_dev->driver = NULL; + afu_dev->device.driver = NULL; + } + + /* return positive value if driver doesn't support this device */ + return 0; +} + +static int +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) +{ + struct rte_afu_driver *drv = NULL; + int rc; + + if (afu_dev == NULL) + return -1; + + /* Check if a driver is already loaded */ + if (afu_dev->driver != NULL) + return 0; + + TAILQ_FOREACH(drv, &afu_driver_list, next) { + rc = ifpga_probe_one_driver(drv, afu_dev); + if (rc < 0) + /* negative value is an error */ + return -1; + if (rc > 0) + /* positive value means driver doesn't support it */ + continue; + return 0; + } + return 1; +} + +/* + * Scan the content of the Intel FPGA bus, and call the probe() function for + * all registered drivers that have a matching entry in its id_table + * for discovered devices. + */ +static int +rte_ifpga_probe(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev = NULL; + int ret = 0; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + + if (afu_dev->device.driver) + continue; + + ret = ifpga_probe_all_drivers(afu_dev); + if (ret < 0) + IFPGA_BUS_ERR("failed to initialize %s device\n", + rte_ifpga_device_name(afu_dev)); + } + } + + return 0; +} + +static int +rte_ifpga_plug(struct rte_device *dev) +{ + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); +} + +static int ifpga_remove_driver(struct rte_afu_device *afu_dev) +{ + const char *name; + const struct rte_afu_driver *driver; + + name = rte_ifpga_device_name(afu_dev); + if (!afu_dev->device.driver) { + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); + return 1; + } + + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); + return driver->remove(afu_dev); +} + +static int +rte_ifpga_unplug(struct rte_device *dev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_devargs *devargs = NULL; + int ret; + + if (dev == NULL) + return -EINVAL; + + afu_dev = RTE_DEV_TO_AFU(dev); + if (!dev) + return -ENOENT; + + ifpga_dev = afu_dev->ifpga_dev; + devargs = dev->devargs; + + ret = ifpga_remove_driver(afu_dev); + if (ret) + return ret; + + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); + + rte_devargs_remove(devargs->bus->name, devargs->name); + free(afu_dev); + return 0; + +} + +static struct rte_device * +rte_ifpga_find_device(const struct rte_device *start, + rte_dev_cmp_t cmp, const void *data) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (start && &afu_dev->device == start) { + start = NULL; + continue; + } + if (cmp(&afu_dev->device, data) == 0) + return &afu_dev->device; + } + } + return NULL; +} +static int +rte_ifpga_parse(const char *name, void *addr) +{ + int *out = addr; + struct rte_rawdev *rawdev = NULL; + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; + char *c1 = NULL, *c2 = NULL; + int port = IFPGA_BUS_DEV_PORT_MAX; + char str_port[8]; + int str_port_len = 0; + int ret; + + memset(str_port, 0, 8); + c1 = strchr(name, '|'); + if (c1 != NULL) { + str_port_len = c1-name; + c2 = c1+1; + } + + if (str_port_len < 8 && + str_port_len > 0) { + memcpy(str_port, name, str_port_len); + ret = sscanf(str_port, "%d", &port); + if (ret == -1) + return 0; + } + + memset(rawdev_name, 0, sizeof(rawdev_name)); + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", c2); + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev && + (addr != NULL)) + *out = port; + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev) + return 0; + else + return 1; +} + +static struct rte_bus rte_ifpga_bus = { + .scan = rte_ifpga_scan, + .probe = rte_ifpga_probe, + .find_device = rte_ifpga_find_device, + .plug = rte_ifpga_plug, + .unplug = rte_ifpga_unplug, + .parse = rte_ifpga_parse, +}; + +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); + +RTE_INIT(ifpga_init_log) +{ + ifpga_bus_logtype = rte_log_register("bus.ifpga"); + if (ifpga_bus_logtype >= 0) + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); +} diff --git a/drivers/bus/ifpga/ifpga_common.c b/drivers/bus/ifpga/ifpga_common.c new file mode 100644 index 0000000..26fee27 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(char **)extra_args = strdup(value); + + if (!*(char **)extra_args) + return -ENOMEM; + + return 0; +} +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(int *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(uint64_t *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_unsigned_long(const char *str, int base) +{ + unsigned long num; + char *end = NULL; + + errno = 0; + + num = strtoul(str, &end, base); + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) + return -1; + + return num; +} + +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1) +{ + if ((afu_id0->uuid_low == afu_id1->uuid_low) && + (afu_id0->uuid_high == afu_id1->uuid_high) && + (afu_id0->port == afu_id1->port)) { + return 0; + } else + return 1; +} diff --git a/drivers/bus/ifpga/ifpga_common.h b/drivers/bus/ifpga/ifpga_common.h new file mode 100644 index 0000000..b6662c8 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMMON_H_ +#define _IFPGA_COMMON_H_ + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_unsigned_long(const char *str, int base); +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1); + +#endif /* _IFPGA_COMMON_H_ */ diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index 0000000..873e0a4 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_logs.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_LOGS_H_ +#define _IFPGA_LOGS_H_ + +#include <rte_log.h> + +extern int ifpga_bus_logtype; + +#define IFPGA_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") + +#define IFPGA_BUS_DEBUG(fmt, args...) \ + IFPGA_BUS_LOG(DEBUG, fmt, ## args) +#define IFPGA_BUS_INFO(fmt, args...) \ + IFPGA_BUS_LOG(INFO, fmt, ## args) +#define IFPGA_BUS_ERR(fmt, args...) \ + IFPGA_BUS_LOG(ERR, fmt, ## args) +#define IFPGA_BUS_WARN(fmt, args...) \ + IFPGA_BUS_LOG(WARNING, fmt, ## args) + +#endif /* _IFPGA_BUS_LOGS_H_ */ diff --git a/drivers/bus/ifpga/meson.build b/drivers/bus/ifpga/meson.build new file mode 100644 index 0000000..4ea31f1 --- /dev/null +++ b/drivers/bus/ifpga/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2018 Intel Corporation + +deps += ['pci', 'kvargs', 'rawdev'] +install_headers('rte_bus_ifpga.h') +sources = files('ifpga_common.c', 'ifpga_bus.c') diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h new file mode 100644 index 0000000..53e7183 --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga.h @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _RTE_BUS_IFPGA_H_ +#define _RTE_BUS_IFPGA_H_ + +/** + * @file + * + * RTE Intel FPGA Bus Interface + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_bus.h> +#include <rte_pci.h> + +/** Name of Intel FPGA Bus */ +#define IFPGA_BUS_NAME ifpga + +/* Forward declarations */ +struct rte_afu_device; + +/** List of Intel AFU devices */ +TAILQ_HEAD(afu_device_list, rte_afu_device); +/** Double linked list of AFU device drivers. */ +TAILQ_HEAD(afu_driver_list, rte_afu_driver); + +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 + +struct rte_afu_uuid { + uint64_t uuid_low; + uint64_t uuid_high; +} __attribute__ ((packed)); + +#define IFPGA_BUS_DEV_PORT_MAX 4 + +/** + * A structure describing an ID for a AFU driver. Each driver provides a + * table of these IDs for each device that it supports. + */ +struct rte_afu_id { + uint64_t uuid_low; + uint64_t uuid_high; + int port; +} __attribute__ ((packed)); + +/** + * A structure pr configuration AFU driver. + */ + +struct rte_afu_pr_conf { + struct rte_afu_id afu_id; + int pr_enable; + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +}; + +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) + +/** + * A structure describing a fpga device. + */ +struct rte_ifpga_device { + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ + struct rte_rawdev *rdev; + struct afu_device_list afu_list; /**< List of AFU devices */ +}; + +/** + * A structure describing a AFU device. + */ +struct rte_afu_device { + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ + struct rte_device device; /**< Inherit core device */ + struct rte_rawdev *rawdev; /**< Point Rawdev */ + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ + struct rte_afu_id id; /**< AFU id within FPGA. */ + uint32_t num_region; /**< number of regions found */ + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; + /**< AFU Memory Resource */ + struct rte_intr_handle intr_handle; /**< Interrupt handle */ + struct rte_afu_driver *driver; /**< Associated driver */ + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +} __attribute__ ((packed)); + +/** + * @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_DRV_TO_AFU_CONST(ptr) \ + container_of(ptr, const struct rte_afu_driver, driver) + +/** + * Initialisation function for the driver called during FPGA BUS probing. + */ +typedef int (afu_probe_t)(struct rte_afu_device *); + +/** + * Uninitialisation function for the driver called during hotplugging. + */ +typedef int (afu_remove_t)(struct rte_afu_device *); + +/** + * A structure describing a AFU device. + */ +struct rte_afu_driver { + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ + struct rte_driver driver; /**< Inherit core driver. */ + afu_probe_t *probe; /**< Device Probe function. */ + afu_remove_t *remove; /**< Device Remove function. */ + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ + uint32_t drv_flags; /**< Flags contolling handling of device. */ +}; + +/** + * Structure describing the Intel FPGA bus + */ +struct rte_ifpga_bus { + struct rte_bus bus; /**< Inherit the generic class */ +}; + +static inline const char * +rte_ifpga_device_name(const struct rte_afu_device *afu) +{ + if (afu && afu->device.name) + return afu->device.name; + return NULL; +} + +/** + * Register a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be registered. + */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver); + +/** + * Unregister a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be unregistered. + */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); + +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ +RTE_INIT(afudrvinitfn_ ##afudrv);\ +static const char *afudrvinit_ ## nm ## _alias;\ +static void afudrvinitfn_ ##afudrv(void)\ +{\ + (afudrv).driver.name = RTE_STR(nm);\ + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ + rte_ifpga_driver_register(&afudrv);\ +} \ +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) + +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ +static const char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) + +#endif /* _RTE_BUS_IFPGA_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map new file mode 100644 index 0000000..1304caf --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map @@ -0,0 +1,10 @@ +DPDK_18.05 { + global: + + ifpga_get_integer32_arg; + ifpga_get_string_arg; + rte_ifpga_driver_register; + rte_ifpga_driver_unregister; + + local: *; +}; diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build index 58dfbe2..170df25 100644 --- a/drivers/bus/meson.build +++ b/drivers/bus/meson.build @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel Corporation -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] +drivers = ['dpaa', 'fslmc', 'pci', 'vdev', 'ifpga'] std_deps = ['eal'] config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' driver_name_fmt = 'rte_bus_@0@' diff --git a/mk/rte.app.mk b/mk/rte.app.mk index a145791..9de2edb 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -107,6 +107,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE) += -lrte_cmdline _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrte_sched +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga + ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v6 1/5] iFPGA: Add Intel FPGA BUS Library 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 1/5] iFPGA: Add Intel FPGA BUS Library Xu, Rosen @ 2018-05-02 13:14 ` Shreyansh Jain 2018-05-02 13:33 ` Zhang, Tianfei 2018-05-03 3:58 ` Tan, Jianfeng 1 sibling, 1 reply; 149+ messages in thread From: Shreyansh Jain @ 2018-05-02 13:14 UTC (permalink / raw) To: Xu, Rosen, dev Cc: declan.doherty, bruce.richardson, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet On Thursday 26 April 2018 03:13 PM, Xu, Rosen wrote: > From: Rosen Xu <rosen.xu@intel.com> > > Defined FPGA-BUS for Acceleration Drivers of AFUs > 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, > probe Intel FPGA Rawdev Driver. > 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. > This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan > the AFUs will be created and their drivers are also probed. > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > Signed-off-by: Figo zhang <tianfei.zhang@intel.com> > --- > config/common_base | 5 + > drivers/bus/Makefile | 1 + > drivers/bus/ifpga/Makefile | 32 ++ > drivers/bus/ifpga/ifpga_bus.c | 503 ++++++++++++++++++++++++++++ > drivers/bus/ifpga/ifpga_common.c | 88 +++++ > drivers/bus/ifpga/ifpga_common.h | 18 + > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > drivers/bus/ifpga/meson.build | 6 + > drivers/bus/ifpga/rte_bus_ifpga.h | 168 ++++++++++ > drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + > drivers/bus/meson.build | 2 +- > mk/rte.app.mk | 2 + > 12 files changed, 865 insertions(+), 1 deletion(-) > create mode 100644 drivers/bus/ifpga/Makefile > create mode 100644 drivers/bus/ifpga/ifpga_bus.c > create mode 100644 drivers/bus/ifpga/ifpga_common.c > create mode 100644 drivers/bus/ifpga/ifpga_common.h > create mode 100644 drivers/bus/ifpga/ifpga_logs.h > create mode 100644 drivers/bus/ifpga/meson.build > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map > Hello Rosen, While compiling this series with meson, I found following warnings: --->8--- 3d/1& [shreyansh:~/build/DPDK/00_dpdk/ifpga-build]↥ master(6)+* ± ninja [335/949] Compiling C object 'drivers/tmp_rte_bus_ifpga@sta/bus_ifpga_ifpga_bus.c.o'. ../drivers/bus/ifpga/ifpga_bus.c: In function ‘rte_ifpga_scan’: ../drivers/bus/ifpga/ifpga_bus.c:217:2: warning: ‘rte_devargs_next’ is deprecated: Symbol is not yet part of stable ABI [-Wdeprecated-declarations] RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { ^~~~~~~~~~~~~~~~~~~~~~~ In file included from ../drivers/bus/ifpga/ifpga_bus.c:24:0: ../lib/librte_eal/common/include/rte_devargs.h:262:1: note: declared here rte_devargs_next(const char *busname, const struct rte_devargs *start); ^~~~~~~~~~~~~~~~ ../drivers/bus/ifpga/ifpga_bus.c:217:2: warning: ‘rte_devargs_next’ is deprecated: Symbol is not yet part of stable ABI [-Wdeprecated-declarations] RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { ^~~~~~~~~~~~~~~~~~~~~~~ In file included from ../drivers/bus/ifpga/ifpga_bus.c:24:0: ../lib/librte_eal/common/include/rte_devargs.h:262:1: note: declared here rte_devargs_next(const char *busname, const struct rte_devargs *start); ^~~~~~~~~~~~~~~~ ../drivers/bus/ifpga/ifpga_bus.c: In function ‘rte_ifpga_unplug’: ../drivers/bus/ifpga/ifpga_bus.c:419:2: warning: ‘rte_devargs_remove’ is deprecated: Symbol is not yet part of stable ABI [-Wdeprecated-declarations] rte_devargs_remove(devargs->bus->name, devargs->name); ^~~~~~~~~~~~~~~~~~ In file included from ../drivers/bus/ifpga/ifpga_bus.c:24:0: ../lib/librte_eal/common/include/rte_devargs.h:195:5: note: declared here int rte_devargs_remove(const char *busname, ^~~~~~~~~~~~~~~~~~ ../drivers/bus/ifpga/ifpga_bus.c: At top level: cc1: warning: unrecognized command line option ‘-W --->8--- My meson configuration is: --->8--- 3d/1& [shreyansh:~/build/DPDK/00_dpdk]↥ master(6)+* 130 ± ~/.local/bin/meson ifpga-build The Meson build system Version: 0.44.0 Source dir: /home/shreyansh/build/DPDK/00_dpdk Build dir: /home/shreyansh/build/DPDK/00_dpdk/ifpga-build Build type: native build Project name: DPDK Native C compiler: ccache cc (gcc 7.2.0) Build machine cpu family: x86_64 Build machine cpu: x86_64 Library numa found: YES Has header "numaif.h": YES ... --->8--- Can you please look into this? - Shreyansh ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v6 1/5] iFPGA: Add Intel FPGA BUS Library 2018-05-02 13:14 ` Shreyansh Jain @ 2018-05-02 13:33 ` Zhang, Tianfei 0 siblings, 0 replies; 149+ messages in thread From: Zhang, Tianfei @ 2018-05-02 13:33 UTC (permalink / raw) To: Shreyansh Jain, Xu, Rosen, dev Cc: Doherty, Declan, Richardson, Bruce, Yigit, Ferruh, Ananyev, Konstantin, Wu, Hao, gaetan.rivet > -----Original Message----- > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > Sent: Wednesday, May 2, 2018 9:14 PM > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org > Cc: Doherty, Declan <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; Yigit, Ferruh <ferruh.yigit@intel.com>; > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Tianfei > <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: Re: [dpdk-dev] [PATCH v6 1/5] iFPGA: Add Intel FPGA BUS Library > > On Thursday 26 April 2018 03:13 PM, Xu, Rosen wrote: > > From: Rosen Xu <rosen.xu@intel.com> > > > > Defined FPGA-BUS for Acceleration Drivers of AFUs 1. FPGA PCI Scan > > (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA > > Rawdev Driver. > > 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. > > This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan > > the AFUs will be created and their drivers are also probed. > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > Signed-off-by: Figo zhang <tianfei.zhang@intel.com> > > --- > > config/common_base | 5 + > > drivers/bus/Makefile | 1 + > > drivers/bus/ifpga/Makefile | 32 ++ > > drivers/bus/ifpga/ifpga_bus.c | 503 > ++++++++++++++++++++++++++++ > > drivers/bus/ifpga/ifpga_common.c | 88 +++++ > > drivers/bus/ifpga/ifpga_common.h | 18 + > > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > > drivers/bus/ifpga/meson.build | 6 + > > drivers/bus/ifpga/rte_bus_ifpga.h | 168 ++++++++++ > > drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + > > drivers/bus/meson.build | 2 +- > > mk/rte.app.mk | 2 + > > 12 files changed, 865 insertions(+), 1 deletion(-) > > create mode 100644 drivers/bus/ifpga/Makefile > > create mode 100644 drivers/bus/ifpga/ifpga_bus.c > > create mode 100644 drivers/bus/ifpga/ifpga_common.c > > create mode 100644 drivers/bus/ifpga/ifpga_common.h > > create mode 100644 drivers/bus/ifpga/ifpga_logs.h > > create mode 100644 drivers/bus/ifpga/meson.build > > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h > > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > Hello Rosen, > > While compiling this series with meson, I found following warnings: > > --->8--- > 3d/1& [shreyansh:~/build/DPDK/00_dpdk/ifpga-build]↥ master(6)+* ± ninja > [335/949] Compiling C object > 'drivers/tmp_rte_bus_ifpga@sta/bus_ifpga_ifpga_bus.c.o'. > ../drivers/bus/ifpga/ifpga_bus.c: In function ‘rte_ifpga_scan’: > ../drivers/bus/ifpga/ifpga_bus.c:217:2: warning: ‘rte_devargs_next’ is > deprecated: Symbol is not yet part of stable ABI > [-Wdeprecated-declarations] > RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { > ^~~~~~~~~~~~~~~~~~~~~~~ > In file included from ../drivers/bus/ifpga/ifpga_bus.c:24:0: > ../lib/librte_eal/common/include/rte_devargs.h:262:1: note: declared here > rte_devargs_next(const char *busname, const struct rte_devargs *start); > ^~~~~~~~~~~~~~~~ > ../drivers/bus/ifpga/ifpga_bus.c:217:2: warning: ‘rte_devargs_next’ is > deprecated: Symbol is not yet part of stable ABI > [-Wdeprecated-declarations] > RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { > ^~~~~~~~~~~~~~~~~~~~~~~ > In file included from ../drivers/bus/ifpga/ifpga_bus.c:24:0: > ../lib/librte_eal/common/include/rte_devargs.h:262:1: note: declared here > rte_devargs_next(const char *busname, const struct rte_devargs *start); > ^~~~~~~~~~~~~~~~ > ../drivers/bus/ifpga/ifpga_bus.c: In function ‘rte_ifpga_unplug’: > ../drivers/bus/ifpga/ifpga_bus.c:419:2: warning: ‘rte_devargs_remove’ is > deprecated: Symbol is not yet part of stable ABI > [-Wdeprecated-declarations] > rte_devargs_remove(devargs->bus->name, devargs->name); > ^~~~~~~~~~~~~~~~~~ > In file included from ../drivers/bus/ifpga/ifpga_bus.c:24:0: > ../lib/librte_eal/common/include/rte_devargs.h:195:5: note: declared here > int rte_devargs_remove(const char *busname, > ^~~~~~~~~~~~~~~~~~ > ../drivers/bus/ifpga/ifpga_bus.c: At top level: > cc1: warning: unrecognized command line option ‘-W > --->8--- > > My meson configuration is: > > --->8--- > 3d/1& [shreyansh:~/build/DPDK/00_dpdk]↥ master(6)+* 130 ± > ~/.local/bin/meson ifpga-build The Meson build system > Version: 0.44.0 > Source dir: /home/shreyansh/build/DPDK/00_dpdk > Build dir: /home/shreyansh/build/DPDK/00_dpdk/ifpga-build > Build type: native build > Project name: DPDK > Native C compiler: ccache cc (gcc 7.2.0) Build machine cpu family: x86_64 > Build machine cpu: x86_64 Library numa found: YES Has header "numaif.h": > YES ... > --->8--- > > Can you please look into this? We will fix it and send v7 patches soon. I try it add " allow_experimental_apis = true " in meson.build can remove those warrings. > > - > Shreyansh ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v6 1/5] iFPGA: Add Intel FPGA BUS Library 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 1/5] iFPGA: Add Intel FPGA BUS Library Xu, Rosen 2018-05-02 13:14 ` Shreyansh Jain @ 2018-05-03 3:58 ` Tan, Jianfeng 2018-05-03 8:12 ` Tan, Jianfeng 2018-05-03 8:35 ` Zhang, Tianfei 1 sibling, 2 replies; 149+ messages in thread From: Tan, Jianfeng @ 2018-05-03 3:58 UTC (permalink / raw) To: Xu, Rosen, dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet For title prefix, use "bus/ifpga" instead. On 4/26/2018 5:43 PM, Xu, Rosen wrote: > From: Rosen Xu <rosen.xu@intel.com> > > Defined FPGA-BUS for Acceleration Drivers of AFUs > 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, > probe Intel FPGA Rawdev Driver. As I understand, this part is not covered in this patch. You might want to add a note that "it will be covered in following patches". > 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. > This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan > the AFUs will be created and their drivers are also probed. This patch is not only responsible for scan, but also other bus ops. So in your commit log, you might want to clarify this, like we introduce rte_afu_device. I have a question, hope you can clarify it a little bit. As I understand, this FPGA bus are used for AFU device enumeration, and each device on this bus needs a AFU driver to drive. But now we register AFU drivers, but enumerate rte_ifpga_device. Why? The reason I can think of, we need to maintain the relationship of fpga devices and afu devices. But I think similar problem would exist in dpaa and fslmc bus too. It is interesting to know the best practice on this. Besides, I see you are using a devargs for scanning, would you like to provide an example here? > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > Signed-off-by: Figo zhang <tianfei.zhang@intel.com> > --- > config/common_base | 5 + > drivers/bus/Makefile | 1 + > drivers/bus/ifpga/Makefile | 32 ++ > drivers/bus/ifpga/ifpga_bus.c | 503 ++++++++++++++++++++++++++++ > drivers/bus/ifpga/ifpga_common.c | 88 +++++ > drivers/bus/ifpga/ifpga_common.h | 18 + > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > drivers/bus/ifpga/meson.build | 6 + > drivers/bus/ifpga/rte_bus_ifpga.h | 168 ++++++++++ > drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + > drivers/bus/meson.build | 2 +- > mk/rte.app.mk | 2 + > 12 files changed, 865 insertions(+), 1 deletion(-) > create mode 100644 drivers/bus/ifpga/Makefile > create mode 100644 drivers/bus/ifpga/ifpga_bus.c > create mode 100644 drivers/bus/ifpga/ifpga_common.c > create mode 100644 drivers/bus/ifpga/ifpga_common.h > create mode 100644 drivers/bus/ifpga/ifpga_logs.h > create mode 100644 drivers/bus/ifpga/meson.build > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map > > diff --git a/config/common_base b/config/common_base > index 7e45412..b59f1de 100644 > --- a/config/common_base > +++ b/config/common_base > @@ -148,6 +148,11 @@ CONFIG_RTE_LIBRTE_PCI_BUS=y > CONFIG_RTE_LIBRTE_VDEV_BUS=y > > # > +# Compile the Intel FPGA bus > +# > +CONFIG_RTE_LIBRTE_IFPGA_BUS=y > + > +# > # Compile ARK PMD > # > CONFIG_RTE_LIBRTE_ARK_PMD=y > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile > index c251b65..cff3567 100644 > --- a/drivers/bus/Makefile > +++ b/drivers/bus/Makefile > @@ -9,5 +9,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc > endif > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > > include $(RTE_SDK)/mk/rte.subdir.mk > diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile > new file mode 100644 > index 0000000..3ff3bdb > --- /dev/null > +++ b/drivers/bus/ifpga/Makefile > @@ -0,0 +1,32 @@ > +# SPDX-License-Identifier: BSD-3-Clause > +# Copyright(c) 2018 Intel Corporation > + > +include $(RTE_SDK)/mk/rte.vars.mk > + > +# > +# library name > +# > +LIB = librte_bus_ifpga.a > + > +CFLAGS += -DALLOW_EXPERIMENTAL_API > +CFLAGS += -O3 > +CFLAGS += $(WERROR_FLAGS) > +LDLIBS += -lrte_eal > +LDLIBS += -lrte_rawdev > +LDLIBS += -lrte_kvargs > + > +# versioning export map > +EXPORT_MAP := rte_bus_ifpga_version.map > + > +# library version > +LIBABIVER := 1 > + > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c > + > +# > +# Export include files > +# > +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h > + > +include $(RTE_SDK)/mk/rte.lib.mk > diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c > new file mode 100644 > index 0000000..67c24ae > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_bus.c > @@ -0,0 +1,503 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation > + */ > + > +#include <string.h> > +#include <inttypes.h> > +#include <stdint.h> > +#include <stdlib.h> > +#include <stdio.h> > +#include <sys/queue.h> > +#include <sys/mman.h> > +#include <sys/types.h> > +#include <unistd.h> > +#include <fcntl.h> > + > +#include <rte_errno.h> > +#include <rte_bus.h> > +#include <rte_per_lcore.h> > +#include <rte_memory.h> > +#include <rte_memzone.h> > +#include <rte_eal.h> > +#include <rte_common.h> > + > +#include <rte_devargs.h> > +#include <rte_kvargs.h> > +#include <rte_alarm.h> > + > +#include "rte_rawdev.h" > +#include "rte_rawdev_pmd.h" > +#include "rte_bus_ifpga.h" > +#include "ifpga_logs.h" > +#include "ifpga_common.h" > + > +int ifpga_bus_logtype; > + > +/* Forward declare to access Intel FPGA bus name */ s/declare/declaration, actually, does "Intel FPGA bus on which iFPGA devices are connected" sound better? > +static struct rte_bus rte_ifpga_bus; > + > +/** Double linked list of IFPGA device. */ > +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); > + > +static struct ifpga_device_list ifpga_device_list = > + TAILQ_HEAD_INITIALIZER(ifpga_device_list); > +struct afu_driver_list afu_driver_list = Why not keep this list as static? > + TAILQ_HEAD_INITIALIZER(afu_driver_list); > + > + > +/* register a ifpga bus based driver */ > +void rte_ifpga_driver_register(struct rte_afu_driver *driver) > +{ > + RTE_VERIFY(driver); > + > + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); > +} > + > +/* un-register a fpga bus based driver */ > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) > +{ > + TAILQ_REMOVE(&afu_driver_list, driver, next); > +} > + > +static struct rte_ifpga_device * > +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) > +{ > + struct rte_ifpga_device *ifpga_dev = NULL; > + > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > + if (rdev && > + ifpga_dev->rdev && > + ifpga_dev->rdev == rdev) > + return ifpga_dev; > + } > + return NULL; > +} > + > +static struct rte_afu_device * > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > + const struct rte_afu_id *afu_id) > +{ > + struct rte_afu_device *afu_dev = NULL; > + > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > + return afu_dev; > + } > + return NULL; > +} > + > +static const char * const valid_args[] = { > +#define IFPGA_ARG_NAME "ifpga" > + IFPGA_ARG_NAME, > +#define IFPGA_ARG_PORT "port" > + IFPGA_ARG_PORT, > +#define IFPGA_AFU_BTS "afu_bts" > + IFPGA_AFU_BTS, > + NULL > +}; > + > +/* > + * Scan the content of the FPGA bus, and the devices in the devices > + * list > + */ > +static struct rte_afu_device * > +rte_ifpga_scan_one(struct rte_devargs *devargs, For internal functions, we'd better not use the prefix "rte". > + struct rte_ifpga_device *ifpga_dev) > +{ > + struct rte_kvargs *kvlist = NULL; > + struct rte_rawdev *rawdev = NULL; > + struct rte_afu_device *afu_dev = NULL; > + struct rte_afu_pr_conf afu_pr_conf; > + int ret = 0; > + char *path = NULL; > + > + memset((char *)(&afu_pr_conf), 0, sizeof(struct rte_afu_pr_conf)); For "void *", no need to add explicit type cast. > + > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > + if (!kvlist) { > + IFPGA_BUS_ERR("error when parsing param"); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, > + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { > + IFPGA_BUS_ERR("error to parse %s", > + IFPGA_ARG_PORT); > + goto end; > + } > + } else { > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_ARG_PORT); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, > + &ifpga_get_string_arg, &path) < 0) { > + IFPGA_BUS_ERR("error to parse %s", s/error/failed > + IFPGA_AFU_BTS); > + goto end; > + } > + } else { > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_AFU_BTS); > + goto end; > + } > + > + afu_pr_conf.afu_id.uuid_low = 0; > + afu_pr_conf.afu_id.uuid_high = 0; > + afu_pr_conf.pr_enable = path?1:0; > + > + rawdev = ifpga_dev->rdev; > + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) > + goto end; > + > + afu_dev = calloc(1, sizeof(*afu_dev)); > + if (!afu_dev) > + goto end; > + > + afu_dev->device.devargs = devargs; > + afu_dev->device.numa_node = SOCKET_ID_ANY; > + afu_dev->device.name = devargs->name; > + afu_dev->rawdev = rawdev; > + afu_dev->id.uuid_low = 0; > + afu_dev->id.uuid_high = 0; > + afu_dev->id.port = afu_pr_conf.afu_id.port; > + afu_dev->ifpga_dev = ifpga_dev; > + > + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) > + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); > + > + if (rawdev->dev_ops && > + rawdev->dev_ops->dev_start && > + rawdev->dev_ops->dev_start(rawdev)) > + goto free_dev; > + > + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); > + if (rawdev->dev_ops->firmware_load && > + rawdev->dev_ops->firmware_load(rawdev, > + &afu_pr_conf)){ > + IFPGA_BUS_ERR("firmware load error %d\n", ret); > + goto free_dev; > + } > + afu_dev->id.uuid_low = afu_pr_conf.afu_id.uuid_low; > + afu_dev->id.uuid_high = afu_pr_conf.afu_id.uuid_high; > + > + > + return afu_dev; > + > +free_dev: > + free(afu_dev); > +end: > + if (kvlist) You can remove above if statement for simplicity. > + rte_kvargs_free(kvlist); > + if (path) Ditto. > + free(path); > + > + return NULL; > +} > + > +/* > + * Scan the content of the FPGA bus, and the devices in the devices > + * list > + */ > +static int > +rte_ifpga_scan(void) > +{ > + struct rte_ifpga_device *ifpga_dev; > + struct rte_devargs *devargs; > + struct rte_kvargs *kvlist = NULL; > + struct rte_rawdev *rawdev = NULL; > + char *name = NULL; > + char name1[RTE_RAWDEV_NAME_MAX_LEN]; > + struct rte_afu_device *afu_dev = NULL; > + > + /* for FPGA devices we scan the devargs_list populated via cmdline */ > + RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { > + if (devargs->bus != &rte_ifpga_bus) > + continue; > + > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > + if (!kvlist) { > + IFPGA_BUS_ERR("error when parsing param"); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, > + &ifpga_get_string_arg, &name) < 0) { > + IFPGA_BUS_ERR("error to parse %s", > + IFPGA_ARG_NAME); > + goto end; > + } > + } else { > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_ARG_NAME); > + goto end; > + } > + > + memset(name1, 0, sizeof(name1)); > + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", name); Change to use strlcpy instead. > + > + rawdev = rte_rawdev_pmd_get_named_dev(name1); > + if (!rawdev) > + goto end; > + > + if (ifpga_find_ifpga_dev(rawdev)) > + continue; > + > + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); > + if (!ifpga_dev) > + goto end; > + > + ifpga_dev->rdev = rawdev; > + TAILQ_INIT(&ifpga_dev->afu_list); > + > + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); > + afu_dev = rte_ifpga_scan_one(devargs, ifpga_dev); > + if (afu_dev != NULL) > + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, next); > + } > + > +end: > + if (kvlist) Ditto. > + rte_kvargs_free(kvlist); > + if (name) Ditto. > + free(name); > + > + return 0; > +} > + > +/* > + * Match the AFU Driver and AFU Device using the ID Table > + */ > +static int > +rte_afu_match(const struct rte_afu_driver *afu_drv, > + const struct rte_afu_device *afu_dev) > +{ > + const struct rte_afu_uuid *id_table; > + > + for (id_table = afu_drv->id_table; > + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); > + id_table++) { > + /* check if device's identifiers match the driver's ones */ > + if ((id_table->uuid_low != afu_dev->id.uuid_low) || > + (id_table->uuid_high != afu_dev->id.uuid_high)) > + continue; > + > + return 1; > + } > + > + return 0; > +} > + > +static int > +ifpga_probe_one_driver(struct rte_afu_driver *drv, > + struct rte_afu_device *afu_dev) > +{ > + int ret; > + > + if (!rte_afu_match(drv, afu_dev)) > + /* Match of device and driver failed */ > + return 1; > + > + /* reference driver structure */ > + afu_dev->driver = drv; > + afu_dev->device.driver = &drv->driver; > + > + /* call the driver probe() function */ > + ret = drv->probe(afu_dev); > + if (ret) { > + afu_dev->driver = NULL; > + afu_dev->device.driver = NULL; > + } > + > + /* return positive value if driver doesn't support this device */ This comment seems wrong; you already exclude the case that this driver does not support this device (>0); here, we only have the cases that, probe succeeds (=0), and probe fails (<0). > + return 0; return ret instead of 0? > +} > + > +static int > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) > +{ > + struct rte_afu_driver *drv = NULL; > + int rc; > + > + if (afu_dev == NULL) > + return -1; > + > + /* Check if a driver is already loaded */ > + if (afu_dev->driver != NULL) > + return 0; > + > + TAILQ_FOREACH(drv, &afu_driver_list, next) { > + rc = ifpga_probe_one_driver(drv, afu_dev); > + if (rc < 0) > + /* negative value is an error */ > + return -1; > + if (rc > 0) > + /* positive value means driver doesn't support it */ > + continue; > + return 0; > + } > + return 1; > +} > + > +/* > + * Scan the content of the Intel FPGA bus, and call the probe() function for > + * all registered drivers that have a matching entry in its id_table > + * for discovered devices. > + */ > +static int > +rte_ifpga_probe(void) > +{ > + struct rte_ifpga_device *ifpga_dev; > + struct rte_afu_device *afu_dev = NULL; > + int ret = 0; > + > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > + > + if (afu_dev->device.driver) > + continue; > + > + ret = ifpga_probe_all_drivers(afu_dev); > + if (ret < 0) > + IFPGA_BUS_ERR("failed to initialize %s device\n", > + rte_ifpga_device_name(afu_dev)); > + } > + } > + > + return 0; > +} > + > +static int > +rte_ifpga_plug(struct rte_device *dev) > +{ > + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); > +} > + > +static int ifpga_remove_driver(struct rte_afu_device *afu_dev) > +{ > + const char *name; > + const struct rte_afu_driver *driver; > + > + name = rte_ifpga_device_name(afu_dev); > + if (!afu_dev->device.driver) { > + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); > + return 1; > + } > + > + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); > + return driver->remove(afu_dev); > +} > + > +static int > +rte_ifpga_unplug(struct rte_device *dev) > +{ > + struct rte_ifpga_device *ifpga_dev = NULL; > + struct rte_afu_device *afu_dev = NULL; > + struct rte_devargs *devargs = NULL; > + int ret; > + > + if (dev == NULL) > + return -EINVAL; > + > + afu_dev = RTE_DEV_TO_AFU(dev); > + if (!dev) > + return -ENOENT; > + > + ifpga_dev = afu_dev->ifpga_dev; > + devargs = dev->devargs; > + > + ret = ifpga_remove_driver(afu_dev); > + if (ret) > + return ret; > + > + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); > + > + rte_devargs_remove(devargs->bus->name, devargs->name); > + free(afu_dev); > + return 0; > + > +} > + > +static struct rte_device * > +rte_ifpga_find_device(const struct rte_device *start, > + rte_dev_cmp_t cmp, const void *data) > +{ > + struct rte_ifpga_device *ifpga_dev; > + struct rte_afu_device *afu_dev; > + > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > + if (start && &afu_dev->device == start) { > + start = NULL; > + continue; > + } > + if (cmp(&afu_dev->device, data) == 0) > + return &afu_dev->device; > + } > + } > + return NULL; > +} > +static int > +rte_ifpga_parse(const char *name, void *addr) > +{ > + int *out = addr; > + struct rte_rawdev *rawdev = NULL; > + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; > + char *c1 = NULL, *c2 = NULL; > + int port = IFPGA_BUS_DEV_PORT_MAX; Duplicated spaces after "int". > + char str_port[8]; > + int str_port_len = 0; > + int ret; > + > + memset(str_port, 0, 8); > + c1 = strchr(name, '|'); > + if (c1 != NULL) { > + str_port_len = c1-name; > + c2 = c1+1; > + } > + > + if (str_port_len < 8 && > + str_port_len > 0) { > + memcpy(str_port, name, str_port_len); > + ret = sscanf(str_port, "%d", &port); > + if (ret == -1) > + return 0; > + } > + > + memset(rawdev_name, 0, sizeof(rawdev_name)); > + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", c2); > + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); > + > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > + rawdev && > + (addr != NULL)) > + *out = port; > + > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > + rawdev) > + return 0; > + else > + return 1; > +} > + > +static struct rte_bus rte_ifpga_bus = { > + .scan = rte_ifpga_scan, > + .probe = rte_ifpga_probe, > + .find_device = rte_ifpga_find_device, > + .plug = rte_ifpga_plug, > + .unplug = rte_ifpga_unplug, > + .parse = rte_ifpga_parse, > +}; > + > +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); > + > +RTE_INIT(ifpga_init_log) > +{ > + ifpga_bus_logtype = rte_log_register("bus.ifpga"); > + if (ifpga_bus_logtype >= 0) > + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); > +} > diff --git a/drivers/bus/ifpga/ifpga_common.c b/drivers/bus/ifpga/ifpga_common.c > new file mode 100644 > index 0000000..26fee27 > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_common.c > @@ -0,0 +1,88 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation > + */ > + > +#include <string.h> > +#include <inttypes.h> > +#include <stdint.h> > +#include <stdlib.h> > +#include <stdio.h> > +#include <sys/queue.h> > +#include <sys/mman.h> > +#include <sys/types.h> > +#include <unistd.h> > +#include <fcntl.h> > + > +#include <rte_errno.h> > +#include <rte_bus.h> > +#include <rte_per_lcore.h> > +#include <rte_memory.h> > +#include <rte_memzone.h> > +#include <rte_eal.h> > +#include <rte_common.h> > + > +#include <rte_devargs.h> > +#include <rte_kvargs.h> > +#include <rte_alarm.h> > + > +#include "rte_bus_ifpga.h" > +#include "ifpga_logs.h" > +#include "ifpga_common.h" > + > +int ifpga_get_string_arg(const char *key __rte_unused, > + const char *value, void *extra_args) > +{ > + if (!value || !extra_args) > + return -EINVAL; > + > + *(char **)extra_args = strdup(value); > + > + if (!*(char **)extra_args) > + return -ENOMEM; > + > + return 0; > +} > +int ifpga_get_integer32_arg(const char *key __rte_unused, > + const char *value, void *extra_args) > +{ > + if (!value || !extra_args) > + return -EINVAL; > + > + *(int *)extra_args = strtoull(value, NULL, 0); > + > + return 0; > +} > +int ifpga_get_integer64_arg(const char *key __rte_unused, > + const char *value, void *extra_args) > +{ > + if (!value || !extra_args) > + return -EINVAL; > + > + *(uint64_t *)extra_args = strtoull(value, NULL, 0); > + > + return 0; > +} > +int ifpga_get_unsigned_long(const char *str, int base) > +{ > + unsigned long num; > + char *end = NULL; > + > + errno = 0; > + > + num = strtoul(str, &end, base); > + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) > + return -1; > + > + return num; > +} > + > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > + const struct rte_afu_id *afu_id1) > +{ > + if ((afu_id0->uuid_low == afu_id1->uuid_low) && > + (afu_id0->uuid_high == afu_id1->uuid_high) && > + (afu_id0->port == afu_id1->port)) { > + return 0; > + } else > + return 1; > +} > diff --git a/drivers/bus/ifpga/ifpga_common.h b/drivers/bus/ifpga/ifpga_common.h > new file mode 100644 > index 0000000..b6662c8 > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_common.h > @@ -0,0 +1,18 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation > + */ > + > +#ifndef _IFPGA_COMMON_H_ > +#define _IFPGA_COMMON_H_ > + > +int ifpga_get_string_arg(const char *key __rte_unused, > + const char *value, void *extra_args); > +int ifpga_get_integer32_arg(const char *key __rte_unused, > + const char *value, void *extra_args); > +int ifpga_get_integer64_arg(const char *key __rte_unused, > + const char *value, void *extra_args); > +int ifpga_get_unsigned_long(const char *str, int base); > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > + const struct rte_afu_id *afu_id1); > + > +#endif /* _IFPGA_COMMON_H_ */ > diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h > new file mode 100644 > index 0000000..873e0a4 > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_logs.h > @@ -0,0 +1,31 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation > + */ > + > +#ifndef _IFPGA_LOGS_H_ > +#define _IFPGA_LOGS_H_ > + > +#include <rte_log.h> > + > +extern int ifpga_bus_logtype; > + > +#define IFPGA_LOG(level, fmt, args...) \ > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > + __func__, ##args) > + > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > + __func__, ##args) > + > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > + > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) > +#define IFPGA_BUS_INFO(fmt, args...) \ > + IFPGA_BUS_LOG(INFO, fmt, ## args) > +#define IFPGA_BUS_ERR(fmt, args...) \ > + IFPGA_BUS_LOG(ERR, fmt, ## args) > +#define IFPGA_BUS_WARN(fmt, args...) \ > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > + > +#endif /* _IFPGA_BUS_LOGS_H_ */ > diff --git a/drivers/bus/ifpga/meson.build b/drivers/bus/ifpga/meson.build > new file mode 100644 > index 0000000..4ea31f1 > --- /dev/null > +++ b/drivers/bus/ifpga/meson.build > @@ -0,0 +1,6 @@ > +# SPDX-License-Identifier: BSD-3-Clause > +# Copyright(c) 2010-2018 Intel Corporation > + > +deps += ['pci', 'kvargs', 'rawdev'] > +install_headers('rte_bus_ifpga.h') > +sources = files('ifpga_common.c', 'ifpga_bus.c') > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h > new file mode 100644 > index 0000000..53e7183 > --- /dev/null > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > @@ -0,0 +1,168 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation > + */ > + > +#ifndef _RTE_BUS_IFPGA_H_ > +#define _RTE_BUS_IFPGA_H_ > + > +/** > + * @file > + * > + * RTE Intel FPGA Bus Interface > + */ > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include <rte_bus.h> > +#include <rte_pci.h> > + > +/** Name of Intel FPGA Bus */ > +#define IFPGA_BUS_NAME ifpga > + > +/* Forward declarations */ > +struct rte_afu_device; > + > +/** List of Intel AFU devices */ > +TAILQ_HEAD(afu_device_list, rte_afu_device); > +/** Double linked list of AFU device drivers. */ > +TAILQ_HEAD(afu_driver_list, rte_afu_driver); > + > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > + > +struct rte_afu_uuid { > + uint64_t uuid_low; > + uint64_t uuid_high; > +} __attribute__ ((packed)); > + > +#define IFPGA_BUS_DEV_PORT_MAX 4 > + > +/** > + * A structure describing an ID for a AFU driver. Each driver provides a It seems that this struct is for describing the AFU device, instead of AFU driver, no? > + * table of these IDs for each device that it supports. > + */ > +struct rte_afu_id { > + uint64_t uuid_low; > + uint64_t uuid_high; Why not reuse struct rte_afu_uuid for above two fields? > + int port; Can you add a note on what *port* means? > +} __attribute__ ((packed)); > + > +/** > + * A structure pr configuration AFU driver. What does pr mean? Mind to add a full name for it? > + */ > + > +struct rte_afu_pr_conf { > + struct rte_afu_id afu_id; > + int pr_enable; > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > +}; > + > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > + > +/** > + * A structure describing a fpga device. > + */ > +struct rte_ifpga_device { > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ > + struct rte_rawdev *rdev; > + struct afu_device_list afu_list; /**< List of AFU devices */ > +}; > + > +/** > + * A structure describing a AFU device. > + */ > +struct rte_afu_device { > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ > + struct rte_device device; /**< Inherit core device */ > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > + struct rte_afu_id id; /**< AFU id within FPGA. */ > + uint32_t num_region; /**< number of regions found */ > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > + /**< AFU Memory Resource */ > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > + struct rte_afu_driver *driver; /**< Associated driver */ > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > +} __attribute__ ((packed)); > + > +/** > + * @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_DRV_TO_AFU_CONST(ptr) \ > + container_of(ptr, const struct rte_afu_driver, driver) > + > +/** > + * Initialisation function for the driver called during FPGA BUS probing. > + */ > +typedef int (afu_probe_t)(struct rte_afu_device *); > + > +/** > + * Uninitialisation function for the driver called during hotplugging. > + */ > +typedef int (afu_remove_t)(struct rte_afu_device *); > + > +/** > + * A structure describing a AFU device. > + */ > +struct rte_afu_driver { > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > + struct rte_driver driver; /**< Inherit core driver. */ > + afu_probe_t *probe; /**< Device Probe function. */ > + afu_remove_t *remove; /**< Device Remove function. */ > + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ > + uint32_t drv_flags; /**< Flags contolling handling of device. */ > +}; > + > +/** > + * Structure describing the Intel FPGA bus > + */ > +struct rte_ifpga_bus { > + struct rte_bus bus; /**< Inherit the generic class */ > +}; Where is this struct used? > + > +static inline const char * > +rte_ifpga_device_name(const struct rte_afu_device *afu) > +{ > + if (afu && afu->device.name) > + return afu->device.name; > + return NULL; > +} > + > +/** > + * Register a ifpga afu device driver. > + * > + * @param driver > + * A pointer to a rte_afu_driver structure describing the driver > + * to be registered. > + */ > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); > + > +/** > + * Unregister a ifpga afu device driver. > + * > + * @param driver > + * A pointer to a rte_afu_driver structure describing the driver > + * to be unregistered. > + */ > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > + > +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ > +RTE_INIT(afudrvinitfn_ ##afudrv);\ > +static const char *afudrvinit_ ## nm ## _alias;\ > +static void afudrvinitfn_ ##afudrv(void)\ > +{\ > + (afudrv).driver.name = RTE_STR(nm);\ > + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ > + rte_ifpga_driver_register(&afudrv);\ > +} \ > +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) > + > +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ > +static const char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) Do we really need alias for new bus? Originally, alias is a way for compatibility, but it seems that it's not necessary for new bus. > + > +#endif /* _RTE_BUS_IFPGA_H_ */ > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map > new file mode 100644 > index 0000000..1304caf > --- /dev/null > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > @@ -0,0 +1,10 @@ > +DPDK_18.05 { > + global: > + > + ifpga_get_integer32_arg; > + ifpga_get_string_arg; Above two functions shall be not exposed as APIs. > + rte_ifpga_driver_register; > + rte_ifpga_driver_unregister; > + > + local: *; > +}; > diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build > index 58dfbe2..170df25 100644 > --- a/drivers/bus/meson.build > +++ b/drivers/bus/meson.build > @@ -1,7 +1,7 @@ > # SPDX-License-Identifier: BSD-3-Clause > # Copyright(c) 2017 Intel Corporation > > -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] > +drivers = ['dpaa', 'fslmc', 'pci', 'vdev', 'ifpga'] > std_deps = ['eal'] > config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' > driver_name_fmt = 'rte_bus_@0@' > diff --git a/mk/rte.app.mk b/mk/rte.app.mk > index a145791..9de2edb 100644 > --- a/mk/rte.app.mk > +++ b/mk/rte.app.mk > @@ -107,6 +107,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE) += -lrte_cmdline > _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder > _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrte_sched > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga > + > ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) > _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni > endif ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v6 1/5] iFPGA: Add Intel FPGA BUS Library 2018-05-03 3:58 ` Tan, Jianfeng @ 2018-05-03 8:12 ` Tan, Jianfeng 2018-05-03 8:35 ` Zhang, Tianfei 1 sibling, 0 replies; 149+ messages in thread From: Tan, Jianfeng @ 2018-05-03 8:12 UTC (permalink / raw) To: Xu, Rosen, dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet On 5/3/2018 11:58 AM, Tan, Jianfeng wrote: > I have a question, hope you can clarify it a little bit. As I > understand, this FPGA bus are used for AFU device enumeration, and > each device on this bus needs a AFU driver to drive. But now we > register AFU drivers, but enumerate rte_ifpga_device. Why? The reason > I can think of, we need to maintain the relationship of fpga devices > and afu devices. But I think similar problem would exist in dpaa and > fslmc bus too. It is interesting to know the best practice on this. After offline discussion with Tianfei, I got that current implementation is to add a bus for afu devices and afu drivers. As for the bus name, ifpga bus or afu bus, I'm OK to both; only if you clarify the purpose of this bus is to manage afu devices and afu drivers. Thanks, Jianfeng ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v6 1/5] iFPGA: Add Intel FPGA BUS Library 2018-05-03 3:58 ` Tan, Jianfeng 2018-05-03 8:12 ` Tan, Jianfeng @ 2018-05-03 8:35 ` Zhang, Tianfei 1 sibling, 0 replies; 149+ messages in thread From: Zhang, Tianfei @ 2018-05-03 8:35 UTC (permalink / raw) To: Tan, Jianfeng, Xu, Rosen, dev Cc: Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Wu, Hao, gaetan.rivet > -----Original Message----- > From: Tan, Jianfeng > Sent: Thursday, May 3, 2018 11:58 AM > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org > Cc: Doherty, Declan <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Wu, Hao <hao.wu@intel.com>; gaetan.rivet@6wind.com > Subject: Re: [dpdk-dev] [PATCH v6 1/5] iFPGA: Add Intel FPGA BUS Library > > For title prefix, use "bus/ifpga" instead. Will fix in next version. > > > On 4/26/2018 5:43 PM, Xu, Rosen wrote: > > From: Rosen Xu <rosen.xu@intel.com> > > > > Defined FPGA-BUS for Acceleration Drivers of AFUs 1. FPGA PCI Scan > > (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA > > Rawdev Driver. > > As I understand, this part is not covered in this patch. You might want to add > a note that "it will be covered in following patches". Yes, this scan in Intel FPGA raw device driver. Will fix this comment in next version. > > > 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. > > This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan > > the AFUs will be created and their drivers are also probed. > > This patch is not only responsible for scan, but also other bus ops. So in your > commit log, you might want to clarify this, like we introduce rte_afu_device. > > I have a question, hope you can clarify it a little bit. As I understand, this > FPGA bus are used for AFU device enumeration, and each device on this bus > needs a AFU driver to drive. But now we register AFU drivers, but enumerate > rte_ifpga_device. Why? The reason I can think of, we need to maintain the > relationship of fpga devices and afu devices. > But I think similar problem would exist in dpaa and fslmc bus too. It is > interesting to know the best practice on this. Suppose we will have multiple FPGA chips in one system, and each FPGA chip will has multiple AFUs, So the rte_ifpga_device will describe the FPGA chip. > > Besides, I see you are using a devargs for scanning, would you like to provide > an example here? This is an example run ethernet functionality on AFU 0 of FPGA (pci addr = 5e:00.0) #./x86_64-native-linuxapp-gcc/app/testpmd -c 0x3 -n 4 --socket-mem 1024,0 --huge-dir=/mnt/huge --vdev 'net_ifpga_cfg0,ifpga=5e:00.0,port=0,afu_bts=./ether.gbs' -- -i --no-numa > > > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > Signed-off-by: Figo zhang <tianfei.zhang@intel.com> > > --- > > config/common_base | 5 + > > drivers/bus/Makefile | 1 + > > drivers/bus/ifpga/Makefile | 32 ++ > > drivers/bus/ifpga/ifpga_bus.c | 503 > ++++++++++++++++++++++++++++ > > drivers/bus/ifpga/ifpga_common.c | 88 +++++ > > drivers/bus/ifpga/ifpga_common.h | 18 + > > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > > drivers/bus/ifpga/meson.build | 6 + > > drivers/bus/ifpga/rte_bus_ifpga.h | 168 ++++++++++ > > drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + > > drivers/bus/meson.build | 2 +- > > mk/rte.app.mk | 2 + > > 12 files changed, 865 insertions(+), 1 deletion(-) > > create mode 100644 drivers/bus/ifpga/Makefile > > create mode 100644 drivers/bus/ifpga/ifpga_bus.c > > create mode 100644 drivers/bus/ifpga/ifpga_common.c > > create mode 100644 drivers/bus/ifpga/ifpga_common.h > > create mode 100644 drivers/bus/ifpga/ifpga_logs.h > > create mode 100644 drivers/bus/ifpga/meson.build > > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h > > create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > diff --git a/config/common_base b/config/common_base > > index 7e45412..b59f1de 100644 > > --- a/config/common_base > > +++ b/config/common_base > > @@ -148,6 +148,11 @@ CONFIG_RTE_LIBRTE_PCI_BUS=y > > CONFIG_RTE_LIBRTE_VDEV_BUS=y > > > > # > > +# Compile the Intel FPGA bus > > +# > > +CONFIG_RTE_LIBRTE_IFPGA_BUS=y > > + > > +# > > # Compile ARK PMD > > # > > CONFIG_RTE_LIBRTE_ARK_PMD=y > > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile > > index c251b65..cff3567 100644 > > --- a/drivers/bus/Makefile > > +++ b/drivers/bus/Makefile > > @@ -9,5 +9,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc > > endif > > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > > > > include $(RTE_SDK)/mk/rte.subdir.mk > > diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile > > new file mode 100644 > > index 0000000..3ff3bdb > > --- /dev/null > > +++ b/drivers/bus/ifpga/Makefile > > @@ -0,0 +1,32 @@ > > +# SPDX-License-Identifier: BSD-3-Clause > > +# Copyright(c) 2018 Intel Corporation > > + > > +include $(RTE_SDK)/mk/rte.vars.mk > > + > > +# > > +# library name > > +# > > +LIB = librte_bus_ifpga.a > > + > > +CFLAGS += -DALLOW_EXPERIMENTAL_API > > +CFLAGS += -O3 > > +CFLAGS += $(WERROR_FLAGS) > > +LDLIBS += -lrte_eal > > +LDLIBS += -lrte_rawdev > > +LDLIBS += -lrte_kvargs > > + > > +# versioning export map > > +EXPORT_MAP := rte_bus_ifpga_version.map > > + > > +# library version > > +LIBABIVER := 1 > > + > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c > > + > > +# > > +# Export include files > > +# > > +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h > > + > > +include $(RTE_SDK)/mk/rte.lib.mk > > diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c > > new file mode 100644 > > index 0000000..67c24ae > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_bus.c > > @@ -0,0 +1,503 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation > > + */ > > + > > +#include <string.h> > > +#include <inttypes.h> > > +#include <stdint.h> > > +#include <stdlib.h> > > +#include <stdio.h> > > +#include <sys/queue.h> > > +#include <sys/mman.h> > > +#include <sys/types.h> > > +#include <unistd.h> > > +#include <fcntl.h> > > + > > +#include <rte_errno.h> > > +#include <rte_bus.h> > > +#include <rte_per_lcore.h> > > +#include <rte_memory.h> > > +#include <rte_memzone.h> > > +#include <rte_eal.h> > > +#include <rte_common.h> > > + > > +#include <rte_devargs.h> > > +#include <rte_kvargs.h> > > +#include <rte_alarm.h> > > + > > +#include "rte_rawdev.h" > > +#include "rte_rawdev_pmd.h" > > +#include "rte_bus_ifpga.h" > > +#include "ifpga_logs.h" > > +#include "ifpga_common.h" > > + > > +int ifpga_bus_logtype; > > + > > +/* Forward declare to access Intel FPGA bus name */ > > s/declare/declaration, actually, does "Intel FPGA bus on which iFPGA > devices are connected" sound better? Yes, sounds good. > > > +static struct rte_bus rte_ifpga_bus; > > + > > +/** Double linked list of IFPGA device. */ > > +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); > > + > > +static struct ifpga_device_list ifpga_device_list = > > + TAILQ_HEAD_INITIALIZER(ifpga_device_list); > > +struct afu_driver_list afu_driver_list = > > Why not keep this list as static? Will fix it in next version. > > > + TAILQ_HEAD_INITIALIZER(afu_driver_list); > > + > > + > > +/* register a ifpga bus based driver */ > > +void rte_ifpga_driver_register(struct rte_afu_driver *driver) > > +{ > > + RTE_VERIFY(driver); > > + > > + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); > > +} > > + > > +/* un-register a fpga bus based driver */ > > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) > > +{ > > + TAILQ_REMOVE(&afu_driver_list, driver, next); > > +} > > + > > +static struct rte_ifpga_device * > > +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) > > +{ > > + struct rte_ifpga_device *ifpga_dev = NULL; > > + > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > + if (rdev && > > + ifpga_dev->rdev && > > + ifpga_dev->rdev == rdev) > > + return ifpga_dev; > > + } > > + return NULL; > > +} > > + > > +static struct rte_afu_device * > > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > > + const struct rte_afu_id *afu_id) > > +{ > > + struct rte_afu_device *afu_dev = NULL; > > + > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > > + return afu_dev; > > + } > > + return NULL; > > +} > > + > > +static const char * const valid_args[] = { > > +#define IFPGA_ARG_NAME "ifpga" > > + IFPGA_ARG_NAME, > > +#define IFPGA_ARG_PORT "port" > > + IFPGA_ARG_PORT, > > +#define IFPGA_AFU_BTS "afu_bts" > > + IFPGA_AFU_BTS, > > + NULL > > +}; > > + > > +/* > > + * Scan the content of the FPGA bus, and the devices in the devices > > + * list > > + */ > > +static struct rte_afu_device * > > +rte_ifpga_scan_one(struct rte_devargs *devargs, > > For internal functions, we'd better not use the prefix "rte". Will fix in next version. > > > + struct rte_ifpga_device *ifpga_dev) > > +{ > > + struct rte_kvargs *kvlist = NULL; > > + struct rte_rawdev *rawdev = NULL; > > + struct rte_afu_device *afu_dev = NULL; > > + struct rte_afu_pr_conf afu_pr_conf; > > + int ret = 0; > > + char *path = NULL; > > + > > + memset((char *)(&afu_pr_conf), 0, sizeof(struct rte_afu_pr_conf)); > > For "void *", no need to add explicit type cast. Will fix in next version. > > > + > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > + if (!kvlist) { > > + IFPGA_BUS_ERR("error when parsing param"); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, > > + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_PORT); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PORT); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, > > + &ifpga_get_string_arg, &path) < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > s/error/failed I think error and failed is ok. > > > + IFPGA_AFU_BTS); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_AFU_BTS); > > + goto end; > > + } > > + > > + afu_pr_conf.afu_id.uuid_low = 0; > > + afu_pr_conf.afu_id.uuid_high = 0; > > + afu_pr_conf.pr_enable = path?1:0; > > + > > + rawdev = ifpga_dev->rdev; > > + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) > > + goto end; > > + > > + afu_dev = calloc(1, sizeof(*afu_dev)); > > + if (!afu_dev) > > + goto end; > > + > > + afu_dev->device.devargs = devargs; > > + afu_dev->device.numa_node = SOCKET_ID_ANY; > > + afu_dev->device.name = devargs->name; > > + afu_dev->rawdev = rawdev; > > + afu_dev->id.uuid_low = 0; > > + afu_dev->id.uuid_high = 0; > > + afu_dev->id.port = afu_pr_conf.afu_id.port; > > + afu_dev->ifpga_dev = ifpga_dev; > > + > > + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) > > + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); > > + > > + if (rawdev->dev_ops && > > + rawdev->dev_ops->dev_start && > > + rawdev->dev_ops->dev_start(rawdev)) > > + goto free_dev; > > + > > + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); > > + if (rawdev->dev_ops->firmware_load && > > + rawdev->dev_ops->firmware_load(rawdev, > > + &afu_pr_conf)){ > > + IFPGA_BUS_ERR("firmware load error %d\n", ret); > > + goto free_dev; > > + } > > + afu_dev->id.uuid_low = afu_pr_conf.afu_id.uuid_low; > > + afu_dev->id.uuid_high = afu_pr_conf.afu_id.uuid_high; > > + > > + > > + return afu_dev; > > + > > +free_dev: > > + free(afu_dev); > > +end: > > + if (kvlist) > > You can remove above if statement for simplicity. > > > + rte_kvargs_free(kvlist); > > + if (path) > > Ditto. > > > + free(path); > > + > > + return NULL; > > +} > > + > > +/* > > + * Scan the content of the FPGA bus, and the devices in the devices > > + * list > > + */ > > +static int > > +rte_ifpga_scan(void) > > +{ > > + struct rte_ifpga_device *ifpga_dev; > > + struct rte_devargs *devargs; > > + struct rte_kvargs *kvlist = NULL; > > + struct rte_rawdev *rawdev = NULL; > > + char *name = NULL; > > + char name1[RTE_RAWDEV_NAME_MAX_LEN]; > > + struct rte_afu_device *afu_dev = NULL; > > + > > + /* for FPGA devices we scan the devargs_list populated via cmdline */ > > + RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { > > + if (devargs->bus != &rte_ifpga_bus) > > + continue; > > + > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > + if (!kvlist) { > > + IFPGA_BUS_ERR("error when parsing param"); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, > > + &ifpga_get_string_arg, &name) < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_NAME); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_NAME); > > + goto end; > > + } > > + > > + memset(name1, 0, sizeof(name1)); > > + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", > name); > > Change to use strlcpy instead. Got it, I agree, will fix in next version. > > > + > > + rawdev = rte_rawdev_pmd_get_named_dev(name1); > > + if (!rawdev) > > + goto end; > > + > > + if (ifpga_find_ifpga_dev(rawdev)) > > + continue; > > + > > + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); > > + if (!ifpga_dev) > > + goto end; > > + > > + ifpga_dev->rdev = rawdev; > > + TAILQ_INIT(&ifpga_dev->afu_list); > > + > > + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); > > + afu_dev = rte_ifpga_scan_one(devargs, ifpga_dev); > > + if (afu_dev != NULL) > > + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, next); > > + } > > + > > +end: > > + if (kvlist) > > Ditto. > > > + rte_kvargs_free(kvlist); > > + if (name) > > Ditto. > > > + free(name); > > + > > + return 0; > > +} > > + > > +/* > > + * Match the AFU Driver and AFU Device using the ID Table > > + */ > > +static int > > +rte_afu_match(const struct rte_afu_driver *afu_drv, > > + const struct rte_afu_device *afu_dev) > > +{ > > + const struct rte_afu_uuid *id_table; > > + > > + for (id_table = afu_drv->id_table; > > + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); > > + id_table++) { > > + /* check if device's identifiers match the driver's ones */ > > + if ((id_table->uuid_low != afu_dev->id.uuid_low) || > > + (id_table->uuid_high != afu_dev->id.uuid_high)) > > + continue; > > + > > + return 1; > > + } > > + > > + return 0; > > +} > > + > > +static int > > +ifpga_probe_one_driver(struct rte_afu_driver *drv, > > + struct rte_afu_device *afu_dev) > > +{ > > + int ret; > > + > > + if (!rte_afu_match(drv, afu_dev)) > > + /* Match of device and driver failed */ > > + return 1; > > + > > + /* reference driver structure */ > > + afu_dev->driver = drv; > > + afu_dev->device.driver = &drv->driver; > > + > > + /* call the driver probe() function */ > > + ret = drv->probe(afu_dev); > > + if (ret) { > > + afu_dev->driver = NULL; > > + afu_dev->device.driver = NULL; > > + } > > + > > + /* return positive value if driver doesn't support this device */ > > This comment seems wrong; you already exclude the case that this driver > does not support this device (>0); here, we only have the cases that, > probe succeeds (=0), and probe fails (<0). > > > + return 0; > > return ret instead of 0? I agree, this return ret is better. > > > +} > > + > > +static int > > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) > > +{ > > + struct rte_afu_driver *drv = NULL; > > + int rc; > > + > > + if (afu_dev == NULL) > > + return -1; > > + > > + /* Check if a driver is already loaded */ > > + if (afu_dev->driver != NULL) > > + return 0; > > + > > + TAILQ_FOREACH(drv, &afu_driver_list, next) { > > + rc = ifpga_probe_one_driver(drv, afu_dev); > > + if (rc < 0) > > + /* negative value is an error */ > > + return -1; > > + if (rc > 0) > > + /* positive value means driver doesn't support it */ > > + continue; > > + return 0; > > + } > > + return 1; > > +} > > + > > +/* > > + * Scan the content of the Intel FPGA bus, and call the probe() function for > > + * all registered drivers that have a matching entry in its id_table > > + * for discovered devices. > > + */ > > +static int > > +rte_ifpga_probe(void) > > +{ > > + struct rte_ifpga_device *ifpga_dev; > > + struct rte_afu_device *afu_dev = NULL; > > + int ret = 0; > > + > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > + > > + if (afu_dev->device.driver) > > + continue; > > + > > + ret = ifpga_probe_all_drivers(afu_dev); > > + if (ret < 0) > > + IFPGA_BUS_ERR("failed to initialize %s device\n", > > + rte_ifpga_device_name(afu_dev)); > > + } > > + } > > + > > + return 0; > > +} > > + > > +static int > > +rte_ifpga_plug(struct rte_device *dev) > > +{ > > + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); > > +} > > + > > +static int ifpga_remove_driver(struct rte_afu_device *afu_dev) > > +{ > > + const char *name; > > + const struct rte_afu_driver *driver; > > + > > + name = rte_ifpga_device_name(afu_dev); > > + if (!afu_dev->device.driver) { > > + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); > > + return 1; > > + } > > + > > + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); > > + return driver->remove(afu_dev); > > +} > > + > > +static int > > +rte_ifpga_unplug(struct rte_device *dev) > > +{ > > + struct rte_ifpga_device *ifpga_dev = NULL; > > + struct rte_afu_device *afu_dev = NULL; > > + struct rte_devargs *devargs = NULL; > > + int ret; > > + > > + if (dev == NULL) > > + return -EINVAL; > > + > > + afu_dev = RTE_DEV_TO_AFU(dev); > > + if (!dev) > > + return -ENOENT; > > + > > + ifpga_dev = afu_dev->ifpga_dev; > > + devargs = dev->devargs; > > + > > + ret = ifpga_remove_driver(afu_dev); > > + if (ret) > > + return ret; > > + > > + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); > > + > > + rte_devargs_remove(devargs->bus->name, devargs->name); > > + free(afu_dev); > > + return 0; > > + > > +} > > + > > +static struct rte_device * > > +rte_ifpga_find_device(const struct rte_device *start, > > + rte_dev_cmp_t cmp, const void *data) > > +{ > > + struct rte_ifpga_device *ifpga_dev; > > + struct rte_afu_device *afu_dev; > > + > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > + if (start && &afu_dev->device == start) { > > + start = NULL; > > + continue; > > + } > > + if (cmp(&afu_dev->device, data) == 0) > > + return &afu_dev->device; > > + } > > + } > > + return NULL; > > +} > > +static int > > +rte_ifpga_parse(const char *name, void *addr) > > +{ > > + int *out = addr; > > + struct rte_rawdev *rawdev = NULL; > > + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; > > + char *c1 = NULL, *c2 = NULL; > > + int port = IFPGA_BUS_DEV_PORT_MAX; > > Duplicated spaces after "int". Will fix it in next version. > > > + char str_port[8]; > > + int str_port_len = 0; > > + int ret; > > + > > + memset(str_port, 0, 8); > > + c1 = strchr(name, '|'); > > + if (c1 != NULL) { > > + str_port_len = c1-name; > > + c2 = c1+1; > > + } > > + > > + if (str_port_len < 8 && > > + str_port_len > 0) { > > + memcpy(str_port, name, str_port_len); > > + ret = sscanf(str_port, "%d", &port); > > + if (ret == -1) > > + return 0; > > + } > > + > > + memset(rawdev_name, 0, sizeof(rawdev_name)); > > + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", > c2); > > + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); > > + > > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > > + rawdev && > > + (addr != NULL)) > > + *out = port; > > + > > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > > + rawdev) > > + return 0; > > + else > > + return 1; > > +} > > + > > +static struct rte_bus rte_ifpga_bus = { > > + .scan = rte_ifpga_scan, > > + .probe = rte_ifpga_probe, > > + .find_device = rte_ifpga_find_device, > > + .plug = rte_ifpga_plug, > > + .unplug = rte_ifpga_unplug, > > + .parse = rte_ifpga_parse, > > +}; > > + > > +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); > > + > > +RTE_INIT(ifpga_init_log) > > +{ > > + ifpga_bus_logtype = rte_log_register("bus.ifpga"); > > + if (ifpga_bus_logtype >= 0) > > + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); > > +} > > diff --git a/drivers/bus/ifpga/ifpga_common.c > b/drivers/bus/ifpga/ifpga_common.c > > new file mode 100644 > > index 0000000..26fee27 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_common.c > > @@ -0,0 +1,88 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation > > + */ > > + > > +#include <string.h> > > +#include <inttypes.h> > > +#include <stdint.h> > > +#include <stdlib.h> > > +#include <stdio.h> > > +#include <sys/queue.h> > > +#include <sys/mman.h> > > +#include <sys/types.h> > > +#include <unistd.h> > > +#include <fcntl.h> > > + > > +#include <rte_errno.h> > > +#include <rte_bus.h> > > +#include <rte_per_lcore.h> > > +#include <rte_memory.h> > > +#include <rte_memzone.h> > > +#include <rte_eal.h> > > +#include <rte_common.h> > > + > > +#include <rte_devargs.h> > > +#include <rte_kvargs.h> > > +#include <rte_alarm.h> > > + > > +#include "rte_bus_ifpga.h" > > +#include "ifpga_logs.h" > > +#include "ifpga_common.h" > > + > > +int ifpga_get_string_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) > > +{ > > + if (!value || !extra_args) > > + return -EINVAL; > > + > > + *(char **)extra_args = strdup(value); > > + > > + if (!*(char **)extra_args) > > + return -ENOMEM; > > + > > + return 0; > > +} > > +int ifpga_get_integer32_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) > > +{ > > + if (!value || !extra_args) > > + return -EINVAL; > > + > > + *(int *)extra_args = strtoull(value, NULL, 0); > > + > > + return 0; > > +} > > +int ifpga_get_integer64_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) > > +{ > > + if (!value || !extra_args) > > + return -EINVAL; > > + > > + *(uint64_t *)extra_args = strtoull(value, NULL, 0); > > + > > + return 0; > > +} > > +int ifpga_get_unsigned_long(const char *str, int base) > > +{ > > + unsigned long num; > > + char *end = NULL; > > + > > + errno = 0; > > + > > + num = strtoul(str, &end, base); > > + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) > > + return -1; > > + > > + return num; > > +} > > + > > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > + const struct rte_afu_id *afu_id1) > > +{ > > + if ((afu_id0->uuid_low == afu_id1->uuid_low) && > > + (afu_id0->uuid_high == afu_id1->uuid_high) && > > + (afu_id0->port == afu_id1->port)) { > > + return 0; > > + } else > > + return 1; > > +} > > diff --git a/drivers/bus/ifpga/ifpga_common.h > b/drivers/bus/ifpga/ifpga_common.h > > new file mode 100644 > > index 0000000..b6662c8 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_common.h > > @@ -0,0 +1,18 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation > > + */ > > + > > +#ifndef _IFPGA_COMMON_H_ > > +#define _IFPGA_COMMON_H_ > > + > > +int ifpga_get_string_arg(const char *key __rte_unused, > > + const char *value, void *extra_args); > > +int ifpga_get_integer32_arg(const char *key __rte_unused, > > + const char *value, void *extra_args); > > +int ifpga_get_integer64_arg(const char *key __rte_unused, > > + const char *value, void *extra_args); > > +int ifpga_get_unsigned_long(const char *str, int base); > > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > + const struct rte_afu_id *afu_id1); > > + > > +#endif /* _IFPGA_COMMON_H_ */ > > diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h > > new file mode 100644 > > index 0000000..873e0a4 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_logs.h > > @@ -0,0 +1,31 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation > > + */ > > + > > +#ifndef _IFPGA_LOGS_H_ > > +#define _IFPGA_LOGS_H_ > > + > > +#include <rte_log.h> > > + > > +extern int ifpga_bus_logtype; > > + > > +#define IFPGA_LOG(level, fmt, args...) \ > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > + __func__, ##args) > > + > > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > + __func__, ##args) > > + > > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > > + > > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) > > +#define IFPGA_BUS_INFO(fmt, args...) \ > > + IFPGA_BUS_LOG(INFO, fmt, ## args) > > +#define IFPGA_BUS_ERR(fmt, args...) \ > > + IFPGA_BUS_LOG(ERR, fmt, ## args) > > +#define IFPGA_BUS_WARN(fmt, args...) \ > > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > > + > > +#endif /* _IFPGA_BUS_LOGS_H_ */ > > diff --git a/drivers/bus/ifpga/meson.build b/drivers/bus/ifpga/meson.build > > new file mode 100644 > > index 0000000..4ea31f1 > > --- /dev/null > > +++ b/drivers/bus/ifpga/meson.build > > @@ -0,0 +1,6 @@ > > +# SPDX-License-Identifier: BSD-3-Clause > > +# Copyright(c) 2010-2018 Intel Corporation > > + > > +deps += ['pci', 'kvargs', 'rawdev'] > > +install_headers('rte_bus_ifpga.h') > > +sources = files('ifpga_common.c', 'ifpga_bus.c') > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h > b/drivers/bus/ifpga/rte_bus_ifpga.h > > new file mode 100644 > > index 0000000..53e7183 > > --- /dev/null > > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > > @@ -0,0 +1,168 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation > > + */ > > + > > +#ifndef _RTE_BUS_IFPGA_H_ > > +#define _RTE_BUS_IFPGA_H_ > > + > > +/** > > + * @file > > + * > > + * RTE Intel FPGA Bus Interface > > + */ > > + > > +#ifdef __cplusplus > > +extern "C" { > > +#endif > > + > > +#include <rte_bus.h> > > +#include <rte_pci.h> > > + > > +/** Name of Intel FPGA Bus */ > > +#define IFPGA_BUS_NAME ifpga > > + > > +/* Forward declarations */ > > +struct rte_afu_device; > > + > > +/** List of Intel AFU devices */ > > +TAILQ_HEAD(afu_device_list, rte_afu_device); > > +/** Double linked list of AFU device drivers. */ > > +TAILQ_HEAD(afu_driver_list, rte_afu_driver); > > + > > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > > + > > +struct rte_afu_uuid { > > + uint64_t uuid_low; > > + uint64_t uuid_high; > > +} __attribute__ ((packed)); > > + > > +#define IFPGA_BUS_DEV_PORT_MAX 4 > > + > > +/** > > + * A structure describing an ID for a AFU driver. Each driver provides a > > It seems that this struct is for describing the AFU device, instead of > AFU driver, no? This struct is describing the AFU device's attribute like UUID which is match AFU driver for AFU device, and port number. > > > + * table of these IDs for each device that it supports. > > + */ > > +struct rte_afu_id { > > + uint64_t uuid_low; > > + uint64_t uuid_high; > > Why not reuse struct rte_afu_uuid for above two fields? Yes, we can reuse the struct rte_afu_uuid. > > > + int port; > > Can you add a note on what *port* means? This is port number, suppose that one FPGA chip may has multiple AFUs, one AFU has one dedicate port. It is like bridge function. > > > +} __attribute__ ((packed)); > > + > > +/** > > + * A structure pr configuration AFU driver. > > What does pr mean? Mind to add a full name for it? PR means partial reconfiguration. > > > + */ > > + > > +struct rte_afu_pr_conf { > > + struct rte_afu_id afu_id; > > + int pr_enable; > > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > +}; > > + > > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > > + > > +/** > > + * A structure describing a fpga device. > > + */ > > +struct rte_ifpga_device { > > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. > */ > > + struct rte_rawdev *rdev; > > + struct afu_device_list afu_list; /**< List of AFU devices */ > > +}; > > + > > +/** > > + * A structure describing a AFU device. > > + */ > > +struct rte_afu_device { > > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ > > + struct rte_device device; /**< Inherit core device */ > > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > > + struct rte_afu_id id; /**< AFU id within FPGA. */ > > + uint32_t num_region; /**< number of regions found */ > > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > > + /**< AFU Memory Resource */ > > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > > + struct rte_afu_driver *driver; /**< Associated driver */ > > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > +} __attribute__ ((packed)); > > + > > +/** > > + * @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_DRV_TO_AFU_CONST(ptr) \ > > + container_of(ptr, const struct rte_afu_driver, driver) > > + > > +/** > > + * Initialisation function for the driver called during FPGA BUS probing. > > + */ > > +typedef int (afu_probe_t)(struct rte_afu_device *); > > + > > +/** > > + * Uninitialisation function for the driver called during hotplugging. > > + */ > > +typedef int (afu_remove_t)(struct rte_afu_device *); > > + > > +/** > > + * A structure describing a AFU device. > > + */ > > +struct rte_afu_driver { > > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > > + struct rte_driver driver; /**< Inherit core driver. */ > > + afu_probe_t *probe; /**< Device Probe > function. */ > > + afu_remove_t *remove; /**< Device Remove > function. */ > > + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ > > + uint32_t drv_flags; /**< Flags contolling handling of device. > */ > > +}; > > + > > +/** > > + * Structure describing the Intel FPGA bus > > + */ > > +struct rte_ifpga_bus { > > + struct rte_bus bus; /**< Inherit the generic class */ > > +}; > > Where is this struct used? This struct no need, will remove in next version. > > > + > > +static inline const char * > > +rte_ifpga_device_name(const struct rte_afu_device *afu) > > +{ > > + if (afu && afu->device.name) > > + return afu->device.name; > > + return NULL; > > +} > > + > > +/** > > + * Register a ifpga afu device driver. > > + * > > + * @param driver > > + * A pointer to a rte_afu_driver structure describing the driver > > + * to be registered. > > + */ > > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); > > + > > +/** > > + * Unregister a ifpga afu device driver. > > + * > > + * @param driver > > + * A pointer to a rte_afu_driver structure describing the driver > > + * to be unregistered. > > + */ > > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > > + > > +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ > > +RTE_INIT(afudrvinitfn_ ##afudrv);\ > > +static const char *afudrvinit_ ## nm ## _alias;\ > > +static void afudrvinitfn_ ##afudrv(void)\ > > +{\ > > + (afudrv).driver.name = RTE_STR(nm);\ > > + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ > > + rte_ifpga_driver_register(&afudrv);\ > > +} \ > > +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) > > + > > +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ > > +static const char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) > > Do we really need alias for new bus? Originally, alias is a way for > compatibility, but it seems that it's not necessary for new bus. > > > + > > +#endif /* _RTE_BUS_IFPGA_H_ */ > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map > b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > new file mode 100644 > > index 0000000..1304caf > > --- /dev/null > > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > @@ -0,0 +1,10 @@ > > +DPDK_18.05 { > > + global: > > + > > + ifpga_get_integer32_arg; > > + ifpga_get_string_arg; > > Above two functions shall be not exposed as APIs. Those APIs used in ifpga raw device driver. > > > + rte_ifpga_driver_register; > > + rte_ifpga_driver_unregister; > > + > > + local: *; > > +}; > > diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build > > index 58dfbe2..170df25 100644 > > --- a/drivers/bus/meson.build > > +++ b/drivers/bus/meson.build > > @@ -1,7 +1,7 @@ > > # SPDX-License-Identifier: BSD-3-Clause > > # Copyright(c) 2017 Intel Corporation > > > > -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] > > +drivers = ['dpaa', 'fslmc', 'pci', 'vdev', 'ifpga'] > > std_deps = ['eal'] > > config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' > > driver_name_fmt = 'rte_bus_@0@' > > diff --git a/mk/rte.app.mk b/mk/rte.app.mk > > index a145791..9de2edb 100644 > > --- a/mk/rte.app.mk > > +++ b/mk/rte.app.mk > > @@ -107,6 +107,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE) > += -lrte_cmdline > > _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder > > _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrte_sched > > > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga > > + > > ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) > > _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni > > endif ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v6 2/5] iFPGA: Add Intel FPGA OPAE Share Code 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 0/5] " Xu, Rosen 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 1/5] iFPGA: Add Intel FPGA BUS Library Xu, Rosen @ 2018-04-26 9:43 ` Xu, Rosen 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen ` (2 subsequent siblings) 4 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-04-26 9:43 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet, Rosen Xu, Xu, Yilun [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset=y, Size: 221569 bytes --] From: Rosen Xu <rosen.xu@intel.com> This patch adds Intel FPGA Open Programmable Acceleration Engine (OPAE)[1] base driver code, in order to support Intel FPGA devices under DPDK. The base code currently supports Intel FPGA solutions including integrated solution (Intel(R) Xeon(R) CPU with FPGAs) and discrete solution (Intel(R) Programmable Acceleration Card with Intel(R) Arria(R) 10 FPGA) and it could be extended to support more FPGA devices in the future. Please refer to [1][2] for more introduction on OPAE and Intel FPGAs. [1] https://01.org/OPAE [2] https://www.altera.com/solutions/acceleration-hub/overview.html Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> Signed-off-by: Wu, Hao <hao.wu@intel.com> Signed-off-by: Xu, Yilun <yilun.xu@intel.com> --- drivers/raw/ifpga_rawdev/base/Makefile | 26 + drivers/raw/ifpga_rawdev/base/README | 31 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 294 ++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 28 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 57 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1661 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 824 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 11 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 314 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 164 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 734 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 301 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 403 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 715 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 372 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 127 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 408 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 165 ++ drivers/raw/ifpga_rawdev/base/opae_debug.c | 99 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 19 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 381 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 253 +++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 145 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 279 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 81 + .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 75 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 45 + 27 files changed, 8012 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/README create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile new file mode 100644 index 0000000..64c8472 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -0,0 +1,26 @@ +#SPDX-License-Identifier: BSD-3-Clause +#Copyright(c) 2010-2018 Intel Corporation + +ifneq ($(CONFIG_RTE_LIBRTE_EAL),) +OSDEP := osdep_rte +else +OSDEP := osdep_raw +endif + +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev/base/$(OSDEP) + +SRCS-y += ifpga_api.c +SRCS-y += ifpga_enumerate.c +SRCS-y += ifpga_feature_dev.c +SRCS-y += ifpga_fme.c +SRCS-y += ifpga_fme_iperf.c +SRCS-y += ifpga_fme_dperf.c +SRCS-y += ifpga_fme_error.c +SRCS-y += ifpga_port.c +SRCS-y += ifpga_port_error.c +SRCS-y += ifpga_fme_pr.c +SRCS-y += opae_hw_api.c +SRCS-y += opae_ifpga_hw_api.c +SRCS-y += opae_debug.c + +SRCS-y += $(wildcard $(SRCDIR)/base/$(OSDEP)/*.c) diff --git a/drivers/raw/ifpga_rawdev/base/README b/drivers/raw/ifpga_rawdev/base/README new file mode 100644 index 0000000..3636ac7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/README @@ -0,0 +1,31 @@ +.. + +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +Intel® iFPGA driver +================== + +This directory contains source code of Intel FPGA driver released by +the team which develops Intel FPGA Open Programmable Acceleration Engine (OPAE). +The directory of base/ contains the original source package. The base code +currently supports Intel FPGA solutions including integrated solution (Intel(R) +Xeon(R) CPU with FPGAs) and discrete solution (Intel(R) Programmable Acceleration +Card with Intel(R) Arria(R) 10 FPGA) and it could be extended to support more FPGA +devices in the future. + +Please refer to [1][2] for more introduction on OPAE and Intel FPGAs. + +[1] https://01.org/OPAE +[2] https://www.altera.com/solutions/acceleration-hub/overview.html + + +Updating the driver +=================== + +NOTE: The source code in this directory should not be modified apart from +the following file(s): + + osdep_raw/osdep_generic.h + osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.c b/drivers/raw/ifpga_rawdev/base/ifpga_api.c new file mode 100644 index 0000000..540e171 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -0,0 +1,294 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_api.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +#include "opae_hw_api.h" + +/* Accelerator APIs */ +static int ifpga_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return fpga_get_afu_uuid(port, uuid); +} + +static int ifpga_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + struct fpga_uafu_irq_set irq_set; + + if (!br || !br->data) + return -EINVAL; + + if (start >= afu_info->num_irqs || start + count > afu_info->num_irqs) + return -EINVAL; + + port = br->data; + + irq_set.start = start; + irq_set.count = count; + irq_set.evtfds = evtfds; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_UINT, &irq_set); +} + +static int ifpga_acc_get_info(struct opae_accelerator *acc, + struct opae_acc_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -ENODEV; + + info->num_regions = afu_info->num_regions; + info->num_irqs = afu_info->num_irqs; + + return 0; +} + +static int ifpga_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -EINVAL; + + if (info->index >= afu_info->num_regions) + return -EINVAL; + + /* always one RW region only for AFU now */ + info->flags = ACC_REGION_READ | ACC_REGION_WRITE | ACC_REGION_MMIO; + info->len = afu_info->region[info->index].len; + info->addr = afu_info->region[info->index].addr; + + return 0; +} + +static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + switch (byte) { + case 8: + *(u64 *)data = opae_readq(region->addr + offset); + break; + case 4: + *(u32 *)data = opae_readl(region->addr + offset); + break; + case 2: + *(u16 *)data = opae_readw(region->addr + offset); + break; + case 1: + *(u8 *)data = opae_readb(region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ifpga_acc_write(struct opae_accelerator *acc, + unsigned int region_idx, u64 offset, + unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + /* normal mmio case */ + switch (byte) { + case 8: + opae_writeq(*(u64 *)data, region->addr + offset); + break; + case 4: + opae_writel(*(u32 *)data, region->addr + offset); + break; + case 2: + opae_writew(*(u16 *)data, region->addr + offset); + break; + case 1: + opae_writeb(*(u8 *)data, region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +struct opae_accelerator_ops ifpga_acc_ops = { + .read = ifpga_acc_read, + .write = ifpga_acc_write, + .set_irq = ifpga_acc_set_irq, + .get_info = ifpga_acc_get_info, + .get_region_info = ifpga_acc_get_region_info, + .get_uuid = ifpga_acc_get_uuid, +}; + +/* Bridge APIs */ + +static int ifpga_br_reset(struct opae_bridge *br) +{ + struct ifpga_port_hw *port = br->data; + + return fpga_port_reset(port); +} + +struct opae_bridge_ops ifpga_br_ops = { + .reset = ifpga_br_reset, +}; + +/* Manager APIs */ +static int ifpga_mgr_flash(struct opae_manager *mgr, int id, void *buf, + u32 size, u64 *status) +{ + struct ifpga_fme_hw *fme = mgr->data; + struct ifpga_hw *hw = fme->parent; + + return ifpga_pr(hw, id, buf, size, status); +} + +struct opae_manager_ops ifpga_mgr_ops = { + .flash = ifpga_mgr_flash, +}; + +/* Adapter APIs */ +static int ifpga_adapter_enumerate(struct opae_adapter *adapter) +{ + struct ifpga_hw *hw = malloc(sizeof(*hw)); + + if (hw) { + memset(hw, 0, sizeof(*hw)); + hw->pci_data = adapter->data; + hw->adapter = adapter; + if (ifpga_bus_enumerate(hw)) + goto error; + return ifpga_bus_init(hw); + } + +error: + return -ENOMEM; +} + +struct opae_adapter_ops ifpga_adapter_ops = { + .enumerate = ifpga_adapter_enumerate, +}; + +/** + * ifpga_pr - do the partial reconfiguration for a given port device + * @hw: pointer to the HW structure + * @port_id: the port device id + * @buffer: the buffer of the bitstream + * @size: the size of the bitstream + * @status: hardware status including PR error code if return -EIO. + * + * @return + * - 0: Success, partial reconfiguration finished. + * - <0: Error code returned in partial reconfiguration. + **/ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return do_pr(hw, port_id, buffer, size, status); +} + +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_get_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_get_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set) +{ + if (!hw || !irq_set) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_irq(&hw->fme, feature_id, irq_set); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_irq(&hw->port[port_id], feature_id, irq_set); + } + + return -ENOENT; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.h b/drivers/raw/ifpga_rawdev/base/ifpga_api.h new file mode 100644 index 0000000..dae7ca1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_API_H_ +#define _IFPGA_API_H_ + +#include "opae_hw_api.h" +#include "ifpga_hw.h" + +extern struct opae_adapter_ops ifpga_adapter_ops; +extern struct opae_manager_ops ifpga_mgr_ops; +extern struct opae_bridge_ops ifpga_br_ops; +extern struct opae_accelerator_ops ifpga_acc_ops; + +/* common APIs */ +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set); + +/* FME APIs */ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +#endif /* _IFPGA_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_compat.h b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h new file mode 100644 index 0000000..78b904e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMPAT_H_ +#define _IFPGA_COMPAT_H_ + +#include "opae_osdep.h" + +#undef container_of +#define container_of(ptr, type, member) ({ \ + typeof(((type *)0)->member)(*__mptr) = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) +#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE) + +#define readl(addr) opae_readl(addr) +#define readq(addr) opae_readq(addr) +#define writel(value, addr) opae_writel(value, addr) +#define writeq(value, addr) opae_writeq(value, addr) + +#define malloc(size) opae_malloc(size) +#define zmalloc(size) opae_zmalloc(size) +#define free(size) opae_free(size) + +/* + * Wait register's _field to be changed to the given value (_expect's _field) + * by polling with given interval and timeout. + */ +#define fpga_wait_register_field(_field, _expect, _reg_addr, _timeout, _invl)\ +({ \ + int wait = 0; \ + int ret = -ETIMEDOUT; \ + typeof(_expect) value; \ + for (; wait <= _timeout; wait += _invl) { \ + value.csr = readq(_reg_addr); \ + if (_expect._field == value._field) { \ + ret = 0; \ + break; \ + } \ + udelay(_invl); \ + } \ + ret; \ +}) + +#define __maybe_unused __attribute__((__unused__)) + +#define UNUSED(x) (void)(x) + +#endif /* _IFPGA_COMPAT_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h new file mode 100644 index 0000000..8989280 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -0,0 +1,1661 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_DEFINES_H_ +#define _IFPGA_DEFINES_H_ + +#include "ifpga_compat.h" + +#define MAX_FPGA_PORT_NUM 4 + +#define FME_FEATURE_HEADER "fme_hdr" +#define FME_FEATURE_THERMAL_MGMT "fme_thermal" +#define FME_FEATURE_POWER_MGMT "fme_power" +#define FME_FEATURE_GLOBAL_IPERF "fme_iperf" +#define FME_FEATURE_GLOBAL_ERR "fme_error" +#define FME_FEATURE_PR_MGMT "fme_pr" +#define FME_FEATURE_HSSI_ETH "fme_hssi" +#define FME_FEATURE_GLOBAL_DPERF "fme_dperf" +#define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" + +#define PORT_FEATURE_HEADER "port_hdr" +#define PORT_FEATURE_UAFU "port_uafu" +#define PORT_FEATURE_ERR "port_err" +#define PORT_FEATURE_UMSG "port_umsg" +#define PORT_FEATURE_PR "port_pr" +#define PORT_FEATURE_UINT "port_uint" +#define PORT_FEATURE_STP "port_stp" + +/* + * do not check the revision id as id may be dynamic under + * some cases, e.g, UAFU. + */ +#define SKIP_REVISION_CHECK 0xff + +#define FME_HEADER_REVISION 1 +#define FME_THERMAL_MGMT_REVISION 0 +#define FME_POWER_MGMT_REVISION 1 +#define FME_GLOBAL_IPERF_REVISION 1 +#define FME_GLOBAL_ERR_REVISION 1 +#define FME_PR_MGMT_REVISION 2 +#define FME_HSSI_ETH_REVISION 0 +#define FME_GLOBAL_DPERF_REVISION 0 +#define FME_QSPI_REVISION 0 + +#define PORT_HEADER_REVISION 0 +/* UAFU's header info depends on the downloaded GBS */ +#define PORT_UAFU_REVISION SKIP_REVISION_CHECK +#define PORT_ERR_REVISION 1 +#define PORT_UMSG_REVISION 0 +#define PORT_UINT_REVISION 0 +#define PORT_STP_REVISION 1 + +#define FEATURE_TYPE_AFU 0x1 +#define FEATURE_TYPE_BBB 0x2 +#define FEATURE_TYPE_PRIVATE 0x3 +#define FEATURE_TYPE_FIU 0x4 + +#define FEATURE_FIU_ID_FME 0x0 +#define FEATURE_FIU_ID_PORT 0x1 + +#define FEATURE_ID_HEADER 0x0 +#define FEATURE_ID_AFU 0xff + +enum fpga_id_type { + FME_ID, + PORT_ID, + 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, +}; + +/* + * All headers and structures must be byte-packed to match the spec. + */ +#pragma pack(1) + +struct feature_header { + union { + u64 csr; + struct { + u16 id:12; + u8 revision:4; + u32 next_header_offset:24; + u8 end_of_list:1; + u32 reserved:19; + u8 type:4; + }; + }; +}; + +struct feature_bbb_header { + struct uuid guid; +}; + +struct feature_afu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fiu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fme_capability { + union { + u64 csr; + struct { + u8 fabric_verid; /* Fabric version ID */ + u8 socket_id:1; /* Socket id */ + u8 rsvd1:3; /* Reserved */ + /* pci0 link available yes /no */ + u8 pci0_link_avile:1; + /* pci1 link available yes /no */ + u8 pci1_link_avile:1; + /* Coherent (QPI/UPI) link available yes /no */ + u8 qpi_link_avile:1; + u8 rsvd2:1; /* Reserved */ + /* IOMMU or VT-d supported yes/no */ + u8 iommu_support:1; + u8 num_ports:3; /* Number of ports */ + u8 sf_fab_ctl:1; /* Internal validation bit */ + u8 rsvd3:3; /* Reserved */ + /* + * Address width supported in bits + * BXT -0x26 , SKX -0x30 + */ + u8 address_width_bits:6; + u8 rsvd4:2; /* Reserved */ + /* Size of cache supported in kb */ + u16 cache_size:12; + u8 cache_assoc:4; /* Cache Associativity */ + u16 rsvd5:15; /* Reserved */ + u8 lock_bit:1; /* Lock bit */ + }; + }; +}; + +#define FME_AFU_ACCESS_PF 0 +#define FME_AFU_ACCESS_VF 1 + +struct feature_fme_port { + union { + u64 csr; + struct { + u32 port_offset:24; + u8 reserved1; + u8 port_bar:3; + u32 reserved2:20; + u8 afu_access_control:1; + u8 reserved3:4; + u8 port_implemented:1; + u8 reserved4:3; + }; + }; +}; + +struct feature_fme_fab_status { + union { + u64 csr; + struct { + u8 upilink_status:4; /* UPI Link Status */ + u8 rsvd1:4; /* Reserved */ + u8 pci0link_status:1; /* pci0 link status */ + u8 rsvd2:3; /* Reserved */ + u8 pci1link_status:1; /* pci1 link status */ + u64 rsvd3:51; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_base { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Base Address of memory range */ + u8 protected_base_addrss:4; + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_limit { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Limit Address of memory range */ + u8 protected_limit_addrss:4; + u16 rsvd2:11; /* Reserved */ + u8 enable:1; /* Enable GENPROTRANGE check */ + u32 rsvd3; /* Reserved */ + }; + }; +}; + +struct feature_fme_dxe_lock { + union { + u64 csr; + struct { + /* + * Determines write access to the DXE region CSRs + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_early_lock:1; + /* + * Determines write access to the HSSI CSR + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_late_lock:1; + u64 rsvd:62; + }; + }; +}; + +#define HSSI_ID_NO_HASSI 0 +#define HSSI_ID_PCIE_RP 1 +#define HSSI_ID_ETHERNET 2 + +struct feature_fme_bitstream_id { + union { + u64 csr; + struct { + u32 gitrepo_hash:32; /* GIT repository hash */ + /* + * HSSI configuration identifier: + * 0 - No HSSI + * 1 - PCIe-RP + * 2 - Ethernet + */ + u8 hssi_id:4; + u16 rsvd1:12; /* Reserved */ + /* Bitstream version patch number */ + u8 bs_verpatch:4; + /* Bitstream version minor number */ + u8 bs_verminor:4; + /* Bitstream version major number */ + u8 bs_vermajor:4; + /* Bitstream version debug number */ + u8 bs_verdebug:4; + }; + }; +}; + +struct feature_fme_bitstream_md { + union { + u64 csr; + struct { + /* Seed number userd for synthesis flow */ + u8 synth_seed:4; + /* Synthesis date(day number - 2 digits) */ + u8 synth_day:8; + /* Synthesis date(month number - 2 digits) */ + u8 synth_month:8; + /* Synthesis date(year number - 2 digits) */ + u8 synth_year:8; + u64 rsvd:36; /* Reserved */ + }; + }; +}; + +struct feature_fme_iommu_ctrl { + union { + u64 csr; + struct { + /* Disables IOMMU prefetcher for C0 channel */ + u8 prefetch_disableC0:1; + /* Disables IOMMU prefetcher for C1 channel */ + u8 prefetch_disableC1:1; + /* Disables IOMMU partial cache line writes */ + u8 prefetch_wrdisable:1; + u8 rsvd1:1; /* Reserved */ + /* + * Select counter and read value from register + * iommu_stat.dbg_counters + * 0 - Number of 4K page translation response + * 1 - Number of 2M page translation response + * 2 - Number of 1G page translation response + */ + u8 counter_sel:2; + u32 rsvd2:26; /* Reserved */ + /* Connected to IOMMU SIP Capabilities */ + u32 capecap_defeature; + }; + }; +}; + +struct feature_fme_iommu_stat { + union { + u64 csr; + struct { + /* Translation Enable bit from IOMMU SIP */ + u8 translation_enable:1; + /* Drain request in progress */ + u8 drain_req_inprog:1; + /* Invalidation current state */ + u8 inv_state:3; + /* C0 Response Buffer current state */ + u8 respbuffer_stateC0:3; + /* C1 Response Buffer current state */ + u8 respbuffer_stateC1:3; + /* Last request ID to IOMMU SIP */ + u8 last_reqID:4; + /* Last IOMMU SIP response ID value */ + u8 last_respID:4; + /* Last IOMMU SIP response status value */ + u8 last_respstatus:3; + /* C0 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC0:1; + /* C1 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC1:1; + /* C0 Request FIFO is not empty */ + u8 reqFIFO_notemptyC0:1; + /* C1 Request FIFO is not empty */ + u8 reqFIFO_notemptyC1:1; + /* C0 Response FIFO is not empty */ + u8 respFIFO_notemptyC0:1; + /* C1 Response FIFO is not empty */ + u8 respFIFO_notemptyC1:1; + /* C0 Response FIFO overflow detected */ + u8 respFIFO_overflowC0:1; + /* C1 Response FIFO overflow detected */ + u8 respFIFO_overflowC1:1; + /* C0 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC0:1; + /* C1 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC1:1; + /* Request FIFO overflow detected */ + u8 reqFIFO_overflow:1; + /* IOMMU memory read in progress */ + u8 memrd_inprog:1; + /* IOMMU memory write in progress */ + u8 memwr_inprog:1; + u8 rsvd1:1; /* Reserved */ + /* Value of counter selected by iommu_ctl.counter_sel */ + u16 dbg_counters:16; + u16 rsvd2:12; /* Reserved */ + }; + }; +}; + +struct feature_fme_pcie0_ctrl { + union { + u64 csr; + struct { + u64 vtd_bar_lock:1; /* Lock VT-D BAR register */ + u64 rsvd1:3; + u64 rciep:1; /* Configure PCIE0 as RCiEP */ + u64 rsvd2:59; + }; + }; +}; + +struct feature_fme_llpr_smrr_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR rule is valid or not */ + /* + * SMRR memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR2 rule is valid or not */ + /* + * SMRR2 memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_meseg_base { + union { + u64 csr; + struct { + /* A[45:19] of base address memory range */ + u64 me_base:27; + u64 rsvd:37; + }; + }; +}; + +struct feature_fme_llpr_meseg_limit { + union { + u64 csr; + struct { + /* A[45:19] of limit address memory range */ + u64 me_limit:27; + u64 rsvd1:4; + u64 enable:1; /* Enable LLPR MESEG rule */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 reserved; + u64 scratchpad; + struct feature_fme_capability capability; + struct feature_fme_port port[MAX_FPGA_PORT_NUM]; + struct feature_fme_fab_status fab_status; + struct feature_fme_bitstream_id bitstream_id; + struct feature_fme_bitstream_md bitstream_md; + struct feature_fme_genprotrange2_base genprotrange2_base; + struct feature_fme_genprotrange2_limit genprotrange2_limit; + struct feature_fme_dxe_lock dxe_lock; + struct feature_fme_iommu_ctrl iommu_ctrl; + struct feature_fme_iommu_stat iommu_stat; + struct feature_fme_pcie0_ctrl pcie0_control; + struct feature_fme_llpr_smrr_base smrr_base; + struct feature_fme_llpr_smrr_mask smrr_mask; + struct feature_fme_llpr_smrr2_base smrr2_base; + struct feature_fme_llpr_smrr2_mask smrr2_mask; + struct feature_fme_llpr_meseg_base meseg_base; + struct feature_fme_llpr_meseg_limit meseg_limit; +}; + +struct feature_port_capability { + union { + u64 csr; + struct { + u8 port_number:2; /* Port Number 0-3 */ + u8 rsvd1:6; /* Reserved */ + u16 mmio_size; /* User MMIO size in KB */ + u8 rsvd2; /* Reserved */ + u8 sp_intr_num:4; /* Supported interrupts num */ + u32 rsvd3:28; /* Reserved */ + }; + }; +}; + +struct feature_port_control { + union { + u64 csr; + struct { + u8 port_sftrst:1; /* Port Soft Reset */ + u8 rsvd1:1; /* Reserved */ + u8 latency_tolerance:1;/* '1' >= 40us, '0' < 40us */ + u8 rsvd2:1; /* Reserved */ + u8 port_sftrst_ack:1; /* HW ACK for Soft Reset */ + u64 rsvd3:59; /* Reserved */ + }; + }; +}; + +#define PORT_POWER_STATE_NORMAL 0 +#define PORT_POWER_STATE_AP1 1 +#define PORT_POWER_STATE_AP2 2 +#define PORT_POWER_STATE_AP6 6 + +struct feature_port_status { + union { + u64 csr; + struct { + u8 port_freeze:1; /* '1' - freezed '0' - normal */ + u8 rsvd1:7; /* Reserved */ + u8 power_state:4; /* Power State */ + u8 ap1_event:1; /* AP1 event was detected */ + u8 ap2_event:1; /* AP2 event was detected */ + u64 rsvd2:50; /* Reserved */ + }; + }; +}; + +/* Port Header Register Set */ +struct feature_port_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 port_mailbox; + u64 scratchpad; + struct feature_port_capability capability; + struct feature_port_control control; + struct feature_port_status status; + u64 rsvd2; + u64 user_clk_freq_cmd0; + u64 user_clk_freq_cmd1; + u64 user_clk_freq_sts0; + u64 user_clk_freq_sts1; +}; + +struct feature_fme_tmp_threshold { + union { + u64 csr; + struct { + u8 tmp_thshold1:7; /* temperature Threshold 1 */ + /* temperature Threshold 1 enable/disable */ + u8 tmp_thshold1_enable:1; + u8 tmp_thshold2:7; /* temperature Threshold 2 */ + /* temperature Threshold 2 enable /disable */ + u8 tmp_thshold2_enable:1; + u8 pro_hot_setpoint:7; /* Proc Hot set point */ + u8 rsvd4:1; /* Reserved */ + u8 therm_trip_thshold:7; /* Thermeal Trip Threshold */ + u8 rsvd3:1; /* Reserved */ + u8 thshold1_status:1; /* Threshold 1 Status */ + u8 thshold2_status:1; /* Threshold 2 Status */ + u8 rsvd5:1; /* Reserved */ + /* Thermeal Trip Threshold status */ + u8 therm_trip_thshold_status:1; + u8 rsvd6:4; /* Reserved */ + /* Validation mode- Force Proc Hot */ + u8 valmodeforce:1; + /* Validation mode - Therm trip Hot */ + u8 valmodetherm:1; + u8 rsvd2:2; /* Reserved */ + u8 thshold_policy:1; /* threshold policy */ + u32 rsvd:19; /* Reserved */ + }; + }; +}; + +/* Temperature Sensor Read values format 1 */ +struct feature_fme_temp_rdsensor_fmt1 { + union { + u64 csr; + struct { + /* Reads out FPGA temperature in celsius */ + u8 fpga_temp:7; + u8 rsvd0:1; /* Reserved */ + /* Temperature reading sequence number */ + u16 tmp_reading_seq_num; + /* Temperature reading is valid */ + u8 tmp_reading_valid:1; + u8 rsvd1:7; /* Reserved */ + u16 dbg_mode:10; /* Debug mode */ + u32 rsvd2:22; /* Reserved */ + }; + }; +}; + +/* Temperature sensor read values format 2 */ +struct feature_fme_temp_rdsensor_fmt2 { + u64 rsvd; /* Reserved */ +}; + +/* Temperature Threshold Capability Register */ +struct feature_fme_tmp_threshold_cap { + union { + u64 csr; + struct { + /* Temperature Threshold Unsupported */ + u8 tmp_thshold_disabled:1; + u64 rsvd:63; /* Reserved */ + }; + }; +}; + +/* FME THERNAL FEATURE */ +struct feature_fme_thermal { + struct feature_header header; + struct feature_fme_tmp_threshold threshold; + struct feature_fme_temp_rdsensor_fmt1 rdsensor_fm1; + struct feature_fme_temp_rdsensor_fmt2 rdsensor_fm2; + struct feature_fme_tmp_threshold_cap threshold_cap; +}; + +/* Power Status register */ +struct feature_fme_pm_status { + union { + u64 csr; + struct { + /* FPGA Power consumed, The format is to be defined */ + u32 pwr_consumed:18; + /* FPGA Latency Tolerance Reporting */ + u8 fpga_latency_report:1; + u64 rsvd:45; /* Reserved */ + }; + }; +}; + +/* AP Thresholds */ +struct feature_fme_pm_ap_threshold { + union { + u64 csr; + struct { + /* + * Number of clocks (5ns period) for assertion + * of FME_data + */ + u8 threshold1:7; + u8 rsvd1:1; + u8 threshold2:7; + u8 rsvd2:1; + u8 threshold1_status:1; + u8 threshold2_status:1; + u64 rsvd3:46; /* Reserved */ + }; + }; +}; + +/* Xeon Power Limit */ +struct feature_fme_pm_xeon_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FPGA Power Limit */ +struct feature_fme_pm_fpga_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FME POWER FEATURE */ +struct feature_fme_power { + struct feature_header header; + struct feature_fme_pm_status status; + struct feature_fme_pm_ap_threshold threshold; + struct feature_fme_pm_xeon_limit xeon_limit; + struct feature_fme_pm_fpga_limit fpga_limit; +}; + +#define CACHE_CHANNEL_RD 0 +#define CACHE_CHANNEL_WR 1 + +enum iperf_cache_events { + IPERF_CACHE_RD_HIT, + IPERF_CACHE_WR_HIT, + IPERF_CACHE_RD_MISS, + IPERF_CACHE_WR_MISS, + IPERF_CACHE_RSVD, /* reserved */ + IPERF_CACHE_HOLD_REQ, + IPERF_CACHE_DATA_WR_PORT_CONTEN, + IPERF_CACHE_TAG_WR_PORT_CONTEN, + IPERF_CACHE_TX_REQ_STALL, + IPERF_CACHE_RX_REQ_STALL, + IPERF_CACHE_EVICTIONS, +}; + +/* FPMON Cache Control */ +struct feature_fme_ifpmon_ch_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd1:7; /* Reserved */ + u8 freeze:1; /* Freeze if set to 1 */ + u8 rsvd2:7; /* Reserved */ + u8 cache_event:4; /* Select the cache event */ + u8 cci_chsel:1; /* Select the channel */ + u64 rsvd3:43; /* Reserved */ + }; + }; +}; + +/* FPMON Cache Counter */ +struct feature_fme_ifpmon_ch_ctr { + union { + u64 csr; + struct { + /* Cache Counter for even addresse */ + u64 cache_counter:48; + u16 rsvd:12; /* Reserved */ + /* Cache Event being reported */ + u8 event_code:4; + }; + }; +}; + +enum iperf_fab_events { + IPERF_FAB_PCIE0_RD, + IPERF_FAB_PCIE0_WR, + IPERF_FAB_PCIE1_RD, + IPERF_FAB_PCIE1_WR, + IPERF_FAB_UPI_RD, + IPERF_FAB_UPI_WR, + IPERF_FAB_MMIO_RD, + IPERF_FAB_MMIO_WR, +}; + +#define FAB_DISABLE_FILTER 0 +#define FAB_ENABLE_FILTER 1 + +/* FPMON FAB Control */ +struct feature_fme_ifpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_ifpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_ifpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +enum iperf_vtd_events { + IPERF_VTD_AFU_MEM_RD_TRANS, + IPERF_VTD_AFU_MEM_WR_TRANS, + IPERF_VTD_AFU_DEVTLB_RD_HIT, + IPERF_VTD_AFU_DEVTLB_WR_HIT, + IPERF_VTD_DEVTLB_4K_FILL, + IPERF_VTD_DEVTLB_2M_FILL, + IPERF_VTD_DEVTLB_1G_FILL, +}; + +/* VT-d control register */ +struct feature_fme_ifpmon_vtd_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d event counter */ +struct feature_fme_ifpmon_vtd_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +enum iperf_vtd_sip_events { + IPERF_VTD_SIP_IOTLB_4K_HIT, + IPERF_VTD_SIP_IOTLB_2M_HIT, + IPERF_VTD_SIP_IOTLB_1G_HIT, + IPERF_VTD_SIP_SLPWC_L3_HIT, + IPERF_VTD_SIP_SLPWC_L4_HIT, + IPERF_VTD_SIP_RCC_HIT, + IPERF_VTD_SIP_IOTLB_4K_MISS, + IPERF_VTD_SIP_IOTLB_2M_MISS, + IPERF_VTD_SIP_IOTLB_1G_MISS, + IPERF_VTD_SIP_SLPWC_L3_MISS, + IPERF_VTD_SIP_SLPWC_L4_MISS, + IPERF_VTD_SIP_RCC_MISS, +}; + +/* VT-d SIP control register */ +struct feature_fme_ifpmon_vtd_sip_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d SIP event counter */ +struct feature_fme_ifpmon_vtd_sip_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +/* FME IPERF FEATURE */ +struct feature_fme_iperf { + struct feature_header header; + struct feature_fme_ifpmon_ch_ctl ch_ctl; + struct feature_fme_ifpmon_ch_ctr ch_ctr0; + struct feature_fme_ifpmon_ch_ctr ch_ctr1; + struct feature_fme_ifpmon_fab_ctl fab_ctl; + struct feature_fme_ifpmon_fab_ctr fab_ctr; + struct feature_fme_ifpmon_clk_ctr clk; + struct feature_fme_ifpmon_vtd_ctl vtd_ctl; + struct feature_fme_ifpmon_vtd_ctr vtd_ctr; + struct feature_fme_ifpmon_vtd_sip_ctl vtd_sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr vtd_sip_ctr; +}; + +enum dperf_fab_events { + DPERF_FAB_PCIE0_RD, + DPERF_FAB_PCIE0_WR, + DPERF_FAB_MMIO_RD = 6, + DPERF_FAB_MMIO_WR, +}; + +/* FPMON FAB Control */ +struct feature_fme_dfpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_dfpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_dfpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +/* FME DPERF FEATURE */ +struct feature_fme_dperf { + struct feature_header header; + u64 rsvd[3]; + struct feature_fme_dfpmon_fab_ctl fab_ctl; + struct feature_fme_dfpmon_fab_ctr fab_ctr; + struct feature_fme_dfpmon_clk_ctr clk; +}; + +struct feature_fme_error0 { +#define FME_ERROR0_MASK 0xFFUL +#define FME_ERROR0_MASK_DEFAULT 0x40UL /* pcode workaround */ + union { + u64 csr; + struct { + u8 fabric_err:1; /* Fabric error */ + u8 fabfifo_overflow:1; /* Fabric fifo overflow */ + u8 kticdc_parity_err:2;/* KTI CDC Parity Error */ + u8 iommu_parity_err:1; /* IOMMU Parity error */ + /* AFU PF/VF access mismatch detected */ + u8 afu_acc_mode_err:1; + u8 mbp_err:1; /* Indicates an MBP event */ + /* PCIE0 CDC Parity Error */ + u8 pcie0cdc_parity_err:5; + /* PCIE1 CDC Parity Error */ + u8 pcie1cdc_parity_err:5; + /* CVL CDC Parity Error */ + u8 cvlcdc_parity_err:3; + u64 rsvd:44; /* Reserved */ + }; + }; +}; + +/* PCIe0 Error Status register */ +struct feature_fme_pcie0_error { +#define FME_PCIE0_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:52; /* Reserved */ + u8 vfnumb_err:1; /* Number of error VF */ + u8 funct_type_err:1; /* Virtual (1) or Physical */ + }; + }; +}; + +/* PCIe1 Error Status register */ +struct feature_fme_pcie1_error { +#define FME_PCIE1_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:54; /* Reserved */ + }; + }; +}; + +/* FME First Error register */ +struct feature_fme_first_error { +#define FME_FIRST_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered first + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered first + */ + u8 errReg_id:4; + }; + }; +}; + +/* FME Next Error register */ +struct feature_fme_next_error { +#define FME_NEXT_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered second + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered second + */ + u8 errReg_id:4; + }; + }; +}; + +/* RAS Non Fatal Error Status register */ +struct feature_fme_ras_nonfaterror { + union { + u64 csr; + struct { + /* thremal threshold AP1 */ + u8 temp_thresh_ap1:1; + /* thremal threshold AP2 */ + u8 temp_thresh_ap2:1; + u8 pcie_error:1; /* pcie Error */ + u8 portfatal_error:1; /* port fatal error */ + u8 proc_hot:1; /* Indicates a ProcHot event */ + /* Indicates an AFU PF/VF access mismatch */ + u8 afu_acc_mode_err:1; + /* Injected nonfata Error */ + u8 injected_nonfata_err:1; + u8 rsvd1:2; + /* Temperature threshold triggered AP6*/ + u8 temp_thresh_AP6:1; + /* Power threshold triggered AP1 */ + u8 power_thresh_AP1:1; + /* Power threshold triggered AP2 */ + u8 power_thresh_AP2:1; + /* Indicates a MBP event */ + u8 mbp_err:1; + u64 rsvd2:51; /* Reserved */ + }; + }; +}; + +/* RAS Catastrophic Fatal Error Status register */ +struct feature_fme_ras_catfaterror { + union { + u64 csr; + struct { + /* KTI Link layer error detected */ + u8 ktilink_fatal_err:1; + /* tag-n-cache error detected */ + u8 tagcch_fatal_err:1; + /* CCI error detected */ + u8 cci_fatal_err:1; + /* KTI Protocol error detected */ + u8 ktiprpto_fatal_err:1; + /* Fatal DRAM error detected */ + u8 dram_fatal_err:1; + /* IOMMU detected */ + u8 iommu_fatal_err:1; + /* Fabric Fatal Error */ + u8 fabric_fatal_err:1; + /* PCIe possion Error */ + u8 pcie_poison_err:1; + /* Injected fatal Error */ + u8 inject_fata_err:1; + /* Catastrophic CRC Error */ + u8 crc_catast_err:1; + /* Catastrophic Thermal Error */ + u8 therm_catast_err:1; + /* Injected Catastrophic Error */ + u8 injected_catast_err:1; + u64 rsvd:52; + }; + }; +}; + +/* RAS Error injection register */ +struct feature_fme_ras_error_inj { +#define FME_RAS_ERROR_INJ_MASK 0x7UL + union { + u64 csr; + struct { + u8 catast_error:1; /* Catastrophic error flag */ + u8 fatal_error:1; /* Fatal error flag */ + u8 nonfatal_error:1; /* NonFatal error flag */ + u64 rsvd:61; /* Reserved */ + }; + }; +}; + +/* FME error capabilities */ +struct feature_fme_error_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* FME ERR FEATURE */ +struct feature_fme_err { + struct feature_header header; + struct feature_fme_error0 fme_err_mask; + struct feature_fme_error0 fme_err; + struct feature_fme_pcie0_error pcie0_err_mask; + struct feature_fme_pcie0_error pcie0_err; + struct feature_fme_pcie1_error pcie1_err_mask; + struct feature_fme_pcie1_error pcie1_err; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + struct feature_fme_ras_nonfaterror ras_nonfat_mask; + struct feature_fme_ras_nonfaterror ras_nonfaterr; + struct feature_fme_ras_catfaterror ras_catfat_mask; + struct feature_fme_ras_catfaterror ras_catfaterr; + struct feature_fme_ras_error_inj ras_error_inj; + struct feature_fme_error_capability fme_err_capability; +}; + +/* FME Partial Reconfiguration Control */ +struct feature_fme_pr_ctl { + union { + u64 csr; + struct { + u8 pr_reset:1; /* Reset PR Engine */ + u8 rsvd3:3; /* Reserved */ + u8 pr_reset_ack:1; /* Reset PR Engine Ack */ + u8 rsvd4:3; /* Reserved */ + u8 pr_regionid:2; /* PR Region ID */ + u8 rsvd1:2; /* Reserved */ + u8 pr_start_req:1; /* PR Start Request */ + u8 pr_push_complete:1; /* PR Data push complete */ + u8 pr_kind:1; /* PR Data push complete */ + u32 rsvd:17; /* Reserved */ + u32 config_data; /* Config data TBD */ + }; + }; +}; + +/* FME Partial Reconfiguration Status */ +struct feature_fme_pr_status { + union { + u64 csr; + struct { + u16 pr_credit:9; /* PR Credits */ + u8 rsvd2:7; /* Reserved */ + u8 pr_status:1; /* PR status */ + u8 rsvd:3; /* Reserved */ + /* Altra PR Controller Block status */ + u8 pr_controller_status:3; + u8 rsvd1:1; /* Reserved */ + u8 pr_host_status:4; /* PR Host status */ + u8 rsvd3:4; /* Reserved */ + /* Security Block Status fields (TBD) */ + u32 security_bstatus; + }; + }; +}; + +/* FME Partial Reconfiguration Data */ +struct feature_fme_pr_data { + union { + u64 csr; /* PR data from the raw-binary file */ + struct { + /* PR data from the raw-binary file */ + u32 pr_data_raw; + u32 rsvd; + }; + }; +}; + +/* FME PR Public Key */ +struct feature_fme_pr_key { + u64 key; /* FME PR Public Hash */ +}; + +/* FME PR FEATURE */ +struct feature_fme_pr { + struct feature_header header; + /*Partial Reconfiguration control */ + struct feature_fme_pr_ctl ccip_fme_pr_control; + + /* Partial Reconfiguration Status */ + struct feature_fme_pr_status ccip_fme_pr_status; + + /* Partial Reconfiguration data */ + struct feature_fme_pr_data ccip_fme_pr_data; + + /* Partial Reconfiguration data */ + u64 ccip_fme_pr_err; + + u64 rsvd1[3]; + + /* Partial Reconfiguration data registers */ + u64 fme_pr_data1; + u64 fme_pr_data2; + u64 fme_pr_data3; + u64 fme_pr_data4; + u64 fme_pr_data5; + u64 fme_pr_data6; + u64 fme_pr_data7; + u64 fme_pr_data8; + + u64 rsvd2[5]; + + /* PR Interface ID */ + u64 fme_pr_intfc_id_l; + u64 fme_pr_intfc_id_h; + + /* MSIX filed to be Added */ +}; + +/* FME HSSI Control */ +struct feature_fme_hssi_eth_ctrl { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u16 address:16; /* HSSI address */ + /* + * HSSI comamnd + * 0x0 - No request + * 0x08 - SW register RD request + * 0x10 - SW register WR request + * 0x40 - Auxiliar bus RD request + * 0x80 - Auxiliar bus WR request + */ + u16 cmd:16; + }; + }; +}; + +/* FME HSSI Status */ +struct feature_fme_hssi_eth_stat { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u8 acknowledge:1; /* HSSI acknowledge */ + u8 spare:1; /* HSSI spare */ + u32 rsvd:30; /* Reserved */ + }; + }; +}; + +/* FME HSSI FEATURE */ +struct feature_fme_hssi { + struct feature_header header; + struct feature_fme_hssi_eth_ctrl hssi_control; + struct feature_fme_hssi_eth_stat hssi_status; +}; + +#define PORT_ERR_MASK 0xfff0703ff001f +struct feature_port_err_key { + union { + u64 csr; + struct { + /* Tx Channel0: Overflow */ + u8 tx_ch0_overflow:1; + /* Tx Channel0: Invalid request encoding */ + u8 tx_ch0_invaldreq :1; + /* Tx Channel0: Request with cl_len=3 not supported */ + u8 tx_ch0_cl_len3:1; + /* Tx Channel0: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch0_cl_len2:1; + /* Tx Channel0: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch0_cl_len4:1; + + u16 rsvd1:4; /* Reserved */ + + /* AFU MMIO RD received while PORT is in reset */ + u8 mmio_rd_whilerst:1; + /* AFU MMIO WR received while PORT is in reset */ + u8 mmio_wr_whilerst:1; + + u16 rsvd2:5; /* Reserved */ + + /* Tx Channel1: Overflow */ + u8 tx_ch1_overflow:1; + /* Tx Channel1: Invalid request encoding */ + u8 tx_ch1_invaldreq:1; + /* Tx Channel1: Request with cl_len=3 not supported */ + u8 tx_ch1_cl_len3:1; + /* Tx Channel1: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch1_cl_len2:1; + /* Tx Channel1: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch1_cl_len4:1; + + /* Tx Channel1: Insufficient data payload */ + u8 tx_ch1_insuff_data:1; + /* Tx Channel1: Data payload overrun */ + u8 tx_ch1_data_overrun:1; + /* Tx Channel1 : Incorrect address */ + u8 tx_ch1_incorr_addr:1; + /* Tx Channel1 : NON-Zero SOP Detected */ + u8 tx_ch1_nzsop:1; + /* Tx Channel1 : Illegal VC_SEL, atomic request VLO */ + u8 tx_ch1_illegal_vcsel:1; + + u8 rsvd3:6; /* Reserved */ + + /* MMIO Read Timeout in AFU */ + u8 mmioread_timeout:1; + + /* Tx Channel2: FIFO Overflow */ + u8 tx_ch2_fifo_overflow:1; + + /* MMIO read is not matching pending request */ + u8 unexp_mmio_resp:1; + + u8 rsvd4:5; /* Reserved */ + + /* Number of pending Requests: counter overflow */ + u8 tx_req_counter_overflow:1; + /* Req with Address violating SMM Range */ + u8 llpr_smrr_err:1; + /* Req with Address violating second SMM Range */ + u8 llpr_smrr2_err:1; + /* Req with Address violating ME Stolen message */ + u8 llpr_mesg_err:1; + /* Req with Address violating Generic Protected Range */ + u8 genprot_range_err:1; + /* Req with Address violating Legacy Range low */ + u8 legrange_low_err:1; + /* Req with Address violating Legacy Range High */ + u8 legrange_high_err:1; + /* Req with Address violating VGA memory range */ + u8 vgmem_range_err:1; + u8 page_fault_err:1; /* Page fault */ + u8 pmr_err:1; /* PMR Error */ + u8 ap6_event:1; /* AP6 event */ + /* VF FLR detected on Port with PF access control */ + u8 vfflr_access_err:1; + u16 rsvd5:12; /* Reserved */ + }; + }; +}; + +/* Port first error register, not contain all error bits in error register. */ +struct feature_port_first_err_key { + union { + u64 csr; + struct { + u8 tx_ch0_overflow:1; + u8 tx_ch0_invaldreq :1; + u8 tx_ch0_cl_len3:1; + u8 tx_ch0_cl_len2:1; + u8 tx_ch0_cl_len4:1; + u8 rsvd1:4; /* Reserved */ + u8 mmio_rd_whilerst:1; + u8 mmio_wr_whilerst:1; + u8 rsvd2:5; /* Reserved */ + u8 tx_ch1_overflow:1; + u8 tx_ch1_invaldreq:1; + u8 tx_ch1_cl_len3:1; + u8 tx_ch1_cl_len2:1; + u8 tx_ch1_cl_len4:1; + u8 tx_ch1_insuff_data:1; + u8 tx_ch1_data_overrun:1; + u8 tx_ch1_incorr_addr:1; + u8 tx_ch1_nzsop:1; + u8 tx_ch1_illegal_vcsel:1; + u8 rsvd3:6; /* Reserved */ + u8 mmioread_timeout:1; + u8 tx_ch2_fifo_overflow:1; + u8 rsvd4:6; /* Reserved */ + u8 tx_req_counter_overflow:1; + u32 rsvd5:23; /* Reserved */ + }; + }; +}; + +/* Port malformed Req0 */ +struct feature_port_malformed_req0 { + u64 header_lsb; +}; + +/* Port malformed Req1 */ +struct feature_port_malformed_req1 { + u64 header_msb; +}; + +/* Port debug register */ +struct feature_port_debug { + u64 port_debug; +}; + +/* Port error capabilities */ +struct feature_port_err_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE ERROR */ +struct feature_port_error { + struct feature_header header; + struct feature_port_err_key error_mask; + struct feature_port_err_key port_error; + struct feature_port_first_err_key port_first_error; + struct feature_port_malformed_req0 malreq0; + struct feature_port_malformed_req1 malreq1; + struct feature_port_debug port_debug; + struct feature_port_err_capability error_capability; +}; + +/* Port UMSG Capability */ +struct feature_port_umsg_cap { + union { + u64 csr; + struct { + /* Number of umsg allocated to this port */ + u8 umsg_allocated; + /* Enable / Disable UMsg engine for this port */ + u8 umsg_enable:1; + /* Usmg initialization status */ + u8 umsg_init_complete:1; + /* IOMMU can not translate the umsg base address */ + u8 umsg_trans_error:1; + u64 rsvd:53; /* Reserved */ + }; + }; +}; + +/* Port UMSG base address */ +struct feature_port_umsg_baseaddr { + union { + u64 csr; + struct { + u64 base_addr:48; /* 48 bit physical address */ + u16 rsvd; /* Reserved */ + }; + }; +}; + +struct feature_port_umsg_mode { + union { + u64 csr; + struct { + u32 umsg_hint_enable; /* UMSG hint enable/disable */ + u32 rsvd; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE UMSG */ +struct feature_port_umsg { + struct feature_header header; + struct feature_port_umsg_cap capability; + struct feature_port_umsg_baseaddr baseaddr; + struct feature_port_umsg_mode mode; +}; + +#define UMSG_EN_POLL_INVL 10 /* us */ +#define UMSG_EN_POLL_TIMEOUT 1000 /* us */ + +/* Port UINT Capability */ +struct feature_port_uint_cap { + union { + u64 csr; + struct { + u16 intr_num:12; /* Supported interrupts num */ + /* First MSI-X vector table entry number */ + u16 first_vec_num:12; + u64 rsvd:40; + }; + }; +}; + +/* PORT FEATURE UINT */ +struct feature_port_uint { + struct feature_header header; + struct feature_port_uint_cap capability; +}; + +/* STP region supports mmap operation, so use page aligned size. */ +#define PORT_FEATURE_STP_REGION_SIZE PAGE_ALIGN(sizeof(struct feature_port_stp)) + +/* Port STP status register (for debug only)*/ +struct feature_port_stp_status { + union { + u64 csr; + struct { + /* SLD Hub end-point read/write timeout */ + u8 sld_ep_timeout:1; + /* Remote STP in reset/disable */ + u8 rstp_disabled:1; + u8 unsupported_read:1; + /* MMIO timeout detected and faked with a response */ + u8 mmio_timeout:1; + u8 txfifo_count:4; + u8 rxfifo_count:4; + u8 txfifo_overflow:1; + u8 txfifo_underflow:1; + u8 rxfifo_overflow:1; + u8 rxfifo_underflow:1; + /* Number of MMIO write requests */ + u16 write_requests; + /* Number of MMIO read requests */ + u16 read_requests; + /* Number of MMIO read responses */ + u16 read_responses; + }; + }; +}; + +/* + * PORT FEATURE STP + * Most registers in STP region are not touched by driver, but mmapped to user + * space. So they are not defined in below data structure, as its actual size + * is 0x18c per spec. + */ +struct feature_port_stp { + struct feature_header header; + struct feature_port_stp_status stp_status; +}; + +/** + * enum fpga_pr_states - fpga PR states + * @FPGA_PR_STATE_UNKNOWN: can't determine state + * @FPGA_PR_STATE_WRITE_INIT: preparing FPGA for programming + * @FPGA_PR_STATE_WRITE_INIT_ERR: Error during WRITE_INIT stage + * @FPGA_PR_STATE_WRITE: writing image to FPGA + * @FPGA_PR_STATE_WRITE_ERR: Error while writing FPGA + * @FPGA_PR_STATE_WRITE_COMPLETE: Doing post programming steps + * @FPGA_PR_STATE_WRITE_COMPLETE_ERR: Error during WRITE_COMPLETE + * @FPGA_PR_STATE_OPERATING: FPGA PR done + */ +enum fpga_pr_states { + /* canot determine state states */ + FPGA_PR_STATE_UNKNOWN, + + /* write sequence: init, write, complete */ + FPGA_PR_STATE_WRITE_INIT, + FPGA_PR_STATE_WRITE_INIT_ERR, + FPGA_PR_STATE_WRITE, + FPGA_PR_STATE_WRITE_ERR, + FPGA_PR_STATE_WRITE_COMPLETE, + FPGA_PR_STATE_WRITE_COMPLETE_ERR, + + /* FPGA PR done */ + FPGA_PR_STATE_DONE, +}; + +/* + * FPGA Manager flags + * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported + */ +#define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + +/** + * struct fpga_pr_info - specific information to a FPGA PR + * @flags: boolean flags as defined above + * @pr_err: PR error code + * @state: fpga manager state + * @port_id: port id + */ +struct fpga_pr_info { + u32 flags; + u64 pr_err; + enum fpga_pr_states state; + int port_id; +}; + +#define DEFINE_FPGA_PR_ERR_MSG(_name_) \ +static const char * const _name_[] = { \ + "PR operation error detected", \ + "PR CRC error detected", \ + "PR incompatiable bitstream error detected", \ + "PR IP protocol error detected", \ + "PR FIFO overflow error detected", \ + "PR timeout error detected", \ + "PR secure load error detected", \ +} + +#define RST_POLL_INVL 10 /* us */ +#define RST_POLL_TIMEOUT 1000 /* us */ + +#define PR_WAIT_TIMEOUT 15000000 + +#define PR_HOST_STATUS_IDLE 0 +#define PR_MAX_ERR_NUM 7 + +DEFINE_FPGA_PR_ERR_MSG(pr_err_msg); + +/* + * green bitstream header must be byte-packed to match the + * real file format. + */ +struct bts_header { + u64 guid_h; + u64 guid_l; + u32 metadata_len; +}; + +#define GBS_GUID_H 0x414750466e6f6558 +#define GBS_GUID_L 0x31303076534247b7 +#define is_valid_bts(bts_hdr) \ + (((bts_hdr)->guid_h == GBS_GUID_H) && \ + ((bts_hdr)->guid_l == GBS_GUID_L)) + +#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 new file mode 100644 index 0000000..10a8f06 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -0,0 +1,824 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_hw_api.h" +#include "ifpga_api.h" + +#include "ifpga_hw.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +struct build_feature_devs_info { + struct opae_adapter_data_pci *pci_data; + + struct ifpga_afu_info *acc_info; + + void *fiu; + enum fpga_id_type current_type; + int current_port_id; + + void *ioaddr; + void *ioend; + uint64_t phys_addr; + int current_bar; + + void *pfme_hdr; + + struct ifpga_hw *hw; +}; + +struct feature_info { + const char *name; + uint32_t resource_size; + int feature_index; + int revision_id; + unsigned int vec_start; + unsigned int vec_cnt; + + struct feature_ops *ops; +}; + +/* 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, + } +}; + +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 = &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 = &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 = &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 = &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 + }, +}; + +static u64 feature_id(void __iomem *start) +{ + struct feature_header header; + + header.csr = readq(start); + + switch (header.type) { + case FEATURE_TYPE_FIU: + return FEATURE_ID_HEADER; + case FEATURE_TYPE_PRIVATE: + return header.id; + case FEATURE_TYPE_AFU: + return FEATURE_ID_AFU; + } + + WARN_ON(1); + return 0; +} + +static int +build_info_add_sub_feature(struct build_feature_devs_info *binfo, + struct feature_info *finfo, void __iomem *start) +{ + 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; + } + + 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->phys_addr = binfo->phys_addr + + ((u8 *)start - (u8 *)binfo->ioaddr); + + if (vec_cnt) { + if (vec_start + vec_cnt <= vec_start) + return -EINVAL; + + ctx = zmalloc(sizeof(*ctx) * vec_cnt); + if (!ctx) + return -ENOMEM; + + for (i = 0; i < vec_cnt; i++) { + ctx[i].eventfd = -1; + ctx[i].idx = vec_start + i; + } + } + + feature->ctx = ctx; + feature->ctx_num = vec_cnt; + feature->vfio_dev_fd = binfo->pci_data->vfio_dev_fd; + + return ret; +} + +static int +create_feature_instance(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + struct feature_header *hdr = start; + + if (((u8 *)binfo->ioend - (u8 *)start) < finfo->resource_size) + return -EINVAL; + + 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); +} + +/* + * UAFU GUID is dynamic as it can be changed after FME downloads different + * Green Bitstream to the port, so we treat the unknown GUIDs which are + * attached on port's feature list as UAFU. + */ +static bool feature_is_UAFU(struct build_feature_devs_info *binfo) +{ + if (binfo->current_type != PORT_ID) + return false; + + return true; +} + +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; + struct ifpga_afu_info *info; + void *start = (void *)hdr; + int ret; + + 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; + } + + if (ret) + return ret; + + /* FIXME: need to figure out a better name */ + info = 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->num_regions = 1; + + binfo->acc_info = info; + + return ret; +} + +static int parse_feature_afus(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + int ret; + struct feature_afu_header *afu_hdr, header; + u8 __iomem *start; + u8 __iomem *end = binfo->ioend; + + start = (u8 __iomem *)hdr; + for (; start < end; start += header.next_afu) { + if (end - start < + (unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr))) + return -EINVAL; + + hdr = (struct feature_header *)start; + afu_hdr = (struct feature_afu_header *)(hdr + 1); + header.csr = readq(&afu_hdr->csr); + + if (feature_is_UAFU(binfo)) { + ret = parse_feature_port_uafu(binfo, hdr); + if (ret) + return ret; + } + + if (!header.next_afu) + break; + } + + return 0; +} + +/* create and register proper private data */ +static int build_info_commit_dev(struct build_feature_devs_info *binfo) +{ + struct ifpga_afu_info *info = binfo->acc_info; + struct ifpga_hw *hw = binfo->hw; + struct opae_manager *mgr; + struct opae_bridge *br; + struct opae_accelerator *acc; + + if (!binfo->fiu) + return 0; + + if (binfo->current_type == PORT_ID) { + /* return error if no valid acc info data structure */ + if (!info) + return -EFAULT; + + br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops, + binfo->fiu); + if (!br) + return -ENOMEM; + + br->id = binfo->current_port_id; + + /* update irq info */ + info->num_irqs = port_features[PORT_FEATURE_ID_UINT].vec_cnt; + + acc = opae_accelerator_alloc(hw->adapter->name, + &ifpga_acc_ops, info); + if (!acc) { + opae_bridge_free(br); + return -ENOMEM; + } + + acc->br = br; + acc->index = br->id; + + opae_adapter_add_acc(hw->adapter, acc); + + } else if (binfo->current_type == FME_ID) { + mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops, + binfo->fiu); + if (!mgr) + return -ENOMEM; + + mgr->adapter = hw->adapter; + hw->adapter->mgr = mgr; + } + + binfo->fiu = NULL; + + return 0; +} + +static int +build_info_create_dev(struct build_feature_devs_info *binfo, + enum fpga_id_type type, unsigned int index) +{ + int ret; + + ret = build_info_commit_dev(binfo); + if (ret) + return ret; + + binfo->current_type = type; + + if (type == FME_ID) { + binfo->fiu = &binfo->hw->fme; + } else if (type == PORT_ID) { + binfo->fiu = &binfo->hw->port[index]; + binfo->current_port_id = index; + } + + return 0; +} + +static int parse_feature_fme(struct build_feature_devs_info *binfo, + struct feature_header *start) +{ + struct ifpga_hw *hw = binfo->hw; + struct ifpga_fme_hw *fme = &hw->fme; + int ret; + + ret = build_info_create_dev(binfo, FME_ID, 0); + if (ret) + return ret; + + /* Update FME states */ + fme->state = IFPGA_FME_IMPLEMENTED; + fme->parent = hw; + spinlock_init(&fme->lock); + + return create_feature_instance(binfo, start, + &fme_features[FME_FEATURE_ID_HEADER]); +} + +static int parse_feature_port(struct build_feature_devs_info *binfo, + void __iomem *start) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + struct ifpga_hw *hw = binfo->hw; + struct ifpga_port_hw *port; + unsigned int port_id; + int ret; + + /* Get current port's id */ + port_hdr = (struct feature_port_header *)start; + capability.csr = readq(&port_hdr->capability); + port_id = capability.port_number; + + ret = build_info_create_dev(binfo, PORT_ID, port_id); + if (ret) + return ret; + + /*found a Port device*/ + port = &hw->port[port_id]; + port->port_id = binfo->current_port_id; + port->parent = hw; + port->state = IFPGA_PORT_ATTACHED; + spinlock_init(&port->lock); + + return create_feature_instance(binfo, start, + &port_features[PORT_FEATURE_ID_HEADER]); +} + +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); +} + +static int parse_feature_fiu(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + struct feature_fiu_header *fiu_hdr, fiu_header; + u8 __iomem *start = (u8 __iomem *)hdr; + int ret; + + header.csr = readq(hdr); + + switch (header.id) { + case FEATURE_FIU_ID_FME: + ret = parse_feature_fme(binfo, hdr); + binfo->pfme_hdr = hdr; + if (ret) + return ret; + break; + case FEATURE_FIU_ID_PORT: + ret = parse_feature_port(binfo, hdr); + enable_port_uafu(binfo, hdr); + if (ret) + return ret; + + /* Check Port FIU's next_afu pointer to User AFU DFH */ + fiu_hdr = (struct feature_fiu_header *)(hdr + 1); + fiu_header.csr = readq(&fiu_hdr->csr); + + if (fiu_header.next_afu) { + start += fiu_header.next_afu; + ret = parse_feature_afus(binfo, + (struct feature_header *)start); + if (ret) + return ret; + } else { + dev_info(binfo, "No AFUs detected on Port\n"); + } + + break; + default: + dev_info(binfo, "FIU TYPE %d is not supported yet.\n", + header.id); + } + + return 0; +} + +static void parse_feature_irqs(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + finfo->vec_start = 0; + finfo->vec_cnt = 0; + + UNUSED(binfo); + + if (!strcmp(finfo->name, PORT_FEATURE_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; + } else { + dev_debug(binfo, "UAFU doesn't support interrupt\n"); + } + } else if (!strcmp(finfo->name, PORT_FEATURE_ERR)) { + 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; + } else { + dev_debug(&binfo, "Port error doesn't support interrupt\n"); + } + + } else if (!strcmp(finfo->name, FME_FEATURE_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; + } else { + dev_debug(&binfo, "FME error doesn't support interrupt\n"); + } + } +} + +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; + } + + parse_feature_irqs(binfo, hdr, &fme_features[header.id]); + + return create_feature_instance(binfo, hdr, &fme_features[header.id]); +} + +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; + + 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]); + + return create_feature_instance(binfo, hdr, &port_features[id]); +} + +static int parse_feature_private(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + + header.csr = readq(hdr); + + switch (binfo->current_type) { + case FME_ID: + return parse_feature_fme_private(binfo, hdr); + case PORT_ID: + return parse_feature_port_private(binfo, hdr); + default: + dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n", + header.id, binfo->current_type); + } + return 0; +} + +static int parse_feature(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + int ret = 0; + + header.csr = readq(hdr); + + switch (header.type) { + case FEATURE_TYPE_AFU: + ret = parse_feature_afus(binfo, hdr); + break; + case FEATURE_TYPE_PRIVATE: + ret = parse_feature_private(binfo, hdr); + break; + case FEATURE_TYPE_FIU: + ret = parse_feature_fiu(binfo, hdr); + break; + default: + dev_err(binfo, "Feature Type %x is not supported.\n", + hdr->type); + }; + + return ret; +} + +static int +parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start) +{ + struct feature_header *hdr, header; + u8 __iomem *end = (u8 __iomem *)binfo->ioend; + int ret = 0; + + for (; start < end; start += header.next_header_offset) { + if (end - start < (unsigned int)sizeof(*hdr)) { + dev_err(binfo, "The region is too small to contain a feature.\n"); + ret = -EINVAL; + break; + } + + hdr = (struct feature_header *)start; + ret = parse_feature(binfo, hdr); + if (ret) + return ret; + + header.csr = readq(hdr); + if (!header.next_header_offset) + break; + } + + return build_info_commit_dev(binfo); +} + +/* switch the memory mapping to BAR# @bar */ +static int parse_switch_to(struct build_feature_devs_info *binfo, int bar) +{ + struct opae_adapter_data_pci *pci_data = binfo->pci_data; + + if (!pci_data->region[bar].addr) + return -ENOMEM; + + binfo->ioaddr = pci_data->region[bar].addr; + binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len; + binfo->phys_addr = pci_data->region[bar].phys_addr; + binfo->current_bar = bar; + + return 0; +} + +static int parse_ports_from_fme(struct build_feature_devs_info *binfo) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_port port; + int i = 0, ret = 0; + + if (!binfo->pfme_hdr) { + dev_info(binfo, "VF is detected.\n"); + return ret; + } + + fme_hdr = binfo->pfme_hdr; + + do { + port.csr = readq(&fme_hdr->port[i]); + if (!port.port_implemented) + break; + + /* skip port which only could be accessed via VF */ + if (port.afu_access_control == FME_AFU_ACCESS_VF) + continue; + + ret = parse_switch_to(binfo, port.port_bar); + if (ret) + break; + + ret = parse_feature_list(binfo, + (u8 __iomem *)binfo->ioaddr + + port.port_offset); + if (ret) + break; + } while (++i < MAX_FPGA_PORT_NUM); + + return ret; +} + +static struct build_feature_devs_info * +build_info_alloc_and_init(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + + binfo = zmalloc(sizeof(*binfo)); + if (!binfo) + return binfo; + + binfo->hw = hw; + binfo->pci_data = hw->pci_data; + + /* fpga feature list starts from BAR 0 */ + if (parse_switch_to(binfo, 0)) { + free(binfo); + return NULL; + } + + return binfo; +} + +static void build_info_free(struct build_feature_devs_info *binfo) +{ + free(binfo); +} + +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; + + 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]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr: 0x%lx\n", + feature->name, (unsigned long long)feature->addr, + (unsigned long long)feature->addr + feature->size - 1, + feature->phys_addr); + } + + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) { + port = &hw->port[i]; + + if (port->state != IFPGA_PORT_ATTACHED) + continue; + + dev_info(hw, "port device: %d\n", port->port_id); + + for (j = 0; j < PORT_FEATURE_ID_MAX; j++) { + feature = &port->sub_feature[j]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr:0x%lx\n", + feature->name, + (unsigned long long)feature->addr, + (unsigned long long)feature->addr + + feature->size - 1, + feature->phys_addr); + } + } +} + +int ifpga_bus_enumerate(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + int ret; + + binfo = build_info_alloc_and_init(hw); + if (!binfo) + return -ENOMEM; + + ret = parse_feature_list(binfo, binfo->ioaddr); + if (ret) + goto exit; + + ret = parse_ports_from_fme(binfo); + if (ret) + goto exit; + + ifpga_print_device_feature_list(hw); + +exit: + build_info_free(binfo); + return ret; +} + +int ifpga_bus_init(struct ifpga_hw *hw) +{ + int i; + + fme_hw_init(&hw->fme); + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) + port_hw_init(&hw->port[i]); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h new file mode 100644 index 0000000..14131e3 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_ENUMERATE_H_ +#define _IFPGA_ENUMERATE_H_ + +int ifpga_bus_init(struct ifpga_hw *hw); +int ifpga_bus_enumerate(struct ifpga_hw *hw); + +#endif /* _IFPGA_ENUMERATE_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c new file mode 100644 index 0000000..6d14523 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -0,0 +1,314 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <linux/vfio.h> +#include <sys/ioctl.h> + +#include "ifpga_feature_dev.h" + +/* + * Enable Port by clear the port soft reset bit, which is set by default. + * The AFU is unable to respond to any MMIO access while in reset. + * __fpga_port_enable function should only be used after __fpga_port_disable + * function. + */ +void __fpga_port_enable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + WARN_ON(!port->disable_count); + + if (--port->disable_count != 0) + return; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x0; + writeq(control.csr, &port_hdr->control); +} + +int __fpga_port_disable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + if (port->disable_count++ != 0) + return 0; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + /* Set port soft reset */ + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x1; + writeq(control.csr, &port_hdr->control); + + /* + * HW sets ack bit to 1 when all outstanding requests have been drained + * on this port and minimum soft reset pulse width has elapsed. + * Driver polls port_soft_reset_ack to determine if reset done by HW. + */ + control.port_sftrst_ack = 1; + + if (fpga_wait_register_field(port_sftrst_ack, control, + &port_hdr->control, RST_POLL_TIMEOUT, + RST_POLL_INVL)) { + dev_err(port, "timeout, fail to reset device\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) +{ + struct feature_port_header *port_hdr; + u64 guidl, guidh; + + port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU); + + spinlock_lock(&port->lock); + guidl = readq(&port_hdr->afu_header.guid.b[0]); + guidh = readq(&port_hdr->afu_header.guid.b[8]); + spinlock_unlock(&port->lock); + + printf("%s: guidl=0x%lx, guidh=0x%lx\n", __func__, guidl, guidh); + + memcpy(uuid->b, &guidl, sizeof(u64)); + memcpy(uuid->b + 8, &guidh, sizeof(u64)); + + return 0; +} + +/* Mask / Unmask Port Errors by the Error Mask register. */ +void port_err_mask(struct ifpga_port_hw *port, bool mask) +{ + struct feature_port_error *port_err; + struct feature_port_err_key err_mask; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + if (mask) + err_mask.csr = PORT_ERR_MASK; + else + err_mask.csr = 0; + + writeq(err_mask.csr, &port_err->error_mask); +} + +/* Clear All Port Errors. */ +int port_err_clear(struct ifpga_port_hw *port, u64 err) +{ + struct feature_port_header *port_hdr; + struct feature_port_error *port_err; + struct feature_port_err_key mask; + struct feature_port_first_err_key first; + struct feature_port_status status; + int ret = 0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + /* + * Clear All Port Errors + * + * - Check for AP6 State + * - Halt Port by keeping Port in reset + * - Set PORT Error mask to all 1 to mask errors + * - Clear all errors + * - Set Port mask to all 0 to enable errors + * - All errors start capturing new errors + * - Enable Port by pulling the port out of reset + */ + + /* If device is still in AP6 state, can not clear any error.*/ + status.csr = readq(&port_hdr->status); + if (status.power_state == PORT_POWER_STATE_AP6) { + dev_err(dev, "Could not clear errors, device in AP6 state.\n"); + return -EBUSY; + } + + /* Halt Port by keeping Port in reset */ + ret = __fpga_port_disable(port); + if (ret) + return ret; + + /* Mask all errors */ + port_err_mask(port, true); + + /* Clear errors if err input matches with current port errors.*/ + mask.csr = readq(&port_err->port_error); + + if (mask.csr == err) { + writeq(mask.csr, &port_err->port_error); + + first.csr = readq(&port_err->port_first_error); + writeq(first.csr, &port_err->port_first_error); + } else { + ret = -EBUSY; + } + + /* Clear mask */ + port_err_mask(port, false); + + /* Enable the Port by clear the reset */ + __fpga_port_enable(port); + + return ret; +} + +int port_clear_error(struct ifpga_port_hw *port) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + + dev_info(port, "read port error: 0x%lx\n", error.csr); + + return port_err_clear(port, error.csr); +} + +void fme_hw_uinit(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return; + + 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); + } +} + +int fme_hw_init(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i, ret; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + 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; + } + } + } + + return 0; +} + +void port_hw_uinit(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i; + + 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); + } +} + +int port_hw_init(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i, 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; + } + } + } + + return 0; +} + +/* + * FIXME: we should get msix vec count during pci enumeration instead of + * below hardcode value. + */ +#define FPGA_MSIX_VEC_COUNT 20 +/* irq set buffer length for interrupt */ +#define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \ + sizeof(int) * FPGA_MSIX_VEC_COUNT) + +/* only support msix for now*/ +static int vfio_msix_enable_block(s32 vfio_dev_fd, unsigned int vec_start, + unsigned int count, s32 *fds) +{ + char irq_set_buf[MSIX_IRQ_SET_BUF_LEN]; + struct vfio_irq_set *irq_set; + int len, ret; + int *fd_ptr; + + len = sizeof(irq_set_buf); + + irq_set = (struct vfio_irq_set *)irq_set_buf; + irq_set->argsz = len; + irq_set->count = count; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; + irq_set->start = vec_start; + + fd_ptr = (int *)&irq_set->data; + memcpy(fd_ptr, fds, sizeof(int) * count); + + ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set); + if (ret) + printf("Error enabling MSI-X interrupts\n"); + + return ret; +} + +int fpga_msix_set_block(struct feature *feature, unsigned int start, + unsigned int count, s32 *fds) +{ + struct feature_irq_ctx *ctx = feature->ctx; + unsigned int i; + int ret; + + if (start >= feature->ctx_num || start + count > feature->ctx_num) + return -EINVAL; + + /* assume that each feature has continuous vector space in msix*/ + ret = vfio_msix_enable_block(feature->vfio_dev_fd, + ctx[start].idx, count, fds); + if (!ret) { + for (i = 0; i < count; i++) + ctx[i].eventfd = fds[i]; + } + + return ret; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h new file mode 100644 index 0000000..cd114fb --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_FEATURE_DEV_H_ +#define _IFPGA_FEATURE_DEV_H_ + +#include "ifpga_hw.h" + +static inline struct ifpga_port_hw * +get_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return NULL; + + return &hw->port[port_id]; +} + +#define ifpga_for_each_feature(hw, feature) \ + for ((feature) = (hw)->sub_feature; \ + (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++) + +static inline struct feature * +get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(fme, feature) { + if (feature->id == id) + return feature; + } + + return NULL; +} + +static inline struct feature * +get_port_feature_by_id(struct ifpga_port_hw *port, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(port, feature) { + 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; +} + +static inline void * +get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index) +{ + return port->sub_feature[index].addr; +} + +static inline bool +is_fme_feature_present(struct ifpga_fme_hw *fme, int index) +{ + return !!get_fme_feature_ioaddr_by_index(fme, index); +} + +static inline bool +is_port_feature_present(struct ifpga_port_hw *port, int index) +{ + return !!get_port_feature_ioaddr_by_index(port, index); +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid); + +int __fpga_port_disable(struct ifpga_port_hw *port); +void __fpga_port_enable(struct ifpga_port_hw *port); + +static inline int fpga_port_disable(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_disable(port); + spinlock_unlock(&port->lock); + return ret; +} + +static inline int fpga_port_enable(struct ifpga_port_hw *port) +{ + spinlock_lock(&port->lock); + __fpga_port_enable(port); + spinlock_unlock(&port->lock); + + return 0; +} + +static inline int __fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + ret = __fpga_port_disable(port); + if (ret) + return ret; + + __fpga_port_enable(port); + + return 0; +} + +static inline int fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_reset(port); + spinlock_unlock(&port->lock); + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +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); +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set); + +int fme_hw_init(struct ifpga_fme_hw *fme); +void fme_hw_uinit(struct ifpga_fme_hw *fme); +void port_hw_uinit(struct ifpga_port_hw *port); +int port_hw_init(struct ifpga_port_hw *port); +int port_clear_error(struct ifpga_port_hw *port); +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; + +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); + +/* This struct is used when parsing uafu irq_set */ +struct fpga_uafu_irq_set { + u32 start; + u32 count; + s32 *evtfds; +}; + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set); + +extern struct feature_ops port_hdr_ops; +extern struct feature_ops port_error_ops; +extern struct feature_ops port_stp_ops; +extern struct feature_ops port_uint_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 new file mode 100644 index 0000000..4be60c0 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -0,0 +1,734 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PWR_THRESHOLD_MAX 0x7F + +int fme_get_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +/* fme private feature head */ +static int fme_hdr_init(struct feature *feature) +{ + struct feature_fme_header *fme_hdr; + + fme_hdr = (struct feature_fme_header *)feature->addr; + + dev_info(NULL, "FME HDR Init.\n"); + dev_info(NULL, "FME cap %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + return 0; +} + +static void fme_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME HDR UInit.\n"); +} + +static int fme_hdr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&fme_hdr->header); + *revision = header.revision; + + return 0; +} + +static int fme_hdr_get_ports_num(struct ifpga_fme_hw *fme, u64 *ports_num) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *ports_num = fme_capability.num_ports; + + return 0; +} + +static int fme_hdr_get_cache_size(struct ifpga_fme_hw *fme, u64 *cache_size) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *cache_size = fme_capability.cache_size; + + return 0; +} + +static int fme_hdr_get_version(struct ifpga_fme_hw *fme, u64 *version) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *version = fme_capability.fabric_verid; + + return 0; +} + +static int fme_hdr_get_socket_id(struct ifpga_fme_hw *fme, u64 *socket_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *socket_id = fme_capability.socket_id; + + return 0; +} + +static int fme_hdr_get_bitstream_id(struct ifpga_fme_hw *fme, + u64 *bitstream_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_id = readq(&fme_hdr->bitstream_id); + + return 0; +} + +static int fme_hdr_get_bitstream_metadata(struct ifpga_fme_hw *fme, + u64 *bitstream_metadata) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_metadata = readq(&fme_hdr->bitstream_md); + + return 0; +} + +static int +fme_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_HDR_PROP_REVISION: + return fme_hdr_get_revision(fme, &prop->data); + case FME_HDR_PROP_PORTS_NUM: + return fme_hdr_get_ports_num(fme, &prop->data); + case FME_HDR_PROP_CACHE_SIZE: + return fme_hdr_get_cache_size(fme, &prop->data); + case FME_HDR_PROP_VERSION: + return fme_hdr_get_version(fme, &prop->data); + case FME_HDR_PROP_SOCKET_ID: + return fme_hdr_get_socket_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_ID: + return fme_hdr_get_bitstream_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_METADATA: + return fme_hdr_get_bitstream_metadata(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_hdr_ops = { + .init = fme_hdr_init, + .uinit = fme_hdr_uinit, + .get_prop = fme_hdr_get_prop, +}; + +/* thermal management */ +static int fme_thermal_get_threshold1(struct ifpga_fme_hw *fme, u64 *thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1 = temp_threshold.tmp_thshold1; + + return 0; +} + +static int fme_thermal_set_threshold1(struct ifpga_fme_hw *fme, u64 thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres1 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres1 == 0) { + tmp_threshold.tmp_thshold1_enable = 0; + tmp_threshold.tmp_thshold1 = thres1; + } else { + tmp_threshold.tmp_thshold1_enable = 1; + tmp_threshold.tmp_thshold1 = thres1; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold2(struct ifpga_fme_hw *fme, u64 *thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres2 = temp_threshold.tmp_thshold2; + + return 0; +} + +static int fme_thermal_set_threshold2(struct ifpga_fme_hw *fme, u64 thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres2 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres2 == 0) { + tmp_threshold.tmp_thshold2_enable = 0; + tmp_threshold.tmp_thshold2 = thres2; + } else { + tmp_threshold.tmp_thshold2_enable = 1; + tmp_threshold.tmp_thshold2 = thres2; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold_trip(struct ifpga_fme_hw *fme, + u64 *thres_trip) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres_trip = temp_threshold.therm_trip_thshold; + + return 0; +} + +static int fme_thermal_get_threshold1_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold1_status; + + return 0; +} + +static int fme_thermal_get_threshold2_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold2_status; + + return 0; +} + +static int fme_thermal_get_threshold1_policy(struct ifpga_fme_hw *fme, + u64 *thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_policy = temp_threshold.thshold_policy; + + return 0; +} + +static int fme_thermal_set_threshold1_policy(struct ifpga_fme_hw *fme, + u64 thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold tmp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + + if (thres1_policy == 0) { + tmp_threshold.thshold_policy = 0; + } else if (thres1_policy == 1) { + tmp_threshold.thshold_policy = 1; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_temperature(struct ifpga_fme_hw *fme, u64 *temp) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_temp_rdsensor_fmt1 temp_rdsensor_fmt1; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_rdsensor_fmt1.csr = readq(&thermal->rdsensor_fm1); + *temp = temp_rdsensor_fmt1.fpga_temp; + + return 0; +} + +static int fme_thermal_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_thermal *fme_thermal + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + struct feature_header header; + + header.csr = readq(&fme_thermal->header); + *revision = header.revision; + + return 0; +} + +#define FME_THERMAL_CAP_NO_TMP_THRESHOLD 0x1 + +static int fme_thermal_mgmt_init(struct feature *feature) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold_cap thermal_cap; + + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt Init.\n"); + + fme_thermal = (struct feature_fme_thermal *)feature->addr; + thermal_cap.csr = readq(&fme_thermal->threshold_cap); + + dev_info(NULL, "FME thermal cap %llx.\n", + (unsigned long long)fme_thermal->threshold_cap.csr); + + if (thermal_cap.tmp_thshold_disabled) + feature->cap |= FME_THERMAL_CAP_NO_TMP_THRESHOLD; + + return 0; +} + +static void fme_thermal_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt UInit.\n"); +} + +static int +fme_thermal_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_set_threshold1(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_set_threshold2(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_set_threshold1_policy(fme, prop->data); + } + + return -ENOENT; +} + +static int +fme_thermal_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD && + prop->prop_id != FME_THERMAL_PROP_TEMPERATURE && + prop->prop_id != FME_THERMAL_PROP_REVISION) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_get_threshold1(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_get_threshold2(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD_TRIP: + return fme_thermal_get_threshold_trip(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_REACHED: + return fme_thermal_get_threshold1_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2_REACHED: + return fme_thermal_get_threshold2_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_get_threshold1_policy(fme, &prop->data); + case FME_THERMAL_PROP_TEMPERATURE: + return fme_thermal_get_temperature(fme, &prop->data); + case FME_THERMAL_PROP_REVISION: + return fme_thermal_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_thermal_mgmt_ops = { + .init = fme_thermal_mgmt_init, + .uinit = fme_thermal_mgmt_uinit, + .get_prop = fme_thermal_get_prop, + .set_prop = fme_thermal_set_prop, +}; + +static int fme_pwr_get_consumed(struct ifpga_fme_hw *fme, u64 *consumed) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *consumed = pm_status.pwr_consumed; + + return 0; +} + +static int fme_pwr_get_threshold1(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold1; + + return 0; +} + +static int fme_pwr_set_threshold1(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold1 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold2(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold2; + + return 0; +} + +static int fme_pwr_set_threshold2(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold2 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold1_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold1_status; + + return 0; +} + +static int fme_pwr_get_threshold2_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold2_status; + + return 0; +} + +static int fme_pwr_get_rtl(struct ifpga_fme_hw *fme, u64 *rtl) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *rtl = pm_status.fpga_latency_report; + + return 0; +} + +static int fme_pwr_get_xeon_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_xeon_limit xeon_limit; + + xeon_limit.csr = readq(&fme_power->xeon_limit); + + if (!xeon_limit.enable) + xeon_limit.pwr_limit = 0; + + *limit = xeon_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_fpga_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_fpga_limit fpga_limit; + + fpga_limit.csr = readq(&fme_power->fpga_limit); + + if (!fpga_limit.enable) + fpga_limit.pwr_limit = 0; + + *limit = fpga_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_header header; + + header.csr = readq(&fme_power->header); + *revision = header.revision; + + return 0; +} + +static int fme_power_mgmt_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt Init.\n"); + + return 0; +} + +static void fme_power_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt UInit.\n"); +} + +static int fme_power_mgmt_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_CONSUMED: + return fme_pwr_get_consumed(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_get_threshold1(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_get_threshold2(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1_STATUS: + return fme_pwr_get_threshold1_status(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2_STATUS: + return fme_pwr_get_threshold2_status(fme, &prop->data); + case FME_PWR_PROP_RTL: + return fme_pwr_get_rtl(fme, &prop->data); + case FME_PWR_PROP_XEON_LIMIT: + return fme_pwr_get_xeon_limit(fme, &prop->data); + case FME_PWR_PROP_FPGA_LIMIT: + return fme_pwr_get_fpga_limit(fme, &prop->data); + case FME_PWR_PROP_REVISION: + return fme_pwr_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_power_mgmt_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_set_threshold1(fme, prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_set_threshold2(fme, prop->data); + } + + return -ENOENT; +} + +struct 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, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c new file mode 100644 index 0000000..1773b87 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_dperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_clk_ctr clk; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + clk.afu_interf_clock = readq(&dperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_dperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_dperf *dperf; + struct feature_header header; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + header.csr = readq(&dperf->header); + *revision = header.revision; + + return 0; +} + +#define DPERF_TIMEOUT 30 + +static bool fabric_pobj_is_enabled(int port_id, + struct feature_fme_dperf *dperf) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + + ctl.csr = readq(&dperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum dperf_fab_events fab_event) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dfpmon_fab_ctr ctr; + struct feature_fme_dperf *dperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, dperf)) + goto exit; + + ctl.csr = readq(&dperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &dperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &dperf->fab_ctr, DPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&dperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_dperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, DPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, DPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(mmio_read, DPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, DPERF_FAB_MMIO_WR); + +static int fme_dperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_dperf *dperf; + int status; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + status = fabric_pobj_is_enabled(port_id, dperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_dperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dperf *dperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, dperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&dperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_dperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_dperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 + +static int fme_global_dperf_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf Init.\n"); + + return 0; +} + +static void fme_global_dperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf UInit.\n"); +} + +static int fme_dperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_dperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_dperf_get_fab_port_pcie0_read(fme, sub, &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_dperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* MMIO_READ */ + return fme_dperf_get_fab_port_mmio_read(fme, sub, &prop->data); + case 0x5: /* MMIO_WRITE */ + return fme_dperf_get_fab_port_mmio_write(fme, sub, &prop->data); + case 0x6: /* ENABLE */ + return fme_dperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_dperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_dperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_dperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_dperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_dperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE - fab root only prop */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_dperf_set_fab_freeze(fme, prop->data); + case 0x6: /* ENABLE - fab both root and sub */ + return fme_dperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_dperf_ops = { + .init = fme_global_dperf_init, + .uinit = fme_global_dperf_uinit, + .get_prop = fme_global_dperf_get_prop, + .set_prop = fme_global_dperf_set_prop, + +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c new file mode 100644 index 0000000..33c241e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static int fme_err_get_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + + fme_error0.csr = readq(&fme_err->fme_err); + *val = fme_error0.csr; + + return 0; +} + +static int fme_err_get_first_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_first_error fme_first_err; + + fme_first_err.csr = readq(&fme_err->fme_first_err); + *val = fme_first_err.err_reg_status; + + return 0; +} + +static int fme_err_get_next_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_next_error fme_next_err; + + fme_next_err.csr = readq(&fme_err->fme_next_err); + *val = fme_next_err.err_reg_status; + + return 0; +} + +static int fme_err_set_clear(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_ERROR0_MASK, &fme_err->fme_err_mask); + + fme_error0.csr = readq(&fme_err->fme_err); + if (val != fme_error0.csr) { + ret = -EBUSY; + goto exit; + } + + fme_first_err.csr = readq(&fme_err->fme_first_err); + fme_next_err.csr = readq(&fme_err->fme_next_err); + + writeq(fme_error0.csr & FME_ERROR0_MASK, &fme_err->fme_err); + writeq(fme_first_err.csr & FME_FIRST_ERROR_MASK, + &fme_err->fme_first_err); + writeq(fme_next_err.csr & FME_NEXT_ERROR_MASK, + &fme_err->fme_next_err); + +exit: + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_revision(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_header header; + + header.csr = readq(&fme_err->header); + *val = header.revision; + + return 0; +} + +static int fme_err_get_pcie0_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + + pcie0_err.csr = readq(&fme_err->pcie0_err); + *val = pcie0_err.csr; + + return 0; +} + +static int fme_err_set_pcie0_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE0_ERROR_MASK, &fme_err->pcie0_err_mask); + + pcie0_err.csr = readq(&fme_err->pcie0_err); + if (val != pcie0_err.csr) + ret = -EBUSY; + else + writeq(pcie0_err.csr & FME_PCIE0_ERROR_MASK, + &fme_err->pcie0_err); + + writeq(0UL, &fme_err->pcie0_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_pcie1_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + + pcie1_err.csr = readq(&fme_err->pcie1_err); + *val = pcie1_err.csr; + + return 0; +} + +static int fme_err_set_pcie1_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE1_ERROR_MASK, &fme_err->pcie1_err_mask); + + pcie1_err.csr = readq(&fme_err->pcie1_err); + if (val != pcie1_err.csr) + ret = -EBUSY; + else + writeq(pcie1_err.csr & FME_PCIE1_ERROR_MASK, + &fme_err->pcie1_err); + + writeq(0UL, &fme_err->pcie1_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_nonfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_nonfaterror ras_nonfaterr; + + ras_nonfaterr.csr = readq(&fme_err->ras_nonfaterr); + *val = ras_nonfaterr.csr; + + return 0; +} + +static int fme_err_get_catfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_catfaterror ras_catfaterr; + + ras_catfaterr.csr = readq(&fme_err->ras_catfaterr); + *val = ras_catfaterr.csr; + + return 0; +} + +static int fme_err_get_inject_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + *val = ras_error_inj.csr & FME_RAS_ERROR_INJ_MASK; + + return 0; +} + +static int fme_err_set_inject_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + spinlock_lock(&fme->lock); + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + + if (val <= FME_RAS_ERROR_INJ_MASK) { + ras_error_inj.csr = val; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(ras_error_inj.csr, &fme_err->ras_error_inj); + spinlock_unlock(&fme->lock); + + return 0; +} + +static void fme_error_enable(struct ifpga_fme_hw *fme) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + writeq(0UL, &fme_err->pcie0_err_mask); + writeq(0UL, &fme_err->pcie1_err_mask); + writeq(0UL, &fme_err->ras_nonfat_mask); + writeq(0UL, &fme_err->ras_catfat_mask); +} + +static int fme_global_error_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = feature->parent; + + fme_error_enable(fme); + + if (feature->ctx_num) + fme->capability |= FPGA_FME_CAP_ERR_IRQ; + + return 0; +} + +static void fme_global_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int fme_err_fme_err_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* ERRORS */ + return fme_err_get_errors(fme, &prop->data); + case 0x2: /* FIRST_ERROR */ + return fme_err_get_first_error(fme, &prop->data); + case 0x3: /* NEXT_ERROR */ + return fme_err_get_next_error(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x5: /* REVISION */ + return fme_err_get_revision(fme, &prop->data); + case 0x6: /* PCIE0_ERRORS */ + return fme_err_get_pcie0_errors(fme, &prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_get_pcie1_errors(fme, &prop->data); + case 0x8: /* NONFATAL_ERRORS */ + return fme_err_get_nonfatal_errors(fme, &prop->data); + case 0x9: /* CATFATAL_ERRORS */ + return fme_err_get_catfatal_errors(fme, &prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_get_inject_errors(fme, &prop->data); + case 0xb: /* REVISION*/ + return fme_err_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_get_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_err_fme_err_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x4: /* CLEAR */ + return fme_err_set_clear(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x6: /* PCIE0_ERRORS */ + return fme_err_set_pcie0_errors(fme, prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_set_pcie1_errors(fme, prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_set_inject_errors(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_set_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_set_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_global_err_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_fme_err_irq_set *err_irq_set = + (struct fpga_fme_err_irq_set *)irq_set; + struct ifpga_fme_hw *fme; + int ret; + + fme = (struct ifpga_fme_hw *)feature->parent; + + spinlock_lock(&fme->lock); + if (!(fme->capability & FPGA_FME_CAP_ERR_IRQ)) { + spinlock_unlock(&fme->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&fme->lock); + + return ret; +} + +struct feature_ops fme_global_err_ops = { + .init = fme_global_error_init, + .uinit = fme_global_error_uinit, + .get_prop = fme_global_error_get_prop, + .set_prop = fme_global_error_set_prop, + .set_irq = fme_global_err_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c new file mode 100644 index 0000000..e6c40a1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c @@ -0,0 +1,715 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_iperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_clk_ctr clk; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + clk.afu_interf_clock = readq(&iperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_iperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_iperf *iperf; + struct feature_header header; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + header.csr = readq(&iperf->header); + *revision = header.revision; + + return 0; +} + +static int fme_iperf_get_cache_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + *freeze = (u64)ctl.freeze; + return 0; +} + +static int fme_iperf_set_cache_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->ch_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define IPERF_TIMEOUT 30 + +static u64 read_cache_counter(struct ifpga_fme_hw *fme, + u8 channel, enum iperf_cache_events event) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + struct feature_fme_ifpmon_ch_ctr ctr0, ctr1; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* set channel access type and cache event code. */ + ctl.csr = readq(&iperf->ch_ctl); + ctl.cci_chsel = channel; + ctl.cache_event = event; + writeq(ctl.csr, &iperf->ch_ctl); + + /* check the event type in the counter registers */ + ctr0.event_code = event; + + if (fpga_wait_register_field(event_code, ctr0, + &iperf->ch_ctr0, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched cache event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr0.csr = readq(&iperf->ch_ctr0); + ctr1.csr = readq(&iperf->ch_ctr1); + counter = ctr0.cache_counter + ctr1.cache_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define CACHE_SHOW(name, type, event) \ +static int fme_iperf_get_cache_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_cache_counter(fme, type, event); \ + return 0; \ +} + +CACHE_SHOW(read_hit, CACHE_CHANNEL_RD, IPERF_CACHE_RD_HIT); +CACHE_SHOW(read_miss, CACHE_CHANNEL_RD, IPERF_CACHE_RD_MISS); +CACHE_SHOW(write_hit, CACHE_CHANNEL_WR, IPERF_CACHE_WR_HIT); +CACHE_SHOW(write_miss, CACHE_CHANNEL_WR, IPERF_CACHE_WR_MISS); +CACHE_SHOW(hold_request, CACHE_CHANNEL_RD, IPERF_CACHE_HOLD_REQ); +CACHE_SHOW(tx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_TX_REQ_STALL); +CACHE_SHOW(rx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_RX_REQ_STALL); +CACHE_SHOW(rx_eviction, CACHE_CHANNEL_RD, IPERF_CACHE_EVICTIONS); +CACHE_SHOW(data_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_DATA_WR_PORT_CONTEN); +CACHE_SHOW(tag_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_TAG_WR_PORT_CONTEN); + +static int fme_iperf_get_vtd_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_vtd_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->vtd_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static u64 read_iommu_sip_counter(struct ifpga_fme_hw *fme, + enum iperf_vtd_sip_events event) +{ + struct feature_fme_ifpmon_vtd_sip_ctl sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr sip_ctr; + struct feature_fme_iperf *iperf; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + sip_ctl.csr = readq(&iperf->vtd_sip_ctl); + sip_ctl.vtd_evtcode = event; + writeq(sip_ctl.csr, &iperf->vtd_sip_ctl); + + sip_ctr.event_code = event; + + if (fpga_wait_register_field(event_code, sip_ctr, + &iperf->vtd_sip_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd SIP event type in counter registers\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + sip_ctr.csr = readq(&iperf->vtd_sip_ctr); + counter = sip_ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_SIP_SHOW(name, event) \ +static int fme_iperf_get_vtd_sip_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_iommu_sip_counter(fme, event); \ + return 0; \ +} + +VTD_SIP_SHOW(iotlb_4k_hit, IPERF_VTD_SIP_IOTLB_4K_HIT); +VTD_SIP_SHOW(iotlb_2m_hit, IPERF_VTD_SIP_IOTLB_2M_HIT); +VTD_SIP_SHOW(iotlb_1g_hit, IPERF_VTD_SIP_IOTLB_1G_HIT); +VTD_SIP_SHOW(slpwc_l3_hit, IPERF_VTD_SIP_SLPWC_L3_HIT); +VTD_SIP_SHOW(slpwc_l4_hit, IPERF_VTD_SIP_SLPWC_L4_HIT); +VTD_SIP_SHOW(rcc_hit, IPERF_VTD_SIP_RCC_HIT); +VTD_SIP_SHOW(iotlb_4k_miss, IPERF_VTD_SIP_IOTLB_4K_MISS); +VTD_SIP_SHOW(iotlb_2m_miss, IPERF_VTD_SIP_IOTLB_2M_MISS); +VTD_SIP_SHOW(iotlb_1g_miss, IPERF_VTD_SIP_IOTLB_1G_MISS); +VTD_SIP_SHOW(slpwc_l3_miss, IPERF_VTD_SIP_SLPWC_L3_MISS); +VTD_SIP_SHOW(slpwc_l4_miss, IPERF_VTD_SIP_SLPWC_L4_MISS); +VTD_SIP_SHOW(rcc_miss, IPERF_VTD_SIP_RCC_MISS); + +static u64 read_iommu_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_vtd_events base_event) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_ifpmon_vtd_ctr ctr; + struct feature_fme_iperf *iperf; + enum iperf_vtd_events event = base_event + port_id; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.vtd_evtcode = event; + writeq(ctl.csr, &iperf->vtd_ctl); + + ctr.event_code = event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->vtd_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->vtd_ctr); + counter = ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_PORT_SHOW(name, base_event) \ +static int fme_iperf_get_vtd_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_iommu_counter(fme, port_id, base_event); \ + return 0; \ +} + +VTD_PORT_SHOW(read_transaction, IPERF_VTD_AFU_MEM_RD_TRANS); +VTD_PORT_SHOW(write_transaction, IPERF_VTD_AFU_MEM_WR_TRANS); +VTD_PORT_SHOW(devtlb_read_hit, IPERF_VTD_AFU_DEVTLB_RD_HIT); +VTD_PORT_SHOW(devtlb_write_hit, IPERF_VTD_AFU_DEVTLB_WR_HIT); +VTD_PORT_SHOW(devtlb_4k_fill, IPERF_VTD_DEVTLB_4K_FILL); +VTD_PORT_SHOW(devtlb_2m_fill, IPERF_VTD_DEVTLB_2M_FILL); +VTD_PORT_SHOW(devtlb_1g_fill, IPERF_VTD_DEVTLB_1G_FILL); + +static bool fabric_pobj_is_enabled(u8 port_id, struct feature_fme_iperf *iperf) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + + ctl.csr = readq(&iperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_fab_events fab_event) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_ifpmon_fab_ctr ctr; + struct feature_fme_iperf *iperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, iperf)) + goto exit; + + ctl.csr = readq(&iperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &iperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->fab_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_iperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, IPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, IPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(pcie1_read, IPERF_FAB_PCIE1_RD); +FAB_PORT_SHOW(pcie1_write, IPERF_FAB_PCIE1_WR); +FAB_PORT_SHOW(upi_read, IPERF_FAB_UPI_RD); +FAB_PORT_SHOW(upi_write, IPERF_FAB_UPI_WR); +FAB_PORT_SHOW(mmio_read, IPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, IPERF_FAB_MMIO_WR); + +static int fme_iperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_iperf *iperf; + int status; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + status = fabric_pobj_is_enabled(port_id, iperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_iperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, iperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&iperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_iperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 +#define FME_IPERF_CAP_IOMMU 0x1 + +static int fme_global_iperf_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme; + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + + dev_info(NULL, "FME global_iperf Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + /* check if iommu is not supported on this device. */ + fme_capability.csr = readq(&fme_hdr->capability); + dev_info(NULL, "FME HEAD fme_capability %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + if (fme_capability.iommu_support) + feature->cap |= FME_IPERF_CAP_IOMMU; + + return 0; +} + +static void fme_global_iperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_iperf UInit.\n"); +} + +static int fme_iperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_iperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_iperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_cache_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_cache_freeze(fme, &prop->data); + case 0x2: /* READ_HIT */ + return fme_iperf_get_cache_read_hit(fme, &prop->data); + case 0x3: /* READ_MISS */ + return fme_iperf_get_cache_read_miss(fme, &prop->data); + case 0x4: /* WRITE_HIT */ + return fme_iperf_get_cache_write_hit(fme, &prop->data); + case 0x5: /* WRITE_MISS */ + return fme_iperf_get_cache_write_miss(fme, &prop->data); + case 0x6: /* HOLD_REQUEST */ + return fme_iperf_get_cache_hold_request(fme, &prop->data); + case 0x7: /* TX_REQ_STALL */ + return fme_iperf_get_cache_tx_req_stall(fme, &prop->data); + case 0x8: /* RX_REQ_STALL */ + return fme_iperf_get_cache_rx_req_stall(fme, &prop->data); + case 0x9: /* RX_EVICTION */ + return fme_iperf_get_cache_rx_eviction(fme, &prop->data); + case 0xa: /* DATA_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_data_write_port_contention(fme, + &prop->data); + case 0xb: /* TAG_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_tag_write_port_contention(fme, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_vtd_freeze(fme, &prop->data); + case 0x2: /* IOTLB_4K_HIT */ + return fme_iperf_get_vtd_sip_iotlb_4k_hit(fme, &prop->data); + case 0x3: /* IOTLB_2M_HIT */ + return fme_iperf_get_vtd_sip_iotlb_2m_hit(fme, &prop->data); + case 0x4: /* IOTLB_1G_HIT */ + return fme_iperf_get_vtd_sip_iotlb_1g_hit(fme, &prop->data); + case 0x5: /* SLPWC_L3_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l3_hit(fme, &prop->data); + case 0x6: /* SLPWC_L4_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l4_hit(fme, &prop->data); + case 0x7: /* RCC_HIT */ + return fme_iperf_get_vtd_sip_rcc_hit(fme, &prop->data); + case 0x8: /* IOTLB_4K_MISS */ + return fme_iperf_get_vtd_sip_iotlb_4k_miss(fme, &prop->data); + case 0x9: /* IOTLB_2M_MISS */ + return fme_iperf_get_vtd_sip_iotlb_2m_miss(fme, &prop->data); + case 0xa: /* IOTLB_1G_MISS */ + return fme_iperf_get_vtd_sip_iotlb_1g_miss(fme, &prop->data); + case 0xb: /* SLPWC_L3_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l3_miss(fme, &prop->data); + case 0xc: /* SLPWC_L4_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l4_miss(fme, &prop->data); + case 0xd: /* RCC_MISS */ + return fme_iperf_get_vtd_sip_rcc_miss(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_sub_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub > PERF_MAX_PORT_NUM) + return -ENOENT; + + switch (id) { + case 0xe: /* READ_TRANSACTION */ + return fme_iperf_get_vtd_port_read_transaction(fme, sub, + &prop->data); + case 0xf: /* WRITE_TRANSACTION */ + return fme_iperf_get_vtd_port_write_transaction(fme, sub, + &prop->data); + case 0x10: /* DEVTLB_READ_HIT */ + return fme_iperf_get_vtd_port_devtlb_read_hit(fme, sub, + &prop->data); + case 0x11: /* DEVTLB_WRITE_HIT */ + return fme_iperf_get_vtd_port_devtlb_write_hit(fme, sub, + &prop->data); + case 0x12: /* DEVTLB_4K_FILL */ + return fme_iperf_get_vtd_port_devtlb_4k_fill(fme, sub, + &prop->data); + case 0x13: /* DEVTLB_2M_FILL */ + return fme_iperf_get_vtd_port_devtlb_2m_fill(fme, sub, + &prop->data); + case 0x14: /* DEVTLB_1G_FILL */ + return fme_iperf_get_vtd_port_devtlb_1g_fill(fme, sub, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED) + return fme_iperf_vtd_root_get_prop(feature, prop); + + return fme_iperf_vtd_sub_get_prop(feature, prop); +} + +static int fme_iperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + /* Other properties are present for both top and sub levels */ + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_iperf_get_fab_port_pcie0_read(fme, sub, + &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_iperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* PCIE1_READ */ + return fme_iperf_get_fab_port_pcie1_read(fme, sub, + &prop->data); + case 0x5: /* PCIE1_WRITE */ + return fme_iperf_get_fab_port_pcie1_write(fme, sub, + &prop->data); + case 0x6: /* UPI_READ */ + return fme_iperf_get_fab_port_upi_read(fme, sub, + &prop->data); + case 0x7: /* UPI_WRITE */ + return fme_iperf_get_fab_port_upi_write(fme, sub, + &prop->data); + case 0x8: /* MMIO_READ */ + return fme_iperf_get_fab_port_mmio_read(fme, sub, + &prop->data); + case 0x9: /* MMIO_WRITE */ + return fme_iperf_get_fab_port_mmio_write(fme, sub, + &prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_get_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_get_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_iperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_iperf_cache_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_cache_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_vtd_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_vtd_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_set_fab_freeze(fme, prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_set_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_set_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_iperf_ops = { + .init = fme_global_iperf_init, + .uinit = fme_global_iperf_uinit, + .get_prop = fme_global_iperf_get_prop, + .set_prop = fme_global_iperf_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c new file mode 100644 index 0000000..6192fa7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c @@ -0,0 +1,372 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#if defined(RTE_ARCH_X86_64) +static inline void copy512(const void *src, void *dst) +{ + asm volatile("vmovdqu64 (%0), %%zmm0;" + "vmovntdq %%zmm0, (%1);" + : + : "r"(src), "r"(dst)); +} +#else +static inline void copy512(const void *src, void *dst) +{ + UNUSED(src); + UNUSED(dst); + WARN_ON(1); +} +#endif + +static u64 +pr_err_handle(struct feature_fme_pr *fme_pr) +{ + struct feature_fme_pr_status fme_pr_status; + unsigned long err_code; + u64 fme_pr_error; + int i; + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + if (!fme_pr_status.pr_status) + return 0; + + err_code = readq(&fme_pr->ccip_fme_pr_err); + fme_pr_error = err_code; + + for (i = 0; i < PR_MAX_ERR_NUM; i++) { + if (err_code & (1 << i)) + dev_info(NULL, "%s\n", pr_err_msg[i]); + } + + writeq(fme_pr_error, &fme_pr->ccip_fme_pr_err); + return fme_pr_error; +} + +static int fme_pr_write_init(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + if (info->flags != FPGA_MGR_PARTIAL_RECONFIG) + return -EINVAL; + + dev_info(fme_dev, "resetting PR before initiated PR\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + fme_pr_ctl.pr_reset_ack = 1; + + if (fpga_wait_register_field(pr_reset_ack, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 0; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "waiting for PR resource in HW to be initialized and ready\n"); + + fme_pr_status.pr_host_status = PR_HOST_STATUS_IDLE; + + if (fpga_wait_register_field(pr_host_status, fme_pr_status, + &fme_pr->ccip_fme_pr_status, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "check if have any previous PR error\n"); + pr_err_handle(fme_pr); + return 0; +} + +static int fme_pr_write(struct ifpga_fme_hw *fme_dev, + int port_id, const char *buf, size_t count, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + struct feature_fme_pr_data fme_pr_data; + int delay, pr_credit; + int ret = 0; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + dev_info(fme_dev, "set PR port ID and start request\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_regionid = port_id; + fme_pr_ctl.pr_start_req = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "pushing data from bitstream to HW\n"); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + + while (count > 0) { + delay = 0; + while (pr_credit <= 1) { + if (delay++ > PR_WAIT_TIMEOUT) { + dev_err(fme_dev, "maximum try\n"); + + info->pr_err = pr_err_handle(fme_pr); + return info->pr_err ? -EIO : -ETIMEDOUT; + } + udelay(1); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + }; + + if (count >= fme_dev->pr_bandwidth) { + switch (fme_dev->pr_bandwidth) { + case 4: + fme_pr_data.rsvd = 0; + fme_pr_data.pr_data_raw = *((const u32 *)buf); + writeq(fme_pr_data.csr, + &fme_pr->ccip_fme_pr_data); + break; + case 64: + copy512(buf, &fme_pr->fme_pr_data1); + break; + default: + ret = -EFAULT; + goto done; + } + + buf += fme_dev->pr_bandwidth; + count -= fme_dev->pr_bandwidth; + pr_credit--; + } else { + WARN_ON(1); + return -EINVAL; + goto done; + } + } + +done: + return ret; +} + +static int fme_pr_write_complete(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_push_complete = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "green bitstream push complete\n"); + dev_info(fme_dev, "waiting for HW to release PR resource\n"); + + fme_pr_ctl.pr_start_req = 0; + + if (fpga_wait_register_field(pr_start_req, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + printf("maximum try.\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "PR operation complete, checking status\n"); + info->pr_err = pr_err_handle(fme_pr); + if (info->pr_err) + return -EIO; + + dev_info(fme_dev, "PR done successfully\n"); + return 0; +} + +static int fpga_pr_buf_load(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info, const char *buf, + size_t count) +{ + int ret; + + info->state = FPGA_PR_STATE_WRITE_INIT; + ret = fme_pr_write_init(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error preparing FPGA for writing\n"); + info->state = FPGA_PR_STATE_WRITE_INIT_ERR; + return ret; + } + + /* + * Write the FPGA image to the FPGA. + */ + info->state = FPGA_PR_STATE_WRITE; + ret = fme_pr_write(fme_dev, info->port_id, buf, count, info); + if (ret) { + dev_err(fme_dev, "Error while writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_ERR; + return ret; + } + + /* + * After all the FPGA image has been written, do the device specific + * steps to finish and set the FPGA into operating mode. + */ + info->state = FPGA_PR_STATE_WRITE_COMPLETE; + ret = fme_pr_write_complete(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error after writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_COMPLETE_ERR; + return ret; + } + info->state = FPGA_PR_STATE_DONE; + + return 0; +} + +static int fme_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + struct ifpga_fme_hw *fme = &hw->fme; + struct fpga_pr_info info; + struct ifpga_port_hw *port; + int ret = 0; + + if (!buffer || size == 0) + return -EINVAL; + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + /* + * Padding extra zeros to align PR buffer with PR bandwidth, HW will + * ignore these zeros automatically. + */ + size = ALIGN(size, fme->pr_bandwidth); + + /* get fme header region */ + fme_hdr = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_HEADER); + if (!fme_hdr) + return -EINVAL; + + /* check port id */ + fme_capability.csr = readq(&fme_hdr->capability); + if (port_id >= fme_capability.num_ports) { + dev_err(fme, "port number more than maximum\n"); + return -EINVAL; + } + + memset(&info, 0, sizeof(struct fpga_pr_info)); + info.flags = FPGA_MGR_PARTIAL_RECONFIG; + info.port_id = port_id; + + spinlock_lock(&fme->lock); + + /* get port device by port_id */ + port = &hw->port[port_id]; + + /* Disable Port before PR */ + fpga_port_disable(port); + + ret = fpga_pr_buf_load(fme, &info, (void *)buffer, size); + + *status = info.pr_err; + + /* Re-enable Port after PR finished */ + fpga_port_enable(port); + spinlock_unlock(&fme->lock); + + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, u64 *status) +{ + struct bts_header *bts_hdr; + void *buf; + struct ifpga_port_hw *port; + int ret; + + if (!buffer || size == 0) { + dev_err(hw, "invalid parameter\n"); + return -EINVAL; + } + + bts_hdr = (struct bts_header *)buffer; + + if (is_valid_bts(bts_hdr)) { + dev_info(hw, "this is a valid bitsteam..\n"); + size -= (sizeof(struct bts_header) + + bts_hdr->metadata_len); + buf = (u8 *)buffer + sizeof(struct bts_header) + + bts_hdr->metadata_len; + } else { + return -EINVAL; + } + + /* clean port error before do PR */ + port = &hw->port[port_id]; + ret = port_clear_error(port); + if (ret) { + dev_err(hw, "port cannot clear error\n"); + return -EINVAL; + } + + return fme_pr(hw, port_id, buf, size, status); +} + +static int fme_pr_mgmt_init(struct feature *feature) +{ + struct feature_fme_pr *fme_pr; + struct feature_header fme_pr_header; + struct ifpga_fme_hw *fme; + + dev_info(NULL, "FME PR MGMT Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + + fme_pr = (struct feature_fme_pr *)feature->addr; + + fme_pr_header.csr = readq(&fme_pr->header); + if (fme_pr_header.revision == 2) { + dev_info(NULL, "using 512-bit PR\n"); + fme->pr_bandwidth = 64; + } else { + dev_info(NULL, "using 32-bit PR\n"); + fme->pr_bandwidth = 4; + } + + return 0; +} + +static void fme_pr_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME PR MGMT UInit.\n"); +} + +struct 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 new file mode 100644 index 0000000..a20520c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_HW_H_ +#define _IFPGA_HW_H_ + +#include "ifpga_defines.h" +#include "opae_ifpga_hw_api.h" + +enum ifpga_feature_state { + IFPGA_FEATURE_UNUSED = 0, + IFPGA_FEATURE_ATTACHED, +}; + +struct feature_irq_ctx { + int eventfd; + int idx; +}; + +struct feature { + enum ifpga_feature_state state; + const char *name; + u64 id; + u8 *addr; + uint64_t phys_addr; + u32 size; + int revision; + u64 cap; + int vfio_dev_fd; + struct feature_irq_ctx *ctx; + unsigned int ctx_num; + + void *parent; /* to parent hw data structure */ + + struct feature_ops *ops;/* callback to this private feature */ +}; + +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); +}; + +enum ifpga_fme_state { + IFPGA_FME_UNUSED = 0, + IFPGA_FME_IMPLEMENTED, +}; + +struct ifpga_fme_hw { + enum ifpga_fme_state state; + + struct feature sub_feature[FME_FEATURE_ID_MAX]; + spinlock_t lock; /* protect hardware access */ + + void *parent; /* pointer to ifpga_hw */ + + /* provied by HEADER feature */ + u32 port_num; + struct uuid bitstream_id; + u64 bitstream_md; + size_t pr_bandwidth; + u32 socket_id; + u32 fabric_version_id; + u32 cache_size; + + u32 capability; +}; + +enum ifpga_port_state { + IFPGA_PORT_UNUSED = 0, + IFPGA_PORT_ATTACHED, + IFPGA_PORT_DETACHED, +}; + +struct ifpga_port_hw { + enum ifpga_port_state state; + + struct feature sub_feature[PORT_FEATURE_ID_MAX]; + spinlock_t lock; /* protect access to hw */ + + void *parent; /* pointer to ifpga_hw */ + + int port_id; /* provied by HEADER feature */ + struct uuid afu_id; /* provied by User AFU feature */ + + unsigned int disable_count; + + u32 capability; + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ + u8 *stp_addr; + u32 stp_size; +}; + +#define AFU_MAX_REGION 1 + +struct ifpga_afu_info { + struct opae_reg_region region[AFU_MAX_REGION]; + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct ifpga_hw { + struct opae_adapter *adapter; + struct opae_adapter_data_pci *pci_data; + + struct ifpga_fme_hw fme; + struct ifpga_port_hw port[MAX_FPGA_PORT_NUM]; +}; + +static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) +{ + return hw->fme.state != IFPGA_FME_UNUSED; +} + +static inline bool is_valid_port_id(struct ifpga_hw *hw, u32 port_id) +{ + if (port_id >= MAX_FPGA_PORT_NUM || + hw->port[port_id].state != IFPGA_PORT_ATTACHED) + return false; + + return true; +} +#endif /* _IFPGA_HW_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c new file mode 100644 index 0000000..8ab1bdb --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c @@ -0,0 +1,408 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +static int port_get_revision(struct ifpga_port_hw *port, u64 *revision) +{ + struct feature_port_header *port_hdr + = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&port_hdr->header); + + *revision = header.revision; + + return 0; +} + +static int port_get_portidx(struct ifpga_port_hw *port, u64 *idx) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + capability.csr = readq(&port_hdr->capability); + *idx = capability.port_number; + + return 0; +} + +static int port_get_latency_tolerance(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + control.csr = readq(&port_hdr->control); + *val = control.latency_tolerance; + + return 0; +} + +static int port_get_ap1_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap1_event; + + return 0; +} + +static int port_set_ap1_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap1_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_ap2_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap2_event; + + return 0; +} + +static int port_set_ap2_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap2_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_power_state(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.power_state; + + return 0; +} + +static int port_get_userclk_freqcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_hdr_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port hdr Init.\n"); + + fpga_port_reset(port); + + return 0; +} + +static void port_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port hdr uinit.\n"); +} + +static int port_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_REVISION: + return port_get_revision(port, &prop->data); + case PORT_HDR_PROP_PORTIDX: + return port_get_portidx(port, &prop->data); + case PORT_HDR_PROP_LATENCY_TOLERANCE: + return port_get_latency_tolerance(port, &prop->data); + case PORT_HDR_PROP_AP1_EVENT: + return port_get_ap1_event(port, &prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_get_ap2_event(port, &prop->data); + case PORT_HDR_PROP_POWER_STATE: + return port_get_power_state(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_get_userclk_freqcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_get_userclk_freqcntrcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQSTS: + return port_get_userclk_freqsts(port, &prop->data); + case PORT_HDR_PROP_USERCLK_CNTRSTS: + return port_get_userclk_freqcntrsts(port, &prop->data); + } + + return -ENOENT; +} + +static int port_hdr_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_AP1_EVENT: + return port_set_ap1_event(port, prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_set_ap2_event(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_set_userclk_freqcmd(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_set_userclk_freqcntrcmd(port, prop->data); + } + + return -ENOENT; +} + +struct feature_ops 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) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port stp Init.\n"); + + spinlock_lock(&port->lock); + port->stp_addr = feature->addr; + port->stp_size = feature->size; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_stp_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port stp uinit.\n"); +} + +struct feature_ops port_stp_ops = { + .init = port_stp_init, + .uinit = port_stp_uinit, +}; + +static int port_uint_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "PORT UINT Init.\n"); + + spinlock_lock(&port->lock); + if (feature->ctx_num) { + port->capability |= FPGA_PORT_CAP_UAFU_IRQ; + port->num_uafu_irqs = feature->ctx_num; + } + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_uint_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT UINT UInit.\n"); +} + +static int port_uint_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_uafu_irq_set *uafu_irq_set = irq_set; + struct ifpga_port_hw *port = feature->parent; + int ret; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_UAFU_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, uafu_irq_set->start, + uafu_irq_set->count, uafu_irq_set->evtfds); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_uint_ops = { + .init = port_uint_init, + .uinit = port_uint_uinit, + .set_irq = port_uint_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c new file mode 100644 index 0000000..3be0f5e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static int port_err_get_revision(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_header header; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + header.csr = readq(&port_err->header); + *val = header.revision; + + return 0; +} + +static int port_err_get_errors(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + *val = error.csr; + + return 0; +} + +static int port_err_get_first_error(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_first_err_key first_error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + first_error.csr = readq(&port_err->port_first_error); + *val = first_error.csr; + + return 0; +} + +static int port_err_get_first_malformed_req_lsb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req0 malreq0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq0.header_lsb = readq(&port_err->malreq0); + *val = malreq0.header_lsb; + + return 0; +} + +static int port_err_get_first_malformed_req_msb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req1 malreq1; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq1.header_msb = readq(&port_err->malreq1); + *val = malreq1.header_msb; + + return 0; +} + +static int port_err_set_clear(struct ifpga_port_hw *port, u64 val) +{ + int ret; + + spinlock_lock(&port->lock); + ret = port_err_clear(port, val); + spinlock_unlock(&port->lock); + + return ret; +} + +static int port_error_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port error Init.\n"); + + spinlock_lock(&port->lock); + port_err_mask(port, false); + if (feature->ctx_num) + port->capability |= FPGA_PORT_CAP_ERR_IRQ; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int port_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_ERR_PROP_REVISION: + return port_err_get_revision(port, &prop->data); + case PORT_ERR_PROP_ERRORS: + return port_err_get_errors(port, &prop->data); + case PORT_ERR_PROP_FIRST_ERROR: + return port_err_get_first_error(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB: + return port_err_get_first_malformed_req_lsb(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB: + return port_err_get_first_malformed_req_msb(port, &prop->data); + } + + return -ENOENT; +} + +static int port_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + if (prop->prop_id == PORT_ERR_PROP_CLEAR) + return port_err_set_clear(port, prop->data); + + return -ENOENT; +} + +static int port_error_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_port_err_irq_set *err_irq_set = irq_set; + struct ifpga_port_hw *port; + int ret; + + port = feature->parent; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_ERR_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_error_ops = { + .init = port_error_init, + .uinit = port_error_uinit, + .get_prop = port_error_get_prop, + .set_prop = port_error_set_prop, + .set_irq = port_error_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.c b/drivers/raw/ifpga_rawdev/base/opae_debug.c new file mode 100644 index 0000000..024d7d2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.c @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#define OPAE_HW_DEBUG + +#include "opae_hw_api.h" +#include "opae_debug.h" + +void opae_manager_dump(struct opae_manager *mgr) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Manger %s\n", mgr->name); + opae_log("OPAE Manger OPs = %p\n", mgr->ops); + opae_log("OPAE Manager Private Data = %p\n", mgr->data); + opae_log("OPAE Adapter(parent) = %p\n", mgr->adapter); + opae_log("==========================\n"); +} + +void opae_bridge_dump(struct opae_bridge *br) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Bridge %s\n", br->name); + opae_log("OPAE Bridge ID = %d\n", br->id); + opae_log("OPAE Bridge OPs = %p\n", br->ops); + opae_log("OPAE Bridge Private Data = %p\n", br->data); + opae_log("OPAE Accelerator(under this bridge) = %p\n", br->acc); + opae_log("==========================\n"); +} + +void opae_accelerator_dump(struct opae_accelerator *acc) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Accelerator %s\n", acc->name); + opae_log("OPAE Accelerator Index = %d\n", acc->index); + opae_log("OPAE Accelerator OPs = %p\n", acc->ops); + opae_log("OPAE Accelerator Private Data = %p\n", acc->data); + opae_log("OPAE Bridge (upstream) = %p\n", acc->br); + opae_log("OPAE Manager (upstream) = %p\n", acc->mgr); + opae_log("==========================\n"); + + if (acc->br) + opae_bridge_dump(acc->br); +} + +static void opae_adapter_data_dump(void *data) +{ + struct opae_adapter_data *d = data; + struct opae_adapter_data_pci *d_pci; + struct opae_reg_region *r; + int i; + + opae_log("=====%s=====\n", __func__); + + switch (d->type) { + case OPAE_FPGA_PCI: + d_pci = (struct opae_adapter_data_pci *)d; + + opae_log("OPAE Adapter Type = PCI\n"); + opae_log("PCI Device ID: 0x%04x\n", d_pci->device_id); + opae_log("PCI Vendor ID: 0x%04x\n", d_pci->vendor_id); + + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + r = &d_pci->region[i]; + opae_log("PCI Bar %d: phy(%llx) len(%llx) addr(%p)\n", + i, (unsigned long long)r->phys_addr, + (unsigned long long)r->len, r->addr); + } + break; + case OPAE_FPGA_NET: + break; + } + + opae_log("==========================\n"); +} + +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) { + if (adapter->mgr) + opae_manager_dump(adapter->mgr); + + opae_adapter_for_each_acc(adapter, acc) + opae_accelerator_dump(acc); + + if (adapter->data) + opae_adapter_data_dump(adapter->data); + } + + opae_log("==========================\n"); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.h b/drivers/raw/ifpga_rawdev/base/opae_debug.h new file mode 100644 index 0000000..a03dff9 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_DEBUG_H_ +#define _OPAE_DEBUG_H_ + +#ifdef OPAE_HW_DEBUG +#define opae_log(fmt, args...) printf(fmt, ## args) +#else +#define opae_log(fme, args...) do {} while (0) +#endif + +void opae_manager_dump(struct opae_manager *mgr); +void opae_bridge_dump(struct opae_bridge *br); +void opae_accelerator_dump(struct opae_accelerator *acc); +void opae_adapter_dump(struct opae_adapter *adapter, int verbose); + +#endif /* _OPAE_DEBUG_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c new file mode 100644 index 0000000..a533dfe --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -0,0 +1,381 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_hw_api.h" +#include "opae_debug.h" +#include "ifpga_api.h" + +/* OPAE Bridge Functions */ + +/** + * opae_bridge_alloc - alloc opae_bridge data structure + * @name: bridge name. + * @ops: ops of this bridge. + * @data: private data of this bridge. + * + * Return opae_bridge on success, otherwise NULL. + */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data) +{ + struct opae_bridge *br = opae_zmalloc(sizeof(*br)); + + if (!br) + return NULL; + + br->name = name; + br->ops = ops; + br->data = data; + + opae_log("%s %p\n", __func__, br); + + return br; +} + +/** + * opae_bridge_reset - reset opae_bridge + * @br: bridge to be reset. + * + * Return: 0 on success, otherwise error code. + */ +int opae_bridge_reset(struct opae_bridge *br) +{ + if (!br) + return -EINVAL; + + if (br->ops && br->ops->reset) + return br->ops->reset(br); + + opae_log("%s no ops\n", __func__); + + return -ENOENT; +} + +/* Accelerator Functions */ + +/** + * opae_accelerator_alloc - alloc opae_accelerator data structure + * @name: accelerator name. + * @ops: ops of this accelerator. + * @data: private data of this accelerator. + * + * Return: opae_accelerator on success, otherwise NULL. + */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data) +{ + struct opae_accelerator *acc = opae_zmalloc(sizeof(*acc)); + + if (!acc) + return NULL; + + acc->name = name; + acc->ops = ops; + acc->data = data; + + opae_log("%s %p\n", __func__, acc); + + return acc; +} + +/** + * opae_acc_reg_read - read accelerator's register from its reg region. + * @acc: accelerator to read. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: read operation width, e.g 4 byte = 32bit read. + * @data: data to store the value read from the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->read) + return acc->ops->read(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_reg_write - write to accelerator's register from its reg region. + * @acc: accelerator to write. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: write operation width, e.g 4 byte = 32bit write. + * @data: data stored the value to write to the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->write) + return acc->ops->write(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_get_info - get information of an accelerator. + * @acc: targeted accelerator + * @info: accelerator info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_info) + return acc->ops->get_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_get_region_info - get information of an accelerator register region. + * @acc: targeted accelerator + * @info: accelerator region info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_region_info) + return acc->ops->get_region_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_set_irq - set an accelerator's irq. + * @acc: targeted accelerator + * @start: start vector number + * @count: count of vectors to be set from the start vector + * @evtfds: event fds to be notified when corresponding irqs happens + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + if (!acc || !acc->data) + return -EINVAL; + + if (start + count <= start) + return -EINVAL; + + if (acc->ops && acc->ops->set_irq) + return acc->ops->set_irq(acc, start, count, evtfds); + + return -ENOENT; +} + +/** + * opae_acc_get_uuid - get accelerator's UUID. + * @acc: targeted accelerator + * @uuid: a pointer to UUID + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + if (!acc || !uuid) + return -EINVAL; + + if (acc->ops && acc->ops->get_uuid) + return acc->ops->get_uuid(acc, uuid); + + return -ENOENT; +} + +/* Manager Functions */ + +/** + * opae_manager_alloc - alloc opae_manager data structure + * @name: manager name. + * @ops: ops of this manager. + * @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) +{ + struct opae_manager *mgr = opae_zmalloc(sizeof(*mgr)); + + if (!mgr) + return NULL; + + mgr->name = name; + mgr->ops = ops; + mgr->data = data; + + opae_log("%s %p\n", __func__, mgr); + + return mgr; +} + +/** + * opae_manager_flash - flash a reconfiguration image via opae_manager + * @mgr: opae_manager for flash. + * @id: id of target region (accelerator). + * @buf: image data buffer. + * @size: buffer size. + * @status: status to store flash result. + * + * Return: 0 on success, otherwise error code. + */ +int opae_manager_flash(struct opae_manager *mgr, int id, void *buf, u32 size, + u64 *status) +{ + if (!mgr) + return -EINVAL; + + if (mgr && mgr->ops && mgr->ops->flash) + return mgr->ops->flash(mgr, id, buf, size, status); + + return -ENOENT; +} + +/* Adapter Functions */ + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @type: opae_adapter_type. + * + * Return: opae_adapter_data on success, otherwise NULL. + */ +void *opae_adapter_data_alloc(enum opae_adapter_type type) +{ + struct opae_adapter_data *data; + int size; + + switch (type) { + case OPAE_FPGA_PCI: + size = sizeof(struct opae_adapter_data_pci); + break; + case OPAE_FPGA_NET: + size = sizeof(struct opae_adapter_data_net); + break; + default: + size = sizeof(struct opae_adapter_data); + break; + } + + data = opae_zmalloc(size); + if (!data) + return NULL; + + data->type = type; + + return data; +} + +static struct opae_adapter_ops *match_ops(struct opae_adapter *adapter) +{ + struct opae_adapter_data *data; + + if (!adapter || !adapter->data) + return NULL; + + data = adapter->data; + + if (data->type == OPAE_FPGA_PCI) + return &ifpga_adapter_ops; + + return NULL; +} + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @name: adapter name. + * @data: private data of this adapter. + * + * Return: opae_adapter on success, otherwise NULL. + */ +struct opae_adapter *opae_adapter_alloc(const char *name, void *data) +{ + struct opae_adapter *adapter = opae_zmalloc(sizeof(*adapter)); + + if (!adapter) + return NULL; + + TAILQ_INIT(&adapter->acc_list); + adapter->data = data; + adapter->name = name; + adapter->ops = match_ops(adapter); + + return adapter; +} + +/** + * opae_adapter_enumerate - enumerate this adapter + * @adapter: adapter to enumerate. + * + * Return: 0 on success, otherwise error code. + */ +int opae_adapter_enumerate(struct opae_adapter *adapter) +{ + int ret = -ENOENT; + + if (!adapter) + return -EINVAL; + + if (adapter->ops && adapter->ops->enumerate) + ret = adapter->ops->enumerate(adapter); + + if (!ret) + opae_adapter_dump(adapter, 1); + + return ret; +} + +/** + * opae_adapter_destroy - destroy this adapter + * @adapter: adapter to destroy. + * + * destroy things allocated during adapter enumeration. + */ +void opae_adapter_destroy(struct opae_adapter *adapter) +{ + if (adapter && adapter->ops && adapter->ops->destroy) + adapter->ops->destroy(adapter); +} + +/** + * opae_adapter_get_acc - find and return accelerator with matched id + * @adapter: adapter to find the accelerator. + * @acc_id: id (index) of the accelerator. + * + * destroy things allocated during adapter enumeration. + */ +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id) +{ + struct opae_accelerator *acc = NULL; + + if (!adapter) + return NULL; + + opae_adapter_for_each_acc(adapter, acc) + if (acc->index == acc_id) + return acc; + + return NULL; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h new file mode 100644 index 0000000..4bbc9df --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_HW_API_H_ +#define _OPAE_HW_API_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> + +#include "opae_osdep.h" + +#ifndef PCI_MAX_RESOURCE +#define PCI_MAX_RESOURCE 6 +#endif + +struct opae_adapter; + +enum opae_adapter_type { + OPAE_FPGA_PCI, + OPAE_FPGA_NET, +}; + +/* OPAE Manager Data Structure */ +struct opae_manager_ops; + +/* + * opae_manager has pointer to its parent adapter, as it could be able to manage + * all components on this FPGA device (adapter). If not the case, don't set this + * adapter, which limit opae_manager ops to manager itself. + */ +struct opae_manager { + const char *name; + struct opae_adapter *adapter; + struct opae_manager_ops *ops; + void *data; +}; + +/* FIXME: add more management ops, e.g power/thermal and etc */ +struct opae_manager_ops { + int (*flash)(struct opae_manager *mgr, int id, void *buffer, + u32 size, u64 *status); +}; + +/* OPAE Manager APIs */ +struct opae_manager * +opae_manager_alloc(const char *name, struct opae_manager_ops *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); + +/* OPAE Bridge Data Structure */ +struct opae_bridge_ops; + +/* + * opae_bridge only has pointer to its downstream accelerator. + */ +struct opae_bridge { + const char *name; + int id; + struct opae_accelerator *acc; + struct opae_bridge_ops *ops; + void *data; +}; + +struct opae_bridge_ops { + int (*reset)(struct opae_bridge *br); +}; + +/* OPAE Bridge APIs */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data); +int opae_bridge_reset(struct opae_bridge *br); +#define opae_bridge_free(br) opae_free(br) + +/* OPAE Acceleraotr Data Structure */ +struct opae_accelerator_ops; + +/* + * opae_accelerator has pointer to its upstream bridge(port). + * In some cases, if we allow same user to do PR on its own accelerator, then + * set the manager pointer during the enumeration. But in other cases, the PR + * functions only could be done via manager in another module / thread / service + * / application for better protection. + */ +struct opae_accelerator { + TAILQ_ENTRY(opae_accelerator) node; + const char *name; + int index; + struct opae_bridge *br; + struct opae_manager *mgr; + struct opae_accelerator_ops *ops; + void *data; +}; + +struct opae_acc_info { + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct opae_acc_region_info { + u32 flags; +#define ACC_REGION_READ (1 << 0) +#define ACC_REGION_WRITE (1 << 1) +#define ACC_REGION_MMIO (1 << 2) + u32 index; + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_accelerator_ops { + int (*read)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*write)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*get_info)(struct opae_accelerator *acc, + struct opae_acc_info *info); + int (*get_region_info)(struct opae_accelerator *acc, + struct opae_acc_region_info *info); + int (*set_irq)(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); + int (*get_uuid)(struct opae_accelerator *acc, + struct uuid *uuid); +}; + +/* OPAE accelerator APIs */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data); +#define opae_accelerator_free(acc) opae_free(acc) +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info); +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info); +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid); + +static inline struct opae_bridge * +opae_acc_get_br(struct opae_accelerator *acc) +{ + return acc ? acc->br : NULL; +} + +static inline struct opae_manager * +opae_acc_get_mgr(struct opae_accelerator *acc) +{ + return acc ? acc->mgr : NULL; +} + +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + +#define opae_acc_reg_read64(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 8, data) +#define opae_acc_reg_write64(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 8, data) +#define opae_acc_reg_read32(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 4, data) +#define opae_acc_reg_write32(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 4, data) +#define opae_acc_reg_read16(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 2, data) +#define opae_acc_reg_write16(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 2, data) +#define opae_acc_reg_read8(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 1, data) +#define opae_acc_reg_write8(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 1, data) + +/*for data stream read/write*/ +int opae_acc_data_read(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); +int opae_acc_data_write(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); + +/* OPAE Adapter Data Structure */ +struct opae_adapter_data { + enum opae_adapter_type type; +}; + +struct opae_reg_region { + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_adapter_data_pci { + enum opae_adapter_type type; + u16 device_id; + u16 vendor_id; + struct opae_reg_region region[PCI_MAX_RESOURCE]; + int vfio_dev_fd; /* VFIO device file descriptor */ +}; + +/* FIXME: OPAE_FPGA_NET type */ +struct opae_adapter_data_net { + enum opae_adapter_type type; +}; + +struct opae_adapter_ops { + int (*enumerate)(struct opae_adapter *adapter); + void (*destroy)(struct opae_adapter *adapter); +}; + +TAILQ_HEAD(opae_accelerator_list, opae_accelerator); + +#define opae_adapter_for_each_acc(adatper, acc) \ + TAILQ_FOREACH(acc, &adapter->acc_list, node) + +struct opae_adapter { + const char *name; + struct opae_manager *mgr; + struct opae_accelerator_list acc_list; + struct opae_adapter_ops *ops; + void *data; +}; + +/* OPAE Adapter APIs */ +void *opae_adapter_data_alloc(enum opae_adapter_type type); +#define opae_adapter_data_free(data) opae_free(data) + +struct opae_adapter *opae_adapter_alloc(const char *name, void *data); +#define opae_adapter_free(adapter) opae_free(adapter) + +int opae_adapter_enumerate(struct opae_adapter *adapter); +void opae_adapter_destroy(struct opae_adapter *adapter); +static inline struct opae_manager * +opae_adapter_get_mgr(struct opae_adapter *adapter) +{ + return adapter ? adapter->mgr : NULL; +} + +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id); + +static inline void opae_adapter_add_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_INSERT_TAIL(&adapter->acc_list, acc, node); +} + +static inline void opae_adapter_remove_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_REMOVE(&adapter->acc_list, acc, node); +} +#endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c new file mode 100644 index 0000000..a40c8da --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_ifpga_hw_api.h" +#include "ifpga_api.h" + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data || !fme_info) + return -EINVAL; + + fme = mgr->data; + + spinlock_lock(&fme->lock); + fme_info->capability = fme->capability; + spinlock_unlock(&fme->lock); + + return 0; +} + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_irq(fme->parent, FEATURE_FIU_ID_FME, 0, + IFPGA_FME_FEATURE_ID_GLOBAL_ERR, err_irq_set); +} + +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_get_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !port_info) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + port_info->capability = port->capability; + port_info->num_uafu_irqs = port->num_uafu_irqs; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !info) + return -EINVAL; + + /* Only support STP region now */ + if (info->index != PORT_REGION_INDEX_STP) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + info->addr = (u64)port->stp_addr; + info->size = port->stp_size; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_ERROR, err_irq_set); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h new file mode 100644 index 0000000..65086cf --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_IFPGA_HW_API_H_ +#define _OPAE_IFPGA_HW_API_H_ + +#include "opae_hw_api.h" + +/** + * struct feature_prop - data structure for feature property + * @feature_id: id of this feature. + * @prop_id: id of this property under this feature. + * @data: property value to set/get. + */ +struct feature_prop { + u64 feature_id; + u64 prop_id; + u64 data; +}; + +#define IFPGA_FIU_ID_FME 0x0 +#define IFPGA_FIU_ID_PORT 0x1 + +#define IFPGA_FME_FEATURE_ID_HEADER 0x0 +#define IFPGA_FME_FEATURE_ID_THERMAL_MGMT 0x1 +#define IFPGA_FME_FEATURE_ID_POWER_MGMT 0x2 +#define IFPGA_FME_FEATURE_ID_GLOBAL_IPERF 0x3 +#define IFPGA_FME_FEATURE_ID_GLOBAL_ERR 0x4 +#define IFPGA_FME_FEATURE_ID_PR_MGMT 0x5 +#define IFPGA_FME_FEATURE_ID_HSSI 0x6 +#define IFPGA_FME_FEATURE_ID_GLOBAL_DPERF 0x7 + +#define IFPGA_PORT_FEATURE_ID_HEADER 0x0 +#define IFPGA_PORT_FEATURE_ID_AFU 0xff +#define IFPGA_PORT_FEATURE_ID_ERROR 0x10 +#define IFPGA_PORT_FEATURE_ID_UMSG 0x11 +#define IFPGA_PORT_FEATURE_ID_UINT 0x12 +#define IFPGA_PORT_FEATURE_ID_STP 0x13 + +/* + * PROP format (TOP + SUB + ID) + * + * (~0x0) means this field is unused. + */ +#define PROP_TOP GENMASK(31, 24) +#define PROP_TOP_UNUSED 0xff +#define PROP_SUB GENMASK(23, 16) +#define PROP_SUB_UNUSED 0xff +#define PROP_ID GENMASK(15, 0) + +#define PROP(_top, _sub, _id) \ + (SET_FIELD(PROP_TOP, _top) | SET_FIELD(PROP_SUB, _sub) |\ + SET_FIELD(PROP_ID, _id)) + +/* FME head feature's properties*/ +#define FME_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define FME_HDR_PROP_PORTS_NUM 0x2 /* RDONLY */ +#define FME_HDR_PROP_CACHE_SIZE 0x3 /* RDONLY */ +#define FME_HDR_PROP_VERSION 0x4 /* RDONLY */ +#define FME_HDR_PROP_SOCKET_ID 0x5 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_ID 0x6 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_METADATA 0x7 /* RDONLY */ + +/* FME error reporting feature's properties */ +/* FME error reporting properties format */ +#define ERR_PROP(_top, _id) PROP(_top, 0xff, _id) +#define ERR_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define ERR_PROP_TOP_FME_ERR 0x1 +#define ERR_PROP_ROOT(_id) ERR_PROP(0xff, _id) +#define ERR_PROP_FME_ERR(_id) ERR_PROP(ERR_PROP_TOP_FME_ERR, _id) + +#define FME_ERR_PROP_ERRORS ERR_PROP_FME_ERR(0x1) +#define FME_ERR_PROP_FIRST_ERROR ERR_PROP_FME_ERR(0x2) +#define FME_ERR_PROP_NEXT_ERROR ERR_PROP_FME_ERR(0x3) +#define FME_ERR_PROP_CLEAR ERR_PROP_FME_ERR(0x4) /* WO */ +#define FME_ERR_PROP_REVISION ERR_PROP_ROOT(0x5) +#define FME_ERR_PROP_PCIE0_ERRORS ERR_PROP_ROOT(0x6) /* RW */ +#define FME_ERR_PROP_PCIE1_ERRORS ERR_PROP_ROOT(0x7) /* RW */ +#define FME_ERR_PROP_NONFATAL_ERRORS ERR_PROP_ROOT(0x8) +#define FME_ERR_PROP_CATFATAL_ERRORS ERR_PROP_ROOT(0x9) +#define FME_ERR_PROP_INJECT_ERRORS ERR_PROP_ROOT(0xa) /* RW */ + +/* FME thermal feature's properties */ +#define FME_THERMAL_PROP_THRESHOLD1 0x1 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD2 0x2 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD_TRIP 0x3 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_REACHED 0x4 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD2_REACHED 0x5 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_POLICY 0x6 /* RW */ +#define FME_THERMAL_PROP_TEMPERATURE 0x7 /* RDONLY */ +#define FME_THERMAL_PROP_REVISION 0x8 /* RDONLY */ + +/* FME power feature's properties */ +#define FME_PWR_PROP_CONSUMED 0x1 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD1 0x2 /* RW */ +#define FME_PWR_PROP_THRESHOLD2 0x3 /* RW */ +#define FME_PWR_PROP_THRESHOLD1_STATUS 0x4 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD2_STATUS 0x5 /* RDONLY */ +#define FME_PWR_PROP_RTL 0x6 /* RDONLY */ +#define FME_PWR_PROP_XEON_LIMIT 0x7 /* RDONLY */ +#define FME_PWR_PROP_FPGA_LIMIT 0x8 /* RDONLY */ +#define FME_PWR_PROP_REVISION 0x9 /* RDONLY */ + +/* FME iperf/dperf PROP format */ +#define PERF_PROP_TOP_CACHE 0x1 +#define PERF_PROP_TOP_VTD 0x2 +#define PERF_PROP_TOP_FAB 0x3 +#define PERF_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define PERF_PROP_SUB_UNUSED PROP_SUB_UNUSED + +#define PERF_PROP_ROOT(_id) PROP(0xff, 0xff, _id) +#define PERF_PROP_CACHE(_id) PROP(PERF_PROP_TOP_CACHE, 0xff, _id) +#define PERF_PROP_VTD(_sub, _id) PROP(PERF_PROP_TOP_VTD, _sub, _id) +#define PERF_PROP_VTD_ROOT(_id) PROP(PERF_PROP_TOP_VTD, 0xff, _id) +#define PERF_PROP_FAB(_sub, _id) PROP(PERF_PROP_TOP_FAB, _sub, _id) +#define PERF_PROP_FAB_ROOT(_id) PROP(PERF_PROP_TOP_FAB, 0xff, _id) + +/* FME iperf feature's properties */ +#define FME_IPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_IPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* iperf CACHE properties */ +#define FME_IPERF_PROP_CACHE_FREEZE PERF_PROP_CACHE(0x1) /* RW */ +#define FME_IPERF_PROP_CACHE_READ_HIT PERF_PROP_CACHE(0x2) +#define FME_IPERF_PROP_CACHE_READ_MISS PERF_PROP_CACHE(0x3) +#define FME_IPERF_PROP_CACHE_WRITE_HIT PERF_PROP_CACHE(0x4) +#define FME_IPERF_PROP_CACHE_WRITE_MISS PERF_PROP_CACHE(0x5) +#define FME_IPERF_PROP_CACHE_HOLD_REQUEST PERF_PROP_CACHE(0x6) +#define FME_IPERF_PROP_CACHE_TX_REQ_STALL PERF_PROP_CACHE(0x7) +#define FME_IPERF_PROP_CACHE_RX_REQ_STALL PERF_PROP_CACHE(0x8) +#define FME_IPERF_PROP_CACHE_RX_EVICTION PERF_PROP_CACHE(0x9) +#define FME_IPERF_PROP_CACHE_DATA_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xa) +#define FME_IPERF_PROP_CACHE_TAG_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xb) +/* iperf VTD properties */ +#define FME_IPERF_PROP_VTD_FREEZE PERF_PROP_VTD_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_HIT PERF_PROP_VTD_ROOT(0x2) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_HIT PERF_PROP_VTD_ROOT(0x3) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_HIT PERF_PROP_VTD_ROOT(0x4) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_HIT PERF_PROP_VTD_ROOT(0x5) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_HIT PERF_PROP_VTD_ROOT(0x6) +#define FME_IPERF_PROP_VTD_SIP_RCC_HIT PERF_PROP_VTD_ROOT(0x7) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_MISS PERF_PROP_VTD_ROOT(0x8) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_MISS PERF_PROP_VTD_ROOT(0x9) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_MISS PERF_PROP_VTD_ROOT(0xa) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_MISS PERF_PROP_VTD_ROOT(0xb) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_MISS PERF_PROP_VTD_ROOT(0xc) +#define FME_IPERF_PROP_VTD_SIP_RCC_MISS PERF_PROP_VTD_ROOT(0xd) +#define FME_IPERF_PROP_VTD_PORT_READ_TRANSACTION(n) PERF_PROP_VTD(n, 0xe) +#define FME_IPERF_PROP_VTD_PORT_WRITE_TRANSACTION(n) PERF_PROP_VTD(n, 0xf) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_READ_HIT(n) PERF_PROP_VTD(n, 0x10) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_WRITE_HIT(n) PERF_PROP_VTD(n, 0x11) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_4K_FILL(n) PERF_PROP_VTD(n, 0x12) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_2M_FILL(n) PERF_PROP_VTD(n, 0x13) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_1G_FILL(n) PERF_PROP_VTD(n, 0x14) +/* iperf FAB properties */ +#define FME_IPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_IPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_IPERF_PROP_FAB_PCIE1_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_IPERF_PROP_FAB_PCIE1_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_IPERF_PROP_FAB_UPI_READ PERF_PROP_FAB_ROOT(0x6) +#define FME_IPERF_PROP_FAB_PORT_UPI_READ(n) PERF_PROP_FAB(n, 0x6) +#define FME_IPERF_PROP_FAB_UPI_WRITE PERF_PROP_FAB_ROOT(0x7) +#define FME_IPERF_PROP_FAB_PORT_UPI_WRITE(n) PERF_PROP_FAB(n, 0x7) +#define FME_IPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x8) +#define FME_IPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x8) +#define FME_IPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x9) +#define FME_IPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x9) +#define FME_IPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0xa) /* RW */ +#define FME_IPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0xa) /* RW */ + +/* FME dperf properties */ +#define FME_DPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_DPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* dperf FAB properties */ +#define FME_DPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_DPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_DPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_DPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_DPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_DPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_DPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_DPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0x6) /* RW */ +#define FME_DPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0x6) /* RW */ + +/*PORT hdr feature's properties*/ +#define PORT_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_HDR_PROP_PORTIDX 0x2 /* RDONLY */ +#define PORT_HDR_PROP_LATENCY_TOLERANCE 0x3 /* RDONLY */ +#define PORT_HDR_PROP_AP1_EVENT 0x4 /* RW */ +#define PORT_HDR_PROP_AP2_EVENT 0x5 /* RW */ +#define PORT_HDR_PROP_POWER_STATE 0x6 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_FREQCMD 0x7 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQCNTRCMD 0x8 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQSTS 0x9 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_CNTRSTS 0xa /* RDONLY */ + +/*PORT error feature's properties*/ +#define PORT_ERR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_ERR_PROP_ERRORS 0x2 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_ERROR 0x3 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB 0x4 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB 0x5 /* RDONLY */ +#define PORT_ERR_PROP_CLEAR 0x6 /* WRONLY */ + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop); +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop); + +/* + * Retrieve information about the fpga fme. + * Driver fills the info in provided struct fpga_fme_info. + */ +struct fpga_fme_info { + u32 capability; /* The capability of FME device */ +#define FPGA_FME_CAP_ERR_IRQ (1 << 0) /* Support fme error interrupt */ +}; + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info); + +/* Set eventfd information for ifpga FME error interrupt */ +struct fpga_fme_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set); + +/* + * Retrieve information about the fpga port. + * Driver fills the info in provided struct fpga_port_info. + */ +struct fpga_port_info { + u32 capability; /* The capability of port device */ +#define FPGA_PORT_CAP_ERR_IRQ (1 << 0) /* Support port error interrupt */ +#define FPGA_PORT_CAP_UAFU_IRQ (1 << 1) /* Support uafu error interrupt */ + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ +}; + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info); +/* + * Retrieve region information about the fpga port. + * Driver needs to fill the index of struct fpga_port_region_info. + */ +struct fpga_port_region_info { + u32 index; +#define PORT_REGION_INDEX_STP (1 << 1) /* Signal Tap Region */ + u64 size; /* Region Size */ + u64 addr; /* Base address of the region */ +}; + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info); + +/* Set eventfd information for ifpga port error interrupt */ +struct fpga_port_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set); + +#endif /* _OPAE_IFPGA_HW_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h new file mode 100644 index 0000000..e9da710 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_OSDEP_H +#define _OPAE_OSDEP_H + +#include <string.h> +#include <stdbool.h> + +#ifdef RTE_LIBRTE_EAL +#include "osdep_rte/osdep_generic.h" +#else +#include "osdep_raw/osdep_generic.h" +#endif + +#include <asm/types.h> + +#define __iomem + +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef uint64_t dma_addr_t; + +struct uuid { + u8 b[16]; +}; + +#ifndef LINUX_MACROS +#ifndef BITS_PER_LONG +#define BITS_PER_LONG (__SIZEOF_LONG__ * 8) +#endif +#ifndef BIT +#define BIT(a) (1UL << (a)) +#endif /* BIT */ +#ifndef BIT_ULL +#define BIT_ULL(a) (1ULL << (a)) +#endif /* BIT_ULL */ +#ifndef GENMASK +#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#endif /* GENMASK */ +#ifndef GENMASK_ULL +#define GENMASK_ULL(h, l) (((U64_C(1) << ((h) - (l) + 1)) - 1) << (l)) +#endif /* GENMASK_ULL */ +#endif /* LINUX_MACROS */ + +#define SET_FIELD(m, v) (((v) << (__builtin_ffsll(m) - 1)) & (m)) +#define GET_FIELD(m, v) (((v) & (m)) >> (__builtin_ffsll(m) - 1)) + +#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) +#define pr_info(y, args...) dev_info(0, y, ##args) + +#ifndef WARN_ON +#define WARN_ON(x) do { \ + int ret = !!(x); \ + if (unlikely(ret)) \ + pr_warn("WARN_ON: \"" #x "\" at %s:%d\n", __func__, __LINE__); \ +} while (0) +#endif + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define udelay(x) opae_udelay(x) +#define msleep(x) opae_udelay(1000 * (x)) +#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000)) + +#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 new file mode 100644 index 0000000..895a1d8 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OSDEP_RAW_GENERIC_H +#define _OSDEP_RAW_GENERIC_H + +#define compiler_barrier() (asm volatile ("" : : : "memory")) + +#define io_wmb() compiler_barrier() +#define io_rmb() compiler_barrier() + +static inline uint8_t opae_readb(const volatile void *addr) +{ + uint8_t val; + + val = *(const volatile uint8_t *)addr; + io_rmb(); + return val; +} + +static inline uint16_t opae_readw(const volatile void *addr) +{ + uint16_t val; + + val = *(const volatile uint16_t *)addr; + io_rmb(); + return val; +} + +static inline uint32_t opae_readl(const volatile void *addr) +{ + uint32_t val; + + val = *(const volatile uint32_t *)addr; + io_rmb(); + return val; +} + +static inline uint64_t opae_readq(const volatile void *addr) +{ + uint64_t val; + + val = *(const volatile uint64_t *)addr; + io_rmb(); + return val; +} + +static inline void opae_writeb(uint8_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint8_t *)addr = value; +} + +static inline void opae_writew(uint16_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint16_t *)addr = value; +} + +static inline void opae_writel(uint32_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint32_t *)addr = value; +} + +static inline void opae_writeq(uint64_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint64_t *)addr = value; +} + +#define opae_free(addr) free(addr) + +#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 new file mode 100644 index 0000000..76902e2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OSDEP_RTE_GENERIC_H +#define _OSDEP_RTE_GENERIC_H + +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_spinlock.h> +#include <rte_log.h> +#include <rte_io.h> +#include <rte_malloc.h> + +#define dev_printf(level, fmt, args...) \ + RTE_LOG(level, PMD, "osdep_rte: " fmt, ## args) + +#define osdep_panic(...) rte_panic(...) + +#define opae_udelay(x) rte_delay_us(x) + +#define opae_readb(addr) rte_read8(addr) +#define opae_readw(addr) rte_read16(addr) +#define opae_readl(addr) rte_read32(addr) +#define opae_readq(addr) rte_read64(addr) +#define opae_writeb(value, addr) rte_write8(value, addr) +#define opae_writew(value, addr) rte_write16(value, addr) +#define opae_writel(value, addr) rte_write32(value, addr) +#define opae_writeq(value, addr) rte_write64(value, addr) + +#define opae_malloc(size) rte_malloc(NULL, size, 0) +#define opae_zmalloc(size) rte_zmalloc(NULL, size, 0) +#define opae_free(addr) rte_free(addr) + +#define ARRAY_SIZE(arr) RTE_DIM(arr) + +#define min(a, b) RTE_MIN(a, b) +#define max(a, b) RTE_MAX(a, b) + +#define spinlock_t rte_spinlock_t +#define spinlock_init(x) rte_spinlock_init(x) +#define spinlock_lock(x) rte_spinlock_lock(x) +#define spinlock_unlock(x) rte_spinlock_unlock(x) + +#endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v6 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 0/5] " Xu, Rosen 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 1/5] iFPGA: Add Intel FPGA BUS Library Xu, Rosen 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 2/5] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen @ 2018-04-26 9:43 ` Xu, Rosen 2018-05-04 9:14 ` Shreyansh Jain 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 4/5] iFPGA: add meson build Xu, Rosen 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 5/5] iFPGA: add document for iFPGA driver Xu, Rosen 4 siblings, 1 reply; 149+ messages in thread From: Xu, Rosen @ 2018-04-26 9:43 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet, Rosen Xu, Yanglong Wu From: Rosen Xu <rosen.xu@intel.com> Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev library. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> Signed-off-by: Figo zhang <tianfei.zhang@intel.com> --- config/common_base | 1 + drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 ++ drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 597 +++++++++++++++++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + mk/rte.app.mk | 1 + 7 files changed, 677 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map diff --git a/config/common_base b/config/common_base index b59f1de..13fce00 100644 --- a/config/common_base +++ b/config/common_base @@ -151,6 +151,7 @@ CONFIG_RTE_LIBRTE_VDEV_BUS=y # Compile the Intel FPGA bus # CONFIG_RTE_LIBRTE_IFPGA_BUS=y +CONFIG_RTE_LIBRTE_IFPGA_RAWDEV=y # # Compile ARK PMD diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index da7c8b4..6fc8f2f 100644 --- a/drivers/raw/Makefile +++ b/drivers/raw/Makefile @@ -5,5 +5,6 @@ include $(RTE_SDK)/mk/rte.vars.mk # DIRS-$(<configuration>) += <directory> DIRS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += skeleton_rawdev +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/raw/ifpga_rawdev/Makefile b/drivers/raw/ifpga_rawdev/Makefile new file mode 100644 index 0000000..66e2e34 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/Makefile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_ifpga_rawdev.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_bus_vdev +LDLIBS += -lrte_kvargs +LDLIBS += -lrte_bus_pci +LDLIBS += -lrte_bus_ifpga + +EXPORT_MAP := rte_ifpga_rawdev_version.map + +LIBABIVER := 1 + +VPATH += $(SRCDIR)/base + +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c new file mode 100644 index 0000000..71a41b9 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c @@ -0,0 +1,597 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <rte_log.h> +#include <rte_bus.h> +#include <rte_eal_memconfig.h> +#include <rte_malloc.h> +#include <rte_devargs.h> +#include <rte_memcpy.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include <rte_errno.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> +#include <rte_bus_vdev.h> + +#include "base/opae_hw_api.h" +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_common.h" +#include "ifpga_logs.h" +#include "ifpga_rawdev.h" + +int ifpga_rawdev_logtype; + +#define PCI_VENDOR_ID_INTEL 0x8086 +/* PCI Device ID */ +#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 +/* 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 RTE_MAX_RAW_DEVICE 10 + +static const struct rte_pci_id pci_ifpga_map[] = { + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_6_X) }, + { 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) }, + { .vendor_id = 0, /* sentinel */ }, +}; + +static int ifpga_fill_afu_dev(struct opae_accelerator *acc, + struct rte_afu_device *afu_dev) +{ + struct rte_mem_resource *res = afu_dev->mem_resource; + struct opae_acc_region_info region_info; + struct opae_acc_info info; + unsigned long i; + int ret; + + ret = opae_acc_get_info(acc, &info); + if (ret) + return ret; + + if (info.num_regions > PCI_MAX_RESOURCE) + return -EFAULT; + + afu_dev->num_region = info.num_regions; + + for (i = 0; i < info.num_regions; i++) { + region_info.index = i; + ret = opae_acc_get_region_info(acc, ®ion_info); + if (ret) + return ret; + + if ((region_info.flags & ACC_REGION_MMIO) && + (region_info.flags & ACC_REGION_READ) && + (region_info.flags & ACC_REGION_WRITE)) { + res[i].phys_addr = region_info.phys_addr; + res[i].len = region_info.len; + res[i].addr = region_info.addr; + } else + return -EFAULT; + } + + return 0; +} + +static void ifpga_rawdev_info_get(struct rte_rawdev *dev, + rte_rawdev_obj_t dev_info) +{ + struct opae_adapter *adapter; + struct opae_accelerator *acc; + struct rte_afu_device *afu_dev; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + if (!dev_info) { + IFPGA_RAWDEV_PMD_ERR("Invalid request"); + return; + } + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return; + + afu_dev = dev_info; + afu_dev->rawdev = dev; + + /* find opae_accelerator and fill info into afu_device */ + opae_adapter_for_each_acc(adapter, acc) { + if (acc->index != afu_dev->id.port) + continue; + + if (ifpga_fill_afu_dev(acc, afu_dev)) { + IFPGA_RAWDEV_PMD_ERR("cannot get info\n"); + return; + } + } +} + +static int ifpga_rawdev_start(struct rte_rawdev *dev) +{ + int ret = 0; + struct opae_adapter *adapter; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + return ret; +} + +static void ifpga_rawdev_stop(struct rte_rawdev *dev) +{ + dev->started = 0; +} + +static int ifpga_rawdev_close(struct rte_rawdev *dev) +{ + if (!dev) + return 1; + else + return 0; +} + +static int ifpga_rawdev_reset(struct rte_rawdev *dev) +{ + if (!dev) + return 1; + else + return 0; +} + +static int +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, + u64 *status) +{ + + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_accelerator *acc; + struct opae_bridge *br; + int ret; + + adapter = ifpga_rawdev_get_priv(raw_dev); + if (!adapter) + return -ENODEV; + + mgr = opae_adapter_get_mgr(adapter); + if (!mgr) + return -ENODEV; + + acc = opae_adapter_get_acc(adapter, port_id); + if (!acc) + return -ENODEV; + + br = opae_acc_get_br(acc); + if (!br) + return -ENODEV; + + ret = opae_manager_flash(mgr, port_id, buffer, size, status); + if (ret) { + printf("%s pr error %d\n", __func__, ret); + return ret; + } + + usleep(100); + ret = opae_bridge_reset(br); + if (ret) { + printf("%s reset port:%d error %d\n", __func__, port_id, ret); + return ret; + } + + return ret; +} + +static int rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, + const char *file_name) +{ + struct stat file_stat; + int file_fd; + int ret = 0; + u32 buffer_size; + void *buffer; + u64 pr_error; + + if (!file_name) + return -EINVAL; + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + printf("%s: open file error: %s\n", __func__, file_name); + printf("Message : %s\n", strerror(errno)); + return -EINVAL; + } + ret = stat(file_name, &file_stat); + if (ret) { + printf("stat on bitstream file failed: %s\n", file_name); + return -EINVAL; + } + buffer_size = file_stat.st_size; + printf("bitstream file size: %u\n", buffer_size); + buffer = rte_malloc(NULL, buffer_size, 0); + if (!buffer) { + ret = -ENOMEM; + goto close_fd; + } + + /*read the raw data*/ + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { + ret = -EINVAL; + goto free_buffer; + } + + /*do PR now*/ + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); + printf("downloading to device port %d....%s.\n", port_id, + ret ? "failed" : "success"); + if (ret) { + ret = -EINVAL; + //raw_dev->ops->show_pr_error(pr_error); + goto free_buffer; + } + +free_buffer: + if (buffer) + rte_free(buffer); +close_fd: + close(file_fd); + file_fd = 0; + return ret; +} + +static int ifpga_rawdev_pr(struct rte_rawdev *dev, + rte_rawdev_obj_t pr_conf) +{ + struct opae_adapter *adapter; + struct rte_afu_pr_conf *afu_pr_conf; + int ret; + struct uuid uuid; + struct opae_accelerator *acc; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + if (!pr_conf) + return -EINVAL; + + afu_pr_conf = pr_conf; + + if (afu_pr_conf->pr_enable) { + ret = rte_fpga_do_pr(dev, + afu_pr_conf->afu_id.port, + afu_pr_conf->bs_path); + if (ret) { + printf("do pr error %d\n", ret); + return ret; + } + } + + acc = opae_adapter_get_acc(adapter, afu_pr_conf->afu_id.port); + if (!acc) + return -ENODEV; + + ret = opae_acc_get_uuid(acc, &uuid); + if (ret) + return ret; + + memcpy(&afu_pr_conf->afu_id.uuid_low, uuid.b, sizeof(u64)); + memcpy(&afu_pr_conf->afu_id.uuid_high, uuid.b + 8, sizeof(u64)); + + printf("%s: uuid_l=0x%lx, uuid_h=0x%lx\n", __func__, + (u64)afu_pr_conf->afu_id.uuid_low, + (u64)afu_pr_conf->afu_id.uuid_high); + + return 0; +} + +static const struct rte_rawdev_ops ifpga_rawdev_ops = { + .dev_info_get = ifpga_rawdev_info_get, + .dev_configure = NULL, + .dev_start = ifpga_rawdev_start, + .dev_stop = ifpga_rawdev_stop, + .dev_close = ifpga_rawdev_close, + .dev_reset = ifpga_rawdev_reset, + + .queue_def_conf = NULL, + .queue_setup = NULL, + .queue_release = NULL, + + .attr_get = NULL, + .attr_set = NULL, + + .enqueue_bufs = NULL, + .dequeue_bufs = NULL, + + .dump = NULL, + + .xstats_get = NULL, + .xstats_get_names = NULL, + .xstats_get_by_name = NULL, + .xstats_reset = NULL, + + .firmware_status_get = NULL, + .firmware_version_get = NULL, + .firmware_load = ifpga_rawdev_pr, + .firmware_unload = NULL, + + .dev_selftest = NULL, +}; + +static int +ifpga_rawdev_create(struct rte_pci_device *pci_dev, + int socket_id) +{ + int ret = 0; + struct rte_rawdev *rawdev = NULL; + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_adapter_data_pci *data; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + int i; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + goto cleanup; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id()); + + /* Allocate device structure */ + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct opae_adapter), + socket_id); + if (rawdev == NULL) { + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); + ret = -EINVAL; + goto cleanup; + } + + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API */ + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); + if (!data) + return -ENOMEM; + + /* init opae_adapter_data_pci for device specific information */ + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + data->region[i].phys_addr = pci_dev->mem_resource[i].phys_addr; + data->region[i].len = pci_dev->mem_resource[i].len; + data->region[i].addr = pci_dev->mem_resource[i].addr; + } + data->device_id = pci_dev->id.device_id; + data->vendor_id = pci_dev->id.vendor_id; + + /* create a opae_adapter based on above device data */ + adapter = opae_adapter_alloc(pci_dev->device.name, data); + if (!adapter) { + opae_adapter_data_free(data); + return -ENOMEM; + } + + rawdev->dev_ops = &ifpga_rawdev_ops; + rawdev->device = &pci_dev->device; + rawdev->driver_name = pci_dev->device.driver->name; + + rawdev->dev_private = adapter; + + /* must enumerate the adapter before use it */ + ret = opae_adapter_enumerate(adapter); + if (ret) + return ret; + + /* set opae_manager to rawdev */ + mgr = opae_adapter_get_mgr(adapter); + if (mgr) { + /*PF function*/ + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); + } + + return ret; + +cleanup: + if (rawdev) + rte_rawdev_pmd_release(rawdev); + + return ret; +} + +static int +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) +{ + int ret; + struct rte_rawdev *rawdev; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + struct opae_adapter *adapter; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + return ret; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", + name, rte_socket_id()); + + rawdev = rte_rawdev_pmd_get_named_dev(name); + if (!rawdev) { + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name); + return -EINVAL; + } + + adapter = ifpga_rawdev_get_priv(rawdev); + if (!adapter) + return -ENODEV; + + opae_adapter_data_free(adapter->data); + opae_adapter_free(adapter); + + /* rte_rawdev_close is called by pmd_release */ + ret = rte_rawdev_pmd_release(rawdev); + if (ret) + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); + + return 0; +} + +static int +ifpga_rawdev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, + struct rte_pci_device *pci_dev) +{ + + printf("## %s\n", __func__); + return ifpga_rawdev_create(pci_dev, rte_socket_id()); +} + +static int ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) +{ + return ifpga_rawdev_destroy(pci_dev); +} + +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { + .id_table = pci_ifpga_map, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, + .probe = ifpga_rawdev_pci_probe, + .remove = ifpga_rawdev_pci_remove, +}; + +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | uio_pci_generic | vfio-pci"); + +RTE_INIT(ifpga_rawdev_init_log); +static void +ifpga_rawdev_init_log(void) +{ + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); + if (ifpga_rawdev_logtype >= 0) + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +static int +ifpga_cfg_probe(struct rte_vdev_device *dev) +{ + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + int port; + char *name = NULL; + char dev_name[RTE_RAWDEV_NAME_MAX_LEN+8]; + + devargs = dev->device.devargs; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &ifpga_get_string_arg, &name) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, + IFPGA_ARG_PORT, + &ifpga_get_integer32_arg, + &port) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + memset(dev_name, 0, sizeof(dev_name)); + snprintf(dev_name, (RTE_RAWDEV_NAME_MAX_LEN+8), "%d|%s", + port, name); + + rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), + dev_name, + devargs->args); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +static int +ifpga_cfg_remove(struct rte_vdev_device *vdev) +{ + IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p", + vdev); + + return 0; +} + +static struct rte_vdev_driver ifpga_cfg_driver = { + .probe = ifpga_cfg_probe, + .remove = ifpga_cfg_remove, +}; + +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, + "bdf=<string> " + "port=<int> " + "afu_bts=<path>"); + diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h new file mode 100644 index 0000000..169dc1d --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_RAWDEV_H_ +#define _IFPGA_RAWDEV_H_ + +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) + +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") + +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) +#define IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) +#define IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) +#define IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) + +enum ifpga_rawdev_device_state { + IFPGA_IDLE, + IFPGA_READY, + IFPGA_ERROR +}; + +static inline struct opae_adapter * +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) +{ + return rawdev->dev_private; +} + +#endif /* _IFPGA_RAWDEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map new file mode 100644 index 0000000..9b9ab1a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map @@ -0,0 +1,4 @@ +DPDK_18.05 { + + local: *; +}; diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 9de2edb..4a76890 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -249,6 +249,7 @@ endif # CONFIG_RTE_LIBRTE_EVENTDEV ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += -lrte_pmd_skeleton_rawdev +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += -lrte_ifpga_rawdev endif # CONFIG_RTE_LIBRTE_RAWDEV -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v6 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen @ 2018-05-04 9:14 ` Shreyansh Jain 2018-05-04 9:04 ` Zhang, Tianfei 0 siblings, 1 reply; 149+ messages in thread From: Shreyansh Jain @ 2018-05-04 9:14 UTC (permalink / raw) To: Xu, Rosen, dev Cc: declan.doherty, bruce.richardson, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet, Yanglong Wu Hello Rosen, Sorry for multiple review iterations, but, in the v7, can you take care of these as well: On Thursday 26 April 2018 03:13 PM, Xu, Rosen wrote: > From: Rosen Xu <rosen.xu@intel.com> > > Add Intel FPGA BUS Rawdev Driver which is based on > librte_rawdev library. > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > Signed-off-by: Figo zhang <tianfei.zhang@intel.com> > --- > config/common_base | 1 + > drivers/raw/Makefile | 1 + > drivers/raw/ifpga_rawdev/Makefile | 36 ++ > drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 597 +++++++++++++++++++++ > drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ > .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + > mk/rte.app.mk | 1 + > 7 files changed, 677 insertions(+) > create mode 100644 drivers/raw/ifpga_rawdev/Makefile > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h > create mode 100644 drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map > [...] > +static int > +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, > + u64 *status) > +{ > + > + struct opae_adapter *adapter; > + struct opae_manager *mgr; > + struct opae_accelerator *acc; > + struct opae_bridge *br; > + int ret; > + > + adapter = ifpga_rawdev_get_priv(raw_dev); > + if (!adapter) > + return -ENODEV; > + > + mgr = opae_adapter_get_mgr(adapter); > + if (!mgr) > + return -ENODEV; > + > + acc = opae_adapter_get_acc(adapter, port_id); > + if (!acc) > + return -ENODEV; > + > + br = opae_acc_get_br(acc); > + if (!br) > + return -ENODEV; > + > + ret = opae_manager_flash(mgr, port_id, buffer, size, status); > + if (ret) { > + printf("%s pr error %d\n", __func__, ret); Please use the debugging or error macros. > + return ret; > + } > + > + usleep(100); Hmm, is that some caveat or a stray line left from some debugging? > + ret = opae_bridge_reset(br); > + if (ret) { > + printf("%s reset port:%d error %d\n", __func__, port_id, ret); Same - debugging/error macros. > + return ret; > + } > + > + return ret; > +} > + > +static int rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, > + const char *file_name) > +{ > + struct stat file_stat; > + int file_fd; > + int ret = 0; > + u32 buffer_size; > + void *buffer; > + u64 pr_error; > + > + if (!file_name) > + return -EINVAL; > + > + file_fd = open(file_name, O_RDONLY); > + if (file_fd < 0) { > + printf("%s: open file error: %s\n", __func__, file_name); > + printf("Message : %s\n", strerror(errno)); Same - debug/error macros > + return -EINVAL; > + } > + ret = stat(file_name, &file_stat); > + if (ret) { > + printf("stat on bitstream file failed: %s\n", file_name); One more (same is applicable across the file). > + return -EINVAL; > + } > + buffer_size = file_stat.st_size; > + printf("bitstream file size: %u\n", buffer_size); > + buffer = rte_malloc(NULL, buffer_size, 0); > + if (!buffer) { > + ret = -ENOMEM; > + goto close_fd; > + } > + > + /*read the raw data*/ > + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { > + ret = -EINVAL; > + goto free_buffer; > + } > + > + /*do PR now*/ > + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); > + printf("downloading to device port %d....%s.\n", port_id, > + ret ? "failed" : "success"); > + if (ret) { > + ret = -EINVAL; > + //raw_dev->ops->show_pr_error(pr_error); I am guessing this is stray from some debugging attempt. Same for the printf above. > + goto free_buffer; > + } > + > +free_buffer: > + if (buffer) > + rte_free(buffer); > +close_fd: > + close(file_fd); > + file_fd = 0; > + return ret; > +} > + > +static int ifpga_rawdev_pr(struct rte_rawdev *dev, > + rte_rawdev_obj_t pr_conf) > +{ > + struct opae_adapter *adapter; > + struct rte_afu_pr_conf *afu_pr_conf; > + int ret; > + struct uuid uuid; > + struct opae_accelerator *acc; > + > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > + > + adapter = ifpga_rawdev_get_priv(dev); > + if (!adapter) > + return -ENODEV; > + > + if (!pr_conf) > + return -EINVAL; > + > + afu_pr_conf = pr_conf; > + > + if (afu_pr_conf->pr_enable) { > + ret = rte_fpga_do_pr(dev, > + afu_pr_conf->afu_id.port, > + afu_pr_conf->bs_path); > + if (ret) { > + printf("do pr error %d\n", ret); One more > + return ret; > + } > + } > + > + acc = opae_adapter_get_acc(adapter, afu_pr_conf->afu_id.port); > + if (!acc) > + return -ENODEV; > + > + ret = opae_acc_get_uuid(acc, &uuid); > + if (ret) > + return ret; > + > + memcpy(&afu_pr_conf->afu_id.uuid_low, uuid.b, sizeof(u64)); > + memcpy(&afu_pr_conf->afu_id.uuid_high, uuid.b + 8, sizeof(u64)); > + > + printf("%s: uuid_l=0x%lx, uuid_h=0x%lx\n", __func__, > + (u64)afu_pr_conf->afu_id.uuid_low, > + (u64)afu_pr_conf->afu_id.uuid_high); debug/error macros > + > + return 0; > +} > + > +static const struct rte_rawdev_ops ifpga_rawdev_ops = { > + .dev_info_get = ifpga_rawdev_info_get, > + .dev_configure = NULL, > + .dev_start = ifpga_rawdev_start, > + .dev_stop = ifpga_rawdev_stop, > + .dev_close = ifpga_rawdev_close, > + .dev_reset = ifpga_rawdev_reset, > + > + .queue_def_conf = NULL, > + .queue_setup = NULL, > + .queue_release = NULL, > + > + .attr_get = NULL, > + .attr_set = NULL, > + > + .enqueue_bufs = NULL, > + .dequeue_bufs = NULL, > + > + .dump = NULL, > + > + .xstats_get = NULL, > + .xstats_get_names = NULL, > + .xstats_get_by_name = NULL, > + .xstats_reset = NULL, > + > + .firmware_status_get = NULL, > + .firmware_version_get = NULL, > + .firmware_load = ifpga_rawdev_pr, > + .firmware_unload = NULL, > + > + .dev_selftest = NULL, > +}; > + > +static int > +ifpga_rawdev_create(struct rte_pci_device *pci_dev, > + int socket_id) > +{ > + int ret = 0; > + struct rte_rawdev *rawdev = NULL; > + struct opae_adapter *adapter; > + struct opae_manager *mgr; > + struct opae_adapter_data_pci *data; > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > + int i; > + > + if (!pci_dev) { > + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); > + ret = -EINVAL; > + goto cleanup; > + } > + > + memset(name, 0, sizeof(name)); > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", > + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); Alignment issue... 'pci_dev->addr.bus ... ' would start from underneath arguments of snprintf. > + > + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id()); > + > + /* Allocate device structure */ > + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct opae_adapter), > + socket_id); > + if (rawdev == NULL) { > + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); > + ret = -EINVAL; > + goto cleanup; > + } > + > + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API */ > + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); > + if (!data) > + return -ENOMEM; What about jumping to cleanup here? (pmd_release()) > + > + /* init opae_adapter_data_pci for device specific information */ > + for (i = 0; i < PCI_MAX_RESOURCE; i++) { > + data->region[i].phys_addr = pci_dev->mem_resource[i].phys_addr; > + data->region[i].len = pci_dev->mem_resource[i].len; > + data->region[i].addr = pci_dev->mem_resource[i].addr; > + } > + data->device_id = pci_dev->id.device_id; > + data->vendor_id = pci_dev->id.vendor_id; > + > + /* create a opae_adapter based on above device data */ > + adapter = opae_adapter_alloc(pci_dev->device.name, data); > + if (!adapter) { > + opae_adapter_data_free(data); > + return -ENOMEM; Same - you are not performing cleanup here. > + } > + > + rawdev->dev_ops = &ifpga_rawdev_ops; > + rawdev->device = &pci_dev->device; > + rawdev->driver_name = pci_dev->device.driver->name; > + > + rawdev->dev_private = adapter; > + > + /* must enumerate the adapter before use it */ > + ret = opae_adapter_enumerate(adapter); > + if (ret) > + return ret; Cleanup to be performed here. > + > + /* set opae_manager to rawdev */ > + mgr = opae_adapter_get_mgr(adapter); > + if (mgr) { > + /*PF function*/ /*<space>PF function<space>*/ > + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); > + } > + > + return ret; > + > +cleanup: > + if (rawdev) > + rte_rawdev_pmd_release(rawdev); > + > + return ret; > +} > + > +static int > +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) > +{ > + int ret; > + struct rte_rawdev *rawdev; > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > + struct opae_adapter *adapter; > + > + if (!pci_dev) { > + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); > + ret = -EINVAL; > + return ret; > + } > + > + memset(name, 0, sizeof(name)); > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", > + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); > + > + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", > + name, rte_socket_id()); > + > + rawdev = rte_rawdev_pmd_get_named_dev(name); > + if (!rawdev) { > + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name); > + return -EINVAL; > + } > + > + adapter = ifpga_rawdev_get_priv(rawdev); > + if (!adapter) > + return -ENODEV; > + > + opae_adapter_data_free(adapter->data); > + opae_adapter_free(adapter); > + > + /* rte_rawdev_close is called by pmd_release */ > + ret = rte_rawdev_pmd_release(rawdev); > + if (ret) > + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); > + > + return 0; > +} > + > +static int > +ifpga_rawdev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, > + struct rte_pci_device *pci_dev) > +{ > + > + printf("## %s\n", __func__); One more. > + return ifpga_rawdev_create(pci_dev, rte_socket_id()); > +} > + > +static int ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) > +{ > + return ifpga_rawdev_destroy(pci_dev); > +} > + > +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { > + .id_table = pci_ifpga_map, > + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, > + .probe = ifpga_rawdev_pci_probe, > + .remove = ifpga_rawdev_pci_remove, > +}; > + > +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); > +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); > +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | uio_pci_generic | vfio-pci"); > + > +RTE_INIT(ifpga_rawdev_init_log); > +static void > +ifpga_rawdev_init_log(void) > +{ > + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); > + if (ifpga_rawdev_logtype >= 0) > + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); > +} > + > +static const char * const valid_args[] = { > +#define IFPGA_ARG_NAME "ifpga" > + IFPGA_ARG_NAME, > +#define IFPGA_ARG_PORT "port" > + IFPGA_ARG_PORT, > +#define IFPGA_AFU_BTS "afu_bts" > + IFPGA_AFU_BTS, > + NULL > +}; > + > +static int > +ifpga_cfg_probe(struct rte_vdev_device *dev) > +{ > + struct rte_devargs *devargs; > + struct rte_kvargs *kvlist = NULL; > + int port; > + char *name = NULL; > + char dev_name[RTE_RAWDEV_NAME_MAX_LEN+8]; > + > + devargs = dev->device.devargs; > + > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > + if (!kvlist) { > + IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param"); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, > + &ifpga_get_string_arg, &name) < 0) { > + IFPGA_RAWDEV_PMD_ERR("error to parse %s", > + IFPGA_ARG_NAME); > + goto end; > + } > + } else { > + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_ARG_NAME); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > + if (rte_kvargs_process(kvlist, > + IFPGA_ARG_PORT, > + &ifpga_get_integer32_arg, > + &port) < 0) { > + IFPGA_RAWDEV_PMD_ERR("error to parse %s", > + IFPGA_ARG_PORT); > + goto end; > + } > + } else { > + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_ARG_PORT); > + goto end; > + } > + > + memset(dev_name, 0, sizeof(dev_name)); > + snprintf(dev_name, (RTE_RAWDEV_NAME_MAX_LEN+8), "%d|%s", Why did you do this? (adding 8 to RTE_RAWDEV_NAME_MAX_LEN)? Just add a patch to increase the value of RTE_RAWDEV_NAME_MAX_LEN. > + port, name); > + > + rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), > + dev_name, > + devargs->args); Seems to be some alignment issue here... > +end: > + if (kvlist) > + rte_kvargs_free(kvlist); > + if (name) > + free(name); > + > + return 0; > +} > + > +static int > +ifpga_cfg_remove(struct rte_vdev_device *vdev) > +{ > + IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p", > + vdev); > + > + return 0; > +} > + > +static struct rte_vdev_driver ifpga_cfg_driver = { > + .probe = ifpga_cfg_probe, > + .remove = ifpga_cfg_remove, > +}; > + > +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); > +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); > +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, > + "bdf=<string> " > + "port=<int> " > + "afu_bts=<path>"); > + > diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > new file mode 100644 > index 0000000..169dc1d > --- /dev/null > +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > @@ -0,0 +1,37 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation > + */ > + > +#ifndef _IFPGA_RAWDEV_H_ > +#define _IFPGA_RAWDEV_H_ > + > +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) Just a trivial comment - you want all your logs, whether INFO, ERROR etc to be appended with function name? Its your choice, but ideally you should separate. > + > +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") > + > +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ > + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) > +#define IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ > + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) > +#define IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ > + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) > +#define IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ > + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) > + > +enum ifpga_rawdev_device_state { > + IFPGA_IDLE, > + IFPGA_READY, > + IFPGA_ERROR > +}; > + > +static inline struct opae_adapter * > +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) > +{ > + return rawdev->dev_private; > +} > + > +#endif /* _IFPGA_RAWDEV_H_ */ > diff --git a/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map > new file mode 100644 > index 0000000..9b9ab1a > --- /dev/null > +++ b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map > @@ -0,0 +1,4 @@ > +DPDK_18.05 { > + > + local: *; > +}; > diff --git a/mk/rte.app.mk b/mk/rte.app.mk > index 9de2edb..4a76890 100644 > --- a/mk/rte.app.mk > +++ b/mk/rte.app.mk > @@ -249,6 +249,7 @@ endif # CONFIG_RTE_LIBRTE_EVENTDEV > > ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += -lrte_pmd_skeleton_rawdev > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += -lrte_ifpga_rawdev > endif # CONFIG_RTE_LIBRTE_RAWDEV > > > How fast can you fix and push? I can spare time tomorrow (5/May) to re-review, if you can push by then. It might help in merging next week. - Shreyansh ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v6 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-04 9:14 ` Shreyansh Jain @ 2018-05-04 9:04 ` Zhang, Tianfei 0 siblings, 0 replies; 149+ messages in thread From: Zhang, Tianfei @ 2018-05-04 9:04 UTC (permalink / raw) To: Shreyansh Jain, Xu, Rosen, dev Cc: Doherty, Declan, Richardson, Bruce, Yigit, Ferruh, Ananyev, Konstantin, Wu, Hao, gaetan.rivet, Wu, Yanglong, Liu, Song > -----Original Message----- > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > Sent: Friday, May 4, 2018 5:15 PM > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org > Cc: Doherty, Declan <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; Yigit, Ferruh <ferruh.yigit@intel.com>; > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Tianfei > <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com; Wu, Yanglong <yanglong.wu@intel.com> > Subject: Re: [dpdk-dev] [PATCH v6 3/5] iFPGA: Add Intel FPGA BUS Rawdev > Driver > > Hello Rosen, > > Sorry for multiple review iterations, but, in the v7, can you take care of these > as well: > > On Thursday 26 April 2018 03:13 PM, Xu, Rosen wrote: > > From: Rosen Xu <rosen.xu@intel.com> > > > > Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev > > library. > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > > Signed-off-by: Figo zhang <tianfei.zhang@intel.com> > > --- > > config/common_base | 1 + > > drivers/raw/Makefile | 1 + > > drivers/raw/ifpga_rawdev/Makefile | 36 ++ > > drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 597 > +++++++++++++++++++++ > > drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ > > .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + > > mk/rte.app.mk | 1 + > > 7 files changed, 677 insertions(+) > > create mode 100644 drivers/raw/ifpga_rawdev/Makefile > > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c > > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > create mode 100644 > > drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map > > > > [...] > > > +static int > > +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, > > + u64 *status) > > +{ > > + > > + struct opae_adapter *adapter; > > + struct opae_manager *mgr; > > + struct opae_accelerator *acc; > > + struct opae_bridge *br; > > + int ret; > > + > > + adapter = ifpga_rawdev_get_priv(raw_dev); > > + if (!adapter) > > + return -ENODEV; > > + > > + mgr = opae_adapter_get_mgr(adapter); > > + if (!mgr) > > + return -ENODEV; > > + > > + acc = opae_adapter_get_acc(adapter, port_id); > > + if (!acc) > > + return -ENODEV; > > + > > + br = opae_acc_get_br(acc); > > + if (!br) > > + return -ENODEV; > > + > > + ret = opae_manager_flash(mgr, port_id, buffer, size, status); > > + if (ret) { > > + printf("%s pr error %d\n", __func__, ret); > > Please use the debugging or error macros. > > > + return ret; > > + } > > + > > + usleep(100); > > Hmm, is that some caveat or a stray line left from some debugging? > > > + ret = opae_bridge_reset(br); > > + if (ret) { > > + printf("%s reset port:%d error %d\n", __func__, port_id, ret); > > Same - debugging/error macros. > > > + return ret; > > + } > > + > > + return ret; > > +} > > + > > +static int rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, > > + const char *file_name) > > +{ > > + struct stat file_stat; > > + int file_fd; > > + int ret = 0; > > + u32 buffer_size; > > + void *buffer; > > + u64 pr_error; > > + > > + if (!file_name) > > + return -EINVAL; > > + > > + file_fd = open(file_name, O_RDONLY); > > + if (file_fd < 0) { > > + printf("%s: open file error: %s\n", __func__, file_name); > > + printf("Message : %s\n", strerror(errno)); > > Same - debug/error macros > > > + return -EINVAL; > > + } > > + ret = stat(file_name, &file_stat); > > + if (ret) { > > + printf("stat on bitstream file failed: %s\n", file_name); > > One more (same is applicable across the file). > > > + return -EINVAL; > > + } > > + buffer_size = file_stat.st_size; > > + printf("bitstream file size: %u\n", buffer_size); > > + buffer = rte_malloc(NULL, buffer_size, 0); > > + if (!buffer) { > > + ret = -ENOMEM; > > + goto close_fd; > > + } > > + > > + /*read the raw data*/ > > + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { > > + ret = -EINVAL; > > + goto free_buffer; > > + } > > + > > + /*do PR now*/ > > + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); > > + printf("downloading to device port %d....%s.\n", port_id, > > + ret ? "failed" : "success"); > > + if (ret) { > > + ret = -EINVAL; > > + //raw_dev->ops->show_pr_error(pr_error); > > I am guessing this is stray from some debugging attempt. Same for the printf > above. > > > + goto free_buffer; > > + } > > + > > +free_buffer: > > + if (buffer) > > + rte_free(buffer); > > +close_fd: > > + close(file_fd); > > + file_fd = 0; > > + return ret; > > +} > > + > > +static int ifpga_rawdev_pr(struct rte_rawdev *dev, > > + rte_rawdev_obj_t pr_conf) > > +{ > > + struct opae_adapter *adapter; > > + struct rte_afu_pr_conf *afu_pr_conf; > > + int ret; > > + struct uuid uuid; > > + struct opae_accelerator *acc; > > + > > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > > + > > + adapter = ifpga_rawdev_get_priv(dev); > > + if (!adapter) > > + return -ENODEV; > > + > > + if (!pr_conf) > > + return -EINVAL; > > + > > + afu_pr_conf = pr_conf; > > + > > + if (afu_pr_conf->pr_enable) { > > + ret = rte_fpga_do_pr(dev, > > + afu_pr_conf->afu_id.port, > > + afu_pr_conf->bs_path); > > + if (ret) { > > + printf("do pr error %d\n", ret); > > One more > > > + return ret; > > + } > > + } > > + > > + acc = opae_adapter_get_acc(adapter, afu_pr_conf->afu_id.port); > > + if (!acc) > > + return -ENODEV; > > + > > + ret = opae_acc_get_uuid(acc, &uuid); > > + if (ret) > > + return ret; > > + > > + memcpy(&afu_pr_conf->afu_id.uuid_low, uuid.b, sizeof(u64)); > > + memcpy(&afu_pr_conf->afu_id.uuid_high, uuid.b + 8, sizeof(u64)); > > + > > + printf("%s: uuid_l=0x%lx, uuid_h=0x%lx\n", __func__, > > + (u64)afu_pr_conf->afu_id.uuid_low, > > + (u64)afu_pr_conf->afu_id.uuid_high); > debug/error macros > > > + > > + return 0; > > +} > > + > > +static const struct rte_rawdev_ops ifpga_rawdev_ops = { > > + .dev_info_get = ifpga_rawdev_info_get, > > + .dev_configure = NULL, > > + .dev_start = ifpga_rawdev_start, > > + .dev_stop = ifpga_rawdev_stop, > > + .dev_close = ifpga_rawdev_close, > > + .dev_reset = ifpga_rawdev_reset, > > + > > + .queue_def_conf = NULL, > > + .queue_setup = NULL, > > + .queue_release = NULL, > > + > > + .attr_get = NULL, > > + .attr_set = NULL, > > + > > + .enqueue_bufs = NULL, > > + .dequeue_bufs = NULL, > > + > > + .dump = NULL, > > + > > + .xstats_get = NULL, > > + .xstats_get_names = NULL, > > + .xstats_get_by_name = NULL, > > + .xstats_reset = NULL, > > + > > + .firmware_status_get = NULL, > > + .firmware_version_get = NULL, > > + .firmware_load = ifpga_rawdev_pr, > > + .firmware_unload = NULL, > > + > > + .dev_selftest = NULL, > > +}; > > + > > +static int > > +ifpga_rawdev_create(struct rte_pci_device *pci_dev, > > + int socket_id) > > +{ > > + int ret = 0; > > + struct rte_rawdev *rawdev = NULL; > > + struct opae_adapter *adapter; > > + struct opae_manager *mgr; > > + struct opae_adapter_data_pci *data; > > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > > + int i; > > + > > + if (!pci_dev) { > > + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); > > + ret = -EINVAL; > > + goto cleanup; > > + } > > + > > + memset(name, 0, sizeof(name)); > > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", > > + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); > > Alignment issue... 'pci_dev->addr.bus ... ' would start from underneath > arguments of snprintf. > > > + > > + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, > > +rte_socket_id()); > > + > > + /* Allocate device structure */ > > + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct opae_adapter), > > + socket_id); > > + if (rawdev == NULL) { > > + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); > > + ret = -EINVAL; > > + goto cleanup; > > + } > > + > > + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API */ > > + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); > > + if (!data) > > + return -ENOMEM; > > What about jumping to cleanup here? (pmd_release()) > > > + > > + /* init opae_adapter_data_pci for device specific information */ > > + for (i = 0; i < PCI_MAX_RESOURCE; i++) { > > + data->region[i].phys_addr = pci_dev->mem_resource[i].phys_addr; > > + data->region[i].len = pci_dev->mem_resource[i].len; > > + data->region[i].addr = pci_dev->mem_resource[i].addr; > > + } > > + data->device_id = pci_dev->id.device_id; > > + data->vendor_id = pci_dev->id.vendor_id; > > + > > + /* create a opae_adapter based on above device data */ > > + adapter = opae_adapter_alloc(pci_dev->device.name, data); > > + if (!adapter) { > > + opae_adapter_data_free(data); > > + return -ENOMEM; > > Same - you are not performing cleanup here. > > > + } > > + > > + rawdev->dev_ops = &ifpga_rawdev_ops; > > + rawdev->device = &pci_dev->device; > > + rawdev->driver_name = pci_dev->device.driver->name; > > + > > + rawdev->dev_private = adapter; > > + > > + /* must enumerate the adapter before use it */ > > + ret = opae_adapter_enumerate(adapter); > > + if (ret) > > + return ret; > > Cleanup to be performed here. > > > + > > + /* set opae_manager to rawdev */ > > + mgr = opae_adapter_get_mgr(adapter); > > + if (mgr) { > > + /*PF function*/ > > /*<space>PF function<space>*/ > > > + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); > > + } > > + > > + return ret; > > + > > +cleanup: > > + if (rawdev) > > + rte_rawdev_pmd_release(rawdev); > > + > > + return ret; > > +} > > + > > +static int > > +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) { > > + int ret; > > + struct rte_rawdev *rawdev; > > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > > + struct opae_adapter *adapter; > > + > > + if (!pci_dev) { > > + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); > > + ret = -EINVAL; > > + return ret; > > + } > > + > > + memset(name, 0, sizeof(name)); > > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", > > + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); > > + > > + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", > > + name, rte_socket_id()); > > + > > + rawdev = rte_rawdev_pmd_get_named_dev(name); > > + if (!rawdev) { > > + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name); > > + return -EINVAL; > > + } > > + > > + adapter = ifpga_rawdev_get_priv(rawdev); > > + if (!adapter) > > + return -ENODEV; > > + > > + opae_adapter_data_free(adapter->data); > > + opae_adapter_free(adapter); > > + > > + /* rte_rawdev_close is called by pmd_release */ > > + ret = rte_rawdev_pmd_release(rawdev); > > + if (ret) > > + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); > > + > > + return 0; > > +} > > + > > +static int > > +ifpga_rawdev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, > > + struct rte_pci_device *pci_dev) > > +{ > > + > > + printf("## %s\n", __func__); > > One more. > > > + return ifpga_rawdev_create(pci_dev, rte_socket_id()); } > > + > > +static int ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) { > > + return ifpga_rawdev_destroy(pci_dev); } > > + > > +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { > > + .id_table = pci_ifpga_map, > > + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, > > + .probe = ifpga_rawdev_pci_probe, > > + .remove = ifpga_rawdev_pci_remove, > > +}; > > + > > +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, > rte_ifpga_rawdev_pmd); > > +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, > > +rte_ifpga_rawdev_pmd); > > +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | > > +uio_pci_generic | vfio-pci"); > > + > > +RTE_INIT(ifpga_rawdev_init_log); > > +static void > > +ifpga_rawdev_init_log(void) > > +{ > > + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); > > + if (ifpga_rawdev_logtype >= 0) > > + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); } > > + > > +static const char * const valid_args[] = { > > +#define IFPGA_ARG_NAME "ifpga" > > + IFPGA_ARG_NAME, > > +#define IFPGA_ARG_PORT "port" > > + IFPGA_ARG_PORT, > > +#define IFPGA_AFU_BTS "afu_bts" > > + IFPGA_AFU_BTS, > > + NULL > > +}; > > + > > +static int > > +ifpga_cfg_probe(struct rte_vdev_device *dev) { > > + struct rte_devargs *devargs; > > + struct rte_kvargs *kvlist = NULL; > > + int port; > > + char *name = NULL; > > + char dev_name[RTE_RAWDEV_NAME_MAX_LEN+8]; > > + > > + devargs = dev->device.devargs; > > + > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > + if (!kvlist) { > > + IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param"); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, > > + &ifpga_get_string_arg, &name) < 0) { > > + IFPGA_RAWDEV_PMD_ERR("error to parse %s", > > + IFPGA_ARG_NAME); > > + goto end; > > + } > > + } else { > > + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_NAME); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > > + if (rte_kvargs_process(kvlist, > > + IFPGA_ARG_PORT, > > + &ifpga_get_integer32_arg, > > + &port) < 0) { > > + IFPGA_RAWDEV_PMD_ERR("error to parse %s", > > + IFPGA_ARG_PORT); > > + goto end; > > + } > > + } else { > > + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PORT); > > + goto end; > > + } > > + > > + memset(dev_name, 0, sizeof(dev_name)); > > + snprintf(dev_name, (RTE_RAWDEV_NAME_MAX_LEN+8), "%d|%s", > > Why did you do this? (adding 8 to RTE_RAWDEV_NAME_MAX_LEN)? > Just add a patch to increase the value of RTE_RAWDEV_NAME_MAX_LEN. > > > + port, name); > > + > > + rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), > > + dev_name, > > + devargs->args); > > Seems to be some alignment issue here... > > > +end: > > + if (kvlist) > > + rte_kvargs_free(kvlist); > > + if (name) > > + free(name); > > + > > + return 0; > > +} > > + > > +static int > > +ifpga_cfg_remove(struct rte_vdev_device *vdev) { > > + IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p", > > + vdev); > > + > > + return 0; > > +} > > + > > +static struct rte_vdev_driver ifpga_cfg_driver = { > > + .probe = ifpga_cfg_probe, > > + .remove = ifpga_cfg_remove, > > +}; > > + > > +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); > > +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); > > +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, > > + "bdf=<string> " > > + "port=<int> " > > + "afu_bts=<path>"); > > + > > diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > new file mode 100644 > > index 0000000..169dc1d > > --- /dev/null > > +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > @@ -0,0 +1,37 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > +#ifndef _IFPGA_RAWDEV_H_ > > +#define _IFPGA_RAWDEV_H_ > > + > > +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) > > Just a trivial comment - you want all your logs, whether INFO, ERROR etc to > be appended with function name? Its your choice, but ideally you should > separate. > > > + > > +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() > IFPGA_RAWDEV_PMD_LOG(DEBUG, > > +">>") > > + > > +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ > > + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) #define > > +IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ > > + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) #define > > +IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ > > + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) #define > > +IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ > > + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) > > + > > +enum ifpga_rawdev_device_state { > > + IFPGA_IDLE, > > + IFPGA_READY, > > + IFPGA_ERROR > > +}; > > + > > +static inline struct opae_adapter * > > +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) { > > + return rawdev->dev_private; > > +} > > + > > +#endif /* _IFPGA_RAWDEV_H_ */ > > diff --git a/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map > > b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map > > new file mode 100644 > > index 0000000..9b9ab1a > > --- /dev/null > > +++ b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map > > @@ -0,0 +1,4 @@ > > +DPDK_18.05 { > > + > > + local: *; > > +}; > > diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 9de2edb..4a76890 > > 100644 > > --- a/mk/rte.app.mk > > +++ b/mk/rte.app.mk > > @@ -249,6 +249,7 @@ endif # CONFIG_RTE_LIBRTE_EVENTDEV > > > > ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += > > -lrte_pmd_skeleton_rawdev > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += > -lrte_ifpga_rawdev > > endif # CONFIG_RTE_LIBRTE_RAWDEV > > > > > > > > How fast can you fix and push? I can spare time tomorrow (5/May) to > re-review, if you can push by then. It might help in merging next week. > > - > Shreyansh Hi Shreyansh: Thank you for your review, we will fix and push at next day. Best Tianfei ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v6 4/5] iFPGA: add meson build 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 0/5] " Xu, Rosen ` (2 preceding siblings ...) 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen @ 2018-04-26 9:43 ` Xu, Rosen 2018-05-02 9:46 ` Shreyansh Jain 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 5/5] iFPGA: add document for iFPGA driver Xu, Rosen 4 siblings, 1 reply; 149+ messages in thread From: Xu, Rosen @ 2018-04-26 9:43 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet From: Figo Zhang <tianfei.zhang@intel.com> add meson build support for iFPGA driver. Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> --- drivers/meson.build | 3 ++- drivers/raw/ifpga_rawdev/base/meson.build | 34 +++++++++++++++++++++++++++++++ drivers/raw/ifpga_rawdev/meson.build | 13 ++++++++++++ drivers/raw/meson.build | 6 ++++++ 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build create mode 100644 drivers/raw/ifpga_rawdev/meson.build create mode 100644 drivers/raw/meson.build diff --git a/drivers/meson.build b/drivers/meson.build index b146f09..b7fc0d6 100644 --- a/drivers/meson.build +++ b/drivers/meson.build @@ -7,7 +7,8 @@ driver_classes = ['common', 'mempool', # depends on common and bus. 'net', # depends on common, bus and mempool. 'crypto', # depends on common, bus and mempool (net in future). - 'event'] # depends on common, bus, mempool and net. + 'event', # depends on common, bus, mempool and net. + 'raw'] foreach class:driver_classes drivers = [] diff --git a/drivers/raw/ifpga_rawdev/base/meson.build b/drivers/raw/ifpga_rawdev/base/meson.build new file mode 100644 index 0000000..cb65535 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/meson.build @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +sources = [ + 'ifpga_api.c', + 'ifpga_enumerate.c', + 'ifpga_feature_dev.c', + 'ifpga_fme.c', + 'ifpga_fme_iperf.c', + 'ifpga_fme_dperf.c', + 'ifpga_fme_error.c', + 'ifpga_port.c', + 'ifpga_port_error.c', + 'ifpga_fme_pr.c', + 'opae_hw_api.c', + 'opae_ifpga_hw_api.c', + 'opae_debug.c' +] + +error_cflags = ['-Wno-sign-compare', '-Wno-unused-value', + '-Wno-format', '-Wno-unused-but-set-variable', + '-Wno-strict-aliasing' +] +c_args = cflags +foreach flag: error_cflags + if cc.has_argument(flag) + c_args += flag + endif +endforeach + +base_lib = static_library('ifpga_rawdev_base', sources, + dependencies: static_rte_eal, + c_args: c_args) +base_objs = base_lib.extract_all_objects() diff --git a/drivers/raw/ifpga_rawdev/meson.build b/drivers/raw/ifpga_rawdev/meson.build new file mode 100644 index 0000000..37896af --- /dev/null +++ b/drivers/raw/ifpga_rawdev/meson.build @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +version = 1 + +subdir('base') +objs = [base_objs] + +deps += ['rawdev', 'pci', 'bus_pci', 'kvargs', + 'bus_vdev', 'bus_ifpga'] +sources = files('ifpga_rawdev.c') + +includes += include_directories('base') diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build new file mode 100644 index 0000000..410f908 --- /dev/null +++ b/drivers/raw/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2017 Intel Corporation + +drivers = ['ifpga_rawdev'] +config_flag_fmt = 'RTE_LIBRTE_@0@_PMD' +driver_name_fmt = 'rte_@0@' -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v6 4/5] iFPGA: add meson build 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 4/5] iFPGA: add meson build Xu, Rosen @ 2018-05-02 9:46 ` Shreyansh Jain 2018-05-02 13:36 ` Zhang, Tianfei 0 siblings, 1 reply; 149+ messages in thread From: Shreyansh Jain @ 2018-05-02 9:46 UTC (permalink / raw) To: Xu, Rosen, dev, ferruh.yigit Cc: declan.doherty, bruce.richardson, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet On Thursday 26 April 2018 03:13 PM, Xu, Rosen wrote: > From: Figo Zhang <tianfei.zhang@intel.com> > > add meson build support for iFPGA driver. > > Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> > --- > drivers/meson.build | 3 ++- > drivers/raw/ifpga_rawdev/base/meson.build | 34 +++++++++++++++++++++++++++++++ > drivers/raw/ifpga_rawdev/meson.build | 13 ++++++++++++ > drivers/raw/meson.build | 6 ++++++ > 4 files changed, 55 insertions(+), 1 deletion(-) > create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build > create mode 100644 drivers/raw/ifpga_rawdev/meson.build > create mode 100644 drivers/raw/meson.build > > diff --git a/drivers/meson.build b/drivers/meson.build > index b146f09..b7fc0d6 100644 > --- a/drivers/meson.build > +++ b/drivers/meson.build > @@ -7,7 +7,8 @@ driver_classes = ['common', > 'mempool', # depends on common and bus. > 'net', # depends on common, bus and mempool. > 'crypto', # depends on common, bus and mempool (net in future). > - 'event'] # depends on common, bus, mempool and net. > + 'event', # depends on common, bus, mempool and net. > + 'raw'] > > foreach class:driver_classes > drivers = [] [...] > diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build > new file mode 100644 > index 0000000..410f908 > --- /dev/null > +++ b/drivers/raw/meson.build > @@ -0,0 +1,6 @@ > +# SPDX-License-Identifier: BSD-3-Clause > +# Copyright(c) 2017 Intel Corporation > + > +drivers = ['ifpga_rawdev'] > +config_flag_fmt = 'RTE_LIBRTE_@0@_PMD' > +driver_name_fmt = 'rte_@0@' > Just a heads-up for Thomas/Ferruh: Either this or patches from Nipun [1] would conflict here as drivers/raw/meson.build is being introduced by both. [1] http://dpdk.org/ml/archives/dev/2018-April/098827.html ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v6 4/5] iFPGA: add meson build 2018-05-02 9:46 ` Shreyansh Jain @ 2018-05-02 13:36 ` Zhang, Tianfei 2018-05-03 9:13 ` Shreyansh Jain 0 siblings, 1 reply; 149+ messages in thread From: Zhang, Tianfei @ 2018-05-02 13:36 UTC (permalink / raw) To: Shreyansh Jain, Xu, Rosen, dev, Yigit, Ferruh Cc: Doherty, Declan, Richardson, Bruce, Ananyev, Konstantin, Wu, Hao, gaetan.rivet > -----Original Message----- > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > Sent: Wednesday, May 2, 2018 5:47 PM > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; Yigit, Ferruh > <ferruh.yigit@intel.com> > Cc: Doherty, Declan <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Wu, Hao <hao.wu@intel.com>; gaetan.rivet@6wind.com > Subject: Re: [dpdk-dev] [PATCH v6 4/5] iFPGA: add meson build > > On Thursday 26 April 2018 03:13 PM, Xu, Rosen wrote: > > From: Figo Zhang <tianfei.zhang@intel.com> > > > > add meson build support for iFPGA driver. > > > > Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> > > --- > > drivers/meson.build | 3 ++- > > drivers/raw/ifpga_rawdev/base/meson.build | 34 > +++++++++++++++++++++++++++++++ > > drivers/raw/ifpga_rawdev/meson.build | 13 ++++++++++++ > > drivers/raw/meson.build | 6 ++++++ > > 4 files changed, 55 insertions(+), 1 deletion(-) > > create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build > > create mode 100644 drivers/raw/ifpga_rawdev/meson.build > > create mode 100644 drivers/raw/meson.build > > > > diff --git a/drivers/meson.build b/drivers/meson.build index > > b146f09..b7fc0d6 100644 > > --- a/drivers/meson.build > > +++ b/drivers/meson.build > > @@ -7,7 +7,8 @@ driver_classes = ['common', > > 'mempool', # depends on common and bus. > > 'net', # depends on common, bus and mempool. > > 'crypto', # depends on common, bus and mempool (net > in future). > > - 'event'] # depends on common, bus, mempool and net. > > + 'event', # depends on common, bus, mempool and net. > > + 'raw'] > > > > foreach class:driver_classes > > drivers = [] > > [...] > > > diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build new > > file mode 100644 index 0000000..410f908 > > --- /dev/null > > +++ b/drivers/raw/meson.build > > @@ -0,0 +1,6 @@ > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel > > +Corporation > > + > > +drivers = ['ifpga_rawdev'] > > +config_flag_fmt = 'RTE_LIBRTE_@0@_PMD' > > +driver_name_fmt = 'rte_@0@' > > > > Just a heads-up for Thomas/Ferruh: Either this or patches from Nipun [1] > would conflict here as drivers/raw/meson.build is being introduced by both. > > [1] http://dpdk.org/ml/archives/dev/2018-April/098827.html Thomas and Ferruh's patch has merged into mainline? We will rebase to latest master branch and send the V7 patches soon. ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v6 4/5] iFPGA: add meson build 2018-05-02 13:36 ` Zhang, Tianfei @ 2018-05-03 9:13 ` Shreyansh Jain 2018-05-03 15:12 ` Zhang, Tianfei 0 siblings, 1 reply; 149+ messages in thread From: Shreyansh Jain @ 2018-05-03 9:13 UTC (permalink / raw) To: Zhang, Tianfei, Xu, Rosen, dev, Yigit, Ferruh Cc: Doherty, Declan, Richardson, Bruce, Ananyev, Konstantin, Wu, Hao, gaetan.rivet On Wednesday 02 May 2018 07:06 PM, Zhang, Tianfei wrote: > >> -----Original Message----- >> From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] >> Sent: Wednesday, May 2, 2018 5:47 PM >> To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; Yigit, Ferruh >> <ferruh.yigit@intel.com> >> Cc: Doherty, Declan <declan.doherty@intel.com>; Richardson, Bruce >> <bruce.richardson@intel.com>; Ananyev, Konstantin >> <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; >> Wu, Hao <hao.wu@intel.com>; gaetan.rivet@6wind.com >> Subject: Re: [dpdk-dev] [PATCH v6 4/5] iFPGA: add meson build >> >> On Thursday 26 April 2018 03:13 PM, Xu, Rosen wrote: >>> From: Figo Zhang <tianfei.zhang@intel.com> >>> >>> add meson build support for iFPGA driver. >>> >>> Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> >>> --- >>> drivers/meson.build | 3 ++- >>> drivers/raw/ifpga_rawdev/base/meson.build | 34 >> +++++++++++++++++++++++++++++++ >>> drivers/raw/ifpga_rawdev/meson.build | 13 ++++++++++++ >>> drivers/raw/meson.build | 6 ++++++ >>> 4 files changed, 55 insertions(+), 1 deletion(-) >>> create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build >>> create mode 100644 drivers/raw/ifpga_rawdev/meson.build >>> create mode 100644 drivers/raw/meson.build >>> >>> diff --git a/drivers/meson.build b/drivers/meson.build index >>> b146f09..b7fc0d6 100644 >>> --- a/drivers/meson.build >>> +++ b/drivers/meson.build >>> @@ -7,7 +7,8 @@ driver_classes = ['common', >>> 'mempool', # depends on common and bus. >>> 'net', # depends on common, bus and mempool. >>> 'crypto', # depends on common, bus and mempool (net >> in future). >>> - 'event'] # depends on common, bus, mempool and net. >>> + 'event', # depends on common, bus, mempool and net. >>> + 'raw'] >>> >>> foreach class:driver_classes >>> drivers = [] >> >> [...] >> >>> diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build new >>> file mode 100644 index 0000000..410f908 >>> --- /dev/null >>> +++ b/drivers/raw/meson.build >>> @@ -0,0 +1,6 @@ >>> +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel >>> +Corporation >>> + >>> +drivers = ['ifpga_rawdev'] >>> +config_flag_fmt = 'RTE_LIBRTE_@0@_PMD' >>> +driver_name_fmt = 'rte_@0@' >>> >> >> Just a heads-up for Thomas/Ferruh: Either this or patches from Nipun [1] >> would conflict here as drivers/raw/meson.build is being introduced by both. >> >> [1] http://dpdk.org/ml/archives/dev/2018-April/098827.html > > Thomas and Ferruh's patch has merged into mainline? > We will rebase to latest master branch and send the V7 patches soon. > In the weekly call, it was decided that qdma patches are almost ready. So, can you rebase your patches over that? You will have to remove the drivers/raw/meson.build and add your entry into the one added by qdma driver [1]. You might have to wait for a couple of days. [1] http://dpdk.org/ml/archives/dev/2018-May/099836.html ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v6 4/5] iFPGA: add meson build 2018-05-03 9:13 ` Shreyansh Jain @ 2018-05-03 15:12 ` Zhang, Tianfei 0 siblings, 0 replies; 149+ messages in thread From: Zhang, Tianfei @ 2018-05-03 15:12 UTC (permalink / raw) To: Shreyansh Jain, Xu, Rosen, dev, Yigit, Ferruh Cc: Doherty, Declan, Richardson, Bruce, Ananyev, Konstantin, Wu, Hao, gaetan.rivet > -----Original Message----- > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > Sent: Thursday, May 3, 2018 5:13 PM > To: Zhang, Tianfei <tianfei.zhang@intel.com>; Xu, Rosen > <rosen.xu@intel.com>; dev@dpdk.org; Yigit, Ferruh <ferruh.yigit@intel.com> > Cc: Doherty, Declan <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: Re: [dpdk-dev] [PATCH v6 4/5] iFPGA: add meson build > > On Wednesday 02 May 2018 07:06 PM, Zhang, Tianfei wrote: > > > >> -----Original Message----- > >> From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > >> Sent: Wednesday, May 2, 2018 5:47 PM > >> To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; Yigit, Ferruh > >> <ferruh.yigit@intel.com> > >> Cc: Doherty, Declan <declan.doherty@intel.com>; Richardson, Bruce > >> <bruce.richardson@intel.com>; Ananyev, Konstantin > >> <konstantin.ananyev@intel.com>; Zhang, Tianfei > >> <tianfei.zhang@intel.com>; Wu, Hao <hao.wu@intel.com>; > >> gaetan.rivet@6wind.com > >> Subject: Re: [dpdk-dev] [PATCH v6 4/5] iFPGA: add meson build > >> > >> On Thursday 26 April 2018 03:13 PM, Xu, Rosen wrote: > >>> From: Figo Zhang <tianfei.zhang@intel.com> > >>> > >>> add meson build support for iFPGA driver. > >>> > >>> Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> > >>> --- > >>> drivers/meson.build | 3 ++- > >>> drivers/raw/ifpga_rawdev/base/meson.build | 34 > >> +++++++++++++++++++++++++++++++ > >>> drivers/raw/ifpga_rawdev/meson.build | 13 ++++++++++++ > >>> drivers/raw/meson.build | 6 ++++++ > >>> 4 files changed, 55 insertions(+), 1 deletion(-) > >>> create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build > >>> create mode 100644 drivers/raw/ifpga_rawdev/meson.build > >>> create mode 100644 drivers/raw/meson.build > >>> > >>> diff --git a/drivers/meson.build b/drivers/meson.build index > >>> b146f09..b7fc0d6 100644 > >>> --- a/drivers/meson.build > >>> +++ b/drivers/meson.build > >>> @@ -7,7 +7,8 @@ driver_classes = ['common', > >>> 'mempool', # depends on common and bus. > >>> 'net', # depends on common, bus and mempool. > >>> 'crypto', # depends on common, bus and mempool (net > >> in future). > >>> - 'event'] # depends on common, bus, mempool and net. > >>> + 'event', # depends on common, bus, mempool and net. > >>> + 'raw'] > >>> > >>> foreach class:driver_classes > >>> drivers = [] > >> > >> [...] > >> > >>> diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build new > >>> file mode 100644 index 0000000..410f908 > >>> --- /dev/null > >>> +++ b/drivers/raw/meson.build > >>> @@ -0,0 +1,6 @@ > >>> +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel > >>> +Corporation > >>> + > >>> +drivers = ['ifpga_rawdev'] > >>> +config_flag_fmt = 'RTE_LIBRTE_@0@_PMD' > >>> +driver_name_fmt = 'rte_@0@' > >>> > >> > >> Just a heads-up for Thomas/Ferruh: Either this or patches from Nipun > >> [1] would conflict here as drivers/raw/meson.build is being introduced by > both. > >> > >> [1] http://dpdk.org/ml/archives/dev/2018-April/098827.html > > > > Thomas and Ferruh's patch has merged into mainline? > > We will rebase to latest master branch and send the V7 patches soon. > > > > In the weekly call, it was decided that qdma patches are almost ready. > So, can you rebase your patches over that? You will have to remove the > drivers/raw/meson.build and add your entry into the one added by qdma > driver [1]. > You might have to wait for a couple of days. > > [1] http://dpdk.org/ml/archives/dev/2018-May/099836.html Sure. By now we have prepare our v7 patches and will send this days, and fix some comments by some community guys. When this patch has merged into mainline, we will rebase over it. ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v6 5/5] iFPGA: add document for iFPGA driver 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 0/5] " Xu, Rosen ` (3 preceding siblings ...) 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 4/5] iFPGA: add meson build Xu, Rosen @ 2018-04-26 9:43 ` Xu, Rosen 4 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-04-26 9:43 UTC (permalink / raw) To: dev Cc: declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, hao.wu, gaetan.rivet, Rosen Xu From: Rosen Xu <rosen.xu@intel.com> add some introduction, motivation and usage for iFPGA driver. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> --- doc/guides/index.rst | 1 + doc/guides/rawdevs/ifpga_rawdev.rst | 112 +++++++++++++++++++++++++++++++++ doc/guides/rawdevs/index.rst | 11 ++++ doc/guides/rel_notes/release_18_05.rst | 13 ++++ 4 files changed, 137 insertions(+) create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst create mode 100644 doc/guides/rawdevs/index.rst diff --git a/doc/guides/index.rst b/doc/guides/index.rst index d60529d..a93baac 100644 --- a/doc/guides/index.rst +++ b/doc/guides/index.rst @@ -20,6 +20,7 @@ DPDK documentation eventdevs/index mempool/index platform/index + rawdevs/index contributing/index rel_notes/index faq/index diff --git a/doc/guides/rawdevs/ifpga_rawdev.rst b/doc/guides/rawdevs/ifpga_rawdev.rst new file mode 100644 index 0000000..3311586 --- /dev/null +++ b/doc/guides/rawdevs/ifpga_rawdev.rst @@ -0,0 +1,112 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2018 Intel Corporation. + +IFPGA Rawdev Driver +====================== + +FPGA is used more and more widely in Cloud and NFV, one primary reason is +that FPGA not only provides ASIC performance but also it's more flexible +than ASIC. + +FPGA uses Partial Reconfigure(PR) Parts of Bit Stream to achieve its +flexibility. That means one FPGA Device Bit Stream is divided into many Parts +of Bit Stream(each Part of Bit Stream is defined as AFU-Accelerated Function +Unit), and each AFU is a hardware acceleration unit which can be dynamically +reloaded respectively. + +By PR(Partial Reconfiguration) AFUs, one FPGA resources can be time-shared by +different users. FPGA hot upgraded and fault tolerance can be provided easily. + +The SW IFPGA Rawdev Driver (**ifpga_rawdev**) provides a Rawdev driver +that utilizes Intel FPGA Software Stack OPAE(Open Programmable Acceleration +Engine) for FPGA management. + +Implementation details +---------------------- + +Each instance of IFPGA Rawdev Driver is probed by Intel FpgaDev. Cooperated +with OPAE share code IFPGA Rawdev Driver provides common FPGA management ops +for FPGA operation, OPAE provides all following operations: +- FPGA PR(Partial Reconfiguration) management +- FPGA AFUs Identifying +- FPGA Thermal Management +- FPGA Power Management +- FPGA Performance reporting +- FPGA Remote Debug + +All configuration parameters is taken by vdev_ifpga_cfg driver. Besides +configuration, vdev_ifpga_cfg driver also hot plugin AFUs in IFPGA Bus. + +All of the AFUs of one FPGA may share same PCI BDF and AFUs scan depend on +IFPGA Rawdev Driver so IFPGA Bus takes AFU device scan and AFU drivers probe. +All AFU device driver bind to AFU device by its UUID(Universally Unique +Identifier). + +To avoid unnecessary code duplication and ensure maximum performance, +handling of AFU devices is left to different PMDs; all the design as +summarized by the following block diagram:: + + +---------------------------------------------------------------+ + | Application(s) | + +----------------------------.----------------------------------+ + | + | + +----------------------------'----------------------------------+ + | DPDK Framework (APIs) | + +----------|------------|--------.---------------------|--------+ + / \ | + / \ | + +-------'-------+ +-------'-------+ +--------'--------+ + | Eth PMD | | Crypto PMD | | | + +-------.-------+ +-------.-------+ | | + | | | | + | | | | + +-------'-------+ +-------'-------+ | IFPGA | + | Eth AFU Dev | |Crypto AFU Dev | | Rawdev Driver | + +-------.-------+ +-------.-------+ |(OPAE Share Code)| + | | | | + | | Rawdev | | + +-------'------------------'-------+ Ops | | + | IFPGA Bus | -------->| | + +-----------------.----------------+ +--------.--------+ + | | + Hot-plugin -->| | + | | + +-----------------'------------------+ +--------'--------+ + | vdev_ifpga_cfg driver | | Intel FpgaDev | + +------------------------------------+ +-----------------+ + +Build options +------------- + +- ``CONFIG_RTE_LIBRTE_IFPGA_BUS`` (default ``y``) + + Toggle compilation of IFPGA Bus library. + +- ``CONFIG_RTE_LIBRTE_IFPGA_RAWDEV`` (default ``y``) + + Toggle compilation of the ``ifpga_rawdev`` driver. + +Run-time parameters +------------------- + +This driver is invoked automatically in systems added Intel FPGA system, +but PR and IFPGA Bus scan is trigged by command line using +``--vdev 'net_ifpga_cfg`` EAL option. + +The following device parameters are supported: + +- ``ifpga`` [string] + + Provide a specific Intel FPGA device PCI BDF. Can be provided multiple + times for additional instances. + +- ``port`` [int] + + Each FPGA can provide many channels to PR AFU by software, each channels + is identified by this parameter. + +- ``afu_bts`` [string] + + If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and + identifies AFU Bit Stream file. \ No newline at end of file diff --git a/doc/guides/rawdevs/index.rst b/doc/guides/rawdevs/index.rst new file mode 100644 index 0000000..cdee371 --- /dev/null +++ b/doc/guides/rawdevs/index.rst @@ -0,0 +1,11 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2018 Intel Corporation + +Raw Device Drivers +======================= + +.. toctree:: + :maxdepth: 2 + :numbered: + + ifpga_rawdev \ No newline at end of file diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst index cd958c1..9e554ea 100644 --- a/doc/guides/rel_notes/release_18_05.rst +++ b/doc/guides/rel_notes/release_18_05.rst @@ -140,6 +140,19 @@ New Features stats/xstats on shared memory from secondary process, and also pdump packets on those virtual devices. +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** + + The Ifpga Bus library provides support for integrating any Intel FPGA device with + the DPDK framework. It provides Intel FPGA Partial Bit Stream AFU(Accelerated + Function Unit) scan and drivers prove. + +* **Added IFPGA(Intel FPGA) Rawdev Driver.** + + Added a new Rawdev driver called IFPGA(Intel FPGA) Rawdev Driver, which cooperates + with OPAE(Open Programmable Acceleration Engine) share code provides common FPGA + management ops for FPGA operation. + + See the :doc:`../rawdevs/ifpga_rawdev` programmer's guide for more details. API Changes ----------- -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v7 0/5] Introduce Intel FPGA BUS 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (9 preceding siblings ...) 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 0/5] " Xu, Rosen @ 2018-05-04 14:10 ` Xu, Rosen 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 1/5] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen ` (4 more replies) 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 0/5] Introduce Intel FPGA BUS Xu, Rosen ` (6 subsequent siblings) 17 siblings, 5 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-04 14:10 UTC (permalink / raw) To: dev Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset=y, Size: 9129 bytes --] From: "Xu, Rosen" <rosen.xu@intel.com> Intel FPGA BUS in DPDK ------------------------- This patch set introduces Intel FPGA BUS support in DPDK. v7 updates: ========== - Fix some comments from DPDK community - Fix the CLANG compile error - Fix the meson build warring. v6 updates: =========== - Add documentation - Add meson build script - Split new patch for OPAE share code v5 updates: =========== - Fixed SHARED LIB Build issue - Changed command name to IFPGA Rawdev name, so remove pci library datastruct and function. - Fixed PATCH v2/v3/v4 comments v4 updates: =========== - Remove all modifications from eal - Create vdev to take IFPGA parameters configuration - AFU Device Driver bind to AFU Device by uuid - Take more test in scenario of Multi-FPGA System v3 updates: =========== - Remove all modifications of bus scan and probe - FPGA BUS Scan is trigged by hotplug of Rawdev - Took Modifications of comments - Move AFU Device to IFPGA - FPGA BUS Scan depend on it¡¯s IFPGA Rawdev - Add Build Macros for FPGA BUS and IFPGA Rawdev Questions ========= Why not PCI Bus? All of the AFUs of one FPGA may share same PCI BDF. Why not vdev Bus? Because AFUs depend on Rawdev, and it's hardware specpic. Motivation ========== FPGA is used more and more widely in Cloud and NFV, one primary reason is that FPGA not only provide ASIC performance but also it's more flexible than ASIC. FPGA use Partial Reconfigure(PR) Parts of Bitstream to achieve its flexibility. Another reason is that one FPGA can be shared by different Users, and each User can use some of AFUs of One FPGA. That means One FPGA Device Bitstream is divided into many Parts of Bitstream(each Part of Bitstream is defined as AFU-Accelerated Function Unit), and each AFU is a Hardware Acceleration Unit and it can dynamically Reload respectively. Proposed Solution ================= - Involve Rawdev to take FPGA Partial Configuration(Download/PR) - Defined FPGA-BUS for Acceleration Drivers of AFUs - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver. FPGA-BUS scan is called, but AFU depend on Rawdev, so this scan doesn't trig AFU device create. - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their dirves are also probed. Scope ===== The Intel FPGA BUS implementation is target towards various FPGA Devices use PR to provide many Acceleration Function. Specific PMDs may also bind to its AFU. And Applications don't care they are using ASIC Acceleration or FPGA AFU Acceleration. Status ===== With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable Acceleration Engine) Share Code, Intel FPGA BUS runs well in Intel PSG FPGA Cards. Figo Zhang (2): iFPGA: add meson build iFPGA: add document for iFPGA driver Rosen Xu (3): bus/ifpga: Add Intel FPGA BUS Library iFPGA: Add Intel FPGA OPAE Share Code iFPGA: Add Intel FPGA BUS Rawdev Driver config/common_base | 6 + doc/guides/index.rst | 1 + doc/guides/rawdevs/ifpga_rawdev.rst | 112 ++ doc/guides/rawdevs/index.rst | 11 + doc/guides/rel_notes/release_18_05.rst | 13 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 + drivers/bus/ifpga/ifpga_bus.c | 500 ++++++ drivers/bus/ifpga/ifpga_common.c | 88 ++ drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 + drivers/bus/ifpga/meson.build | 8 + drivers/bus/ifpga/rte_bus_ifpga.h | 160 ++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/bus/meson.build | 2 +- drivers/meson.build | 3 +- drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 + drivers/raw/ifpga_rawdev/base/Makefile | 30 + drivers/raw/ifpga_rawdev/base/README | 31 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 294 ++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 28 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 57 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1661 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 824 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 11 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 314 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 164 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 734 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 301 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 403 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 715 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 372 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 127 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 408 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 165 ++ drivers/raw/ifpga_rawdev/base/meson.build | 34 + drivers/raw/ifpga_rawdev/base/opae_debug.c | 99 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 19 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 381 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 253 +++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 145 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 279 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 81 + .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 75 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 45 + drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 599 +++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 + drivers/raw/ifpga_rawdev/meson.build | 15 + .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + drivers/raw/meson.build | 6 + mk/rte.app.mk | 3 + 52 files changed, 9745 insertions(+), 2 deletions(-) create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst create mode 100644 doc/guides/rawdevs/index.rst create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/meson.build create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/README create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/meson.build create mode 100644 drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map create mode 100644 drivers/raw/meson.build -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v7 1/5] bus/ifpga: Add Intel FPGA BUS Library 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 0/5] Introduce Intel FPGA BUS Xu, Rosen @ 2018-05-04 14:10 ` Xu, Rosen 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 2/5] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen ` (3 subsequent siblings) 4 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-04 14:10 UTC (permalink / raw) To: dev Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: Rosen Xu <rosen.xu@intel.com> Defined FPGA-BUS for Acceleration Drivers of AFUs 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver, it will be covered in following patches. 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their drivers are also probed. This patch will introduce rte_afu_device which describe the AFU device listed in the FPGA-BUS. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Figo zhang <tianfei.zhang@intel.com> --- config/common_base | 5 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 ++ drivers/bus/ifpga/ifpga_bus.c | 500 ++++++++++++++++++++++++++++ drivers/bus/ifpga/ifpga_common.c | 88 +++++ drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 ++ drivers/bus/ifpga/meson.build | 8 + drivers/bus/ifpga/rte_bus_ifpga.h | 160 +++++++++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/bus/meson.build | 2 +- mk/rte.app.mk | 2 + 12 files changed, 856 insertions(+), 1 deletion(-) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/meson.build create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map diff --git a/config/common_base b/config/common_base index 03a8688..bd4b356 100644 --- a/config/common_base +++ b/config/common_base @@ -149,6 +149,11 @@ CONFIG_RTE_LIBRTE_PCI_BUS=y CONFIG_RTE_LIBRTE_VDEV_BUS=y # +# Compile the Intel FPGA bus +# +CONFIG_RTE_LIBRTE_IFPGA_BUS=y + +# # Compile ARK PMD # CONFIG_RTE_LIBRTE_ARK_PMD=y diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index c251b65..cff3567 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -9,5 +9,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc endif DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile new file mode 100644 index 0000000..3ff3bdb --- /dev/null +++ b/drivers/bus/ifpga/Makefile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_bus_ifpga.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_kvargs + +# versioning export map +EXPORT_MAP := rte_bus_ifpga_version.map + +# library version +LIBABIVER := 1 + +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c + +# +# Export include files +# +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index 0000000..8453af5 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -0,0 +1,500 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_bus_logtype; + +/* Forward declaration to access Intel FPGA bus + * on which iFPGA devices are connected + */ +static struct rte_bus rte_ifpga_bus; + +/** Double linked list of IFPGA device. */ +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); + +static struct ifpga_device_list ifpga_device_list = + TAILQ_HEAD_INITIALIZER(ifpga_device_list); +static struct afu_driver_list afu_driver_list = + TAILQ_HEAD_INITIALIZER(afu_driver_list); + + +/* register a ifpga bus based driver */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver) +{ + RTE_VERIFY(driver); + + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); +} + +/* un-register a fpga bus based driver */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) +{ + TAILQ_REMOVE(&afu_driver_list, driver, next); +} + +static struct rte_ifpga_device * +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + if (rdev && + ifpga_dev->rdev && + ifpga_dev->rdev == rdev) + return ifpga_dev; + } + return NULL; +} + +static struct rte_afu_device * +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, + const struct rte_afu_id *afu_id) +{ + struct rte_afu_device *afu_dev = NULL; + + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) + return afu_dev; + } + return NULL; +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static struct rte_afu_device * +ifpga_scan_one(struct rte_devargs *devargs, + struct rte_ifpga_device *ifpga_dev) +{ + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_afu_pr_conf afu_pr_conf; + int ret = 0; + char *path = NULL; + + memset(&afu_pr_conf, 0, sizeof(struct rte_afu_pr_conf)); + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, + &ifpga_get_string_arg, &path) < 0) { + IFPGA_BUS_ERR("Failed to parse %s", + IFPGA_AFU_BTS); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_AFU_BTS); + goto end; + } + + afu_pr_conf.afu_id.uuid.uuid_low = 0; + afu_pr_conf.afu_id.uuid.uuid_high = 0; + afu_pr_conf.pr_enable = path?1:0; + + rawdev = ifpga_dev->rdev; + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) + goto end; + + afu_dev = calloc(1, sizeof(*afu_dev)); + if (!afu_dev) + goto end; + + afu_dev->device.devargs = devargs; + afu_dev->device.numa_node = SOCKET_ID_ANY; + afu_dev->device.name = devargs->name; + afu_dev->rawdev = rawdev; + afu_dev->id.uuid.uuid_low = 0; + afu_dev->id.uuid.uuid_high = 0; + afu_dev->id.port = afu_pr_conf.afu_id.port; + afu_dev->ifpga_dev = ifpga_dev; + + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); + + if (rawdev->dev_ops && + rawdev->dev_ops->dev_start && + rawdev->dev_ops->dev_start(rawdev)) + goto free_dev; + + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); + if (rawdev->dev_ops->firmware_load && + rawdev->dev_ops->firmware_load(rawdev, + &afu_pr_conf)){ + IFPGA_BUS_ERR("firmware load error %d\n", ret); + goto free_dev; + } + afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; + afu_dev->id.uuid.uuid_high = afu_pr_conf.afu_id.uuid.uuid_high; + + return afu_dev; + +free_dev: + free(afu_dev); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (path) + free(path); + + return NULL; +} + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static int +ifpga_scan(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + char *name = NULL; + char name1[RTE_RAWDEV_NAME_MAX_LEN]; + struct rte_afu_device *afu_dev = NULL; + + /* for FPGA devices we scan the devargs_list populated via cmdline */ + RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { + if (devargs->bus != &rte_ifpga_bus) + continue; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &ifpga_get_string_arg, &name) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + memset(name1, 0, sizeof(name1)); + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", name); + + rawdev = rte_rawdev_pmd_get_named_dev(name1); + if (!rawdev) + goto end; + + if (ifpga_find_ifpga_dev(rawdev)) + continue; + + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); + if (!ifpga_dev) + goto end; + + ifpga_dev->rdev = rawdev; + TAILQ_INIT(&ifpga_dev->afu_list); + + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); + afu_dev = ifpga_scan_one(devargs, ifpga_dev); + if (afu_dev != NULL) + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, next); + } + +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +/* + * Match the AFU Driver and AFU Device using the ID Table + */ +static int +rte_afu_match(const struct rte_afu_driver *afu_drv, + const struct rte_afu_device *afu_dev) +{ + const struct rte_afu_uuid *id_table; + + for (id_table = afu_drv->id_table; + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); + id_table++) { + /* check if device's identifiers match the driver's ones */ + if ((id_table->uuid_low != afu_dev->id.uuid.uuid_low) || + id_table->uuid_high != + afu_dev->id.uuid.uuid_high) + continue; + + return 1; + } + + return 0; +} + +static int +ifpga_probe_one_driver(struct rte_afu_driver *drv, + struct rte_afu_device *afu_dev) +{ + int ret; + + if (!rte_afu_match(drv, afu_dev)) + /* Match of device and driver failed */ + return 1; + + /* reference driver structure */ + afu_dev->driver = drv; + afu_dev->device.driver = &drv->driver; + + /* call the driver probe() function */ + ret = drv->probe(afu_dev); + if (ret) { + afu_dev->driver = NULL; + afu_dev->device.driver = NULL; + } + + return ret; +} + +static int +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) +{ + struct rte_afu_driver *drv = NULL; + int ret = 0; + + if (afu_dev == NULL) + return -1; + + /* Check if a driver is already loaded */ + if (afu_dev->driver != NULL) + return 0; + + TAILQ_FOREACH(drv, &afu_driver_list, next) { + if (ifpga_probe_one_driver(drv, afu_dev)) { + ret = -1; + break; + } + } + return ret; +} + +/* + * Scan the content of the Intel FPGA bus, and call the probe() function for + * all registered drivers that have a matching entry in its id_table + * for discovered devices. + */ +static int +ifpga_probe(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev = NULL; + int ret = 0; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + + if (afu_dev->device.driver) + continue; + + ret = ifpga_probe_all_drivers(afu_dev); + if (ret < 0) + IFPGA_BUS_ERR("failed to initialize %s device\n", + rte_ifpga_device_name(afu_dev)); + } + } + + return ret; +} + +static int +ifpga_plug(struct rte_device *dev) +{ + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); +} + +static int ifpga_remove_driver(struct rte_afu_device *afu_dev) +{ + const char *name; + const struct rte_afu_driver *driver; + + name = rte_ifpga_device_name(afu_dev); + if (!afu_dev->device.driver) { + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); + return 1; + } + + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); + return driver->remove(afu_dev); +} + +static int +ifpga_unplug(struct rte_device *dev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_devargs *devargs = NULL; + int ret; + + if (dev == NULL) + return -EINVAL; + + afu_dev = RTE_DEV_TO_AFU(dev); + if (!dev) + return -ENOENT; + + ifpga_dev = afu_dev->ifpga_dev; + devargs = dev->devargs; + + ret = ifpga_remove_driver(afu_dev); + if (ret) + return ret; + + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); + + rte_devargs_remove(devargs->bus->name, devargs->name); + free(afu_dev); + return 0; + +} + +static struct rte_device * +ifpga_find_device(const struct rte_device *start, + rte_dev_cmp_t cmp, const void *data) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (start && &afu_dev->device == start) { + start = NULL; + continue; + } + if (cmp(&afu_dev->device, data) == 0) + return &afu_dev->device; + } + } + return NULL; +} +static int +ifpga_parse(const char *name, void *addr) +{ + int *out = addr; + struct rte_rawdev *rawdev = NULL; + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; + char *c1 = NULL, *c2 = NULL; + int port = IFPGA_BUS_DEV_PORT_MAX; + char str_port[8]; + int str_port_len = 0; + int ret; + + memset(str_port, 0, 8); + c1 = strchr(name, '|'); + if (c1 != NULL) { + str_port_len = c1-name; + c2 = c1+1; + } + + if (str_port_len < 8 && + str_port_len > 0) { + memcpy(str_port, name, str_port_len); + ret = sscanf(str_port, "%d", &port); + if (ret == -1) + return 0; + } + + memset(rawdev_name, 0, sizeof(rawdev_name)); + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", c2); + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev && + (addr != NULL)) + *out = port; + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev) + return 0; + else + return 1; +} + +static struct rte_bus rte_ifpga_bus = { + .scan = ifpga_scan, + .probe = ifpga_probe, + .find_device = ifpga_find_device, + .plug = ifpga_plug, + .unplug = ifpga_unplug, + .parse = ifpga_parse, +}; + +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); + +RTE_INIT(ifpga_init_log) +{ + ifpga_bus_logtype = rte_log_register("bus.ifpga"); + if (ifpga_bus_logtype >= 0) + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); +} diff --git a/drivers/bus/ifpga/ifpga_common.c b/drivers/bus/ifpga/ifpga_common.c new file mode 100644 index 0000000..b4efc20 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(char **)extra_args = strdup(value); + + if (!*(char **)extra_args) + return -ENOMEM; + + return 0; +} +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(int *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(uint64_t *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_unsigned_long(const char *str, int base) +{ + unsigned long num; + char *end = NULL; + + errno = 0; + + num = strtoul(str, &end, base); + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) + return -1; + + return num; +} + +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1) +{ + if ((afu_id0->uuid.uuid_low == afu_id1->uuid.uuid_low) && + (afu_id0->uuid.uuid_high == afu_id1->uuid.uuid_high) && + (afu_id0->port == afu_id1->port)) { + return 0; + } else + return 1; +} diff --git a/drivers/bus/ifpga/ifpga_common.h b/drivers/bus/ifpga/ifpga_common.h new file mode 100644 index 0000000..b6662c8 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMMON_H_ +#define _IFPGA_COMMON_H_ + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_unsigned_long(const char *str, int base); +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1); + +#endif /* _IFPGA_COMMON_H_ */ diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index 0000000..873e0a4 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_logs.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_LOGS_H_ +#define _IFPGA_LOGS_H_ + +#include <rte_log.h> + +extern int ifpga_bus_logtype; + +#define IFPGA_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") + +#define IFPGA_BUS_DEBUG(fmt, args...) \ + IFPGA_BUS_LOG(DEBUG, fmt, ## args) +#define IFPGA_BUS_INFO(fmt, args...) \ + IFPGA_BUS_LOG(INFO, fmt, ## args) +#define IFPGA_BUS_ERR(fmt, args...) \ + IFPGA_BUS_LOG(ERR, fmt, ## args) +#define IFPGA_BUS_WARN(fmt, args...) \ + IFPGA_BUS_LOG(WARNING, fmt, ## args) + +#endif /* _IFPGA_BUS_LOGS_H_ */ diff --git a/drivers/bus/ifpga/meson.build b/drivers/bus/ifpga/meson.build new file mode 100644 index 0000000..c9b08c8 --- /dev/null +++ b/drivers/bus/ifpga/meson.build @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2018 Intel Corporation + +deps += ['pci', 'kvargs', 'rawdev'] +install_headers('rte_bus_ifpga.h') +sources = files('ifpga_common.c', 'ifpga_bus.c') + +allow_experimental_apis = true diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h new file mode 100644 index 0000000..5c559e1 --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga.h @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _RTE_BUS_IFPGA_H_ +#define _RTE_BUS_IFPGA_H_ + +/** + * @file + * + * RTE Intel FPGA Bus Interface + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_bus.h> +#include <rte_pci.h> + +/** Name of Intel FPGA Bus */ +#define IFPGA_BUS_NAME ifpga + +/* Forward declarations */ +struct rte_afu_device; + +/** List of Intel AFU devices */ +TAILQ_HEAD(afu_device_list, rte_afu_device); +/** Double linked list of AFU device drivers. */ +TAILQ_HEAD(afu_driver_list, rte_afu_driver); + +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 + +struct rte_afu_uuid { + uint64_t uuid_low; + uint64_t uuid_high; +} __attribute__ ((packed)); + +#define IFPGA_BUS_DEV_PORT_MAX 4 + +/** + * A structure describing an ID for a AFU driver. Each driver provides a + * table of these IDs for each device that it supports. + */ +struct rte_afu_id { + struct rte_afu_uuid uuid; + int port; /**< port number */ +} __attribute__ ((packed)); + +/** + * A structure PR (Partial Reconfiguration) configuration AFU driver. + */ + +struct rte_afu_pr_conf { + struct rte_afu_id afu_id; + int pr_enable; + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +}; + +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) + +/** + * A structure describing a fpga device. + */ +struct rte_ifpga_device { + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ + struct rte_rawdev *rdev; + struct afu_device_list afu_list; /**< List of AFU devices */ +}; + +/** + * A structure describing a AFU device. + */ +struct rte_afu_device { + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ + struct rte_device device; /**< Inherit core device */ + struct rte_rawdev *rawdev; /**< Point Rawdev */ + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ + struct rte_afu_id id; /**< AFU id within FPGA. */ + uint32_t num_region; /**< number of regions found */ + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; + /**< AFU Memory Resource */ + struct rte_intr_handle intr_handle; /**< Interrupt handle */ + struct rte_afu_driver *driver; /**< Associated driver */ + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +} __attribute__ ((packed)); + +/** + * @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_DRV_TO_AFU_CONST(ptr) \ + container_of(ptr, const struct rte_afu_driver, driver) + +/** + * Initialisation function for the driver called during FPGA BUS probing. + */ +typedef int (afu_probe_t)(struct rte_afu_device *); + +/** + * Uninitialisation function for the driver called during hotplugging. + */ +typedef int (afu_remove_t)(struct rte_afu_device *); + +/** + * A structure describing a AFU device. + */ +struct rte_afu_driver { + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ + struct rte_driver driver; /**< Inherit core driver. */ + afu_probe_t *probe; /**< Device Probe function. */ + afu_remove_t *remove; /**< Device Remove function. */ + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ + uint32_t drv_flags; /**< Flags contolling handling of device. */ +}; + +static inline const char * +rte_ifpga_device_name(const struct rte_afu_device *afu) +{ + if (afu && afu->device.name) + return afu->device.name; + return NULL; +} + +/** + * Register a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be registered. + */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver); + +/** + * Unregister a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be unregistered. + */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); + +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ +RTE_INIT(afudrvinitfn_ ##afudrv);\ +static const char *afudrvinit_ ## nm ## _alias;\ +static void afudrvinitfn_ ##afudrv(void)\ +{\ + (afudrv).driver.name = RTE_STR(nm);\ + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ + rte_ifpga_driver_register(&afudrv);\ +} \ +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) + +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ +static const char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) + +#endif /* _RTE_BUS_IFPGA_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map new file mode 100644 index 0000000..1304caf --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map @@ -0,0 +1,10 @@ +DPDK_18.05 { + global: + + ifpga_get_integer32_arg; + ifpga_get_string_arg; + rte_ifpga_driver_register; + rte_ifpga_driver_unregister; + + local: *; +}; diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build index 58dfbe2..170df25 100644 --- a/drivers/bus/meson.build +++ b/drivers/bus/meson.build @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel Corporation -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] +drivers = ['dpaa', 'fslmc', 'pci', 'vdev', 'ifpga'] std_deps = ['eal'] config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' driver_name_fmt = 'rte_bus_@0@' diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 29a2a60..f47bbe8 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -107,6 +107,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE) += -lrte_cmdline _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrte_sched +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga + ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v7 2/5] iFPGA: Add Intel FPGA OPAE Share Code 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 0/5] Introduce Intel FPGA BUS Xu, Rosen 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 1/5] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen @ 2018-05-04 14:10 ` Xu, Rosen 2018-05-04 14:11 ` [dpdk-dev] [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen ` (2 subsequent siblings) 4 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-04 14:10 UTC (permalink / raw) To: dev Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Xu, Yilun [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset=y, Size: 221656 bytes --] From: Rosen Xu <rosen.xu@intel.com> This patch adds Intel FPGA Open Programmable Acceleration Engine (OPAE)[1] base driver code, in order to support Intel FPGA devices under DPDK. The base code currently supports Intel FPGA solutions including integrated solution (Intel(R) Xeon(R) CPU with FPGAs) and discrete solution (Intel(R) Programmable Acceleration Card with Intel(R) Arria(R) 10 FPGA) and it could be extended to support more FPGA devices in the future. Please refer to [1][2] for more introduction on OPAE and Intel FPGAs. [1] https://01.org/OPAE [2] https://www.altera.com/solutions/acceleration-hub/overview.html Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> Signed-off-by: Wu, Hao <hao.wu@intel.com> Signed-off-by: Xu, Yilun <yilun.xu@intel.com> --- drivers/raw/ifpga_rawdev/base/Makefile | 30 + drivers/raw/ifpga_rawdev/base/README | 31 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 294 ++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 28 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 57 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1661 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 824 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 11 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 314 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 164 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 734 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 301 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 403 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 715 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 372 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 127 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 408 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 165 ++ drivers/raw/ifpga_rawdev/base/opae_debug.c | 99 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 19 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 381 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 253 +++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 145 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 279 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 81 + .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 75 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 45 + 27 files changed, 8016 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/README create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile new file mode 100644 index 0000000..ade3551 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -0,0 +1,30 @@ +#SPDX-License-Identifier: BSD-3-Clause +#Copyright(c) 2010-2018 Intel Corporation + +ifneq ($(CONFIG_RTE_LIBRTE_EAL),) +OSDEP := osdep_rte +else +OSDEP := osdep_raw +endif + +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev/base/$(OSDEP) + +SRCS-y += ifpga_api.c +SRCS-y += ifpga_enumerate.c +SRCS-y += ifpga_feature_dev.c +SRCS-y += ifpga_fme.c +SRCS-y += ifpga_fme_iperf.c +SRCS-y += ifpga_fme_dperf.c +SRCS-y += ifpga_fme_error.c +SRCS-y += ifpga_port.c +SRCS-y += ifpga_port_error.c +SRCS-y += opae_hw_api.c +SRCS-y += opae_ifpga_hw_api.c +SRCS-y += opae_debug.c +SRCS-y += ifpga_fme_pr.c + +ifeq ($(CONFIG_RTE_TOOLCHAIN_CLANG),y) + CFLAGS_ifpga_fme_pr.o += -march=knl +endif + +SRCS-y += $(wildcard $(SRCDIR)/base/$(OSDEP)/*.c) diff --git a/drivers/raw/ifpga_rawdev/base/README b/drivers/raw/ifpga_rawdev/base/README new file mode 100644 index 0000000..3636ac7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/README @@ -0,0 +1,31 @@ +.. + +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +Intel® iFPGA driver +================== + +This directory contains source code of Intel FPGA driver released by +the team which develops Intel FPGA Open Programmable Acceleration Engine (OPAE). +The directory of base/ contains the original source package. The base code +currently supports Intel FPGA solutions including integrated solution (Intel(R) +Xeon(R) CPU with FPGAs) and discrete solution (Intel(R) Programmable Acceleration +Card with Intel(R) Arria(R) 10 FPGA) and it could be extended to support more FPGA +devices in the future. + +Please refer to [1][2] for more introduction on OPAE and Intel FPGAs. + +[1] https://01.org/OPAE +[2] https://www.altera.com/solutions/acceleration-hub/overview.html + + +Updating the driver +=================== + +NOTE: The source code in this directory should not be modified apart from +the following file(s): + + osdep_raw/osdep_generic.h + osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.c b/drivers/raw/ifpga_rawdev/base/ifpga_api.c new file mode 100644 index 0000000..540e171 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -0,0 +1,294 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_api.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +#include "opae_hw_api.h" + +/* Accelerator APIs */ +static int ifpga_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return fpga_get_afu_uuid(port, uuid); +} + +static int ifpga_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + struct fpga_uafu_irq_set irq_set; + + if (!br || !br->data) + return -EINVAL; + + if (start >= afu_info->num_irqs || start + count > afu_info->num_irqs) + return -EINVAL; + + port = br->data; + + irq_set.start = start; + irq_set.count = count; + irq_set.evtfds = evtfds; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_UINT, &irq_set); +} + +static int ifpga_acc_get_info(struct opae_accelerator *acc, + struct opae_acc_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -ENODEV; + + info->num_regions = afu_info->num_regions; + info->num_irqs = afu_info->num_irqs; + + return 0; +} + +static int ifpga_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -EINVAL; + + if (info->index >= afu_info->num_regions) + return -EINVAL; + + /* always one RW region only for AFU now */ + info->flags = ACC_REGION_READ | ACC_REGION_WRITE | ACC_REGION_MMIO; + info->len = afu_info->region[info->index].len; + info->addr = afu_info->region[info->index].addr; + + return 0; +} + +static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + switch (byte) { + case 8: + *(u64 *)data = opae_readq(region->addr + offset); + break; + case 4: + *(u32 *)data = opae_readl(region->addr + offset); + break; + case 2: + *(u16 *)data = opae_readw(region->addr + offset); + break; + case 1: + *(u8 *)data = opae_readb(region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ifpga_acc_write(struct opae_accelerator *acc, + unsigned int region_idx, u64 offset, + unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + /* normal mmio case */ + switch (byte) { + case 8: + opae_writeq(*(u64 *)data, region->addr + offset); + break; + case 4: + opae_writel(*(u32 *)data, region->addr + offset); + break; + case 2: + opae_writew(*(u16 *)data, region->addr + offset); + break; + case 1: + opae_writeb(*(u8 *)data, region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +struct opae_accelerator_ops ifpga_acc_ops = { + .read = ifpga_acc_read, + .write = ifpga_acc_write, + .set_irq = ifpga_acc_set_irq, + .get_info = ifpga_acc_get_info, + .get_region_info = ifpga_acc_get_region_info, + .get_uuid = ifpga_acc_get_uuid, +}; + +/* Bridge APIs */ + +static int ifpga_br_reset(struct opae_bridge *br) +{ + struct ifpga_port_hw *port = br->data; + + return fpga_port_reset(port); +} + +struct opae_bridge_ops ifpga_br_ops = { + .reset = ifpga_br_reset, +}; + +/* Manager APIs */ +static int ifpga_mgr_flash(struct opae_manager *mgr, int id, void *buf, + u32 size, u64 *status) +{ + struct ifpga_fme_hw *fme = mgr->data; + struct ifpga_hw *hw = fme->parent; + + return ifpga_pr(hw, id, buf, size, status); +} + +struct opae_manager_ops ifpga_mgr_ops = { + .flash = ifpga_mgr_flash, +}; + +/* Adapter APIs */ +static int ifpga_adapter_enumerate(struct opae_adapter *adapter) +{ + struct ifpga_hw *hw = malloc(sizeof(*hw)); + + if (hw) { + memset(hw, 0, sizeof(*hw)); + hw->pci_data = adapter->data; + hw->adapter = adapter; + if (ifpga_bus_enumerate(hw)) + goto error; + return ifpga_bus_init(hw); + } + +error: + return -ENOMEM; +} + +struct opae_adapter_ops ifpga_adapter_ops = { + .enumerate = ifpga_adapter_enumerate, +}; + +/** + * ifpga_pr - do the partial reconfiguration for a given port device + * @hw: pointer to the HW structure + * @port_id: the port device id + * @buffer: the buffer of the bitstream + * @size: the size of the bitstream + * @status: hardware status including PR error code if return -EIO. + * + * @return + * - 0: Success, partial reconfiguration finished. + * - <0: Error code returned in partial reconfiguration. + **/ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return do_pr(hw, port_id, buffer, size, status); +} + +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_get_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_get_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set) +{ + if (!hw || !irq_set) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_irq(&hw->fme, feature_id, irq_set); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_irq(&hw->port[port_id], feature_id, irq_set); + } + + return -ENOENT; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.h b/drivers/raw/ifpga_rawdev/base/ifpga_api.h new file mode 100644 index 0000000..dae7ca1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_API_H_ +#define _IFPGA_API_H_ + +#include "opae_hw_api.h" +#include "ifpga_hw.h" + +extern struct opae_adapter_ops ifpga_adapter_ops; +extern struct opae_manager_ops ifpga_mgr_ops; +extern struct opae_bridge_ops ifpga_br_ops; +extern struct opae_accelerator_ops ifpga_acc_ops; + +/* common APIs */ +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set); + +/* FME APIs */ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +#endif /* _IFPGA_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_compat.h b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h new file mode 100644 index 0000000..78b904e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMPAT_H_ +#define _IFPGA_COMPAT_H_ + +#include "opae_osdep.h" + +#undef container_of +#define container_of(ptr, type, member) ({ \ + typeof(((type *)0)->member)(*__mptr) = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) +#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE) + +#define readl(addr) opae_readl(addr) +#define readq(addr) opae_readq(addr) +#define writel(value, addr) opae_writel(value, addr) +#define writeq(value, addr) opae_writeq(value, addr) + +#define malloc(size) opae_malloc(size) +#define zmalloc(size) opae_zmalloc(size) +#define free(size) opae_free(size) + +/* + * Wait register's _field to be changed to the given value (_expect's _field) + * by polling with given interval and timeout. + */ +#define fpga_wait_register_field(_field, _expect, _reg_addr, _timeout, _invl)\ +({ \ + int wait = 0; \ + int ret = -ETIMEDOUT; \ + typeof(_expect) value; \ + for (; wait <= _timeout; wait += _invl) { \ + value.csr = readq(_reg_addr); \ + if (_expect._field == value._field) { \ + ret = 0; \ + break; \ + } \ + udelay(_invl); \ + } \ + ret; \ +}) + +#define __maybe_unused __attribute__((__unused__)) + +#define UNUSED(x) (void)(x) + +#endif /* _IFPGA_COMPAT_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h new file mode 100644 index 0000000..8989280 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -0,0 +1,1661 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_DEFINES_H_ +#define _IFPGA_DEFINES_H_ + +#include "ifpga_compat.h" + +#define MAX_FPGA_PORT_NUM 4 + +#define FME_FEATURE_HEADER "fme_hdr" +#define FME_FEATURE_THERMAL_MGMT "fme_thermal" +#define FME_FEATURE_POWER_MGMT "fme_power" +#define FME_FEATURE_GLOBAL_IPERF "fme_iperf" +#define FME_FEATURE_GLOBAL_ERR "fme_error" +#define FME_FEATURE_PR_MGMT "fme_pr" +#define FME_FEATURE_HSSI_ETH "fme_hssi" +#define FME_FEATURE_GLOBAL_DPERF "fme_dperf" +#define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" + +#define PORT_FEATURE_HEADER "port_hdr" +#define PORT_FEATURE_UAFU "port_uafu" +#define PORT_FEATURE_ERR "port_err" +#define PORT_FEATURE_UMSG "port_umsg" +#define PORT_FEATURE_PR "port_pr" +#define PORT_FEATURE_UINT "port_uint" +#define PORT_FEATURE_STP "port_stp" + +/* + * do not check the revision id as id may be dynamic under + * some cases, e.g, UAFU. + */ +#define SKIP_REVISION_CHECK 0xff + +#define FME_HEADER_REVISION 1 +#define FME_THERMAL_MGMT_REVISION 0 +#define FME_POWER_MGMT_REVISION 1 +#define FME_GLOBAL_IPERF_REVISION 1 +#define FME_GLOBAL_ERR_REVISION 1 +#define FME_PR_MGMT_REVISION 2 +#define FME_HSSI_ETH_REVISION 0 +#define FME_GLOBAL_DPERF_REVISION 0 +#define FME_QSPI_REVISION 0 + +#define PORT_HEADER_REVISION 0 +/* UAFU's header info depends on the downloaded GBS */ +#define PORT_UAFU_REVISION SKIP_REVISION_CHECK +#define PORT_ERR_REVISION 1 +#define PORT_UMSG_REVISION 0 +#define PORT_UINT_REVISION 0 +#define PORT_STP_REVISION 1 + +#define FEATURE_TYPE_AFU 0x1 +#define FEATURE_TYPE_BBB 0x2 +#define FEATURE_TYPE_PRIVATE 0x3 +#define FEATURE_TYPE_FIU 0x4 + +#define FEATURE_FIU_ID_FME 0x0 +#define FEATURE_FIU_ID_PORT 0x1 + +#define FEATURE_ID_HEADER 0x0 +#define FEATURE_ID_AFU 0xff + +enum fpga_id_type { + FME_ID, + PORT_ID, + 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, +}; + +/* + * All headers and structures must be byte-packed to match the spec. + */ +#pragma pack(1) + +struct feature_header { + union { + u64 csr; + struct { + u16 id:12; + u8 revision:4; + u32 next_header_offset:24; + u8 end_of_list:1; + u32 reserved:19; + u8 type:4; + }; + }; +}; + +struct feature_bbb_header { + struct uuid guid; +}; + +struct feature_afu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fiu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fme_capability { + union { + u64 csr; + struct { + u8 fabric_verid; /* Fabric version ID */ + u8 socket_id:1; /* Socket id */ + u8 rsvd1:3; /* Reserved */ + /* pci0 link available yes /no */ + u8 pci0_link_avile:1; + /* pci1 link available yes /no */ + u8 pci1_link_avile:1; + /* Coherent (QPI/UPI) link available yes /no */ + u8 qpi_link_avile:1; + u8 rsvd2:1; /* Reserved */ + /* IOMMU or VT-d supported yes/no */ + u8 iommu_support:1; + u8 num_ports:3; /* Number of ports */ + u8 sf_fab_ctl:1; /* Internal validation bit */ + u8 rsvd3:3; /* Reserved */ + /* + * Address width supported in bits + * BXT -0x26 , SKX -0x30 + */ + u8 address_width_bits:6; + u8 rsvd4:2; /* Reserved */ + /* Size of cache supported in kb */ + u16 cache_size:12; + u8 cache_assoc:4; /* Cache Associativity */ + u16 rsvd5:15; /* Reserved */ + u8 lock_bit:1; /* Lock bit */ + }; + }; +}; + +#define FME_AFU_ACCESS_PF 0 +#define FME_AFU_ACCESS_VF 1 + +struct feature_fme_port { + union { + u64 csr; + struct { + u32 port_offset:24; + u8 reserved1; + u8 port_bar:3; + u32 reserved2:20; + u8 afu_access_control:1; + u8 reserved3:4; + u8 port_implemented:1; + u8 reserved4:3; + }; + }; +}; + +struct feature_fme_fab_status { + union { + u64 csr; + struct { + u8 upilink_status:4; /* UPI Link Status */ + u8 rsvd1:4; /* Reserved */ + u8 pci0link_status:1; /* pci0 link status */ + u8 rsvd2:3; /* Reserved */ + u8 pci1link_status:1; /* pci1 link status */ + u64 rsvd3:51; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_base { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Base Address of memory range */ + u8 protected_base_addrss:4; + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_limit { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Limit Address of memory range */ + u8 protected_limit_addrss:4; + u16 rsvd2:11; /* Reserved */ + u8 enable:1; /* Enable GENPROTRANGE check */ + u32 rsvd3; /* Reserved */ + }; + }; +}; + +struct feature_fme_dxe_lock { + union { + u64 csr; + struct { + /* + * Determines write access to the DXE region CSRs + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_early_lock:1; + /* + * Determines write access to the HSSI CSR + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_late_lock:1; + u64 rsvd:62; + }; + }; +}; + +#define HSSI_ID_NO_HASSI 0 +#define HSSI_ID_PCIE_RP 1 +#define HSSI_ID_ETHERNET 2 + +struct feature_fme_bitstream_id { + union { + u64 csr; + struct { + u32 gitrepo_hash:32; /* GIT repository hash */ + /* + * HSSI configuration identifier: + * 0 - No HSSI + * 1 - PCIe-RP + * 2 - Ethernet + */ + u8 hssi_id:4; + u16 rsvd1:12; /* Reserved */ + /* Bitstream version patch number */ + u8 bs_verpatch:4; + /* Bitstream version minor number */ + u8 bs_verminor:4; + /* Bitstream version major number */ + u8 bs_vermajor:4; + /* Bitstream version debug number */ + u8 bs_verdebug:4; + }; + }; +}; + +struct feature_fme_bitstream_md { + union { + u64 csr; + struct { + /* Seed number userd for synthesis flow */ + u8 synth_seed:4; + /* Synthesis date(day number - 2 digits) */ + u8 synth_day:8; + /* Synthesis date(month number - 2 digits) */ + u8 synth_month:8; + /* Synthesis date(year number - 2 digits) */ + u8 synth_year:8; + u64 rsvd:36; /* Reserved */ + }; + }; +}; + +struct feature_fme_iommu_ctrl { + union { + u64 csr; + struct { + /* Disables IOMMU prefetcher for C0 channel */ + u8 prefetch_disableC0:1; + /* Disables IOMMU prefetcher for C1 channel */ + u8 prefetch_disableC1:1; + /* Disables IOMMU partial cache line writes */ + u8 prefetch_wrdisable:1; + u8 rsvd1:1; /* Reserved */ + /* + * Select counter and read value from register + * iommu_stat.dbg_counters + * 0 - Number of 4K page translation response + * 1 - Number of 2M page translation response + * 2 - Number of 1G page translation response + */ + u8 counter_sel:2; + u32 rsvd2:26; /* Reserved */ + /* Connected to IOMMU SIP Capabilities */ + u32 capecap_defeature; + }; + }; +}; + +struct feature_fme_iommu_stat { + union { + u64 csr; + struct { + /* Translation Enable bit from IOMMU SIP */ + u8 translation_enable:1; + /* Drain request in progress */ + u8 drain_req_inprog:1; + /* Invalidation current state */ + u8 inv_state:3; + /* C0 Response Buffer current state */ + u8 respbuffer_stateC0:3; + /* C1 Response Buffer current state */ + u8 respbuffer_stateC1:3; + /* Last request ID to IOMMU SIP */ + u8 last_reqID:4; + /* Last IOMMU SIP response ID value */ + u8 last_respID:4; + /* Last IOMMU SIP response status value */ + u8 last_respstatus:3; + /* C0 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC0:1; + /* C1 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC1:1; + /* C0 Request FIFO is not empty */ + u8 reqFIFO_notemptyC0:1; + /* C1 Request FIFO is not empty */ + u8 reqFIFO_notemptyC1:1; + /* C0 Response FIFO is not empty */ + u8 respFIFO_notemptyC0:1; + /* C1 Response FIFO is not empty */ + u8 respFIFO_notemptyC1:1; + /* C0 Response FIFO overflow detected */ + u8 respFIFO_overflowC0:1; + /* C1 Response FIFO overflow detected */ + u8 respFIFO_overflowC1:1; + /* C0 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC0:1; + /* C1 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC1:1; + /* Request FIFO overflow detected */ + u8 reqFIFO_overflow:1; + /* IOMMU memory read in progress */ + u8 memrd_inprog:1; + /* IOMMU memory write in progress */ + u8 memwr_inprog:1; + u8 rsvd1:1; /* Reserved */ + /* Value of counter selected by iommu_ctl.counter_sel */ + u16 dbg_counters:16; + u16 rsvd2:12; /* Reserved */ + }; + }; +}; + +struct feature_fme_pcie0_ctrl { + union { + u64 csr; + struct { + u64 vtd_bar_lock:1; /* Lock VT-D BAR register */ + u64 rsvd1:3; + u64 rciep:1; /* Configure PCIE0 as RCiEP */ + u64 rsvd2:59; + }; + }; +}; + +struct feature_fme_llpr_smrr_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR rule is valid or not */ + /* + * SMRR memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR2 rule is valid or not */ + /* + * SMRR2 memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_meseg_base { + union { + u64 csr; + struct { + /* A[45:19] of base address memory range */ + u64 me_base:27; + u64 rsvd:37; + }; + }; +}; + +struct feature_fme_llpr_meseg_limit { + union { + u64 csr; + struct { + /* A[45:19] of limit address memory range */ + u64 me_limit:27; + u64 rsvd1:4; + u64 enable:1; /* Enable LLPR MESEG rule */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 reserved; + u64 scratchpad; + struct feature_fme_capability capability; + struct feature_fme_port port[MAX_FPGA_PORT_NUM]; + struct feature_fme_fab_status fab_status; + struct feature_fme_bitstream_id bitstream_id; + struct feature_fme_bitstream_md bitstream_md; + struct feature_fme_genprotrange2_base genprotrange2_base; + struct feature_fme_genprotrange2_limit genprotrange2_limit; + struct feature_fme_dxe_lock dxe_lock; + struct feature_fme_iommu_ctrl iommu_ctrl; + struct feature_fme_iommu_stat iommu_stat; + struct feature_fme_pcie0_ctrl pcie0_control; + struct feature_fme_llpr_smrr_base smrr_base; + struct feature_fme_llpr_smrr_mask smrr_mask; + struct feature_fme_llpr_smrr2_base smrr2_base; + struct feature_fme_llpr_smrr2_mask smrr2_mask; + struct feature_fme_llpr_meseg_base meseg_base; + struct feature_fme_llpr_meseg_limit meseg_limit; +}; + +struct feature_port_capability { + union { + u64 csr; + struct { + u8 port_number:2; /* Port Number 0-3 */ + u8 rsvd1:6; /* Reserved */ + u16 mmio_size; /* User MMIO size in KB */ + u8 rsvd2; /* Reserved */ + u8 sp_intr_num:4; /* Supported interrupts num */ + u32 rsvd3:28; /* Reserved */ + }; + }; +}; + +struct feature_port_control { + union { + u64 csr; + struct { + u8 port_sftrst:1; /* Port Soft Reset */ + u8 rsvd1:1; /* Reserved */ + u8 latency_tolerance:1;/* '1' >= 40us, '0' < 40us */ + u8 rsvd2:1; /* Reserved */ + u8 port_sftrst_ack:1; /* HW ACK for Soft Reset */ + u64 rsvd3:59; /* Reserved */ + }; + }; +}; + +#define PORT_POWER_STATE_NORMAL 0 +#define PORT_POWER_STATE_AP1 1 +#define PORT_POWER_STATE_AP2 2 +#define PORT_POWER_STATE_AP6 6 + +struct feature_port_status { + union { + u64 csr; + struct { + u8 port_freeze:1; /* '1' - freezed '0' - normal */ + u8 rsvd1:7; /* Reserved */ + u8 power_state:4; /* Power State */ + u8 ap1_event:1; /* AP1 event was detected */ + u8 ap2_event:1; /* AP2 event was detected */ + u64 rsvd2:50; /* Reserved */ + }; + }; +}; + +/* Port Header Register Set */ +struct feature_port_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 port_mailbox; + u64 scratchpad; + struct feature_port_capability capability; + struct feature_port_control control; + struct feature_port_status status; + u64 rsvd2; + u64 user_clk_freq_cmd0; + u64 user_clk_freq_cmd1; + u64 user_clk_freq_sts0; + u64 user_clk_freq_sts1; +}; + +struct feature_fme_tmp_threshold { + union { + u64 csr; + struct { + u8 tmp_thshold1:7; /* temperature Threshold 1 */ + /* temperature Threshold 1 enable/disable */ + u8 tmp_thshold1_enable:1; + u8 tmp_thshold2:7; /* temperature Threshold 2 */ + /* temperature Threshold 2 enable /disable */ + u8 tmp_thshold2_enable:1; + u8 pro_hot_setpoint:7; /* Proc Hot set point */ + u8 rsvd4:1; /* Reserved */ + u8 therm_trip_thshold:7; /* Thermeal Trip Threshold */ + u8 rsvd3:1; /* Reserved */ + u8 thshold1_status:1; /* Threshold 1 Status */ + u8 thshold2_status:1; /* Threshold 2 Status */ + u8 rsvd5:1; /* Reserved */ + /* Thermeal Trip Threshold status */ + u8 therm_trip_thshold_status:1; + u8 rsvd6:4; /* Reserved */ + /* Validation mode- Force Proc Hot */ + u8 valmodeforce:1; + /* Validation mode - Therm trip Hot */ + u8 valmodetherm:1; + u8 rsvd2:2; /* Reserved */ + u8 thshold_policy:1; /* threshold policy */ + u32 rsvd:19; /* Reserved */ + }; + }; +}; + +/* Temperature Sensor Read values format 1 */ +struct feature_fme_temp_rdsensor_fmt1 { + union { + u64 csr; + struct { + /* Reads out FPGA temperature in celsius */ + u8 fpga_temp:7; + u8 rsvd0:1; /* Reserved */ + /* Temperature reading sequence number */ + u16 tmp_reading_seq_num; + /* Temperature reading is valid */ + u8 tmp_reading_valid:1; + u8 rsvd1:7; /* Reserved */ + u16 dbg_mode:10; /* Debug mode */ + u32 rsvd2:22; /* Reserved */ + }; + }; +}; + +/* Temperature sensor read values format 2 */ +struct feature_fme_temp_rdsensor_fmt2 { + u64 rsvd; /* Reserved */ +}; + +/* Temperature Threshold Capability Register */ +struct feature_fme_tmp_threshold_cap { + union { + u64 csr; + struct { + /* Temperature Threshold Unsupported */ + u8 tmp_thshold_disabled:1; + u64 rsvd:63; /* Reserved */ + }; + }; +}; + +/* FME THERNAL FEATURE */ +struct feature_fme_thermal { + struct feature_header header; + struct feature_fme_tmp_threshold threshold; + struct feature_fme_temp_rdsensor_fmt1 rdsensor_fm1; + struct feature_fme_temp_rdsensor_fmt2 rdsensor_fm2; + struct feature_fme_tmp_threshold_cap threshold_cap; +}; + +/* Power Status register */ +struct feature_fme_pm_status { + union { + u64 csr; + struct { + /* FPGA Power consumed, The format is to be defined */ + u32 pwr_consumed:18; + /* FPGA Latency Tolerance Reporting */ + u8 fpga_latency_report:1; + u64 rsvd:45; /* Reserved */ + }; + }; +}; + +/* AP Thresholds */ +struct feature_fme_pm_ap_threshold { + union { + u64 csr; + struct { + /* + * Number of clocks (5ns period) for assertion + * of FME_data + */ + u8 threshold1:7; + u8 rsvd1:1; + u8 threshold2:7; + u8 rsvd2:1; + u8 threshold1_status:1; + u8 threshold2_status:1; + u64 rsvd3:46; /* Reserved */ + }; + }; +}; + +/* Xeon Power Limit */ +struct feature_fme_pm_xeon_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FPGA Power Limit */ +struct feature_fme_pm_fpga_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FME POWER FEATURE */ +struct feature_fme_power { + struct feature_header header; + struct feature_fme_pm_status status; + struct feature_fme_pm_ap_threshold threshold; + struct feature_fme_pm_xeon_limit xeon_limit; + struct feature_fme_pm_fpga_limit fpga_limit; +}; + +#define CACHE_CHANNEL_RD 0 +#define CACHE_CHANNEL_WR 1 + +enum iperf_cache_events { + IPERF_CACHE_RD_HIT, + IPERF_CACHE_WR_HIT, + IPERF_CACHE_RD_MISS, + IPERF_CACHE_WR_MISS, + IPERF_CACHE_RSVD, /* reserved */ + IPERF_CACHE_HOLD_REQ, + IPERF_CACHE_DATA_WR_PORT_CONTEN, + IPERF_CACHE_TAG_WR_PORT_CONTEN, + IPERF_CACHE_TX_REQ_STALL, + IPERF_CACHE_RX_REQ_STALL, + IPERF_CACHE_EVICTIONS, +}; + +/* FPMON Cache Control */ +struct feature_fme_ifpmon_ch_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd1:7; /* Reserved */ + u8 freeze:1; /* Freeze if set to 1 */ + u8 rsvd2:7; /* Reserved */ + u8 cache_event:4; /* Select the cache event */ + u8 cci_chsel:1; /* Select the channel */ + u64 rsvd3:43; /* Reserved */ + }; + }; +}; + +/* FPMON Cache Counter */ +struct feature_fme_ifpmon_ch_ctr { + union { + u64 csr; + struct { + /* Cache Counter for even addresse */ + u64 cache_counter:48; + u16 rsvd:12; /* Reserved */ + /* Cache Event being reported */ + u8 event_code:4; + }; + }; +}; + +enum iperf_fab_events { + IPERF_FAB_PCIE0_RD, + IPERF_FAB_PCIE0_WR, + IPERF_FAB_PCIE1_RD, + IPERF_FAB_PCIE1_WR, + IPERF_FAB_UPI_RD, + IPERF_FAB_UPI_WR, + IPERF_FAB_MMIO_RD, + IPERF_FAB_MMIO_WR, +}; + +#define FAB_DISABLE_FILTER 0 +#define FAB_ENABLE_FILTER 1 + +/* FPMON FAB Control */ +struct feature_fme_ifpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_ifpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_ifpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +enum iperf_vtd_events { + IPERF_VTD_AFU_MEM_RD_TRANS, + IPERF_VTD_AFU_MEM_WR_TRANS, + IPERF_VTD_AFU_DEVTLB_RD_HIT, + IPERF_VTD_AFU_DEVTLB_WR_HIT, + IPERF_VTD_DEVTLB_4K_FILL, + IPERF_VTD_DEVTLB_2M_FILL, + IPERF_VTD_DEVTLB_1G_FILL, +}; + +/* VT-d control register */ +struct feature_fme_ifpmon_vtd_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d event counter */ +struct feature_fme_ifpmon_vtd_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +enum iperf_vtd_sip_events { + IPERF_VTD_SIP_IOTLB_4K_HIT, + IPERF_VTD_SIP_IOTLB_2M_HIT, + IPERF_VTD_SIP_IOTLB_1G_HIT, + IPERF_VTD_SIP_SLPWC_L3_HIT, + IPERF_VTD_SIP_SLPWC_L4_HIT, + IPERF_VTD_SIP_RCC_HIT, + IPERF_VTD_SIP_IOTLB_4K_MISS, + IPERF_VTD_SIP_IOTLB_2M_MISS, + IPERF_VTD_SIP_IOTLB_1G_MISS, + IPERF_VTD_SIP_SLPWC_L3_MISS, + IPERF_VTD_SIP_SLPWC_L4_MISS, + IPERF_VTD_SIP_RCC_MISS, +}; + +/* VT-d SIP control register */ +struct feature_fme_ifpmon_vtd_sip_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d SIP event counter */ +struct feature_fme_ifpmon_vtd_sip_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +/* FME IPERF FEATURE */ +struct feature_fme_iperf { + struct feature_header header; + struct feature_fme_ifpmon_ch_ctl ch_ctl; + struct feature_fme_ifpmon_ch_ctr ch_ctr0; + struct feature_fme_ifpmon_ch_ctr ch_ctr1; + struct feature_fme_ifpmon_fab_ctl fab_ctl; + struct feature_fme_ifpmon_fab_ctr fab_ctr; + struct feature_fme_ifpmon_clk_ctr clk; + struct feature_fme_ifpmon_vtd_ctl vtd_ctl; + struct feature_fme_ifpmon_vtd_ctr vtd_ctr; + struct feature_fme_ifpmon_vtd_sip_ctl vtd_sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr vtd_sip_ctr; +}; + +enum dperf_fab_events { + DPERF_FAB_PCIE0_RD, + DPERF_FAB_PCIE0_WR, + DPERF_FAB_MMIO_RD = 6, + DPERF_FAB_MMIO_WR, +}; + +/* FPMON FAB Control */ +struct feature_fme_dfpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_dfpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_dfpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +/* FME DPERF FEATURE */ +struct feature_fme_dperf { + struct feature_header header; + u64 rsvd[3]; + struct feature_fme_dfpmon_fab_ctl fab_ctl; + struct feature_fme_dfpmon_fab_ctr fab_ctr; + struct feature_fme_dfpmon_clk_ctr clk; +}; + +struct feature_fme_error0 { +#define FME_ERROR0_MASK 0xFFUL +#define FME_ERROR0_MASK_DEFAULT 0x40UL /* pcode workaround */ + union { + u64 csr; + struct { + u8 fabric_err:1; /* Fabric error */ + u8 fabfifo_overflow:1; /* Fabric fifo overflow */ + u8 kticdc_parity_err:2;/* KTI CDC Parity Error */ + u8 iommu_parity_err:1; /* IOMMU Parity error */ + /* AFU PF/VF access mismatch detected */ + u8 afu_acc_mode_err:1; + u8 mbp_err:1; /* Indicates an MBP event */ + /* PCIE0 CDC Parity Error */ + u8 pcie0cdc_parity_err:5; + /* PCIE1 CDC Parity Error */ + u8 pcie1cdc_parity_err:5; + /* CVL CDC Parity Error */ + u8 cvlcdc_parity_err:3; + u64 rsvd:44; /* Reserved */ + }; + }; +}; + +/* PCIe0 Error Status register */ +struct feature_fme_pcie0_error { +#define FME_PCIE0_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:52; /* Reserved */ + u8 vfnumb_err:1; /* Number of error VF */ + u8 funct_type_err:1; /* Virtual (1) or Physical */ + }; + }; +}; + +/* PCIe1 Error Status register */ +struct feature_fme_pcie1_error { +#define FME_PCIE1_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:54; /* Reserved */ + }; + }; +}; + +/* FME First Error register */ +struct feature_fme_first_error { +#define FME_FIRST_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered first + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered first + */ + u8 errReg_id:4; + }; + }; +}; + +/* FME Next Error register */ +struct feature_fme_next_error { +#define FME_NEXT_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered second + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered second + */ + u8 errReg_id:4; + }; + }; +}; + +/* RAS Non Fatal Error Status register */ +struct feature_fme_ras_nonfaterror { + union { + u64 csr; + struct { + /* thremal threshold AP1 */ + u8 temp_thresh_ap1:1; + /* thremal threshold AP2 */ + u8 temp_thresh_ap2:1; + u8 pcie_error:1; /* pcie Error */ + u8 portfatal_error:1; /* port fatal error */ + u8 proc_hot:1; /* Indicates a ProcHot event */ + /* Indicates an AFU PF/VF access mismatch */ + u8 afu_acc_mode_err:1; + /* Injected nonfata Error */ + u8 injected_nonfata_err:1; + u8 rsvd1:2; + /* Temperature threshold triggered AP6*/ + u8 temp_thresh_AP6:1; + /* Power threshold triggered AP1 */ + u8 power_thresh_AP1:1; + /* Power threshold triggered AP2 */ + u8 power_thresh_AP2:1; + /* Indicates a MBP event */ + u8 mbp_err:1; + u64 rsvd2:51; /* Reserved */ + }; + }; +}; + +/* RAS Catastrophic Fatal Error Status register */ +struct feature_fme_ras_catfaterror { + union { + u64 csr; + struct { + /* KTI Link layer error detected */ + u8 ktilink_fatal_err:1; + /* tag-n-cache error detected */ + u8 tagcch_fatal_err:1; + /* CCI error detected */ + u8 cci_fatal_err:1; + /* KTI Protocol error detected */ + u8 ktiprpto_fatal_err:1; + /* Fatal DRAM error detected */ + u8 dram_fatal_err:1; + /* IOMMU detected */ + u8 iommu_fatal_err:1; + /* Fabric Fatal Error */ + u8 fabric_fatal_err:1; + /* PCIe possion Error */ + u8 pcie_poison_err:1; + /* Injected fatal Error */ + u8 inject_fata_err:1; + /* Catastrophic CRC Error */ + u8 crc_catast_err:1; + /* Catastrophic Thermal Error */ + u8 therm_catast_err:1; + /* Injected Catastrophic Error */ + u8 injected_catast_err:1; + u64 rsvd:52; + }; + }; +}; + +/* RAS Error injection register */ +struct feature_fme_ras_error_inj { +#define FME_RAS_ERROR_INJ_MASK 0x7UL + union { + u64 csr; + struct { + u8 catast_error:1; /* Catastrophic error flag */ + u8 fatal_error:1; /* Fatal error flag */ + u8 nonfatal_error:1; /* NonFatal error flag */ + u64 rsvd:61; /* Reserved */ + }; + }; +}; + +/* FME error capabilities */ +struct feature_fme_error_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* FME ERR FEATURE */ +struct feature_fme_err { + struct feature_header header; + struct feature_fme_error0 fme_err_mask; + struct feature_fme_error0 fme_err; + struct feature_fme_pcie0_error pcie0_err_mask; + struct feature_fme_pcie0_error pcie0_err; + struct feature_fme_pcie1_error pcie1_err_mask; + struct feature_fme_pcie1_error pcie1_err; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + struct feature_fme_ras_nonfaterror ras_nonfat_mask; + struct feature_fme_ras_nonfaterror ras_nonfaterr; + struct feature_fme_ras_catfaterror ras_catfat_mask; + struct feature_fme_ras_catfaterror ras_catfaterr; + struct feature_fme_ras_error_inj ras_error_inj; + struct feature_fme_error_capability fme_err_capability; +}; + +/* FME Partial Reconfiguration Control */ +struct feature_fme_pr_ctl { + union { + u64 csr; + struct { + u8 pr_reset:1; /* Reset PR Engine */ + u8 rsvd3:3; /* Reserved */ + u8 pr_reset_ack:1; /* Reset PR Engine Ack */ + u8 rsvd4:3; /* Reserved */ + u8 pr_regionid:2; /* PR Region ID */ + u8 rsvd1:2; /* Reserved */ + u8 pr_start_req:1; /* PR Start Request */ + u8 pr_push_complete:1; /* PR Data push complete */ + u8 pr_kind:1; /* PR Data push complete */ + u32 rsvd:17; /* Reserved */ + u32 config_data; /* Config data TBD */ + }; + }; +}; + +/* FME Partial Reconfiguration Status */ +struct feature_fme_pr_status { + union { + u64 csr; + struct { + u16 pr_credit:9; /* PR Credits */ + u8 rsvd2:7; /* Reserved */ + u8 pr_status:1; /* PR status */ + u8 rsvd:3; /* Reserved */ + /* Altra PR Controller Block status */ + u8 pr_controller_status:3; + u8 rsvd1:1; /* Reserved */ + u8 pr_host_status:4; /* PR Host status */ + u8 rsvd3:4; /* Reserved */ + /* Security Block Status fields (TBD) */ + u32 security_bstatus; + }; + }; +}; + +/* FME Partial Reconfiguration Data */ +struct feature_fme_pr_data { + union { + u64 csr; /* PR data from the raw-binary file */ + struct { + /* PR data from the raw-binary file */ + u32 pr_data_raw; + u32 rsvd; + }; + }; +}; + +/* FME PR Public Key */ +struct feature_fme_pr_key { + u64 key; /* FME PR Public Hash */ +}; + +/* FME PR FEATURE */ +struct feature_fme_pr { + struct feature_header header; + /*Partial Reconfiguration control */ + struct feature_fme_pr_ctl ccip_fme_pr_control; + + /* Partial Reconfiguration Status */ + struct feature_fme_pr_status ccip_fme_pr_status; + + /* Partial Reconfiguration data */ + struct feature_fme_pr_data ccip_fme_pr_data; + + /* Partial Reconfiguration data */ + u64 ccip_fme_pr_err; + + u64 rsvd1[3]; + + /* Partial Reconfiguration data registers */ + u64 fme_pr_data1; + u64 fme_pr_data2; + u64 fme_pr_data3; + u64 fme_pr_data4; + u64 fme_pr_data5; + u64 fme_pr_data6; + u64 fme_pr_data7; + u64 fme_pr_data8; + + u64 rsvd2[5]; + + /* PR Interface ID */ + u64 fme_pr_intfc_id_l; + u64 fme_pr_intfc_id_h; + + /* MSIX filed to be Added */ +}; + +/* FME HSSI Control */ +struct feature_fme_hssi_eth_ctrl { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u16 address:16; /* HSSI address */ + /* + * HSSI comamnd + * 0x0 - No request + * 0x08 - SW register RD request + * 0x10 - SW register WR request + * 0x40 - Auxiliar bus RD request + * 0x80 - Auxiliar bus WR request + */ + u16 cmd:16; + }; + }; +}; + +/* FME HSSI Status */ +struct feature_fme_hssi_eth_stat { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u8 acknowledge:1; /* HSSI acknowledge */ + u8 spare:1; /* HSSI spare */ + u32 rsvd:30; /* Reserved */ + }; + }; +}; + +/* FME HSSI FEATURE */ +struct feature_fme_hssi { + struct feature_header header; + struct feature_fme_hssi_eth_ctrl hssi_control; + struct feature_fme_hssi_eth_stat hssi_status; +}; + +#define PORT_ERR_MASK 0xfff0703ff001f +struct feature_port_err_key { + union { + u64 csr; + struct { + /* Tx Channel0: Overflow */ + u8 tx_ch0_overflow:1; + /* Tx Channel0: Invalid request encoding */ + u8 tx_ch0_invaldreq :1; + /* Tx Channel0: Request with cl_len=3 not supported */ + u8 tx_ch0_cl_len3:1; + /* Tx Channel0: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch0_cl_len2:1; + /* Tx Channel0: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch0_cl_len4:1; + + u16 rsvd1:4; /* Reserved */ + + /* AFU MMIO RD received while PORT is in reset */ + u8 mmio_rd_whilerst:1; + /* AFU MMIO WR received while PORT is in reset */ + u8 mmio_wr_whilerst:1; + + u16 rsvd2:5; /* Reserved */ + + /* Tx Channel1: Overflow */ + u8 tx_ch1_overflow:1; + /* Tx Channel1: Invalid request encoding */ + u8 tx_ch1_invaldreq:1; + /* Tx Channel1: Request with cl_len=3 not supported */ + u8 tx_ch1_cl_len3:1; + /* Tx Channel1: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch1_cl_len2:1; + /* Tx Channel1: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch1_cl_len4:1; + + /* Tx Channel1: Insufficient data payload */ + u8 tx_ch1_insuff_data:1; + /* Tx Channel1: Data payload overrun */ + u8 tx_ch1_data_overrun:1; + /* Tx Channel1 : Incorrect address */ + u8 tx_ch1_incorr_addr:1; + /* Tx Channel1 : NON-Zero SOP Detected */ + u8 tx_ch1_nzsop:1; + /* Tx Channel1 : Illegal VC_SEL, atomic request VLO */ + u8 tx_ch1_illegal_vcsel:1; + + u8 rsvd3:6; /* Reserved */ + + /* MMIO Read Timeout in AFU */ + u8 mmioread_timeout:1; + + /* Tx Channel2: FIFO Overflow */ + u8 tx_ch2_fifo_overflow:1; + + /* MMIO read is not matching pending request */ + u8 unexp_mmio_resp:1; + + u8 rsvd4:5; /* Reserved */ + + /* Number of pending Requests: counter overflow */ + u8 tx_req_counter_overflow:1; + /* Req with Address violating SMM Range */ + u8 llpr_smrr_err:1; + /* Req with Address violating second SMM Range */ + u8 llpr_smrr2_err:1; + /* Req with Address violating ME Stolen message */ + u8 llpr_mesg_err:1; + /* Req with Address violating Generic Protected Range */ + u8 genprot_range_err:1; + /* Req with Address violating Legacy Range low */ + u8 legrange_low_err:1; + /* Req with Address violating Legacy Range High */ + u8 legrange_high_err:1; + /* Req with Address violating VGA memory range */ + u8 vgmem_range_err:1; + u8 page_fault_err:1; /* Page fault */ + u8 pmr_err:1; /* PMR Error */ + u8 ap6_event:1; /* AP6 event */ + /* VF FLR detected on Port with PF access control */ + u8 vfflr_access_err:1; + u16 rsvd5:12; /* Reserved */ + }; + }; +}; + +/* Port first error register, not contain all error bits in error register. */ +struct feature_port_first_err_key { + union { + u64 csr; + struct { + u8 tx_ch0_overflow:1; + u8 tx_ch0_invaldreq :1; + u8 tx_ch0_cl_len3:1; + u8 tx_ch0_cl_len2:1; + u8 tx_ch0_cl_len4:1; + u8 rsvd1:4; /* Reserved */ + u8 mmio_rd_whilerst:1; + u8 mmio_wr_whilerst:1; + u8 rsvd2:5; /* Reserved */ + u8 tx_ch1_overflow:1; + u8 tx_ch1_invaldreq:1; + u8 tx_ch1_cl_len3:1; + u8 tx_ch1_cl_len2:1; + u8 tx_ch1_cl_len4:1; + u8 tx_ch1_insuff_data:1; + u8 tx_ch1_data_overrun:1; + u8 tx_ch1_incorr_addr:1; + u8 tx_ch1_nzsop:1; + u8 tx_ch1_illegal_vcsel:1; + u8 rsvd3:6; /* Reserved */ + u8 mmioread_timeout:1; + u8 tx_ch2_fifo_overflow:1; + u8 rsvd4:6; /* Reserved */ + u8 tx_req_counter_overflow:1; + u32 rsvd5:23; /* Reserved */ + }; + }; +}; + +/* Port malformed Req0 */ +struct feature_port_malformed_req0 { + u64 header_lsb; +}; + +/* Port malformed Req1 */ +struct feature_port_malformed_req1 { + u64 header_msb; +}; + +/* Port debug register */ +struct feature_port_debug { + u64 port_debug; +}; + +/* Port error capabilities */ +struct feature_port_err_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE ERROR */ +struct feature_port_error { + struct feature_header header; + struct feature_port_err_key error_mask; + struct feature_port_err_key port_error; + struct feature_port_first_err_key port_first_error; + struct feature_port_malformed_req0 malreq0; + struct feature_port_malformed_req1 malreq1; + struct feature_port_debug port_debug; + struct feature_port_err_capability error_capability; +}; + +/* Port UMSG Capability */ +struct feature_port_umsg_cap { + union { + u64 csr; + struct { + /* Number of umsg allocated to this port */ + u8 umsg_allocated; + /* Enable / Disable UMsg engine for this port */ + u8 umsg_enable:1; + /* Usmg initialization status */ + u8 umsg_init_complete:1; + /* IOMMU can not translate the umsg base address */ + u8 umsg_trans_error:1; + u64 rsvd:53; /* Reserved */ + }; + }; +}; + +/* Port UMSG base address */ +struct feature_port_umsg_baseaddr { + union { + u64 csr; + struct { + u64 base_addr:48; /* 48 bit physical address */ + u16 rsvd; /* Reserved */ + }; + }; +}; + +struct feature_port_umsg_mode { + union { + u64 csr; + struct { + u32 umsg_hint_enable; /* UMSG hint enable/disable */ + u32 rsvd; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE UMSG */ +struct feature_port_umsg { + struct feature_header header; + struct feature_port_umsg_cap capability; + struct feature_port_umsg_baseaddr baseaddr; + struct feature_port_umsg_mode mode; +}; + +#define UMSG_EN_POLL_INVL 10 /* us */ +#define UMSG_EN_POLL_TIMEOUT 1000 /* us */ + +/* Port UINT Capability */ +struct feature_port_uint_cap { + union { + u64 csr; + struct { + u16 intr_num:12; /* Supported interrupts num */ + /* First MSI-X vector table entry number */ + u16 first_vec_num:12; + u64 rsvd:40; + }; + }; +}; + +/* PORT FEATURE UINT */ +struct feature_port_uint { + struct feature_header header; + struct feature_port_uint_cap capability; +}; + +/* STP region supports mmap operation, so use page aligned size. */ +#define PORT_FEATURE_STP_REGION_SIZE PAGE_ALIGN(sizeof(struct feature_port_stp)) + +/* Port STP status register (for debug only)*/ +struct feature_port_stp_status { + union { + u64 csr; + struct { + /* SLD Hub end-point read/write timeout */ + u8 sld_ep_timeout:1; + /* Remote STP in reset/disable */ + u8 rstp_disabled:1; + u8 unsupported_read:1; + /* MMIO timeout detected and faked with a response */ + u8 mmio_timeout:1; + u8 txfifo_count:4; + u8 rxfifo_count:4; + u8 txfifo_overflow:1; + u8 txfifo_underflow:1; + u8 rxfifo_overflow:1; + u8 rxfifo_underflow:1; + /* Number of MMIO write requests */ + u16 write_requests; + /* Number of MMIO read requests */ + u16 read_requests; + /* Number of MMIO read responses */ + u16 read_responses; + }; + }; +}; + +/* + * PORT FEATURE STP + * Most registers in STP region are not touched by driver, but mmapped to user + * space. So they are not defined in below data structure, as its actual size + * is 0x18c per spec. + */ +struct feature_port_stp { + struct feature_header header; + struct feature_port_stp_status stp_status; +}; + +/** + * enum fpga_pr_states - fpga PR states + * @FPGA_PR_STATE_UNKNOWN: can't determine state + * @FPGA_PR_STATE_WRITE_INIT: preparing FPGA for programming + * @FPGA_PR_STATE_WRITE_INIT_ERR: Error during WRITE_INIT stage + * @FPGA_PR_STATE_WRITE: writing image to FPGA + * @FPGA_PR_STATE_WRITE_ERR: Error while writing FPGA + * @FPGA_PR_STATE_WRITE_COMPLETE: Doing post programming steps + * @FPGA_PR_STATE_WRITE_COMPLETE_ERR: Error during WRITE_COMPLETE + * @FPGA_PR_STATE_OPERATING: FPGA PR done + */ +enum fpga_pr_states { + /* canot determine state states */ + FPGA_PR_STATE_UNKNOWN, + + /* write sequence: init, write, complete */ + FPGA_PR_STATE_WRITE_INIT, + FPGA_PR_STATE_WRITE_INIT_ERR, + FPGA_PR_STATE_WRITE, + FPGA_PR_STATE_WRITE_ERR, + FPGA_PR_STATE_WRITE_COMPLETE, + FPGA_PR_STATE_WRITE_COMPLETE_ERR, + + /* FPGA PR done */ + FPGA_PR_STATE_DONE, +}; + +/* + * FPGA Manager flags + * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported + */ +#define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + +/** + * struct fpga_pr_info - specific information to a FPGA PR + * @flags: boolean flags as defined above + * @pr_err: PR error code + * @state: fpga manager state + * @port_id: port id + */ +struct fpga_pr_info { + u32 flags; + u64 pr_err; + enum fpga_pr_states state; + int port_id; +}; + +#define DEFINE_FPGA_PR_ERR_MSG(_name_) \ +static const char * const _name_[] = { \ + "PR operation error detected", \ + "PR CRC error detected", \ + "PR incompatiable bitstream error detected", \ + "PR IP protocol error detected", \ + "PR FIFO overflow error detected", \ + "PR timeout error detected", \ + "PR secure load error detected", \ +} + +#define RST_POLL_INVL 10 /* us */ +#define RST_POLL_TIMEOUT 1000 /* us */ + +#define PR_WAIT_TIMEOUT 15000000 + +#define PR_HOST_STATUS_IDLE 0 +#define PR_MAX_ERR_NUM 7 + +DEFINE_FPGA_PR_ERR_MSG(pr_err_msg); + +/* + * green bitstream header must be byte-packed to match the + * real file format. + */ +struct bts_header { + u64 guid_h; + u64 guid_l; + u32 metadata_len; +}; + +#define GBS_GUID_H 0x414750466e6f6558 +#define GBS_GUID_L 0x31303076534247b7 +#define is_valid_bts(bts_hdr) \ + (((bts_hdr)->guid_h == GBS_GUID_H) && \ + ((bts_hdr)->guid_l == GBS_GUID_L)) + +#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 new file mode 100644 index 0000000..10a8f06 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -0,0 +1,824 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_hw_api.h" +#include "ifpga_api.h" + +#include "ifpga_hw.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +struct build_feature_devs_info { + struct opae_adapter_data_pci *pci_data; + + struct ifpga_afu_info *acc_info; + + void *fiu; + enum fpga_id_type current_type; + int current_port_id; + + void *ioaddr; + void *ioend; + uint64_t phys_addr; + int current_bar; + + void *pfme_hdr; + + struct ifpga_hw *hw; +}; + +struct feature_info { + const char *name; + uint32_t resource_size; + int feature_index; + int revision_id; + unsigned int vec_start; + unsigned int vec_cnt; + + struct feature_ops *ops; +}; + +/* 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, + } +}; + +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 = &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 = &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 = &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 = &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 + }, +}; + +static u64 feature_id(void __iomem *start) +{ + struct feature_header header; + + header.csr = readq(start); + + switch (header.type) { + case FEATURE_TYPE_FIU: + return FEATURE_ID_HEADER; + case FEATURE_TYPE_PRIVATE: + return header.id; + case FEATURE_TYPE_AFU: + return FEATURE_ID_AFU; + } + + WARN_ON(1); + return 0; +} + +static int +build_info_add_sub_feature(struct build_feature_devs_info *binfo, + struct feature_info *finfo, void __iomem *start) +{ + 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; + } + + 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->phys_addr = binfo->phys_addr + + ((u8 *)start - (u8 *)binfo->ioaddr); + + if (vec_cnt) { + if (vec_start + vec_cnt <= vec_start) + return -EINVAL; + + ctx = zmalloc(sizeof(*ctx) * vec_cnt); + if (!ctx) + return -ENOMEM; + + for (i = 0; i < vec_cnt; i++) { + ctx[i].eventfd = -1; + ctx[i].idx = vec_start + i; + } + } + + feature->ctx = ctx; + feature->ctx_num = vec_cnt; + feature->vfio_dev_fd = binfo->pci_data->vfio_dev_fd; + + return ret; +} + +static int +create_feature_instance(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + struct feature_header *hdr = start; + + if (((u8 *)binfo->ioend - (u8 *)start) < finfo->resource_size) + return -EINVAL; + + 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); +} + +/* + * UAFU GUID is dynamic as it can be changed after FME downloads different + * Green Bitstream to the port, so we treat the unknown GUIDs which are + * attached on port's feature list as UAFU. + */ +static bool feature_is_UAFU(struct build_feature_devs_info *binfo) +{ + if (binfo->current_type != PORT_ID) + return false; + + return true; +} + +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; + struct ifpga_afu_info *info; + void *start = (void *)hdr; + int ret; + + 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; + } + + if (ret) + return ret; + + /* FIXME: need to figure out a better name */ + info = 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->num_regions = 1; + + binfo->acc_info = info; + + return ret; +} + +static int parse_feature_afus(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + int ret; + struct feature_afu_header *afu_hdr, header; + u8 __iomem *start; + u8 __iomem *end = binfo->ioend; + + start = (u8 __iomem *)hdr; + for (; start < end; start += header.next_afu) { + if (end - start < + (unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr))) + return -EINVAL; + + hdr = (struct feature_header *)start; + afu_hdr = (struct feature_afu_header *)(hdr + 1); + header.csr = readq(&afu_hdr->csr); + + if (feature_is_UAFU(binfo)) { + ret = parse_feature_port_uafu(binfo, hdr); + if (ret) + return ret; + } + + if (!header.next_afu) + break; + } + + return 0; +} + +/* create and register proper private data */ +static int build_info_commit_dev(struct build_feature_devs_info *binfo) +{ + struct ifpga_afu_info *info = binfo->acc_info; + struct ifpga_hw *hw = binfo->hw; + struct opae_manager *mgr; + struct opae_bridge *br; + struct opae_accelerator *acc; + + if (!binfo->fiu) + return 0; + + if (binfo->current_type == PORT_ID) { + /* return error if no valid acc info data structure */ + if (!info) + return -EFAULT; + + br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops, + binfo->fiu); + if (!br) + return -ENOMEM; + + br->id = binfo->current_port_id; + + /* update irq info */ + info->num_irqs = port_features[PORT_FEATURE_ID_UINT].vec_cnt; + + acc = opae_accelerator_alloc(hw->adapter->name, + &ifpga_acc_ops, info); + if (!acc) { + opae_bridge_free(br); + return -ENOMEM; + } + + acc->br = br; + acc->index = br->id; + + opae_adapter_add_acc(hw->adapter, acc); + + } else if (binfo->current_type == FME_ID) { + mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops, + binfo->fiu); + if (!mgr) + return -ENOMEM; + + mgr->adapter = hw->adapter; + hw->adapter->mgr = mgr; + } + + binfo->fiu = NULL; + + return 0; +} + +static int +build_info_create_dev(struct build_feature_devs_info *binfo, + enum fpga_id_type type, unsigned int index) +{ + int ret; + + ret = build_info_commit_dev(binfo); + if (ret) + return ret; + + binfo->current_type = type; + + if (type == FME_ID) { + binfo->fiu = &binfo->hw->fme; + } else if (type == PORT_ID) { + binfo->fiu = &binfo->hw->port[index]; + binfo->current_port_id = index; + } + + return 0; +} + +static int parse_feature_fme(struct build_feature_devs_info *binfo, + struct feature_header *start) +{ + struct ifpga_hw *hw = binfo->hw; + struct ifpga_fme_hw *fme = &hw->fme; + int ret; + + ret = build_info_create_dev(binfo, FME_ID, 0); + if (ret) + return ret; + + /* Update FME states */ + fme->state = IFPGA_FME_IMPLEMENTED; + fme->parent = hw; + spinlock_init(&fme->lock); + + return create_feature_instance(binfo, start, + &fme_features[FME_FEATURE_ID_HEADER]); +} + +static int parse_feature_port(struct build_feature_devs_info *binfo, + void __iomem *start) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + struct ifpga_hw *hw = binfo->hw; + struct ifpga_port_hw *port; + unsigned int port_id; + int ret; + + /* Get current port's id */ + port_hdr = (struct feature_port_header *)start; + capability.csr = readq(&port_hdr->capability); + port_id = capability.port_number; + + ret = build_info_create_dev(binfo, PORT_ID, port_id); + if (ret) + return ret; + + /*found a Port device*/ + port = &hw->port[port_id]; + port->port_id = binfo->current_port_id; + port->parent = hw; + port->state = IFPGA_PORT_ATTACHED; + spinlock_init(&port->lock); + + return create_feature_instance(binfo, start, + &port_features[PORT_FEATURE_ID_HEADER]); +} + +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); +} + +static int parse_feature_fiu(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + struct feature_fiu_header *fiu_hdr, fiu_header; + u8 __iomem *start = (u8 __iomem *)hdr; + int ret; + + header.csr = readq(hdr); + + switch (header.id) { + case FEATURE_FIU_ID_FME: + ret = parse_feature_fme(binfo, hdr); + binfo->pfme_hdr = hdr; + if (ret) + return ret; + break; + case FEATURE_FIU_ID_PORT: + ret = parse_feature_port(binfo, hdr); + enable_port_uafu(binfo, hdr); + if (ret) + return ret; + + /* Check Port FIU's next_afu pointer to User AFU DFH */ + fiu_hdr = (struct feature_fiu_header *)(hdr + 1); + fiu_header.csr = readq(&fiu_hdr->csr); + + if (fiu_header.next_afu) { + start += fiu_header.next_afu; + ret = parse_feature_afus(binfo, + (struct feature_header *)start); + if (ret) + return ret; + } else { + dev_info(binfo, "No AFUs detected on Port\n"); + } + + break; + default: + dev_info(binfo, "FIU TYPE %d is not supported yet.\n", + header.id); + } + + return 0; +} + +static void parse_feature_irqs(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + finfo->vec_start = 0; + finfo->vec_cnt = 0; + + UNUSED(binfo); + + if (!strcmp(finfo->name, PORT_FEATURE_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; + } else { + dev_debug(binfo, "UAFU doesn't support interrupt\n"); + } + } else if (!strcmp(finfo->name, PORT_FEATURE_ERR)) { + 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; + } else { + dev_debug(&binfo, "Port error doesn't support interrupt\n"); + } + + } else if (!strcmp(finfo->name, FME_FEATURE_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; + } else { + dev_debug(&binfo, "FME error doesn't support interrupt\n"); + } + } +} + +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; + } + + parse_feature_irqs(binfo, hdr, &fme_features[header.id]); + + return create_feature_instance(binfo, hdr, &fme_features[header.id]); +} + +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; + + 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]); + + return create_feature_instance(binfo, hdr, &port_features[id]); +} + +static int parse_feature_private(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + + header.csr = readq(hdr); + + switch (binfo->current_type) { + case FME_ID: + return parse_feature_fme_private(binfo, hdr); + case PORT_ID: + return parse_feature_port_private(binfo, hdr); + default: + dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n", + header.id, binfo->current_type); + } + return 0; +} + +static int parse_feature(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + int ret = 0; + + header.csr = readq(hdr); + + switch (header.type) { + case FEATURE_TYPE_AFU: + ret = parse_feature_afus(binfo, hdr); + break; + case FEATURE_TYPE_PRIVATE: + ret = parse_feature_private(binfo, hdr); + break; + case FEATURE_TYPE_FIU: + ret = parse_feature_fiu(binfo, hdr); + break; + default: + dev_err(binfo, "Feature Type %x is not supported.\n", + hdr->type); + }; + + return ret; +} + +static int +parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start) +{ + struct feature_header *hdr, header; + u8 __iomem *end = (u8 __iomem *)binfo->ioend; + int ret = 0; + + for (; start < end; start += header.next_header_offset) { + if (end - start < (unsigned int)sizeof(*hdr)) { + dev_err(binfo, "The region is too small to contain a feature.\n"); + ret = -EINVAL; + break; + } + + hdr = (struct feature_header *)start; + ret = parse_feature(binfo, hdr); + if (ret) + return ret; + + header.csr = readq(hdr); + if (!header.next_header_offset) + break; + } + + return build_info_commit_dev(binfo); +} + +/* switch the memory mapping to BAR# @bar */ +static int parse_switch_to(struct build_feature_devs_info *binfo, int bar) +{ + struct opae_adapter_data_pci *pci_data = binfo->pci_data; + + if (!pci_data->region[bar].addr) + return -ENOMEM; + + binfo->ioaddr = pci_data->region[bar].addr; + binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len; + binfo->phys_addr = pci_data->region[bar].phys_addr; + binfo->current_bar = bar; + + return 0; +} + +static int parse_ports_from_fme(struct build_feature_devs_info *binfo) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_port port; + int i = 0, ret = 0; + + if (!binfo->pfme_hdr) { + dev_info(binfo, "VF is detected.\n"); + return ret; + } + + fme_hdr = binfo->pfme_hdr; + + do { + port.csr = readq(&fme_hdr->port[i]); + if (!port.port_implemented) + break; + + /* skip port which only could be accessed via VF */ + if (port.afu_access_control == FME_AFU_ACCESS_VF) + continue; + + ret = parse_switch_to(binfo, port.port_bar); + if (ret) + break; + + ret = parse_feature_list(binfo, + (u8 __iomem *)binfo->ioaddr + + port.port_offset); + if (ret) + break; + } while (++i < MAX_FPGA_PORT_NUM); + + return ret; +} + +static struct build_feature_devs_info * +build_info_alloc_and_init(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + + binfo = zmalloc(sizeof(*binfo)); + if (!binfo) + return binfo; + + binfo->hw = hw; + binfo->pci_data = hw->pci_data; + + /* fpga feature list starts from BAR 0 */ + if (parse_switch_to(binfo, 0)) { + free(binfo); + return NULL; + } + + return binfo; +} + +static void build_info_free(struct build_feature_devs_info *binfo) +{ + free(binfo); +} + +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; + + 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]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr: 0x%lx\n", + feature->name, (unsigned long long)feature->addr, + (unsigned long long)feature->addr + feature->size - 1, + feature->phys_addr); + } + + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) { + port = &hw->port[i]; + + if (port->state != IFPGA_PORT_ATTACHED) + continue; + + dev_info(hw, "port device: %d\n", port->port_id); + + for (j = 0; j < PORT_FEATURE_ID_MAX; j++) { + feature = &port->sub_feature[j]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr:0x%lx\n", + feature->name, + (unsigned long long)feature->addr, + (unsigned long long)feature->addr + + feature->size - 1, + feature->phys_addr); + } + } +} + +int ifpga_bus_enumerate(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + int ret; + + binfo = build_info_alloc_and_init(hw); + if (!binfo) + return -ENOMEM; + + ret = parse_feature_list(binfo, binfo->ioaddr); + if (ret) + goto exit; + + ret = parse_ports_from_fme(binfo); + if (ret) + goto exit; + + ifpga_print_device_feature_list(hw); + +exit: + build_info_free(binfo); + return ret; +} + +int ifpga_bus_init(struct ifpga_hw *hw) +{ + int i; + + fme_hw_init(&hw->fme); + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) + port_hw_init(&hw->port[i]); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h new file mode 100644 index 0000000..14131e3 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_ENUMERATE_H_ +#define _IFPGA_ENUMERATE_H_ + +int ifpga_bus_init(struct ifpga_hw *hw); +int ifpga_bus_enumerate(struct ifpga_hw *hw); + +#endif /* _IFPGA_ENUMERATE_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c new file mode 100644 index 0000000..6d14523 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -0,0 +1,314 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <linux/vfio.h> +#include <sys/ioctl.h> + +#include "ifpga_feature_dev.h" + +/* + * Enable Port by clear the port soft reset bit, which is set by default. + * The AFU is unable to respond to any MMIO access while in reset. + * __fpga_port_enable function should only be used after __fpga_port_disable + * function. + */ +void __fpga_port_enable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + WARN_ON(!port->disable_count); + + if (--port->disable_count != 0) + return; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x0; + writeq(control.csr, &port_hdr->control); +} + +int __fpga_port_disable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + if (port->disable_count++ != 0) + return 0; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + /* Set port soft reset */ + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x1; + writeq(control.csr, &port_hdr->control); + + /* + * HW sets ack bit to 1 when all outstanding requests have been drained + * on this port and minimum soft reset pulse width has elapsed. + * Driver polls port_soft_reset_ack to determine if reset done by HW. + */ + control.port_sftrst_ack = 1; + + if (fpga_wait_register_field(port_sftrst_ack, control, + &port_hdr->control, RST_POLL_TIMEOUT, + RST_POLL_INVL)) { + dev_err(port, "timeout, fail to reset device\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) +{ + struct feature_port_header *port_hdr; + u64 guidl, guidh; + + port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU); + + spinlock_lock(&port->lock); + guidl = readq(&port_hdr->afu_header.guid.b[0]); + guidh = readq(&port_hdr->afu_header.guid.b[8]); + spinlock_unlock(&port->lock); + + printf("%s: guidl=0x%lx, guidh=0x%lx\n", __func__, guidl, guidh); + + memcpy(uuid->b, &guidl, sizeof(u64)); + memcpy(uuid->b + 8, &guidh, sizeof(u64)); + + return 0; +} + +/* Mask / Unmask Port Errors by the Error Mask register. */ +void port_err_mask(struct ifpga_port_hw *port, bool mask) +{ + struct feature_port_error *port_err; + struct feature_port_err_key err_mask; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + if (mask) + err_mask.csr = PORT_ERR_MASK; + else + err_mask.csr = 0; + + writeq(err_mask.csr, &port_err->error_mask); +} + +/* Clear All Port Errors. */ +int port_err_clear(struct ifpga_port_hw *port, u64 err) +{ + struct feature_port_header *port_hdr; + struct feature_port_error *port_err; + struct feature_port_err_key mask; + struct feature_port_first_err_key first; + struct feature_port_status status; + int ret = 0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + /* + * Clear All Port Errors + * + * - Check for AP6 State + * - Halt Port by keeping Port in reset + * - Set PORT Error mask to all 1 to mask errors + * - Clear all errors + * - Set Port mask to all 0 to enable errors + * - All errors start capturing new errors + * - Enable Port by pulling the port out of reset + */ + + /* If device is still in AP6 state, can not clear any error.*/ + status.csr = readq(&port_hdr->status); + if (status.power_state == PORT_POWER_STATE_AP6) { + dev_err(dev, "Could not clear errors, device in AP6 state.\n"); + return -EBUSY; + } + + /* Halt Port by keeping Port in reset */ + ret = __fpga_port_disable(port); + if (ret) + return ret; + + /* Mask all errors */ + port_err_mask(port, true); + + /* Clear errors if err input matches with current port errors.*/ + mask.csr = readq(&port_err->port_error); + + if (mask.csr == err) { + writeq(mask.csr, &port_err->port_error); + + first.csr = readq(&port_err->port_first_error); + writeq(first.csr, &port_err->port_first_error); + } else { + ret = -EBUSY; + } + + /* Clear mask */ + port_err_mask(port, false); + + /* Enable the Port by clear the reset */ + __fpga_port_enable(port); + + return ret; +} + +int port_clear_error(struct ifpga_port_hw *port) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + + dev_info(port, "read port error: 0x%lx\n", error.csr); + + return port_err_clear(port, error.csr); +} + +void fme_hw_uinit(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return; + + 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); + } +} + +int fme_hw_init(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i, ret; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + 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; + } + } + } + + return 0; +} + +void port_hw_uinit(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i; + + 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); + } +} + +int port_hw_init(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i, 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; + } + } + } + + return 0; +} + +/* + * FIXME: we should get msix vec count during pci enumeration instead of + * below hardcode value. + */ +#define FPGA_MSIX_VEC_COUNT 20 +/* irq set buffer length for interrupt */ +#define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \ + sizeof(int) * FPGA_MSIX_VEC_COUNT) + +/* only support msix for now*/ +static int vfio_msix_enable_block(s32 vfio_dev_fd, unsigned int vec_start, + unsigned int count, s32 *fds) +{ + char irq_set_buf[MSIX_IRQ_SET_BUF_LEN]; + struct vfio_irq_set *irq_set; + int len, ret; + int *fd_ptr; + + len = sizeof(irq_set_buf); + + irq_set = (struct vfio_irq_set *)irq_set_buf; + irq_set->argsz = len; + irq_set->count = count; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; + irq_set->start = vec_start; + + fd_ptr = (int *)&irq_set->data; + memcpy(fd_ptr, fds, sizeof(int) * count); + + ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set); + if (ret) + printf("Error enabling MSI-X interrupts\n"); + + return ret; +} + +int fpga_msix_set_block(struct feature *feature, unsigned int start, + unsigned int count, s32 *fds) +{ + struct feature_irq_ctx *ctx = feature->ctx; + unsigned int i; + int ret; + + if (start >= feature->ctx_num || start + count > feature->ctx_num) + return -EINVAL; + + /* assume that each feature has continuous vector space in msix*/ + ret = vfio_msix_enable_block(feature->vfio_dev_fd, + ctx[start].idx, count, fds); + if (!ret) { + for (i = 0; i < count; i++) + ctx[i].eventfd = fds[i]; + } + + return ret; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h new file mode 100644 index 0000000..cd114fb --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_FEATURE_DEV_H_ +#define _IFPGA_FEATURE_DEV_H_ + +#include "ifpga_hw.h" + +static inline struct ifpga_port_hw * +get_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return NULL; + + return &hw->port[port_id]; +} + +#define ifpga_for_each_feature(hw, feature) \ + for ((feature) = (hw)->sub_feature; \ + (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++) + +static inline struct feature * +get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(fme, feature) { + if (feature->id == id) + return feature; + } + + return NULL; +} + +static inline struct feature * +get_port_feature_by_id(struct ifpga_port_hw *port, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(port, feature) { + 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; +} + +static inline void * +get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index) +{ + return port->sub_feature[index].addr; +} + +static inline bool +is_fme_feature_present(struct ifpga_fme_hw *fme, int index) +{ + return !!get_fme_feature_ioaddr_by_index(fme, index); +} + +static inline bool +is_port_feature_present(struct ifpga_port_hw *port, int index) +{ + return !!get_port_feature_ioaddr_by_index(port, index); +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid); + +int __fpga_port_disable(struct ifpga_port_hw *port); +void __fpga_port_enable(struct ifpga_port_hw *port); + +static inline int fpga_port_disable(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_disable(port); + spinlock_unlock(&port->lock); + return ret; +} + +static inline int fpga_port_enable(struct ifpga_port_hw *port) +{ + spinlock_lock(&port->lock); + __fpga_port_enable(port); + spinlock_unlock(&port->lock); + + return 0; +} + +static inline int __fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + ret = __fpga_port_disable(port); + if (ret) + return ret; + + __fpga_port_enable(port); + + return 0; +} + +static inline int fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_reset(port); + spinlock_unlock(&port->lock); + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +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); +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set); + +int fme_hw_init(struct ifpga_fme_hw *fme); +void fme_hw_uinit(struct ifpga_fme_hw *fme); +void port_hw_uinit(struct ifpga_port_hw *port); +int port_hw_init(struct ifpga_port_hw *port); +int port_clear_error(struct ifpga_port_hw *port); +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; + +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); + +/* This struct is used when parsing uafu irq_set */ +struct fpga_uafu_irq_set { + u32 start; + u32 count; + s32 *evtfds; +}; + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set); + +extern struct feature_ops port_hdr_ops; +extern struct feature_ops port_error_ops; +extern struct feature_ops port_stp_ops; +extern struct feature_ops port_uint_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 new file mode 100644 index 0000000..4be60c0 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -0,0 +1,734 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PWR_THRESHOLD_MAX 0x7F + +int fme_get_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +/* fme private feature head */ +static int fme_hdr_init(struct feature *feature) +{ + struct feature_fme_header *fme_hdr; + + fme_hdr = (struct feature_fme_header *)feature->addr; + + dev_info(NULL, "FME HDR Init.\n"); + dev_info(NULL, "FME cap %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + return 0; +} + +static void fme_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME HDR UInit.\n"); +} + +static int fme_hdr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&fme_hdr->header); + *revision = header.revision; + + return 0; +} + +static int fme_hdr_get_ports_num(struct ifpga_fme_hw *fme, u64 *ports_num) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *ports_num = fme_capability.num_ports; + + return 0; +} + +static int fme_hdr_get_cache_size(struct ifpga_fme_hw *fme, u64 *cache_size) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *cache_size = fme_capability.cache_size; + + return 0; +} + +static int fme_hdr_get_version(struct ifpga_fme_hw *fme, u64 *version) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *version = fme_capability.fabric_verid; + + return 0; +} + +static int fme_hdr_get_socket_id(struct ifpga_fme_hw *fme, u64 *socket_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *socket_id = fme_capability.socket_id; + + return 0; +} + +static int fme_hdr_get_bitstream_id(struct ifpga_fme_hw *fme, + u64 *bitstream_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_id = readq(&fme_hdr->bitstream_id); + + return 0; +} + +static int fme_hdr_get_bitstream_metadata(struct ifpga_fme_hw *fme, + u64 *bitstream_metadata) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_metadata = readq(&fme_hdr->bitstream_md); + + return 0; +} + +static int +fme_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_HDR_PROP_REVISION: + return fme_hdr_get_revision(fme, &prop->data); + case FME_HDR_PROP_PORTS_NUM: + return fme_hdr_get_ports_num(fme, &prop->data); + case FME_HDR_PROP_CACHE_SIZE: + return fme_hdr_get_cache_size(fme, &prop->data); + case FME_HDR_PROP_VERSION: + return fme_hdr_get_version(fme, &prop->data); + case FME_HDR_PROP_SOCKET_ID: + return fme_hdr_get_socket_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_ID: + return fme_hdr_get_bitstream_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_METADATA: + return fme_hdr_get_bitstream_metadata(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_hdr_ops = { + .init = fme_hdr_init, + .uinit = fme_hdr_uinit, + .get_prop = fme_hdr_get_prop, +}; + +/* thermal management */ +static int fme_thermal_get_threshold1(struct ifpga_fme_hw *fme, u64 *thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1 = temp_threshold.tmp_thshold1; + + return 0; +} + +static int fme_thermal_set_threshold1(struct ifpga_fme_hw *fme, u64 thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres1 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres1 == 0) { + tmp_threshold.tmp_thshold1_enable = 0; + tmp_threshold.tmp_thshold1 = thres1; + } else { + tmp_threshold.tmp_thshold1_enable = 1; + tmp_threshold.tmp_thshold1 = thres1; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold2(struct ifpga_fme_hw *fme, u64 *thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres2 = temp_threshold.tmp_thshold2; + + return 0; +} + +static int fme_thermal_set_threshold2(struct ifpga_fme_hw *fme, u64 thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres2 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres2 == 0) { + tmp_threshold.tmp_thshold2_enable = 0; + tmp_threshold.tmp_thshold2 = thres2; + } else { + tmp_threshold.tmp_thshold2_enable = 1; + tmp_threshold.tmp_thshold2 = thres2; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold_trip(struct ifpga_fme_hw *fme, + u64 *thres_trip) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres_trip = temp_threshold.therm_trip_thshold; + + return 0; +} + +static int fme_thermal_get_threshold1_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold1_status; + + return 0; +} + +static int fme_thermal_get_threshold2_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold2_status; + + return 0; +} + +static int fme_thermal_get_threshold1_policy(struct ifpga_fme_hw *fme, + u64 *thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_policy = temp_threshold.thshold_policy; + + return 0; +} + +static int fme_thermal_set_threshold1_policy(struct ifpga_fme_hw *fme, + u64 thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold tmp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + + if (thres1_policy == 0) { + tmp_threshold.thshold_policy = 0; + } else if (thres1_policy == 1) { + tmp_threshold.thshold_policy = 1; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_temperature(struct ifpga_fme_hw *fme, u64 *temp) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_temp_rdsensor_fmt1 temp_rdsensor_fmt1; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_rdsensor_fmt1.csr = readq(&thermal->rdsensor_fm1); + *temp = temp_rdsensor_fmt1.fpga_temp; + + return 0; +} + +static int fme_thermal_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_thermal *fme_thermal + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + struct feature_header header; + + header.csr = readq(&fme_thermal->header); + *revision = header.revision; + + return 0; +} + +#define FME_THERMAL_CAP_NO_TMP_THRESHOLD 0x1 + +static int fme_thermal_mgmt_init(struct feature *feature) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold_cap thermal_cap; + + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt Init.\n"); + + fme_thermal = (struct feature_fme_thermal *)feature->addr; + thermal_cap.csr = readq(&fme_thermal->threshold_cap); + + dev_info(NULL, "FME thermal cap %llx.\n", + (unsigned long long)fme_thermal->threshold_cap.csr); + + if (thermal_cap.tmp_thshold_disabled) + feature->cap |= FME_THERMAL_CAP_NO_TMP_THRESHOLD; + + return 0; +} + +static void fme_thermal_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt UInit.\n"); +} + +static int +fme_thermal_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_set_threshold1(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_set_threshold2(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_set_threshold1_policy(fme, prop->data); + } + + return -ENOENT; +} + +static int +fme_thermal_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD && + prop->prop_id != FME_THERMAL_PROP_TEMPERATURE && + prop->prop_id != FME_THERMAL_PROP_REVISION) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_get_threshold1(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_get_threshold2(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD_TRIP: + return fme_thermal_get_threshold_trip(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_REACHED: + return fme_thermal_get_threshold1_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2_REACHED: + return fme_thermal_get_threshold2_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_get_threshold1_policy(fme, &prop->data); + case FME_THERMAL_PROP_TEMPERATURE: + return fme_thermal_get_temperature(fme, &prop->data); + case FME_THERMAL_PROP_REVISION: + return fme_thermal_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_thermal_mgmt_ops = { + .init = fme_thermal_mgmt_init, + .uinit = fme_thermal_mgmt_uinit, + .get_prop = fme_thermal_get_prop, + .set_prop = fme_thermal_set_prop, +}; + +static int fme_pwr_get_consumed(struct ifpga_fme_hw *fme, u64 *consumed) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *consumed = pm_status.pwr_consumed; + + return 0; +} + +static int fme_pwr_get_threshold1(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold1; + + return 0; +} + +static int fme_pwr_set_threshold1(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold1 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold2(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold2; + + return 0; +} + +static int fme_pwr_set_threshold2(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold2 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold1_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold1_status; + + return 0; +} + +static int fme_pwr_get_threshold2_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold2_status; + + return 0; +} + +static int fme_pwr_get_rtl(struct ifpga_fme_hw *fme, u64 *rtl) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *rtl = pm_status.fpga_latency_report; + + return 0; +} + +static int fme_pwr_get_xeon_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_xeon_limit xeon_limit; + + xeon_limit.csr = readq(&fme_power->xeon_limit); + + if (!xeon_limit.enable) + xeon_limit.pwr_limit = 0; + + *limit = xeon_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_fpga_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_fpga_limit fpga_limit; + + fpga_limit.csr = readq(&fme_power->fpga_limit); + + if (!fpga_limit.enable) + fpga_limit.pwr_limit = 0; + + *limit = fpga_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_header header; + + header.csr = readq(&fme_power->header); + *revision = header.revision; + + return 0; +} + +static int fme_power_mgmt_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt Init.\n"); + + return 0; +} + +static void fme_power_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt UInit.\n"); +} + +static int fme_power_mgmt_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_CONSUMED: + return fme_pwr_get_consumed(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_get_threshold1(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_get_threshold2(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1_STATUS: + return fme_pwr_get_threshold1_status(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2_STATUS: + return fme_pwr_get_threshold2_status(fme, &prop->data); + case FME_PWR_PROP_RTL: + return fme_pwr_get_rtl(fme, &prop->data); + case FME_PWR_PROP_XEON_LIMIT: + return fme_pwr_get_xeon_limit(fme, &prop->data); + case FME_PWR_PROP_FPGA_LIMIT: + return fme_pwr_get_fpga_limit(fme, &prop->data); + case FME_PWR_PROP_REVISION: + return fme_pwr_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_power_mgmt_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_set_threshold1(fme, prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_set_threshold2(fme, prop->data); + } + + return -ENOENT; +} + +struct 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, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c new file mode 100644 index 0000000..1773b87 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_dperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_clk_ctr clk; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + clk.afu_interf_clock = readq(&dperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_dperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_dperf *dperf; + struct feature_header header; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + header.csr = readq(&dperf->header); + *revision = header.revision; + + return 0; +} + +#define DPERF_TIMEOUT 30 + +static bool fabric_pobj_is_enabled(int port_id, + struct feature_fme_dperf *dperf) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + + ctl.csr = readq(&dperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum dperf_fab_events fab_event) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dfpmon_fab_ctr ctr; + struct feature_fme_dperf *dperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, dperf)) + goto exit; + + ctl.csr = readq(&dperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &dperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &dperf->fab_ctr, DPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&dperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_dperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, DPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, DPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(mmio_read, DPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, DPERF_FAB_MMIO_WR); + +static int fme_dperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_dperf *dperf; + int status; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + status = fabric_pobj_is_enabled(port_id, dperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_dperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dperf *dperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, dperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&dperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_dperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_dperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 + +static int fme_global_dperf_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf Init.\n"); + + return 0; +} + +static void fme_global_dperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf UInit.\n"); +} + +static int fme_dperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_dperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_dperf_get_fab_port_pcie0_read(fme, sub, &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_dperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* MMIO_READ */ + return fme_dperf_get_fab_port_mmio_read(fme, sub, &prop->data); + case 0x5: /* MMIO_WRITE */ + return fme_dperf_get_fab_port_mmio_write(fme, sub, &prop->data); + case 0x6: /* ENABLE */ + return fme_dperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_dperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_dperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_dperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_dperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_dperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE - fab root only prop */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_dperf_set_fab_freeze(fme, prop->data); + case 0x6: /* ENABLE - fab both root and sub */ + return fme_dperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_dperf_ops = { + .init = fme_global_dperf_init, + .uinit = fme_global_dperf_uinit, + .get_prop = fme_global_dperf_get_prop, + .set_prop = fme_global_dperf_set_prop, + +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c new file mode 100644 index 0000000..33c241e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static int fme_err_get_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + + fme_error0.csr = readq(&fme_err->fme_err); + *val = fme_error0.csr; + + return 0; +} + +static int fme_err_get_first_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_first_error fme_first_err; + + fme_first_err.csr = readq(&fme_err->fme_first_err); + *val = fme_first_err.err_reg_status; + + return 0; +} + +static int fme_err_get_next_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_next_error fme_next_err; + + fme_next_err.csr = readq(&fme_err->fme_next_err); + *val = fme_next_err.err_reg_status; + + return 0; +} + +static int fme_err_set_clear(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_ERROR0_MASK, &fme_err->fme_err_mask); + + fme_error0.csr = readq(&fme_err->fme_err); + if (val != fme_error0.csr) { + ret = -EBUSY; + goto exit; + } + + fme_first_err.csr = readq(&fme_err->fme_first_err); + fme_next_err.csr = readq(&fme_err->fme_next_err); + + writeq(fme_error0.csr & FME_ERROR0_MASK, &fme_err->fme_err); + writeq(fme_first_err.csr & FME_FIRST_ERROR_MASK, + &fme_err->fme_first_err); + writeq(fme_next_err.csr & FME_NEXT_ERROR_MASK, + &fme_err->fme_next_err); + +exit: + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_revision(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_header header; + + header.csr = readq(&fme_err->header); + *val = header.revision; + + return 0; +} + +static int fme_err_get_pcie0_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + + pcie0_err.csr = readq(&fme_err->pcie0_err); + *val = pcie0_err.csr; + + return 0; +} + +static int fme_err_set_pcie0_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE0_ERROR_MASK, &fme_err->pcie0_err_mask); + + pcie0_err.csr = readq(&fme_err->pcie0_err); + if (val != pcie0_err.csr) + ret = -EBUSY; + else + writeq(pcie0_err.csr & FME_PCIE0_ERROR_MASK, + &fme_err->pcie0_err); + + writeq(0UL, &fme_err->pcie0_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_pcie1_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + + pcie1_err.csr = readq(&fme_err->pcie1_err); + *val = pcie1_err.csr; + + return 0; +} + +static int fme_err_set_pcie1_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE1_ERROR_MASK, &fme_err->pcie1_err_mask); + + pcie1_err.csr = readq(&fme_err->pcie1_err); + if (val != pcie1_err.csr) + ret = -EBUSY; + else + writeq(pcie1_err.csr & FME_PCIE1_ERROR_MASK, + &fme_err->pcie1_err); + + writeq(0UL, &fme_err->pcie1_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_nonfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_nonfaterror ras_nonfaterr; + + ras_nonfaterr.csr = readq(&fme_err->ras_nonfaterr); + *val = ras_nonfaterr.csr; + + return 0; +} + +static int fme_err_get_catfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_catfaterror ras_catfaterr; + + ras_catfaterr.csr = readq(&fme_err->ras_catfaterr); + *val = ras_catfaterr.csr; + + return 0; +} + +static int fme_err_get_inject_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + *val = ras_error_inj.csr & FME_RAS_ERROR_INJ_MASK; + + return 0; +} + +static int fme_err_set_inject_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + spinlock_lock(&fme->lock); + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + + if (val <= FME_RAS_ERROR_INJ_MASK) { + ras_error_inj.csr = val; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(ras_error_inj.csr, &fme_err->ras_error_inj); + spinlock_unlock(&fme->lock); + + return 0; +} + +static void fme_error_enable(struct ifpga_fme_hw *fme) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + writeq(0UL, &fme_err->pcie0_err_mask); + writeq(0UL, &fme_err->pcie1_err_mask); + writeq(0UL, &fme_err->ras_nonfat_mask); + writeq(0UL, &fme_err->ras_catfat_mask); +} + +static int fme_global_error_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = feature->parent; + + fme_error_enable(fme); + + if (feature->ctx_num) + fme->capability |= FPGA_FME_CAP_ERR_IRQ; + + return 0; +} + +static void fme_global_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int fme_err_fme_err_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* ERRORS */ + return fme_err_get_errors(fme, &prop->data); + case 0x2: /* FIRST_ERROR */ + return fme_err_get_first_error(fme, &prop->data); + case 0x3: /* NEXT_ERROR */ + return fme_err_get_next_error(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x5: /* REVISION */ + return fme_err_get_revision(fme, &prop->data); + case 0x6: /* PCIE0_ERRORS */ + return fme_err_get_pcie0_errors(fme, &prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_get_pcie1_errors(fme, &prop->data); + case 0x8: /* NONFATAL_ERRORS */ + return fme_err_get_nonfatal_errors(fme, &prop->data); + case 0x9: /* CATFATAL_ERRORS */ + return fme_err_get_catfatal_errors(fme, &prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_get_inject_errors(fme, &prop->data); + case 0xb: /* REVISION*/ + return fme_err_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_get_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_err_fme_err_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x4: /* CLEAR */ + return fme_err_set_clear(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x6: /* PCIE0_ERRORS */ + return fme_err_set_pcie0_errors(fme, prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_set_pcie1_errors(fme, prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_set_inject_errors(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_set_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_set_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_global_err_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_fme_err_irq_set *err_irq_set = + (struct fpga_fme_err_irq_set *)irq_set; + struct ifpga_fme_hw *fme; + int ret; + + fme = (struct ifpga_fme_hw *)feature->parent; + + spinlock_lock(&fme->lock); + if (!(fme->capability & FPGA_FME_CAP_ERR_IRQ)) { + spinlock_unlock(&fme->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&fme->lock); + + return ret; +} + +struct feature_ops fme_global_err_ops = { + .init = fme_global_error_init, + .uinit = fme_global_error_uinit, + .get_prop = fme_global_error_get_prop, + .set_prop = fme_global_error_set_prop, + .set_irq = fme_global_err_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c new file mode 100644 index 0000000..e6c40a1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c @@ -0,0 +1,715 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_iperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_clk_ctr clk; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + clk.afu_interf_clock = readq(&iperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_iperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_iperf *iperf; + struct feature_header header; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + header.csr = readq(&iperf->header); + *revision = header.revision; + + return 0; +} + +static int fme_iperf_get_cache_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + *freeze = (u64)ctl.freeze; + return 0; +} + +static int fme_iperf_set_cache_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->ch_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define IPERF_TIMEOUT 30 + +static u64 read_cache_counter(struct ifpga_fme_hw *fme, + u8 channel, enum iperf_cache_events event) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + struct feature_fme_ifpmon_ch_ctr ctr0, ctr1; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* set channel access type and cache event code. */ + ctl.csr = readq(&iperf->ch_ctl); + ctl.cci_chsel = channel; + ctl.cache_event = event; + writeq(ctl.csr, &iperf->ch_ctl); + + /* check the event type in the counter registers */ + ctr0.event_code = event; + + if (fpga_wait_register_field(event_code, ctr0, + &iperf->ch_ctr0, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched cache event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr0.csr = readq(&iperf->ch_ctr0); + ctr1.csr = readq(&iperf->ch_ctr1); + counter = ctr0.cache_counter + ctr1.cache_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define CACHE_SHOW(name, type, event) \ +static int fme_iperf_get_cache_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_cache_counter(fme, type, event); \ + return 0; \ +} + +CACHE_SHOW(read_hit, CACHE_CHANNEL_RD, IPERF_CACHE_RD_HIT); +CACHE_SHOW(read_miss, CACHE_CHANNEL_RD, IPERF_CACHE_RD_MISS); +CACHE_SHOW(write_hit, CACHE_CHANNEL_WR, IPERF_CACHE_WR_HIT); +CACHE_SHOW(write_miss, CACHE_CHANNEL_WR, IPERF_CACHE_WR_MISS); +CACHE_SHOW(hold_request, CACHE_CHANNEL_RD, IPERF_CACHE_HOLD_REQ); +CACHE_SHOW(tx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_TX_REQ_STALL); +CACHE_SHOW(rx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_RX_REQ_STALL); +CACHE_SHOW(rx_eviction, CACHE_CHANNEL_RD, IPERF_CACHE_EVICTIONS); +CACHE_SHOW(data_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_DATA_WR_PORT_CONTEN); +CACHE_SHOW(tag_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_TAG_WR_PORT_CONTEN); + +static int fme_iperf_get_vtd_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_vtd_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->vtd_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static u64 read_iommu_sip_counter(struct ifpga_fme_hw *fme, + enum iperf_vtd_sip_events event) +{ + struct feature_fme_ifpmon_vtd_sip_ctl sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr sip_ctr; + struct feature_fme_iperf *iperf; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + sip_ctl.csr = readq(&iperf->vtd_sip_ctl); + sip_ctl.vtd_evtcode = event; + writeq(sip_ctl.csr, &iperf->vtd_sip_ctl); + + sip_ctr.event_code = event; + + if (fpga_wait_register_field(event_code, sip_ctr, + &iperf->vtd_sip_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd SIP event type in counter registers\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + sip_ctr.csr = readq(&iperf->vtd_sip_ctr); + counter = sip_ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_SIP_SHOW(name, event) \ +static int fme_iperf_get_vtd_sip_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_iommu_sip_counter(fme, event); \ + return 0; \ +} + +VTD_SIP_SHOW(iotlb_4k_hit, IPERF_VTD_SIP_IOTLB_4K_HIT); +VTD_SIP_SHOW(iotlb_2m_hit, IPERF_VTD_SIP_IOTLB_2M_HIT); +VTD_SIP_SHOW(iotlb_1g_hit, IPERF_VTD_SIP_IOTLB_1G_HIT); +VTD_SIP_SHOW(slpwc_l3_hit, IPERF_VTD_SIP_SLPWC_L3_HIT); +VTD_SIP_SHOW(slpwc_l4_hit, IPERF_VTD_SIP_SLPWC_L4_HIT); +VTD_SIP_SHOW(rcc_hit, IPERF_VTD_SIP_RCC_HIT); +VTD_SIP_SHOW(iotlb_4k_miss, IPERF_VTD_SIP_IOTLB_4K_MISS); +VTD_SIP_SHOW(iotlb_2m_miss, IPERF_VTD_SIP_IOTLB_2M_MISS); +VTD_SIP_SHOW(iotlb_1g_miss, IPERF_VTD_SIP_IOTLB_1G_MISS); +VTD_SIP_SHOW(slpwc_l3_miss, IPERF_VTD_SIP_SLPWC_L3_MISS); +VTD_SIP_SHOW(slpwc_l4_miss, IPERF_VTD_SIP_SLPWC_L4_MISS); +VTD_SIP_SHOW(rcc_miss, IPERF_VTD_SIP_RCC_MISS); + +static u64 read_iommu_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_vtd_events base_event) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_ifpmon_vtd_ctr ctr; + struct feature_fme_iperf *iperf; + enum iperf_vtd_events event = base_event + port_id; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.vtd_evtcode = event; + writeq(ctl.csr, &iperf->vtd_ctl); + + ctr.event_code = event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->vtd_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->vtd_ctr); + counter = ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_PORT_SHOW(name, base_event) \ +static int fme_iperf_get_vtd_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_iommu_counter(fme, port_id, base_event); \ + return 0; \ +} + +VTD_PORT_SHOW(read_transaction, IPERF_VTD_AFU_MEM_RD_TRANS); +VTD_PORT_SHOW(write_transaction, IPERF_VTD_AFU_MEM_WR_TRANS); +VTD_PORT_SHOW(devtlb_read_hit, IPERF_VTD_AFU_DEVTLB_RD_HIT); +VTD_PORT_SHOW(devtlb_write_hit, IPERF_VTD_AFU_DEVTLB_WR_HIT); +VTD_PORT_SHOW(devtlb_4k_fill, IPERF_VTD_DEVTLB_4K_FILL); +VTD_PORT_SHOW(devtlb_2m_fill, IPERF_VTD_DEVTLB_2M_FILL); +VTD_PORT_SHOW(devtlb_1g_fill, IPERF_VTD_DEVTLB_1G_FILL); + +static bool fabric_pobj_is_enabled(u8 port_id, struct feature_fme_iperf *iperf) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + + ctl.csr = readq(&iperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_fab_events fab_event) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_ifpmon_fab_ctr ctr; + struct feature_fme_iperf *iperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, iperf)) + goto exit; + + ctl.csr = readq(&iperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &iperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->fab_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_iperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, IPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, IPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(pcie1_read, IPERF_FAB_PCIE1_RD); +FAB_PORT_SHOW(pcie1_write, IPERF_FAB_PCIE1_WR); +FAB_PORT_SHOW(upi_read, IPERF_FAB_UPI_RD); +FAB_PORT_SHOW(upi_write, IPERF_FAB_UPI_WR); +FAB_PORT_SHOW(mmio_read, IPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, IPERF_FAB_MMIO_WR); + +static int fme_iperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_iperf *iperf; + int status; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + status = fabric_pobj_is_enabled(port_id, iperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_iperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, iperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&iperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_iperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 +#define FME_IPERF_CAP_IOMMU 0x1 + +static int fme_global_iperf_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme; + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + + dev_info(NULL, "FME global_iperf Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + /* check if iommu is not supported on this device. */ + fme_capability.csr = readq(&fme_hdr->capability); + dev_info(NULL, "FME HEAD fme_capability %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + if (fme_capability.iommu_support) + feature->cap |= FME_IPERF_CAP_IOMMU; + + return 0; +} + +static void fme_global_iperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_iperf UInit.\n"); +} + +static int fme_iperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_iperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_iperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_cache_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_cache_freeze(fme, &prop->data); + case 0x2: /* READ_HIT */ + return fme_iperf_get_cache_read_hit(fme, &prop->data); + case 0x3: /* READ_MISS */ + return fme_iperf_get_cache_read_miss(fme, &prop->data); + case 0x4: /* WRITE_HIT */ + return fme_iperf_get_cache_write_hit(fme, &prop->data); + case 0x5: /* WRITE_MISS */ + return fme_iperf_get_cache_write_miss(fme, &prop->data); + case 0x6: /* HOLD_REQUEST */ + return fme_iperf_get_cache_hold_request(fme, &prop->data); + case 0x7: /* TX_REQ_STALL */ + return fme_iperf_get_cache_tx_req_stall(fme, &prop->data); + case 0x8: /* RX_REQ_STALL */ + return fme_iperf_get_cache_rx_req_stall(fme, &prop->data); + case 0x9: /* RX_EVICTION */ + return fme_iperf_get_cache_rx_eviction(fme, &prop->data); + case 0xa: /* DATA_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_data_write_port_contention(fme, + &prop->data); + case 0xb: /* TAG_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_tag_write_port_contention(fme, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_vtd_freeze(fme, &prop->data); + case 0x2: /* IOTLB_4K_HIT */ + return fme_iperf_get_vtd_sip_iotlb_4k_hit(fme, &prop->data); + case 0x3: /* IOTLB_2M_HIT */ + return fme_iperf_get_vtd_sip_iotlb_2m_hit(fme, &prop->data); + case 0x4: /* IOTLB_1G_HIT */ + return fme_iperf_get_vtd_sip_iotlb_1g_hit(fme, &prop->data); + case 0x5: /* SLPWC_L3_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l3_hit(fme, &prop->data); + case 0x6: /* SLPWC_L4_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l4_hit(fme, &prop->data); + case 0x7: /* RCC_HIT */ + return fme_iperf_get_vtd_sip_rcc_hit(fme, &prop->data); + case 0x8: /* IOTLB_4K_MISS */ + return fme_iperf_get_vtd_sip_iotlb_4k_miss(fme, &prop->data); + case 0x9: /* IOTLB_2M_MISS */ + return fme_iperf_get_vtd_sip_iotlb_2m_miss(fme, &prop->data); + case 0xa: /* IOTLB_1G_MISS */ + return fme_iperf_get_vtd_sip_iotlb_1g_miss(fme, &prop->data); + case 0xb: /* SLPWC_L3_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l3_miss(fme, &prop->data); + case 0xc: /* SLPWC_L4_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l4_miss(fme, &prop->data); + case 0xd: /* RCC_MISS */ + return fme_iperf_get_vtd_sip_rcc_miss(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_sub_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub > PERF_MAX_PORT_NUM) + return -ENOENT; + + switch (id) { + case 0xe: /* READ_TRANSACTION */ + return fme_iperf_get_vtd_port_read_transaction(fme, sub, + &prop->data); + case 0xf: /* WRITE_TRANSACTION */ + return fme_iperf_get_vtd_port_write_transaction(fme, sub, + &prop->data); + case 0x10: /* DEVTLB_READ_HIT */ + return fme_iperf_get_vtd_port_devtlb_read_hit(fme, sub, + &prop->data); + case 0x11: /* DEVTLB_WRITE_HIT */ + return fme_iperf_get_vtd_port_devtlb_write_hit(fme, sub, + &prop->data); + case 0x12: /* DEVTLB_4K_FILL */ + return fme_iperf_get_vtd_port_devtlb_4k_fill(fme, sub, + &prop->data); + case 0x13: /* DEVTLB_2M_FILL */ + return fme_iperf_get_vtd_port_devtlb_2m_fill(fme, sub, + &prop->data); + case 0x14: /* DEVTLB_1G_FILL */ + return fme_iperf_get_vtd_port_devtlb_1g_fill(fme, sub, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED) + return fme_iperf_vtd_root_get_prop(feature, prop); + + return fme_iperf_vtd_sub_get_prop(feature, prop); +} + +static int fme_iperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + /* Other properties are present for both top and sub levels */ + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_iperf_get_fab_port_pcie0_read(fme, sub, + &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_iperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* PCIE1_READ */ + return fme_iperf_get_fab_port_pcie1_read(fme, sub, + &prop->data); + case 0x5: /* PCIE1_WRITE */ + return fme_iperf_get_fab_port_pcie1_write(fme, sub, + &prop->data); + case 0x6: /* UPI_READ */ + return fme_iperf_get_fab_port_upi_read(fme, sub, + &prop->data); + case 0x7: /* UPI_WRITE */ + return fme_iperf_get_fab_port_upi_write(fme, sub, + &prop->data); + case 0x8: /* MMIO_READ */ + return fme_iperf_get_fab_port_mmio_read(fme, sub, + &prop->data); + case 0x9: /* MMIO_WRITE */ + return fme_iperf_get_fab_port_mmio_write(fme, sub, + &prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_get_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_get_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_iperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_iperf_cache_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_cache_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_vtd_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_vtd_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_set_fab_freeze(fme, prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_set_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_set_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_iperf_ops = { + .init = fme_global_iperf_init, + .uinit = fme_global_iperf_uinit, + .get_prop = fme_global_iperf_get_prop, + .set_prop = fme_global_iperf_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c new file mode 100644 index 0000000..6192fa7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c @@ -0,0 +1,372 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#if defined(RTE_ARCH_X86_64) +static inline void copy512(const void *src, void *dst) +{ + asm volatile("vmovdqu64 (%0), %%zmm0;" + "vmovntdq %%zmm0, (%1);" + : + : "r"(src), "r"(dst)); +} +#else +static inline void copy512(const void *src, void *dst) +{ + UNUSED(src); + UNUSED(dst); + WARN_ON(1); +} +#endif + +static u64 +pr_err_handle(struct feature_fme_pr *fme_pr) +{ + struct feature_fme_pr_status fme_pr_status; + unsigned long err_code; + u64 fme_pr_error; + int i; + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + if (!fme_pr_status.pr_status) + return 0; + + err_code = readq(&fme_pr->ccip_fme_pr_err); + fme_pr_error = err_code; + + for (i = 0; i < PR_MAX_ERR_NUM; i++) { + if (err_code & (1 << i)) + dev_info(NULL, "%s\n", pr_err_msg[i]); + } + + writeq(fme_pr_error, &fme_pr->ccip_fme_pr_err); + return fme_pr_error; +} + +static int fme_pr_write_init(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + if (info->flags != FPGA_MGR_PARTIAL_RECONFIG) + return -EINVAL; + + dev_info(fme_dev, "resetting PR before initiated PR\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + fme_pr_ctl.pr_reset_ack = 1; + + if (fpga_wait_register_field(pr_reset_ack, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 0; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "waiting for PR resource in HW to be initialized and ready\n"); + + fme_pr_status.pr_host_status = PR_HOST_STATUS_IDLE; + + if (fpga_wait_register_field(pr_host_status, fme_pr_status, + &fme_pr->ccip_fme_pr_status, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "check if have any previous PR error\n"); + pr_err_handle(fme_pr); + return 0; +} + +static int fme_pr_write(struct ifpga_fme_hw *fme_dev, + int port_id, const char *buf, size_t count, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + struct feature_fme_pr_data fme_pr_data; + int delay, pr_credit; + int ret = 0; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + dev_info(fme_dev, "set PR port ID and start request\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_regionid = port_id; + fme_pr_ctl.pr_start_req = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "pushing data from bitstream to HW\n"); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + + while (count > 0) { + delay = 0; + while (pr_credit <= 1) { + if (delay++ > PR_WAIT_TIMEOUT) { + dev_err(fme_dev, "maximum try\n"); + + info->pr_err = pr_err_handle(fme_pr); + return info->pr_err ? -EIO : -ETIMEDOUT; + } + udelay(1); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + }; + + if (count >= fme_dev->pr_bandwidth) { + switch (fme_dev->pr_bandwidth) { + case 4: + fme_pr_data.rsvd = 0; + fme_pr_data.pr_data_raw = *((const u32 *)buf); + writeq(fme_pr_data.csr, + &fme_pr->ccip_fme_pr_data); + break; + case 64: + copy512(buf, &fme_pr->fme_pr_data1); + break; + default: + ret = -EFAULT; + goto done; + } + + buf += fme_dev->pr_bandwidth; + count -= fme_dev->pr_bandwidth; + pr_credit--; + } else { + WARN_ON(1); + return -EINVAL; + goto done; + } + } + +done: + return ret; +} + +static int fme_pr_write_complete(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_push_complete = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "green bitstream push complete\n"); + dev_info(fme_dev, "waiting for HW to release PR resource\n"); + + fme_pr_ctl.pr_start_req = 0; + + if (fpga_wait_register_field(pr_start_req, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + printf("maximum try.\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "PR operation complete, checking status\n"); + info->pr_err = pr_err_handle(fme_pr); + if (info->pr_err) + return -EIO; + + dev_info(fme_dev, "PR done successfully\n"); + return 0; +} + +static int fpga_pr_buf_load(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info, const char *buf, + size_t count) +{ + int ret; + + info->state = FPGA_PR_STATE_WRITE_INIT; + ret = fme_pr_write_init(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error preparing FPGA for writing\n"); + info->state = FPGA_PR_STATE_WRITE_INIT_ERR; + return ret; + } + + /* + * Write the FPGA image to the FPGA. + */ + info->state = FPGA_PR_STATE_WRITE; + ret = fme_pr_write(fme_dev, info->port_id, buf, count, info); + if (ret) { + dev_err(fme_dev, "Error while writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_ERR; + return ret; + } + + /* + * After all the FPGA image has been written, do the device specific + * steps to finish and set the FPGA into operating mode. + */ + info->state = FPGA_PR_STATE_WRITE_COMPLETE; + ret = fme_pr_write_complete(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error after writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_COMPLETE_ERR; + return ret; + } + info->state = FPGA_PR_STATE_DONE; + + return 0; +} + +static int fme_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + struct ifpga_fme_hw *fme = &hw->fme; + struct fpga_pr_info info; + struct ifpga_port_hw *port; + int ret = 0; + + if (!buffer || size == 0) + return -EINVAL; + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + /* + * Padding extra zeros to align PR buffer with PR bandwidth, HW will + * ignore these zeros automatically. + */ + size = ALIGN(size, fme->pr_bandwidth); + + /* get fme header region */ + fme_hdr = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_HEADER); + if (!fme_hdr) + return -EINVAL; + + /* check port id */ + fme_capability.csr = readq(&fme_hdr->capability); + if (port_id >= fme_capability.num_ports) { + dev_err(fme, "port number more than maximum\n"); + return -EINVAL; + } + + memset(&info, 0, sizeof(struct fpga_pr_info)); + info.flags = FPGA_MGR_PARTIAL_RECONFIG; + info.port_id = port_id; + + spinlock_lock(&fme->lock); + + /* get port device by port_id */ + port = &hw->port[port_id]; + + /* Disable Port before PR */ + fpga_port_disable(port); + + ret = fpga_pr_buf_load(fme, &info, (void *)buffer, size); + + *status = info.pr_err; + + /* Re-enable Port after PR finished */ + fpga_port_enable(port); + spinlock_unlock(&fme->lock); + + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, u64 *status) +{ + struct bts_header *bts_hdr; + void *buf; + struct ifpga_port_hw *port; + int ret; + + if (!buffer || size == 0) { + dev_err(hw, "invalid parameter\n"); + return -EINVAL; + } + + bts_hdr = (struct bts_header *)buffer; + + if (is_valid_bts(bts_hdr)) { + dev_info(hw, "this is a valid bitsteam..\n"); + size -= (sizeof(struct bts_header) + + bts_hdr->metadata_len); + buf = (u8 *)buffer + sizeof(struct bts_header) + + bts_hdr->metadata_len; + } else { + return -EINVAL; + } + + /* clean port error before do PR */ + port = &hw->port[port_id]; + ret = port_clear_error(port); + if (ret) { + dev_err(hw, "port cannot clear error\n"); + return -EINVAL; + } + + return fme_pr(hw, port_id, buf, size, status); +} + +static int fme_pr_mgmt_init(struct feature *feature) +{ + struct feature_fme_pr *fme_pr; + struct feature_header fme_pr_header; + struct ifpga_fme_hw *fme; + + dev_info(NULL, "FME PR MGMT Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + + fme_pr = (struct feature_fme_pr *)feature->addr; + + fme_pr_header.csr = readq(&fme_pr->header); + if (fme_pr_header.revision == 2) { + dev_info(NULL, "using 512-bit PR\n"); + fme->pr_bandwidth = 64; + } else { + dev_info(NULL, "using 32-bit PR\n"); + fme->pr_bandwidth = 4; + } + + return 0; +} + +static void fme_pr_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME PR MGMT UInit.\n"); +} + +struct 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 new file mode 100644 index 0000000..a20520c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_HW_H_ +#define _IFPGA_HW_H_ + +#include "ifpga_defines.h" +#include "opae_ifpga_hw_api.h" + +enum ifpga_feature_state { + IFPGA_FEATURE_UNUSED = 0, + IFPGA_FEATURE_ATTACHED, +}; + +struct feature_irq_ctx { + int eventfd; + int idx; +}; + +struct feature { + enum ifpga_feature_state state; + const char *name; + u64 id; + u8 *addr; + uint64_t phys_addr; + u32 size; + int revision; + u64 cap; + int vfio_dev_fd; + struct feature_irq_ctx *ctx; + unsigned int ctx_num; + + void *parent; /* to parent hw data structure */ + + struct feature_ops *ops;/* callback to this private feature */ +}; + +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); +}; + +enum ifpga_fme_state { + IFPGA_FME_UNUSED = 0, + IFPGA_FME_IMPLEMENTED, +}; + +struct ifpga_fme_hw { + enum ifpga_fme_state state; + + struct feature sub_feature[FME_FEATURE_ID_MAX]; + spinlock_t lock; /* protect hardware access */ + + void *parent; /* pointer to ifpga_hw */ + + /* provied by HEADER feature */ + u32 port_num; + struct uuid bitstream_id; + u64 bitstream_md; + size_t pr_bandwidth; + u32 socket_id; + u32 fabric_version_id; + u32 cache_size; + + u32 capability; +}; + +enum ifpga_port_state { + IFPGA_PORT_UNUSED = 0, + IFPGA_PORT_ATTACHED, + IFPGA_PORT_DETACHED, +}; + +struct ifpga_port_hw { + enum ifpga_port_state state; + + struct feature sub_feature[PORT_FEATURE_ID_MAX]; + spinlock_t lock; /* protect access to hw */ + + void *parent; /* pointer to ifpga_hw */ + + int port_id; /* provied by HEADER feature */ + struct uuid afu_id; /* provied by User AFU feature */ + + unsigned int disable_count; + + u32 capability; + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ + u8 *stp_addr; + u32 stp_size; +}; + +#define AFU_MAX_REGION 1 + +struct ifpga_afu_info { + struct opae_reg_region region[AFU_MAX_REGION]; + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct ifpga_hw { + struct opae_adapter *adapter; + struct opae_adapter_data_pci *pci_data; + + struct ifpga_fme_hw fme; + struct ifpga_port_hw port[MAX_FPGA_PORT_NUM]; +}; + +static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) +{ + return hw->fme.state != IFPGA_FME_UNUSED; +} + +static inline bool is_valid_port_id(struct ifpga_hw *hw, u32 port_id) +{ + if (port_id >= MAX_FPGA_PORT_NUM || + hw->port[port_id].state != IFPGA_PORT_ATTACHED) + return false; + + return true; +} +#endif /* _IFPGA_HW_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c new file mode 100644 index 0000000..8ab1bdb --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c @@ -0,0 +1,408 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +static int port_get_revision(struct ifpga_port_hw *port, u64 *revision) +{ + struct feature_port_header *port_hdr + = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&port_hdr->header); + + *revision = header.revision; + + return 0; +} + +static int port_get_portidx(struct ifpga_port_hw *port, u64 *idx) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + capability.csr = readq(&port_hdr->capability); + *idx = capability.port_number; + + return 0; +} + +static int port_get_latency_tolerance(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + control.csr = readq(&port_hdr->control); + *val = control.latency_tolerance; + + return 0; +} + +static int port_get_ap1_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap1_event; + + return 0; +} + +static int port_set_ap1_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap1_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_ap2_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap2_event; + + return 0; +} + +static int port_set_ap2_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap2_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_power_state(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.power_state; + + return 0; +} + +static int port_get_userclk_freqcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_hdr_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port hdr Init.\n"); + + fpga_port_reset(port); + + return 0; +} + +static void port_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port hdr uinit.\n"); +} + +static int port_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_REVISION: + return port_get_revision(port, &prop->data); + case PORT_HDR_PROP_PORTIDX: + return port_get_portidx(port, &prop->data); + case PORT_HDR_PROP_LATENCY_TOLERANCE: + return port_get_latency_tolerance(port, &prop->data); + case PORT_HDR_PROP_AP1_EVENT: + return port_get_ap1_event(port, &prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_get_ap2_event(port, &prop->data); + case PORT_HDR_PROP_POWER_STATE: + return port_get_power_state(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_get_userclk_freqcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_get_userclk_freqcntrcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQSTS: + return port_get_userclk_freqsts(port, &prop->data); + case PORT_HDR_PROP_USERCLK_CNTRSTS: + return port_get_userclk_freqcntrsts(port, &prop->data); + } + + return -ENOENT; +} + +static int port_hdr_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_AP1_EVENT: + return port_set_ap1_event(port, prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_set_ap2_event(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_set_userclk_freqcmd(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_set_userclk_freqcntrcmd(port, prop->data); + } + + return -ENOENT; +} + +struct feature_ops 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) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port stp Init.\n"); + + spinlock_lock(&port->lock); + port->stp_addr = feature->addr; + port->stp_size = feature->size; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_stp_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port stp uinit.\n"); +} + +struct feature_ops port_stp_ops = { + .init = port_stp_init, + .uinit = port_stp_uinit, +}; + +static int port_uint_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "PORT UINT Init.\n"); + + spinlock_lock(&port->lock); + if (feature->ctx_num) { + port->capability |= FPGA_PORT_CAP_UAFU_IRQ; + port->num_uafu_irqs = feature->ctx_num; + } + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_uint_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT UINT UInit.\n"); +} + +static int port_uint_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_uafu_irq_set *uafu_irq_set = irq_set; + struct ifpga_port_hw *port = feature->parent; + int ret; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_UAFU_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, uafu_irq_set->start, + uafu_irq_set->count, uafu_irq_set->evtfds); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_uint_ops = { + .init = port_uint_init, + .uinit = port_uint_uinit, + .set_irq = port_uint_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c new file mode 100644 index 0000000..3be0f5e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static int port_err_get_revision(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_header header; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + header.csr = readq(&port_err->header); + *val = header.revision; + + return 0; +} + +static int port_err_get_errors(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + *val = error.csr; + + return 0; +} + +static int port_err_get_first_error(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_first_err_key first_error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + first_error.csr = readq(&port_err->port_first_error); + *val = first_error.csr; + + return 0; +} + +static int port_err_get_first_malformed_req_lsb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req0 malreq0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq0.header_lsb = readq(&port_err->malreq0); + *val = malreq0.header_lsb; + + return 0; +} + +static int port_err_get_first_malformed_req_msb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req1 malreq1; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq1.header_msb = readq(&port_err->malreq1); + *val = malreq1.header_msb; + + return 0; +} + +static int port_err_set_clear(struct ifpga_port_hw *port, u64 val) +{ + int ret; + + spinlock_lock(&port->lock); + ret = port_err_clear(port, val); + spinlock_unlock(&port->lock); + + return ret; +} + +static int port_error_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port error Init.\n"); + + spinlock_lock(&port->lock); + port_err_mask(port, false); + if (feature->ctx_num) + port->capability |= FPGA_PORT_CAP_ERR_IRQ; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int port_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_ERR_PROP_REVISION: + return port_err_get_revision(port, &prop->data); + case PORT_ERR_PROP_ERRORS: + return port_err_get_errors(port, &prop->data); + case PORT_ERR_PROP_FIRST_ERROR: + return port_err_get_first_error(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB: + return port_err_get_first_malformed_req_lsb(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB: + return port_err_get_first_malformed_req_msb(port, &prop->data); + } + + return -ENOENT; +} + +static int port_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + if (prop->prop_id == PORT_ERR_PROP_CLEAR) + return port_err_set_clear(port, prop->data); + + return -ENOENT; +} + +static int port_error_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_port_err_irq_set *err_irq_set = irq_set; + struct ifpga_port_hw *port; + int ret; + + port = feature->parent; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_ERR_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_error_ops = { + .init = port_error_init, + .uinit = port_error_uinit, + .get_prop = port_error_get_prop, + .set_prop = port_error_set_prop, + .set_irq = port_error_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.c b/drivers/raw/ifpga_rawdev/base/opae_debug.c new file mode 100644 index 0000000..024d7d2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.c @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#define OPAE_HW_DEBUG + +#include "opae_hw_api.h" +#include "opae_debug.h" + +void opae_manager_dump(struct opae_manager *mgr) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Manger %s\n", mgr->name); + opae_log("OPAE Manger OPs = %p\n", mgr->ops); + opae_log("OPAE Manager Private Data = %p\n", mgr->data); + opae_log("OPAE Adapter(parent) = %p\n", mgr->adapter); + opae_log("==========================\n"); +} + +void opae_bridge_dump(struct opae_bridge *br) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Bridge %s\n", br->name); + opae_log("OPAE Bridge ID = %d\n", br->id); + opae_log("OPAE Bridge OPs = %p\n", br->ops); + opae_log("OPAE Bridge Private Data = %p\n", br->data); + opae_log("OPAE Accelerator(under this bridge) = %p\n", br->acc); + opae_log("==========================\n"); +} + +void opae_accelerator_dump(struct opae_accelerator *acc) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Accelerator %s\n", acc->name); + opae_log("OPAE Accelerator Index = %d\n", acc->index); + opae_log("OPAE Accelerator OPs = %p\n", acc->ops); + opae_log("OPAE Accelerator Private Data = %p\n", acc->data); + opae_log("OPAE Bridge (upstream) = %p\n", acc->br); + opae_log("OPAE Manager (upstream) = %p\n", acc->mgr); + opae_log("==========================\n"); + + if (acc->br) + opae_bridge_dump(acc->br); +} + +static void opae_adapter_data_dump(void *data) +{ + struct opae_adapter_data *d = data; + struct opae_adapter_data_pci *d_pci; + struct opae_reg_region *r; + int i; + + opae_log("=====%s=====\n", __func__); + + switch (d->type) { + case OPAE_FPGA_PCI: + d_pci = (struct opae_adapter_data_pci *)d; + + opae_log("OPAE Adapter Type = PCI\n"); + opae_log("PCI Device ID: 0x%04x\n", d_pci->device_id); + opae_log("PCI Vendor ID: 0x%04x\n", d_pci->vendor_id); + + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + r = &d_pci->region[i]; + opae_log("PCI Bar %d: phy(%llx) len(%llx) addr(%p)\n", + i, (unsigned long long)r->phys_addr, + (unsigned long long)r->len, r->addr); + } + break; + case OPAE_FPGA_NET: + break; + } + + opae_log("==========================\n"); +} + +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) { + if (adapter->mgr) + opae_manager_dump(adapter->mgr); + + opae_adapter_for_each_acc(adapter, acc) + opae_accelerator_dump(acc); + + if (adapter->data) + opae_adapter_data_dump(adapter->data); + } + + opae_log("==========================\n"); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.h b/drivers/raw/ifpga_rawdev/base/opae_debug.h new file mode 100644 index 0000000..a03dff9 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_DEBUG_H_ +#define _OPAE_DEBUG_H_ + +#ifdef OPAE_HW_DEBUG +#define opae_log(fmt, args...) printf(fmt, ## args) +#else +#define opae_log(fme, args...) do {} while (0) +#endif + +void opae_manager_dump(struct opae_manager *mgr); +void opae_bridge_dump(struct opae_bridge *br); +void opae_accelerator_dump(struct opae_accelerator *acc); +void opae_adapter_dump(struct opae_adapter *adapter, int verbose); + +#endif /* _OPAE_DEBUG_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c new file mode 100644 index 0000000..a533dfe --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -0,0 +1,381 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_hw_api.h" +#include "opae_debug.h" +#include "ifpga_api.h" + +/* OPAE Bridge Functions */ + +/** + * opae_bridge_alloc - alloc opae_bridge data structure + * @name: bridge name. + * @ops: ops of this bridge. + * @data: private data of this bridge. + * + * Return opae_bridge on success, otherwise NULL. + */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data) +{ + struct opae_bridge *br = opae_zmalloc(sizeof(*br)); + + if (!br) + return NULL; + + br->name = name; + br->ops = ops; + br->data = data; + + opae_log("%s %p\n", __func__, br); + + return br; +} + +/** + * opae_bridge_reset - reset opae_bridge + * @br: bridge to be reset. + * + * Return: 0 on success, otherwise error code. + */ +int opae_bridge_reset(struct opae_bridge *br) +{ + if (!br) + return -EINVAL; + + if (br->ops && br->ops->reset) + return br->ops->reset(br); + + opae_log("%s no ops\n", __func__); + + return -ENOENT; +} + +/* Accelerator Functions */ + +/** + * opae_accelerator_alloc - alloc opae_accelerator data structure + * @name: accelerator name. + * @ops: ops of this accelerator. + * @data: private data of this accelerator. + * + * Return: opae_accelerator on success, otherwise NULL. + */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data) +{ + struct opae_accelerator *acc = opae_zmalloc(sizeof(*acc)); + + if (!acc) + return NULL; + + acc->name = name; + acc->ops = ops; + acc->data = data; + + opae_log("%s %p\n", __func__, acc); + + return acc; +} + +/** + * opae_acc_reg_read - read accelerator's register from its reg region. + * @acc: accelerator to read. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: read operation width, e.g 4 byte = 32bit read. + * @data: data to store the value read from the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->read) + return acc->ops->read(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_reg_write - write to accelerator's register from its reg region. + * @acc: accelerator to write. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: write operation width, e.g 4 byte = 32bit write. + * @data: data stored the value to write to the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->write) + return acc->ops->write(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_get_info - get information of an accelerator. + * @acc: targeted accelerator + * @info: accelerator info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_info) + return acc->ops->get_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_get_region_info - get information of an accelerator register region. + * @acc: targeted accelerator + * @info: accelerator region info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_region_info) + return acc->ops->get_region_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_set_irq - set an accelerator's irq. + * @acc: targeted accelerator + * @start: start vector number + * @count: count of vectors to be set from the start vector + * @evtfds: event fds to be notified when corresponding irqs happens + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + if (!acc || !acc->data) + return -EINVAL; + + if (start + count <= start) + return -EINVAL; + + if (acc->ops && acc->ops->set_irq) + return acc->ops->set_irq(acc, start, count, evtfds); + + return -ENOENT; +} + +/** + * opae_acc_get_uuid - get accelerator's UUID. + * @acc: targeted accelerator + * @uuid: a pointer to UUID + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + if (!acc || !uuid) + return -EINVAL; + + if (acc->ops && acc->ops->get_uuid) + return acc->ops->get_uuid(acc, uuid); + + return -ENOENT; +} + +/* Manager Functions */ + +/** + * opae_manager_alloc - alloc opae_manager data structure + * @name: manager name. + * @ops: ops of this manager. + * @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) +{ + struct opae_manager *mgr = opae_zmalloc(sizeof(*mgr)); + + if (!mgr) + return NULL; + + mgr->name = name; + mgr->ops = ops; + mgr->data = data; + + opae_log("%s %p\n", __func__, mgr); + + return mgr; +} + +/** + * opae_manager_flash - flash a reconfiguration image via opae_manager + * @mgr: opae_manager for flash. + * @id: id of target region (accelerator). + * @buf: image data buffer. + * @size: buffer size. + * @status: status to store flash result. + * + * Return: 0 on success, otherwise error code. + */ +int opae_manager_flash(struct opae_manager *mgr, int id, void *buf, u32 size, + u64 *status) +{ + if (!mgr) + return -EINVAL; + + if (mgr && mgr->ops && mgr->ops->flash) + return mgr->ops->flash(mgr, id, buf, size, status); + + return -ENOENT; +} + +/* Adapter Functions */ + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @type: opae_adapter_type. + * + * Return: opae_adapter_data on success, otherwise NULL. + */ +void *opae_adapter_data_alloc(enum opae_adapter_type type) +{ + struct opae_adapter_data *data; + int size; + + switch (type) { + case OPAE_FPGA_PCI: + size = sizeof(struct opae_adapter_data_pci); + break; + case OPAE_FPGA_NET: + size = sizeof(struct opae_adapter_data_net); + break; + default: + size = sizeof(struct opae_adapter_data); + break; + } + + data = opae_zmalloc(size); + if (!data) + return NULL; + + data->type = type; + + return data; +} + +static struct opae_adapter_ops *match_ops(struct opae_adapter *adapter) +{ + struct opae_adapter_data *data; + + if (!adapter || !adapter->data) + return NULL; + + data = adapter->data; + + if (data->type == OPAE_FPGA_PCI) + return &ifpga_adapter_ops; + + return NULL; +} + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @name: adapter name. + * @data: private data of this adapter. + * + * Return: opae_adapter on success, otherwise NULL. + */ +struct opae_adapter *opae_adapter_alloc(const char *name, void *data) +{ + struct opae_adapter *adapter = opae_zmalloc(sizeof(*adapter)); + + if (!adapter) + return NULL; + + TAILQ_INIT(&adapter->acc_list); + adapter->data = data; + adapter->name = name; + adapter->ops = match_ops(adapter); + + return adapter; +} + +/** + * opae_adapter_enumerate - enumerate this adapter + * @adapter: adapter to enumerate. + * + * Return: 0 on success, otherwise error code. + */ +int opae_adapter_enumerate(struct opae_adapter *adapter) +{ + int ret = -ENOENT; + + if (!adapter) + return -EINVAL; + + if (adapter->ops && adapter->ops->enumerate) + ret = adapter->ops->enumerate(adapter); + + if (!ret) + opae_adapter_dump(adapter, 1); + + return ret; +} + +/** + * opae_adapter_destroy - destroy this adapter + * @adapter: adapter to destroy. + * + * destroy things allocated during adapter enumeration. + */ +void opae_adapter_destroy(struct opae_adapter *adapter) +{ + if (adapter && adapter->ops && adapter->ops->destroy) + adapter->ops->destroy(adapter); +} + +/** + * opae_adapter_get_acc - find and return accelerator with matched id + * @adapter: adapter to find the accelerator. + * @acc_id: id (index) of the accelerator. + * + * destroy things allocated during adapter enumeration. + */ +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id) +{ + struct opae_accelerator *acc = NULL; + + if (!adapter) + return NULL; + + opae_adapter_for_each_acc(adapter, acc) + if (acc->index == acc_id) + return acc; + + return NULL; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h new file mode 100644 index 0000000..4bbc9df --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_HW_API_H_ +#define _OPAE_HW_API_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> + +#include "opae_osdep.h" + +#ifndef PCI_MAX_RESOURCE +#define PCI_MAX_RESOURCE 6 +#endif + +struct opae_adapter; + +enum opae_adapter_type { + OPAE_FPGA_PCI, + OPAE_FPGA_NET, +}; + +/* OPAE Manager Data Structure */ +struct opae_manager_ops; + +/* + * opae_manager has pointer to its parent adapter, as it could be able to manage + * all components on this FPGA device (adapter). If not the case, don't set this + * adapter, which limit opae_manager ops to manager itself. + */ +struct opae_manager { + const char *name; + struct opae_adapter *adapter; + struct opae_manager_ops *ops; + void *data; +}; + +/* FIXME: add more management ops, e.g power/thermal and etc */ +struct opae_manager_ops { + int (*flash)(struct opae_manager *mgr, int id, void *buffer, + u32 size, u64 *status); +}; + +/* OPAE Manager APIs */ +struct opae_manager * +opae_manager_alloc(const char *name, struct opae_manager_ops *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); + +/* OPAE Bridge Data Structure */ +struct opae_bridge_ops; + +/* + * opae_bridge only has pointer to its downstream accelerator. + */ +struct opae_bridge { + const char *name; + int id; + struct opae_accelerator *acc; + struct opae_bridge_ops *ops; + void *data; +}; + +struct opae_bridge_ops { + int (*reset)(struct opae_bridge *br); +}; + +/* OPAE Bridge APIs */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data); +int opae_bridge_reset(struct opae_bridge *br); +#define opae_bridge_free(br) opae_free(br) + +/* OPAE Acceleraotr Data Structure */ +struct opae_accelerator_ops; + +/* + * opae_accelerator has pointer to its upstream bridge(port). + * In some cases, if we allow same user to do PR on its own accelerator, then + * set the manager pointer during the enumeration. But in other cases, the PR + * functions only could be done via manager in another module / thread / service + * / application for better protection. + */ +struct opae_accelerator { + TAILQ_ENTRY(opae_accelerator) node; + const char *name; + int index; + struct opae_bridge *br; + struct opae_manager *mgr; + struct opae_accelerator_ops *ops; + void *data; +}; + +struct opae_acc_info { + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct opae_acc_region_info { + u32 flags; +#define ACC_REGION_READ (1 << 0) +#define ACC_REGION_WRITE (1 << 1) +#define ACC_REGION_MMIO (1 << 2) + u32 index; + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_accelerator_ops { + int (*read)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*write)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*get_info)(struct opae_accelerator *acc, + struct opae_acc_info *info); + int (*get_region_info)(struct opae_accelerator *acc, + struct opae_acc_region_info *info); + int (*set_irq)(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); + int (*get_uuid)(struct opae_accelerator *acc, + struct uuid *uuid); +}; + +/* OPAE accelerator APIs */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data); +#define opae_accelerator_free(acc) opae_free(acc) +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info); +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info); +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid); + +static inline struct opae_bridge * +opae_acc_get_br(struct opae_accelerator *acc) +{ + return acc ? acc->br : NULL; +} + +static inline struct opae_manager * +opae_acc_get_mgr(struct opae_accelerator *acc) +{ + return acc ? acc->mgr : NULL; +} + +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + +#define opae_acc_reg_read64(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 8, data) +#define opae_acc_reg_write64(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 8, data) +#define opae_acc_reg_read32(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 4, data) +#define opae_acc_reg_write32(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 4, data) +#define opae_acc_reg_read16(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 2, data) +#define opae_acc_reg_write16(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 2, data) +#define opae_acc_reg_read8(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 1, data) +#define opae_acc_reg_write8(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 1, data) + +/*for data stream read/write*/ +int opae_acc_data_read(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); +int opae_acc_data_write(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); + +/* OPAE Adapter Data Structure */ +struct opae_adapter_data { + enum opae_adapter_type type; +}; + +struct opae_reg_region { + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_adapter_data_pci { + enum opae_adapter_type type; + u16 device_id; + u16 vendor_id; + struct opae_reg_region region[PCI_MAX_RESOURCE]; + int vfio_dev_fd; /* VFIO device file descriptor */ +}; + +/* FIXME: OPAE_FPGA_NET type */ +struct opae_adapter_data_net { + enum opae_adapter_type type; +}; + +struct opae_adapter_ops { + int (*enumerate)(struct opae_adapter *adapter); + void (*destroy)(struct opae_adapter *adapter); +}; + +TAILQ_HEAD(opae_accelerator_list, opae_accelerator); + +#define opae_adapter_for_each_acc(adatper, acc) \ + TAILQ_FOREACH(acc, &adapter->acc_list, node) + +struct opae_adapter { + const char *name; + struct opae_manager *mgr; + struct opae_accelerator_list acc_list; + struct opae_adapter_ops *ops; + void *data; +}; + +/* OPAE Adapter APIs */ +void *opae_adapter_data_alloc(enum opae_adapter_type type); +#define opae_adapter_data_free(data) opae_free(data) + +struct opae_adapter *opae_adapter_alloc(const char *name, void *data); +#define opae_adapter_free(adapter) opae_free(adapter) + +int opae_adapter_enumerate(struct opae_adapter *adapter); +void opae_adapter_destroy(struct opae_adapter *adapter); +static inline struct opae_manager * +opae_adapter_get_mgr(struct opae_adapter *adapter) +{ + return adapter ? adapter->mgr : NULL; +} + +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id); + +static inline void opae_adapter_add_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_INSERT_TAIL(&adapter->acc_list, acc, node); +} + +static inline void opae_adapter_remove_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_REMOVE(&adapter->acc_list, acc, node); +} +#endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c new file mode 100644 index 0000000..a40c8da --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_ifpga_hw_api.h" +#include "ifpga_api.h" + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data || !fme_info) + return -EINVAL; + + fme = mgr->data; + + spinlock_lock(&fme->lock); + fme_info->capability = fme->capability; + spinlock_unlock(&fme->lock); + + return 0; +} + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_irq(fme->parent, FEATURE_FIU_ID_FME, 0, + IFPGA_FME_FEATURE_ID_GLOBAL_ERR, err_irq_set); +} + +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_get_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !port_info) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + port_info->capability = port->capability; + port_info->num_uafu_irqs = port->num_uafu_irqs; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !info) + return -EINVAL; + + /* Only support STP region now */ + if (info->index != PORT_REGION_INDEX_STP) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + info->addr = (u64)port->stp_addr; + info->size = port->stp_size; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_ERROR, err_irq_set); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h new file mode 100644 index 0000000..65086cf --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_IFPGA_HW_API_H_ +#define _OPAE_IFPGA_HW_API_H_ + +#include "opae_hw_api.h" + +/** + * struct feature_prop - data structure for feature property + * @feature_id: id of this feature. + * @prop_id: id of this property under this feature. + * @data: property value to set/get. + */ +struct feature_prop { + u64 feature_id; + u64 prop_id; + u64 data; +}; + +#define IFPGA_FIU_ID_FME 0x0 +#define IFPGA_FIU_ID_PORT 0x1 + +#define IFPGA_FME_FEATURE_ID_HEADER 0x0 +#define IFPGA_FME_FEATURE_ID_THERMAL_MGMT 0x1 +#define IFPGA_FME_FEATURE_ID_POWER_MGMT 0x2 +#define IFPGA_FME_FEATURE_ID_GLOBAL_IPERF 0x3 +#define IFPGA_FME_FEATURE_ID_GLOBAL_ERR 0x4 +#define IFPGA_FME_FEATURE_ID_PR_MGMT 0x5 +#define IFPGA_FME_FEATURE_ID_HSSI 0x6 +#define IFPGA_FME_FEATURE_ID_GLOBAL_DPERF 0x7 + +#define IFPGA_PORT_FEATURE_ID_HEADER 0x0 +#define IFPGA_PORT_FEATURE_ID_AFU 0xff +#define IFPGA_PORT_FEATURE_ID_ERROR 0x10 +#define IFPGA_PORT_FEATURE_ID_UMSG 0x11 +#define IFPGA_PORT_FEATURE_ID_UINT 0x12 +#define IFPGA_PORT_FEATURE_ID_STP 0x13 + +/* + * PROP format (TOP + SUB + ID) + * + * (~0x0) means this field is unused. + */ +#define PROP_TOP GENMASK(31, 24) +#define PROP_TOP_UNUSED 0xff +#define PROP_SUB GENMASK(23, 16) +#define PROP_SUB_UNUSED 0xff +#define PROP_ID GENMASK(15, 0) + +#define PROP(_top, _sub, _id) \ + (SET_FIELD(PROP_TOP, _top) | SET_FIELD(PROP_SUB, _sub) |\ + SET_FIELD(PROP_ID, _id)) + +/* FME head feature's properties*/ +#define FME_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define FME_HDR_PROP_PORTS_NUM 0x2 /* RDONLY */ +#define FME_HDR_PROP_CACHE_SIZE 0x3 /* RDONLY */ +#define FME_HDR_PROP_VERSION 0x4 /* RDONLY */ +#define FME_HDR_PROP_SOCKET_ID 0x5 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_ID 0x6 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_METADATA 0x7 /* RDONLY */ + +/* FME error reporting feature's properties */ +/* FME error reporting properties format */ +#define ERR_PROP(_top, _id) PROP(_top, 0xff, _id) +#define ERR_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define ERR_PROP_TOP_FME_ERR 0x1 +#define ERR_PROP_ROOT(_id) ERR_PROP(0xff, _id) +#define ERR_PROP_FME_ERR(_id) ERR_PROP(ERR_PROP_TOP_FME_ERR, _id) + +#define FME_ERR_PROP_ERRORS ERR_PROP_FME_ERR(0x1) +#define FME_ERR_PROP_FIRST_ERROR ERR_PROP_FME_ERR(0x2) +#define FME_ERR_PROP_NEXT_ERROR ERR_PROP_FME_ERR(0x3) +#define FME_ERR_PROP_CLEAR ERR_PROP_FME_ERR(0x4) /* WO */ +#define FME_ERR_PROP_REVISION ERR_PROP_ROOT(0x5) +#define FME_ERR_PROP_PCIE0_ERRORS ERR_PROP_ROOT(0x6) /* RW */ +#define FME_ERR_PROP_PCIE1_ERRORS ERR_PROP_ROOT(0x7) /* RW */ +#define FME_ERR_PROP_NONFATAL_ERRORS ERR_PROP_ROOT(0x8) +#define FME_ERR_PROP_CATFATAL_ERRORS ERR_PROP_ROOT(0x9) +#define FME_ERR_PROP_INJECT_ERRORS ERR_PROP_ROOT(0xa) /* RW */ + +/* FME thermal feature's properties */ +#define FME_THERMAL_PROP_THRESHOLD1 0x1 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD2 0x2 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD_TRIP 0x3 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_REACHED 0x4 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD2_REACHED 0x5 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_POLICY 0x6 /* RW */ +#define FME_THERMAL_PROP_TEMPERATURE 0x7 /* RDONLY */ +#define FME_THERMAL_PROP_REVISION 0x8 /* RDONLY */ + +/* FME power feature's properties */ +#define FME_PWR_PROP_CONSUMED 0x1 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD1 0x2 /* RW */ +#define FME_PWR_PROP_THRESHOLD2 0x3 /* RW */ +#define FME_PWR_PROP_THRESHOLD1_STATUS 0x4 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD2_STATUS 0x5 /* RDONLY */ +#define FME_PWR_PROP_RTL 0x6 /* RDONLY */ +#define FME_PWR_PROP_XEON_LIMIT 0x7 /* RDONLY */ +#define FME_PWR_PROP_FPGA_LIMIT 0x8 /* RDONLY */ +#define FME_PWR_PROP_REVISION 0x9 /* RDONLY */ + +/* FME iperf/dperf PROP format */ +#define PERF_PROP_TOP_CACHE 0x1 +#define PERF_PROP_TOP_VTD 0x2 +#define PERF_PROP_TOP_FAB 0x3 +#define PERF_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define PERF_PROP_SUB_UNUSED PROP_SUB_UNUSED + +#define PERF_PROP_ROOT(_id) PROP(0xff, 0xff, _id) +#define PERF_PROP_CACHE(_id) PROP(PERF_PROP_TOP_CACHE, 0xff, _id) +#define PERF_PROP_VTD(_sub, _id) PROP(PERF_PROP_TOP_VTD, _sub, _id) +#define PERF_PROP_VTD_ROOT(_id) PROP(PERF_PROP_TOP_VTD, 0xff, _id) +#define PERF_PROP_FAB(_sub, _id) PROP(PERF_PROP_TOP_FAB, _sub, _id) +#define PERF_PROP_FAB_ROOT(_id) PROP(PERF_PROP_TOP_FAB, 0xff, _id) + +/* FME iperf feature's properties */ +#define FME_IPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_IPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* iperf CACHE properties */ +#define FME_IPERF_PROP_CACHE_FREEZE PERF_PROP_CACHE(0x1) /* RW */ +#define FME_IPERF_PROP_CACHE_READ_HIT PERF_PROP_CACHE(0x2) +#define FME_IPERF_PROP_CACHE_READ_MISS PERF_PROP_CACHE(0x3) +#define FME_IPERF_PROP_CACHE_WRITE_HIT PERF_PROP_CACHE(0x4) +#define FME_IPERF_PROP_CACHE_WRITE_MISS PERF_PROP_CACHE(0x5) +#define FME_IPERF_PROP_CACHE_HOLD_REQUEST PERF_PROP_CACHE(0x6) +#define FME_IPERF_PROP_CACHE_TX_REQ_STALL PERF_PROP_CACHE(0x7) +#define FME_IPERF_PROP_CACHE_RX_REQ_STALL PERF_PROP_CACHE(0x8) +#define FME_IPERF_PROP_CACHE_RX_EVICTION PERF_PROP_CACHE(0x9) +#define FME_IPERF_PROP_CACHE_DATA_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xa) +#define FME_IPERF_PROP_CACHE_TAG_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xb) +/* iperf VTD properties */ +#define FME_IPERF_PROP_VTD_FREEZE PERF_PROP_VTD_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_HIT PERF_PROP_VTD_ROOT(0x2) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_HIT PERF_PROP_VTD_ROOT(0x3) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_HIT PERF_PROP_VTD_ROOT(0x4) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_HIT PERF_PROP_VTD_ROOT(0x5) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_HIT PERF_PROP_VTD_ROOT(0x6) +#define FME_IPERF_PROP_VTD_SIP_RCC_HIT PERF_PROP_VTD_ROOT(0x7) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_MISS PERF_PROP_VTD_ROOT(0x8) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_MISS PERF_PROP_VTD_ROOT(0x9) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_MISS PERF_PROP_VTD_ROOT(0xa) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_MISS PERF_PROP_VTD_ROOT(0xb) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_MISS PERF_PROP_VTD_ROOT(0xc) +#define FME_IPERF_PROP_VTD_SIP_RCC_MISS PERF_PROP_VTD_ROOT(0xd) +#define FME_IPERF_PROP_VTD_PORT_READ_TRANSACTION(n) PERF_PROP_VTD(n, 0xe) +#define FME_IPERF_PROP_VTD_PORT_WRITE_TRANSACTION(n) PERF_PROP_VTD(n, 0xf) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_READ_HIT(n) PERF_PROP_VTD(n, 0x10) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_WRITE_HIT(n) PERF_PROP_VTD(n, 0x11) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_4K_FILL(n) PERF_PROP_VTD(n, 0x12) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_2M_FILL(n) PERF_PROP_VTD(n, 0x13) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_1G_FILL(n) PERF_PROP_VTD(n, 0x14) +/* iperf FAB properties */ +#define FME_IPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_IPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_IPERF_PROP_FAB_PCIE1_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_IPERF_PROP_FAB_PCIE1_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_IPERF_PROP_FAB_UPI_READ PERF_PROP_FAB_ROOT(0x6) +#define FME_IPERF_PROP_FAB_PORT_UPI_READ(n) PERF_PROP_FAB(n, 0x6) +#define FME_IPERF_PROP_FAB_UPI_WRITE PERF_PROP_FAB_ROOT(0x7) +#define FME_IPERF_PROP_FAB_PORT_UPI_WRITE(n) PERF_PROP_FAB(n, 0x7) +#define FME_IPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x8) +#define FME_IPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x8) +#define FME_IPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x9) +#define FME_IPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x9) +#define FME_IPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0xa) /* RW */ +#define FME_IPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0xa) /* RW */ + +/* FME dperf properties */ +#define FME_DPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_DPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* dperf FAB properties */ +#define FME_DPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_DPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_DPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_DPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_DPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_DPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_DPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_DPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0x6) /* RW */ +#define FME_DPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0x6) /* RW */ + +/*PORT hdr feature's properties*/ +#define PORT_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_HDR_PROP_PORTIDX 0x2 /* RDONLY */ +#define PORT_HDR_PROP_LATENCY_TOLERANCE 0x3 /* RDONLY */ +#define PORT_HDR_PROP_AP1_EVENT 0x4 /* RW */ +#define PORT_HDR_PROP_AP2_EVENT 0x5 /* RW */ +#define PORT_HDR_PROP_POWER_STATE 0x6 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_FREQCMD 0x7 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQCNTRCMD 0x8 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQSTS 0x9 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_CNTRSTS 0xa /* RDONLY */ + +/*PORT error feature's properties*/ +#define PORT_ERR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_ERR_PROP_ERRORS 0x2 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_ERROR 0x3 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB 0x4 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB 0x5 /* RDONLY */ +#define PORT_ERR_PROP_CLEAR 0x6 /* WRONLY */ + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop); +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop); + +/* + * Retrieve information about the fpga fme. + * Driver fills the info in provided struct fpga_fme_info. + */ +struct fpga_fme_info { + u32 capability; /* The capability of FME device */ +#define FPGA_FME_CAP_ERR_IRQ (1 << 0) /* Support fme error interrupt */ +}; + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info); + +/* Set eventfd information for ifpga FME error interrupt */ +struct fpga_fme_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set); + +/* + * Retrieve information about the fpga port. + * Driver fills the info in provided struct fpga_port_info. + */ +struct fpga_port_info { + u32 capability; /* The capability of port device */ +#define FPGA_PORT_CAP_ERR_IRQ (1 << 0) /* Support port error interrupt */ +#define FPGA_PORT_CAP_UAFU_IRQ (1 << 1) /* Support uafu error interrupt */ + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ +}; + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info); +/* + * Retrieve region information about the fpga port. + * Driver needs to fill the index of struct fpga_port_region_info. + */ +struct fpga_port_region_info { + u32 index; +#define PORT_REGION_INDEX_STP (1 << 1) /* Signal Tap Region */ + u64 size; /* Region Size */ + u64 addr; /* Base address of the region */ +}; + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info); + +/* Set eventfd information for ifpga port error interrupt */ +struct fpga_port_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set); + +#endif /* _OPAE_IFPGA_HW_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h new file mode 100644 index 0000000..e9da710 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_OSDEP_H +#define _OPAE_OSDEP_H + +#include <string.h> +#include <stdbool.h> + +#ifdef RTE_LIBRTE_EAL +#include "osdep_rte/osdep_generic.h" +#else +#include "osdep_raw/osdep_generic.h" +#endif + +#include <asm/types.h> + +#define __iomem + +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef uint64_t dma_addr_t; + +struct uuid { + u8 b[16]; +}; + +#ifndef LINUX_MACROS +#ifndef BITS_PER_LONG +#define BITS_PER_LONG (__SIZEOF_LONG__ * 8) +#endif +#ifndef BIT +#define BIT(a) (1UL << (a)) +#endif /* BIT */ +#ifndef BIT_ULL +#define BIT_ULL(a) (1ULL << (a)) +#endif /* BIT_ULL */ +#ifndef GENMASK +#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#endif /* GENMASK */ +#ifndef GENMASK_ULL +#define GENMASK_ULL(h, l) (((U64_C(1) << ((h) - (l) + 1)) - 1) << (l)) +#endif /* GENMASK_ULL */ +#endif /* LINUX_MACROS */ + +#define SET_FIELD(m, v) (((v) << (__builtin_ffsll(m) - 1)) & (m)) +#define GET_FIELD(m, v) (((v) & (m)) >> (__builtin_ffsll(m) - 1)) + +#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) +#define pr_info(y, args...) dev_info(0, y, ##args) + +#ifndef WARN_ON +#define WARN_ON(x) do { \ + int ret = !!(x); \ + if (unlikely(ret)) \ + pr_warn("WARN_ON: \"" #x "\" at %s:%d\n", __func__, __LINE__); \ +} while (0) +#endif + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define udelay(x) opae_udelay(x) +#define msleep(x) opae_udelay(1000 * (x)) +#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000)) + +#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 new file mode 100644 index 0000000..895a1d8 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OSDEP_RAW_GENERIC_H +#define _OSDEP_RAW_GENERIC_H + +#define compiler_barrier() (asm volatile ("" : : : "memory")) + +#define io_wmb() compiler_barrier() +#define io_rmb() compiler_barrier() + +static inline uint8_t opae_readb(const volatile void *addr) +{ + uint8_t val; + + val = *(const volatile uint8_t *)addr; + io_rmb(); + return val; +} + +static inline uint16_t opae_readw(const volatile void *addr) +{ + uint16_t val; + + val = *(const volatile uint16_t *)addr; + io_rmb(); + return val; +} + +static inline uint32_t opae_readl(const volatile void *addr) +{ + uint32_t val; + + val = *(const volatile uint32_t *)addr; + io_rmb(); + return val; +} + +static inline uint64_t opae_readq(const volatile void *addr) +{ + uint64_t val; + + val = *(const volatile uint64_t *)addr; + io_rmb(); + return val; +} + +static inline void opae_writeb(uint8_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint8_t *)addr = value; +} + +static inline void opae_writew(uint16_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint16_t *)addr = value; +} + +static inline void opae_writel(uint32_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint32_t *)addr = value; +} + +static inline void opae_writeq(uint64_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint64_t *)addr = value; +} + +#define opae_free(addr) free(addr) + +#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 new file mode 100644 index 0000000..76902e2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OSDEP_RTE_GENERIC_H +#define _OSDEP_RTE_GENERIC_H + +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_spinlock.h> +#include <rte_log.h> +#include <rte_io.h> +#include <rte_malloc.h> + +#define dev_printf(level, fmt, args...) \ + RTE_LOG(level, PMD, "osdep_rte: " fmt, ## args) + +#define osdep_panic(...) rte_panic(...) + +#define opae_udelay(x) rte_delay_us(x) + +#define opae_readb(addr) rte_read8(addr) +#define opae_readw(addr) rte_read16(addr) +#define opae_readl(addr) rte_read32(addr) +#define opae_readq(addr) rte_read64(addr) +#define opae_writeb(value, addr) rte_write8(value, addr) +#define opae_writew(value, addr) rte_write16(value, addr) +#define opae_writel(value, addr) rte_write32(value, addr) +#define opae_writeq(value, addr) rte_write64(value, addr) + +#define opae_malloc(size) rte_malloc(NULL, size, 0) +#define opae_zmalloc(size) rte_zmalloc(NULL, size, 0) +#define opae_free(addr) rte_free(addr) + +#define ARRAY_SIZE(arr) RTE_DIM(arr) + +#define min(a, b) RTE_MIN(a, b) +#define max(a, b) RTE_MAX(a, b) + +#define spinlock_t rte_spinlock_t +#define spinlock_init(x) rte_spinlock_init(x) +#define spinlock_lock(x) rte_spinlock_lock(x) +#define spinlock_unlock(x) rte_spinlock_unlock(x) + +#endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 0/5] Introduce Intel FPGA BUS Xu, Rosen 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 1/5] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 2/5] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen @ 2018-05-04 14:11 ` Xu, Rosen 2018-05-05 18:42 ` Shreyansh Jain 2018-05-05 19:09 ` Shreyansh Jain 2018-05-04 14:11 ` [dpdk-dev] [PATCH v7 4/5] iFPGA: add meson build Xu, Rosen 2018-05-04 14:11 ` [dpdk-dev] [PATCH v7 5/5] iFPGA: add document for iFPGA driver Xu, Rosen 4 siblings, 2 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-04 14:11 UTC (permalink / raw) To: dev Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Yanglong Wu From: Rosen Xu <rosen.xu@intel.com> Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev library. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> Signed-off-by: Figo zhang <tianfei.zhang@intel.com> --- config/common_base | 1 + drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 ++ drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 599 +++++++++++++++++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + mk/rte.app.mk | 1 + 7 files changed, 679 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map diff --git a/config/common_base b/config/common_base index bd4b356..650eda7 100644 --- a/config/common_base +++ b/config/common_base @@ -152,6 +152,7 @@ CONFIG_RTE_LIBRTE_VDEV_BUS=y # Compile the Intel FPGA bus # CONFIG_RTE_LIBRTE_IFPGA_BUS=y +CONFIG_RTE_LIBRTE_IFPGA_RAWDEV=y # # Compile ARK PMD diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index da7c8b4..6fc8f2f 100644 --- a/drivers/raw/Makefile +++ b/drivers/raw/Makefile @@ -5,5 +5,6 @@ include $(RTE_SDK)/mk/rte.vars.mk # DIRS-$(<configuration>) += <directory> DIRS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += skeleton_rawdev +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/raw/ifpga_rawdev/Makefile b/drivers/raw/ifpga_rawdev/Makefile new file mode 100644 index 0000000..66e2e34 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/Makefile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_ifpga_rawdev.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_bus_vdev +LDLIBS += -lrte_kvargs +LDLIBS += -lrte_bus_pci +LDLIBS += -lrte_bus_ifpga + +EXPORT_MAP := rte_ifpga_rawdev_version.map + +LIBABIVER := 1 + +VPATH += $(SRCDIR)/base + +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c new file mode 100644 index 0000000..68a9e6f --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c @@ -0,0 +1,599 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <rte_log.h> +#include <rte_bus.h> +#include <rte_eal_memconfig.h> +#include <rte_malloc.h> +#include <rte_devargs.h> +#include <rte_memcpy.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include <rte_errno.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> +#include <rte_bus_vdev.h> + +#include "base/opae_hw_api.h" +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_common.h" +#include "ifpga_logs.h" +#include "ifpga_rawdev.h" + +int ifpga_rawdev_logtype; + +#define PCI_VENDOR_ID_INTEL 0x8086 +/* PCI Device ID */ +#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 +/* 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 RTE_MAX_RAW_DEVICE 10 + +static const struct rte_pci_id pci_ifpga_map[] = { + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_6_X) }, + { 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) }, + { .vendor_id = 0, /* sentinel */ }, +}; + +static int ifpga_fill_afu_dev(struct opae_accelerator *acc, + struct rte_afu_device *afu_dev) +{ + struct rte_mem_resource *res = afu_dev->mem_resource; + struct opae_acc_region_info region_info; + struct opae_acc_info info; + unsigned long i; + int ret; + + ret = opae_acc_get_info(acc, &info); + if (ret) + return ret; + + if (info.num_regions > PCI_MAX_RESOURCE) + return -EFAULT; + + afu_dev->num_region = info.num_regions; + + for (i = 0; i < info.num_regions; i++) { + region_info.index = i; + ret = opae_acc_get_region_info(acc, ®ion_info); + if (ret) + return ret; + + if ((region_info.flags & ACC_REGION_MMIO) && + (region_info.flags & ACC_REGION_READ) && + (region_info.flags & ACC_REGION_WRITE)) { + res[i].phys_addr = region_info.phys_addr; + res[i].len = region_info.len; + res[i].addr = region_info.addr; + } else + return -EFAULT; + } + + return 0; +} + +static void ifpga_rawdev_info_get(struct rte_rawdev *dev, + rte_rawdev_obj_t dev_info) +{ + struct opae_adapter *adapter; + struct opae_accelerator *acc; + struct rte_afu_device *afu_dev; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + if (!dev_info) { + IFPGA_RAWDEV_PMD_ERR("Invalid request"); + return; + } + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return; + + afu_dev = dev_info; + afu_dev->rawdev = dev; + + /* find opae_accelerator and fill info into afu_device */ + opae_adapter_for_each_acc(adapter, acc) { + if (acc->index != afu_dev->id.port) + continue; + + if (ifpga_fill_afu_dev(acc, afu_dev)) { + IFPGA_RAWDEV_PMD_ERR("cannot get info\n"); + return; + } + } +} + +static int ifpga_rawdev_start(struct rte_rawdev *dev) +{ + int ret = 0; + struct opae_adapter *adapter; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + return ret; +} + +static void ifpga_rawdev_stop(struct rte_rawdev *dev) +{ + dev->started = 0; +} + +static int ifpga_rawdev_close(struct rte_rawdev *dev) +{ + return dev ? 0:1; +} + +static int ifpga_rawdev_reset(struct rte_rawdev *dev) +{ + return dev ? 0:1; +} + +static int +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, + u64 *status) +{ + + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_accelerator *acc; + struct opae_bridge *br; + int ret; + + adapter = ifpga_rawdev_get_priv(raw_dev); + if (!adapter) + return -ENODEV; + + mgr = opae_adapter_get_mgr(adapter); + if (!mgr) + return -ENODEV; + + acc = opae_adapter_get_acc(adapter, port_id); + if (!acc) + return -ENODEV; + + br = opae_acc_get_br(acc); + if (!br) + return -ENODEV; + + ret = opae_manager_flash(mgr, port_id, buffer, size, status); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("%s pr error %d\n", __func__, ret); + return ret; + } + + ret = opae_bridge_reset(br); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("%s reset port:%d error %d\n", + __func__, port_id, ret); + return ret; + } + + return ret; +} + +static int rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, + const char *file_name) +{ + struct stat file_stat; + int file_fd; + int ret = 0; + u32 buffer_size; + void *buffer; + u64 pr_error; + + if (!file_name) + return -EINVAL; + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + IFPGA_RAWDEV_PMD_ERR("%s: open file error: %s\n", + __func__, file_name); + IFPGA_RAWDEV_PMD_ERR("Message : %s\n", strerror(errno)); + return -EINVAL; + } + ret = stat(file_name, &file_stat); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("stat on bitstream file failed: %s\n", + file_name); + return -EINVAL; + } + buffer_size = file_stat.st_size; + IFPGA_RAWDEV_PMD_INFO("bitstream file size: %u\n", buffer_size); + buffer = rte_malloc(NULL, buffer_size, 0); + if (!buffer) { + ret = -ENOMEM; + goto close_fd; + } + + /*read the raw data*/ + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { + ret = -EINVAL; + goto free_buffer; + } + + /*do PR now*/ + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); + IFPGA_RAWDEV_PMD_INFO("downloading to device port %d....%s.\n", port_id, + ret ? "failed" : "success"); + if (ret) { + ret = -EINVAL; + goto free_buffer; + } + +free_buffer: + if (buffer) + rte_free(buffer); +close_fd: + close(file_fd); + file_fd = 0; + return ret; +} + +static int ifpga_rawdev_pr(struct rte_rawdev *dev, + rte_rawdev_obj_t pr_conf) +{ + struct opae_adapter *adapter; + struct rte_afu_pr_conf *afu_pr_conf; + int ret; + struct uuid uuid; + struct opae_accelerator *acc; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + if (!pr_conf) + return -EINVAL; + + afu_pr_conf = pr_conf; + + if (afu_pr_conf->pr_enable) { + ret = rte_fpga_do_pr(dev, + afu_pr_conf->afu_id.port, + afu_pr_conf->bs_path); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("do pr error %d\n", ret); + return ret; + } + } + + acc = opae_adapter_get_acc(adapter, afu_pr_conf->afu_id.port); + if (!acc) + return -ENODEV; + + ret = opae_acc_get_uuid(acc, &uuid); + if (ret) + return ret; + + memcpy(&afu_pr_conf->afu_id.uuid.uuid_low, uuid.b, sizeof(u64)); + memcpy(&afu_pr_conf->afu_id.uuid.uuid_high, uuid.b + 8, sizeof(u64)); + + IFPGA_RAWDEV_PMD_INFO("%s: uuid_l=0x%lx, uuid_h=0x%lx\n", __func__, + (u64)afu_pr_conf->afu_id.uuid.uuid_low, + (u64)afu_pr_conf->afu_id.uuid.uuid_high); + + return 0; +} + +static const struct rte_rawdev_ops ifpga_rawdev_ops = { + .dev_info_get = ifpga_rawdev_info_get, + .dev_configure = NULL, + .dev_start = ifpga_rawdev_start, + .dev_stop = ifpga_rawdev_stop, + .dev_close = ifpga_rawdev_close, + .dev_reset = ifpga_rawdev_reset, + + .queue_def_conf = NULL, + .queue_setup = NULL, + .queue_release = NULL, + + .attr_get = NULL, + .attr_set = NULL, + + .enqueue_bufs = NULL, + .dequeue_bufs = NULL, + + .dump = NULL, + + .xstats_get = NULL, + .xstats_get_names = NULL, + .xstats_get_by_name = NULL, + .xstats_reset = NULL, + + .firmware_status_get = NULL, + .firmware_version_get = NULL, + .firmware_load = ifpga_rawdev_pr, + .firmware_unload = NULL, + + .dev_selftest = NULL, +}; + +static int +ifpga_rawdev_create(struct rte_pci_device *pci_dev, + int socket_id) +{ + int ret = 0; + struct rte_rawdev *rawdev = NULL; + struct opae_adapter *adapter = NULL; + struct opae_manager *mgr = NULL; + struct opae_adapter_data_pci *data = NULL; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + int i; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + goto cleanup; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id()); + + /* Allocate device structure */ + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct opae_adapter), + socket_id); + if (rawdev == NULL) { + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); + ret = -EINVAL; + goto cleanup; + } + + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API */ + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); + if (!data) { + ret = -ENOMEM; + goto cleanup; + } + + /* init opae_adapter_data_pci for device specific information */ + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + data->region[i].phys_addr = pci_dev->mem_resource[i].phys_addr; + data->region[i].len = pci_dev->mem_resource[i].len; + data->region[i].addr = pci_dev->mem_resource[i].addr; + } + data->device_id = pci_dev->id.device_id; + data->vendor_id = pci_dev->id.vendor_id; + + /* create a opae_adapter based on above device data */ + adapter = opae_adapter_alloc(pci_dev->device.name, data); + if (!adapter) { + ret = -ENOMEM; + goto free_adapter_data; + } + + rawdev->dev_ops = &ifpga_rawdev_ops; + rawdev->device = &pci_dev->device; + rawdev->driver_name = pci_dev->device.driver->name; + + rawdev->dev_private = adapter; + + /* must enumerate the adapter before use it */ + ret = opae_adapter_enumerate(adapter); + if (ret) + goto free_adapter; + + /* get opae_manager to rawdev */ + mgr = opae_adapter_get_mgr(adapter); + if (mgr) { + /* PF function */ + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); + } + + return ret; + +free_adapter: + if (adapter) + opae_adapter_free(adapter); +free_adapter_data: + if (data) + opae_adapter_data_free(data); +cleanup: + if (rawdev) + rte_rawdev_pmd_release(rawdev); + + return ret; +} + +static int +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) +{ + int ret; + struct rte_rawdev *rawdev; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + struct opae_adapter *adapter; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + return ret; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", + name, rte_socket_id()); + + rawdev = rte_rawdev_pmd_get_named_dev(name); + if (!rawdev) { + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name); + return -EINVAL; + } + + adapter = ifpga_rawdev_get_priv(rawdev); + if (!adapter) + return -ENODEV; + + opae_adapter_data_free(adapter->data); + opae_adapter_free(adapter); + + /* rte_rawdev_close is called by pmd_release */ + ret = rte_rawdev_pmd_release(rawdev); + if (ret) + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); + + return ret; +} + +static int +ifpga_rawdev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, + struct rte_pci_device *pci_dev) +{ + + IFPGA_RAWDEV_PMD_INFO("## %s\n", __func__); + return ifpga_rawdev_create(pci_dev, rte_socket_id()); +} + +static int ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) +{ + return ifpga_rawdev_destroy(pci_dev); +} + +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { + .id_table = pci_ifpga_map, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, + .probe = ifpga_rawdev_pci_probe, + .remove = ifpga_rawdev_pci_remove, +}; + +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | uio_pci_generic | vfio-pci"); + +RTE_INIT(ifpga_rawdev_init_log); +static void +ifpga_rawdev_init_log(void) +{ + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); + if (ifpga_rawdev_logtype >= 0) + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +static int +ifpga_cfg_probe(struct rte_vdev_device *dev) +{ + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + int port; + char *name = NULL; + char dev_name[RTE_RAWDEV_NAME_MAX_LEN]; + + devargs = dev->device.devargs; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &ifpga_get_string_arg, &name) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, + IFPGA_ARG_PORT, + &ifpga_get_integer32_arg, + &port) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + memset(dev_name, 0, sizeof(dev_name)); + snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s", + port, name); + + rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), + dev_name, devargs->args); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +static int +ifpga_cfg_remove(struct rte_vdev_device *vdev) +{ + IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p", + vdev); + + return 0; +} + +static struct rte_vdev_driver ifpga_cfg_driver = { + .probe = ifpga_cfg_probe, + .remove = ifpga_cfg_remove, +}; + +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, + "bdf=<string> " + "port=<int> " + "afu_bts=<path>"); + diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h new file mode 100644 index 0000000..9a09561 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_RAWDEV_H_ +#define _IFPGA_RAWDEV_H_ + +extern int ifpga_rawdev_logtype; + +#define IFPGA_RAWDEV_PMD_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_rawdev_logtype, "ifgpa: " fmt "\n", \ + ##args) + +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") + +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) +#define IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) +#define IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) +#define IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) + +enum ifpga_rawdev_device_state { + IFPGA_IDLE, + IFPGA_READY, + IFPGA_ERROR +}; + +static inline struct opae_adapter * +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) +{ + return rawdev->dev_private; +} + +#endif /* _IFPGA_RAWDEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map new file mode 100644 index 0000000..9b9ab1a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map @@ -0,0 +1,4 @@ +DPDK_18.05 { + + local: *; +}; diff --git a/mk/rte.app.mk b/mk/rte.app.mk index f47bbe8..b0a994f 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -253,6 +253,7 @@ endif # CONFIG_RTE_LIBRTE_EVENTDEV ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += -lrte_pmd_skeleton_rawdev +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += -lrte_ifpga_rawdev endif # CONFIG_RTE_LIBRTE_RAWDEV -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-04 14:11 ` [dpdk-dev] [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen @ 2018-05-05 18:42 ` Shreyansh Jain 2018-05-06 0:28 ` Zhang, Tianfei 2018-05-05 19:09 ` Shreyansh Jain 1 sibling, 1 reply; 149+ messages in thread From: Shreyansh Jain @ 2018-05-05 18:42 UTC (permalink / raw) To: Xu, Rosen, dev Cc: declan.doherty, bruce.richardson, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Yanglong Wu Hello Rosen, > -----Original Message----- > From: Xu, Rosen [mailto:rosen.xu@intel.com] > Sent: Friday, May 4, 2018 7:41 PM > To: dev@dpdk.org > Cc: rosen.xu@intel.com; declan.doherty@intel.com; > bruce.richardson@intel.com; Shreyansh Jain <shreyansh.jain@nxp.com>; > ferruh.yigit@intel.com; konstantin.ananyev@intel.com; > tianfei.zhang@intel.com; song.liu@intel.com; hao.wu@intel.com; > gaetan.rivet@6wind.com; Yanglong Wu <yanglong.wu@intel.com> > Subject: [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver > > From: Rosen Xu <rosen.xu@intel.com> > > Add Intel FPGA BUS Rawdev Driver which is based on > librte_rawdev library. > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > Signed-off-by: Figo zhang <tianfei.zhang@intel.com> > --- > config/common_base | 1 + > drivers/raw/Makefile | 1 + > drivers/raw/ifpga_rawdev/Makefile | 36 ++ > drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 599 > +++++++++++++++++++++ > drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ > .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + > mk/rte.app.mk | 1 + > 7 files changed, 679 insertions(+) > create mode 100644 drivers/raw/ifpga_rawdev/Makefile > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h > create mode 100644 > drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map > [...] > --- /dev/null > +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c > @@ -0,0 +1,599 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation > + */ > + > +#include <string.h> > +#include <dirent.h> > +#include <sys/stat.h> > +#include <unistd.h> > +#include <sys/types.h> > +#include <fcntl.h> > +#include <rte_log.h> > +#include <rte_bus.h> > +#include <rte_eal_memconfig.h> > +#include <rte_malloc.h> > +#include <rte_devargs.h> > +#include <rte_memcpy.h> > +#include <rte_pci.h> > +#include <rte_bus_pci.h> > +#include <rte_kvargs.h> > +#include <rte_alarm.h> > + > +#include <rte_errno.h> > +#include <rte_per_lcore.h> > +#include <rte_memory.h> > +#include <rte_memzone.h> > +#include <rte_eal.h> > +#include <rte_common.h> > +#include <rte_bus_vdev.h> > + > +#include "base/opae_hw_api.h" > +#include "rte_rawdev.h" > +#include "rte_rawdev_pmd.h" > +#include "rte_bus_ifpga.h" > +#include "ifpga_common.h" > +#include "ifpga_logs.h" > +#include "ifpga_rawdev.h" > + > +int ifpga_rawdev_logtype; > + > +#define PCI_VENDOR_ID_INTEL 0x8086 > +/* PCI Device ID */ > +#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 > +/* 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 RTE_MAX_RAW_DEVICE 10 > + > +static const struct rte_pci_id pci_ifpga_map[] = { > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X) > }, > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_5_X) > }, > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_6_X) > }, > + { 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) > }, > + { .vendor_id = 0, /* sentinel */ }, > +}; > + > +static int ifpga_fill_afu_dev(struct opae_accelerator *acc, > + struct rte_afu_device *afu_dev) Sorry, for nitpicking, but the function definitions should follow [1] model where return types are different lines than name. Something like: static int ifpga_fill_afu_dev(...) [1] http://dpdk.org/doc/guides/contributing/coding_style.html#c-function-definition-declaration-and-use This is valid for multiple function definitions. Can you please fix when you send v8 (which you might have to send for rebasing over master). > +{ > + struct rte_mem_resource *res = afu_dev->mem_resource; > + struct opae_acc_region_info region_info; > + struct opae_acc_info info; > + unsigned long i; > + int ret; > + > + ret = opae_acc_get_info(acc, &info); > + if (ret) > + return ret; > + > + if (info.num_regions > PCI_MAX_RESOURCE) > + return -EFAULT; > + > + afu_dev->num_region = info.num_regions; > + > + for (i = 0; i < info.num_regions; i++) { > + region_info.index = i; > + ret = opae_acc_get_region_info(acc, ®ion_info); > + if (ret) > + return ret; > + > + if ((region_info.flags & ACC_REGION_MMIO) && > + (region_info.flags & ACC_REGION_READ) && > + (region_info.flags & ACC_REGION_WRITE)) { > + res[i].phys_addr = region_info.phys_addr; > + res[i].len = region_info.len; > + res[i].addr = region_info.addr; > + } else > + return -EFAULT; > + } > + > + return 0; > +} > + > +static void ifpga_rawdev_info_get(struct rte_rawdev *dev, > + rte_rawdev_obj_t dev_info) > +{ > + struct opae_adapter *adapter; > + struct opae_accelerator *acc; > + struct rte_afu_device *afu_dev; > + > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > + [...] > + > +static int > +ifpga_rawdev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, > + struct rte_pci_device *pci_dev) > +{ > + > + IFPGA_RAWDEV_PMD_INFO("## %s\n", __func__); Actually, this is not INFO - this is debug. And, this seems like place for FUNC_TRACE call you have already defined in your log file. > + return ifpga_rawdev_create(pci_dev, rte_socket_id()); > +} > + > +static int ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) > +{ > + return ifpga_rawdev_destroy(pci_dev); > +} > + > +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { > + .id_table = pci_ifpga_map, > + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, > + .probe = ifpga_rawdev_pci_probe, > + .remove = ifpga_rawdev_pci_remove, > +}; > + [...] > diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > new file mode 100644 > index 0000000..9a09561 > --- /dev/null > +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > @@ -0,0 +1,37 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation > + */ > + > +#ifndef _IFPGA_RAWDEV_H_ > +#define _IFPGA_RAWDEV_H_ > + > +extern int ifpga_rawdev_logtype; > + > +#define IFPGA_RAWDEV_PMD_LOG(level, fmt, args...) \ > + rte_log(RTE_LOG_ ## level, ifpga_rawdev_logtype, "ifgpa: " fmt > "\n", \ > + ##args) Another one. In many of your logs, you are adding '\n' in the end. Your PMD_LOG definition also has a '\n' - that is double new lines being printed for those logs. > + > +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() IFPGA_RAWDEV_PMD_LOG(DEBUG, > ">>") > + > +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ > + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) > +#define IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ > + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) > +#define IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ > + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) > +#define IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ > + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) > + > +enum ifpga_rawdev_device_state { > + IFPGA_IDLE, > + IFPGA_READY, > + IFPGA_ERROR > +}; > + > +static inline struct opae_adapter * > +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) > +{ > + return rawdev->dev_private; > +} > + > +#endif /* _IFPGA_RAWDEV_H_ */ [...] There are some nitpicks highlighted in mail above - but nothing major. I would have no more comments (as well as review) for this. In principle, I am OK with this. For v8, please feel free to use for this patch: Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> Thanks for the work and patience. ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-05 18:42 ` Shreyansh Jain @ 2018-05-06 0:28 ` Zhang, Tianfei 0 siblings, 0 replies; 149+ messages in thread From: Zhang, Tianfei @ 2018-05-06 0:28 UTC (permalink / raw) To: Shreyansh Jain, Xu, Rosen, dev Cc: Doherty, Declan, Richardson, Bruce, Yigit, Ferruh, Ananyev, Konstantin, Liu, Song, Wu, Hao, gaetan.rivet, Wu, Yanglong > -----Original Message----- > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > Sent: Sunday, May 6, 2018 2:43 AM > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org > Cc: Doherty, Declan <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; Yigit, Ferruh <ferruh.yigit@intel.com>; > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Tianfei > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > <hao.wu@intel.com>; gaetan.rivet@6wind.com; Wu, Yanglong > <yanglong.wu@intel.com> > Subject: RE: [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver > > Hello Rosen, > > > -----Original Message----- > > From: Xu, Rosen [mailto:rosen.xu@intel.com] > > Sent: Friday, May 4, 2018 7:41 PM > > To: dev@dpdk.org > > Cc: rosen.xu@intel.com; declan.doherty@intel.com; > > bruce.richardson@intel.com; Shreyansh Jain <shreyansh.jain@nxp.com>; > > ferruh.yigit@intel.com; konstantin.ananyev@intel.com; > > tianfei.zhang@intel.com; song.liu@intel.com; hao.wu@intel.com; > > gaetan.rivet@6wind.com; Yanglong Wu <yanglong.wu@intel.com> > > Subject: [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver > > > > From: Rosen Xu <rosen.xu@intel.com> > > > > Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev > > library. > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > > Signed-off-by: Figo zhang <tianfei.zhang@intel.com> > > --- > > config/common_base | 1 + > > drivers/raw/Makefile | 1 + > > drivers/raw/ifpga_rawdev/Makefile | 36 ++ > > drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 599 > > +++++++++++++++++++++ > > drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ > > .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + > > mk/rte.app.mk | 1 + > > 7 files changed, 679 insertions(+) > > create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode > > 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c > > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > create mode 100644 > > drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map > > > > [...] > > > --- /dev/null > > +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c > > @@ -0,0 +1,599 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > +#include <string.h> > > +#include <dirent.h> > > +#include <sys/stat.h> > > +#include <unistd.h> > > +#include <sys/types.h> > > +#include <fcntl.h> > > +#include <rte_log.h> > > +#include <rte_bus.h> > > +#include <rte_eal_memconfig.h> > > +#include <rte_malloc.h> > > +#include <rte_devargs.h> > > +#include <rte_memcpy.h> > > +#include <rte_pci.h> > > +#include <rte_bus_pci.h> > > +#include <rte_kvargs.h> > > +#include <rte_alarm.h> > > + > > +#include <rte_errno.h> > > +#include <rte_per_lcore.h> > > +#include <rte_memory.h> > > +#include <rte_memzone.h> > > +#include <rte_eal.h> > > +#include <rte_common.h> > > +#include <rte_bus_vdev.h> > > + > > +#include "base/opae_hw_api.h" > > +#include "rte_rawdev.h" > > +#include "rte_rawdev_pmd.h" > > +#include "rte_bus_ifpga.h" > > +#include "ifpga_common.h" > > +#include "ifpga_logs.h" > > +#include "ifpga_rawdev.h" > > + > > +int ifpga_rawdev_logtype; > > + > > +#define PCI_VENDOR_ID_INTEL 0x8086 > > +/* PCI Device ID */ > > +#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 > > +/* 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 RTE_MAX_RAW_DEVICE 10 > > + > > +static const struct rte_pci_id pci_ifpga_map[] = { > > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, > PCIE_DEVICE_ID_PF_INT_5_X) > > }, > > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, > PCIE_DEVICE_ID_VF_INT_5_X) > > }, > > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, > PCIE_DEVICE_ID_PF_INT_6_X) > > }, > > + { 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) > > }, > > + { .vendor_id = 0, /* sentinel */ }, > > +}; > > + > > +static int ifpga_fill_afu_dev(struct opae_accelerator *acc, > > + struct rte_afu_device *afu_dev) > > Sorry, for nitpicking, but the function definitions should follow [1] model > where return types are different lines than name. > > Something like: > > static int > ifpga_fill_afu_dev(...) > > > [1] > http://dpdk.org/doc/guides/contributing/coding_style.html#c-function-defi > nition-declaration-and-use > > This is valid for multiple function definitions. Can you please fix when you > send v8 (which you might have to send for rebasing over master). > > > +{ > > + struct rte_mem_resource *res = afu_dev->mem_resource; > > + struct opae_acc_region_info region_info; > > + struct opae_acc_info info; > > + unsigned long i; > > + int ret; > > + > > + ret = opae_acc_get_info(acc, &info); > > + if (ret) > > + return ret; > > + > > + if (info.num_regions > PCI_MAX_RESOURCE) > > + return -EFAULT; > > + > > + afu_dev->num_region = info.num_regions; > > + > > + for (i = 0; i < info.num_regions; i++) { > > + region_info.index = i; > > + ret = opae_acc_get_region_info(acc, ®ion_info); > > + if (ret) > > + return ret; > > + > > + if ((region_info.flags & ACC_REGION_MMIO) && > > + (region_info.flags & ACC_REGION_READ) && > > + (region_info.flags & ACC_REGION_WRITE)) { > > + res[i].phys_addr = region_info.phys_addr; > > + res[i].len = region_info.len; > > + res[i].addr = region_info.addr; > > + } else > > + return -EFAULT; > > + } > > + > > + return 0; > > +} > > + > > +static void ifpga_rawdev_info_get(struct rte_rawdev *dev, > > + rte_rawdev_obj_t dev_info) > > +{ > > + struct opae_adapter *adapter; > > + struct opae_accelerator *acc; > > + struct rte_afu_device *afu_dev; > > + > > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > > + > > [...] > > > + > > +static int > > +ifpga_rawdev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, > > + struct rte_pci_device *pci_dev) > > +{ > > + > > + IFPGA_RAWDEV_PMD_INFO("## %s\n", __func__); > > Actually, this is not INFO - this is debug. And, this seems like place for > FUNC_TRACE call you have already defined in your log file. > > > + return ifpga_rawdev_create(pci_dev, rte_socket_id()); } > > + > > +static int ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) { > > + return ifpga_rawdev_destroy(pci_dev); } > > + > > +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { > > + .id_table = pci_ifpga_map, > > + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, > > + .probe = ifpga_rawdev_pci_probe, > > + .remove = ifpga_rawdev_pci_remove, > > +}; > > + > > [...] > > > diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > new file mode 100644 > > index 0000000..9a09561 > > --- /dev/null > > +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > @@ -0,0 +1,37 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > +#ifndef _IFPGA_RAWDEV_H_ > > +#define _IFPGA_RAWDEV_H_ > > + > > +extern int ifpga_rawdev_logtype; > > + > > +#define IFPGA_RAWDEV_PMD_LOG(level, fmt, args...) \ > > + rte_log(RTE_LOG_ ## level, ifpga_rawdev_logtype, "ifgpa: " fmt > > "\n", \ > > + ##args) > > Another one. > In many of your logs, you are adding '\n' in the end. Your PMD_LOG > definition also has a '\n' - that is double new lines being printed for those > logs. > > > + > > +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() > IFPGA_RAWDEV_PMD_LOG(DEBUG, > > ">>") > > + > > +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ > > + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) #define > > +IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ > > + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) #define > > +IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ > > + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) #define > > +IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ > > + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) > > + > > +enum ifpga_rawdev_device_state { > > + IFPGA_IDLE, > > + IFPGA_READY, > > + IFPGA_ERROR > > +}; > > + > > +static inline struct opae_adapter * > > +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) { > > + return rawdev->dev_private; > > +} > > + > > +#endif /* _IFPGA_RAWDEV_H_ */ > > [...] > > There are some nitpicks highlighted in mail above - but nothing major. I > would have no more comments (as well as review) for this. > In principle, I am OK with this. For v8, please feel free to use for this patch: > > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> > > Thanks for the work and patience. Thanks Shreyansh great support, we will send the v8 patches today. ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-04 14:11 ` [dpdk-dev] [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2018-05-05 18:42 ` Shreyansh Jain @ 2018-05-05 19:09 ` Shreyansh Jain 2018-05-06 0:52 ` Zhang, Tianfei 1 sibling, 1 reply; 149+ messages in thread From: Shreyansh Jain @ 2018-05-05 19:09 UTC (permalink / raw) To: Xu, Rosen, dev Cc: declan.doherty, bruce.richardson, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Yanglong Wu Though I had already acked this, I had a quick comment: > -----Original Message----- > From: Xu, Rosen [mailto:rosen.xu@intel.com] > Sent: Friday, May 4, 2018 7:41 PM > To: dev@dpdk.org > Cc: rosen.xu@intel.com; declan.doherty@intel.com; > bruce.richardson@intel.com; Shreyansh Jain <shreyansh.jain@nxp.com>; > ferruh.yigit@intel.com; konstantin.ananyev@intel.com; > tianfei.zhang@intel.com; song.liu@intel.com; hao.wu@intel.com; > gaetan.rivet@6wind.com; Yanglong Wu <yanglong.wu@intel.com> > Subject: [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver > > From: Rosen Xu <rosen.xu@intel.com> > > Add Intel FPGA BUS Rawdev Driver which is based on > librte_rawdev library. > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > Signed-off-by: Figo zhang <tianfei.zhang@intel.com> > --- [...] > diff --git a/mk/rte.app.mk b/mk/rte.app.mk > index f47bbe8..b0a994f 100644 > --- a/mk/rte.app.mk > +++ b/mk/rte.app.mk > @@ -253,6 +253,7 @@ endif # CONFIG_RTE_LIBRTE_EVENTDEV > > ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += - > lrte_pmd_skeleton_rawdev > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += -lrte_ifpga_rawdev > endif # CONFIG_RTE_LIBRTE_RAWDEV This driver is dependent on CONFIG_RTE_LIBRTE_IFPGA_BUS and if someone disables that, it would lead to build issues. I think you should enclose the IFPGA_RAWDEV compilation into conditional for CONFIG_RTE_LIBRTE_IFPGA_BUS=y. Though, I do faintly remember a discussion in past that such thing should/can be left to individual environment configuration and it can be safely assumed that such erroneous configuration would be user-responsibility (at least until a dependency based configuration system is available in DPDK). So, it is a good-to-have rather a necessity. > > > -- > 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-05 19:09 ` Shreyansh Jain @ 2018-05-06 0:52 ` Zhang, Tianfei 0 siblings, 0 replies; 149+ messages in thread From: Zhang, Tianfei @ 2018-05-06 0:52 UTC (permalink / raw) To: Shreyansh Jain, Xu, Rosen, dev Cc: Doherty, Declan, Richardson, Bruce, Yigit, Ferruh, Ananyev, Konstantin, Liu, Song, Wu, Hao, gaetan.rivet, Wu, Yanglong > -----Original Message----- > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > Sent: Sunday, May 6, 2018 3:10 AM > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org > Cc: Doherty, Declan <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; Yigit, Ferruh <ferruh.yigit@intel.com>; > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Tianfei > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > <hao.wu@intel.com>; gaetan.rivet@6wind.com; Wu, Yanglong > <yanglong.wu@intel.com> > Subject: RE: [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver > > Though I had already acked this, I had a quick comment: > > > -----Original Message----- > > From: Xu, Rosen [mailto:rosen.xu@intel.com] > > Sent: Friday, May 4, 2018 7:41 PM > > To: dev@dpdk.org > > Cc: rosen.xu@intel.com; declan.doherty@intel.com; > > bruce.richardson@intel.com; Shreyansh Jain <shreyansh.jain@nxp.com>; > > ferruh.yigit@intel.com; konstantin.ananyev@intel.com; > > tianfei.zhang@intel.com; song.liu@intel.com; hao.wu@intel.com; > > gaetan.rivet@6wind.com; Yanglong Wu <yanglong.wu@intel.com> > > Subject: [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver > > > > From: Rosen Xu <rosen.xu@intel.com> > > > > Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev > > library. > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > > Signed-off-by: Figo zhang <tianfei.zhang@intel.com> > > --- > > [...] > > > diff --git a/mk/rte.app.mk b/mk/rte.app.mk index f47bbe8..b0a994f > > 100644 > > --- a/mk/rte.app.mk > > +++ b/mk/rte.app.mk > > @@ -253,6 +253,7 @@ endif # CONFIG_RTE_LIBRTE_EVENTDEV > > > > ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += - > > lrte_pmd_skeleton_rawdev > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += > -lrte_ifpga_rawdev > > endif # CONFIG_RTE_LIBRTE_RAWDEV > > This driver is dependent on CONFIG_RTE_LIBRTE_IFPGA_BUS and if > someone disables that, it would lead to build issues. I think you should > enclose the IFPGA_RAWDEV compilation into conditional for > CONFIG_RTE_LIBRTE_IFPGA_BUS=y. > > Though, I do faintly remember a discussion in past that such thing > should/can be left to individual environment configuration and it can be > safely assumed that such erroneous configuration would be > user-responsibility (at least until a dependency based configuration system is > available in DPDK). So, it is a good-to-have rather a necessity. Good point, we will add RAWDEV condition in our Patch 1: ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga endif # CONFIG_RTE_LIBRTE_RAWDEV and add IFGA_BUS condition checking in Patch 3, like this: ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += -lrte_pmd_skeleton_rawdevi _LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga ifeq($(CONFIG_RTE_LIBRTE_IFPGA_BUS),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += -lrte_ifpga_rawdev endif# CONFIG_RTE_LIBRTE_IFPGA_BUS endif # CONFIG_RTE_LIBRTE_RAWDEV ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v7 4/5] iFPGA: add meson build 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 0/5] Introduce Intel FPGA BUS Xu, Rosen ` (2 preceding siblings ...) 2018-05-04 14:11 ` [dpdk-dev] [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen @ 2018-05-04 14:11 ` Xu, Rosen 2018-05-05 18:21 ` Shreyansh Jain 2018-05-04 14:11 ` [dpdk-dev] [PATCH v7 5/5] iFPGA: add document for iFPGA driver Xu, Rosen 4 siblings, 1 reply; 149+ messages in thread From: Xu, Rosen @ 2018-05-04 14:11 UTC (permalink / raw) To: dev Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: Figo Zhang <tianfei.zhang@intel.com> add meson build support for iFPGA driver. Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> --- drivers/meson.build | 3 ++- drivers/raw/ifpga_rawdev/base/meson.build | 34 +++++++++++++++++++++++++++++++ drivers/raw/ifpga_rawdev/meson.build | 15 ++++++++++++++ drivers/raw/meson.build | 6 ++++++ 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build create mode 100644 drivers/raw/ifpga_rawdev/meson.build create mode 100644 drivers/raw/meson.build diff --git a/drivers/meson.build b/drivers/meson.build index b146f09..b7fc0d6 100644 --- a/drivers/meson.build +++ b/drivers/meson.build @@ -7,7 +7,8 @@ driver_classes = ['common', 'mempool', # depends on common and bus. 'net', # depends on common, bus and mempool. 'crypto', # depends on common, bus and mempool (net in future). - 'event'] # depends on common, bus, mempool and net. + 'event', # depends on common, bus, mempool and net. + 'raw'] foreach class:driver_classes drivers = [] diff --git a/drivers/raw/ifpga_rawdev/base/meson.build b/drivers/raw/ifpga_rawdev/base/meson.build new file mode 100644 index 0000000..cb65535 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/meson.build @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +sources = [ + 'ifpga_api.c', + 'ifpga_enumerate.c', + 'ifpga_feature_dev.c', + 'ifpga_fme.c', + 'ifpga_fme_iperf.c', + 'ifpga_fme_dperf.c', + 'ifpga_fme_error.c', + 'ifpga_port.c', + 'ifpga_port_error.c', + 'ifpga_fme_pr.c', + 'opae_hw_api.c', + 'opae_ifpga_hw_api.c', + 'opae_debug.c' +] + +error_cflags = ['-Wno-sign-compare', '-Wno-unused-value', + '-Wno-format', '-Wno-unused-but-set-variable', + '-Wno-strict-aliasing' +] +c_args = cflags +foreach flag: error_cflags + if cc.has_argument(flag) + c_args += flag + endif +endforeach + +base_lib = static_library('ifpga_rawdev_base', sources, + dependencies: static_rte_eal, + c_args: c_args) +base_objs = base_lib.extract_all_objects() diff --git a/drivers/raw/ifpga_rawdev/meson.build b/drivers/raw/ifpga_rawdev/meson.build new file mode 100644 index 0000000..6725687 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/meson.build @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +version = 1 + +subdir('base') +objs = [base_objs] + +deps += ['rawdev', 'pci', 'bus_pci', 'kvargs', + 'bus_vdev', 'bus_ifpga'] +sources = files('ifpga_rawdev.c') + +includes += include_directories('base') + +allow_experimental_apis = true diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build new file mode 100644 index 0000000..410f908 --- /dev/null +++ b/drivers/raw/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2017 Intel Corporation + +drivers = ['ifpga_rawdev'] +config_flag_fmt = 'RTE_LIBRTE_@0@_PMD' +driver_name_fmt = 'rte_@0@' -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v7 4/5] iFPGA: add meson build 2018-05-04 14:11 ` [dpdk-dev] [PATCH v7 4/5] iFPGA: add meson build Xu, Rosen @ 2018-05-05 18:21 ` Shreyansh Jain 2018-05-06 0:27 ` Zhang, Tianfei 0 siblings, 1 reply; 149+ messages in thread From: Shreyansh Jain @ 2018-05-05 18:21 UTC (permalink / raw) To: Xu, Rosen, dev Cc: declan.doherty, bruce.richardson, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet > -----Original Message----- > From: Xu, Rosen [mailto:rosen.xu@intel.com] > Sent: Friday, May 4, 2018 7:41 PM > To: dev@dpdk.org > Cc: rosen.xu@intel.com; declan.doherty@intel.com; > bruce.richardson@intel.com; Shreyansh Jain <shreyansh.jain@nxp.com>; > ferruh.yigit@intel.com; konstantin.ananyev@intel.com; > tianfei.zhang@intel.com; song.liu@intel.com; hao.wu@intel.com; > gaetan.rivet@6wind.com > Subject: [PATCH v7 4/5] iFPGA: add meson build > [...] > index 0000000..6725687 > --- /dev/null > +++ b/drivers/raw/ifpga_rawdev/meson.build > @@ -0,0 +1,15 @@ > +# SPDX-License-Identifier: BSD-3-Clause > +# Copyright(c) 2018 Intel Corporation > + > +version = 1 > + > +subdir('base') > +objs = [base_objs] > + > +deps += ['rawdev', 'pci', 'bus_pci', 'kvargs', > + 'bus_vdev', 'bus_ifpga'] > +sources = files('ifpga_rawdev.c') > + > +includes += include_directories('base') > + > +allow_experimental_apis = true > diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build > new file mode 100644 > index 0000000..410f908 > --- /dev/null > +++ b/drivers/raw/meson.build > @@ -0,0 +1,6 @@ > +# SPDX-License-Identifier: BSD-3-Clause > +# Copyright(c) 2017 Intel Corporation > + > +drivers = ['ifpga_rawdev'] > +config_flag_fmt = 'RTE_LIBRTE_@0@_PMD' > +driver_name_fmt = 'rte_@0@' I think you missed this again. From [1], you were to base your patch over cmdif so that this drivers/raw/meson.build introduction doesn't conflict. Can you rebase and send once again, but *only* once cmdif patches have been merged? [1] http://dpdk.org/ml/archives/dev/2018-May/100064.html ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v7 4/5] iFPGA: add meson build 2018-05-05 18:21 ` Shreyansh Jain @ 2018-05-06 0:27 ` Zhang, Tianfei 0 siblings, 0 replies; 149+ messages in thread From: Zhang, Tianfei @ 2018-05-06 0:27 UTC (permalink / raw) To: Shreyansh Jain, Xu, Rosen, dev Cc: Doherty, Declan, Richardson, Bruce, Yigit, Ferruh, Ananyev, Konstantin, Liu, Song, Wu, Hao, gaetan.rivet > -----Original Message----- > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > Sent: Sunday, May 6, 2018 2:22 AM > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org > Cc: Doherty, Declan <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; Yigit, Ferruh <ferruh.yigit@intel.com>; > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Tianfei > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > <hao.wu@intel.com>; gaetan.rivet@6wind.com > Subject: RE: [PATCH v7 4/5] iFPGA: add meson build > > > -----Original Message----- > > From: Xu, Rosen [mailto:rosen.xu@intel.com] > > Sent: Friday, May 4, 2018 7:41 PM > > To: dev@dpdk.org > > Cc: rosen.xu@intel.com; declan.doherty@intel.com; > > bruce.richardson@intel.com; Shreyansh Jain <shreyansh.jain@nxp.com>; > > ferruh.yigit@intel.com; konstantin.ananyev@intel.com; > > tianfei.zhang@intel.com; song.liu@intel.com; hao.wu@intel.com; > > gaetan.rivet@6wind.com > > Subject: [PATCH v7 4/5] iFPGA: add meson build > > > > [...] > > > index 0000000..6725687 > > --- /dev/null > > +++ b/drivers/raw/ifpga_rawdev/meson.build > > @@ -0,0 +1,15 @@ > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > > +Corporation > > + > > +version = 1 > > + > > +subdir('base') > > +objs = [base_objs] > > + > > +deps += ['rawdev', 'pci', 'bus_pci', 'kvargs', > > + 'bus_vdev', 'bus_ifpga'] > > +sources = files('ifpga_rawdev.c') > > + > > +includes += include_directories('base') > > + > > +allow_experimental_apis = true > > diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build new > > file mode 100644 index 0000000..410f908 > > --- /dev/null > > +++ b/drivers/raw/meson.build > > @@ -0,0 +1,6 @@ > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel > > +Corporation > > + > > +drivers = ['ifpga_rawdev'] > > +config_flag_fmt = 'RTE_LIBRTE_@0@_PMD' > > +driver_name_fmt = 'rte_@0@' > > I think you missed this again. From [1], you were to base your patch over > cmdif so that this drivers/raw/meson.build introduction doesn't conflict. > > Can you rebase and send once again, but *only* once cmdif patches have > been merged? > > [1] http://dpdk.org/ml/archives/dev/2018-May/100064.html Oh, we will modify it and send the v8 patches today. ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v7 5/5] iFPGA: add document for iFPGA driver 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 0/5] Introduce Intel FPGA BUS Xu, Rosen ` (3 preceding siblings ...) 2018-05-04 14:11 ` [dpdk-dev] [PATCH v7 4/5] iFPGA: add meson build Xu, Rosen @ 2018-05-04 14:11 ` Xu, Rosen 2018-05-05 19:19 ` Shreyansh Jain 4 siblings, 1 reply; 149+ messages in thread From: Xu, Rosen @ 2018-05-04 14:11 UTC (permalink / raw) To: dev Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: Figo Zhang <tianfei.zhang@intel.com> add some introduction, motivation and usage for iFPGA driver. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> --- doc/guides/index.rst | 1 + doc/guides/rawdevs/ifpga_rawdev.rst | 112 +++++++++++++++++++++++++++++++++ doc/guides/rawdevs/index.rst | 11 ++++ doc/guides/rel_notes/release_18_05.rst | 13 ++++ 4 files changed, 137 insertions(+) create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst create mode 100644 doc/guides/rawdevs/index.rst diff --git a/doc/guides/index.rst b/doc/guides/index.rst index d60529d..a93baac 100644 --- a/doc/guides/index.rst +++ b/doc/guides/index.rst @@ -20,6 +20,7 @@ DPDK documentation eventdevs/index mempool/index platform/index + rawdevs/index contributing/index rel_notes/index faq/index diff --git a/doc/guides/rawdevs/ifpga_rawdev.rst b/doc/guides/rawdevs/ifpga_rawdev.rst new file mode 100644 index 0000000..3311586 --- /dev/null +++ b/doc/guides/rawdevs/ifpga_rawdev.rst @@ -0,0 +1,112 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2018 Intel Corporation. + +IFPGA Rawdev Driver +====================== + +FPGA is used more and more widely in Cloud and NFV, one primary reason is +that FPGA not only provides ASIC performance but also it's more flexible +than ASIC. + +FPGA uses Partial Reconfigure(PR) Parts of Bit Stream to achieve its +flexibility. That means one FPGA Device Bit Stream is divided into many Parts +of Bit Stream(each Part of Bit Stream is defined as AFU-Accelerated Function +Unit), and each AFU is a hardware acceleration unit which can be dynamically +reloaded respectively. + +By PR(Partial Reconfiguration) AFUs, one FPGA resources can be time-shared by +different users. FPGA hot upgraded and fault tolerance can be provided easily. + +The SW IFPGA Rawdev Driver (**ifpga_rawdev**) provides a Rawdev driver +that utilizes Intel FPGA Software Stack OPAE(Open Programmable Acceleration +Engine) for FPGA management. + +Implementation details +---------------------- + +Each instance of IFPGA Rawdev Driver is probed by Intel FpgaDev. Cooperated +with OPAE share code IFPGA Rawdev Driver provides common FPGA management ops +for FPGA operation, OPAE provides all following operations: +- FPGA PR(Partial Reconfiguration) management +- FPGA AFUs Identifying +- FPGA Thermal Management +- FPGA Power Management +- FPGA Performance reporting +- FPGA Remote Debug + +All configuration parameters is taken by vdev_ifpga_cfg driver. Besides +configuration, vdev_ifpga_cfg driver also hot plugin AFUs in IFPGA Bus. + +All of the AFUs of one FPGA may share same PCI BDF and AFUs scan depend on +IFPGA Rawdev Driver so IFPGA Bus takes AFU device scan and AFU drivers probe. +All AFU device driver bind to AFU device by its UUID(Universally Unique +Identifier). + +To avoid unnecessary code duplication and ensure maximum performance, +handling of AFU devices is left to different PMDs; all the design as +summarized by the following block diagram:: + + +---------------------------------------------------------------+ + | Application(s) | + +----------------------------.----------------------------------+ + | + | + +----------------------------'----------------------------------+ + | DPDK Framework (APIs) | + +----------|------------|--------.---------------------|--------+ + / \ | + / \ | + +-------'-------+ +-------'-------+ +--------'--------+ + | Eth PMD | | Crypto PMD | | | + +-------.-------+ +-------.-------+ | | + | | | | + | | | | + +-------'-------+ +-------'-------+ | IFPGA | + | Eth AFU Dev | |Crypto AFU Dev | | Rawdev Driver | + +-------.-------+ +-------.-------+ |(OPAE Share Code)| + | | | | + | | Rawdev | | + +-------'------------------'-------+ Ops | | + | IFPGA Bus | -------->| | + +-----------------.----------------+ +--------.--------+ + | | + Hot-plugin -->| | + | | + +-----------------'------------------+ +--------'--------+ + | vdev_ifpga_cfg driver | | Intel FpgaDev | + +------------------------------------+ +-----------------+ + +Build options +------------- + +- ``CONFIG_RTE_LIBRTE_IFPGA_BUS`` (default ``y``) + + Toggle compilation of IFPGA Bus library. + +- ``CONFIG_RTE_LIBRTE_IFPGA_RAWDEV`` (default ``y``) + + Toggle compilation of the ``ifpga_rawdev`` driver. + +Run-time parameters +------------------- + +This driver is invoked automatically in systems added Intel FPGA system, +but PR and IFPGA Bus scan is trigged by command line using +``--vdev 'net_ifpga_cfg`` EAL option. + +The following device parameters are supported: + +- ``ifpga`` [string] + + Provide a specific Intel FPGA device PCI BDF. Can be provided multiple + times for additional instances. + +- ``port`` [int] + + Each FPGA can provide many channels to PR AFU by software, each channels + is identified by this parameter. + +- ``afu_bts`` [string] + + If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and + identifies AFU Bit Stream file. \ No newline at end of file diff --git a/doc/guides/rawdevs/index.rst b/doc/guides/rawdevs/index.rst new file mode 100644 index 0000000..cdee371 --- /dev/null +++ b/doc/guides/rawdevs/index.rst @@ -0,0 +1,11 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2018 Intel Corporation + +Raw Device Drivers +======================= + +.. toctree:: + :maxdepth: 2 + :numbered: + + ifpga_rawdev \ No newline at end of file diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst index 0ae61e8..77b96e2 100644 --- a/doc/guides/rel_notes/release_18_05.rst +++ b/doc/guides/rel_notes/release_18_05.rst @@ -164,6 +164,19 @@ New Features stats/xstats on shared memory from secondary process, and also pdump packets on those virtual devices. +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** + + The Ifpga Bus library provides support for integrating any Intel FPGA device with + the DPDK framework. It provides Intel FPGA Partial Bit Stream AFU(Accelerated + Function Unit) scan and drivers prove. + +* **Added IFPGA(Intel FPGA) Rawdev Driver.** + + Added a new Rawdev driver called IFPGA(Intel FPGA) Rawdev Driver, which cooperates + with OPAE(Open Programmable Acceleration Engine) share code provides common FPGA + management ops for FPGA operation. + + See the :doc:`../rawdevs/ifpga_rawdev` programmer's guide for more details. API Changes ----------- -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v7 5/5] iFPGA: add document for iFPGA driver 2018-05-04 14:11 ` [dpdk-dev] [PATCH v7 5/5] iFPGA: add document for iFPGA driver Xu, Rosen @ 2018-05-05 19:19 ` Shreyansh Jain 0 siblings, 0 replies; 149+ messages in thread From: Shreyansh Jain @ 2018-05-05 19:19 UTC (permalink / raw) To: Xu, Rosen, dev Cc: declan.doherty, bruce.richardson, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet Some trivial comments inlined which can be fixed in v8 easily: > -----Original Message----- > From: Xu, Rosen [mailto:rosen.xu@intel.com] > Sent: Friday, May 4, 2018 7:41 PM > To: dev@dpdk.org > Cc: rosen.xu@intel.com; declan.doherty@intel.com; > bruce.richardson@intel.com; Shreyansh Jain <shreyansh.jain@nxp.com>; > ferruh.yigit@intel.com; konstantin.ananyev@intel.com; > tianfei.zhang@intel.com; song.liu@intel.com; hao.wu@intel.com; > gaetan.rivet@6wind.com > Subject: [PATCH v7 5/5] iFPGA: add document for iFPGA driver > > From: Figo Zhang <tianfei.zhang@intel.com> > > add some introduction, motivation and usage for iFPGA driver. > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> > --- > doc/guides/index.rst | 1 + > doc/guides/rawdevs/ifpga_rawdev.rst | 112 > +++++++++++++++++++++++++++++++++ > doc/guides/rawdevs/index.rst | 11 ++++ > doc/guides/rel_notes/release_18_05.rst | 13 ++++ > 4 files changed, 137 insertions(+) > create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst > create mode 100644 doc/guides/rawdevs/index.rst > > diff --git a/doc/guides/index.rst b/doc/guides/index.rst > index d60529d..a93baac 100644 > --- a/doc/guides/index.rst > +++ b/doc/guides/index.rst > @@ -20,6 +20,7 @@ DPDK documentation > eventdevs/index > mempool/index > platform/index > + rawdevs/index > contributing/index > rel_notes/index > faq/index > diff --git a/doc/guides/rawdevs/ifpga_rawdev.rst > b/doc/guides/rawdevs/ifpga_rawdev.rst > new file mode 100644 > index 0000000..3311586 > --- /dev/null > +++ b/doc/guides/rawdevs/ifpga_rawdev.rst > @@ -0,0 +1,112 @@ > +.. SPDX-License-Identifier: BSD-3-Clause > + Copyright(c) 2018 Intel Corporation. > + > +IFPGA Rawdev Driver > +====================== > + > +FPGA is used more and more widely in Cloud and NFV, one primary reason > is > +that FPGA not only provides ASIC performance but also it's more > flexible > +than ASIC. > + > +FPGA uses Partial Reconfigure(PR) Parts of Bit Stream to achieve its > +flexibility. That means one FPGA Device Bit Stream is divided into > many Parts > +of Bit Stream(each Part of Bit Stream is defined as AFU-Accelerated ^^^^^^ Stream<space>(each ... Same at couple of places in below text as well. > Function > +Unit), and each AFU is a hardware acceleration unit which can be > dynamically > +reloaded respectively. > + > +By PR(Partial Reconfiguration) AFUs, one FPGA resources can be time- > shared by > +different users. FPGA hot upgraded and fault tolerance can be provided ^^^^^^^^^^^^ Hot upgrade? > easily. > + > +The SW IFPGA Rawdev Driver (**ifpga_rawdev**) provides a Rawdev driver > +that utilizes Intel FPGA Software Stack OPAE(Open Programmable > Acceleration > +Engine) for FPGA management. > + > +Implementation details > +---------------------- > + > +Each instance of IFPGA Rawdev Driver is probed by Intel FpgaDev. > Cooperated Or, maybe you can use 'In coordination with...' in pace of 'Cooperated'. > +with OPAE share code IFPGA Rawdev Driver provides common FPGA > management ops > +for FPGA operation, OPAE provides all following operations: > +- FPGA PR(Partial Reconfiguration) management > +- FPGA AFUs Identifying > +- FPGA Thermal Management > +- FPGA Power Management > +- FPGA Performance reporting > +- FPGA Remote Debug > + > +All configuration parameters is taken by vdev_ifpga_cfg driver. ^^^^ are > Besides > +configuration, vdev_ifpga_cfg driver also hot plugin AFUs in IFPGA ^^^^^^^^^^^^ also hot plugs > Bus. > + > +All of the AFUs of one FPGA may share same PCI BDF and AFUs scan > depend on > +IFPGA Rawdev Driver so IFPGA Bus takes AFU device scan and AFU drivers > probe. > +All AFU device driver bind to AFU device by its UUID(Universally > Unique > +Identifier). > + > +To avoid unnecessary code duplication and ensure maximum performance, > +handling of AFU devices is left to different PMDs; all the design as > +summarized by the following block diagram:: > + > + +---------------------------------------------------------------+ > + | Application(s) | > + +----------------------------.----------------------------------+ > + | > + | > + +----------------------------'----------------------------------+ > + | DPDK Framework (APIs) | > + +----------|------------|--------.---------------------|--------+ > + / \ | > + / \ | > + +-------'-------+ +-------'-------+ +--------'--------+ > + | Eth PMD | | Crypto PMD | | | > + +-------.-------+ +-------.-------+ | | > + | | | | > + | | | | > + +-------'-------+ +-------'-------+ | IFPGA | > + | Eth AFU Dev | |Crypto AFU Dev | | Rawdev Driver | > + +-------.-------+ +-------.-------+ |(OPAE Share Code)| > + | | | | > + | | Rawdev | | > + +-------'------------------'-------+ Ops | | > + | IFPGA Bus | -------->| | > + +-----------------.----------------+ +--------.--------+ > + | | > + Hot-plugin -->| | > + | | > + +-----------------'------------------+ +--------'--------+ > + | vdev_ifpga_cfg driver | | Intel FpgaDev | > + +------------------------------------+ +-----------------+ > + > +Build options > +------------- > + > +- ``CONFIG_RTE_LIBRTE_IFPGA_BUS`` (default ``y``) > + > + Toggle compilation of IFPGA Bus library. > + > +- ``CONFIG_RTE_LIBRTE_IFPGA_RAWDEV`` (default ``y``) > + > + Toggle compilation of the ``ifpga_rawdev`` driver. > + > +Run-time parameters > +------------------- > + > +This driver is invoked automatically in systems added Intel FPGA ^^^^^^^^^^^^^^ Maybe you meant "systems added with Intel FPGA,.." > system, > +but PR and IFPGA Bus scan is trigged by command line using > +``--vdev 'net_ifpga_cfg`` EAL option. > + > +The following device parameters are supported: > + > +- ``ifpga`` [string] > + > + Provide a specific Intel FPGA device PCI BDF. Can be provided > multiple > + times for additional instances. > + > +- ``port`` [int] > + > + Each FPGA can provide many channels to PR AFU by software, each > channels > + is identified by this parameter. > + > +- ``afu_bts`` [string] > + > + If null, the AFU Bit Stream has been PR in FPGA, if not forces PR > and > + identifies AFU Bit Stream file. > \ No newline at end of file > diff --git a/doc/guides/rawdevs/index.rst > b/doc/guides/rawdevs/index.rst > new file mode 100644 > index 0000000..cdee371 > --- /dev/null > +++ b/doc/guides/rawdevs/index.rst > @@ -0,0 +1,11 @@ > +.. SPDX-License-Identifier: BSD-3-Clause > + Copyright(c) 2018 Intel Corporation > + > +Raw Device Drivers > +======================= > + > +.. toctree:: > + :maxdepth: 2 > + :numbered: > + > + ifpga_rawdev > \ No newline at end of file This patch too would have to be rebased over cmdif patches as that already introduces the rawdevs/index.rst file. > diff --git a/doc/guides/rel_notes/release_18_05.rst > b/doc/guides/rel_notes/release_18_05.rst > index 0ae61e8..77b96e2 100644 > --- a/doc/guides/rel_notes/release_18_05.rst > +++ b/doc/guides/rel_notes/release_18_05.rst > @@ -164,6 +164,19 @@ New Features > stats/xstats on shared memory from secondary process, and also pdump > packets on > those virtual devices. > > +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** > + > + The Ifpga Bus library provides support for integrating any Intel > FPGA device with > + the DPDK framework. It provides Intel FPGA Partial Bit Stream > AFU(Accelerated > + Function Unit) scan and drivers prove. > + > +* **Added IFPGA(Intel FPGA) Rawdev Driver.** > + > + Added a new Rawdev driver called IFPGA(Intel FPGA) Rawdev Driver, > which cooperates > + with OPAE(Open Programmable Acceleration Engine) share code provides > common FPGA > + management ops for FPGA operation. > + > + See the :doc:`../rawdevs/ifpga_rawdev` programmer's guide for more > details. > > API Changes > ----------- > -- > 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v8 0/5] Introduce Intel FPGA BUS 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (10 preceding siblings ...) 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 0/5] Introduce Intel FPGA BUS Xu, Rosen @ 2018-05-06 8:40 ` Xu, Rosen 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 1/5] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen ` (4 more replies) 2018-05-08 14:18 ` [dpdk-dev] [PATCH v9 0/4] Introduce Intel FPGA BUS Xu, Rosen ` (5 subsequent siblings) 17 siblings, 5 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-06 8:40 UTC (permalink / raw) To: dev Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset=y, Size: 8975 bytes --] From: "Xu, Rosen" <rosen.xu@intel.com> Intel FPGA BUS in DPDK ------------------------- This patch set introduces Intel FPGA BUS support in DPDK. v8 updates: ========== - Fix some comments from Shreyansh Jain - Patch 3 and Patch 5 will continue rebase when qcom patches merging into mainline - add Shreyansh Jain's Acked-by v7 updates: ========== - Fix some comments from DPDK community - Fix the CLANG compile error - Fix the meson build warring. v6 updates: =========== - Add documentation - Add meson build script - Split new patch for OPAE share code v5 updates: =========== - Fixed SHARED LIB Build issue - Changed command name to IFPGA Rawdev name, so remove pci library datastruct and function. - Fixed PATCH v2/v3/v4 comments v4 updates: =========== - Remove all modifications from eal - Create vdev to take IFPGA parameters configuration - AFU Device Driver bind to AFU Device by uuid - Take more test in scenario of Multi-FPGA System v3 updates: =========== - Remove all modifications of bus scan and probe - FPGA BUS Scan is trigged by hotplug of Rawdev - Took Modifications of comments - Move AFU Device to IFPGA - FPGA BUS Scan depend on it¡¯s IFPGA Rawdev - Add Build Macros for FPGA BUS and IFPGA Rawdev Questions ========= Why not PCI Bus? All of the AFUs of one FPGA may share same PCI BDF. Why not vdev Bus? Because AFUs depend on Rawdev, and it's hardware specpic. Motivation ========== FPGA is used more and more widely in Cloud and NFV, one primary reason is that FPGA not only provide ASIC performance but also it's more flexible than ASIC. FPGA use Partial Reconfigure(PR) Parts of Bitstream to achieve its flexibility. Another reason is that one FPGA can be shared by different Users, and each User can use some of AFUs of One FPGA. That means One FPGA Device Bitstream is divided into many Parts of Bitstream(each Part of Bitstream is defined as AFU-Accelerated Function Unit), and each AFU is a Hardware Acceleration Unit and it can dynamically Reload respectively. Proposed Solution ================= - Involve Rawdev to take FPGA Partial Configuration(Download/PR) - Defined FPGA-BUS for Acceleration Drivers of AFUs - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver. FPGA-BUS scan is called, but AFU depend on Rawdev, so this scan doesn't trig AFU device create. - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their dirves are also probed. Scope ===== The Intel FPGA BUS implementation is target towards various FPGA Devices use PR to provide many Acceleration Function. Specific PMDs may also bind to its AFU. And Applications don't care they are using ASIC Acceleration or FPGA AFU Acceleration. Status ===== With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable Acceleration Engine) Share Code, Intel FPGA BUS runs well in Intel PSG FPGA Cards. Figo Zhang (2): iFPGA: add meson build iFPGA: add document for iFPGA driver Rosen Xu (3): bus/ifpga: Add Intel FPGA BUS Library iFPGA: Add Intel FPGA OPAE Share Code iFPGA: Add Intel FPGA BUS Rawdev Driver config/common_base | 6 + doc/guides/rawdevs/ifpga_rawdev.rst | 112 ++ doc/guides/rel_notes/release_18_05.rst | 13 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 + drivers/bus/ifpga/ifpga_bus.c | 501 ++++++ drivers/bus/ifpga/ifpga_common.c | 88 ++ drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 + drivers/bus/ifpga/meson.build | 8 + drivers/bus/ifpga/rte_bus_ifpga.h | 160 ++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/bus/meson.build | 2 +- drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 + drivers/raw/ifpga_rawdev/base/Makefile | 30 + drivers/raw/ifpga_rawdev/base/README | 31 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 294 ++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 28 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 57 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1661 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 824 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 11 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 314 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 164 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 734 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 301 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 403 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 715 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 372 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 127 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 408 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 165 ++ drivers/raw/ifpga_rawdev/base/meson.build | 34 + drivers/raw/ifpga_rawdev/base/opae_debug.c | 99 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 19 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 381 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 253 +++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 145 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 279 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 81 + .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 75 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 45 + drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 608 +++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 + drivers/raw/ifpga_rawdev/meson.build | 15 + .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + mk/rte.app.mk | 5 +- 48 files changed, 9736 insertions(+), 2 deletions(-) create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/meson.build create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/README create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/meson.build create mode 100644 drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v8 1/5] bus/ifpga: Add Intel FPGA BUS Library 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 0/5] Introduce Intel FPGA BUS Xu, Rosen @ 2018-05-06 8:40 ` Xu, Rosen 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 2/5] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen ` (3 subsequent siblings) 4 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-06 8:40 UTC (permalink / raw) To: dev Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: Rosen Xu <rosen.xu@intel.com> Defined FPGA-BUS for Acceleration Drivers of AFUs 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver, it will be covered in following patches. 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their drivers are also probed. This patch will introduce rte_afu_device which describe the AFU device listed in the FPGA-BUS. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Figo zhang <tianfei.zhang@intel.com> --- config/common_base | 5 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 ++ drivers/bus/ifpga/ifpga_bus.c | 501 ++++++++++++++++++++++++++++ drivers/bus/ifpga/ifpga_common.c | 88 +++++ drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 ++ drivers/bus/ifpga/meson.build | 8 + drivers/bus/ifpga/rte_bus_ifpga.h | 160 +++++++++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/bus/meson.build | 2 +- mk/rte.app.mk | 1 + 12 files changed, 856 insertions(+), 1 deletion(-) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/meson.build create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map diff --git a/config/common_base b/config/common_base index 03a8688..bd4b356 100644 --- a/config/common_base +++ b/config/common_base @@ -149,6 +149,11 @@ CONFIG_RTE_LIBRTE_PCI_BUS=y CONFIG_RTE_LIBRTE_VDEV_BUS=y # +# Compile the Intel FPGA bus +# +CONFIG_RTE_LIBRTE_IFPGA_BUS=y + +# # Compile ARK PMD # CONFIG_RTE_LIBRTE_ARK_PMD=y diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index c251b65..cff3567 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -9,5 +9,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc endif DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile new file mode 100644 index 0000000..3ff3bdb --- /dev/null +++ b/drivers/bus/ifpga/Makefile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_bus_ifpga.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_kvargs + +# versioning export map +EXPORT_MAP := rte_bus_ifpga_version.map + +# library version +LIBABIVER := 1 + +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c + +# +# Export include files +# +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index 0000000..174ac54 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -0,0 +1,501 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_bus_logtype; + +/* Forward declaration to access Intel FPGA bus + * on which iFPGA devices are connected + */ +static struct rte_bus rte_ifpga_bus; + +/** Double linked list of IFPGA device. */ +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); + +static struct ifpga_device_list ifpga_device_list = + TAILQ_HEAD_INITIALIZER(ifpga_device_list); +static struct afu_driver_list afu_driver_list = + TAILQ_HEAD_INITIALIZER(afu_driver_list); + + +/* register a ifpga bus based driver */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver) +{ + RTE_VERIFY(driver); + + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); +} + +/* un-register a fpga bus based driver */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) +{ + TAILQ_REMOVE(&afu_driver_list, driver, next); +} + +static struct rte_ifpga_device * +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + if (rdev && + ifpga_dev->rdev && + ifpga_dev->rdev == rdev) + return ifpga_dev; + } + return NULL; +} + +static struct rte_afu_device * +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, + const struct rte_afu_id *afu_id) +{ + struct rte_afu_device *afu_dev = NULL; + + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) + return afu_dev; + } + return NULL; +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static struct rte_afu_device * +ifpga_scan_one(struct rte_devargs *devargs, + struct rte_ifpga_device *ifpga_dev) +{ + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_afu_pr_conf afu_pr_conf; + int ret = 0; + char *path = NULL; + + memset(&afu_pr_conf, 0, sizeof(struct rte_afu_pr_conf)); + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, + &ifpga_get_string_arg, &path) < 0) { + IFPGA_BUS_ERR("Failed to parse %s", + IFPGA_AFU_BTS); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_AFU_BTS); + goto end; + } + + afu_pr_conf.afu_id.uuid.uuid_low = 0; + afu_pr_conf.afu_id.uuid.uuid_high = 0; + afu_pr_conf.pr_enable = path?1:0; + + rawdev = ifpga_dev->rdev; + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) + goto end; + + afu_dev = calloc(1, sizeof(*afu_dev)); + if (!afu_dev) + goto end; + + afu_dev->device.devargs = devargs; + afu_dev->device.numa_node = SOCKET_ID_ANY; + afu_dev->device.name = devargs->name; + afu_dev->rawdev = rawdev; + afu_dev->id.uuid.uuid_low = 0; + afu_dev->id.uuid.uuid_high = 0; + afu_dev->id.port = afu_pr_conf.afu_id.port; + afu_dev->ifpga_dev = ifpga_dev; + + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); + + if (rawdev->dev_ops && + rawdev->dev_ops->dev_start && + rawdev->dev_ops->dev_start(rawdev)) + goto free_dev; + + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); + if (rawdev->dev_ops->firmware_load && + rawdev->dev_ops->firmware_load(rawdev, + &afu_pr_conf)){ + IFPGA_BUS_ERR("firmware load error %d\n", ret); + goto free_dev; + } + afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; + afu_dev->id.uuid.uuid_high = afu_pr_conf.afu_id.uuid.uuid_high; + + return afu_dev; + +free_dev: + free(afu_dev); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (path) + free(path); + + return NULL; +} + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static int +ifpga_scan(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + char *name = NULL; + char name1[RTE_RAWDEV_NAME_MAX_LEN]; + struct rte_afu_device *afu_dev = NULL; + + /* for FPGA devices we scan the devargs_list populated via cmdline */ + RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { + if (devargs->bus != &rte_ifpga_bus) + continue; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &ifpga_get_string_arg, &name) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + memset(name1, 0, sizeof(name1)); + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", name); + + rawdev = rte_rawdev_pmd_get_named_dev(name1); + if (!rawdev) + goto end; + + if (ifpga_find_ifpga_dev(rawdev)) + continue; + + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); + if (!ifpga_dev) + goto end; + + ifpga_dev->rdev = rawdev; + TAILQ_INIT(&ifpga_dev->afu_list); + + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); + afu_dev = ifpga_scan_one(devargs, ifpga_dev); + if (afu_dev != NULL) + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, next); + } + +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +/* + * Match the AFU Driver and AFU Device using the ID Table + */ +static int +rte_afu_match(const struct rte_afu_driver *afu_drv, + const struct rte_afu_device *afu_dev) +{ + const struct rte_afu_uuid *id_table; + + for (id_table = afu_drv->id_table; + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); + id_table++) { + /* check if device's identifiers match the driver's ones */ + if ((id_table->uuid_low != afu_dev->id.uuid.uuid_low) || + id_table->uuid_high != + afu_dev->id.uuid.uuid_high) + continue; + + return 1; + } + + return 0; +} + +static int +ifpga_probe_one_driver(struct rte_afu_driver *drv, + struct rte_afu_device *afu_dev) +{ + int ret; + + if (!rte_afu_match(drv, afu_dev)) + /* Match of device and driver failed */ + return 1; + + /* reference driver structure */ + afu_dev->driver = drv; + afu_dev->device.driver = &drv->driver; + + /* call the driver probe() function */ + ret = drv->probe(afu_dev); + if (ret) { + afu_dev->driver = NULL; + afu_dev->device.driver = NULL; + } + + return ret; +} + +static int +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) +{ + struct rte_afu_driver *drv = NULL; + int ret = 0; + + if (afu_dev == NULL) + return -1; + + /* Check if a driver is already loaded */ + if (afu_dev->driver != NULL) + return 0; + + TAILQ_FOREACH(drv, &afu_driver_list, next) { + if (ifpga_probe_one_driver(drv, afu_dev)) { + ret = -1; + break; + } + } + return ret; +} + +/* + * Scan the content of the Intel FPGA bus, and call the probe() function for + * all registered drivers that have a matching entry in its id_table + * for discovered devices. + */ +static int +ifpga_probe(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev = NULL; + int ret = 0; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + + if (afu_dev->device.driver) + continue; + + ret = ifpga_probe_all_drivers(afu_dev); + if (ret < 0) + IFPGA_BUS_ERR("failed to initialize %s device\n", + rte_ifpga_device_name(afu_dev)); + } + } + + return ret; +} + +static int +ifpga_plug(struct rte_device *dev) +{ + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); +} + +static int +ifpga_remove_driver(struct rte_afu_device *afu_dev) +{ + const char *name; + const struct rte_afu_driver *driver; + + name = rte_ifpga_device_name(afu_dev); + if (!afu_dev->device.driver) { + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); + return 1; + } + + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); + return driver->remove(afu_dev); +} + +static int +ifpga_unplug(struct rte_device *dev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_devargs *devargs = NULL; + int ret; + + if (dev == NULL) + return -EINVAL; + + afu_dev = RTE_DEV_TO_AFU(dev); + if (!dev) + return -ENOENT; + + ifpga_dev = afu_dev->ifpga_dev; + devargs = dev->devargs; + + ret = ifpga_remove_driver(afu_dev); + if (ret) + return ret; + + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); + + rte_devargs_remove(devargs->bus->name, devargs->name); + free(afu_dev); + return 0; + +} + +static struct rte_device * +ifpga_find_device(const struct rte_device *start, + rte_dev_cmp_t cmp, const void *data) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (start && &afu_dev->device == start) { + start = NULL; + continue; + } + if (cmp(&afu_dev->device, data) == 0) + return &afu_dev->device; + } + } + return NULL; +} +static int +ifpga_parse(const char *name, void *addr) +{ + int *out = addr; + struct rte_rawdev *rawdev = NULL; + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; + char *c1 = NULL, *c2 = NULL; + int port = IFPGA_BUS_DEV_PORT_MAX; + char str_port[8]; + int str_port_len = 0; + int ret; + + memset(str_port, 0, 8); + c1 = strchr(name, '|'); + if (c1 != NULL) { + str_port_len = c1-name; + c2 = c1+1; + } + + if (str_port_len < 8 && + str_port_len > 0) { + memcpy(str_port, name, str_port_len); + ret = sscanf(str_port, "%d", &port); + if (ret == -1) + return 0; + } + + memset(rawdev_name, 0, sizeof(rawdev_name)); + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", c2); + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev && + (addr != NULL)) + *out = port; + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev) + return 0; + else + return 1; +} + +static struct rte_bus rte_ifpga_bus = { + .scan = ifpga_scan, + .probe = ifpga_probe, + .find_device = ifpga_find_device, + .plug = ifpga_plug, + .unplug = ifpga_unplug, + .parse = ifpga_parse, +}; + +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); + +RTE_INIT(ifpga_init_log) +{ + ifpga_bus_logtype = rte_log_register("bus.ifpga"); + if (ifpga_bus_logtype >= 0) + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); +} diff --git a/drivers/bus/ifpga/ifpga_common.c b/drivers/bus/ifpga/ifpga_common.c new file mode 100644 index 0000000..b4efc20 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(char **)extra_args = strdup(value); + + if (!*(char **)extra_args) + return -ENOMEM; + + return 0; +} +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(int *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(uint64_t *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_unsigned_long(const char *str, int base) +{ + unsigned long num; + char *end = NULL; + + errno = 0; + + num = strtoul(str, &end, base); + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) + return -1; + + return num; +} + +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1) +{ + if ((afu_id0->uuid.uuid_low == afu_id1->uuid.uuid_low) && + (afu_id0->uuid.uuid_high == afu_id1->uuid.uuid_high) && + (afu_id0->port == afu_id1->port)) { + return 0; + } else + return 1; +} diff --git a/drivers/bus/ifpga/ifpga_common.h b/drivers/bus/ifpga/ifpga_common.h new file mode 100644 index 0000000..b6662c8 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMMON_H_ +#define _IFPGA_COMMON_H_ + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_unsigned_long(const char *str, int base); +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1); + +#endif /* _IFPGA_COMMON_H_ */ diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index 0000000..873e0a4 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_logs.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_LOGS_H_ +#define _IFPGA_LOGS_H_ + +#include <rte_log.h> + +extern int ifpga_bus_logtype; + +#define IFPGA_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") + +#define IFPGA_BUS_DEBUG(fmt, args...) \ + IFPGA_BUS_LOG(DEBUG, fmt, ## args) +#define IFPGA_BUS_INFO(fmt, args...) \ + IFPGA_BUS_LOG(INFO, fmt, ## args) +#define IFPGA_BUS_ERR(fmt, args...) \ + IFPGA_BUS_LOG(ERR, fmt, ## args) +#define IFPGA_BUS_WARN(fmt, args...) \ + IFPGA_BUS_LOG(WARNING, fmt, ## args) + +#endif /* _IFPGA_BUS_LOGS_H_ */ diff --git a/drivers/bus/ifpga/meson.build b/drivers/bus/ifpga/meson.build new file mode 100644 index 0000000..c9b08c8 --- /dev/null +++ b/drivers/bus/ifpga/meson.build @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2018 Intel Corporation + +deps += ['pci', 'kvargs', 'rawdev'] +install_headers('rte_bus_ifpga.h') +sources = files('ifpga_common.c', 'ifpga_bus.c') + +allow_experimental_apis = true diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h new file mode 100644 index 0000000..5c559e1 --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga.h @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _RTE_BUS_IFPGA_H_ +#define _RTE_BUS_IFPGA_H_ + +/** + * @file + * + * RTE Intel FPGA Bus Interface + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_bus.h> +#include <rte_pci.h> + +/** Name of Intel FPGA Bus */ +#define IFPGA_BUS_NAME ifpga + +/* Forward declarations */ +struct rte_afu_device; + +/** List of Intel AFU devices */ +TAILQ_HEAD(afu_device_list, rte_afu_device); +/** Double linked list of AFU device drivers. */ +TAILQ_HEAD(afu_driver_list, rte_afu_driver); + +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 + +struct rte_afu_uuid { + uint64_t uuid_low; + uint64_t uuid_high; +} __attribute__ ((packed)); + +#define IFPGA_BUS_DEV_PORT_MAX 4 + +/** + * A structure describing an ID for a AFU driver. Each driver provides a + * table of these IDs for each device that it supports. + */ +struct rte_afu_id { + struct rte_afu_uuid uuid; + int port; /**< port number */ +} __attribute__ ((packed)); + +/** + * A structure PR (Partial Reconfiguration) configuration AFU driver. + */ + +struct rte_afu_pr_conf { + struct rte_afu_id afu_id; + int pr_enable; + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +}; + +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) + +/** + * A structure describing a fpga device. + */ +struct rte_ifpga_device { + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ + struct rte_rawdev *rdev; + struct afu_device_list afu_list; /**< List of AFU devices */ +}; + +/** + * A structure describing a AFU device. + */ +struct rte_afu_device { + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ + struct rte_device device; /**< Inherit core device */ + struct rte_rawdev *rawdev; /**< Point Rawdev */ + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ + struct rte_afu_id id; /**< AFU id within FPGA. */ + uint32_t num_region; /**< number of regions found */ + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; + /**< AFU Memory Resource */ + struct rte_intr_handle intr_handle; /**< Interrupt handle */ + struct rte_afu_driver *driver; /**< Associated driver */ + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +} __attribute__ ((packed)); + +/** + * @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_DRV_TO_AFU_CONST(ptr) \ + container_of(ptr, const struct rte_afu_driver, driver) + +/** + * Initialisation function for the driver called during FPGA BUS probing. + */ +typedef int (afu_probe_t)(struct rte_afu_device *); + +/** + * Uninitialisation function for the driver called during hotplugging. + */ +typedef int (afu_remove_t)(struct rte_afu_device *); + +/** + * A structure describing a AFU device. + */ +struct rte_afu_driver { + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ + struct rte_driver driver; /**< Inherit core driver. */ + afu_probe_t *probe; /**< Device Probe function. */ + afu_remove_t *remove; /**< Device Remove function. */ + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ + uint32_t drv_flags; /**< Flags contolling handling of device. */ +}; + +static inline const char * +rte_ifpga_device_name(const struct rte_afu_device *afu) +{ + if (afu && afu->device.name) + return afu->device.name; + return NULL; +} + +/** + * Register a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be registered. + */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver); + +/** + * Unregister a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be unregistered. + */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); + +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ +RTE_INIT(afudrvinitfn_ ##afudrv);\ +static const char *afudrvinit_ ## nm ## _alias;\ +static void afudrvinitfn_ ##afudrv(void)\ +{\ + (afudrv).driver.name = RTE_STR(nm);\ + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ + rte_ifpga_driver_register(&afudrv);\ +} \ +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) + +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ +static const char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) + +#endif /* _RTE_BUS_IFPGA_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map new file mode 100644 index 0000000..1304caf --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map @@ -0,0 +1,10 @@ +DPDK_18.05 { + global: + + ifpga_get_integer32_arg; + ifpga_get_string_arg; + rte_ifpga_driver_register; + rte_ifpga_driver_unregister; + + local: *; +}; diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build index 58dfbe2..170df25 100644 --- a/drivers/bus/meson.build +++ b/drivers/bus/meson.build @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel Corporation -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] +drivers = ['dpaa', 'fslmc', 'pci', 'vdev', 'ifpga'] std_deps = ['eal'] config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' driver_name_fmt = 'rte_bus_@0@' diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 29a2a60..8b10c2a 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -251,6 +251,7 @@ endif # CONFIG_RTE_LIBRTE_EVENTDEV ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += -lrte_pmd_skeleton_rawdev +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga endif # CONFIG_RTE_LIBRTE_RAWDEV -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v8 2/5] iFPGA: Add Intel FPGA OPAE Share Code 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 0/5] Introduce Intel FPGA BUS Xu, Rosen 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 1/5] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen @ 2018-05-06 8:40 ` Xu, Rosen 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen ` (2 subsequent siblings) 4 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-06 8:40 UTC (permalink / raw) To: dev Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Xu, Yilun [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset=y, Size: 221656 bytes --] From: Rosen Xu <rosen.xu@intel.com> This patch adds Intel FPGA Open Programmable Acceleration Engine (OPAE)[1] base driver code, in order to support Intel FPGA devices under DPDK. The base code currently supports Intel FPGA solutions including integrated solution (Intel(R) Xeon(R) CPU with FPGAs) and discrete solution (Intel(R) Programmable Acceleration Card with Intel(R) Arria(R) 10 FPGA) and it could be extended to support more FPGA devices in the future. Please refer to [1][2] for more introduction on OPAE and Intel FPGAs. [1] https://01.org/OPAE [2] https://www.altera.com/solutions/acceleration-hub/overview.html Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> Signed-off-by: Wu, Hao <hao.wu@intel.com> Signed-off-by: Xu, Yilun <yilun.xu@intel.com> --- drivers/raw/ifpga_rawdev/base/Makefile | 30 + drivers/raw/ifpga_rawdev/base/README | 31 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 294 ++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 28 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 57 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1661 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 824 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 11 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 314 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 164 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 734 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 301 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 403 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 715 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 372 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 127 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 408 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 165 ++ drivers/raw/ifpga_rawdev/base/opae_debug.c | 99 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 19 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 381 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 253 +++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 145 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 279 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 81 + .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 75 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 45 + 27 files changed, 8016 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/README create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile new file mode 100644 index 0000000..ade3551 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -0,0 +1,30 @@ +#SPDX-License-Identifier: BSD-3-Clause +#Copyright(c) 2010-2018 Intel Corporation + +ifneq ($(CONFIG_RTE_LIBRTE_EAL),) +OSDEP := osdep_rte +else +OSDEP := osdep_raw +endif + +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev/base/$(OSDEP) + +SRCS-y += ifpga_api.c +SRCS-y += ifpga_enumerate.c +SRCS-y += ifpga_feature_dev.c +SRCS-y += ifpga_fme.c +SRCS-y += ifpga_fme_iperf.c +SRCS-y += ifpga_fme_dperf.c +SRCS-y += ifpga_fme_error.c +SRCS-y += ifpga_port.c +SRCS-y += ifpga_port_error.c +SRCS-y += opae_hw_api.c +SRCS-y += opae_ifpga_hw_api.c +SRCS-y += opae_debug.c +SRCS-y += ifpga_fme_pr.c + +ifeq ($(CONFIG_RTE_TOOLCHAIN_CLANG),y) + CFLAGS_ifpga_fme_pr.o += -march=knl +endif + +SRCS-y += $(wildcard $(SRCDIR)/base/$(OSDEP)/*.c) diff --git a/drivers/raw/ifpga_rawdev/base/README b/drivers/raw/ifpga_rawdev/base/README new file mode 100644 index 0000000..3636ac7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/README @@ -0,0 +1,31 @@ +.. + +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +Intel® iFPGA driver +================== + +This directory contains source code of Intel FPGA driver released by +the team which develops Intel FPGA Open Programmable Acceleration Engine (OPAE). +The directory of base/ contains the original source package. The base code +currently supports Intel FPGA solutions including integrated solution (Intel(R) +Xeon(R) CPU with FPGAs) and discrete solution (Intel(R) Programmable Acceleration +Card with Intel(R) Arria(R) 10 FPGA) and it could be extended to support more FPGA +devices in the future. + +Please refer to [1][2] for more introduction on OPAE and Intel FPGAs. + +[1] https://01.org/OPAE +[2] https://www.altera.com/solutions/acceleration-hub/overview.html + + +Updating the driver +=================== + +NOTE: The source code in this directory should not be modified apart from +the following file(s): + + osdep_raw/osdep_generic.h + osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.c b/drivers/raw/ifpga_rawdev/base/ifpga_api.c new file mode 100644 index 0000000..540e171 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -0,0 +1,294 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_api.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +#include "opae_hw_api.h" + +/* Accelerator APIs */ +static int ifpga_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return fpga_get_afu_uuid(port, uuid); +} + +static int ifpga_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + struct fpga_uafu_irq_set irq_set; + + if (!br || !br->data) + return -EINVAL; + + if (start >= afu_info->num_irqs || start + count > afu_info->num_irqs) + return -EINVAL; + + port = br->data; + + irq_set.start = start; + irq_set.count = count; + irq_set.evtfds = evtfds; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_UINT, &irq_set); +} + +static int ifpga_acc_get_info(struct opae_accelerator *acc, + struct opae_acc_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -ENODEV; + + info->num_regions = afu_info->num_regions; + info->num_irqs = afu_info->num_irqs; + + return 0; +} + +static int ifpga_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -EINVAL; + + if (info->index >= afu_info->num_regions) + return -EINVAL; + + /* always one RW region only for AFU now */ + info->flags = ACC_REGION_READ | ACC_REGION_WRITE | ACC_REGION_MMIO; + info->len = afu_info->region[info->index].len; + info->addr = afu_info->region[info->index].addr; + + return 0; +} + +static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + switch (byte) { + case 8: + *(u64 *)data = opae_readq(region->addr + offset); + break; + case 4: + *(u32 *)data = opae_readl(region->addr + offset); + break; + case 2: + *(u16 *)data = opae_readw(region->addr + offset); + break; + case 1: + *(u8 *)data = opae_readb(region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ifpga_acc_write(struct opae_accelerator *acc, + unsigned int region_idx, u64 offset, + unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + /* normal mmio case */ + switch (byte) { + case 8: + opae_writeq(*(u64 *)data, region->addr + offset); + break; + case 4: + opae_writel(*(u32 *)data, region->addr + offset); + break; + case 2: + opae_writew(*(u16 *)data, region->addr + offset); + break; + case 1: + opae_writeb(*(u8 *)data, region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +struct opae_accelerator_ops ifpga_acc_ops = { + .read = ifpga_acc_read, + .write = ifpga_acc_write, + .set_irq = ifpga_acc_set_irq, + .get_info = ifpga_acc_get_info, + .get_region_info = ifpga_acc_get_region_info, + .get_uuid = ifpga_acc_get_uuid, +}; + +/* Bridge APIs */ + +static int ifpga_br_reset(struct opae_bridge *br) +{ + struct ifpga_port_hw *port = br->data; + + return fpga_port_reset(port); +} + +struct opae_bridge_ops ifpga_br_ops = { + .reset = ifpga_br_reset, +}; + +/* Manager APIs */ +static int ifpga_mgr_flash(struct opae_manager *mgr, int id, void *buf, + u32 size, u64 *status) +{ + struct ifpga_fme_hw *fme = mgr->data; + struct ifpga_hw *hw = fme->parent; + + return ifpga_pr(hw, id, buf, size, status); +} + +struct opae_manager_ops ifpga_mgr_ops = { + .flash = ifpga_mgr_flash, +}; + +/* Adapter APIs */ +static int ifpga_adapter_enumerate(struct opae_adapter *adapter) +{ + struct ifpga_hw *hw = malloc(sizeof(*hw)); + + if (hw) { + memset(hw, 0, sizeof(*hw)); + hw->pci_data = adapter->data; + hw->adapter = adapter; + if (ifpga_bus_enumerate(hw)) + goto error; + return ifpga_bus_init(hw); + } + +error: + return -ENOMEM; +} + +struct opae_adapter_ops ifpga_adapter_ops = { + .enumerate = ifpga_adapter_enumerate, +}; + +/** + * ifpga_pr - do the partial reconfiguration for a given port device + * @hw: pointer to the HW structure + * @port_id: the port device id + * @buffer: the buffer of the bitstream + * @size: the size of the bitstream + * @status: hardware status including PR error code if return -EIO. + * + * @return + * - 0: Success, partial reconfiguration finished. + * - <0: Error code returned in partial reconfiguration. + **/ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return do_pr(hw, port_id, buffer, size, status); +} + +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_get_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_get_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set) +{ + if (!hw || !irq_set) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_irq(&hw->fme, feature_id, irq_set); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_irq(&hw->port[port_id], feature_id, irq_set); + } + + return -ENOENT; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.h b/drivers/raw/ifpga_rawdev/base/ifpga_api.h new file mode 100644 index 0000000..dae7ca1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_API_H_ +#define _IFPGA_API_H_ + +#include "opae_hw_api.h" +#include "ifpga_hw.h" + +extern struct opae_adapter_ops ifpga_adapter_ops; +extern struct opae_manager_ops ifpga_mgr_ops; +extern struct opae_bridge_ops ifpga_br_ops; +extern struct opae_accelerator_ops ifpga_acc_ops; + +/* common APIs */ +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set); + +/* FME APIs */ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +#endif /* _IFPGA_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_compat.h b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h new file mode 100644 index 0000000..78b904e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMPAT_H_ +#define _IFPGA_COMPAT_H_ + +#include "opae_osdep.h" + +#undef container_of +#define container_of(ptr, type, member) ({ \ + typeof(((type *)0)->member)(*__mptr) = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) +#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE) + +#define readl(addr) opae_readl(addr) +#define readq(addr) opae_readq(addr) +#define writel(value, addr) opae_writel(value, addr) +#define writeq(value, addr) opae_writeq(value, addr) + +#define malloc(size) opae_malloc(size) +#define zmalloc(size) opae_zmalloc(size) +#define free(size) opae_free(size) + +/* + * Wait register's _field to be changed to the given value (_expect's _field) + * by polling with given interval and timeout. + */ +#define fpga_wait_register_field(_field, _expect, _reg_addr, _timeout, _invl)\ +({ \ + int wait = 0; \ + int ret = -ETIMEDOUT; \ + typeof(_expect) value; \ + for (; wait <= _timeout; wait += _invl) { \ + value.csr = readq(_reg_addr); \ + if (_expect._field == value._field) { \ + ret = 0; \ + break; \ + } \ + udelay(_invl); \ + } \ + ret; \ +}) + +#define __maybe_unused __attribute__((__unused__)) + +#define UNUSED(x) (void)(x) + +#endif /* _IFPGA_COMPAT_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h new file mode 100644 index 0000000..8989280 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -0,0 +1,1661 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_DEFINES_H_ +#define _IFPGA_DEFINES_H_ + +#include "ifpga_compat.h" + +#define MAX_FPGA_PORT_NUM 4 + +#define FME_FEATURE_HEADER "fme_hdr" +#define FME_FEATURE_THERMAL_MGMT "fme_thermal" +#define FME_FEATURE_POWER_MGMT "fme_power" +#define FME_FEATURE_GLOBAL_IPERF "fme_iperf" +#define FME_FEATURE_GLOBAL_ERR "fme_error" +#define FME_FEATURE_PR_MGMT "fme_pr" +#define FME_FEATURE_HSSI_ETH "fme_hssi" +#define FME_FEATURE_GLOBAL_DPERF "fme_dperf" +#define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" + +#define PORT_FEATURE_HEADER "port_hdr" +#define PORT_FEATURE_UAFU "port_uafu" +#define PORT_FEATURE_ERR "port_err" +#define PORT_FEATURE_UMSG "port_umsg" +#define PORT_FEATURE_PR "port_pr" +#define PORT_FEATURE_UINT "port_uint" +#define PORT_FEATURE_STP "port_stp" + +/* + * do not check the revision id as id may be dynamic under + * some cases, e.g, UAFU. + */ +#define SKIP_REVISION_CHECK 0xff + +#define FME_HEADER_REVISION 1 +#define FME_THERMAL_MGMT_REVISION 0 +#define FME_POWER_MGMT_REVISION 1 +#define FME_GLOBAL_IPERF_REVISION 1 +#define FME_GLOBAL_ERR_REVISION 1 +#define FME_PR_MGMT_REVISION 2 +#define FME_HSSI_ETH_REVISION 0 +#define FME_GLOBAL_DPERF_REVISION 0 +#define FME_QSPI_REVISION 0 + +#define PORT_HEADER_REVISION 0 +/* UAFU's header info depends on the downloaded GBS */ +#define PORT_UAFU_REVISION SKIP_REVISION_CHECK +#define PORT_ERR_REVISION 1 +#define PORT_UMSG_REVISION 0 +#define PORT_UINT_REVISION 0 +#define PORT_STP_REVISION 1 + +#define FEATURE_TYPE_AFU 0x1 +#define FEATURE_TYPE_BBB 0x2 +#define FEATURE_TYPE_PRIVATE 0x3 +#define FEATURE_TYPE_FIU 0x4 + +#define FEATURE_FIU_ID_FME 0x0 +#define FEATURE_FIU_ID_PORT 0x1 + +#define FEATURE_ID_HEADER 0x0 +#define FEATURE_ID_AFU 0xff + +enum fpga_id_type { + FME_ID, + PORT_ID, + 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, +}; + +/* + * All headers and structures must be byte-packed to match the spec. + */ +#pragma pack(1) + +struct feature_header { + union { + u64 csr; + struct { + u16 id:12; + u8 revision:4; + u32 next_header_offset:24; + u8 end_of_list:1; + u32 reserved:19; + u8 type:4; + }; + }; +}; + +struct feature_bbb_header { + struct uuid guid; +}; + +struct feature_afu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fiu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fme_capability { + union { + u64 csr; + struct { + u8 fabric_verid; /* Fabric version ID */ + u8 socket_id:1; /* Socket id */ + u8 rsvd1:3; /* Reserved */ + /* pci0 link available yes /no */ + u8 pci0_link_avile:1; + /* pci1 link available yes /no */ + u8 pci1_link_avile:1; + /* Coherent (QPI/UPI) link available yes /no */ + u8 qpi_link_avile:1; + u8 rsvd2:1; /* Reserved */ + /* IOMMU or VT-d supported yes/no */ + u8 iommu_support:1; + u8 num_ports:3; /* Number of ports */ + u8 sf_fab_ctl:1; /* Internal validation bit */ + u8 rsvd3:3; /* Reserved */ + /* + * Address width supported in bits + * BXT -0x26 , SKX -0x30 + */ + u8 address_width_bits:6; + u8 rsvd4:2; /* Reserved */ + /* Size of cache supported in kb */ + u16 cache_size:12; + u8 cache_assoc:4; /* Cache Associativity */ + u16 rsvd5:15; /* Reserved */ + u8 lock_bit:1; /* Lock bit */ + }; + }; +}; + +#define FME_AFU_ACCESS_PF 0 +#define FME_AFU_ACCESS_VF 1 + +struct feature_fme_port { + union { + u64 csr; + struct { + u32 port_offset:24; + u8 reserved1; + u8 port_bar:3; + u32 reserved2:20; + u8 afu_access_control:1; + u8 reserved3:4; + u8 port_implemented:1; + u8 reserved4:3; + }; + }; +}; + +struct feature_fme_fab_status { + union { + u64 csr; + struct { + u8 upilink_status:4; /* UPI Link Status */ + u8 rsvd1:4; /* Reserved */ + u8 pci0link_status:1; /* pci0 link status */ + u8 rsvd2:3; /* Reserved */ + u8 pci1link_status:1; /* pci1 link status */ + u64 rsvd3:51; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_base { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Base Address of memory range */ + u8 protected_base_addrss:4; + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_limit { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Limit Address of memory range */ + u8 protected_limit_addrss:4; + u16 rsvd2:11; /* Reserved */ + u8 enable:1; /* Enable GENPROTRANGE check */ + u32 rsvd3; /* Reserved */ + }; + }; +}; + +struct feature_fme_dxe_lock { + union { + u64 csr; + struct { + /* + * Determines write access to the DXE region CSRs + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_early_lock:1; + /* + * Determines write access to the HSSI CSR + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_late_lock:1; + u64 rsvd:62; + }; + }; +}; + +#define HSSI_ID_NO_HASSI 0 +#define HSSI_ID_PCIE_RP 1 +#define HSSI_ID_ETHERNET 2 + +struct feature_fme_bitstream_id { + union { + u64 csr; + struct { + u32 gitrepo_hash:32; /* GIT repository hash */ + /* + * HSSI configuration identifier: + * 0 - No HSSI + * 1 - PCIe-RP + * 2 - Ethernet + */ + u8 hssi_id:4; + u16 rsvd1:12; /* Reserved */ + /* Bitstream version patch number */ + u8 bs_verpatch:4; + /* Bitstream version minor number */ + u8 bs_verminor:4; + /* Bitstream version major number */ + u8 bs_vermajor:4; + /* Bitstream version debug number */ + u8 bs_verdebug:4; + }; + }; +}; + +struct feature_fme_bitstream_md { + union { + u64 csr; + struct { + /* Seed number userd for synthesis flow */ + u8 synth_seed:4; + /* Synthesis date(day number - 2 digits) */ + u8 synth_day:8; + /* Synthesis date(month number - 2 digits) */ + u8 synth_month:8; + /* Synthesis date(year number - 2 digits) */ + u8 synth_year:8; + u64 rsvd:36; /* Reserved */ + }; + }; +}; + +struct feature_fme_iommu_ctrl { + union { + u64 csr; + struct { + /* Disables IOMMU prefetcher for C0 channel */ + u8 prefetch_disableC0:1; + /* Disables IOMMU prefetcher for C1 channel */ + u8 prefetch_disableC1:1; + /* Disables IOMMU partial cache line writes */ + u8 prefetch_wrdisable:1; + u8 rsvd1:1; /* Reserved */ + /* + * Select counter and read value from register + * iommu_stat.dbg_counters + * 0 - Number of 4K page translation response + * 1 - Number of 2M page translation response + * 2 - Number of 1G page translation response + */ + u8 counter_sel:2; + u32 rsvd2:26; /* Reserved */ + /* Connected to IOMMU SIP Capabilities */ + u32 capecap_defeature; + }; + }; +}; + +struct feature_fme_iommu_stat { + union { + u64 csr; + struct { + /* Translation Enable bit from IOMMU SIP */ + u8 translation_enable:1; + /* Drain request in progress */ + u8 drain_req_inprog:1; + /* Invalidation current state */ + u8 inv_state:3; + /* C0 Response Buffer current state */ + u8 respbuffer_stateC0:3; + /* C1 Response Buffer current state */ + u8 respbuffer_stateC1:3; + /* Last request ID to IOMMU SIP */ + u8 last_reqID:4; + /* Last IOMMU SIP response ID value */ + u8 last_respID:4; + /* Last IOMMU SIP response status value */ + u8 last_respstatus:3; + /* C0 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC0:1; + /* C1 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC1:1; + /* C0 Request FIFO is not empty */ + u8 reqFIFO_notemptyC0:1; + /* C1 Request FIFO is not empty */ + u8 reqFIFO_notemptyC1:1; + /* C0 Response FIFO is not empty */ + u8 respFIFO_notemptyC0:1; + /* C1 Response FIFO is not empty */ + u8 respFIFO_notemptyC1:1; + /* C0 Response FIFO overflow detected */ + u8 respFIFO_overflowC0:1; + /* C1 Response FIFO overflow detected */ + u8 respFIFO_overflowC1:1; + /* C0 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC0:1; + /* C1 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC1:1; + /* Request FIFO overflow detected */ + u8 reqFIFO_overflow:1; + /* IOMMU memory read in progress */ + u8 memrd_inprog:1; + /* IOMMU memory write in progress */ + u8 memwr_inprog:1; + u8 rsvd1:1; /* Reserved */ + /* Value of counter selected by iommu_ctl.counter_sel */ + u16 dbg_counters:16; + u16 rsvd2:12; /* Reserved */ + }; + }; +}; + +struct feature_fme_pcie0_ctrl { + union { + u64 csr; + struct { + u64 vtd_bar_lock:1; /* Lock VT-D BAR register */ + u64 rsvd1:3; + u64 rciep:1; /* Configure PCIE0 as RCiEP */ + u64 rsvd2:59; + }; + }; +}; + +struct feature_fme_llpr_smrr_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR rule is valid or not */ + /* + * SMRR memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR2 rule is valid or not */ + /* + * SMRR2 memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_meseg_base { + union { + u64 csr; + struct { + /* A[45:19] of base address memory range */ + u64 me_base:27; + u64 rsvd:37; + }; + }; +}; + +struct feature_fme_llpr_meseg_limit { + union { + u64 csr; + struct { + /* A[45:19] of limit address memory range */ + u64 me_limit:27; + u64 rsvd1:4; + u64 enable:1; /* Enable LLPR MESEG rule */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 reserved; + u64 scratchpad; + struct feature_fme_capability capability; + struct feature_fme_port port[MAX_FPGA_PORT_NUM]; + struct feature_fme_fab_status fab_status; + struct feature_fme_bitstream_id bitstream_id; + struct feature_fme_bitstream_md bitstream_md; + struct feature_fme_genprotrange2_base genprotrange2_base; + struct feature_fme_genprotrange2_limit genprotrange2_limit; + struct feature_fme_dxe_lock dxe_lock; + struct feature_fme_iommu_ctrl iommu_ctrl; + struct feature_fme_iommu_stat iommu_stat; + struct feature_fme_pcie0_ctrl pcie0_control; + struct feature_fme_llpr_smrr_base smrr_base; + struct feature_fme_llpr_smrr_mask smrr_mask; + struct feature_fme_llpr_smrr2_base smrr2_base; + struct feature_fme_llpr_smrr2_mask smrr2_mask; + struct feature_fme_llpr_meseg_base meseg_base; + struct feature_fme_llpr_meseg_limit meseg_limit; +}; + +struct feature_port_capability { + union { + u64 csr; + struct { + u8 port_number:2; /* Port Number 0-3 */ + u8 rsvd1:6; /* Reserved */ + u16 mmio_size; /* User MMIO size in KB */ + u8 rsvd2; /* Reserved */ + u8 sp_intr_num:4; /* Supported interrupts num */ + u32 rsvd3:28; /* Reserved */ + }; + }; +}; + +struct feature_port_control { + union { + u64 csr; + struct { + u8 port_sftrst:1; /* Port Soft Reset */ + u8 rsvd1:1; /* Reserved */ + u8 latency_tolerance:1;/* '1' >= 40us, '0' < 40us */ + u8 rsvd2:1; /* Reserved */ + u8 port_sftrst_ack:1; /* HW ACK for Soft Reset */ + u64 rsvd3:59; /* Reserved */ + }; + }; +}; + +#define PORT_POWER_STATE_NORMAL 0 +#define PORT_POWER_STATE_AP1 1 +#define PORT_POWER_STATE_AP2 2 +#define PORT_POWER_STATE_AP6 6 + +struct feature_port_status { + union { + u64 csr; + struct { + u8 port_freeze:1; /* '1' - freezed '0' - normal */ + u8 rsvd1:7; /* Reserved */ + u8 power_state:4; /* Power State */ + u8 ap1_event:1; /* AP1 event was detected */ + u8 ap2_event:1; /* AP2 event was detected */ + u64 rsvd2:50; /* Reserved */ + }; + }; +}; + +/* Port Header Register Set */ +struct feature_port_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 port_mailbox; + u64 scratchpad; + struct feature_port_capability capability; + struct feature_port_control control; + struct feature_port_status status; + u64 rsvd2; + u64 user_clk_freq_cmd0; + u64 user_clk_freq_cmd1; + u64 user_clk_freq_sts0; + u64 user_clk_freq_sts1; +}; + +struct feature_fme_tmp_threshold { + union { + u64 csr; + struct { + u8 tmp_thshold1:7; /* temperature Threshold 1 */ + /* temperature Threshold 1 enable/disable */ + u8 tmp_thshold1_enable:1; + u8 tmp_thshold2:7; /* temperature Threshold 2 */ + /* temperature Threshold 2 enable /disable */ + u8 tmp_thshold2_enable:1; + u8 pro_hot_setpoint:7; /* Proc Hot set point */ + u8 rsvd4:1; /* Reserved */ + u8 therm_trip_thshold:7; /* Thermeal Trip Threshold */ + u8 rsvd3:1; /* Reserved */ + u8 thshold1_status:1; /* Threshold 1 Status */ + u8 thshold2_status:1; /* Threshold 2 Status */ + u8 rsvd5:1; /* Reserved */ + /* Thermeal Trip Threshold status */ + u8 therm_trip_thshold_status:1; + u8 rsvd6:4; /* Reserved */ + /* Validation mode- Force Proc Hot */ + u8 valmodeforce:1; + /* Validation mode - Therm trip Hot */ + u8 valmodetherm:1; + u8 rsvd2:2; /* Reserved */ + u8 thshold_policy:1; /* threshold policy */ + u32 rsvd:19; /* Reserved */ + }; + }; +}; + +/* Temperature Sensor Read values format 1 */ +struct feature_fme_temp_rdsensor_fmt1 { + union { + u64 csr; + struct { + /* Reads out FPGA temperature in celsius */ + u8 fpga_temp:7; + u8 rsvd0:1; /* Reserved */ + /* Temperature reading sequence number */ + u16 tmp_reading_seq_num; + /* Temperature reading is valid */ + u8 tmp_reading_valid:1; + u8 rsvd1:7; /* Reserved */ + u16 dbg_mode:10; /* Debug mode */ + u32 rsvd2:22; /* Reserved */ + }; + }; +}; + +/* Temperature sensor read values format 2 */ +struct feature_fme_temp_rdsensor_fmt2 { + u64 rsvd; /* Reserved */ +}; + +/* Temperature Threshold Capability Register */ +struct feature_fme_tmp_threshold_cap { + union { + u64 csr; + struct { + /* Temperature Threshold Unsupported */ + u8 tmp_thshold_disabled:1; + u64 rsvd:63; /* Reserved */ + }; + }; +}; + +/* FME THERNAL FEATURE */ +struct feature_fme_thermal { + struct feature_header header; + struct feature_fme_tmp_threshold threshold; + struct feature_fme_temp_rdsensor_fmt1 rdsensor_fm1; + struct feature_fme_temp_rdsensor_fmt2 rdsensor_fm2; + struct feature_fme_tmp_threshold_cap threshold_cap; +}; + +/* Power Status register */ +struct feature_fme_pm_status { + union { + u64 csr; + struct { + /* FPGA Power consumed, The format is to be defined */ + u32 pwr_consumed:18; + /* FPGA Latency Tolerance Reporting */ + u8 fpga_latency_report:1; + u64 rsvd:45; /* Reserved */ + }; + }; +}; + +/* AP Thresholds */ +struct feature_fme_pm_ap_threshold { + union { + u64 csr; + struct { + /* + * Number of clocks (5ns period) for assertion + * of FME_data + */ + u8 threshold1:7; + u8 rsvd1:1; + u8 threshold2:7; + u8 rsvd2:1; + u8 threshold1_status:1; + u8 threshold2_status:1; + u64 rsvd3:46; /* Reserved */ + }; + }; +}; + +/* Xeon Power Limit */ +struct feature_fme_pm_xeon_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FPGA Power Limit */ +struct feature_fme_pm_fpga_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FME POWER FEATURE */ +struct feature_fme_power { + struct feature_header header; + struct feature_fme_pm_status status; + struct feature_fme_pm_ap_threshold threshold; + struct feature_fme_pm_xeon_limit xeon_limit; + struct feature_fme_pm_fpga_limit fpga_limit; +}; + +#define CACHE_CHANNEL_RD 0 +#define CACHE_CHANNEL_WR 1 + +enum iperf_cache_events { + IPERF_CACHE_RD_HIT, + IPERF_CACHE_WR_HIT, + IPERF_CACHE_RD_MISS, + IPERF_CACHE_WR_MISS, + IPERF_CACHE_RSVD, /* reserved */ + IPERF_CACHE_HOLD_REQ, + IPERF_CACHE_DATA_WR_PORT_CONTEN, + IPERF_CACHE_TAG_WR_PORT_CONTEN, + IPERF_CACHE_TX_REQ_STALL, + IPERF_CACHE_RX_REQ_STALL, + IPERF_CACHE_EVICTIONS, +}; + +/* FPMON Cache Control */ +struct feature_fme_ifpmon_ch_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd1:7; /* Reserved */ + u8 freeze:1; /* Freeze if set to 1 */ + u8 rsvd2:7; /* Reserved */ + u8 cache_event:4; /* Select the cache event */ + u8 cci_chsel:1; /* Select the channel */ + u64 rsvd3:43; /* Reserved */ + }; + }; +}; + +/* FPMON Cache Counter */ +struct feature_fme_ifpmon_ch_ctr { + union { + u64 csr; + struct { + /* Cache Counter for even addresse */ + u64 cache_counter:48; + u16 rsvd:12; /* Reserved */ + /* Cache Event being reported */ + u8 event_code:4; + }; + }; +}; + +enum iperf_fab_events { + IPERF_FAB_PCIE0_RD, + IPERF_FAB_PCIE0_WR, + IPERF_FAB_PCIE1_RD, + IPERF_FAB_PCIE1_WR, + IPERF_FAB_UPI_RD, + IPERF_FAB_UPI_WR, + IPERF_FAB_MMIO_RD, + IPERF_FAB_MMIO_WR, +}; + +#define FAB_DISABLE_FILTER 0 +#define FAB_ENABLE_FILTER 1 + +/* FPMON FAB Control */ +struct feature_fme_ifpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_ifpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_ifpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +enum iperf_vtd_events { + IPERF_VTD_AFU_MEM_RD_TRANS, + IPERF_VTD_AFU_MEM_WR_TRANS, + IPERF_VTD_AFU_DEVTLB_RD_HIT, + IPERF_VTD_AFU_DEVTLB_WR_HIT, + IPERF_VTD_DEVTLB_4K_FILL, + IPERF_VTD_DEVTLB_2M_FILL, + IPERF_VTD_DEVTLB_1G_FILL, +}; + +/* VT-d control register */ +struct feature_fme_ifpmon_vtd_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d event counter */ +struct feature_fme_ifpmon_vtd_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +enum iperf_vtd_sip_events { + IPERF_VTD_SIP_IOTLB_4K_HIT, + IPERF_VTD_SIP_IOTLB_2M_HIT, + IPERF_VTD_SIP_IOTLB_1G_HIT, + IPERF_VTD_SIP_SLPWC_L3_HIT, + IPERF_VTD_SIP_SLPWC_L4_HIT, + IPERF_VTD_SIP_RCC_HIT, + IPERF_VTD_SIP_IOTLB_4K_MISS, + IPERF_VTD_SIP_IOTLB_2M_MISS, + IPERF_VTD_SIP_IOTLB_1G_MISS, + IPERF_VTD_SIP_SLPWC_L3_MISS, + IPERF_VTD_SIP_SLPWC_L4_MISS, + IPERF_VTD_SIP_RCC_MISS, +}; + +/* VT-d SIP control register */ +struct feature_fme_ifpmon_vtd_sip_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d SIP event counter */ +struct feature_fme_ifpmon_vtd_sip_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +/* FME IPERF FEATURE */ +struct feature_fme_iperf { + struct feature_header header; + struct feature_fme_ifpmon_ch_ctl ch_ctl; + struct feature_fme_ifpmon_ch_ctr ch_ctr0; + struct feature_fme_ifpmon_ch_ctr ch_ctr1; + struct feature_fme_ifpmon_fab_ctl fab_ctl; + struct feature_fme_ifpmon_fab_ctr fab_ctr; + struct feature_fme_ifpmon_clk_ctr clk; + struct feature_fme_ifpmon_vtd_ctl vtd_ctl; + struct feature_fme_ifpmon_vtd_ctr vtd_ctr; + struct feature_fme_ifpmon_vtd_sip_ctl vtd_sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr vtd_sip_ctr; +}; + +enum dperf_fab_events { + DPERF_FAB_PCIE0_RD, + DPERF_FAB_PCIE0_WR, + DPERF_FAB_MMIO_RD = 6, + DPERF_FAB_MMIO_WR, +}; + +/* FPMON FAB Control */ +struct feature_fme_dfpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_dfpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_dfpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +/* FME DPERF FEATURE */ +struct feature_fme_dperf { + struct feature_header header; + u64 rsvd[3]; + struct feature_fme_dfpmon_fab_ctl fab_ctl; + struct feature_fme_dfpmon_fab_ctr fab_ctr; + struct feature_fme_dfpmon_clk_ctr clk; +}; + +struct feature_fme_error0 { +#define FME_ERROR0_MASK 0xFFUL +#define FME_ERROR0_MASK_DEFAULT 0x40UL /* pcode workaround */ + union { + u64 csr; + struct { + u8 fabric_err:1; /* Fabric error */ + u8 fabfifo_overflow:1; /* Fabric fifo overflow */ + u8 kticdc_parity_err:2;/* KTI CDC Parity Error */ + u8 iommu_parity_err:1; /* IOMMU Parity error */ + /* AFU PF/VF access mismatch detected */ + u8 afu_acc_mode_err:1; + u8 mbp_err:1; /* Indicates an MBP event */ + /* PCIE0 CDC Parity Error */ + u8 pcie0cdc_parity_err:5; + /* PCIE1 CDC Parity Error */ + u8 pcie1cdc_parity_err:5; + /* CVL CDC Parity Error */ + u8 cvlcdc_parity_err:3; + u64 rsvd:44; /* Reserved */ + }; + }; +}; + +/* PCIe0 Error Status register */ +struct feature_fme_pcie0_error { +#define FME_PCIE0_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:52; /* Reserved */ + u8 vfnumb_err:1; /* Number of error VF */ + u8 funct_type_err:1; /* Virtual (1) or Physical */ + }; + }; +}; + +/* PCIe1 Error Status register */ +struct feature_fme_pcie1_error { +#define FME_PCIE1_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:54; /* Reserved */ + }; + }; +}; + +/* FME First Error register */ +struct feature_fme_first_error { +#define FME_FIRST_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered first + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered first + */ + u8 errReg_id:4; + }; + }; +}; + +/* FME Next Error register */ +struct feature_fme_next_error { +#define FME_NEXT_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered second + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered second + */ + u8 errReg_id:4; + }; + }; +}; + +/* RAS Non Fatal Error Status register */ +struct feature_fme_ras_nonfaterror { + union { + u64 csr; + struct { + /* thremal threshold AP1 */ + u8 temp_thresh_ap1:1; + /* thremal threshold AP2 */ + u8 temp_thresh_ap2:1; + u8 pcie_error:1; /* pcie Error */ + u8 portfatal_error:1; /* port fatal error */ + u8 proc_hot:1; /* Indicates a ProcHot event */ + /* Indicates an AFU PF/VF access mismatch */ + u8 afu_acc_mode_err:1; + /* Injected nonfata Error */ + u8 injected_nonfata_err:1; + u8 rsvd1:2; + /* Temperature threshold triggered AP6*/ + u8 temp_thresh_AP6:1; + /* Power threshold triggered AP1 */ + u8 power_thresh_AP1:1; + /* Power threshold triggered AP2 */ + u8 power_thresh_AP2:1; + /* Indicates a MBP event */ + u8 mbp_err:1; + u64 rsvd2:51; /* Reserved */ + }; + }; +}; + +/* RAS Catastrophic Fatal Error Status register */ +struct feature_fme_ras_catfaterror { + union { + u64 csr; + struct { + /* KTI Link layer error detected */ + u8 ktilink_fatal_err:1; + /* tag-n-cache error detected */ + u8 tagcch_fatal_err:1; + /* CCI error detected */ + u8 cci_fatal_err:1; + /* KTI Protocol error detected */ + u8 ktiprpto_fatal_err:1; + /* Fatal DRAM error detected */ + u8 dram_fatal_err:1; + /* IOMMU detected */ + u8 iommu_fatal_err:1; + /* Fabric Fatal Error */ + u8 fabric_fatal_err:1; + /* PCIe possion Error */ + u8 pcie_poison_err:1; + /* Injected fatal Error */ + u8 inject_fata_err:1; + /* Catastrophic CRC Error */ + u8 crc_catast_err:1; + /* Catastrophic Thermal Error */ + u8 therm_catast_err:1; + /* Injected Catastrophic Error */ + u8 injected_catast_err:1; + u64 rsvd:52; + }; + }; +}; + +/* RAS Error injection register */ +struct feature_fme_ras_error_inj { +#define FME_RAS_ERROR_INJ_MASK 0x7UL + union { + u64 csr; + struct { + u8 catast_error:1; /* Catastrophic error flag */ + u8 fatal_error:1; /* Fatal error flag */ + u8 nonfatal_error:1; /* NonFatal error flag */ + u64 rsvd:61; /* Reserved */ + }; + }; +}; + +/* FME error capabilities */ +struct feature_fme_error_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* FME ERR FEATURE */ +struct feature_fme_err { + struct feature_header header; + struct feature_fme_error0 fme_err_mask; + struct feature_fme_error0 fme_err; + struct feature_fme_pcie0_error pcie0_err_mask; + struct feature_fme_pcie0_error pcie0_err; + struct feature_fme_pcie1_error pcie1_err_mask; + struct feature_fme_pcie1_error pcie1_err; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + struct feature_fme_ras_nonfaterror ras_nonfat_mask; + struct feature_fme_ras_nonfaterror ras_nonfaterr; + struct feature_fme_ras_catfaterror ras_catfat_mask; + struct feature_fme_ras_catfaterror ras_catfaterr; + struct feature_fme_ras_error_inj ras_error_inj; + struct feature_fme_error_capability fme_err_capability; +}; + +/* FME Partial Reconfiguration Control */ +struct feature_fme_pr_ctl { + union { + u64 csr; + struct { + u8 pr_reset:1; /* Reset PR Engine */ + u8 rsvd3:3; /* Reserved */ + u8 pr_reset_ack:1; /* Reset PR Engine Ack */ + u8 rsvd4:3; /* Reserved */ + u8 pr_regionid:2; /* PR Region ID */ + u8 rsvd1:2; /* Reserved */ + u8 pr_start_req:1; /* PR Start Request */ + u8 pr_push_complete:1; /* PR Data push complete */ + u8 pr_kind:1; /* PR Data push complete */ + u32 rsvd:17; /* Reserved */ + u32 config_data; /* Config data TBD */ + }; + }; +}; + +/* FME Partial Reconfiguration Status */ +struct feature_fme_pr_status { + union { + u64 csr; + struct { + u16 pr_credit:9; /* PR Credits */ + u8 rsvd2:7; /* Reserved */ + u8 pr_status:1; /* PR status */ + u8 rsvd:3; /* Reserved */ + /* Altra PR Controller Block status */ + u8 pr_controller_status:3; + u8 rsvd1:1; /* Reserved */ + u8 pr_host_status:4; /* PR Host status */ + u8 rsvd3:4; /* Reserved */ + /* Security Block Status fields (TBD) */ + u32 security_bstatus; + }; + }; +}; + +/* FME Partial Reconfiguration Data */ +struct feature_fme_pr_data { + union { + u64 csr; /* PR data from the raw-binary file */ + struct { + /* PR data from the raw-binary file */ + u32 pr_data_raw; + u32 rsvd; + }; + }; +}; + +/* FME PR Public Key */ +struct feature_fme_pr_key { + u64 key; /* FME PR Public Hash */ +}; + +/* FME PR FEATURE */ +struct feature_fme_pr { + struct feature_header header; + /*Partial Reconfiguration control */ + struct feature_fme_pr_ctl ccip_fme_pr_control; + + /* Partial Reconfiguration Status */ + struct feature_fme_pr_status ccip_fme_pr_status; + + /* Partial Reconfiguration data */ + struct feature_fme_pr_data ccip_fme_pr_data; + + /* Partial Reconfiguration data */ + u64 ccip_fme_pr_err; + + u64 rsvd1[3]; + + /* Partial Reconfiguration data registers */ + u64 fme_pr_data1; + u64 fme_pr_data2; + u64 fme_pr_data3; + u64 fme_pr_data4; + u64 fme_pr_data5; + u64 fme_pr_data6; + u64 fme_pr_data7; + u64 fme_pr_data8; + + u64 rsvd2[5]; + + /* PR Interface ID */ + u64 fme_pr_intfc_id_l; + u64 fme_pr_intfc_id_h; + + /* MSIX filed to be Added */ +}; + +/* FME HSSI Control */ +struct feature_fme_hssi_eth_ctrl { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u16 address:16; /* HSSI address */ + /* + * HSSI comamnd + * 0x0 - No request + * 0x08 - SW register RD request + * 0x10 - SW register WR request + * 0x40 - Auxiliar bus RD request + * 0x80 - Auxiliar bus WR request + */ + u16 cmd:16; + }; + }; +}; + +/* FME HSSI Status */ +struct feature_fme_hssi_eth_stat { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u8 acknowledge:1; /* HSSI acknowledge */ + u8 spare:1; /* HSSI spare */ + u32 rsvd:30; /* Reserved */ + }; + }; +}; + +/* FME HSSI FEATURE */ +struct feature_fme_hssi { + struct feature_header header; + struct feature_fme_hssi_eth_ctrl hssi_control; + struct feature_fme_hssi_eth_stat hssi_status; +}; + +#define PORT_ERR_MASK 0xfff0703ff001f +struct feature_port_err_key { + union { + u64 csr; + struct { + /* Tx Channel0: Overflow */ + u8 tx_ch0_overflow:1; + /* Tx Channel0: Invalid request encoding */ + u8 tx_ch0_invaldreq :1; + /* Tx Channel0: Request with cl_len=3 not supported */ + u8 tx_ch0_cl_len3:1; + /* Tx Channel0: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch0_cl_len2:1; + /* Tx Channel0: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch0_cl_len4:1; + + u16 rsvd1:4; /* Reserved */ + + /* AFU MMIO RD received while PORT is in reset */ + u8 mmio_rd_whilerst:1; + /* AFU MMIO WR received while PORT is in reset */ + u8 mmio_wr_whilerst:1; + + u16 rsvd2:5; /* Reserved */ + + /* Tx Channel1: Overflow */ + u8 tx_ch1_overflow:1; + /* Tx Channel1: Invalid request encoding */ + u8 tx_ch1_invaldreq:1; + /* Tx Channel1: Request with cl_len=3 not supported */ + u8 tx_ch1_cl_len3:1; + /* Tx Channel1: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch1_cl_len2:1; + /* Tx Channel1: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch1_cl_len4:1; + + /* Tx Channel1: Insufficient data payload */ + u8 tx_ch1_insuff_data:1; + /* Tx Channel1: Data payload overrun */ + u8 tx_ch1_data_overrun:1; + /* Tx Channel1 : Incorrect address */ + u8 tx_ch1_incorr_addr:1; + /* Tx Channel1 : NON-Zero SOP Detected */ + u8 tx_ch1_nzsop:1; + /* Tx Channel1 : Illegal VC_SEL, atomic request VLO */ + u8 tx_ch1_illegal_vcsel:1; + + u8 rsvd3:6; /* Reserved */ + + /* MMIO Read Timeout in AFU */ + u8 mmioread_timeout:1; + + /* Tx Channel2: FIFO Overflow */ + u8 tx_ch2_fifo_overflow:1; + + /* MMIO read is not matching pending request */ + u8 unexp_mmio_resp:1; + + u8 rsvd4:5; /* Reserved */ + + /* Number of pending Requests: counter overflow */ + u8 tx_req_counter_overflow:1; + /* Req with Address violating SMM Range */ + u8 llpr_smrr_err:1; + /* Req with Address violating second SMM Range */ + u8 llpr_smrr2_err:1; + /* Req with Address violating ME Stolen message */ + u8 llpr_mesg_err:1; + /* Req with Address violating Generic Protected Range */ + u8 genprot_range_err:1; + /* Req with Address violating Legacy Range low */ + u8 legrange_low_err:1; + /* Req with Address violating Legacy Range High */ + u8 legrange_high_err:1; + /* Req with Address violating VGA memory range */ + u8 vgmem_range_err:1; + u8 page_fault_err:1; /* Page fault */ + u8 pmr_err:1; /* PMR Error */ + u8 ap6_event:1; /* AP6 event */ + /* VF FLR detected on Port with PF access control */ + u8 vfflr_access_err:1; + u16 rsvd5:12; /* Reserved */ + }; + }; +}; + +/* Port first error register, not contain all error bits in error register. */ +struct feature_port_first_err_key { + union { + u64 csr; + struct { + u8 tx_ch0_overflow:1; + u8 tx_ch0_invaldreq :1; + u8 tx_ch0_cl_len3:1; + u8 tx_ch0_cl_len2:1; + u8 tx_ch0_cl_len4:1; + u8 rsvd1:4; /* Reserved */ + u8 mmio_rd_whilerst:1; + u8 mmio_wr_whilerst:1; + u8 rsvd2:5; /* Reserved */ + u8 tx_ch1_overflow:1; + u8 tx_ch1_invaldreq:1; + u8 tx_ch1_cl_len3:1; + u8 tx_ch1_cl_len2:1; + u8 tx_ch1_cl_len4:1; + u8 tx_ch1_insuff_data:1; + u8 tx_ch1_data_overrun:1; + u8 tx_ch1_incorr_addr:1; + u8 tx_ch1_nzsop:1; + u8 tx_ch1_illegal_vcsel:1; + u8 rsvd3:6; /* Reserved */ + u8 mmioread_timeout:1; + u8 tx_ch2_fifo_overflow:1; + u8 rsvd4:6; /* Reserved */ + u8 tx_req_counter_overflow:1; + u32 rsvd5:23; /* Reserved */ + }; + }; +}; + +/* Port malformed Req0 */ +struct feature_port_malformed_req0 { + u64 header_lsb; +}; + +/* Port malformed Req1 */ +struct feature_port_malformed_req1 { + u64 header_msb; +}; + +/* Port debug register */ +struct feature_port_debug { + u64 port_debug; +}; + +/* Port error capabilities */ +struct feature_port_err_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE ERROR */ +struct feature_port_error { + struct feature_header header; + struct feature_port_err_key error_mask; + struct feature_port_err_key port_error; + struct feature_port_first_err_key port_first_error; + struct feature_port_malformed_req0 malreq0; + struct feature_port_malformed_req1 malreq1; + struct feature_port_debug port_debug; + struct feature_port_err_capability error_capability; +}; + +/* Port UMSG Capability */ +struct feature_port_umsg_cap { + union { + u64 csr; + struct { + /* Number of umsg allocated to this port */ + u8 umsg_allocated; + /* Enable / Disable UMsg engine for this port */ + u8 umsg_enable:1; + /* Usmg initialization status */ + u8 umsg_init_complete:1; + /* IOMMU can not translate the umsg base address */ + u8 umsg_trans_error:1; + u64 rsvd:53; /* Reserved */ + }; + }; +}; + +/* Port UMSG base address */ +struct feature_port_umsg_baseaddr { + union { + u64 csr; + struct { + u64 base_addr:48; /* 48 bit physical address */ + u16 rsvd; /* Reserved */ + }; + }; +}; + +struct feature_port_umsg_mode { + union { + u64 csr; + struct { + u32 umsg_hint_enable; /* UMSG hint enable/disable */ + u32 rsvd; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE UMSG */ +struct feature_port_umsg { + struct feature_header header; + struct feature_port_umsg_cap capability; + struct feature_port_umsg_baseaddr baseaddr; + struct feature_port_umsg_mode mode; +}; + +#define UMSG_EN_POLL_INVL 10 /* us */ +#define UMSG_EN_POLL_TIMEOUT 1000 /* us */ + +/* Port UINT Capability */ +struct feature_port_uint_cap { + union { + u64 csr; + struct { + u16 intr_num:12; /* Supported interrupts num */ + /* First MSI-X vector table entry number */ + u16 first_vec_num:12; + u64 rsvd:40; + }; + }; +}; + +/* PORT FEATURE UINT */ +struct feature_port_uint { + struct feature_header header; + struct feature_port_uint_cap capability; +}; + +/* STP region supports mmap operation, so use page aligned size. */ +#define PORT_FEATURE_STP_REGION_SIZE PAGE_ALIGN(sizeof(struct feature_port_stp)) + +/* Port STP status register (for debug only)*/ +struct feature_port_stp_status { + union { + u64 csr; + struct { + /* SLD Hub end-point read/write timeout */ + u8 sld_ep_timeout:1; + /* Remote STP in reset/disable */ + u8 rstp_disabled:1; + u8 unsupported_read:1; + /* MMIO timeout detected and faked with a response */ + u8 mmio_timeout:1; + u8 txfifo_count:4; + u8 rxfifo_count:4; + u8 txfifo_overflow:1; + u8 txfifo_underflow:1; + u8 rxfifo_overflow:1; + u8 rxfifo_underflow:1; + /* Number of MMIO write requests */ + u16 write_requests; + /* Number of MMIO read requests */ + u16 read_requests; + /* Number of MMIO read responses */ + u16 read_responses; + }; + }; +}; + +/* + * PORT FEATURE STP + * Most registers in STP region are not touched by driver, but mmapped to user + * space. So they are not defined in below data structure, as its actual size + * is 0x18c per spec. + */ +struct feature_port_stp { + struct feature_header header; + struct feature_port_stp_status stp_status; +}; + +/** + * enum fpga_pr_states - fpga PR states + * @FPGA_PR_STATE_UNKNOWN: can't determine state + * @FPGA_PR_STATE_WRITE_INIT: preparing FPGA for programming + * @FPGA_PR_STATE_WRITE_INIT_ERR: Error during WRITE_INIT stage + * @FPGA_PR_STATE_WRITE: writing image to FPGA + * @FPGA_PR_STATE_WRITE_ERR: Error while writing FPGA + * @FPGA_PR_STATE_WRITE_COMPLETE: Doing post programming steps + * @FPGA_PR_STATE_WRITE_COMPLETE_ERR: Error during WRITE_COMPLETE + * @FPGA_PR_STATE_OPERATING: FPGA PR done + */ +enum fpga_pr_states { + /* canot determine state states */ + FPGA_PR_STATE_UNKNOWN, + + /* write sequence: init, write, complete */ + FPGA_PR_STATE_WRITE_INIT, + FPGA_PR_STATE_WRITE_INIT_ERR, + FPGA_PR_STATE_WRITE, + FPGA_PR_STATE_WRITE_ERR, + FPGA_PR_STATE_WRITE_COMPLETE, + FPGA_PR_STATE_WRITE_COMPLETE_ERR, + + /* FPGA PR done */ + FPGA_PR_STATE_DONE, +}; + +/* + * FPGA Manager flags + * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported + */ +#define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + +/** + * struct fpga_pr_info - specific information to a FPGA PR + * @flags: boolean flags as defined above + * @pr_err: PR error code + * @state: fpga manager state + * @port_id: port id + */ +struct fpga_pr_info { + u32 flags; + u64 pr_err; + enum fpga_pr_states state; + int port_id; +}; + +#define DEFINE_FPGA_PR_ERR_MSG(_name_) \ +static const char * const _name_[] = { \ + "PR operation error detected", \ + "PR CRC error detected", \ + "PR incompatiable bitstream error detected", \ + "PR IP protocol error detected", \ + "PR FIFO overflow error detected", \ + "PR timeout error detected", \ + "PR secure load error detected", \ +} + +#define RST_POLL_INVL 10 /* us */ +#define RST_POLL_TIMEOUT 1000 /* us */ + +#define PR_WAIT_TIMEOUT 15000000 + +#define PR_HOST_STATUS_IDLE 0 +#define PR_MAX_ERR_NUM 7 + +DEFINE_FPGA_PR_ERR_MSG(pr_err_msg); + +/* + * green bitstream header must be byte-packed to match the + * real file format. + */ +struct bts_header { + u64 guid_h; + u64 guid_l; + u32 metadata_len; +}; + +#define GBS_GUID_H 0x414750466e6f6558 +#define GBS_GUID_L 0x31303076534247b7 +#define is_valid_bts(bts_hdr) \ + (((bts_hdr)->guid_h == GBS_GUID_H) && \ + ((bts_hdr)->guid_l == GBS_GUID_L)) + +#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 new file mode 100644 index 0000000..10a8f06 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -0,0 +1,824 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_hw_api.h" +#include "ifpga_api.h" + +#include "ifpga_hw.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +struct build_feature_devs_info { + struct opae_adapter_data_pci *pci_data; + + struct ifpga_afu_info *acc_info; + + void *fiu; + enum fpga_id_type current_type; + int current_port_id; + + void *ioaddr; + void *ioend; + uint64_t phys_addr; + int current_bar; + + void *pfme_hdr; + + struct ifpga_hw *hw; +}; + +struct feature_info { + const char *name; + uint32_t resource_size; + int feature_index; + int revision_id; + unsigned int vec_start; + unsigned int vec_cnt; + + struct feature_ops *ops; +}; + +/* 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, + } +}; + +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 = &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 = &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 = &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 = &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 + }, +}; + +static u64 feature_id(void __iomem *start) +{ + struct feature_header header; + + header.csr = readq(start); + + switch (header.type) { + case FEATURE_TYPE_FIU: + return FEATURE_ID_HEADER; + case FEATURE_TYPE_PRIVATE: + return header.id; + case FEATURE_TYPE_AFU: + return FEATURE_ID_AFU; + } + + WARN_ON(1); + return 0; +} + +static int +build_info_add_sub_feature(struct build_feature_devs_info *binfo, + struct feature_info *finfo, void __iomem *start) +{ + 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; + } + + 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->phys_addr = binfo->phys_addr + + ((u8 *)start - (u8 *)binfo->ioaddr); + + if (vec_cnt) { + if (vec_start + vec_cnt <= vec_start) + return -EINVAL; + + ctx = zmalloc(sizeof(*ctx) * vec_cnt); + if (!ctx) + return -ENOMEM; + + for (i = 0; i < vec_cnt; i++) { + ctx[i].eventfd = -1; + ctx[i].idx = vec_start + i; + } + } + + feature->ctx = ctx; + feature->ctx_num = vec_cnt; + feature->vfio_dev_fd = binfo->pci_data->vfio_dev_fd; + + return ret; +} + +static int +create_feature_instance(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + struct feature_header *hdr = start; + + if (((u8 *)binfo->ioend - (u8 *)start) < finfo->resource_size) + return -EINVAL; + + 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); +} + +/* + * UAFU GUID is dynamic as it can be changed after FME downloads different + * Green Bitstream to the port, so we treat the unknown GUIDs which are + * attached on port's feature list as UAFU. + */ +static bool feature_is_UAFU(struct build_feature_devs_info *binfo) +{ + if (binfo->current_type != PORT_ID) + return false; + + return true; +} + +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; + struct ifpga_afu_info *info; + void *start = (void *)hdr; + int ret; + + 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; + } + + if (ret) + return ret; + + /* FIXME: need to figure out a better name */ + info = 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->num_regions = 1; + + binfo->acc_info = info; + + return ret; +} + +static int parse_feature_afus(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + int ret; + struct feature_afu_header *afu_hdr, header; + u8 __iomem *start; + u8 __iomem *end = binfo->ioend; + + start = (u8 __iomem *)hdr; + for (; start < end; start += header.next_afu) { + if (end - start < + (unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr))) + return -EINVAL; + + hdr = (struct feature_header *)start; + afu_hdr = (struct feature_afu_header *)(hdr + 1); + header.csr = readq(&afu_hdr->csr); + + if (feature_is_UAFU(binfo)) { + ret = parse_feature_port_uafu(binfo, hdr); + if (ret) + return ret; + } + + if (!header.next_afu) + break; + } + + return 0; +} + +/* create and register proper private data */ +static int build_info_commit_dev(struct build_feature_devs_info *binfo) +{ + struct ifpga_afu_info *info = binfo->acc_info; + struct ifpga_hw *hw = binfo->hw; + struct opae_manager *mgr; + struct opae_bridge *br; + struct opae_accelerator *acc; + + if (!binfo->fiu) + return 0; + + if (binfo->current_type == PORT_ID) { + /* return error if no valid acc info data structure */ + if (!info) + return -EFAULT; + + br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops, + binfo->fiu); + if (!br) + return -ENOMEM; + + br->id = binfo->current_port_id; + + /* update irq info */ + info->num_irqs = port_features[PORT_FEATURE_ID_UINT].vec_cnt; + + acc = opae_accelerator_alloc(hw->adapter->name, + &ifpga_acc_ops, info); + if (!acc) { + opae_bridge_free(br); + return -ENOMEM; + } + + acc->br = br; + acc->index = br->id; + + opae_adapter_add_acc(hw->adapter, acc); + + } else if (binfo->current_type == FME_ID) { + mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops, + binfo->fiu); + if (!mgr) + return -ENOMEM; + + mgr->adapter = hw->adapter; + hw->adapter->mgr = mgr; + } + + binfo->fiu = NULL; + + return 0; +} + +static int +build_info_create_dev(struct build_feature_devs_info *binfo, + enum fpga_id_type type, unsigned int index) +{ + int ret; + + ret = build_info_commit_dev(binfo); + if (ret) + return ret; + + binfo->current_type = type; + + if (type == FME_ID) { + binfo->fiu = &binfo->hw->fme; + } else if (type == PORT_ID) { + binfo->fiu = &binfo->hw->port[index]; + binfo->current_port_id = index; + } + + return 0; +} + +static int parse_feature_fme(struct build_feature_devs_info *binfo, + struct feature_header *start) +{ + struct ifpga_hw *hw = binfo->hw; + struct ifpga_fme_hw *fme = &hw->fme; + int ret; + + ret = build_info_create_dev(binfo, FME_ID, 0); + if (ret) + return ret; + + /* Update FME states */ + fme->state = IFPGA_FME_IMPLEMENTED; + fme->parent = hw; + spinlock_init(&fme->lock); + + return create_feature_instance(binfo, start, + &fme_features[FME_FEATURE_ID_HEADER]); +} + +static int parse_feature_port(struct build_feature_devs_info *binfo, + void __iomem *start) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + struct ifpga_hw *hw = binfo->hw; + struct ifpga_port_hw *port; + unsigned int port_id; + int ret; + + /* Get current port's id */ + port_hdr = (struct feature_port_header *)start; + capability.csr = readq(&port_hdr->capability); + port_id = capability.port_number; + + ret = build_info_create_dev(binfo, PORT_ID, port_id); + if (ret) + return ret; + + /*found a Port device*/ + port = &hw->port[port_id]; + port->port_id = binfo->current_port_id; + port->parent = hw; + port->state = IFPGA_PORT_ATTACHED; + spinlock_init(&port->lock); + + return create_feature_instance(binfo, start, + &port_features[PORT_FEATURE_ID_HEADER]); +} + +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); +} + +static int parse_feature_fiu(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + struct feature_fiu_header *fiu_hdr, fiu_header; + u8 __iomem *start = (u8 __iomem *)hdr; + int ret; + + header.csr = readq(hdr); + + switch (header.id) { + case FEATURE_FIU_ID_FME: + ret = parse_feature_fme(binfo, hdr); + binfo->pfme_hdr = hdr; + if (ret) + return ret; + break; + case FEATURE_FIU_ID_PORT: + ret = parse_feature_port(binfo, hdr); + enable_port_uafu(binfo, hdr); + if (ret) + return ret; + + /* Check Port FIU's next_afu pointer to User AFU DFH */ + fiu_hdr = (struct feature_fiu_header *)(hdr + 1); + fiu_header.csr = readq(&fiu_hdr->csr); + + if (fiu_header.next_afu) { + start += fiu_header.next_afu; + ret = parse_feature_afus(binfo, + (struct feature_header *)start); + if (ret) + return ret; + } else { + dev_info(binfo, "No AFUs detected on Port\n"); + } + + break; + default: + dev_info(binfo, "FIU TYPE %d is not supported yet.\n", + header.id); + } + + return 0; +} + +static void parse_feature_irqs(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + finfo->vec_start = 0; + finfo->vec_cnt = 0; + + UNUSED(binfo); + + if (!strcmp(finfo->name, PORT_FEATURE_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; + } else { + dev_debug(binfo, "UAFU doesn't support interrupt\n"); + } + } else if (!strcmp(finfo->name, PORT_FEATURE_ERR)) { + 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; + } else { + dev_debug(&binfo, "Port error doesn't support interrupt\n"); + } + + } else if (!strcmp(finfo->name, FME_FEATURE_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; + } else { + dev_debug(&binfo, "FME error doesn't support interrupt\n"); + } + } +} + +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; + } + + parse_feature_irqs(binfo, hdr, &fme_features[header.id]); + + return create_feature_instance(binfo, hdr, &fme_features[header.id]); +} + +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; + + 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]); + + return create_feature_instance(binfo, hdr, &port_features[id]); +} + +static int parse_feature_private(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + + header.csr = readq(hdr); + + switch (binfo->current_type) { + case FME_ID: + return parse_feature_fme_private(binfo, hdr); + case PORT_ID: + return parse_feature_port_private(binfo, hdr); + default: + dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n", + header.id, binfo->current_type); + } + return 0; +} + +static int parse_feature(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + int ret = 0; + + header.csr = readq(hdr); + + switch (header.type) { + case FEATURE_TYPE_AFU: + ret = parse_feature_afus(binfo, hdr); + break; + case FEATURE_TYPE_PRIVATE: + ret = parse_feature_private(binfo, hdr); + break; + case FEATURE_TYPE_FIU: + ret = parse_feature_fiu(binfo, hdr); + break; + default: + dev_err(binfo, "Feature Type %x is not supported.\n", + hdr->type); + }; + + return ret; +} + +static int +parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start) +{ + struct feature_header *hdr, header; + u8 __iomem *end = (u8 __iomem *)binfo->ioend; + int ret = 0; + + for (; start < end; start += header.next_header_offset) { + if (end - start < (unsigned int)sizeof(*hdr)) { + dev_err(binfo, "The region is too small to contain a feature.\n"); + ret = -EINVAL; + break; + } + + hdr = (struct feature_header *)start; + ret = parse_feature(binfo, hdr); + if (ret) + return ret; + + header.csr = readq(hdr); + if (!header.next_header_offset) + break; + } + + return build_info_commit_dev(binfo); +} + +/* switch the memory mapping to BAR# @bar */ +static int parse_switch_to(struct build_feature_devs_info *binfo, int bar) +{ + struct opae_adapter_data_pci *pci_data = binfo->pci_data; + + if (!pci_data->region[bar].addr) + return -ENOMEM; + + binfo->ioaddr = pci_data->region[bar].addr; + binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len; + binfo->phys_addr = pci_data->region[bar].phys_addr; + binfo->current_bar = bar; + + return 0; +} + +static int parse_ports_from_fme(struct build_feature_devs_info *binfo) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_port port; + int i = 0, ret = 0; + + if (!binfo->pfme_hdr) { + dev_info(binfo, "VF is detected.\n"); + return ret; + } + + fme_hdr = binfo->pfme_hdr; + + do { + port.csr = readq(&fme_hdr->port[i]); + if (!port.port_implemented) + break; + + /* skip port which only could be accessed via VF */ + if (port.afu_access_control == FME_AFU_ACCESS_VF) + continue; + + ret = parse_switch_to(binfo, port.port_bar); + if (ret) + break; + + ret = parse_feature_list(binfo, + (u8 __iomem *)binfo->ioaddr + + port.port_offset); + if (ret) + break; + } while (++i < MAX_FPGA_PORT_NUM); + + return ret; +} + +static struct build_feature_devs_info * +build_info_alloc_and_init(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + + binfo = zmalloc(sizeof(*binfo)); + if (!binfo) + return binfo; + + binfo->hw = hw; + binfo->pci_data = hw->pci_data; + + /* fpga feature list starts from BAR 0 */ + if (parse_switch_to(binfo, 0)) { + free(binfo); + return NULL; + } + + return binfo; +} + +static void build_info_free(struct build_feature_devs_info *binfo) +{ + free(binfo); +} + +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; + + 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]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr: 0x%lx\n", + feature->name, (unsigned long long)feature->addr, + (unsigned long long)feature->addr + feature->size - 1, + feature->phys_addr); + } + + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) { + port = &hw->port[i]; + + if (port->state != IFPGA_PORT_ATTACHED) + continue; + + dev_info(hw, "port device: %d\n", port->port_id); + + for (j = 0; j < PORT_FEATURE_ID_MAX; j++) { + feature = &port->sub_feature[j]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr:0x%lx\n", + feature->name, + (unsigned long long)feature->addr, + (unsigned long long)feature->addr + + feature->size - 1, + feature->phys_addr); + } + } +} + +int ifpga_bus_enumerate(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + int ret; + + binfo = build_info_alloc_and_init(hw); + if (!binfo) + return -ENOMEM; + + ret = parse_feature_list(binfo, binfo->ioaddr); + if (ret) + goto exit; + + ret = parse_ports_from_fme(binfo); + if (ret) + goto exit; + + ifpga_print_device_feature_list(hw); + +exit: + build_info_free(binfo); + return ret; +} + +int ifpga_bus_init(struct ifpga_hw *hw) +{ + int i; + + fme_hw_init(&hw->fme); + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) + port_hw_init(&hw->port[i]); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h new file mode 100644 index 0000000..14131e3 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_ENUMERATE_H_ +#define _IFPGA_ENUMERATE_H_ + +int ifpga_bus_init(struct ifpga_hw *hw); +int ifpga_bus_enumerate(struct ifpga_hw *hw); + +#endif /* _IFPGA_ENUMERATE_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c new file mode 100644 index 0000000..6d14523 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -0,0 +1,314 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <linux/vfio.h> +#include <sys/ioctl.h> + +#include "ifpga_feature_dev.h" + +/* + * Enable Port by clear the port soft reset bit, which is set by default. + * The AFU is unable to respond to any MMIO access while in reset. + * __fpga_port_enable function should only be used after __fpga_port_disable + * function. + */ +void __fpga_port_enable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + WARN_ON(!port->disable_count); + + if (--port->disable_count != 0) + return; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x0; + writeq(control.csr, &port_hdr->control); +} + +int __fpga_port_disable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + if (port->disable_count++ != 0) + return 0; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + /* Set port soft reset */ + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x1; + writeq(control.csr, &port_hdr->control); + + /* + * HW sets ack bit to 1 when all outstanding requests have been drained + * on this port and minimum soft reset pulse width has elapsed. + * Driver polls port_soft_reset_ack to determine if reset done by HW. + */ + control.port_sftrst_ack = 1; + + if (fpga_wait_register_field(port_sftrst_ack, control, + &port_hdr->control, RST_POLL_TIMEOUT, + RST_POLL_INVL)) { + dev_err(port, "timeout, fail to reset device\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) +{ + struct feature_port_header *port_hdr; + u64 guidl, guidh; + + port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU); + + spinlock_lock(&port->lock); + guidl = readq(&port_hdr->afu_header.guid.b[0]); + guidh = readq(&port_hdr->afu_header.guid.b[8]); + spinlock_unlock(&port->lock); + + printf("%s: guidl=0x%lx, guidh=0x%lx\n", __func__, guidl, guidh); + + memcpy(uuid->b, &guidl, sizeof(u64)); + memcpy(uuid->b + 8, &guidh, sizeof(u64)); + + return 0; +} + +/* Mask / Unmask Port Errors by the Error Mask register. */ +void port_err_mask(struct ifpga_port_hw *port, bool mask) +{ + struct feature_port_error *port_err; + struct feature_port_err_key err_mask; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + if (mask) + err_mask.csr = PORT_ERR_MASK; + else + err_mask.csr = 0; + + writeq(err_mask.csr, &port_err->error_mask); +} + +/* Clear All Port Errors. */ +int port_err_clear(struct ifpga_port_hw *port, u64 err) +{ + struct feature_port_header *port_hdr; + struct feature_port_error *port_err; + struct feature_port_err_key mask; + struct feature_port_first_err_key first; + struct feature_port_status status; + int ret = 0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + /* + * Clear All Port Errors + * + * - Check for AP6 State + * - Halt Port by keeping Port in reset + * - Set PORT Error mask to all 1 to mask errors + * - Clear all errors + * - Set Port mask to all 0 to enable errors + * - All errors start capturing new errors + * - Enable Port by pulling the port out of reset + */ + + /* If device is still in AP6 state, can not clear any error.*/ + status.csr = readq(&port_hdr->status); + if (status.power_state == PORT_POWER_STATE_AP6) { + dev_err(dev, "Could not clear errors, device in AP6 state.\n"); + return -EBUSY; + } + + /* Halt Port by keeping Port in reset */ + ret = __fpga_port_disable(port); + if (ret) + return ret; + + /* Mask all errors */ + port_err_mask(port, true); + + /* Clear errors if err input matches with current port errors.*/ + mask.csr = readq(&port_err->port_error); + + if (mask.csr == err) { + writeq(mask.csr, &port_err->port_error); + + first.csr = readq(&port_err->port_first_error); + writeq(first.csr, &port_err->port_first_error); + } else { + ret = -EBUSY; + } + + /* Clear mask */ + port_err_mask(port, false); + + /* Enable the Port by clear the reset */ + __fpga_port_enable(port); + + return ret; +} + +int port_clear_error(struct ifpga_port_hw *port) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + + dev_info(port, "read port error: 0x%lx\n", error.csr); + + return port_err_clear(port, error.csr); +} + +void fme_hw_uinit(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return; + + 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); + } +} + +int fme_hw_init(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i, ret; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + 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; + } + } + } + + return 0; +} + +void port_hw_uinit(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i; + + 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); + } +} + +int port_hw_init(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i, 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; + } + } + } + + return 0; +} + +/* + * FIXME: we should get msix vec count during pci enumeration instead of + * below hardcode value. + */ +#define FPGA_MSIX_VEC_COUNT 20 +/* irq set buffer length for interrupt */ +#define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \ + sizeof(int) * FPGA_MSIX_VEC_COUNT) + +/* only support msix for now*/ +static int vfio_msix_enable_block(s32 vfio_dev_fd, unsigned int vec_start, + unsigned int count, s32 *fds) +{ + char irq_set_buf[MSIX_IRQ_SET_BUF_LEN]; + struct vfio_irq_set *irq_set; + int len, ret; + int *fd_ptr; + + len = sizeof(irq_set_buf); + + irq_set = (struct vfio_irq_set *)irq_set_buf; + irq_set->argsz = len; + irq_set->count = count; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; + irq_set->start = vec_start; + + fd_ptr = (int *)&irq_set->data; + memcpy(fd_ptr, fds, sizeof(int) * count); + + ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set); + if (ret) + printf("Error enabling MSI-X interrupts\n"); + + return ret; +} + +int fpga_msix_set_block(struct feature *feature, unsigned int start, + unsigned int count, s32 *fds) +{ + struct feature_irq_ctx *ctx = feature->ctx; + unsigned int i; + int ret; + + if (start >= feature->ctx_num || start + count > feature->ctx_num) + return -EINVAL; + + /* assume that each feature has continuous vector space in msix*/ + ret = vfio_msix_enable_block(feature->vfio_dev_fd, + ctx[start].idx, count, fds); + if (!ret) { + for (i = 0; i < count; i++) + ctx[i].eventfd = fds[i]; + } + + return ret; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h new file mode 100644 index 0000000..cd114fb --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_FEATURE_DEV_H_ +#define _IFPGA_FEATURE_DEV_H_ + +#include "ifpga_hw.h" + +static inline struct ifpga_port_hw * +get_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return NULL; + + return &hw->port[port_id]; +} + +#define ifpga_for_each_feature(hw, feature) \ + for ((feature) = (hw)->sub_feature; \ + (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++) + +static inline struct feature * +get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(fme, feature) { + if (feature->id == id) + return feature; + } + + return NULL; +} + +static inline struct feature * +get_port_feature_by_id(struct ifpga_port_hw *port, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(port, feature) { + 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; +} + +static inline void * +get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index) +{ + return port->sub_feature[index].addr; +} + +static inline bool +is_fme_feature_present(struct ifpga_fme_hw *fme, int index) +{ + return !!get_fme_feature_ioaddr_by_index(fme, index); +} + +static inline bool +is_port_feature_present(struct ifpga_port_hw *port, int index) +{ + return !!get_port_feature_ioaddr_by_index(port, index); +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid); + +int __fpga_port_disable(struct ifpga_port_hw *port); +void __fpga_port_enable(struct ifpga_port_hw *port); + +static inline int fpga_port_disable(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_disable(port); + spinlock_unlock(&port->lock); + return ret; +} + +static inline int fpga_port_enable(struct ifpga_port_hw *port) +{ + spinlock_lock(&port->lock); + __fpga_port_enable(port); + spinlock_unlock(&port->lock); + + return 0; +} + +static inline int __fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + ret = __fpga_port_disable(port); + if (ret) + return ret; + + __fpga_port_enable(port); + + return 0; +} + +static inline int fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_reset(port); + spinlock_unlock(&port->lock); + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +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); +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set); + +int fme_hw_init(struct ifpga_fme_hw *fme); +void fme_hw_uinit(struct ifpga_fme_hw *fme); +void port_hw_uinit(struct ifpga_port_hw *port); +int port_hw_init(struct ifpga_port_hw *port); +int port_clear_error(struct ifpga_port_hw *port); +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; + +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); + +/* This struct is used when parsing uafu irq_set */ +struct fpga_uafu_irq_set { + u32 start; + u32 count; + s32 *evtfds; +}; + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set); + +extern struct feature_ops port_hdr_ops; +extern struct feature_ops port_error_ops; +extern struct feature_ops port_stp_ops; +extern struct feature_ops port_uint_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 new file mode 100644 index 0000000..4be60c0 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -0,0 +1,734 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PWR_THRESHOLD_MAX 0x7F + +int fme_get_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +/* fme private feature head */ +static int fme_hdr_init(struct feature *feature) +{ + struct feature_fme_header *fme_hdr; + + fme_hdr = (struct feature_fme_header *)feature->addr; + + dev_info(NULL, "FME HDR Init.\n"); + dev_info(NULL, "FME cap %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + return 0; +} + +static void fme_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME HDR UInit.\n"); +} + +static int fme_hdr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&fme_hdr->header); + *revision = header.revision; + + return 0; +} + +static int fme_hdr_get_ports_num(struct ifpga_fme_hw *fme, u64 *ports_num) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *ports_num = fme_capability.num_ports; + + return 0; +} + +static int fme_hdr_get_cache_size(struct ifpga_fme_hw *fme, u64 *cache_size) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *cache_size = fme_capability.cache_size; + + return 0; +} + +static int fme_hdr_get_version(struct ifpga_fme_hw *fme, u64 *version) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *version = fme_capability.fabric_verid; + + return 0; +} + +static int fme_hdr_get_socket_id(struct ifpga_fme_hw *fme, u64 *socket_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *socket_id = fme_capability.socket_id; + + return 0; +} + +static int fme_hdr_get_bitstream_id(struct ifpga_fme_hw *fme, + u64 *bitstream_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_id = readq(&fme_hdr->bitstream_id); + + return 0; +} + +static int fme_hdr_get_bitstream_metadata(struct ifpga_fme_hw *fme, + u64 *bitstream_metadata) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_metadata = readq(&fme_hdr->bitstream_md); + + return 0; +} + +static int +fme_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_HDR_PROP_REVISION: + return fme_hdr_get_revision(fme, &prop->data); + case FME_HDR_PROP_PORTS_NUM: + return fme_hdr_get_ports_num(fme, &prop->data); + case FME_HDR_PROP_CACHE_SIZE: + return fme_hdr_get_cache_size(fme, &prop->data); + case FME_HDR_PROP_VERSION: + return fme_hdr_get_version(fme, &prop->data); + case FME_HDR_PROP_SOCKET_ID: + return fme_hdr_get_socket_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_ID: + return fme_hdr_get_bitstream_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_METADATA: + return fme_hdr_get_bitstream_metadata(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_hdr_ops = { + .init = fme_hdr_init, + .uinit = fme_hdr_uinit, + .get_prop = fme_hdr_get_prop, +}; + +/* thermal management */ +static int fme_thermal_get_threshold1(struct ifpga_fme_hw *fme, u64 *thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1 = temp_threshold.tmp_thshold1; + + return 0; +} + +static int fme_thermal_set_threshold1(struct ifpga_fme_hw *fme, u64 thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres1 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres1 == 0) { + tmp_threshold.tmp_thshold1_enable = 0; + tmp_threshold.tmp_thshold1 = thres1; + } else { + tmp_threshold.tmp_thshold1_enable = 1; + tmp_threshold.tmp_thshold1 = thres1; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold2(struct ifpga_fme_hw *fme, u64 *thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres2 = temp_threshold.tmp_thshold2; + + return 0; +} + +static int fme_thermal_set_threshold2(struct ifpga_fme_hw *fme, u64 thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres2 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres2 == 0) { + tmp_threshold.tmp_thshold2_enable = 0; + tmp_threshold.tmp_thshold2 = thres2; + } else { + tmp_threshold.tmp_thshold2_enable = 1; + tmp_threshold.tmp_thshold2 = thres2; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold_trip(struct ifpga_fme_hw *fme, + u64 *thres_trip) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres_trip = temp_threshold.therm_trip_thshold; + + return 0; +} + +static int fme_thermal_get_threshold1_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold1_status; + + return 0; +} + +static int fme_thermal_get_threshold2_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold2_status; + + return 0; +} + +static int fme_thermal_get_threshold1_policy(struct ifpga_fme_hw *fme, + u64 *thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_policy = temp_threshold.thshold_policy; + + return 0; +} + +static int fme_thermal_set_threshold1_policy(struct ifpga_fme_hw *fme, + u64 thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold tmp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + + if (thres1_policy == 0) { + tmp_threshold.thshold_policy = 0; + } else if (thres1_policy == 1) { + tmp_threshold.thshold_policy = 1; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_temperature(struct ifpga_fme_hw *fme, u64 *temp) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_temp_rdsensor_fmt1 temp_rdsensor_fmt1; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_rdsensor_fmt1.csr = readq(&thermal->rdsensor_fm1); + *temp = temp_rdsensor_fmt1.fpga_temp; + + return 0; +} + +static int fme_thermal_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_thermal *fme_thermal + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + struct feature_header header; + + header.csr = readq(&fme_thermal->header); + *revision = header.revision; + + return 0; +} + +#define FME_THERMAL_CAP_NO_TMP_THRESHOLD 0x1 + +static int fme_thermal_mgmt_init(struct feature *feature) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold_cap thermal_cap; + + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt Init.\n"); + + fme_thermal = (struct feature_fme_thermal *)feature->addr; + thermal_cap.csr = readq(&fme_thermal->threshold_cap); + + dev_info(NULL, "FME thermal cap %llx.\n", + (unsigned long long)fme_thermal->threshold_cap.csr); + + if (thermal_cap.tmp_thshold_disabled) + feature->cap |= FME_THERMAL_CAP_NO_TMP_THRESHOLD; + + return 0; +} + +static void fme_thermal_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt UInit.\n"); +} + +static int +fme_thermal_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_set_threshold1(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_set_threshold2(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_set_threshold1_policy(fme, prop->data); + } + + return -ENOENT; +} + +static int +fme_thermal_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD && + prop->prop_id != FME_THERMAL_PROP_TEMPERATURE && + prop->prop_id != FME_THERMAL_PROP_REVISION) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_get_threshold1(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_get_threshold2(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD_TRIP: + return fme_thermal_get_threshold_trip(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_REACHED: + return fme_thermal_get_threshold1_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2_REACHED: + return fme_thermal_get_threshold2_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_get_threshold1_policy(fme, &prop->data); + case FME_THERMAL_PROP_TEMPERATURE: + return fme_thermal_get_temperature(fme, &prop->data); + case FME_THERMAL_PROP_REVISION: + return fme_thermal_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_thermal_mgmt_ops = { + .init = fme_thermal_mgmt_init, + .uinit = fme_thermal_mgmt_uinit, + .get_prop = fme_thermal_get_prop, + .set_prop = fme_thermal_set_prop, +}; + +static int fme_pwr_get_consumed(struct ifpga_fme_hw *fme, u64 *consumed) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *consumed = pm_status.pwr_consumed; + + return 0; +} + +static int fme_pwr_get_threshold1(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold1; + + return 0; +} + +static int fme_pwr_set_threshold1(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold1 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold2(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold2; + + return 0; +} + +static int fme_pwr_set_threshold2(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold2 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold1_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold1_status; + + return 0; +} + +static int fme_pwr_get_threshold2_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold2_status; + + return 0; +} + +static int fme_pwr_get_rtl(struct ifpga_fme_hw *fme, u64 *rtl) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *rtl = pm_status.fpga_latency_report; + + return 0; +} + +static int fme_pwr_get_xeon_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_xeon_limit xeon_limit; + + xeon_limit.csr = readq(&fme_power->xeon_limit); + + if (!xeon_limit.enable) + xeon_limit.pwr_limit = 0; + + *limit = xeon_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_fpga_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_fpga_limit fpga_limit; + + fpga_limit.csr = readq(&fme_power->fpga_limit); + + if (!fpga_limit.enable) + fpga_limit.pwr_limit = 0; + + *limit = fpga_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_header header; + + header.csr = readq(&fme_power->header); + *revision = header.revision; + + return 0; +} + +static int fme_power_mgmt_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt Init.\n"); + + return 0; +} + +static void fme_power_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt UInit.\n"); +} + +static int fme_power_mgmt_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_CONSUMED: + return fme_pwr_get_consumed(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_get_threshold1(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_get_threshold2(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1_STATUS: + return fme_pwr_get_threshold1_status(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2_STATUS: + return fme_pwr_get_threshold2_status(fme, &prop->data); + case FME_PWR_PROP_RTL: + return fme_pwr_get_rtl(fme, &prop->data); + case FME_PWR_PROP_XEON_LIMIT: + return fme_pwr_get_xeon_limit(fme, &prop->data); + case FME_PWR_PROP_FPGA_LIMIT: + return fme_pwr_get_fpga_limit(fme, &prop->data); + case FME_PWR_PROP_REVISION: + return fme_pwr_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_power_mgmt_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_set_threshold1(fme, prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_set_threshold2(fme, prop->data); + } + + return -ENOENT; +} + +struct 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, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c new file mode 100644 index 0000000..1773b87 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_dperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_clk_ctr clk; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + clk.afu_interf_clock = readq(&dperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_dperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_dperf *dperf; + struct feature_header header; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + header.csr = readq(&dperf->header); + *revision = header.revision; + + return 0; +} + +#define DPERF_TIMEOUT 30 + +static bool fabric_pobj_is_enabled(int port_id, + struct feature_fme_dperf *dperf) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + + ctl.csr = readq(&dperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum dperf_fab_events fab_event) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dfpmon_fab_ctr ctr; + struct feature_fme_dperf *dperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, dperf)) + goto exit; + + ctl.csr = readq(&dperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &dperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &dperf->fab_ctr, DPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&dperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_dperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, DPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, DPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(mmio_read, DPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, DPERF_FAB_MMIO_WR); + +static int fme_dperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_dperf *dperf; + int status; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + status = fabric_pobj_is_enabled(port_id, dperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_dperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dperf *dperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, dperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&dperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_dperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_dperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 + +static int fme_global_dperf_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf Init.\n"); + + return 0; +} + +static void fme_global_dperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf UInit.\n"); +} + +static int fme_dperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_dperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_dperf_get_fab_port_pcie0_read(fme, sub, &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_dperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* MMIO_READ */ + return fme_dperf_get_fab_port_mmio_read(fme, sub, &prop->data); + case 0x5: /* MMIO_WRITE */ + return fme_dperf_get_fab_port_mmio_write(fme, sub, &prop->data); + case 0x6: /* ENABLE */ + return fme_dperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_dperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_dperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_dperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_dperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_dperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE - fab root only prop */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_dperf_set_fab_freeze(fme, prop->data); + case 0x6: /* ENABLE - fab both root and sub */ + return fme_dperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_dperf_ops = { + .init = fme_global_dperf_init, + .uinit = fme_global_dperf_uinit, + .get_prop = fme_global_dperf_get_prop, + .set_prop = fme_global_dperf_set_prop, + +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c new file mode 100644 index 0000000..33c241e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static int fme_err_get_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + + fme_error0.csr = readq(&fme_err->fme_err); + *val = fme_error0.csr; + + return 0; +} + +static int fme_err_get_first_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_first_error fme_first_err; + + fme_first_err.csr = readq(&fme_err->fme_first_err); + *val = fme_first_err.err_reg_status; + + return 0; +} + +static int fme_err_get_next_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_next_error fme_next_err; + + fme_next_err.csr = readq(&fme_err->fme_next_err); + *val = fme_next_err.err_reg_status; + + return 0; +} + +static int fme_err_set_clear(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_ERROR0_MASK, &fme_err->fme_err_mask); + + fme_error0.csr = readq(&fme_err->fme_err); + if (val != fme_error0.csr) { + ret = -EBUSY; + goto exit; + } + + fme_first_err.csr = readq(&fme_err->fme_first_err); + fme_next_err.csr = readq(&fme_err->fme_next_err); + + writeq(fme_error0.csr & FME_ERROR0_MASK, &fme_err->fme_err); + writeq(fme_first_err.csr & FME_FIRST_ERROR_MASK, + &fme_err->fme_first_err); + writeq(fme_next_err.csr & FME_NEXT_ERROR_MASK, + &fme_err->fme_next_err); + +exit: + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_revision(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_header header; + + header.csr = readq(&fme_err->header); + *val = header.revision; + + return 0; +} + +static int fme_err_get_pcie0_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + + pcie0_err.csr = readq(&fme_err->pcie0_err); + *val = pcie0_err.csr; + + return 0; +} + +static int fme_err_set_pcie0_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE0_ERROR_MASK, &fme_err->pcie0_err_mask); + + pcie0_err.csr = readq(&fme_err->pcie0_err); + if (val != pcie0_err.csr) + ret = -EBUSY; + else + writeq(pcie0_err.csr & FME_PCIE0_ERROR_MASK, + &fme_err->pcie0_err); + + writeq(0UL, &fme_err->pcie0_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_pcie1_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + + pcie1_err.csr = readq(&fme_err->pcie1_err); + *val = pcie1_err.csr; + + return 0; +} + +static int fme_err_set_pcie1_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE1_ERROR_MASK, &fme_err->pcie1_err_mask); + + pcie1_err.csr = readq(&fme_err->pcie1_err); + if (val != pcie1_err.csr) + ret = -EBUSY; + else + writeq(pcie1_err.csr & FME_PCIE1_ERROR_MASK, + &fme_err->pcie1_err); + + writeq(0UL, &fme_err->pcie1_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_nonfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_nonfaterror ras_nonfaterr; + + ras_nonfaterr.csr = readq(&fme_err->ras_nonfaterr); + *val = ras_nonfaterr.csr; + + return 0; +} + +static int fme_err_get_catfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_catfaterror ras_catfaterr; + + ras_catfaterr.csr = readq(&fme_err->ras_catfaterr); + *val = ras_catfaterr.csr; + + return 0; +} + +static int fme_err_get_inject_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + *val = ras_error_inj.csr & FME_RAS_ERROR_INJ_MASK; + + return 0; +} + +static int fme_err_set_inject_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + spinlock_lock(&fme->lock); + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + + if (val <= FME_RAS_ERROR_INJ_MASK) { + ras_error_inj.csr = val; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(ras_error_inj.csr, &fme_err->ras_error_inj); + spinlock_unlock(&fme->lock); + + return 0; +} + +static void fme_error_enable(struct ifpga_fme_hw *fme) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + writeq(0UL, &fme_err->pcie0_err_mask); + writeq(0UL, &fme_err->pcie1_err_mask); + writeq(0UL, &fme_err->ras_nonfat_mask); + writeq(0UL, &fme_err->ras_catfat_mask); +} + +static int fme_global_error_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = feature->parent; + + fme_error_enable(fme); + + if (feature->ctx_num) + fme->capability |= FPGA_FME_CAP_ERR_IRQ; + + return 0; +} + +static void fme_global_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int fme_err_fme_err_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* ERRORS */ + return fme_err_get_errors(fme, &prop->data); + case 0x2: /* FIRST_ERROR */ + return fme_err_get_first_error(fme, &prop->data); + case 0x3: /* NEXT_ERROR */ + return fme_err_get_next_error(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x5: /* REVISION */ + return fme_err_get_revision(fme, &prop->data); + case 0x6: /* PCIE0_ERRORS */ + return fme_err_get_pcie0_errors(fme, &prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_get_pcie1_errors(fme, &prop->data); + case 0x8: /* NONFATAL_ERRORS */ + return fme_err_get_nonfatal_errors(fme, &prop->data); + case 0x9: /* CATFATAL_ERRORS */ + return fme_err_get_catfatal_errors(fme, &prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_get_inject_errors(fme, &prop->data); + case 0xb: /* REVISION*/ + return fme_err_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_get_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_err_fme_err_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x4: /* CLEAR */ + return fme_err_set_clear(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x6: /* PCIE0_ERRORS */ + return fme_err_set_pcie0_errors(fme, prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_set_pcie1_errors(fme, prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_set_inject_errors(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_set_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_set_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_global_err_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_fme_err_irq_set *err_irq_set = + (struct fpga_fme_err_irq_set *)irq_set; + struct ifpga_fme_hw *fme; + int ret; + + fme = (struct ifpga_fme_hw *)feature->parent; + + spinlock_lock(&fme->lock); + if (!(fme->capability & FPGA_FME_CAP_ERR_IRQ)) { + spinlock_unlock(&fme->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&fme->lock); + + return ret; +} + +struct feature_ops fme_global_err_ops = { + .init = fme_global_error_init, + .uinit = fme_global_error_uinit, + .get_prop = fme_global_error_get_prop, + .set_prop = fme_global_error_set_prop, + .set_irq = fme_global_err_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c new file mode 100644 index 0000000..e6c40a1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c @@ -0,0 +1,715 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_iperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_clk_ctr clk; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + clk.afu_interf_clock = readq(&iperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_iperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_iperf *iperf; + struct feature_header header; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + header.csr = readq(&iperf->header); + *revision = header.revision; + + return 0; +} + +static int fme_iperf_get_cache_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + *freeze = (u64)ctl.freeze; + return 0; +} + +static int fme_iperf_set_cache_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->ch_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define IPERF_TIMEOUT 30 + +static u64 read_cache_counter(struct ifpga_fme_hw *fme, + u8 channel, enum iperf_cache_events event) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + struct feature_fme_ifpmon_ch_ctr ctr0, ctr1; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* set channel access type and cache event code. */ + ctl.csr = readq(&iperf->ch_ctl); + ctl.cci_chsel = channel; + ctl.cache_event = event; + writeq(ctl.csr, &iperf->ch_ctl); + + /* check the event type in the counter registers */ + ctr0.event_code = event; + + if (fpga_wait_register_field(event_code, ctr0, + &iperf->ch_ctr0, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched cache event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr0.csr = readq(&iperf->ch_ctr0); + ctr1.csr = readq(&iperf->ch_ctr1); + counter = ctr0.cache_counter + ctr1.cache_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define CACHE_SHOW(name, type, event) \ +static int fme_iperf_get_cache_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_cache_counter(fme, type, event); \ + return 0; \ +} + +CACHE_SHOW(read_hit, CACHE_CHANNEL_RD, IPERF_CACHE_RD_HIT); +CACHE_SHOW(read_miss, CACHE_CHANNEL_RD, IPERF_CACHE_RD_MISS); +CACHE_SHOW(write_hit, CACHE_CHANNEL_WR, IPERF_CACHE_WR_HIT); +CACHE_SHOW(write_miss, CACHE_CHANNEL_WR, IPERF_CACHE_WR_MISS); +CACHE_SHOW(hold_request, CACHE_CHANNEL_RD, IPERF_CACHE_HOLD_REQ); +CACHE_SHOW(tx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_TX_REQ_STALL); +CACHE_SHOW(rx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_RX_REQ_STALL); +CACHE_SHOW(rx_eviction, CACHE_CHANNEL_RD, IPERF_CACHE_EVICTIONS); +CACHE_SHOW(data_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_DATA_WR_PORT_CONTEN); +CACHE_SHOW(tag_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_TAG_WR_PORT_CONTEN); + +static int fme_iperf_get_vtd_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_vtd_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->vtd_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static u64 read_iommu_sip_counter(struct ifpga_fme_hw *fme, + enum iperf_vtd_sip_events event) +{ + struct feature_fme_ifpmon_vtd_sip_ctl sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr sip_ctr; + struct feature_fme_iperf *iperf; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + sip_ctl.csr = readq(&iperf->vtd_sip_ctl); + sip_ctl.vtd_evtcode = event; + writeq(sip_ctl.csr, &iperf->vtd_sip_ctl); + + sip_ctr.event_code = event; + + if (fpga_wait_register_field(event_code, sip_ctr, + &iperf->vtd_sip_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd SIP event type in counter registers\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + sip_ctr.csr = readq(&iperf->vtd_sip_ctr); + counter = sip_ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_SIP_SHOW(name, event) \ +static int fme_iperf_get_vtd_sip_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_iommu_sip_counter(fme, event); \ + return 0; \ +} + +VTD_SIP_SHOW(iotlb_4k_hit, IPERF_VTD_SIP_IOTLB_4K_HIT); +VTD_SIP_SHOW(iotlb_2m_hit, IPERF_VTD_SIP_IOTLB_2M_HIT); +VTD_SIP_SHOW(iotlb_1g_hit, IPERF_VTD_SIP_IOTLB_1G_HIT); +VTD_SIP_SHOW(slpwc_l3_hit, IPERF_VTD_SIP_SLPWC_L3_HIT); +VTD_SIP_SHOW(slpwc_l4_hit, IPERF_VTD_SIP_SLPWC_L4_HIT); +VTD_SIP_SHOW(rcc_hit, IPERF_VTD_SIP_RCC_HIT); +VTD_SIP_SHOW(iotlb_4k_miss, IPERF_VTD_SIP_IOTLB_4K_MISS); +VTD_SIP_SHOW(iotlb_2m_miss, IPERF_VTD_SIP_IOTLB_2M_MISS); +VTD_SIP_SHOW(iotlb_1g_miss, IPERF_VTD_SIP_IOTLB_1G_MISS); +VTD_SIP_SHOW(slpwc_l3_miss, IPERF_VTD_SIP_SLPWC_L3_MISS); +VTD_SIP_SHOW(slpwc_l4_miss, IPERF_VTD_SIP_SLPWC_L4_MISS); +VTD_SIP_SHOW(rcc_miss, IPERF_VTD_SIP_RCC_MISS); + +static u64 read_iommu_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_vtd_events base_event) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_ifpmon_vtd_ctr ctr; + struct feature_fme_iperf *iperf; + enum iperf_vtd_events event = base_event + port_id; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.vtd_evtcode = event; + writeq(ctl.csr, &iperf->vtd_ctl); + + ctr.event_code = event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->vtd_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->vtd_ctr); + counter = ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_PORT_SHOW(name, base_event) \ +static int fme_iperf_get_vtd_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_iommu_counter(fme, port_id, base_event); \ + return 0; \ +} + +VTD_PORT_SHOW(read_transaction, IPERF_VTD_AFU_MEM_RD_TRANS); +VTD_PORT_SHOW(write_transaction, IPERF_VTD_AFU_MEM_WR_TRANS); +VTD_PORT_SHOW(devtlb_read_hit, IPERF_VTD_AFU_DEVTLB_RD_HIT); +VTD_PORT_SHOW(devtlb_write_hit, IPERF_VTD_AFU_DEVTLB_WR_HIT); +VTD_PORT_SHOW(devtlb_4k_fill, IPERF_VTD_DEVTLB_4K_FILL); +VTD_PORT_SHOW(devtlb_2m_fill, IPERF_VTD_DEVTLB_2M_FILL); +VTD_PORT_SHOW(devtlb_1g_fill, IPERF_VTD_DEVTLB_1G_FILL); + +static bool fabric_pobj_is_enabled(u8 port_id, struct feature_fme_iperf *iperf) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + + ctl.csr = readq(&iperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_fab_events fab_event) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_ifpmon_fab_ctr ctr; + struct feature_fme_iperf *iperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, iperf)) + goto exit; + + ctl.csr = readq(&iperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &iperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->fab_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_iperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, IPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, IPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(pcie1_read, IPERF_FAB_PCIE1_RD); +FAB_PORT_SHOW(pcie1_write, IPERF_FAB_PCIE1_WR); +FAB_PORT_SHOW(upi_read, IPERF_FAB_UPI_RD); +FAB_PORT_SHOW(upi_write, IPERF_FAB_UPI_WR); +FAB_PORT_SHOW(mmio_read, IPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, IPERF_FAB_MMIO_WR); + +static int fme_iperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_iperf *iperf; + int status; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + status = fabric_pobj_is_enabled(port_id, iperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_iperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, iperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&iperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_iperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 +#define FME_IPERF_CAP_IOMMU 0x1 + +static int fme_global_iperf_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme; + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + + dev_info(NULL, "FME global_iperf Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + /* check if iommu is not supported on this device. */ + fme_capability.csr = readq(&fme_hdr->capability); + dev_info(NULL, "FME HEAD fme_capability %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + if (fme_capability.iommu_support) + feature->cap |= FME_IPERF_CAP_IOMMU; + + return 0; +} + +static void fme_global_iperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_iperf UInit.\n"); +} + +static int fme_iperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_iperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_iperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_cache_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_cache_freeze(fme, &prop->data); + case 0x2: /* READ_HIT */ + return fme_iperf_get_cache_read_hit(fme, &prop->data); + case 0x3: /* READ_MISS */ + return fme_iperf_get_cache_read_miss(fme, &prop->data); + case 0x4: /* WRITE_HIT */ + return fme_iperf_get_cache_write_hit(fme, &prop->data); + case 0x5: /* WRITE_MISS */ + return fme_iperf_get_cache_write_miss(fme, &prop->data); + case 0x6: /* HOLD_REQUEST */ + return fme_iperf_get_cache_hold_request(fme, &prop->data); + case 0x7: /* TX_REQ_STALL */ + return fme_iperf_get_cache_tx_req_stall(fme, &prop->data); + case 0x8: /* RX_REQ_STALL */ + return fme_iperf_get_cache_rx_req_stall(fme, &prop->data); + case 0x9: /* RX_EVICTION */ + return fme_iperf_get_cache_rx_eviction(fme, &prop->data); + case 0xa: /* DATA_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_data_write_port_contention(fme, + &prop->data); + case 0xb: /* TAG_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_tag_write_port_contention(fme, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_vtd_freeze(fme, &prop->data); + case 0x2: /* IOTLB_4K_HIT */ + return fme_iperf_get_vtd_sip_iotlb_4k_hit(fme, &prop->data); + case 0x3: /* IOTLB_2M_HIT */ + return fme_iperf_get_vtd_sip_iotlb_2m_hit(fme, &prop->data); + case 0x4: /* IOTLB_1G_HIT */ + return fme_iperf_get_vtd_sip_iotlb_1g_hit(fme, &prop->data); + case 0x5: /* SLPWC_L3_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l3_hit(fme, &prop->data); + case 0x6: /* SLPWC_L4_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l4_hit(fme, &prop->data); + case 0x7: /* RCC_HIT */ + return fme_iperf_get_vtd_sip_rcc_hit(fme, &prop->data); + case 0x8: /* IOTLB_4K_MISS */ + return fme_iperf_get_vtd_sip_iotlb_4k_miss(fme, &prop->data); + case 0x9: /* IOTLB_2M_MISS */ + return fme_iperf_get_vtd_sip_iotlb_2m_miss(fme, &prop->data); + case 0xa: /* IOTLB_1G_MISS */ + return fme_iperf_get_vtd_sip_iotlb_1g_miss(fme, &prop->data); + case 0xb: /* SLPWC_L3_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l3_miss(fme, &prop->data); + case 0xc: /* SLPWC_L4_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l4_miss(fme, &prop->data); + case 0xd: /* RCC_MISS */ + return fme_iperf_get_vtd_sip_rcc_miss(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_sub_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub > PERF_MAX_PORT_NUM) + return -ENOENT; + + switch (id) { + case 0xe: /* READ_TRANSACTION */ + return fme_iperf_get_vtd_port_read_transaction(fme, sub, + &prop->data); + case 0xf: /* WRITE_TRANSACTION */ + return fme_iperf_get_vtd_port_write_transaction(fme, sub, + &prop->data); + case 0x10: /* DEVTLB_READ_HIT */ + return fme_iperf_get_vtd_port_devtlb_read_hit(fme, sub, + &prop->data); + case 0x11: /* DEVTLB_WRITE_HIT */ + return fme_iperf_get_vtd_port_devtlb_write_hit(fme, sub, + &prop->data); + case 0x12: /* DEVTLB_4K_FILL */ + return fme_iperf_get_vtd_port_devtlb_4k_fill(fme, sub, + &prop->data); + case 0x13: /* DEVTLB_2M_FILL */ + return fme_iperf_get_vtd_port_devtlb_2m_fill(fme, sub, + &prop->data); + case 0x14: /* DEVTLB_1G_FILL */ + return fme_iperf_get_vtd_port_devtlb_1g_fill(fme, sub, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED) + return fme_iperf_vtd_root_get_prop(feature, prop); + + return fme_iperf_vtd_sub_get_prop(feature, prop); +} + +static int fme_iperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + /* Other properties are present for both top and sub levels */ + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_iperf_get_fab_port_pcie0_read(fme, sub, + &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_iperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* PCIE1_READ */ + return fme_iperf_get_fab_port_pcie1_read(fme, sub, + &prop->data); + case 0x5: /* PCIE1_WRITE */ + return fme_iperf_get_fab_port_pcie1_write(fme, sub, + &prop->data); + case 0x6: /* UPI_READ */ + return fme_iperf_get_fab_port_upi_read(fme, sub, + &prop->data); + case 0x7: /* UPI_WRITE */ + return fme_iperf_get_fab_port_upi_write(fme, sub, + &prop->data); + case 0x8: /* MMIO_READ */ + return fme_iperf_get_fab_port_mmio_read(fme, sub, + &prop->data); + case 0x9: /* MMIO_WRITE */ + return fme_iperf_get_fab_port_mmio_write(fme, sub, + &prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_get_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_get_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_iperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_iperf_cache_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_cache_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_vtd_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_vtd_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_set_fab_freeze(fme, prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_set_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_set_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_iperf_ops = { + .init = fme_global_iperf_init, + .uinit = fme_global_iperf_uinit, + .get_prop = fme_global_iperf_get_prop, + .set_prop = fme_global_iperf_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c new file mode 100644 index 0000000..6192fa7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c @@ -0,0 +1,372 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#if defined(RTE_ARCH_X86_64) +static inline void copy512(const void *src, void *dst) +{ + asm volatile("vmovdqu64 (%0), %%zmm0;" + "vmovntdq %%zmm0, (%1);" + : + : "r"(src), "r"(dst)); +} +#else +static inline void copy512(const void *src, void *dst) +{ + UNUSED(src); + UNUSED(dst); + WARN_ON(1); +} +#endif + +static u64 +pr_err_handle(struct feature_fme_pr *fme_pr) +{ + struct feature_fme_pr_status fme_pr_status; + unsigned long err_code; + u64 fme_pr_error; + int i; + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + if (!fme_pr_status.pr_status) + return 0; + + err_code = readq(&fme_pr->ccip_fme_pr_err); + fme_pr_error = err_code; + + for (i = 0; i < PR_MAX_ERR_NUM; i++) { + if (err_code & (1 << i)) + dev_info(NULL, "%s\n", pr_err_msg[i]); + } + + writeq(fme_pr_error, &fme_pr->ccip_fme_pr_err); + return fme_pr_error; +} + +static int fme_pr_write_init(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + if (info->flags != FPGA_MGR_PARTIAL_RECONFIG) + return -EINVAL; + + dev_info(fme_dev, "resetting PR before initiated PR\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + fme_pr_ctl.pr_reset_ack = 1; + + if (fpga_wait_register_field(pr_reset_ack, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 0; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "waiting for PR resource in HW to be initialized and ready\n"); + + fme_pr_status.pr_host_status = PR_HOST_STATUS_IDLE; + + if (fpga_wait_register_field(pr_host_status, fme_pr_status, + &fme_pr->ccip_fme_pr_status, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "check if have any previous PR error\n"); + pr_err_handle(fme_pr); + return 0; +} + +static int fme_pr_write(struct ifpga_fme_hw *fme_dev, + int port_id, const char *buf, size_t count, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + struct feature_fme_pr_data fme_pr_data; + int delay, pr_credit; + int ret = 0; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + dev_info(fme_dev, "set PR port ID and start request\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_regionid = port_id; + fme_pr_ctl.pr_start_req = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "pushing data from bitstream to HW\n"); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + + while (count > 0) { + delay = 0; + while (pr_credit <= 1) { + if (delay++ > PR_WAIT_TIMEOUT) { + dev_err(fme_dev, "maximum try\n"); + + info->pr_err = pr_err_handle(fme_pr); + return info->pr_err ? -EIO : -ETIMEDOUT; + } + udelay(1); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + }; + + if (count >= fme_dev->pr_bandwidth) { + switch (fme_dev->pr_bandwidth) { + case 4: + fme_pr_data.rsvd = 0; + fme_pr_data.pr_data_raw = *((const u32 *)buf); + writeq(fme_pr_data.csr, + &fme_pr->ccip_fme_pr_data); + break; + case 64: + copy512(buf, &fme_pr->fme_pr_data1); + break; + default: + ret = -EFAULT; + goto done; + } + + buf += fme_dev->pr_bandwidth; + count -= fme_dev->pr_bandwidth; + pr_credit--; + } else { + WARN_ON(1); + return -EINVAL; + goto done; + } + } + +done: + return ret; +} + +static int fme_pr_write_complete(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_push_complete = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "green bitstream push complete\n"); + dev_info(fme_dev, "waiting for HW to release PR resource\n"); + + fme_pr_ctl.pr_start_req = 0; + + if (fpga_wait_register_field(pr_start_req, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + printf("maximum try.\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "PR operation complete, checking status\n"); + info->pr_err = pr_err_handle(fme_pr); + if (info->pr_err) + return -EIO; + + dev_info(fme_dev, "PR done successfully\n"); + return 0; +} + +static int fpga_pr_buf_load(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info, const char *buf, + size_t count) +{ + int ret; + + info->state = FPGA_PR_STATE_WRITE_INIT; + ret = fme_pr_write_init(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error preparing FPGA for writing\n"); + info->state = FPGA_PR_STATE_WRITE_INIT_ERR; + return ret; + } + + /* + * Write the FPGA image to the FPGA. + */ + info->state = FPGA_PR_STATE_WRITE; + ret = fme_pr_write(fme_dev, info->port_id, buf, count, info); + if (ret) { + dev_err(fme_dev, "Error while writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_ERR; + return ret; + } + + /* + * After all the FPGA image has been written, do the device specific + * steps to finish and set the FPGA into operating mode. + */ + info->state = FPGA_PR_STATE_WRITE_COMPLETE; + ret = fme_pr_write_complete(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error after writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_COMPLETE_ERR; + return ret; + } + info->state = FPGA_PR_STATE_DONE; + + return 0; +} + +static int fme_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + struct ifpga_fme_hw *fme = &hw->fme; + struct fpga_pr_info info; + struct ifpga_port_hw *port; + int ret = 0; + + if (!buffer || size == 0) + return -EINVAL; + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + /* + * Padding extra zeros to align PR buffer with PR bandwidth, HW will + * ignore these zeros automatically. + */ + size = ALIGN(size, fme->pr_bandwidth); + + /* get fme header region */ + fme_hdr = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_HEADER); + if (!fme_hdr) + return -EINVAL; + + /* check port id */ + fme_capability.csr = readq(&fme_hdr->capability); + if (port_id >= fme_capability.num_ports) { + dev_err(fme, "port number more than maximum\n"); + return -EINVAL; + } + + memset(&info, 0, sizeof(struct fpga_pr_info)); + info.flags = FPGA_MGR_PARTIAL_RECONFIG; + info.port_id = port_id; + + spinlock_lock(&fme->lock); + + /* get port device by port_id */ + port = &hw->port[port_id]; + + /* Disable Port before PR */ + fpga_port_disable(port); + + ret = fpga_pr_buf_load(fme, &info, (void *)buffer, size); + + *status = info.pr_err; + + /* Re-enable Port after PR finished */ + fpga_port_enable(port); + spinlock_unlock(&fme->lock); + + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, u64 *status) +{ + struct bts_header *bts_hdr; + void *buf; + struct ifpga_port_hw *port; + int ret; + + if (!buffer || size == 0) { + dev_err(hw, "invalid parameter\n"); + return -EINVAL; + } + + bts_hdr = (struct bts_header *)buffer; + + if (is_valid_bts(bts_hdr)) { + dev_info(hw, "this is a valid bitsteam..\n"); + size -= (sizeof(struct bts_header) + + bts_hdr->metadata_len); + buf = (u8 *)buffer + sizeof(struct bts_header) + + bts_hdr->metadata_len; + } else { + return -EINVAL; + } + + /* clean port error before do PR */ + port = &hw->port[port_id]; + ret = port_clear_error(port); + if (ret) { + dev_err(hw, "port cannot clear error\n"); + return -EINVAL; + } + + return fme_pr(hw, port_id, buf, size, status); +} + +static int fme_pr_mgmt_init(struct feature *feature) +{ + struct feature_fme_pr *fme_pr; + struct feature_header fme_pr_header; + struct ifpga_fme_hw *fme; + + dev_info(NULL, "FME PR MGMT Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + + fme_pr = (struct feature_fme_pr *)feature->addr; + + fme_pr_header.csr = readq(&fme_pr->header); + if (fme_pr_header.revision == 2) { + dev_info(NULL, "using 512-bit PR\n"); + fme->pr_bandwidth = 64; + } else { + dev_info(NULL, "using 32-bit PR\n"); + fme->pr_bandwidth = 4; + } + + return 0; +} + +static void fme_pr_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME PR MGMT UInit.\n"); +} + +struct 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 new file mode 100644 index 0000000..a20520c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_HW_H_ +#define _IFPGA_HW_H_ + +#include "ifpga_defines.h" +#include "opae_ifpga_hw_api.h" + +enum ifpga_feature_state { + IFPGA_FEATURE_UNUSED = 0, + IFPGA_FEATURE_ATTACHED, +}; + +struct feature_irq_ctx { + int eventfd; + int idx; +}; + +struct feature { + enum ifpga_feature_state state; + const char *name; + u64 id; + u8 *addr; + uint64_t phys_addr; + u32 size; + int revision; + u64 cap; + int vfio_dev_fd; + struct feature_irq_ctx *ctx; + unsigned int ctx_num; + + void *parent; /* to parent hw data structure */ + + struct feature_ops *ops;/* callback to this private feature */ +}; + +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); +}; + +enum ifpga_fme_state { + IFPGA_FME_UNUSED = 0, + IFPGA_FME_IMPLEMENTED, +}; + +struct ifpga_fme_hw { + enum ifpga_fme_state state; + + struct feature sub_feature[FME_FEATURE_ID_MAX]; + spinlock_t lock; /* protect hardware access */ + + void *parent; /* pointer to ifpga_hw */ + + /* provied by HEADER feature */ + u32 port_num; + struct uuid bitstream_id; + u64 bitstream_md; + size_t pr_bandwidth; + u32 socket_id; + u32 fabric_version_id; + u32 cache_size; + + u32 capability; +}; + +enum ifpga_port_state { + IFPGA_PORT_UNUSED = 0, + IFPGA_PORT_ATTACHED, + IFPGA_PORT_DETACHED, +}; + +struct ifpga_port_hw { + enum ifpga_port_state state; + + struct feature sub_feature[PORT_FEATURE_ID_MAX]; + spinlock_t lock; /* protect access to hw */ + + void *parent; /* pointer to ifpga_hw */ + + int port_id; /* provied by HEADER feature */ + struct uuid afu_id; /* provied by User AFU feature */ + + unsigned int disable_count; + + u32 capability; + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ + u8 *stp_addr; + u32 stp_size; +}; + +#define AFU_MAX_REGION 1 + +struct ifpga_afu_info { + struct opae_reg_region region[AFU_MAX_REGION]; + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct ifpga_hw { + struct opae_adapter *adapter; + struct opae_adapter_data_pci *pci_data; + + struct ifpga_fme_hw fme; + struct ifpga_port_hw port[MAX_FPGA_PORT_NUM]; +}; + +static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) +{ + return hw->fme.state != IFPGA_FME_UNUSED; +} + +static inline bool is_valid_port_id(struct ifpga_hw *hw, u32 port_id) +{ + if (port_id >= MAX_FPGA_PORT_NUM || + hw->port[port_id].state != IFPGA_PORT_ATTACHED) + return false; + + return true; +} +#endif /* _IFPGA_HW_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c new file mode 100644 index 0000000..8ab1bdb --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c @@ -0,0 +1,408 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +static int port_get_revision(struct ifpga_port_hw *port, u64 *revision) +{ + struct feature_port_header *port_hdr + = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&port_hdr->header); + + *revision = header.revision; + + return 0; +} + +static int port_get_portidx(struct ifpga_port_hw *port, u64 *idx) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + capability.csr = readq(&port_hdr->capability); + *idx = capability.port_number; + + return 0; +} + +static int port_get_latency_tolerance(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + control.csr = readq(&port_hdr->control); + *val = control.latency_tolerance; + + return 0; +} + +static int port_get_ap1_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap1_event; + + return 0; +} + +static int port_set_ap1_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap1_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_ap2_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap2_event; + + return 0; +} + +static int port_set_ap2_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap2_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_power_state(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.power_state; + + return 0; +} + +static int port_get_userclk_freqcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_hdr_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port hdr Init.\n"); + + fpga_port_reset(port); + + return 0; +} + +static void port_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port hdr uinit.\n"); +} + +static int port_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_REVISION: + return port_get_revision(port, &prop->data); + case PORT_HDR_PROP_PORTIDX: + return port_get_portidx(port, &prop->data); + case PORT_HDR_PROP_LATENCY_TOLERANCE: + return port_get_latency_tolerance(port, &prop->data); + case PORT_HDR_PROP_AP1_EVENT: + return port_get_ap1_event(port, &prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_get_ap2_event(port, &prop->data); + case PORT_HDR_PROP_POWER_STATE: + return port_get_power_state(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_get_userclk_freqcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_get_userclk_freqcntrcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQSTS: + return port_get_userclk_freqsts(port, &prop->data); + case PORT_HDR_PROP_USERCLK_CNTRSTS: + return port_get_userclk_freqcntrsts(port, &prop->data); + } + + return -ENOENT; +} + +static int port_hdr_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_AP1_EVENT: + return port_set_ap1_event(port, prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_set_ap2_event(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_set_userclk_freqcmd(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_set_userclk_freqcntrcmd(port, prop->data); + } + + return -ENOENT; +} + +struct feature_ops 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) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port stp Init.\n"); + + spinlock_lock(&port->lock); + port->stp_addr = feature->addr; + port->stp_size = feature->size; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_stp_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port stp uinit.\n"); +} + +struct feature_ops port_stp_ops = { + .init = port_stp_init, + .uinit = port_stp_uinit, +}; + +static int port_uint_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "PORT UINT Init.\n"); + + spinlock_lock(&port->lock); + if (feature->ctx_num) { + port->capability |= FPGA_PORT_CAP_UAFU_IRQ; + port->num_uafu_irqs = feature->ctx_num; + } + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_uint_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT UINT UInit.\n"); +} + +static int port_uint_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_uafu_irq_set *uafu_irq_set = irq_set; + struct ifpga_port_hw *port = feature->parent; + int ret; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_UAFU_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, uafu_irq_set->start, + uafu_irq_set->count, uafu_irq_set->evtfds); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_uint_ops = { + .init = port_uint_init, + .uinit = port_uint_uinit, + .set_irq = port_uint_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c new file mode 100644 index 0000000..3be0f5e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static int port_err_get_revision(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_header header; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + header.csr = readq(&port_err->header); + *val = header.revision; + + return 0; +} + +static int port_err_get_errors(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + *val = error.csr; + + return 0; +} + +static int port_err_get_first_error(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_first_err_key first_error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + first_error.csr = readq(&port_err->port_first_error); + *val = first_error.csr; + + return 0; +} + +static int port_err_get_first_malformed_req_lsb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req0 malreq0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq0.header_lsb = readq(&port_err->malreq0); + *val = malreq0.header_lsb; + + return 0; +} + +static int port_err_get_first_malformed_req_msb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req1 malreq1; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq1.header_msb = readq(&port_err->malreq1); + *val = malreq1.header_msb; + + return 0; +} + +static int port_err_set_clear(struct ifpga_port_hw *port, u64 val) +{ + int ret; + + spinlock_lock(&port->lock); + ret = port_err_clear(port, val); + spinlock_unlock(&port->lock); + + return ret; +} + +static int port_error_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port error Init.\n"); + + spinlock_lock(&port->lock); + port_err_mask(port, false); + if (feature->ctx_num) + port->capability |= FPGA_PORT_CAP_ERR_IRQ; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int port_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_ERR_PROP_REVISION: + return port_err_get_revision(port, &prop->data); + case PORT_ERR_PROP_ERRORS: + return port_err_get_errors(port, &prop->data); + case PORT_ERR_PROP_FIRST_ERROR: + return port_err_get_first_error(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB: + return port_err_get_first_malformed_req_lsb(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB: + return port_err_get_first_malformed_req_msb(port, &prop->data); + } + + return -ENOENT; +} + +static int port_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + if (prop->prop_id == PORT_ERR_PROP_CLEAR) + return port_err_set_clear(port, prop->data); + + return -ENOENT; +} + +static int port_error_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_port_err_irq_set *err_irq_set = irq_set; + struct ifpga_port_hw *port; + int ret; + + port = feature->parent; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_ERR_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_error_ops = { + .init = port_error_init, + .uinit = port_error_uinit, + .get_prop = port_error_get_prop, + .set_prop = port_error_set_prop, + .set_irq = port_error_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.c b/drivers/raw/ifpga_rawdev/base/opae_debug.c new file mode 100644 index 0000000..024d7d2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.c @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#define OPAE_HW_DEBUG + +#include "opae_hw_api.h" +#include "opae_debug.h" + +void opae_manager_dump(struct opae_manager *mgr) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Manger %s\n", mgr->name); + opae_log("OPAE Manger OPs = %p\n", mgr->ops); + opae_log("OPAE Manager Private Data = %p\n", mgr->data); + opae_log("OPAE Adapter(parent) = %p\n", mgr->adapter); + opae_log("==========================\n"); +} + +void opae_bridge_dump(struct opae_bridge *br) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Bridge %s\n", br->name); + opae_log("OPAE Bridge ID = %d\n", br->id); + opae_log("OPAE Bridge OPs = %p\n", br->ops); + opae_log("OPAE Bridge Private Data = %p\n", br->data); + opae_log("OPAE Accelerator(under this bridge) = %p\n", br->acc); + opae_log("==========================\n"); +} + +void opae_accelerator_dump(struct opae_accelerator *acc) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Accelerator %s\n", acc->name); + opae_log("OPAE Accelerator Index = %d\n", acc->index); + opae_log("OPAE Accelerator OPs = %p\n", acc->ops); + opae_log("OPAE Accelerator Private Data = %p\n", acc->data); + opae_log("OPAE Bridge (upstream) = %p\n", acc->br); + opae_log("OPAE Manager (upstream) = %p\n", acc->mgr); + opae_log("==========================\n"); + + if (acc->br) + opae_bridge_dump(acc->br); +} + +static void opae_adapter_data_dump(void *data) +{ + struct opae_adapter_data *d = data; + struct opae_adapter_data_pci *d_pci; + struct opae_reg_region *r; + int i; + + opae_log("=====%s=====\n", __func__); + + switch (d->type) { + case OPAE_FPGA_PCI: + d_pci = (struct opae_adapter_data_pci *)d; + + opae_log("OPAE Adapter Type = PCI\n"); + opae_log("PCI Device ID: 0x%04x\n", d_pci->device_id); + opae_log("PCI Vendor ID: 0x%04x\n", d_pci->vendor_id); + + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + r = &d_pci->region[i]; + opae_log("PCI Bar %d: phy(%llx) len(%llx) addr(%p)\n", + i, (unsigned long long)r->phys_addr, + (unsigned long long)r->len, r->addr); + } + break; + case OPAE_FPGA_NET: + break; + } + + opae_log("==========================\n"); +} + +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) { + if (adapter->mgr) + opae_manager_dump(adapter->mgr); + + opae_adapter_for_each_acc(adapter, acc) + opae_accelerator_dump(acc); + + if (adapter->data) + opae_adapter_data_dump(adapter->data); + } + + opae_log("==========================\n"); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.h b/drivers/raw/ifpga_rawdev/base/opae_debug.h new file mode 100644 index 0000000..a03dff9 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_DEBUG_H_ +#define _OPAE_DEBUG_H_ + +#ifdef OPAE_HW_DEBUG +#define opae_log(fmt, args...) printf(fmt, ## args) +#else +#define opae_log(fme, args...) do {} while (0) +#endif + +void opae_manager_dump(struct opae_manager *mgr); +void opae_bridge_dump(struct opae_bridge *br); +void opae_accelerator_dump(struct opae_accelerator *acc); +void opae_adapter_dump(struct opae_adapter *adapter, int verbose); + +#endif /* _OPAE_DEBUG_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c new file mode 100644 index 0000000..a533dfe --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -0,0 +1,381 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_hw_api.h" +#include "opae_debug.h" +#include "ifpga_api.h" + +/* OPAE Bridge Functions */ + +/** + * opae_bridge_alloc - alloc opae_bridge data structure + * @name: bridge name. + * @ops: ops of this bridge. + * @data: private data of this bridge. + * + * Return opae_bridge on success, otherwise NULL. + */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data) +{ + struct opae_bridge *br = opae_zmalloc(sizeof(*br)); + + if (!br) + return NULL; + + br->name = name; + br->ops = ops; + br->data = data; + + opae_log("%s %p\n", __func__, br); + + return br; +} + +/** + * opae_bridge_reset - reset opae_bridge + * @br: bridge to be reset. + * + * Return: 0 on success, otherwise error code. + */ +int opae_bridge_reset(struct opae_bridge *br) +{ + if (!br) + return -EINVAL; + + if (br->ops && br->ops->reset) + return br->ops->reset(br); + + opae_log("%s no ops\n", __func__); + + return -ENOENT; +} + +/* Accelerator Functions */ + +/** + * opae_accelerator_alloc - alloc opae_accelerator data structure + * @name: accelerator name. + * @ops: ops of this accelerator. + * @data: private data of this accelerator. + * + * Return: opae_accelerator on success, otherwise NULL. + */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data) +{ + struct opae_accelerator *acc = opae_zmalloc(sizeof(*acc)); + + if (!acc) + return NULL; + + acc->name = name; + acc->ops = ops; + acc->data = data; + + opae_log("%s %p\n", __func__, acc); + + return acc; +} + +/** + * opae_acc_reg_read - read accelerator's register from its reg region. + * @acc: accelerator to read. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: read operation width, e.g 4 byte = 32bit read. + * @data: data to store the value read from the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->read) + return acc->ops->read(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_reg_write - write to accelerator's register from its reg region. + * @acc: accelerator to write. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: write operation width, e.g 4 byte = 32bit write. + * @data: data stored the value to write to the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->write) + return acc->ops->write(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_get_info - get information of an accelerator. + * @acc: targeted accelerator + * @info: accelerator info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_info) + return acc->ops->get_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_get_region_info - get information of an accelerator register region. + * @acc: targeted accelerator + * @info: accelerator region info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_region_info) + return acc->ops->get_region_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_set_irq - set an accelerator's irq. + * @acc: targeted accelerator + * @start: start vector number + * @count: count of vectors to be set from the start vector + * @evtfds: event fds to be notified when corresponding irqs happens + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + if (!acc || !acc->data) + return -EINVAL; + + if (start + count <= start) + return -EINVAL; + + if (acc->ops && acc->ops->set_irq) + return acc->ops->set_irq(acc, start, count, evtfds); + + return -ENOENT; +} + +/** + * opae_acc_get_uuid - get accelerator's UUID. + * @acc: targeted accelerator + * @uuid: a pointer to UUID + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + if (!acc || !uuid) + return -EINVAL; + + if (acc->ops && acc->ops->get_uuid) + return acc->ops->get_uuid(acc, uuid); + + return -ENOENT; +} + +/* Manager Functions */ + +/** + * opae_manager_alloc - alloc opae_manager data structure + * @name: manager name. + * @ops: ops of this manager. + * @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) +{ + struct opae_manager *mgr = opae_zmalloc(sizeof(*mgr)); + + if (!mgr) + return NULL; + + mgr->name = name; + mgr->ops = ops; + mgr->data = data; + + opae_log("%s %p\n", __func__, mgr); + + return mgr; +} + +/** + * opae_manager_flash - flash a reconfiguration image via opae_manager + * @mgr: opae_manager for flash. + * @id: id of target region (accelerator). + * @buf: image data buffer. + * @size: buffer size. + * @status: status to store flash result. + * + * Return: 0 on success, otherwise error code. + */ +int opae_manager_flash(struct opae_manager *mgr, int id, void *buf, u32 size, + u64 *status) +{ + if (!mgr) + return -EINVAL; + + if (mgr && mgr->ops && mgr->ops->flash) + return mgr->ops->flash(mgr, id, buf, size, status); + + return -ENOENT; +} + +/* Adapter Functions */ + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @type: opae_adapter_type. + * + * Return: opae_adapter_data on success, otherwise NULL. + */ +void *opae_adapter_data_alloc(enum opae_adapter_type type) +{ + struct opae_adapter_data *data; + int size; + + switch (type) { + case OPAE_FPGA_PCI: + size = sizeof(struct opae_adapter_data_pci); + break; + case OPAE_FPGA_NET: + size = sizeof(struct opae_adapter_data_net); + break; + default: + size = sizeof(struct opae_adapter_data); + break; + } + + data = opae_zmalloc(size); + if (!data) + return NULL; + + data->type = type; + + return data; +} + +static struct opae_adapter_ops *match_ops(struct opae_adapter *adapter) +{ + struct opae_adapter_data *data; + + if (!adapter || !adapter->data) + return NULL; + + data = adapter->data; + + if (data->type == OPAE_FPGA_PCI) + return &ifpga_adapter_ops; + + return NULL; +} + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @name: adapter name. + * @data: private data of this adapter. + * + * Return: opae_adapter on success, otherwise NULL. + */ +struct opae_adapter *opae_adapter_alloc(const char *name, void *data) +{ + struct opae_adapter *adapter = opae_zmalloc(sizeof(*adapter)); + + if (!adapter) + return NULL; + + TAILQ_INIT(&adapter->acc_list); + adapter->data = data; + adapter->name = name; + adapter->ops = match_ops(adapter); + + return adapter; +} + +/** + * opae_adapter_enumerate - enumerate this adapter + * @adapter: adapter to enumerate. + * + * Return: 0 on success, otherwise error code. + */ +int opae_adapter_enumerate(struct opae_adapter *adapter) +{ + int ret = -ENOENT; + + if (!adapter) + return -EINVAL; + + if (adapter->ops && adapter->ops->enumerate) + ret = adapter->ops->enumerate(adapter); + + if (!ret) + opae_adapter_dump(adapter, 1); + + return ret; +} + +/** + * opae_adapter_destroy - destroy this adapter + * @adapter: adapter to destroy. + * + * destroy things allocated during adapter enumeration. + */ +void opae_adapter_destroy(struct opae_adapter *adapter) +{ + if (adapter && adapter->ops && adapter->ops->destroy) + adapter->ops->destroy(adapter); +} + +/** + * opae_adapter_get_acc - find and return accelerator with matched id + * @adapter: adapter to find the accelerator. + * @acc_id: id (index) of the accelerator. + * + * destroy things allocated during adapter enumeration. + */ +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id) +{ + struct opae_accelerator *acc = NULL; + + if (!adapter) + return NULL; + + opae_adapter_for_each_acc(adapter, acc) + if (acc->index == acc_id) + return acc; + + return NULL; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h new file mode 100644 index 0000000..4bbc9df --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_HW_API_H_ +#define _OPAE_HW_API_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> + +#include "opae_osdep.h" + +#ifndef PCI_MAX_RESOURCE +#define PCI_MAX_RESOURCE 6 +#endif + +struct opae_adapter; + +enum opae_adapter_type { + OPAE_FPGA_PCI, + OPAE_FPGA_NET, +}; + +/* OPAE Manager Data Structure */ +struct opae_manager_ops; + +/* + * opae_manager has pointer to its parent adapter, as it could be able to manage + * all components on this FPGA device (adapter). If not the case, don't set this + * adapter, which limit opae_manager ops to manager itself. + */ +struct opae_manager { + const char *name; + struct opae_adapter *adapter; + struct opae_manager_ops *ops; + void *data; +}; + +/* FIXME: add more management ops, e.g power/thermal and etc */ +struct opae_manager_ops { + int (*flash)(struct opae_manager *mgr, int id, void *buffer, + u32 size, u64 *status); +}; + +/* OPAE Manager APIs */ +struct opae_manager * +opae_manager_alloc(const char *name, struct opae_manager_ops *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); + +/* OPAE Bridge Data Structure */ +struct opae_bridge_ops; + +/* + * opae_bridge only has pointer to its downstream accelerator. + */ +struct opae_bridge { + const char *name; + int id; + struct opae_accelerator *acc; + struct opae_bridge_ops *ops; + void *data; +}; + +struct opae_bridge_ops { + int (*reset)(struct opae_bridge *br); +}; + +/* OPAE Bridge APIs */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data); +int opae_bridge_reset(struct opae_bridge *br); +#define opae_bridge_free(br) opae_free(br) + +/* OPAE Acceleraotr Data Structure */ +struct opae_accelerator_ops; + +/* + * opae_accelerator has pointer to its upstream bridge(port). + * In some cases, if we allow same user to do PR on its own accelerator, then + * set the manager pointer during the enumeration. But in other cases, the PR + * functions only could be done via manager in another module / thread / service + * / application for better protection. + */ +struct opae_accelerator { + TAILQ_ENTRY(opae_accelerator) node; + const char *name; + int index; + struct opae_bridge *br; + struct opae_manager *mgr; + struct opae_accelerator_ops *ops; + void *data; +}; + +struct opae_acc_info { + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct opae_acc_region_info { + u32 flags; +#define ACC_REGION_READ (1 << 0) +#define ACC_REGION_WRITE (1 << 1) +#define ACC_REGION_MMIO (1 << 2) + u32 index; + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_accelerator_ops { + int (*read)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*write)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*get_info)(struct opae_accelerator *acc, + struct opae_acc_info *info); + int (*get_region_info)(struct opae_accelerator *acc, + struct opae_acc_region_info *info); + int (*set_irq)(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); + int (*get_uuid)(struct opae_accelerator *acc, + struct uuid *uuid); +}; + +/* OPAE accelerator APIs */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data); +#define opae_accelerator_free(acc) opae_free(acc) +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info); +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info); +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid); + +static inline struct opae_bridge * +opae_acc_get_br(struct opae_accelerator *acc) +{ + return acc ? acc->br : NULL; +} + +static inline struct opae_manager * +opae_acc_get_mgr(struct opae_accelerator *acc) +{ + return acc ? acc->mgr : NULL; +} + +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + +#define opae_acc_reg_read64(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 8, data) +#define opae_acc_reg_write64(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 8, data) +#define opae_acc_reg_read32(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 4, data) +#define opae_acc_reg_write32(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 4, data) +#define opae_acc_reg_read16(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 2, data) +#define opae_acc_reg_write16(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 2, data) +#define opae_acc_reg_read8(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 1, data) +#define opae_acc_reg_write8(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 1, data) + +/*for data stream read/write*/ +int opae_acc_data_read(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); +int opae_acc_data_write(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); + +/* OPAE Adapter Data Structure */ +struct opae_adapter_data { + enum opae_adapter_type type; +}; + +struct opae_reg_region { + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_adapter_data_pci { + enum opae_adapter_type type; + u16 device_id; + u16 vendor_id; + struct opae_reg_region region[PCI_MAX_RESOURCE]; + int vfio_dev_fd; /* VFIO device file descriptor */ +}; + +/* FIXME: OPAE_FPGA_NET type */ +struct opae_adapter_data_net { + enum opae_adapter_type type; +}; + +struct opae_adapter_ops { + int (*enumerate)(struct opae_adapter *adapter); + void (*destroy)(struct opae_adapter *adapter); +}; + +TAILQ_HEAD(opae_accelerator_list, opae_accelerator); + +#define opae_adapter_for_each_acc(adatper, acc) \ + TAILQ_FOREACH(acc, &adapter->acc_list, node) + +struct opae_adapter { + const char *name; + struct opae_manager *mgr; + struct opae_accelerator_list acc_list; + struct opae_adapter_ops *ops; + void *data; +}; + +/* OPAE Adapter APIs */ +void *opae_adapter_data_alloc(enum opae_adapter_type type); +#define opae_adapter_data_free(data) opae_free(data) + +struct opae_adapter *opae_adapter_alloc(const char *name, void *data); +#define opae_adapter_free(adapter) opae_free(adapter) + +int opae_adapter_enumerate(struct opae_adapter *adapter); +void opae_adapter_destroy(struct opae_adapter *adapter); +static inline struct opae_manager * +opae_adapter_get_mgr(struct opae_adapter *adapter) +{ + return adapter ? adapter->mgr : NULL; +} + +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id); + +static inline void opae_adapter_add_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_INSERT_TAIL(&adapter->acc_list, acc, node); +} + +static inline void opae_adapter_remove_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_REMOVE(&adapter->acc_list, acc, node); +} +#endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c new file mode 100644 index 0000000..a40c8da --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_ifpga_hw_api.h" +#include "ifpga_api.h" + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data || !fme_info) + return -EINVAL; + + fme = mgr->data; + + spinlock_lock(&fme->lock); + fme_info->capability = fme->capability; + spinlock_unlock(&fme->lock); + + return 0; +} + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_irq(fme->parent, FEATURE_FIU_ID_FME, 0, + IFPGA_FME_FEATURE_ID_GLOBAL_ERR, err_irq_set); +} + +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_get_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !port_info) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + port_info->capability = port->capability; + port_info->num_uafu_irqs = port->num_uafu_irqs; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !info) + return -EINVAL; + + /* Only support STP region now */ + if (info->index != PORT_REGION_INDEX_STP) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + info->addr = (u64)port->stp_addr; + info->size = port->stp_size; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_ERROR, err_irq_set); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h new file mode 100644 index 0000000..65086cf --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_IFPGA_HW_API_H_ +#define _OPAE_IFPGA_HW_API_H_ + +#include "opae_hw_api.h" + +/** + * struct feature_prop - data structure for feature property + * @feature_id: id of this feature. + * @prop_id: id of this property under this feature. + * @data: property value to set/get. + */ +struct feature_prop { + u64 feature_id; + u64 prop_id; + u64 data; +}; + +#define IFPGA_FIU_ID_FME 0x0 +#define IFPGA_FIU_ID_PORT 0x1 + +#define IFPGA_FME_FEATURE_ID_HEADER 0x0 +#define IFPGA_FME_FEATURE_ID_THERMAL_MGMT 0x1 +#define IFPGA_FME_FEATURE_ID_POWER_MGMT 0x2 +#define IFPGA_FME_FEATURE_ID_GLOBAL_IPERF 0x3 +#define IFPGA_FME_FEATURE_ID_GLOBAL_ERR 0x4 +#define IFPGA_FME_FEATURE_ID_PR_MGMT 0x5 +#define IFPGA_FME_FEATURE_ID_HSSI 0x6 +#define IFPGA_FME_FEATURE_ID_GLOBAL_DPERF 0x7 + +#define IFPGA_PORT_FEATURE_ID_HEADER 0x0 +#define IFPGA_PORT_FEATURE_ID_AFU 0xff +#define IFPGA_PORT_FEATURE_ID_ERROR 0x10 +#define IFPGA_PORT_FEATURE_ID_UMSG 0x11 +#define IFPGA_PORT_FEATURE_ID_UINT 0x12 +#define IFPGA_PORT_FEATURE_ID_STP 0x13 + +/* + * PROP format (TOP + SUB + ID) + * + * (~0x0) means this field is unused. + */ +#define PROP_TOP GENMASK(31, 24) +#define PROP_TOP_UNUSED 0xff +#define PROP_SUB GENMASK(23, 16) +#define PROP_SUB_UNUSED 0xff +#define PROP_ID GENMASK(15, 0) + +#define PROP(_top, _sub, _id) \ + (SET_FIELD(PROP_TOP, _top) | SET_FIELD(PROP_SUB, _sub) |\ + SET_FIELD(PROP_ID, _id)) + +/* FME head feature's properties*/ +#define FME_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define FME_HDR_PROP_PORTS_NUM 0x2 /* RDONLY */ +#define FME_HDR_PROP_CACHE_SIZE 0x3 /* RDONLY */ +#define FME_HDR_PROP_VERSION 0x4 /* RDONLY */ +#define FME_HDR_PROP_SOCKET_ID 0x5 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_ID 0x6 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_METADATA 0x7 /* RDONLY */ + +/* FME error reporting feature's properties */ +/* FME error reporting properties format */ +#define ERR_PROP(_top, _id) PROP(_top, 0xff, _id) +#define ERR_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define ERR_PROP_TOP_FME_ERR 0x1 +#define ERR_PROP_ROOT(_id) ERR_PROP(0xff, _id) +#define ERR_PROP_FME_ERR(_id) ERR_PROP(ERR_PROP_TOP_FME_ERR, _id) + +#define FME_ERR_PROP_ERRORS ERR_PROP_FME_ERR(0x1) +#define FME_ERR_PROP_FIRST_ERROR ERR_PROP_FME_ERR(0x2) +#define FME_ERR_PROP_NEXT_ERROR ERR_PROP_FME_ERR(0x3) +#define FME_ERR_PROP_CLEAR ERR_PROP_FME_ERR(0x4) /* WO */ +#define FME_ERR_PROP_REVISION ERR_PROP_ROOT(0x5) +#define FME_ERR_PROP_PCIE0_ERRORS ERR_PROP_ROOT(0x6) /* RW */ +#define FME_ERR_PROP_PCIE1_ERRORS ERR_PROP_ROOT(0x7) /* RW */ +#define FME_ERR_PROP_NONFATAL_ERRORS ERR_PROP_ROOT(0x8) +#define FME_ERR_PROP_CATFATAL_ERRORS ERR_PROP_ROOT(0x9) +#define FME_ERR_PROP_INJECT_ERRORS ERR_PROP_ROOT(0xa) /* RW */ + +/* FME thermal feature's properties */ +#define FME_THERMAL_PROP_THRESHOLD1 0x1 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD2 0x2 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD_TRIP 0x3 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_REACHED 0x4 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD2_REACHED 0x5 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_POLICY 0x6 /* RW */ +#define FME_THERMAL_PROP_TEMPERATURE 0x7 /* RDONLY */ +#define FME_THERMAL_PROP_REVISION 0x8 /* RDONLY */ + +/* FME power feature's properties */ +#define FME_PWR_PROP_CONSUMED 0x1 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD1 0x2 /* RW */ +#define FME_PWR_PROP_THRESHOLD2 0x3 /* RW */ +#define FME_PWR_PROP_THRESHOLD1_STATUS 0x4 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD2_STATUS 0x5 /* RDONLY */ +#define FME_PWR_PROP_RTL 0x6 /* RDONLY */ +#define FME_PWR_PROP_XEON_LIMIT 0x7 /* RDONLY */ +#define FME_PWR_PROP_FPGA_LIMIT 0x8 /* RDONLY */ +#define FME_PWR_PROP_REVISION 0x9 /* RDONLY */ + +/* FME iperf/dperf PROP format */ +#define PERF_PROP_TOP_CACHE 0x1 +#define PERF_PROP_TOP_VTD 0x2 +#define PERF_PROP_TOP_FAB 0x3 +#define PERF_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define PERF_PROP_SUB_UNUSED PROP_SUB_UNUSED + +#define PERF_PROP_ROOT(_id) PROP(0xff, 0xff, _id) +#define PERF_PROP_CACHE(_id) PROP(PERF_PROP_TOP_CACHE, 0xff, _id) +#define PERF_PROP_VTD(_sub, _id) PROP(PERF_PROP_TOP_VTD, _sub, _id) +#define PERF_PROP_VTD_ROOT(_id) PROP(PERF_PROP_TOP_VTD, 0xff, _id) +#define PERF_PROP_FAB(_sub, _id) PROP(PERF_PROP_TOP_FAB, _sub, _id) +#define PERF_PROP_FAB_ROOT(_id) PROP(PERF_PROP_TOP_FAB, 0xff, _id) + +/* FME iperf feature's properties */ +#define FME_IPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_IPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* iperf CACHE properties */ +#define FME_IPERF_PROP_CACHE_FREEZE PERF_PROP_CACHE(0x1) /* RW */ +#define FME_IPERF_PROP_CACHE_READ_HIT PERF_PROP_CACHE(0x2) +#define FME_IPERF_PROP_CACHE_READ_MISS PERF_PROP_CACHE(0x3) +#define FME_IPERF_PROP_CACHE_WRITE_HIT PERF_PROP_CACHE(0x4) +#define FME_IPERF_PROP_CACHE_WRITE_MISS PERF_PROP_CACHE(0x5) +#define FME_IPERF_PROP_CACHE_HOLD_REQUEST PERF_PROP_CACHE(0x6) +#define FME_IPERF_PROP_CACHE_TX_REQ_STALL PERF_PROP_CACHE(0x7) +#define FME_IPERF_PROP_CACHE_RX_REQ_STALL PERF_PROP_CACHE(0x8) +#define FME_IPERF_PROP_CACHE_RX_EVICTION PERF_PROP_CACHE(0x9) +#define FME_IPERF_PROP_CACHE_DATA_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xa) +#define FME_IPERF_PROP_CACHE_TAG_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xb) +/* iperf VTD properties */ +#define FME_IPERF_PROP_VTD_FREEZE PERF_PROP_VTD_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_HIT PERF_PROP_VTD_ROOT(0x2) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_HIT PERF_PROP_VTD_ROOT(0x3) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_HIT PERF_PROP_VTD_ROOT(0x4) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_HIT PERF_PROP_VTD_ROOT(0x5) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_HIT PERF_PROP_VTD_ROOT(0x6) +#define FME_IPERF_PROP_VTD_SIP_RCC_HIT PERF_PROP_VTD_ROOT(0x7) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_MISS PERF_PROP_VTD_ROOT(0x8) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_MISS PERF_PROP_VTD_ROOT(0x9) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_MISS PERF_PROP_VTD_ROOT(0xa) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_MISS PERF_PROP_VTD_ROOT(0xb) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_MISS PERF_PROP_VTD_ROOT(0xc) +#define FME_IPERF_PROP_VTD_SIP_RCC_MISS PERF_PROP_VTD_ROOT(0xd) +#define FME_IPERF_PROP_VTD_PORT_READ_TRANSACTION(n) PERF_PROP_VTD(n, 0xe) +#define FME_IPERF_PROP_VTD_PORT_WRITE_TRANSACTION(n) PERF_PROP_VTD(n, 0xf) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_READ_HIT(n) PERF_PROP_VTD(n, 0x10) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_WRITE_HIT(n) PERF_PROP_VTD(n, 0x11) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_4K_FILL(n) PERF_PROP_VTD(n, 0x12) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_2M_FILL(n) PERF_PROP_VTD(n, 0x13) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_1G_FILL(n) PERF_PROP_VTD(n, 0x14) +/* iperf FAB properties */ +#define FME_IPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_IPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_IPERF_PROP_FAB_PCIE1_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_IPERF_PROP_FAB_PCIE1_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_IPERF_PROP_FAB_UPI_READ PERF_PROP_FAB_ROOT(0x6) +#define FME_IPERF_PROP_FAB_PORT_UPI_READ(n) PERF_PROP_FAB(n, 0x6) +#define FME_IPERF_PROP_FAB_UPI_WRITE PERF_PROP_FAB_ROOT(0x7) +#define FME_IPERF_PROP_FAB_PORT_UPI_WRITE(n) PERF_PROP_FAB(n, 0x7) +#define FME_IPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x8) +#define FME_IPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x8) +#define FME_IPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x9) +#define FME_IPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x9) +#define FME_IPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0xa) /* RW */ +#define FME_IPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0xa) /* RW */ + +/* FME dperf properties */ +#define FME_DPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_DPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* dperf FAB properties */ +#define FME_DPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_DPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_DPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_DPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_DPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_DPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_DPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_DPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0x6) /* RW */ +#define FME_DPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0x6) /* RW */ + +/*PORT hdr feature's properties*/ +#define PORT_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_HDR_PROP_PORTIDX 0x2 /* RDONLY */ +#define PORT_HDR_PROP_LATENCY_TOLERANCE 0x3 /* RDONLY */ +#define PORT_HDR_PROP_AP1_EVENT 0x4 /* RW */ +#define PORT_HDR_PROP_AP2_EVENT 0x5 /* RW */ +#define PORT_HDR_PROP_POWER_STATE 0x6 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_FREQCMD 0x7 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQCNTRCMD 0x8 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQSTS 0x9 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_CNTRSTS 0xa /* RDONLY */ + +/*PORT error feature's properties*/ +#define PORT_ERR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_ERR_PROP_ERRORS 0x2 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_ERROR 0x3 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB 0x4 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB 0x5 /* RDONLY */ +#define PORT_ERR_PROP_CLEAR 0x6 /* WRONLY */ + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop); +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop); + +/* + * Retrieve information about the fpga fme. + * Driver fills the info in provided struct fpga_fme_info. + */ +struct fpga_fme_info { + u32 capability; /* The capability of FME device */ +#define FPGA_FME_CAP_ERR_IRQ (1 << 0) /* Support fme error interrupt */ +}; + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info); + +/* Set eventfd information for ifpga FME error interrupt */ +struct fpga_fme_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set); + +/* + * Retrieve information about the fpga port. + * Driver fills the info in provided struct fpga_port_info. + */ +struct fpga_port_info { + u32 capability; /* The capability of port device */ +#define FPGA_PORT_CAP_ERR_IRQ (1 << 0) /* Support port error interrupt */ +#define FPGA_PORT_CAP_UAFU_IRQ (1 << 1) /* Support uafu error interrupt */ + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ +}; + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info); +/* + * Retrieve region information about the fpga port. + * Driver needs to fill the index of struct fpga_port_region_info. + */ +struct fpga_port_region_info { + u32 index; +#define PORT_REGION_INDEX_STP (1 << 1) /* Signal Tap Region */ + u64 size; /* Region Size */ + u64 addr; /* Base address of the region */ +}; + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info); + +/* Set eventfd information for ifpga port error interrupt */ +struct fpga_port_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set); + +#endif /* _OPAE_IFPGA_HW_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h new file mode 100644 index 0000000..e9da710 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_OSDEP_H +#define _OPAE_OSDEP_H + +#include <string.h> +#include <stdbool.h> + +#ifdef RTE_LIBRTE_EAL +#include "osdep_rte/osdep_generic.h" +#else +#include "osdep_raw/osdep_generic.h" +#endif + +#include <asm/types.h> + +#define __iomem + +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef uint64_t dma_addr_t; + +struct uuid { + u8 b[16]; +}; + +#ifndef LINUX_MACROS +#ifndef BITS_PER_LONG +#define BITS_PER_LONG (__SIZEOF_LONG__ * 8) +#endif +#ifndef BIT +#define BIT(a) (1UL << (a)) +#endif /* BIT */ +#ifndef BIT_ULL +#define BIT_ULL(a) (1ULL << (a)) +#endif /* BIT_ULL */ +#ifndef GENMASK +#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#endif /* GENMASK */ +#ifndef GENMASK_ULL +#define GENMASK_ULL(h, l) (((U64_C(1) << ((h) - (l) + 1)) - 1) << (l)) +#endif /* GENMASK_ULL */ +#endif /* LINUX_MACROS */ + +#define SET_FIELD(m, v) (((v) << (__builtin_ffsll(m) - 1)) & (m)) +#define GET_FIELD(m, v) (((v) & (m)) >> (__builtin_ffsll(m) - 1)) + +#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) +#define pr_info(y, args...) dev_info(0, y, ##args) + +#ifndef WARN_ON +#define WARN_ON(x) do { \ + int ret = !!(x); \ + if (unlikely(ret)) \ + pr_warn("WARN_ON: \"" #x "\" at %s:%d\n", __func__, __LINE__); \ +} while (0) +#endif + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define udelay(x) opae_udelay(x) +#define msleep(x) opae_udelay(1000 * (x)) +#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000)) + +#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 new file mode 100644 index 0000000..895a1d8 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OSDEP_RAW_GENERIC_H +#define _OSDEP_RAW_GENERIC_H + +#define compiler_barrier() (asm volatile ("" : : : "memory")) + +#define io_wmb() compiler_barrier() +#define io_rmb() compiler_barrier() + +static inline uint8_t opae_readb(const volatile void *addr) +{ + uint8_t val; + + val = *(const volatile uint8_t *)addr; + io_rmb(); + return val; +} + +static inline uint16_t opae_readw(const volatile void *addr) +{ + uint16_t val; + + val = *(const volatile uint16_t *)addr; + io_rmb(); + return val; +} + +static inline uint32_t opae_readl(const volatile void *addr) +{ + uint32_t val; + + val = *(const volatile uint32_t *)addr; + io_rmb(); + return val; +} + +static inline uint64_t opae_readq(const volatile void *addr) +{ + uint64_t val; + + val = *(const volatile uint64_t *)addr; + io_rmb(); + return val; +} + +static inline void opae_writeb(uint8_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint8_t *)addr = value; +} + +static inline void opae_writew(uint16_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint16_t *)addr = value; +} + +static inline void opae_writel(uint32_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint32_t *)addr = value; +} + +static inline void opae_writeq(uint64_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint64_t *)addr = value; +} + +#define opae_free(addr) free(addr) + +#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 new file mode 100644 index 0000000..76902e2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OSDEP_RTE_GENERIC_H +#define _OSDEP_RTE_GENERIC_H + +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_spinlock.h> +#include <rte_log.h> +#include <rte_io.h> +#include <rte_malloc.h> + +#define dev_printf(level, fmt, args...) \ + RTE_LOG(level, PMD, "osdep_rte: " fmt, ## args) + +#define osdep_panic(...) rte_panic(...) + +#define opae_udelay(x) rte_delay_us(x) + +#define opae_readb(addr) rte_read8(addr) +#define opae_readw(addr) rte_read16(addr) +#define opae_readl(addr) rte_read32(addr) +#define opae_readq(addr) rte_read64(addr) +#define opae_writeb(value, addr) rte_write8(value, addr) +#define opae_writew(value, addr) rte_write16(value, addr) +#define opae_writel(value, addr) rte_write32(value, addr) +#define opae_writeq(value, addr) rte_write64(value, addr) + +#define opae_malloc(size) rte_malloc(NULL, size, 0) +#define opae_zmalloc(size) rte_zmalloc(NULL, size, 0) +#define opae_free(addr) rte_free(addr) + +#define ARRAY_SIZE(arr) RTE_DIM(arr) + +#define min(a, b) RTE_MIN(a, b) +#define max(a, b) RTE_MAX(a, b) + +#define spinlock_t rte_spinlock_t +#define spinlock_init(x) rte_spinlock_init(x) +#define spinlock_lock(x) rte_spinlock_lock(x) +#define spinlock_unlock(x) rte_spinlock_unlock(x) + +#endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v8 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 0/5] Introduce Intel FPGA BUS Xu, Rosen 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 1/5] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 2/5] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen @ 2018-05-06 8:40 ` Xu, Rosen 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 4/5] iFPGA: add meson build Xu, Rosen 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 5/5] iFPGA: add document for iFPGA driver Xu, Rosen 4 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-06 8:40 UTC (permalink / raw) To: dev Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Yanglong Wu From: Rosen Xu <rosen.xu@intel.com> Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev library. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> Signed-off-by: Figo zhang <tianfei.zhang@intel.com> Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> --- config/common_base | 1 + drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 ++ drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 608 +++++++++++++++++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ .../raw/ifpga_rawdev/rte_ifpga_rawdev_version.map | 4 + mk/rte.app.mk | 4 +- 7 files changed, 690 insertions(+), 1 deletion(-) create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map diff --git a/config/common_base b/config/common_base index bd4b356..650eda7 100644 --- a/config/common_base +++ b/config/common_base @@ -152,6 +152,7 @@ CONFIG_RTE_LIBRTE_VDEV_BUS=y # Compile the Intel FPGA bus # CONFIG_RTE_LIBRTE_IFPGA_BUS=y +CONFIG_RTE_LIBRTE_IFPGA_RAWDEV=y # # Compile ARK PMD diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index da7c8b4..6fc8f2f 100644 --- a/drivers/raw/Makefile +++ b/drivers/raw/Makefile @@ -5,5 +5,6 @@ include $(RTE_SDK)/mk/rte.vars.mk # DIRS-$(<configuration>) += <directory> DIRS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += skeleton_rawdev +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/raw/ifpga_rawdev/Makefile b/drivers/raw/ifpga_rawdev/Makefile new file mode 100644 index 0000000..66e2e34 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/Makefile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_ifpga_rawdev.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_bus_vdev +LDLIBS += -lrte_kvargs +LDLIBS += -lrte_bus_pci +LDLIBS += -lrte_bus_ifpga + +EXPORT_MAP := rte_ifpga_rawdev_version.map + +LIBABIVER := 1 + +VPATH += $(SRCDIR)/base + +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c new file mode 100644 index 0000000..81d9edf --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c @@ -0,0 +1,608 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <rte_log.h> +#include <rte_bus.h> +#include <rte_eal_memconfig.h> +#include <rte_malloc.h> +#include <rte_devargs.h> +#include <rte_memcpy.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include <rte_errno.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> +#include <rte_bus_vdev.h> + +#include "base/opae_hw_api.h" +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_common.h" +#include "ifpga_logs.h" +#include "ifpga_rawdev.h" + +int ifpga_rawdev_logtype; + +#define PCI_VENDOR_ID_INTEL 0x8086 +/* PCI Device ID */ +#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 +/* 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 RTE_MAX_RAW_DEVICE 10 + +static const struct rte_pci_id pci_ifpga_map[] = { + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_6_X) }, + { 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) }, + { .vendor_id = 0, /* sentinel */ }, +}; + +static int +ifpga_fill_afu_dev(struct opae_accelerator *acc, + struct rte_afu_device *afu_dev) +{ + struct rte_mem_resource *res = afu_dev->mem_resource; + struct opae_acc_region_info region_info; + struct opae_acc_info info; + unsigned long i; + int ret; + + ret = opae_acc_get_info(acc, &info); + if (ret) + return ret; + + if (info.num_regions > PCI_MAX_RESOURCE) + return -EFAULT; + + afu_dev->num_region = info.num_regions; + + for (i = 0; i < info.num_regions; i++) { + region_info.index = i; + ret = opae_acc_get_region_info(acc, ®ion_info); + if (ret) + return ret; + + if ((region_info.flags & ACC_REGION_MMIO) && + (region_info.flags & ACC_REGION_READ) && + (region_info.flags & ACC_REGION_WRITE)) { + res[i].phys_addr = region_info.phys_addr; + res[i].len = region_info.len; + res[i].addr = region_info.addr; + } else + return -EFAULT; + } + + return 0; +} + +static void +ifpga_rawdev_info_get(struct rte_rawdev *dev, + rte_rawdev_obj_t dev_info) +{ + struct opae_adapter *adapter; + struct opae_accelerator *acc; + struct rte_afu_device *afu_dev; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + if (!dev_info) { + IFPGA_RAWDEV_PMD_ERR("Invalid request"); + return; + } + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return; + + afu_dev = dev_info; + afu_dev->rawdev = dev; + + /* find opae_accelerator and fill info into afu_device */ + opae_adapter_for_each_acc(adapter, acc) { + if (acc->index != afu_dev->id.port) + continue; + + if (ifpga_fill_afu_dev(acc, afu_dev)) { + IFPGA_RAWDEV_PMD_ERR("cannot get info\n"); + return; + } + } +} + +static int +ifpga_rawdev_start(struct rte_rawdev *dev) +{ + int ret = 0; + struct opae_adapter *adapter; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + return ret; +} + +static void +ifpga_rawdev_stop(struct rte_rawdev *dev) +{ + dev->started = 0; +} + +static int +ifpga_rawdev_close(struct rte_rawdev *dev) +{ + return dev ? 0:1; +} + +static int +ifpga_rawdev_reset(struct rte_rawdev *dev) +{ + return dev ? 0:1; +} + +static int +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, + u64 *status) +{ + + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_accelerator *acc; + struct opae_bridge *br; + int ret; + + adapter = ifpga_rawdev_get_priv(raw_dev); + if (!adapter) + return -ENODEV; + + mgr = opae_adapter_get_mgr(adapter); + if (!mgr) + return -ENODEV; + + acc = opae_adapter_get_acc(adapter, port_id); + if (!acc) + return -ENODEV; + + br = opae_acc_get_br(acc); + if (!br) + return -ENODEV; + + ret = opae_manager_flash(mgr, port_id, buffer, size, status); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("%s pr error %d\n", __func__, ret); + return ret; + } + + ret = opae_bridge_reset(br); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("%s reset port:%d error %d\n", + __func__, port_id, ret); + return ret; + } + + return ret; +} + +static int +rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, + const char *file_name) +{ + struct stat file_stat; + int file_fd; + int ret = 0; + u32 buffer_size; + void *buffer; + u64 pr_error; + + if (!file_name) + return -EINVAL; + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + IFPGA_RAWDEV_PMD_ERR("%s: open file error: %s\n", + __func__, file_name); + IFPGA_RAWDEV_PMD_ERR("Message : %s\n", strerror(errno)); + return -EINVAL; + } + ret = stat(file_name, &file_stat); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("stat on bitstream file failed: %s\n", + file_name); + return -EINVAL; + } + buffer_size = file_stat.st_size; + IFPGA_RAWDEV_PMD_INFO("bitstream file size: %u\n", buffer_size); + buffer = rte_malloc(NULL, buffer_size, 0); + if (!buffer) { + ret = -ENOMEM; + goto close_fd; + } + + /*read the raw data*/ + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { + ret = -EINVAL; + goto free_buffer; + } + + /*do PR now*/ + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); + IFPGA_RAWDEV_PMD_INFO("downloading to device port %d....%s.\n", port_id, + ret ? "failed" : "success"); + if (ret) { + ret = -EINVAL; + goto free_buffer; + } + +free_buffer: + if (buffer) + rte_free(buffer); +close_fd: + close(file_fd); + file_fd = 0; + return ret; +} + +static int +ifpga_rawdev_pr(struct rte_rawdev *dev, + rte_rawdev_obj_t pr_conf) +{ + struct opae_adapter *adapter; + struct rte_afu_pr_conf *afu_pr_conf; + int ret; + struct uuid uuid; + struct opae_accelerator *acc; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + if (!pr_conf) + return -EINVAL; + + afu_pr_conf = pr_conf; + + if (afu_pr_conf->pr_enable) { + ret = rte_fpga_do_pr(dev, + afu_pr_conf->afu_id.port, + afu_pr_conf->bs_path); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("do pr error %d\n", ret); + return ret; + } + } + + acc = opae_adapter_get_acc(adapter, afu_pr_conf->afu_id.port); + if (!acc) + return -ENODEV; + + ret = opae_acc_get_uuid(acc, &uuid); + if (ret) + return ret; + + memcpy(&afu_pr_conf->afu_id.uuid.uuid_low, uuid.b, sizeof(u64)); + memcpy(&afu_pr_conf->afu_id.uuid.uuid_high, uuid.b + 8, sizeof(u64)); + + IFPGA_RAWDEV_PMD_INFO("%s: uuid_l=0x%lx, uuid_h=0x%lx\n", __func__, + (u64)afu_pr_conf->afu_id.uuid.uuid_low, + (u64)afu_pr_conf->afu_id.uuid.uuid_high); + + return 0; +} + +static const struct rte_rawdev_ops ifpga_rawdev_ops = { + .dev_info_get = ifpga_rawdev_info_get, + .dev_configure = NULL, + .dev_start = ifpga_rawdev_start, + .dev_stop = ifpga_rawdev_stop, + .dev_close = ifpga_rawdev_close, + .dev_reset = ifpga_rawdev_reset, + + .queue_def_conf = NULL, + .queue_setup = NULL, + .queue_release = NULL, + + .attr_get = NULL, + .attr_set = NULL, + + .enqueue_bufs = NULL, + .dequeue_bufs = NULL, + + .dump = NULL, + + .xstats_get = NULL, + .xstats_get_names = NULL, + .xstats_get_by_name = NULL, + .xstats_reset = NULL, + + .firmware_status_get = NULL, + .firmware_version_get = NULL, + .firmware_load = ifpga_rawdev_pr, + .firmware_unload = NULL, + + .dev_selftest = NULL, +}; + +static int +ifpga_rawdev_create(struct rte_pci_device *pci_dev, + int socket_id) +{ + int ret = 0; + struct rte_rawdev *rawdev = NULL; + struct opae_adapter *adapter = NULL; + struct opae_manager *mgr = NULL; + struct opae_adapter_data_pci *data = NULL; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + int i; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + goto cleanup; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id()); + + /* Allocate device structure */ + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct opae_adapter), + socket_id); + if (rawdev == NULL) { + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); + ret = -EINVAL; + goto cleanup; + } + + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API */ + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); + if (!data) { + ret = -ENOMEM; + goto cleanup; + } + + /* init opae_adapter_data_pci for device specific information */ + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + data->region[i].phys_addr = pci_dev->mem_resource[i].phys_addr; + data->region[i].len = pci_dev->mem_resource[i].len; + data->region[i].addr = pci_dev->mem_resource[i].addr; + } + data->device_id = pci_dev->id.device_id; + data->vendor_id = pci_dev->id.vendor_id; + + /* create a opae_adapter based on above device data */ + adapter = opae_adapter_alloc(pci_dev->device.name, data); + if (!adapter) { + ret = -ENOMEM; + goto free_adapter_data; + } + + rawdev->dev_ops = &ifpga_rawdev_ops; + rawdev->device = &pci_dev->device; + rawdev->driver_name = pci_dev->device.driver->name; + + rawdev->dev_private = adapter; + + /* must enumerate the adapter before use it */ + ret = opae_adapter_enumerate(adapter); + if (ret) + goto free_adapter; + + /* get opae_manager to rawdev */ + mgr = opae_adapter_get_mgr(adapter); + if (mgr) { + /* PF function */ + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); + } + + return ret; + +free_adapter: + if (adapter) + opae_adapter_free(adapter); +free_adapter_data: + if (data) + opae_adapter_data_free(data); +cleanup: + if (rawdev) + rte_rawdev_pmd_release(rawdev); + + return ret; +} + +static int +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) +{ + int ret; + struct rte_rawdev *rawdev; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + struct opae_adapter *adapter; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + return ret; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", + name, rte_socket_id()); + + rawdev = rte_rawdev_pmd_get_named_dev(name); + if (!rawdev) { + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name); + return -EINVAL; + } + + adapter = ifpga_rawdev_get_priv(rawdev); + if (!adapter) + return -ENODEV; + + opae_adapter_data_free(adapter->data); + opae_adapter_free(adapter); + + /* rte_rawdev_close is called by pmd_release */ + ret = rte_rawdev_pmd_release(rawdev); + if (ret) + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); + + return ret; +} + +static int +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()); +} + +static int +ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) +{ + return ifpga_rawdev_destroy(pci_dev); +} + +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { + .id_table = pci_ifpga_map, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, + .probe = ifpga_rawdev_pci_probe, + .remove = ifpga_rawdev_pci_remove, +}; + +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | uio_pci_generic | vfio-pci"); + +RTE_INIT(ifpga_rawdev_init_log); +static void +ifpga_rawdev_init_log(void) +{ + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); + if (ifpga_rawdev_logtype >= 0) + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +static int +ifpga_cfg_probe(struct rte_vdev_device *dev) +{ + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + int port; + char *name = NULL; + char dev_name[RTE_RAWDEV_NAME_MAX_LEN]; + + devargs = dev->device.devargs; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &ifpga_get_string_arg, &name) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, + IFPGA_ARG_PORT, + &ifpga_get_integer32_arg, + &port) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + memset(dev_name, 0, sizeof(dev_name)); + snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s", + port, name); + + rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), + dev_name, devargs->args); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +static int +ifpga_cfg_remove(struct rte_vdev_device *vdev) +{ + IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p", + vdev); + + return 0; +} + +static struct rte_vdev_driver ifpga_cfg_driver = { + .probe = ifpga_cfg_probe, + .remove = ifpga_cfg_remove, +}; + +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, + "bdf=<string> " + "port=<int> " + "afu_bts=<path>"); + diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h new file mode 100644 index 0000000..c7759b8 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_RAWDEV_H_ +#define _IFPGA_RAWDEV_H_ + +extern int ifpga_rawdev_logtype; + +#define IFPGA_RAWDEV_PMD_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_rawdev_logtype, "ifgpa: " fmt, \ + ##args) + +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") + +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) +#define IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) +#define IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) +#define IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) + +enum ifpga_rawdev_device_state { + IFPGA_IDLE, + IFPGA_READY, + IFPGA_ERROR +}; + +static inline struct opae_adapter * +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) +{ + return rawdev->dev_private; +} + +#endif /* _IFPGA_RAWDEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map new file mode 100644 index 0000000..9b9ab1a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/rte_ifpga_rawdev_version.map @@ -0,0 +1,4 @@ +DPDK_18.05 { + + local: *; +}; diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 8b10c2a..107b5f2 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -252,9 +252,11 @@ endif # CONFIG_RTE_LIBRTE_EVENTDEV ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV) += -lrte_pmd_skeleton_rawdev _LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga +ifeq ($(CONFIG_RTE_LIBRTE_IFPGA_BUS),y) +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += -lrte_ifpga_rawdev +endif # CONFIG_RTE_LIBRTE_IFPGA_BUS endif # CONFIG_RTE_LIBRTE_RAWDEV - endif # !CONFIG_RTE_BUILD_SHARED_LIBS _LDLIBS-y += --no-whole-archive -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v8 4/5] iFPGA: add meson build 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 0/5] Introduce Intel FPGA BUS Xu, Rosen ` (2 preceding siblings ...) 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen @ 2018-05-06 8:40 ` Xu, Rosen 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 5/5] iFPGA: add document for iFPGA driver Xu, Rosen 4 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-06 8:40 UTC (permalink / raw) To: dev Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: Figo Zhang <tianfei.zhang@intel.com> add meson build support for iFPGA driver. Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> --- drivers/raw/ifpga_rawdev/base/meson.build | 34 +++++++++++++++++++++++++++++++ drivers/raw/ifpga_rawdev/meson.build | 15 ++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build create mode 100644 drivers/raw/ifpga_rawdev/meson.build diff --git a/drivers/raw/ifpga_rawdev/base/meson.build b/drivers/raw/ifpga_rawdev/base/meson.build new file mode 100644 index 0000000..cb65535 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/meson.build @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +sources = [ + 'ifpga_api.c', + 'ifpga_enumerate.c', + 'ifpga_feature_dev.c', + 'ifpga_fme.c', + 'ifpga_fme_iperf.c', + 'ifpga_fme_dperf.c', + 'ifpga_fme_error.c', + 'ifpga_port.c', + 'ifpga_port_error.c', + 'ifpga_fme_pr.c', + 'opae_hw_api.c', + 'opae_ifpga_hw_api.c', + 'opae_debug.c' +] + +error_cflags = ['-Wno-sign-compare', '-Wno-unused-value', + '-Wno-format', '-Wno-unused-but-set-variable', + '-Wno-strict-aliasing' +] +c_args = cflags +foreach flag: error_cflags + if cc.has_argument(flag) + c_args += flag + endif +endforeach + +base_lib = static_library('ifpga_rawdev_base', sources, + dependencies: static_rte_eal, + c_args: c_args) +base_objs = base_lib.extract_all_objects() diff --git a/drivers/raw/ifpga_rawdev/meson.build b/drivers/raw/ifpga_rawdev/meson.build new file mode 100644 index 0000000..6725687 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/meson.build @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +version = 1 + +subdir('base') +objs = [base_objs] + +deps += ['rawdev', 'pci', 'bus_pci', 'kvargs', + 'bus_vdev', 'bus_ifpga'] +sources = files('ifpga_rawdev.c') + +includes += include_directories('base') + +allow_experimental_apis = true -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v8 5/5] iFPGA: add document for iFPGA driver 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 0/5] Introduce Intel FPGA BUS Xu, Rosen ` (3 preceding siblings ...) 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 4/5] iFPGA: add meson build Xu, Rosen @ 2018-05-06 8:40 ` Xu, Rosen 2018-05-06 11:54 ` Shreyansh Jain 4 siblings, 1 reply; 149+ messages in thread From: Xu, Rosen @ 2018-05-06 8:40 UTC (permalink / raw) To: dev Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: Figo Zhang <tianfei.zhang@intel.com> add some introduction, motivation and usage for iFPGA driver. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> --- doc/guides/rawdevs/ifpga_rawdev.rst | 112 +++++++++++++++++++++++++++++++++ doc/guides/rel_notes/release_18_05.rst | 13 ++++ 2 files changed, 125 insertions(+) create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst diff --git a/doc/guides/rawdevs/ifpga_rawdev.rst b/doc/guides/rawdevs/ifpga_rawdev.rst new file mode 100644 index 0000000..37ae4cc --- /dev/null +++ b/doc/guides/rawdevs/ifpga_rawdev.rst @@ -0,0 +1,112 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2018 Intel Corporation. + +IFPGA Rawdev Driver +====================== + +FPGA is used more and more widely in Cloud and NFV, one primary reason is +that FPGA not only provides ASIC performance but also it's more flexible +than ASIC. + +FPGA uses Partial Reconfigure (PR) Parts of Bit Stream to achieve its +flexibility. That means one FPGA Device Bit Stream is divided into many Parts +of Bit Stream(each Part of Bit Stream is defined as AFU-Accelerated Function +Unit), and each AFU is a hardware acceleration unit which can be dynamically +reloaded respectively. + +By PR (Partial Reconfiguration) AFUs, one FPGA resources can be time-shared by +different users. FPGA hot upgrade and fault tolerance can be provided easily. + +The SW IFPGA Rawdev Driver (**ifpga_rawdev**) provides a Rawdev driver +that utilizes Intel FPGA Software Stack OPAE(Open Programmable Acceleration +Engine) for FPGA management. + +Implementation details +---------------------- + +Each instance of IFPGA Rawdev Driver is probed by Intel FpgaDev. In coordination +with OPAE share code IFPGA Rawdev Driver provides common FPGA management ops +for FPGA operation, OPAE provides all following operations: +- FPGA PR (Partial Reconfiguration) management +- FPGA AFUs Identifying +- FPGA Thermal Management +- FPGA Power Management +- FPGA Performance reporting +- FPGA Remote Debug + +All configuration parameters are taken by vdev_ifpga_cfg driver. Besides +configuration, vdev_ifpga_cfg driver also hot plugs in IFPGA Bus. + +All of the AFUs of one FPGA may share same PCI BDF and AFUs scan depend on +IFPGA Rawdev Driver so IFPGA Bus takes AFU device scan and AFU drivers probe. +All AFU device driver bind to AFU device by its UUID (Universally Unique +Identifier). + +To avoid unnecessary code duplication and ensure maximum performance, +handling of AFU devices is left to different PMDs; all the design as +summarized by the following block diagram:: + + +---------------------------------------------------------------+ + | Application(s) | + +----------------------------.----------------------------------+ + | + | + +----------------------------'----------------------------------+ + | DPDK Framework (APIs) | + +----------|------------|--------.---------------------|--------+ + / \ | + / \ | + +-------'-------+ +-------'-------+ +--------'--------+ + | Eth PMD | | Crypto PMD | | | + +-------.-------+ +-------.-------+ | | + | | | | + | | | | + +-------'-------+ +-------'-------+ | IFPGA | + | Eth AFU Dev | |Crypto AFU Dev | | Rawdev Driver | + +-------.-------+ +-------.-------+ |(OPAE Share Code)| + | | | | + | | Rawdev | | + +-------'------------------'-------+ Ops | | + | IFPGA Bus | -------->| | + +-----------------.----------------+ +--------.--------+ + | | + Hot-plugin -->| | + | | + +-----------------'------------------+ +--------'--------+ + | vdev_ifpga_cfg driver | | Intel FpgaDev | + +------------------------------------+ +-----------------+ + +Build options +------------- + +- ``CONFIG_RTE_LIBRTE_IFPGA_BUS`` (default ``y``) + + Toggle compilation of IFPGA Bus library. + +- ``CONFIG_RTE_LIBRTE_IFPGA_RAWDEV`` (default ``y``) + + Toggle compilation of the ``ifpga_rawdev`` driver. + +Run-time parameters +------------------- + +This driver is invoked automatically in systems added with Intel FPGA, +but PR and IFPGA Bus scan is trigged by command line using +``--vdev 'net_ifpga_cfg`` EAL option. + +The following device parameters are supported: + +- ``ifpga`` [string] + + Provide a specific Intel FPGA device PCI BDF. Can be provided multiple + times for additional instances. + +- ``port`` [int] + + Each FPGA can provide many channels to PR AFU by software, each channels + is identified by this parameter. + +- ``afu_bts`` [string] + + If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and + identifies AFU Bit Stream file. diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst index 0ae61e8..77b96e2 100644 --- a/doc/guides/rel_notes/release_18_05.rst +++ b/doc/guides/rel_notes/release_18_05.rst @@ -164,6 +164,19 @@ New Features stats/xstats on shared memory from secondary process, and also pdump packets on those virtual devices. +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** + + The Ifpga Bus library provides support for integrating any Intel FPGA device with + the DPDK framework. It provides Intel FPGA Partial Bit Stream AFU(Accelerated + Function Unit) scan and drivers prove. + +* **Added IFPGA(Intel FPGA) Rawdev Driver.** + + Added a new Rawdev driver called IFPGA(Intel FPGA) Rawdev Driver, which cooperates + with OPAE(Open Programmable Acceleration Engine) share code provides common FPGA + management ops for FPGA operation. + + See the :doc:`../rawdevs/ifpga_rawdev` programmer's guide for more details. API Changes ----------- -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v8 5/5] iFPGA: add document for iFPGA driver 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 5/5] iFPGA: add document for iFPGA driver Xu, Rosen @ 2018-05-06 11:54 ` Shreyansh Jain 2018-05-06 14:24 ` Zhang, Tianfei 0 siblings, 1 reply; 149+ messages in thread From: Shreyansh Jain @ 2018-05-06 11:54 UTC (permalink / raw) To: Xu, Rosen, dev, thomas Cc: declan.doherty, bruce.richardson, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet Hi Rosen, > -----Original Message----- > From: Xu, Rosen [mailto:rosen.xu@intel.com] > Sent: Sunday, May 6, 2018 2:11 PM > To: dev@dpdk.org > Cc: rosen.xu@intel.com; declan.doherty@intel.com; > bruce.richardson@intel.com; Shreyansh Jain <shreyansh.jain@nxp.com>; > ferruh.yigit@intel.com; konstantin.ananyev@intel.com; > tianfei.zhang@intel.com; song.liu@intel.com; hao.wu@intel.com; > gaetan.rivet@6wind.com > Subject: [PATCH v8 5/5] iFPGA: add document for iFPGA driver > > From: Figo Zhang <tianfei.zhang@intel.com> > > add some introduction, motivation and usage for iFPGA driver. > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> > --- > doc/guides/rawdevs/ifpga_rawdev.rst | 112 > +++++++++++++++++++++++++++++++++ > doc/guides/rel_notes/release_18_05.rst | 13 ++++ > 2 files changed, 125 insertions(+) > create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst > > diff --git a/doc/guides/rawdevs/ifpga_rawdev.rst > b/doc/guides/rawdevs/ifpga_rawdev.rst > new file mode 100644 > index 0000000..37ae4cc > --- /dev/null > +++ b/doc/guides/rawdevs/ifpga_rawdev.rst > @@ -0,0 +1,112 @@ > +.. SPDX-License-Identifier: BSD-3-Clause > + Copyright(c) 2018 Intel Corporation. > + > +IFPGA Rawdev Driver > +====================== > + > +FPGA is used more and more widely in Cloud and NFV, one primary reason > is > +that FPGA not only provides ASIC performance but also it's more > flexible > +than ASIC. > + > +FPGA uses Partial Reconfigure (PR) Parts of Bit Stream to achieve its > +flexibility. That means one FPGA Device Bit Stream is divided into > many Parts > +of Bit Stream(each Part of Bit Stream is defined as AFU-Accelerated > Function > +Unit), and each AFU is a hardware acceleration unit which can be > dynamically > +reloaded respectively. > + > +By PR (Partial Reconfiguration) AFUs, one FPGA resources can be time- > shared by > +different users. FPGA hot upgrade and fault tolerance can be provided > easily. > + > +The SW IFPGA Rawdev Driver (**ifpga_rawdev**) provides a Rawdev driver > +that utilizes Intel FPGA Software Stack OPAE(Open Programmable > Acceleration > +Engine) for FPGA management. > + > +Implementation details > +---------------------- > + > +Each instance of IFPGA Rawdev Driver is probed by Intel FpgaDev. In > coordination > +with OPAE share code IFPGA Rawdev Driver provides common FPGA > management ops > +for FPGA operation, OPAE provides all following operations: > +- FPGA PR (Partial Reconfiguration) management > +- FPGA AFUs Identifying > +- FPGA Thermal Management > +- FPGA Power Management > +- FPGA Performance reporting > +- FPGA Remote Debug > + > +All configuration parameters are taken by vdev_ifpga_cfg driver. > Besides > +configuration, vdev_ifpga_cfg driver also hot plugs in IFPGA Bus. > + > +All of the AFUs of one FPGA may share same PCI BDF and AFUs scan > depend on > +IFPGA Rawdev Driver so IFPGA Bus takes AFU device scan and AFU drivers > probe. > +All AFU device driver bind to AFU device by its UUID (Universally > Unique > +Identifier). > + > +To avoid unnecessary code duplication and ensure maximum performance, > +handling of AFU devices is left to different PMDs; all the design as > +summarized by the following block diagram:: > + > + +---------------------------------------------------------------+ > + | Application(s) | > + +----------------------------.----------------------------------+ > + | > + | > + +----------------------------'----------------------------------+ > + | DPDK Framework (APIs) | > + +----------|------------|--------.---------------------|--------+ > + / \ | > + / \ | > + +-------'-------+ +-------'-------+ +--------'--------+ > + | Eth PMD | | Crypto PMD | | | > + +-------.-------+ +-------.-------+ | | > + | | | | > + | | | | > + +-------'-------+ +-------'-------+ | IFPGA | > + | Eth AFU Dev | |Crypto AFU Dev | | Rawdev Driver | > + +-------.-------+ +-------.-------+ |(OPAE Share Code)| > + | | | | > + | | Rawdev | | > + +-------'------------------'-------+ Ops | | > + | IFPGA Bus | -------->| | > + +-----------------.----------------+ +--------.--------+ > + | | > + Hot-plugin -->| | > + | | > + +-----------------'------------------+ +--------'--------+ > + | vdev_ifpga_cfg driver | | Intel FpgaDev | > + +------------------------------------+ +-----------------+ > + > +Build options > +------------- > + > +- ``CONFIG_RTE_LIBRTE_IFPGA_BUS`` (default ``y``) > + > + Toggle compilation of IFPGA Bus library. > + > +- ``CONFIG_RTE_LIBRTE_IFPGA_RAWDEV`` (default ``y``) > + > + Toggle compilation of the ``ifpga_rawdev`` driver. > + > +Run-time parameters > +------------------- > + > +This driver is invoked automatically in systems added with Intel FPGA, > +but PR and IFPGA Bus scan is trigged by command line using > +``--vdev 'net_ifpga_cfg`` EAL option. > + > +The following device parameters are supported: > + > +- ``ifpga`` [string] > + > + Provide a specific Intel FPGA device PCI BDF. Can be provided > multiple > + times for additional instances. > + > +- ``port`` [int] > + > + Each FPGA can provide many channels to PR AFU by software, each > channels > + is identified by this parameter. > + > +- ``afu_bts`` [string] > + > + If null, the AFU Bit Stream has been PR in FPGA, if not forces PR > and > + identifies AFU Bit Stream file. [...] If you don't introduce this file into doc/guides/rawdevs/index.rst (like your v7), the doc index won't be generated. I think you misunderstood my comment in [1] - I meant that you will have to rebase over CMDIF because it has already introduced the doc/guides/rawdevs/index.rst file. Your patch v7 was adding this file. It would have conflicted for Thomas' eventual merge. [1] http://dpdk.org/ml/archives/dev/2018-May/100313.html Unfortunately, you might have to send a v9 or maybe Thomas can take care of this while merging. ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v8 5/5] iFPGA: add document for iFPGA driver 2018-05-06 11:54 ` Shreyansh Jain @ 2018-05-06 14:24 ` Zhang, Tianfei 0 siblings, 0 replies; 149+ messages in thread From: Zhang, Tianfei @ 2018-05-06 14:24 UTC (permalink / raw) To: Shreyansh Jain, Xu, Rosen, dev, thomas Cc: Doherty, Declan, Richardson, Bruce, Yigit, Ferruh, Ananyev, Konstantin, Liu, Song, Wu, Hao, gaetan.rivet > -----Original Message----- > From: Shreyansh Jain [mailto:shreyansh.jain@nxp.com] > Sent: Sunday, May 6, 2018 7:54 PM > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; > thomas@monjalon.net > Cc: Doherty, Declan <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; Yigit, Ferruh <ferruh.yigit@intel.com>; > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Tianfei > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > <hao.wu@intel.com>; gaetan.rivet@6wind.com > Subject: RE: [PATCH v8 5/5] iFPGA: add document for iFPGA driver > > Hi Rosen, > > > -----Original Message----- > > From: Xu, Rosen [mailto:rosen.xu@intel.com] > > Sent: Sunday, May 6, 2018 2:11 PM > > To: dev@dpdk.org > > Cc: rosen.xu@intel.com; declan.doherty@intel.com; > > bruce.richardson@intel.com; Shreyansh Jain <shreyansh.jain@nxp.com>; > > ferruh.yigit@intel.com; konstantin.ananyev@intel.com; > > tianfei.zhang@intel.com; song.liu@intel.com; hao.wu@intel.com; > > gaetan.rivet@6wind.com > > Subject: [PATCH v8 5/5] iFPGA: add document for iFPGA driver > > > > From: Figo Zhang <tianfei.zhang@intel.com> > > > > add some introduction, motivation and usage for iFPGA driver. > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> > > --- > > doc/guides/rawdevs/ifpga_rawdev.rst | 112 > > +++++++++++++++++++++++++++++++++ > > doc/guides/rel_notes/release_18_05.rst | 13 ++++ > > 2 files changed, 125 insertions(+) > > create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst > > > > diff --git a/doc/guides/rawdevs/ifpga_rawdev.rst > > b/doc/guides/rawdevs/ifpga_rawdev.rst > > new file mode 100644 > > index 0000000..37ae4cc > > --- /dev/null > > +++ b/doc/guides/rawdevs/ifpga_rawdev.rst > > @@ -0,0 +1,112 @@ > > +.. SPDX-License-Identifier: BSD-3-Clause > > + Copyright(c) 2018 Intel Corporation. > > + > > +IFPGA Rawdev Driver > > +====================== > > + > > +FPGA is used more and more widely in Cloud and NFV, one primary > > +reason > > is > > +that FPGA not only provides ASIC performance but also it's more > > flexible > > +than ASIC. > > + > > +FPGA uses Partial Reconfigure (PR) Parts of Bit Stream to achieve its > > +flexibility. That means one FPGA Device Bit Stream is divided into > > many Parts > > +of Bit Stream(each Part of Bit Stream is defined as AFU-Accelerated > > Function > > +Unit), and each AFU is a hardware acceleration unit which can be > > dynamically > > +reloaded respectively. > > + > > +By PR (Partial Reconfiguration) AFUs, one FPGA resources can be time- > > shared by > > +different users. FPGA hot upgrade and fault tolerance can be provided > > easily. > > + > > +The SW IFPGA Rawdev Driver (**ifpga_rawdev**) provides a Rawdev > > +driver that utilizes Intel FPGA Software Stack OPAE(Open Programmable > > Acceleration > > +Engine) for FPGA management. > > + > > +Implementation details > > +---------------------- > > + > > +Each instance of IFPGA Rawdev Driver is probed by Intel FpgaDev. In > > coordination > > +with OPAE share code IFPGA Rawdev Driver provides common FPGA > > management ops > > +for FPGA operation, OPAE provides all following operations: > > +- FPGA PR (Partial Reconfiguration) management > > +- FPGA AFUs Identifying > > +- FPGA Thermal Management > > +- FPGA Power Management > > +- FPGA Performance reporting > > +- FPGA Remote Debug > > + > > +All configuration parameters are taken by vdev_ifpga_cfg driver. > > Besides > > +configuration, vdev_ifpga_cfg driver also hot plugs in IFPGA Bus. > > + > > +All of the AFUs of one FPGA may share same PCI BDF and AFUs scan > > depend on > > +IFPGA Rawdev Driver so IFPGA Bus takes AFU device scan and AFU > > +drivers > > probe. > > +All AFU device driver bind to AFU device by its UUID (Universally > > Unique > > +Identifier). > > + > > +To avoid unnecessary code duplication and ensure maximum > performance, > > +handling of AFU devices is left to different PMDs; all the design as > > +summarized by the following block diagram:: > > + > > + +---------------------------------------------------------------+ > > + | Application(s) > | > > + +----------------------------.----------------------------------+ > > + | > > + | > > + +----------------------------'----------------------------------+ > > + | DPDK Framework (APIs) > | > > + +----------|------------|--------.---------------------|--------+ > > + / \ > | > > + / \ > | > > + +-------'-------+ +-------'-------+ +--------'--------+ > > + | Eth PMD | | Crypto PMD | | > | > > + +-------.-------+ +-------.-------+ | | > > + | | | > | > > + | | | > | > > + +-------'-------+ +-------'-------+ | IFPGA | > > + | Eth AFU Dev | |Crypto AFU Dev | | Rawdev > Driver | > > + +-------.-------+ +-------.-------+ |(OPAE Share Code)| > > + | | | > | > > + | | Rawdev | > | > > + +-------'------------------'-------+ Ops | | > > + | IFPGA Bus | -------->| > | > > + +-----------------.----------------+ +--------.--------+ > > + | > | > > + Hot-plugin -->| | > > + | > | > > + +-----------------'------------------+ +--------'--------+ > > + | vdev_ifpga_cfg driver | | Intel > FpgaDev | > > + +------------------------------------+ +-----------------+ > > + > > +Build options > > +------------- > > + > > +- ``CONFIG_RTE_LIBRTE_IFPGA_BUS`` (default ``y``) > > + > > + Toggle compilation of IFPGA Bus library. > > + > > +- ``CONFIG_RTE_LIBRTE_IFPGA_RAWDEV`` (default ``y``) > > + > > + Toggle compilation of the ``ifpga_rawdev`` driver. > > + > > +Run-time parameters > > +------------------- > > + > > +This driver is invoked automatically in systems added with Intel > > +FPGA, but PR and IFPGA Bus scan is trigged by command line using > > +``--vdev 'net_ifpga_cfg`` EAL option. > > + > > +The following device parameters are supported: > > + > > +- ``ifpga`` [string] > > + > > + Provide a specific Intel FPGA device PCI BDF. Can be provided > > multiple > > + times for additional instances. > > + > > +- ``port`` [int] > > + > > + Each FPGA can provide many channels to PR AFU by software, each > > channels > > + is identified by this parameter. > > + > > +- ``afu_bts`` [string] > > + > > + If null, the AFU Bit Stream has been PR in FPGA, if not forces PR > > and > > + identifies AFU Bit Stream file. > > [...] > > If you don't introduce this file into doc/guides/rawdevs/index.rst (like your > v7), the doc index won't be generated. > I think you misunderstood my comment in [1] - I meant that you will have to > rebase over CMDIF because it has already introduced the > doc/guides/rawdevs/index.rst file. Your patch v7 was adding this file. It > would have conflicted for Thomas' eventual merge. > > [1] http://dpdk.org/ml/archives/dev/2018-May/100313.html > > Unfortunately, you might have to send a v9 or maybe Thomas can take care > of this while merging. Hi Shreyansh, Do you mean we donot need this patch on V9. Reset this patch when the CMDIF patches have merged into mainline, right? ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v9 0/4] Introduce Intel FPGA BUS 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (11 preceding siblings ...) 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 0/5] Introduce Intel FPGA BUS Xu, Rosen @ 2018-05-08 14:18 ` Xu, Rosen 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 1/4] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen ` (3 more replies) 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 0/3] Introduce Intel FPGA BUS Xu, Rosen ` (4 subsequent siblings) 17 siblings, 4 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-08 14:18 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: "Xu, Rosen" <rosen.xu@intel.com> Intel FPGA BUS in DPDK ------------------------- This patch set introduces Intel FPGA BUS support in DPDK. v9 updates: ========== - Rebase ifpga_rawdev on QDMA and CMDIF driver - Split and squash the patch 4(v8 patch) into patch 2 and patch 3 v8 updates: ========== - Fix some comments from Shreyansh Jain - Patch 3 and Patch 5 will continue rebase when qcom patches merging into mainline - add Shreyansh Jain's Acked-by v7 updates: ========== - Fix some comments from DPDK community - Fix the CLANG compile error - Fix the meson build warring. v6 updates: =========== - Add documentation - Add meson build script - Split new patch for OPAE share code v5 updates: =========== - Fixed SHARED LIB Build issue - Changed command name to IFPGA Rawdev name, so remove pci library datastruct and function. - Fixed PATCH v2/v3/v4 comments v4 updates: =========== - Remove all modifications from eal - Create vdev to take IFPGA parameters configuration - AFU Device Driver bind to AFU Device by uuid - Take more test in scenario of Multi-FPGA System v3 updates: =========== - Remove all modifications of bus scan and probe - FPGA BUS Scan is trigged by hotplug of Rawdev - Took Modifications of comments - Move AFU Device to IFPGA - FPGA BUS Scan depend on it's IFPGA Rawdev - Add Build Macros for FPGA BUS and IFPGA Rawdev Questions ========= Why not PCI Bus? All of the AFUs of one FPGA may share same PCI BDF. Why not vdev Bus? Because AFUs depend on Rawdev, and it's hardware specpic. Motivation ========== FPGA is used more and more widely in Cloud and NFV, one primary reason is that FPGA not only provide ASIC performance but also it's more flexible than ASIC. FPGA use Partial Reconfigure(PR) Parts of Bitstream to achieve its flexibility. Another reason is that one FPGA can be shared by different Users, and each User can use some of AFUs of One FPGA. That means One FPGA Device Bitstream is divided into many Parts of Bitstream(each Part of Bitstream is defined as AFU-Accelerated Function Unit), and each AFU is a Hardware Acceleration Unit and it can dynamically Reload respectively. Proposed Solution ================= - Involve Rawdev to take FPGA Partial Configuration(Download/PR) - Defined FPGA-BUS for Acceleration Drivers of AFUs - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver. FPGA-BUS scan is called, but AFU depend on Rawdev, so this scan doesn't trig AFU device create. - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their dirves are also probed. Scope ===== The Intel FPGA BUS implementation is target towards various FPGA Devices use PR to provide many Acceleration Function. Specific PMDs may also bind to its AFU. And Applications don't care they are using ASIC Acceleration or FPGA AFU Acceleration. Status ===== With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable Acceleration Engine) Share Code, Intel FPGA BUS runs well in Intel PSG FPGA Cards. Figo Zhang (2): iFPGA: Add Intel FPGA BUS Rawdev Driver iFPGA: Add Intel FPGA OPAE Share Code Rosen Xu (2): bus/ifpga: Add Intel FPGA BUS Library iFPGA: add document for iFPGA driver config/common_base | 6 + doc/guides/rawdevs/ifpga_rawdev.rst | 112 ++ doc/guides/rawdevs/index.rst | 1 + doc/guides/rel_notes/release_18_05.rst | 13 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 + drivers/bus/ifpga/ifpga_bus.c | 501 ++++++ drivers/bus/ifpga/ifpga_common.c | 88 ++ drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 + drivers/bus/ifpga/meson.build | 8 + drivers/bus/ifpga/rte_bus_ifpga.h | 160 ++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/bus/meson.build | 2 +- drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 + drivers/raw/ifpga_rawdev/base/Makefile | 30 + drivers/raw/ifpga_rawdev/base/README | 31 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 294 ++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 28 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 57 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1661 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 824 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 11 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 314 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 164 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 734 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 301 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 403 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 715 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 372 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 127 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 408 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 165 ++ drivers/raw/ifpga_rawdev/base/meson.build | 34 + drivers/raw/ifpga_rawdev/base/opae_debug.c | 99 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 19 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 381 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 253 +++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 145 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 279 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 81 + .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 75 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 45 + drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 608 +++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 + drivers/raw/ifpga_rawdev/meson.build | 15 + .../ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map | 4 + drivers/raw/meson.build | 2 +- mk/rte.app.mk | 5 +- 50 files changed, 9738 insertions(+), 3 deletions(-) create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/meson.build create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/README create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/meson.build create mode 100644 drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v9 1/4] bus/ifpga: Add Intel FPGA BUS Library 2018-05-08 14:18 ` [dpdk-dev] [PATCH v9 0/4] Introduce Intel FPGA BUS Xu, Rosen @ 2018-05-08 14:19 ` Xu, Rosen 2018-05-08 14:42 ` Thomas Monjalon 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 2/4] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen ` (2 subsequent siblings) 3 siblings, 1 reply; 149+ messages in thread From: Xu, Rosen @ 2018-05-08 14:19 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: Rosen Xu <rosen.xu@intel.com> Defined FPGA-BUS for Acceleration Drivers of AFUs 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver, it will be covered in following patches. 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their drivers are also probed. This patch will introduce rte_afu_device which describe the AFU device listed in the FPGA-BUS. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Figo zhang <tianfei.zhang@intel.com> --- config/common_base | 5 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 ++ drivers/bus/ifpga/ifpga_bus.c | 501 ++++++++++++++++++++++++++++ drivers/bus/ifpga/ifpga_common.c | 88 +++++ drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 ++ drivers/bus/ifpga/meson.build | 8 + drivers/bus/ifpga/rte_bus_ifpga.h | 160 +++++++++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/bus/meson.build | 2 +- mk/rte.app.mk | 1 + 12 files changed, 856 insertions(+), 1 deletion(-) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/meson.build create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map diff --git a/config/common_base b/config/common_base index 0d181ac..7b79e37 100644 --- a/config/common_base +++ b/config/common_base @@ -149,6 +149,11 @@ CONFIG_RTE_LIBRTE_PCI_BUS=y CONFIG_RTE_LIBRTE_VDEV_BUS=y # +# Compile the Intel FPGA bus +# +CONFIG_RTE_LIBRTE_IFPGA_BUS=y + +# # Compile ARK PMD # CONFIG_RTE_LIBRTE_ARK_PMD=y diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index c251b65..cff3567 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -9,5 +9,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc endif DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile new file mode 100644 index 0000000..3ff3bdb --- /dev/null +++ b/drivers/bus/ifpga/Makefile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_bus_ifpga.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_kvargs + +# versioning export map +EXPORT_MAP := rte_bus_ifpga_version.map + +# library version +LIBABIVER := 1 + +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c + +# +# Export include files +# +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index 0000000..174ac54 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -0,0 +1,501 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_bus_logtype; + +/* Forward declaration to access Intel FPGA bus + * on which iFPGA devices are connected + */ +static struct rte_bus rte_ifpga_bus; + +/** Double linked list of IFPGA device. */ +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); + +static struct ifpga_device_list ifpga_device_list = + TAILQ_HEAD_INITIALIZER(ifpga_device_list); +static struct afu_driver_list afu_driver_list = + TAILQ_HEAD_INITIALIZER(afu_driver_list); + + +/* register a ifpga bus based driver */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver) +{ + RTE_VERIFY(driver); + + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); +} + +/* un-register a fpga bus based driver */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) +{ + TAILQ_REMOVE(&afu_driver_list, driver, next); +} + +static struct rte_ifpga_device * +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + if (rdev && + ifpga_dev->rdev && + ifpga_dev->rdev == rdev) + return ifpga_dev; + } + return NULL; +} + +static struct rte_afu_device * +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, + const struct rte_afu_id *afu_id) +{ + struct rte_afu_device *afu_dev = NULL; + + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) + return afu_dev; + } + return NULL; +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static struct rte_afu_device * +ifpga_scan_one(struct rte_devargs *devargs, + struct rte_ifpga_device *ifpga_dev) +{ + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_afu_pr_conf afu_pr_conf; + int ret = 0; + char *path = NULL; + + memset(&afu_pr_conf, 0, sizeof(struct rte_afu_pr_conf)); + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, + &ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, + &ifpga_get_string_arg, &path) < 0) { + IFPGA_BUS_ERR("Failed to parse %s", + IFPGA_AFU_BTS); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_AFU_BTS); + goto end; + } + + afu_pr_conf.afu_id.uuid.uuid_low = 0; + afu_pr_conf.afu_id.uuid.uuid_high = 0; + afu_pr_conf.pr_enable = path?1:0; + + rawdev = ifpga_dev->rdev; + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) + goto end; + + afu_dev = calloc(1, sizeof(*afu_dev)); + if (!afu_dev) + goto end; + + afu_dev->device.devargs = devargs; + afu_dev->device.numa_node = SOCKET_ID_ANY; + afu_dev->device.name = devargs->name; + afu_dev->rawdev = rawdev; + afu_dev->id.uuid.uuid_low = 0; + afu_dev->id.uuid.uuid_high = 0; + afu_dev->id.port = afu_pr_conf.afu_id.port; + afu_dev->ifpga_dev = ifpga_dev; + + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); + + if (rawdev->dev_ops && + rawdev->dev_ops->dev_start && + rawdev->dev_ops->dev_start(rawdev)) + goto free_dev; + + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); + if (rawdev->dev_ops->firmware_load && + rawdev->dev_ops->firmware_load(rawdev, + &afu_pr_conf)){ + IFPGA_BUS_ERR("firmware load error %d\n", ret); + goto free_dev; + } + afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; + afu_dev->id.uuid.uuid_high = afu_pr_conf.afu_id.uuid.uuid_high; + + return afu_dev; + +free_dev: + free(afu_dev); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (path) + free(path); + + return NULL; +} + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static int +ifpga_scan(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + char *name = NULL; + char name1[RTE_RAWDEV_NAME_MAX_LEN]; + struct rte_afu_device *afu_dev = NULL; + + /* for FPGA devices we scan the devargs_list populated via cmdline */ + RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { + if (devargs->bus != &rte_ifpga_bus) + continue; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &ifpga_get_string_arg, &name) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + memset(name1, 0, sizeof(name1)); + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", name); + + rawdev = rte_rawdev_pmd_get_named_dev(name1); + if (!rawdev) + goto end; + + if (ifpga_find_ifpga_dev(rawdev)) + continue; + + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); + if (!ifpga_dev) + goto end; + + ifpga_dev->rdev = rawdev; + TAILQ_INIT(&ifpga_dev->afu_list); + + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); + afu_dev = ifpga_scan_one(devargs, ifpga_dev); + if (afu_dev != NULL) + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, next); + } + +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +/* + * Match the AFU Driver and AFU Device using the ID Table + */ +static int +rte_afu_match(const struct rte_afu_driver *afu_drv, + const struct rte_afu_device *afu_dev) +{ + const struct rte_afu_uuid *id_table; + + for (id_table = afu_drv->id_table; + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); + id_table++) { + /* check if device's identifiers match the driver's ones */ + if ((id_table->uuid_low != afu_dev->id.uuid.uuid_low) || + id_table->uuid_high != + afu_dev->id.uuid.uuid_high) + continue; + + return 1; + } + + return 0; +} + +static int +ifpga_probe_one_driver(struct rte_afu_driver *drv, + struct rte_afu_device *afu_dev) +{ + int ret; + + if (!rte_afu_match(drv, afu_dev)) + /* Match of device and driver failed */ + return 1; + + /* reference driver structure */ + afu_dev->driver = drv; + afu_dev->device.driver = &drv->driver; + + /* call the driver probe() function */ + ret = drv->probe(afu_dev); + if (ret) { + afu_dev->driver = NULL; + afu_dev->device.driver = NULL; + } + + return ret; +} + +static int +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) +{ + struct rte_afu_driver *drv = NULL; + int ret = 0; + + if (afu_dev == NULL) + return -1; + + /* Check if a driver is already loaded */ + if (afu_dev->driver != NULL) + return 0; + + TAILQ_FOREACH(drv, &afu_driver_list, next) { + if (ifpga_probe_one_driver(drv, afu_dev)) { + ret = -1; + break; + } + } + return ret; +} + +/* + * Scan the content of the Intel FPGA bus, and call the probe() function for + * all registered drivers that have a matching entry in its id_table + * for discovered devices. + */ +static int +ifpga_probe(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev = NULL; + int ret = 0; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + + if (afu_dev->device.driver) + continue; + + ret = ifpga_probe_all_drivers(afu_dev); + if (ret < 0) + IFPGA_BUS_ERR("failed to initialize %s device\n", + rte_ifpga_device_name(afu_dev)); + } + } + + return ret; +} + +static int +ifpga_plug(struct rte_device *dev) +{ + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); +} + +static int +ifpga_remove_driver(struct rte_afu_device *afu_dev) +{ + const char *name; + const struct rte_afu_driver *driver; + + name = rte_ifpga_device_name(afu_dev); + if (!afu_dev->device.driver) { + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); + return 1; + } + + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); + return driver->remove(afu_dev); +} + +static int +ifpga_unplug(struct rte_device *dev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_devargs *devargs = NULL; + int ret; + + if (dev == NULL) + return -EINVAL; + + afu_dev = RTE_DEV_TO_AFU(dev); + if (!dev) + return -ENOENT; + + ifpga_dev = afu_dev->ifpga_dev; + devargs = dev->devargs; + + ret = ifpga_remove_driver(afu_dev); + if (ret) + return ret; + + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); + + rte_devargs_remove(devargs->bus->name, devargs->name); + free(afu_dev); + return 0; + +} + +static struct rte_device * +ifpga_find_device(const struct rte_device *start, + rte_dev_cmp_t cmp, const void *data) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (start && &afu_dev->device == start) { + start = NULL; + continue; + } + if (cmp(&afu_dev->device, data) == 0) + return &afu_dev->device; + } + } + return NULL; +} +static int +ifpga_parse(const char *name, void *addr) +{ + int *out = addr; + struct rte_rawdev *rawdev = NULL; + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; + char *c1 = NULL, *c2 = NULL; + int port = IFPGA_BUS_DEV_PORT_MAX; + char str_port[8]; + int str_port_len = 0; + int ret; + + memset(str_port, 0, 8); + c1 = strchr(name, '|'); + if (c1 != NULL) { + str_port_len = c1-name; + c2 = c1+1; + } + + if (str_port_len < 8 && + str_port_len > 0) { + memcpy(str_port, name, str_port_len); + ret = sscanf(str_port, "%d", &port); + if (ret == -1) + return 0; + } + + memset(rawdev_name, 0, sizeof(rawdev_name)); + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", c2); + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev && + (addr != NULL)) + *out = port; + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev) + return 0; + else + return 1; +} + +static struct rte_bus rte_ifpga_bus = { + .scan = ifpga_scan, + .probe = ifpga_probe, + .find_device = ifpga_find_device, + .plug = ifpga_plug, + .unplug = ifpga_unplug, + .parse = ifpga_parse, +}; + +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); + +RTE_INIT(ifpga_init_log) +{ + ifpga_bus_logtype = rte_log_register("bus.ifpga"); + if (ifpga_bus_logtype >= 0) + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); +} diff --git a/drivers/bus/ifpga/ifpga_common.c b/drivers/bus/ifpga/ifpga_common.c new file mode 100644 index 0000000..b4efc20 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(char **)extra_args = strdup(value); + + if (!*(char **)extra_args) + return -ENOMEM; + + return 0; +} +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(int *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(uint64_t *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_unsigned_long(const char *str, int base) +{ + unsigned long num; + char *end = NULL; + + errno = 0; + + num = strtoul(str, &end, base); + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) + return -1; + + return num; +} + +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1) +{ + if ((afu_id0->uuid.uuid_low == afu_id1->uuid.uuid_low) && + (afu_id0->uuid.uuid_high == afu_id1->uuid.uuid_high) && + (afu_id0->port == afu_id1->port)) { + return 0; + } else + return 1; +} diff --git a/drivers/bus/ifpga/ifpga_common.h b/drivers/bus/ifpga/ifpga_common.h new file mode 100644 index 0000000..b6662c8 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMMON_H_ +#define _IFPGA_COMMON_H_ + +int ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_unsigned_long(const char *str, int base); +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1); + +#endif /* _IFPGA_COMMON_H_ */ diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index 0000000..873e0a4 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_logs.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_LOGS_H_ +#define _IFPGA_LOGS_H_ + +#include <rte_log.h> + +extern int ifpga_bus_logtype; + +#define IFPGA_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") + +#define IFPGA_BUS_DEBUG(fmt, args...) \ + IFPGA_BUS_LOG(DEBUG, fmt, ## args) +#define IFPGA_BUS_INFO(fmt, args...) \ + IFPGA_BUS_LOG(INFO, fmt, ## args) +#define IFPGA_BUS_ERR(fmt, args...) \ + IFPGA_BUS_LOG(ERR, fmt, ## args) +#define IFPGA_BUS_WARN(fmt, args...) \ + IFPGA_BUS_LOG(WARNING, fmt, ## args) + +#endif /* _IFPGA_BUS_LOGS_H_ */ diff --git a/drivers/bus/ifpga/meson.build b/drivers/bus/ifpga/meson.build new file mode 100644 index 0000000..c9b08c8 --- /dev/null +++ b/drivers/bus/ifpga/meson.build @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2018 Intel Corporation + +deps += ['pci', 'kvargs', 'rawdev'] +install_headers('rte_bus_ifpga.h') +sources = files('ifpga_common.c', 'ifpga_bus.c') + +allow_experimental_apis = true diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h new file mode 100644 index 0000000..5c559e1 --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga.h @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _RTE_BUS_IFPGA_H_ +#define _RTE_BUS_IFPGA_H_ + +/** + * @file + * + * RTE Intel FPGA Bus Interface + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_bus.h> +#include <rte_pci.h> + +/** Name of Intel FPGA Bus */ +#define IFPGA_BUS_NAME ifpga + +/* Forward declarations */ +struct rte_afu_device; + +/** List of Intel AFU devices */ +TAILQ_HEAD(afu_device_list, rte_afu_device); +/** Double linked list of AFU device drivers. */ +TAILQ_HEAD(afu_driver_list, rte_afu_driver); + +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 + +struct rte_afu_uuid { + uint64_t uuid_low; + uint64_t uuid_high; +} __attribute__ ((packed)); + +#define IFPGA_BUS_DEV_PORT_MAX 4 + +/** + * A structure describing an ID for a AFU driver. Each driver provides a + * table of these IDs for each device that it supports. + */ +struct rte_afu_id { + struct rte_afu_uuid uuid; + int port; /**< port number */ +} __attribute__ ((packed)); + +/** + * A structure PR (Partial Reconfiguration) configuration AFU driver. + */ + +struct rte_afu_pr_conf { + struct rte_afu_id afu_id; + int pr_enable; + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +}; + +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) + +/** + * A structure describing a fpga device. + */ +struct rte_ifpga_device { + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ + struct rte_rawdev *rdev; + struct afu_device_list afu_list; /**< List of AFU devices */ +}; + +/** + * A structure describing a AFU device. + */ +struct rte_afu_device { + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ + struct rte_device device; /**< Inherit core device */ + struct rte_rawdev *rawdev; /**< Point Rawdev */ + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ + struct rte_afu_id id; /**< AFU id within FPGA. */ + uint32_t num_region; /**< number of regions found */ + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; + /**< AFU Memory Resource */ + struct rte_intr_handle intr_handle; /**< Interrupt handle */ + struct rte_afu_driver *driver; /**< Associated driver */ + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +} __attribute__ ((packed)); + +/** + * @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_DRV_TO_AFU_CONST(ptr) \ + container_of(ptr, const struct rte_afu_driver, driver) + +/** + * Initialisation function for the driver called during FPGA BUS probing. + */ +typedef int (afu_probe_t)(struct rte_afu_device *); + +/** + * Uninitialisation function for the driver called during hotplugging. + */ +typedef int (afu_remove_t)(struct rte_afu_device *); + +/** + * A structure describing a AFU device. + */ +struct rte_afu_driver { + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ + struct rte_driver driver; /**< Inherit core driver. */ + afu_probe_t *probe; /**< Device Probe function. */ + afu_remove_t *remove; /**< Device Remove function. */ + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ + uint32_t drv_flags; /**< Flags contolling handling of device. */ +}; + +static inline const char * +rte_ifpga_device_name(const struct rte_afu_device *afu) +{ + if (afu && afu->device.name) + return afu->device.name; + return NULL; +} + +/** + * Register a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be registered. + */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver); + +/** + * Unregister a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be unregistered. + */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); + +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ +RTE_INIT(afudrvinitfn_ ##afudrv);\ +static const char *afudrvinit_ ## nm ## _alias;\ +static void afudrvinitfn_ ##afudrv(void)\ +{\ + (afudrv).driver.name = RTE_STR(nm);\ + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ + rte_ifpga_driver_register(&afudrv);\ +} \ +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) + +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ +static const char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) + +#endif /* _RTE_BUS_IFPGA_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map new file mode 100644 index 0000000..1304caf --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map @@ -0,0 +1,10 @@ +DPDK_18.05 { + global: + + ifpga_get_integer32_arg; + ifpga_get_string_arg; + rte_ifpga_driver_register; + rte_ifpga_driver_unregister; + + local: *; +}; diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build index 58dfbe2..170df25 100644 --- a/drivers/bus/meson.build +++ b/drivers/bus/meson.build @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel Corporation -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] +drivers = ['dpaa', 'fslmc', 'pci', 'vdev', 'ifpga'] std_deps = ['eal'] config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' driver_name_fmt = 'rte_bus_@0@' diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 26f3563..3861e1a 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -255,6 +255,7 @@ ifeq ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += -lrte_pmd_dpaa2_cmdif _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += -lrte_pmd_dpaa2_qdma endif # CONFIG_RTE_LIBRTE_FSLMC_BUS +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga endif # CONFIG_RTE_LIBRTE_RAWDEV -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v9 1/4] bus/ifpga: Add Intel FPGA BUS Library 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 1/4] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen @ 2018-05-08 14:42 ` Thomas Monjalon 2018-05-09 1:25 ` Xu, Rosen 0 siblings, 1 reply; 149+ messages in thread From: Thomas Monjalon @ 2018-05-08 14:42 UTC (permalink / raw) To: Xu, Rosen Cc: dev, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet 08/05/2018 16:19, Xu, Rosen: > --- /dev/null > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > + ifpga_get_integer32_arg; > + ifpga_get_string_arg; > + rte_ifpga_driver_register; > + rte_ifpga_driver_unregister; All exported symbols must start with rte_ > --- a/drivers/bus/meson.build > +++ b/drivers/bus/meson.build > -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] > +drivers = ['dpaa', 'fslmc', 'pci', 'vdev', 'ifpga'] Would be better sorted in alphabetical order (between fslmc and pci). Same comment in files config/common_base and drivers/bus/Makefile. ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v9 1/4] bus/ifpga: Add Intel FPGA BUS Library 2018-05-08 14:42 ` Thomas Monjalon @ 2018-05-09 1:25 ` Xu, Rosen 0 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-09 1:25 UTC (permalink / raw) To: Thomas Monjalon Cc: dev, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet Hi Thomas, > -----Original Message----- > From: Thomas Monjalon [mailto:thomas@monjalon.net] > Sent: Tuesday, May 08, 2018 22:43 > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: Re: [PATCH v9 1/4] bus/ifpga: Add Intel FPGA BUS Library > > 08/05/2018 16:19, Xu, Rosen: > > --- /dev/null > > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > + ifpga_get_integer32_arg; > > + ifpga_get_string_arg; > > + rte_ifpga_driver_register; > > + rte_ifpga_driver_unregister; > > All exported symbols must start with rte_ I will fix it in v10. > > > --- a/drivers/bus/meson.build > > +++ b/drivers/bus/meson.build > > -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] > > +drivers = ['dpaa', 'fslmc', 'pci', 'vdev', 'ifpga'] > > Would be better sorted in alphabetical order (between fslmc and pci). > Same comment in files config/common_base and drivers/bus/Makefile. I will fix in in v10. ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v9 2/4] iFPGA: Add Intel FPGA OPAE Share Code 2018-05-08 14:18 ` [dpdk-dev] [PATCH v9 0/4] Introduce Intel FPGA BUS Xu, Rosen 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 1/4] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen @ 2018-05-08 14:19 ` Xu, Rosen 2018-05-08 14:45 ` Thomas Monjalon 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 3/4] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 4/4] iFPGA: add document for iFPGA driver Xu, Rosen 3 siblings, 1 reply; 149+ messages in thread From: Xu, Rosen @ 2018-05-08 14:19 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Xu, Yilun [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset=y, Size: 222776 bytes --] From: Rosen Xu <rosen.xu@intel.com> This patch adds Intel FPGA Open Programmable Acceleration Engine (OPAE)[1] base driver code, in order to support Intel FPGA devices under DPDK. The base code currently supports Intel FPGA solutions including integrated solution (Intel(R) Xeon(R) CPU with FPGAs) and discrete solution (Intel(R) Programmable Acceleration Card with Intel(R) Arria(R) 10 FPGA) and it could be extended to support more FPGA devices in the future. Please refer to [1][2] for more introduction on OPAE and Intel FPGAs. [1] https://01.org/OPAE [2] https://www.altera.com/solutions/acceleration-hub/overview.html Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> Signed-off-by: Wu, Hao <hao.wu@intel.com> Signed-off-by: Xu, Yilun <yilun.xu@intel.com> --- drivers/raw/ifpga_rawdev/base/Makefile | 30 + drivers/raw/ifpga_rawdev/base/README | 31 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 294 ++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 28 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 57 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1661 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 824 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 11 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 314 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 164 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 734 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 301 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 403 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 715 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 372 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 127 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 408 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 165 ++ drivers/raw/ifpga_rawdev/base/meson.build | 34 + drivers/raw/ifpga_rawdev/base/opae_debug.c | 99 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 19 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 381 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 253 +++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 145 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 279 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 81 + .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 75 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 45 + 28 files changed, 8050 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/README create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile new file mode 100644 index 0000000..ade3551 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -0,0 +1,30 @@ +#SPDX-License-Identifier: BSD-3-Clause +#Copyright(c) 2010-2018 Intel Corporation + +ifneq ($(CONFIG_RTE_LIBRTE_EAL),) +OSDEP := osdep_rte +else +OSDEP := osdep_raw +endif + +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev/base/$(OSDEP) + +SRCS-y += ifpga_api.c +SRCS-y += ifpga_enumerate.c +SRCS-y += ifpga_feature_dev.c +SRCS-y += ifpga_fme.c +SRCS-y += ifpga_fme_iperf.c +SRCS-y += ifpga_fme_dperf.c +SRCS-y += ifpga_fme_error.c +SRCS-y += ifpga_port.c +SRCS-y += ifpga_port_error.c +SRCS-y += opae_hw_api.c +SRCS-y += opae_ifpga_hw_api.c +SRCS-y += opae_debug.c +SRCS-y += ifpga_fme_pr.c + +ifeq ($(CONFIG_RTE_TOOLCHAIN_CLANG),y) + CFLAGS_ifpga_fme_pr.o += -march=knl +endif + +SRCS-y += $(wildcard $(SRCDIR)/base/$(OSDEP)/*.c) diff --git a/drivers/raw/ifpga_rawdev/base/README b/drivers/raw/ifpga_rawdev/base/README new file mode 100644 index 0000000..3636ac7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/README @@ -0,0 +1,31 @@ +.. + +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +Intel® iFPGA driver +================== + +This directory contains source code of Intel FPGA driver released by +the team which develops Intel FPGA Open Programmable Acceleration Engine (OPAE). +The directory of base/ contains the original source package. The base code +currently supports Intel FPGA solutions including integrated solution (Intel(R) +Xeon(R) CPU with FPGAs) and discrete solution (Intel(R) Programmable Acceleration +Card with Intel(R) Arria(R) 10 FPGA) and it could be extended to support more FPGA +devices in the future. + +Please refer to [1][2] for more introduction on OPAE and Intel FPGAs. + +[1] https://01.org/OPAE +[2] https://www.altera.com/solutions/acceleration-hub/overview.html + + +Updating the driver +=================== + +NOTE: The source code in this directory should not be modified apart from +the following file(s): + + osdep_raw/osdep_generic.h + osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.c b/drivers/raw/ifpga_rawdev/base/ifpga_api.c new file mode 100644 index 0000000..540e171 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -0,0 +1,294 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_api.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +#include "opae_hw_api.h" + +/* Accelerator APIs */ +static int ifpga_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return fpga_get_afu_uuid(port, uuid); +} + +static int ifpga_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + struct fpga_uafu_irq_set irq_set; + + if (!br || !br->data) + return -EINVAL; + + if (start >= afu_info->num_irqs || start + count > afu_info->num_irqs) + return -EINVAL; + + port = br->data; + + irq_set.start = start; + irq_set.count = count; + irq_set.evtfds = evtfds; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_UINT, &irq_set); +} + +static int ifpga_acc_get_info(struct opae_accelerator *acc, + struct opae_acc_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -ENODEV; + + info->num_regions = afu_info->num_regions; + info->num_irqs = afu_info->num_irqs; + + return 0; +} + +static int ifpga_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -EINVAL; + + if (info->index >= afu_info->num_regions) + return -EINVAL; + + /* always one RW region only for AFU now */ + info->flags = ACC_REGION_READ | ACC_REGION_WRITE | ACC_REGION_MMIO; + info->len = afu_info->region[info->index].len; + info->addr = afu_info->region[info->index].addr; + + return 0; +} + +static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + switch (byte) { + case 8: + *(u64 *)data = opae_readq(region->addr + offset); + break; + case 4: + *(u32 *)data = opae_readl(region->addr + offset); + break; + case 2: + *(u16 *)data = opae_readw(region->addr + offset); + break; + case 1: + *(u8 *)data = opae_readb(region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ifpga_acc_write(struct opae_accelerator *acc, + unsigned int region_idx, u64 offset, + unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + /* normal mmio case */ + switch (byte) { + case 8: + opae_writeq(*(u64 *)data, region->addr + offset); + break; + case 4: + opae_writel(*(u32 *)data, region->addr + offset); + break; + case 2: + opae_writew(*(u16 *)data, region->addr + offset); + break; + case 1: + opae_writeb(*(u8 *)data, region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +struct opae_accelerator_ops ifpga_acc_ops = { + .read = ifpga_acc_read, + .write = ifpga_acc_write, + .set_irq = ifpga_acc_set_irq, + .get_info = ifpga_acc_get_info, + .get_region_info = ifpga_acc_get_region_info, + .get_uuid = ifpga_acc_get_uuid, +}; + +/* Bridge APIs */ + +static int ifpga_br_reset(struct opae_bridge *br) +{ + struct ifpga_port_hw *port = br->data; + + return fpga_port_reset(port); +} + +struct opae_bridge_ops ifpga_br_ops = { + .reset = ifpga_br_reset, +}; + +/* Manager APIs */ +static int ifpga_mgr_flash(struct opae_manager *mgr, int id, void *buf, + u32 size, u64 *status) +{ + struct ifpga_fme_hw *fme = mgr->data; + struct ifpga_hw *hw = fme->parent; + + return ifpga_pr(hw, id, buf, size, status); +} + +struct opae_manager_ops ifpga_mgr_ops = { + .flash = ifpga_mgr_flash, +}; + +/* Adapter APIs */ +static int ifpga_adapter_enumerate(struct opae_adapter *adapter) +{ + struct ifpga_hw *hw = malloc(sizeof(*hw)); + + if (hw) { + memset(hw, 0, sizeof(*hw)); + hw->pci_data = adapter->data; + hw->adapter = adapter; + if (ifpga_bus_enumerate(hw)) + goto error; + return ifpga_bus_init(hw); + } + +error: + return -ENOMEM; +} + +struct opae_adapter_ops ifpga_adapter_ops = { + .enumerate = ifpga_adapter_enumerate, +}; + +/** + * ifpga_pr - do the partial reconfiguration for a given port device + * @hw: pointer to the HW structure + * @port_id: the port device id + * @buffer: the buffer of the bitstream + * @size: the size of the bitstream + * @status: hardware status including PR error code if return -EIO. + * + * @return + * - 0: Success, partial reconfiguration finished. + * - <0: Error code returned in partial reconfiguration. + **/ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return do_pr(hw, port_id, buffer, size, status); +} + +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_get_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_get_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set) +{ + if (!hw || !irq_set) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_irq(&hw->fme, feature_id, irq_set); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_irq(&hw->port[port_id], feature_id, irq_set); + } + + return -ENOENT; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.h b/drivers/raw/ifpga_rawdev/base/ifpga_api.h new file mode 100644 index 0000000..dae7ca1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_API_H_ +#define _IFPGA_API_H_ + +#include "opae_hw_api.h" +#include "ifpga_hw.h" + +extern struct opae_adapter_ops ifpga_adapter_ops; +extern struct opae_manager_ops ifpga_mgr_ops; +extern struct opae_bridge_ops ifpga_br_ops; +extern struct opae_accelerator_ops ifpga_acc_ops; + +/* common APIs */ +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set); + +/* FME APIs */ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +#endif /* _IFPGA_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_compat.h b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h new file mode 100644 index 0000000..78b904e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMPAT_H_ +#define _IFPGA_COMPAT_H_ + +#include "opae_osdep.h" + +#undef container_of +#define container_of(ptr, type, member) ({ \ + typeof(((type *)0)->member)(*__mptr) = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) +#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE) + +#define readl(addr) opae_readl(addr) +#define readq(addr) opae_readq(addr) +#define writel(value, addr) opae_writel(value, addr) +#define writeq(value, addr) opae_writeq(value, addr) + +#define malloc(size) opae_malloc(size) +#define zmalloc(size) opae_zmalloc(size) +#define free(size) opae_free(size) + +/* + * Wait register's _field to be changed to the given value (_expect's _field) + * by polling with given interval and timeout. + */ +#define fpga_wait_register_field(_field, _expect, _reg_addr, _timeout, _invl)\ +({ \ + int wait = 0; \ + int ret = -ETIMEDOUT; \ + typeof(_expect) value; \ + for (; wait <= _timeout; wait += _invl) { \ + value.csr = readq(_reg_addr); \ + if (_expect._field == value._field) { \ + ret = 0; \ + break; \ + } \ + udelay(_invl); \ + } \ + ret; \ +}) + +#define __maybe_unused __attribute__((__unused__)) + +#define UNUSED(x) (void)(x) + +#endif /* _IFPGA_COMPAT_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h new file mode 100644 index 0000000..8989280 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -0,0 +1,1661 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_DEFINES_H_ +#define _IFPGA_DEFINES_H_ + +#include "ifpga_compat.h" + +#define MAX_FPGA_PORT_NUM 4 + +#define FME_FEATURE_HEADER "fme_hdr" +#define FME_FEATURE_THERMAL_MGMT "fme_thermal" +#define FME_FEATURE_POWER_MGMT "fme_power" +#define FME_FEATURE_GLOBAL_IPERF "fme_iperf" +#define FME_FEATURE_GLOBAL_ERR "fme_error" +#define FME_FEATURE_PR_MGMT "fme_pr" +#define FME_FEATURE_HSSI_ETH "fme_hssi" +#define FME_FEATURE_GLOBAL_DPERF "fme_dperf" +#define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" + +#define PORT_FEATURE_HEADER "port_hdr" +#define PORT_FEATURE_UAFU "port_uafu" +#define PORT_FEATURE_ERR "port_err" +#define PORT_FEATURE_UMSG "port_umsg" +#define PORT_FEATURE_PR "port_pr" +#define PORT_FEATURE_UINT "port_uint" +#define PORT_FEATURE_STP "port_stp" + +/* + * do not check the revision id as id may be dynamic under + * some cases, e.g, UAFU. + */ +#define SKIP_REVISION_CHECK 0xff + +#define FME_HEADER_REVISION 1 +#define FME_THERMAL_MGMT_REVISION 0 +#define FME_POWER_MGMT_REVISION 1 +#define FME_GLOBAL_IPERF_REVISION 1 +#define FME_GLOBAL_ERR_REVISION 1 +#define FME_PR_MGMT_REVISION 2 +#define FME_HSSI_ETH_REVISION 0 +#define FME_GLOBAL_DPERF_REVISION 0 +#define FME_QSPI_REVISION 0 + +#define PORT_HEADER_REVISION 0 +/* UAFU's header info depends on the downloaded GBS */ +#define PORT_UAFU_REVISION SKIP_REVISION_CHECK +#define PORT_ERR_REVISION 1 +#define PORT_UMSG_REVISION 0 +#define PORT_UINT_REVISION 0 +#define PORT_STP_REVISION 1 + +#define FEATURE_TYPE_AFU 0x1 +#define FEATURE_TYPE_BBB 0x2 +#define FEATURE_TYPE_PRIVATE 0x3 +#define FEATURE_TYPE_FIU 0x4 + +#define FEATURE_FIU_ID_FME 0x0 +#define FEATURE_FIU_ID_PORT 0x1 + +#define FEATURE_ID_HEADER 0x0 +#define FEATURE_ID_AFU 0xff + +enum fpga_id_type { + FME_ID, + PORT_ID, + 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, +}; + +/* + * All headers and structures must be byte-packed to match the spec. + */ +#pragma pack(1) + +struct feature_header { + union { + u64 csr; + struct { + u16 id:12; + u8 revision:4; + u32 next_header_offset:24; + u8 end_of_list:1; + u32 reserved:19; + u8 type:4; + }; + }; +}; + +struct feature_bbb_header { + struct uuid guid; +}; + +struct feature_afu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fiu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fme_capability { + union { + u64 csr; + struct { + u8 fabric_verid; /* Fabric version ID */ + u8 socket_id:1; /* Socket id */ + u8 rsvd1:3; /* Reserved */ + /* pci0 link available yes /no */ + u8 pci0_link_avile:1; + /* pci1 link available yes /no */ + u8 pci1_link_avile:1; + /* Coherent (QPI/UPI) link available yes /no */ + u8 qpi_link_avile:1; + u8 rsvd2:1; /* Reserved */ + /* IOMMU or VT-d supported yes/no */ + u8 iommu_support:1; + u8 num_ports:3; /* Number of ports */ + u8 sf_fab_ctl:1; /* Internal validation bit */ + u8 rsvd3:3; /* Reserved */ + /* + * Address width supported in bits + * BXT -0x26 , SKX -0x30 + */ + u8 address_width_bits:6; + u8 rsvd4:2; /* Reserved */ + /* Size of cache supported in kb */ + u16 cache_size:12; + u8 cache_assoc:4; /* Cache Associativity */ + u16 rsvd5:15; /* Reserved */ + u8 lock_bit:1; /* Lock bit */ + }; + }; +}; + +#define FME_AFU_ACCESS_PF 0 +#define FME_AFU_ACCESS_VF 1 + +struct feature_fme_port { + union { + u64 csr; + struct { + u32 port_offset:24; + u8 reserved1; + u8 port_bar:3; + u32 reserved2:20; + u8 afu_access_control:1; + u8 reserved3:4; + u8 port_implemented:1; + u8 reserved4:3; + }; + }; +}; + +struct feature_fme_fab_status { + union { + u64 csr; + struct { + u8 upilink_status:4; /* UPI Link Status */ + u8 rsvd1:4; /* Reserved */ + u8 pci0link_status:1; /* pci0 link status */ + u8 rsvd2:3; /* Reserved */ + u8 pci1link_status:1; /* pci1 link status */ + u64 rsvd3:51; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_base { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Base Address of memory range */ + u8 protected_base_addrss:4; + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_limit { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Limit Address of memory range */ + u8 protected_limit_addrss:4; + u16 rsvd2:11; /* Reserved */ + u8 enable:1; /* Enable GENPROTRANGE check */ + u32 rsvd3; /* Reserved */ + }; + }; +}; + +struct feature_fme_dxe_lock { + union { + u64 csr; + struct { + /* + * Determines write access to the DXE region CSRs + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_early_lock:1; + /* + * Determines write access to the HSSI CSR + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_late_lock:1; + u64 rsvd:62; + }; + }; +}; + +#define HSSI_ID_NO_HASSI 0 +#define HSSI_ID_PCIE_RP 1 +#define HSSI_ID_ETHERNET 2 + +struct feature_fme_bitstream_id { + union { + u64 csr; + struct { + u32 gitrepo_hash:32; /* GIT repository hash */ + /* + * HSSI configuration identifier: + * 0 - No HSSI + * 1 - PCIe-RP + * 2 - Ethernet + */ + u8 hssi_id:4; + u16 rsvd1:12; /* Reserved */ + /* Bitstream version patch number */ + u8 bs_verpatch:4; + /* Bitstream version minor number */ + u8 bs_verminor:4; + /* Bitstream version major number */ + u8 bs_vermajor:4; + /* Bitstream version debug number */ + u8 bs_verdebug:4; + }; + }; +}; + +struct feature_fme_bitstream_md { + union { + u64 csr; + struct { + /* Seed number userd for synthesis flow */ + u8 synth_seed:4; + /* Synthesis date(day number - 2 digits) */ + u8 synth_day:8; + /* Synthesis date(month number - 2 digits) */ + u8 synth_month:8; + /* Synthesis date(year number - 2 digits) */ + u8 synth_year:8; + u64 rsvd:36; /* Reserved */ + }; + }; +}; + +struct feature_fme_iommu_ctrl { + union { + u64 csr; + struct { + /* Disables IOMMU prefetcher for C0 channel */ + u8 prefetch_disableC0:1; + /* Disables IOMMU prefetcher for C1 channel */ + u8 prefetch_disableC1:1; + /* Disables IOMMU partial cache line writes */ + u8 prefetch_wrdisable:1; + u8 rsvd1:1; /* Reserved */ + /* + * Select counter and read value from register + * iommu_stat.dbg_counters + * 0 - Number of 4K page translation response + * 1 - Number of 2M page translation response + * 2 - Number of 1G page translation response + */ + u8 counter_sel:2; + u32 rsvd2:26; /* Reserved */ + /* Connected to IOMMU SIP Capabilities */ + u32 capecap_defeature; + }; + }; +}; + +struct feature_fme_iommu_stat { + union { + u64 csr; + struct { + /* Translation Enable bit from IOMMU SIP */ + u8 translation_enable:1; + /* Drain request in progress */ + u8 drain_req_inprog:1; + /* Invalidation current state */ + u8 inv_state:3; + /* C0 Response Buffer current state */ + u8 respbuffer_stateC0:3; + /* C1 Response Buffer current state */ + u8 respbuffer_stateC1:3; + /* Last request ID to IOMMU SIP */ + u8 last_reqID:4; + /* Last IOMMU SIP response ID value */ + u8 last_respID:4; + /* Last IOMMU SIP response status value */ + u8 last_respstatus:3; + /* C0 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC0:1; + /* C1 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC1:1; + /* C0 Request FIFO is not empty */ + u8 reqFIFO_notemptyC0:1; + /* C1 Request FIFO is not empty */ + u8 reqFIFO_notemptyC1:1; + /* C0 Response FIFO is not empty */ + u8 respFIFO_notemptyC0:1; + /* C1 Response FIFO is not empty */ + u8 respFIFO_notemptyC1:1; + /* C0 Response FIFO overflow detected */ + u8 respFIFO_overflowC0:1; + /* C1 Response FIFO overflow detected */ + u8 respFIFO_overflowC1:1; + /* C0 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC0:1; + /* C1 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC1:1; + /* Request FIFO overflow detected */ + u8 reqFIFO_overflow:1; + /* IOMMU memory read in progress */ + u8 memrd_inprog:1; + /* IOMMU memory write in progress */ + u8 memwr_inprog:1; + u8 rsvd1:1; /* Reserved */ + /* Value of counter selected by iommu_ctl.counter_sel */ + u16 dbg_counters:16; + u16 rsvd2:12; /* Reserved */ + }; + }; +}; + +struct feature_fme_pcie0_ctrl { + union { + u64 csr; + struct { + u64 vtd_bar_lock:1; /* Lock VT-D BAR register */ + u64 rsvd1:3; + u64 rciep:1; /* Configure PCIE0 as RCiEP */ + u64 rsvd2:59; + }; + }; +}; + +struct feature_fme_llpr_smrr_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR rule is valid or not */ + /* + * SMRR memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR2 rule is valid or not */ + /* + * SMRR2 memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_meseg_base { + union { + u64 csr; + struct { + /* A[45:19] of base address memory range */ + u64 me_base:27; + u64 rsvd:37; + }; + }; +}; + +struct feature_fme_llpr_meseg_limit { + union { + u64 csr; + struct { + /* A[45:19] of limit address memory range */ + u64 me_limit:27; + u64 rsvd1:4; + u64 enable:1; /* Enable LLPR MESEG rule */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 reserved; + u64 scratchpad; + struct feature_fme_capability capability; + struct feature_fme_port port[MAX_FPGA_PORT_NUM]; + struct feature_fme_fab_status fab_status; + struct feature_fme_bitstream_id bitstream_id; + struct feature_fme_bitstream_md bitstream_md; + struct feature_fme_genprotrange2_base genprotrange2_base; + struct feature_fme_genprotrange2_limit genprotrange2_limit; + struct feature_fme_dxe_lock dxe_lock; + struct feature_fme_iommu_ctrl iommu_ctrl; + struct feature_fme_iommu_stat iommu_stat; + struct feature_fme_pcie0_ctrl pcie0_control; + struct feature_fme_llpr_smrr_base smrr_base; + struct feature_fme_llpr_smrr_mask smrr_mask; + struct feature_fme_llpr_smrr2_base smrr2_base; + struct feature_fme_llpr_smrr2_mask smrr2_mask; + struct feature_fme_llpr_meseg_base meseg_base; + struct feature_fme_llpr_meseg_limit meseg_limit; +}; + +struct feature_port_capability { + union { + u64 csr; + struct { + u8 port_number:2; /* Port Number 0-3 */ + u8 rsvd1:6; /* Reserved */ + u16 mmio_size; /* User MMIO size in KB */ + u8 rsvd2; /* Reserved */ + u8 sp_intr_num:4; /* Supported interrupts num */ + u32 rsvd3:28; /* Reserved */ + }; + }; +}; + +struct feature_port_control { + union { + u64 csr; + struct { + u8 port_sftrst:1; /* Port Soft Reset */ + u8 rsvd1:1; /* Reserved */ + u8 latency_tolerance:1;/* '1' >= 40us, '0' < 40us */ + u8 rsvd2:1; /* Reserved */ + u8 port_sftrst_ack:1; /* HW ACK for Soft Reset */ + u64 rsvd3:59; /* Reserved */ + }; + }; +}; + +#define PORT_POWER_STATE_NORMAL 0 +#define PORT_POWER_STATE_AP1 1 +#define PORT_POWER_STATE_AP2 2 +#define PORT_POWER_STATE_AP6 6 + +struct feature_port_status { + union { + u64 csr; + struct { + u8 port_freeze:1; /* '1' - freezed '0' - normal */ + u8 rsvd1:7; /* Reserved */ + u8 power_state:4; /* Power State */ + u8 ap1_event:1; /* AP1 event was detected */ + u8 ap2_event:1; /* AP2 event was detected */ + u64 rsvd2:50; /* Reserved */ + }; + }; +}; + +/* Port Header Register Set */ +struct feature_port_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 port_mailbox; + u64 scratchpad; + struct feature_port_capability capability; + struct feature_port_control control; + struct feature_port_status status; + u64 rsvd2; + u64 user_clk_freq_cmd0; + u64 user_clk_freq_cmd1; + u64 user_clk_freq_sts0; + u64 user_clk_freq_sts1; +}; + +struct feature_fme_tmp_threshold { + union { + u64 csr; + struct { + u8 tmp_thshold1:7; /* temperature Threshold 1 */ + /* temperature Threshold 1 enable/disable */ + u8 tmp_thshold1_enable:1; + u8 tmp_thshold2:7; /* temperature Threshold 2 */ + /* temperature Threshold 2 enable /disable */ + u8 tmp_thshold2_enable:1; + u8 pro_hot_setpoint:7; /* Proc Hot set point */ + u8 rsvd4:1; /* Reserved */ + u8 therm_trip_thshold:7; /* Thermeal Trip Threshold */ + u8 rsvd3:1; /* Reserved */ + u8 thshold1_status:1; /* Threshold 1 Status */ + u8 thshold2_status:1; /* Threshold 2 Status */ + u8 rsvd5:1; /* Reserved */ + /* Thermeal Trip Threshold status */ + u8 therm_trip_thshold_status:1; + u8 rsvd6:4; /* Reserved */ + /* Validation mode- Force Proc Hot */ + u8 valmodeforce:1; + /* Validation mode - Therm trip Hot */ + u8 valmodetherm:1; + u8 rsvd2:2; /* Reserved */ + u8 thshold_policy:1; /* threshold policy */ + u32 rsvd:19; /* Reserved */ + }; + }; +}; + +/* Temperature Sensor Read values format 1 */ +struct feature_fme_temp_rdsensor_fmt1 { + union { + u64 csr; + struct { + /* Reads out FPGA temperature in celsius */ + u8 fpga_temp:7; + u8 rsvd0:1; /* Reserved */ + /* Temperature reading sequence number */ + u16 tmp_reading_seq_num; + /* Temperature reading is valid */ + u8 tmp_reading_valid:1; + u8 rsvd1:7; /* Reserved */ + u16 dbg_mode:10; /* Debug mode */ + u32 rsvd2:22; /* Reserved */ + }; + }; +}; + +/* Temperature sensor read values format 2 */ +struct feature_fme_temp_rdsensor_fmt2 { + u64 rsvd; /* Reserved */ +}; + +/* Temperature Threshold Capability Register */ +struct feature_fme_tmp_threshold_cap { + union { + u64 csr; + struct { + /* Temperature Threshold Unsupported */ + u8 tmp_thshold_disabled:1; + u64 rsvd:63; /* Reserved */ + }; + }; +}; + +/* FME THERNAL FEATURE */ +struct feature_fme_thermal { + struct feature_header header; + struct feature_fme_tmp_threshold threshold; + struct feature_fme_temp_rdsensor_fmt1 rdsensor_fm1; + struct feature_fme_temp_rdsensor_fmt2 rdsensor_fm2; + struct feature_fme_tmp_threshold_cap threshold_cap; +}; + +/* Power Status register */ +struct feature_fme_pm_status { + union { + u64 csr; + struct { + /* FPGA Power consumed, The format is to be defined */ + u32 pwr_consumed:18; + /* FPGA Latency Tolerance Reporting */ + u8 fpga_latency_report:1; + u64 rsvd:45; /* Reserved */ + }; + }; +}; + +/* AP Thresholds */ +struct feature_fme_pm_ap_threshold { + union { + u64 csr; + struct { + /* + * Number of clocks (5ns period) for assertion + * of FME_data + */ + u8 threshold1:7; + u8 rsvd1:1; + u8 threshold2:7; + u8 rsvd2:1; + u8 threshold1_status:1; + u8 threshold2_status:1; + u64 rsvd3:46; /* Reserved */ + }; + }; +}; + +/* Xeon Power Limit */ +struct feature_fme_pm_xeon_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FPGA Power Limit */ +struct feature_fme_pm_fpga_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FME POWER FEATURE */ +struct feature_fme_power { + struct feature_header header; + struct feature_fme_pm_status status; + struct feature_fme_pm_ap_threshold threshold; + struct feature_fme_pm_xeon_limit xeon_limit; + struct feature_fme_pm_fpga_limit fpga_limit; +}; + +#define CACHE_CHANNEL_RD 0 +#define CACHE_CHANNEL_WR 1 + +enum iperf_cache_events { + IPERF_CACHE_RD_HIT, + IPERF_CACHE_WR_HIT, + IPERF_CACHE_RD_MISS, + IPERF_CACHE_WR_MISS, + IPERF_CACHE_RSVD, /* reserved */ + IPERF_CACHE_HOLD_REQ, + IPERF_CACHE_DATA_WR_PORT_CONTEN, + IPERF_CACHE_TAG_WR_PORT_CONTEN, + IPERF_CACHE_TX_REQ_STALL, + IPERF_CACHE_RX_REQ_STALL, + IPERF_CACHE_EVICTIONS, +}; + +/* FPMON Cache Control */ +struct feature_fme_ifpmon_ch_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd1:7; /* Reserved */ + u8 freeze:1; /* Freeze if set to 1 */ + u8 rsvd2:7; /* Reserved */ + u8 cache_event:4; /* Select the cache event */ + u8 cci_chsel:1; /* Select the channel */ + u64 rsvd3:43; /* Reserved */ + }; + }; +}; + +/* FPMON Cache Counter */ +struct feature_fme_ifpmon_ch_ctr { + union { + u64 csr; + struct { + /* Cache Counter for even addresse */ + u64 cache_counter:48; + u16 rsvd:12; /* Reserved */ + /* Cache Event being reported */ + u8 event_code:4; + }; + }; +}; + +enum iperf_fab_events { + IPERF_FAB_PCIE0_RD, + IPERF_FAB_PCIE0_WR, + IPERF_FAB_PCIE1_RD, + IPERF_FAB_PCIE1_WR, + IPERF_FAB_UPI_RD, + IPERF_FAB_UPI_WR, + IPERF_FAB_MMIO_RD, + IPERF_FAB_MMIO_WR, +}; + +#define FAB_DISABLE_FILTER 0 +#define FAB_ENABLE_FILTER 1 + +/* FPMON FAB Control */ +struct feature_fme_ifpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_ifpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_ifpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +enum iperf_vtd_events { + IPERF_VTD_AFU_MEM_RD_TRANS, + IPERF_VTD_AFU_MEM_WR_TRANS, + IPERF_VTD_AFU_DEVTLB_RD_HIT, + IPERF_VTD_AFU_DEVTLB_WR_HIT, + IPERF_VTD_DEVTLB_4K_FILL, + IPERF_VTD_DEVTLB_2M_FILL, + IPERF_VTD_DEVTLB_1G_FILL, +}; + +/* VT-d control register */ +struct feature_fme_ifpmon_vtd_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d event counter */ +struct feature_fme_ifpmon_vtd_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +enum iperf_vtd_sip_events { + IPERF_VTD_SIP_IOTLB_4K_HIT, + IPERF_VTD_SIP_IOTLB_2M_HIT, + IPERF_VTD_SIP_IOTLB_1G_HIT, + IPERF_VTD_SIP_SLPWC_L3_HIT, + IPERF_VTD_SIP_SLPWC_L4_HIT, + IPERF_VTD_SIP_RCC_HIT, + IPERF_VTD_SIP_IOTLB_4K_MISS, + IPERF_VTD_SIP_IOTLB_2M_MISS, + IPERF_VTD_SIP_IOTLB_1G_MISS, + IPERF_VTD_SIP_SLPWC_L3_MISS, + IPERF_VTD_SIP_SLPWC_L4_MISS, + IPERF_VTD_SIP_RCC_MISS, +}; + +/* VT-d SIP control register */ +struct feature_fme_ifpmon_vtd_sip_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d SIP event counter */ +struct feature_fme_ifpmon_vtd_sip_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +/* FME IPERF FEATURE */ +struct feature_fme_iperf { + struct feature_header header; + struct feature_fme_ifpmon_ch_ctl ch_ctl; + struct feature_fme_ifpmon_ch_ctr ch_ctr0; + struct feature_fme_ifpmon_ch_ctr ch_ctr1; + struct feature_fme_ifpmon_fab_ctl fab_ctl; + struct feature_fme_ifpmon_fab_ctr fab_ctr; + struct feature_fme_ifpmon_clk_ctr clk; + struct feature_fme_ifpmon_vtd_ctl vtd_ctl; + struct feature_fme_ifpmon_vtd_ctr vtd_ctr; + struct feature_fme_ifpmon_vtd_sip_ctl vtd_sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr vtd_sip_ctr; +}; + +enum dperf_fab_events { + DPERF_FAB_PCIE0_RD, + DPERF_FAB_PCIE0_WR, + DPERF_FAB_MMIO_RD = 6, + DPERF_FAB_MMIO_WR, +}; + +/* FPMON FAB Control */ +struct feature_fme_dfpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_dfpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_dfpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +/* FME DPERF FEATURE */ +struct feature_fme_dperf { + struct feature_header header; + u64 rsvd[3]; + struct feature_fme_dfpmon_fab_ctl fab_ctl; + struct feature_fme_dfpmon_fab_ctr fab_ctr; + struct feature_fme_dfpmon_clk_ctr clk; +}; + +struct feature_fme_error0 { +#define FME_ERROR0_MASK 0xFFUL +#define FME_ERROR0_MASK_DEFAULT 0x40UL /* pcode workaround */ + union { + u64 csr; + struct { + u8 fabric_err:1; /* Fabric error */ + u8 fabfifo_overflow:1; /* Fabric fifo overflow */ + u8 kticdc_parity_err:2;/* KTI CDC Parity Error */ + u8 iommu_parity_err:1; /* IOMMU Parity error */ + /* AFU PF/VF access mismatch detected */ + u8 afu_acc_mode_err:1; + u8 mbp_err:1; /* Indicates an MBP event */ + /* PCIE0 CDC Parity Error */ + u8 pcie0cdc_parity_err:5; + /* PCIE1 CDC Parity Error */ + u8 pcie1cdc_parity_err:5; + /* CVL CDC Parity Error */ + u8 cvlcdc_parity_err:3; + u64 rsvd:44; /* Reserved */ + }; + }; +}; + +/* PCIe0 Error Status register */ +struct feature_fme_pcie0_error { +#define FME_PCIE0_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:52; /* Reserved */ + u8 vfnumb_err:1; /* Number of error VF */ + u8 funct_type_err:1; /* Virtual (1) or Physical */ + }; + }; +}; + +/* PCIe1 Error Status register */ +struct feature_fme_pcie1_error { +#define FME_PCIE1_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:54; /* Reserved */ + }; + }; +}; + +/* FME First Error register */ +struct feature_fme_first_error { +#define FME_FIRST_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered first + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered first + */ + u8 errReg_id:4; + }; + }; +}; + +/* FME Next Error register */ +struct feature_fme_next_error { +#define FME_NEXT_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered second + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered second + */ + u8 errReg_id:4; + }; + }; +}; + +/* RAS Non Fatal Error Status register */ +struct feature_fme_ras_nonfaterror { + union { + u64 csr; + struct { + /* thremal threshold AP1 */ + u8 temp_thresh_ap1:1; + /* thremal threshold AP2 */ + u8 temp_thresh_ap2:1; + u8 pcie_error:1; /* pcie Error */ + u8 portfatal_error:1; /* port fatal error */ + u8 proc_hot:1; /* Indicates a ProcHot event */ + /* Indicates an AFU PF/VF access mismatch */ + u8 afu_acc_mode_err:1; + /* Injected nonfata Error */ + u8 injected_nonfata_err:1; + u8 rsvd1:2; + /* Temperature threshold triggered AP6*/ + u8 temp_thresh_AP6:1; + /* Power threshold triggered AP1 */ + u8 power_thresh_AP1:1; + /* Power threshold triggered AP2 */ + u8 power_thresh_AP2:1; + /* Indicates a MBP event */ + u8 mbp_err:1; + u64 rsvd2:51; /* Reserved */ + }; + }; +}; + +/* RAS Catastrophic Fatal Error Status register */ +struct feature_fme_ras_catfaterror { + union { + u64 csr; + struct { + /* KTI Link layer error detected */ + u8 ktilink_fatal_err:1; + /* tag-n-cache error detected */ + u8 tagcch_fatal_err:1; + /* CCI error detected */ + u8 cci_fatal_err:1; + /* KTI Protocol error detected */ + u8 ktiprpto_fatal_err:1; + /* Fatal DRAM error detected */ + u8 dram_fatal_err:1; + /* IOMMU detected */ + u8 iommu_fatal_err:1; + /* Fabric Fatal Error */ + u8 fabric_fatal_err:1; + /* PCIe possion Error */ + u8 pcie_poison_err:1; + /* Injected fatal Error */ + u8 inject_fata_err:1; + /* Catastrophic CRC Error */ + u8 crc_catast_err:1; + /* Catastrophic Thermal Error */ + u8 therm_catast_err:1; + /* Injected Catastrophic Error */ + u8 injected_catast_err:1; + u64 rsvd:52; + }; + }; +}; + +/* RAS Error injection register */ +struct feature_fme_ras_error_inj { +#define FME_RAS_ERROR_INJ_MASK 0x7UL + union { + u64 csr; + struct { + u8 catast_error:1; /* Catastrophic error flag */ + u8 fatal_error:1; /* Fatal error flag */ + u8 nonfatal_error:1; /* NonFatal error flag */ + u64 rsvd:61; /* Reserved */ + }; + }; +}; + +/* FME error capabilities */ +struct feature_fme_error_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* FME ERR FEATURE */ +struct feature_fme_err { + struct feature_header header; + struct feature_fme_error0 fme_err_mask; + struct feature_fme_error0 fme_err; + struct feature_fme_pcie0_error pcie0_err_mask; + struct feature_fme_pcie0_error pcie0_err; + struct feature_fme_pcie1_error pcie1_err_mask; + struct feature_fme_pcie1_error pcie1_err; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + struct feature_fme_ras_nonfaterror ras_nonfat_mask; + struct feature_fme_ras_nonfaterror ras_nonfaterr; + struct feature_fme_ras_catfaterror ras_catfat_mask; + struct feature_fme_ras_catfaterror ras_catfaterr; + struct feature_fme_ras_error_inj ras_error_inj; + struct feature_fme_error_capability fme_err_capability; +}; + +/* FME Partial Reconfiguration Control */ +struct feature_fme_pr_ctl { + union { + u64 csr; + struct { + u8 pr_reset:1; /* Reset PR Engine */ + u8 rsvd3:3; /* Reserved */ + u8 pr_reset_ack:1; /* Reset PR Engine Ack */ + u8 rsvd4:3; /* Reserved */ + u8 pr_regionid:2; /* PR Region ID */ + u8 rsvd1:2; /* Reserved */ + u8 pr_start_req:1; /* PR Start Request */ + u8 pr_push_complete:1; /* PR Data push complete */ + u8 pr_kind:1; /* PR Data push complete */ + u32 rsvd:17; /* Reserved */ + u32 config_data; /* Config data TBD */ + }; + }; +}; + +/* FME Partial Reconfiguration Status */ +struct feature_fme_pr_status { + union { + u64 csr; + struct { + u16 pr_credit:9; /* PR Credits */ + u8 rsvd2:7; /* Reserved */ + u8 pr_status:1; /* PR status */ + u8 rsvd:3; /* Reserved */ + /* Altra PR Controller Block status */ + u8 pr_controller_status:3; + u8 rsvd1:1; /* Reserved */ + u8 pr_host_status:4; /* PR Host status */ + u8 rsvd3:4; /* Reserved */ + /* Security Block Status fields (TBD) */ + u32 security_bstatus; + }; + }; +}; + +/* FME Partial Reconfiguration Data */ +struct feature_fme_pr_data { + union { + u64 csr; /* PR data from the raw-binary file */ + struct { + /* PR data from the raw-binary file */ + u32 pr_data_raw; + u32 rsvd; + }; + }; +}; + +/* FME PR Public Key */ +struct feature_fme_pr_key { + u64 key; /* FME PR Public Hash */ +}; + +/* FME PR FEATURE */ +struct feature_fme_pr { + struct feature_header header; + /*Partial Reconfiguration control */ + struct feature_fme_pr_ctl ccip_fme_pr_control; + + /* Partial Reconfiguration Status */ + struct feature_fme_pr_status ccip_fme_pr_status; + + /* Partial Reconfiguration data */ + struct feature_fme_pr_data ccip_fme_pr_data; + + /* Partial Reconfiguration data */ + u64 ccip_fme_pr_err; + + u64 rsvd1[3]; + + /* Partial Reconfiguration data registers */ + u64 fme_pr_data1; + u64 fme_pr_data2; + u64 fme_pr_data3; + u64 fme_pr_data4; + u64 fme_pr_data5; + u64 fme_pr_data6; + u64 fme_pr_data7; + u64 fme_pr_data8; + + u64 rsvd2[5]; + + /* PR Interface ID */ + u64 fme_pr_intfc_id_l; + u64 fme_pr_intfc_id_h; + + /* MSIX filed to be Added */ +}; + +/* FME HSSI Control */ +struct feature_fme_hssi_eth_ctrl { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u16 address:16; /* HSSI address */ + /* + * HSSI comamnd + * 0x0 - No request + * 0x08 - SW register RD request + * 0x10 - SW register WR request + * 0x40 - Auxiliar bus RD request + * 0x80 - Auxiliar bus WR request + */ + u16 cmd:16; + }; + }; +}; + +/* FME HSSI Status */ +struct feature_fme_hssi_eth_stat { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u8 acknowledge:1; /* HSSI acknowledge */ + u8 spare:1; /* HSSI spare */ + u32 rsvd:30; /* Reserved */ + }; + }; +}; + +/* FME HSSI FEATURE */ +struct feature_fme_hssi { + struct feature_header header; + struct feature_fme_hssi_eth_ctrl hssi_control; + struct feature_fme_hssi_eth_stat hssi_status; +}; + +#define PORT_ERR_MASK 0xfff0703ff001f +struct feature_port_err_key { + union { + u64 csr; + struct { + /* Tx Channel0: Overflow */ + u8 tx_ch0_overflow:1; + /* Tx Channel0: Invalid request encoding */ + u8 tx_ch0_invaldreq :1; + /* Tx Channel0: Request with cl_len=3 not supported */ + u8 tx_ch0_cl_len3:1; + /* Tx Channel0: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch0_cl_len2:1; + /* Tx Channel0: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch0_cl_len4:1; + + u16 rsvd1:4; /* Reserved */ + + /* AFU MMIO RD received while PORT is in reset */ + u8 mmio_rd_whilerst:1; + /* AFU MMIO WR received while PORT is in reset */ + u8 mmio_wr_whilerst:1; + + u16 rsvd2:5; /* Reserved */ + + /* Tx Channel1: Overflow */ + u8 tx_ch1_overflow:1; + /* Tx Channel1: Invalid request encoding */ + u8 tx_ch1_invaldreq:1; + /* Tx Channel1: Request with cl_len=3 not supported */ + u8 tx_ch1_cl_len3:1; + /* Tx Channel1: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch1_cl_len2:1; + /* Tx Channel1: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch1_cl_len4:1; + + /* Tx Channel1: Insufficient data payload */ + u8 tx_ch1_insuff_data:1; + /* Tx Channel1: Data payload overrun */ + u8 tx_ch1_data_overrun:1; + /* Tx Channel1 : Incorrect address */ + u8 tx_ch1_incorr_addr:1; + /* Tx Channel1 : NON-Zero SOP Detected */ + u8 tx_ch1_nzsop:1; + /* Tx Channel1 : Illegal VC_SEL, atomic request VLO */ + u8 tx_ch1_illegal_vcsel:1; + + u8 rsvd3:6; /* Reserved */ + + /* MMIO Read Timeout in AFU */ + u8 mmioread_timeout:1; + + /* Tx Channel2: FIFO Overflow */ + u8 tx_ch2_fifo_overflow:1; + + /* MMIO read is not matching pending request */ + u8 unexp_mmio_resp:1; + + u8 rsvd4:5; /* Reserved */ + + /* Number of pending Requests: counter overflow */ + u8 tx_req_counter_overflow:1; + /* Req with Address violating SMM Range */ + u8 llpr_smrr_err:1; + /* Req with Address violating second SMM Range */ + u8 llpr_smrr2_err:1; + /* Req with Address violating ME Stolen message */ + u8 llpr_mesg_err:1; + /* Req with Address violating Generic Protected Range */ + u8 genprot_range_err:1; + /* Req with Address violating Legacy Range low */ + u8 legrange_low_err:1; + /* Req with Address violating Legacy Range High */ + u8 legrange_high_err:1; + /* Req with Address violating VGA memory range */ + u8 vgmem_range_err:1; + u8 page_fault_err:1; /* Page fault */ + u8 pmr_err:1; /* PMR Error */ + u8 ap6_event:1; /* AP6 event */ + /* VF FLR detected on Port with PF access control */ + u8 vfflr_access_err:1; + u16 rsvd5:12; /* Reserved */ + }; + }; +}; + +/* Port first error register, not contain all error bits in error register. */ +struct feature_port_first_err_key { + union { + u64 csr; + struct { + u8 tx_ch0_overflow:1; + u8 tx_ch0_invaldreq :1; + u8 tx_ch0_cl_len3:1; + u8 tx_ch0_cl_len2:1; + u8 tx_ch0_cl_len4:1; + u8 rsvd1:4; /* Reserved */ + u8 mmio_rd_whilerst:1; + u8 mmio_wr_whilerst:1; + u8 rsvd2:5; /* Reserved */ + u8 tx_ch1_overflow:1; + u8 tx_ch1_invaldreq:1; + u8 tx_ch1_cl_len3:1; + u8 tx_ch1_cl_len2:1; + u8 tx_ch1_cl_len4:1; + u8 tx_ch1_insuff_data:1; + u8 tx_ch1_data_overrun:1; + u8 tx_ch1_incorr_addr:1; + u8 tx_ch1_nzsop:1; + u8 tx_ch1_illegal_vcsel:1; + u8 rsvd3:6; /* Reserved */ + u8 mmioread_timeout:1; + u8 tx_ch2_fifo_overflow:1; + u8 rsvd4:6; /* Reserved */ + u8 tx_req_counter_overflow:1; + u32 rsvd5:23; /* Reserved */ + }; + }; +}; + +/* Port malformed Req0 */ +struct feature_port_malformed_req0 { + u64 header_lsb; +}; + +/* Port malformed Req1 */ +struct feature_port_malformed_req1 { + u64 header_msb; +}; + +/* Port debug register */ +struct feature_port_debug { + u64 port_debug; +}; + +/* Port error capabilities */ +struct feature_port_err_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE ERROR */ +struct feature_port_error { + struct feature_header header; + struct feature_port_err_key error_mask; + struct feature_port_err_key port_error; + struct feature_port_first_err_key port_first_error; + struct feature_port_malformed_req0 malreq0; + struct feature_port_malformed_req1 malreq1; + struct feature_port_debug port_debug; + struct feature_port_err_capability error_capability; +}; + +/* Port UMSG Capability */ +struct feature_port_umsg_cap { + union { + u64 csr; + struct { + /* Number of umsg allocated to this port */ + u8 umsg_allocated; + /* Enable / Disable UMsg engine for this port */ + u8 umsg_enable:1; + /* Usmg initialization status */ + u8 umsg_init_complete:1; + /* IOMMU can not translate the umsg base address */ + u8 umsg_trans_error:1; + u64 rsvd:53; /* Reserved */ + }; + }; +}; + +/* Port UMSG base address */ +struct feature_port_umsg_baseaddr { + union { + u64 csr; + struct { + u64 base_addr:48; /* 48 bit physical address */ + u16 rsvd; /* Reserved */ + }; + }; +}; + +struct feature_port_umsg_mode { + union { + u64 csr; + struct { + u32 umsg_hint_enable; /* UMSG hint enable/disable */ + u32 rsvd; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE UMSG */ +struct feature_port_umsg { + struct feature_header header; + struct feature_port_umsg_cap capability; + struct feature_port_umsg_baseaddr baseaddr; + struct feature_port_umsg_mode mode; +}; + +#define UMSG_EN_POLL_INVL 10 /* us */ +#define UMSG_EN_POLL_TIMEOUT 1000 /* us */ + +/* Port UINT Capability */ +struct feature_port_uint_cap { + union { + u64 csr; + struct { + u16 intr_num:12; /* Supported interrupts num */ + /* First MSI-X vector table entry number */ + u16 first_vec_num:12; + u64 rsvd:40; + }; + }; +}; + +/* PORT FEATURE UINT */ +struct feature_port_uint { + struct feature_header header; + struct feature_port_uint_cap capability; +}; + +/* STP region supports mmap operation, so use page aligned size. */ +#define PORT_FEATURE_STP_REGION_SIZE PAGE_ALIGN(sizeof(struct feature_port_stp)) + +/* Port STP status register (for debug only)*/ +struct feature_port_stp_status { + union { + u64 csr; + struct { + /* SLD Hub end-point read/write timeout */ + u8 sld_ep_timeout:1; + /* Remote STP in reset/disable */ + u8 rstp_disabled:1; + u8 unsupported_read:1; + /* MMIO timeout detected and faked with a response */ + u8 mmio_timeout:1; + u8 txfifo_count:4; + u8 rxfifo_count:4; + u8 txfifo_overflow:1; + u8 txfifo_underflow:1; + u8 rxfifo_overflow:1; + u8 rxfifo_underflow:1; + /* Number of MMIO write requests */ + u16 write_requests; + /* Number of MMIO read requests */ + u16 read_requests; + /* Number of MMIO read responses */ + u16 read_responses; + }; + }; +}; + +/* + * PORT FEATURE STP + * Most registers in STP region are not touched by driver, but mmapped to user + * space. So they are not defined in below data structure, as its actual size + * is 0x18c per spec. + */ +struct feature_port_stp { + struct feature_header header; + struct feature_port_stp_status stp_status; +}; + +/** + * enum fpga_pr_states - fpga PR states + * @FPGA_PR_STATE_UNKNOWN: can't determine state + * @FPGA_PR_STATE_WRITE_INIT: preparing FPGA for programming + * @FPGA_PR_STATE_WRITE_INIT_ERR: Error during WRITE_INIT stage + * @FPGA_PR_STATE_WRITE: writing image to FPGA + * @FPGA_PR_STATE_WRITE_ERR: Error while writing FPGA + * @FPGA_PR_STATE_WRITE_COMPLETE: Doing post programming steps + * @FPGA_PR_STATE_WRITE_COMPLETE_ERR: Error during WRITE_COMPLETE + * @FPGA_PR_STATE_OPERATING: FPGA PR done + */ +enum fpga_pr_states { + /* canot determine state states */ + FPGA_PR_STATE_UNKNOWN, + + /* write sequence: init, write, complete */ + FPGA_PR_STATE_WRITE_INIT, + FPGA_PR_STATE_WRITE_INIT_ERR, + FPGA_PR_STATE_WRITE, + FPGA_PR_STATE_WRITE_ERR, + FPGA_PR_STATE_WRITE_COMPLETE, + FPGA_PR_STATE_WRITE_COMPLETE_ERR, + + /* FPGA PR done */ + FPGA_PR_STATE_DONE, +}; + +/* + * FPGA Manager flags + * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported + */ +#define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + +/** + * struct fpga_pr_info - specific information to a FPGA PR + * @flags: boolean flags as defined above + * @pr_err: PR error code + * @state: fpga manager state + * @port_id: port id + */ +struct fpga_pr_info { + u32 flags; + u64 pr_err; + enum fpga_pr_states state; + int port_id; +}; + +#define DEFINE_FPGA_PR_ERR_MSG(_name_) \ +static const char * const _name_[] = { \ + "PR operation error detected", \ + "PR CRC error detected", \ + "PR incompatiable bitstream error detected", \ + "PR IP protocol error detected", \ + "PR FIFO overflow error detected", \ + "PR timeout error detected", \ + "PR secure load error detected", \ +} + +#define RST_POLL_INVL 10 /* us */ +#define RST_POLL_TIMEOUT 1000 /* us */ + +#define PR_WAIT_TIMEOUT 15000000 + +#define PR_HOST_STATUS_IDLE 0 +#define PR_MAX_ERR_NUM 7 + +DEFINE_FPGA_PR_ERR_MSG(pr_err_msg); + +/* + * green bitstream header must be byte-packed to match the + * real file format. + */ +struct bts_header { + u64 guid_h; + u64 guid_l; + u32 metadata_len; +}; + +#define GBS_GUID_H 0x414750466e6f6558 +#define GBS_GUID_L 0x31303076534247b7 +#define is_valid_bts(bts_hdr) \ + (((bts_hdr)->guid_h == GBS_GUID_H) && \ + ((bts_hdr)->guid_l == GBS_GUID_L)) + +#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 new file mode 100644 index 0000000..10a8f06 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -0,0 +1,824 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_hw_api.h" +#include "ifpga_api.h" + +#include "ifpga_hw.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +struct build_feature_devs_info { + struct opae_adapter_data_pci *pci_data; + + struct ifpga_afu_info *acc_info; + + void *fiu; + enum fpga_id_type current_type; + int current_port_id; + + void *ioaddr; + void *ioend; + uint64_t phys_addr; + int current_bar; + + void *pfme_hdr; + + struct ifpga_hw *hw; +}; + +struct feature_info { + const char *name; + uint32_t resource_size; + int feature_index; + int revision_id; + unsigned int vec_start; + unsigned int vec_cnt; + + struct feature_ops *ops; +}; + +/* 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, + } +}; + +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 = &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 = &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 = &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 = &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 + }, +}; + +static u64 feature_id(void __iomem *start) +{ + struct feature_header header; + + header.csr = readq(start); + + switch (header.type) { + case FEATURE_TYPE_FIU: + return FEATURE_ID_HEADER; + case FEATURE_TYPE_PRIVATE: + return header.id; + case FEATURE_TYPE_AFU: + return FEATURE_ID_AFU; + } + + WARN_ON(1); + return 0; +} + +static int +build_info_add_sub_feature(struct build_feature_devs_info *binfo, + struct feature_info *finfo, void __iomem *start) +{ + 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; + } + + 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->phys_addr = binfo->phys_addr + + ((u8 *)start - (u8 *)binfo->ioaddr); + + if (vec_cnt) { + if (vec_start + vec_cnt <= vec_start) + return -EINVAL; + + ctx = zmalloc(sizeof(*ctx) * vec_cnt); + if (!ctx) + return -ENOMEM; + + for (i = 0; i < vec_cnt; i++) { + ctx[i].eventfd = -1; + ctx[i].idx = vec_start + i; + } + } + + feature->ctx = ctx; + feature->ctx_num = vec_cnt; + feature->vfio_dev_fd = binfo->pci_data->vfio_dev_fd; + + return ret; +} + +static int +create_feature_instance(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + struct feature_header *hdr = start; + + if (((u8 *)binfo->ioend - (u8 *)start) < finfo->resource_size) + return -EINVAL; + + 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); +} + +/* + * UAFU GUID is dynamic as it can be changed after FME downloads different + * Green Bitstream to the port, so we treat the unknown GUIDs which are + * attached on port's feature list as UAFU. + */ +static bool feature_is_UAFU(struct build_feature_devs_info *binfo) +{ + if (binfo->current_type != PORT_ID) + return false; + + return true; +} + +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; + struct ifpga_afu_info *info; + void *start = (void *)hdr; + int ret; + + 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; + } + + if (ret) + return ret; + + /* FIXME: need to figure out a better name */ + info = 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->num_regions = 1; + + binfo->acc_info = info; + + return ret; +} + +static int parse_feature_afus(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + int ret; + struct feature_afu_header *afu_hdr, header; + u8 __iomem *start; + u8 __iomem *end = binfo->ioend; + + start = (u8 __iomem *)hdr; + for (; start < end; start += header.next_afu) { + if (end - start < + (unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr))) + return -EINVAL; + + hdr = (struct feature_header *)start; + afu_hdr = (struct feature_afu_header *)(hdr + 1); + header.csr = readq(&afu_hdr->csr); + + if (feature_is_UAFU(binfo)) { + ret = parse_feature_port_uafu(binfo, hdr); + if (ret) + return ret; + } + + if (!header.next_afu) + break; + } + + return 0; +} + +/* create and register proper private data */ +static int build_info_commit_dev(struct build_feature_devs_info *binfo) +{ + struct ifpga_afu_info *info = binfo->acc_info; + struct ifpga_hw *hw = binfo->hw; + struct opae_manager *mgr; + struct opae_bridge *br; + struct opae_accelerator *acc; + + if (!binfo->fiu) + return 0; + + if (binfo->current_type == PORT_ID) { + /* return error if no valid acc info data structure */ + if (!info) + return -EFAULT; + + br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops, + binfo->fiu); + if (!br) + return -ENOMEM; + + br->id = binfo->current_port_id; + + /* update irq info */ + info->num_irqs = port_features[PORT_FEATURE_ID_UINT].vec_cnt; + + acc = opae_accelerator_alloc(hw->adapter->name, + &ifpga_acc_ops, info); + if (!acc) { + opae_bridge_free(br); + return -ENOMEM; + } + + acc->br = br; + acc->index = br->id; + + opae_adapter_add_acc(hw->adapter, acc); + + } else if (binfo->current_type == FME_ID) { + mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops, + binfo->fiu); + if (!mgr) + return -ENOMEM; + + mgr->adapter = hw->adapter; + hw->adapter->mgr = mgr; + } + + binfo->fiu = NULL; + + return 0; +} + +static int +build_info_create_dev(struct build_feature_devs_info *binfo, + enum fpga_id_type type, unsigned int index) +{ + int ret; + + ret = build_info_commit_dev(binfo); + if (ret) + return ret; + + binfo->current_type = type; + + if (type == FME_ID) { + binfo->fiu = &binfo->hw->fme; + } else if (type == PORT_ID) { + binfo->fiu = &binfo->hw->port[index]; + binfo->current_port_id = index; + } + + return 0; +} + +static int parse_feature_fme(struct build_feature_devs_info *binfo, + struct feature_header *start) +{ + struct ifpga_hw *hw = binfo->hw; + struct ifpga_fme_hw *fme = &hw->fme; + int ret; + + ret = build_info_create_dev(binfo, FME_ID, 0); + if (ret) + return ret; + + /* Update FME states */ + fme->state = IFPGA_FME_IMPLEMENTED; + fme->parent = hw; + spinlock_init(&fme->lock); + + return create_feature_instance(binfo, start, + &fme_features[FME_FEATURE_ID_HEADER]); +} + +static int parse_feature_port(struct build_feature_devs_info *binfo, + void __iomem *start) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + struct ifpga_hw *hw = binfo->hw; + struct ifpga_port_hw *port; + unsigned int port_id; + int ret; + + /* Get current port's id */ + port_hdr = (struct feature_port_header *)start; + capability.csr = readq(&port_hdr->capability); + port_id = capability.port_number; + + ret = build_info_create_dev(binfo, PORT_ID, port_id); + if (ret) + return ret; + + /*found a Port device*/ + port = &hw->port[port_id]; + port->port_id = binfo->current_port_id; + port->parent = hw; + port->state = IFPGA_PORT_ATTACHED; + spinlock_init(&port->lock); + + return create_feature_instance(binfo, start, + &port_features[PORT_FEATURE_ID_HEADER]); +} + +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); +} + +static int parse_feature_fiu(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + struct feature_fiu_header *fiu_hdr, fiu_header; + u8 __iomem *start = (u8 __iomem *)hdr; + int ret; + + header.csr = readq(hdr); + + switch (header.id) { + case FEATURE_FIU_ID_FME: + ret = parse_feature_fme(binfo, hdr); + binfo->pfme_hdr = hdr; + if (ret) + return ret; + break; + case FEATURE_FIU_ID_PORT: + ret = parse_feature_port(binfo, hdr); + enable_port_uafu(binfo, hdr); + if (ret) + return ret; + + /* Check Port FIU's next_afu pointer to User AFU DFH */ + fiu_hdr = (struct feature_fiu_header *)(hdr + 1); + fiu_header.csr = readq(&fiu_hdr->csr); + + if (fiu_header.next_afu) { + start += fiu_header.next_afu; + ret = parse_feature_afus(binfo, + (struct feature_header *)start); + if (ret) + return ret; + } else { + dev_info(binfo, "No AFUs detected on Port\n"); + } + + break; + default: + dev_info(binfo, "FIU TYPE %d is not supported yet.\n", + header.id); + } + + return 0; +} + +static void parse_feature_irqs(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + finfo->vec_start = 0; + finfo->vec_cnt = 0; + + UNUSED(binfo); + + if (!strcmp(finfo->name, PORT_FEATURE_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; + } else { + dev_debug(binfo, "UAFU doesn't support interrupt\n"); + } + } else if (!strcmp(finfo->name, PORT_FEATURE_ERR)) { + 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; + } else { + dev_debug(&binfo, "Port error doesn't support interrupt\n"); + } + + } else if (!strcmp(finfo->name, FME_FEATURE_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; + } else { + dev_debug(&binfo, "FME error doesn't support interrupt\n"); + } + } +} + +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; + } + + parse_feature_irqs(binfo, hdr, &fme_features[header.id]); + + return create_feature_instance(binfo, hdr, &fme_features[header.id]); +} + +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; + + 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]); + + return create_feature_instance(binfo, hdr, &port_features[id]); +} + +static int parse_feature_private(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + + header.csr = readq(hdr); + + switch (binfo->current_type) { + case FME_ID: + return parse_feature_fme_private(binfo, hdr); + case PORT_ID: + return parse_feature_port_private(binfo, hdr); + default: + dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n", + header.id, binfo->current_type); + } + return 0; +} + +static int parse_feature(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + int ret = 0; + + header.csr = readq(hdr); + + switch (header.type) { + case FEATURE_TYPE_AFU: + ret = parse_feature_afus(binfo, hdr); + break; + case FEATURE_TYPE_PRIVATE: + ret = parse_feature_private(binfo, hdr); + break; + case FEATURE_TYPE_FIU: + ret = parse_feature_fiu(binfo, hdr); + break; + default: + dev_err(binfo, "Feature Type %x is not supported.\n", + hdr->type); + }; + + return ret; +} + +static int +parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start) +{ + struct feature_header *hdr, header; + u8 __iomem *end = (u8 __iomem *)binfo->ioend; + int ret = 0; + + for (; start < end; start += header.next_header_offset) { + if (end - start < (unsigned int)sizeof(*hdr)) { + dev_err(binfo, "The region is too small to contain a feature.\n"); + ret = -EINVAL; + break; + } + + hdr = (struct feature_header *)start; + ret = parse_feature(binfo, hdr); + if (ret) + return ret; + + header.csr = readq(hdr); + if (!header.next_header_offset) + break; + } + + return build_info_commit_dev(binfo); +} + +/* switch the memory mapping to BAR# @bar */ +static int parse_switch_to(struct build_feature_devs_info *binfo, int bar) +{ + struct opae_adapter_data_pci *pci_data = binfo->pci_data; + + if (!pci_data->region[bar].addr) + return -ENOMEM; + + binfo->ioaddr = pci_data->region[bar].addr; + binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len; + binfo->phys_addr = pci_data->region[bar].phys_addr; + binfo->current_bar = bar; + + return 0; +} + +static int parse_ports_from_fme(struct build_feature_devs_info *binfo) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_port port; + int i = 0, ret = 0; + + if (!binfo->pfme_hdr) { + dev_info(binfo, "VF is detected.\n"); + return ret; + } + + fme_hdr = binfo->pfme_hdr; + + do { + port.csr = readq(&fme_hdr->port[i]); + if (!port.port_implemented) + break; + + /* skip port which only could be accessed via VF */ + if (port.afu_access_control == FME_AFU_ACCESS_VF) + continue; + + ret = parse_switch_to(binfo, port.port_bar); + if (ret) + break; + + ret = parse_feature_list(binfo, + (u8 __iomem *)binfo->ioaddr + + port.port_offset); + if (ret) + break; + } while (++i < MAX_FPGA_PORT_NUM); + + return ret; +} + +static struct build_feature_devs_info * +build_info_alloc_and_init(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + + binfo = zmalloc(sizeof(*binfo)); + if (!binfo) + return binfo; + + binfo->hw = hw; + binfo->pci_data = hw->pci_data; + + /* fpga feature list starts from BAR 0 */ + if (parse_switch_to(binfo, 0)) { + free(binfo); + return NULL; + } + + return binfo; +} + +static void build_info_free(struct build_feature_devs_info *binfo) +{ + free(binfo); +} + +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; + + 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]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr: 0x%lx\n", + feature->name, (unsigned long long)feature->addr, + (unsigned long long)feature->addr + feature->size - 1, + feature->phys_addr); + } + + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) { + port = &hw->port[i]; + + if (port->state != IFPGA_PORT_ATTACHED) + continue; + + dev_info(hw, "port device: %d\n", port->port_id); + + for (j = 0; j < PORT_FEATURE_ID_MAX; j++) { + feature = &port->sub_feature[j]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr:0x%lx\n", + feature->name, + (unsigned long long)feature->addr, + (unsigned long long)feature->addr + + feature->size - 1, + feature->phys_addr); + } + } +} + +int ifpga_bus_enumerate(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + int ret; + + binfo = build_info_alloc_and_init(hw); + if (!binfo) + return -ENOMEM; + + ret = parse_feature_list(binfo, binfo->ioaddr); + if (ret) + goto exit; + + ret = parse_ports_from_fme(binfo); + if (ret) + goto exit; + + ifpga_print_device_feature_list(hw); + +exit: + build_info_free(binfo); + return ret; +} + +int ifpga_bus_init(struct ifpga_hw *hw) +{ + int i; + + fme_hw_init(&hw->fme); + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) + port_hw_init(&hw->port[i]); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h new file mode 100644 index 0000000..14131e3 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_ENUMERATE_H_ +#define _IFPGA_ENUMERATE_H_ + +int ifpga_bus_init(struct ifpga_hw *hw); +int ifpga_bus_enumerate(struct ifpga_hw *hw); + +#endif /* _IFPGA_ENUMERATE_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c new file mode 100644 index 0000000..6d14523 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -0,0 +1,314 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <linux/vfio.h> +#include <sys/ioctl.h> + +#include "ifpga_feature_dev.h" + +/* + * Enable Port by clear the port soft reset bit, which is set by default. + * The AFU is unable to respond to any MMIO access while in reset. + * __fpga_port_enable function should only be used after __fpga_port_disable + * function. + */ +void __fpga_port_enable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + WARN_ON(!port->disable_count); + + if (--port->disable_count != 0) + return; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x0; + writeq(control.csr, &port_hdr->control); +} + +int __fpga_port_disable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + if (port->disable_count++ != 0) + return 0; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + /* Set port soft reset */ + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x1; + writeq(control.csr, &port_hdr->control); + + /* + * HW sets ack bit to 1 when all outstanding requests have been drained + * on this port and minimum soft reset pulse width has elapsed. + * Driver polls port_soft_reset_ack to determine if reset done by HW. + */ + control.port_sftrst_ack = 1; + + if (fpga_wait_register_field(port_sftrst_ack, control, + &port_hdr->control, RST_POLL_TIMEOUT, + RST_POLL_INVL)) { + dev_err(port, "timeout, fail to reset device\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) +{ + struct feature_port_header *port_hdr; + u64 guidl, guidh; + + port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU); + + spinlock_lock(&port->lock); + guidl = readq(&port_hdr->afu_header.guid.b[0]); + guidh = readq(&port_hdr->afu_header.guid.b[8]); + spinlock_unlock(&port->lock); + + printf("%s: guidl=0x%lx, guidh=0x%lx\n", __func__, guidl, guidh); + + memcpy(uuid->b, &guidl, sizeof(u64)); + memcpy(uuid->b + 8, &guidh, sizeof(u64)); + + return 0; +} + +/* Mask / Unmask Port Errors by the Error Mask register. */ +void port_err_mask(struct ifpga_port_hw *port, bool mask) +{ + struct feature_port_error *port_err; + struct feature_port_err_key err_mask; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + if (mask) + err_mask.csr = PORT_ERR_MASK; + else + err_mask.csr = 0; + + writeq(err_mask.csr, &port_err->error_mask); +} + +/* Clear All Port Errors. */ +int port_err_clear(struct ifpga_port_hw *port, u64 err) +{ + struct feature_port_header *port_hdr; + struct feature_port_error *port_err; + struct feature_port_err_key mask; + struct feature_port_first_err_key first; + struct feature_port_status status; + int ret = 0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + /* + * Clear All Port Errors + * + * - Check for AP6 State + * - Halt Port by keeping Port in reset + * - Set PORT Error mask to all 1 to mask errors + * - Clear all errors + * - Set Port mask to all 0 to enable errors + * - All errors start capturing new errors + * - Enable Port by pulling the port out of reset + */ + + /* If device is still in AP6 state, can not clear any error.*/ + status.csr = readq(&port_hdr->status); + if (status.power_state == PORT_POWER_STATE_AP6) { + dev_err(dev, "Could not clear errors, device in AP6 state.\n"); + return -EBUSY; + } + + /* Halt Port by keeping Port in reset */ + ret = __fpga_port_disable(port); + if (ret) + return ret; + + /* Mask all errors */ + port_err_mask(port, true); + + /* Clear errors if err input matches with current port errors.*/ + mask.csr = readq(&port_err->port_error); + + if (mask.csr == err) { + writeq(mask.csr, &port_err->port_error); + + first.csr = readq(&port_err->port_first_error); + writeq(first.csr, &port_err->port_first_error); + } else { + ret = -EBUSY; + } + + /* Clear mask */ + port_err_mask(port, false); + + /* Enable the Port by clear the reset */ + __fpga_port_enable(port); + + return ret; +} + +int port_clear_error(struct ifpga_port_hw *port) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + + dev_info(port, "read port error: 0x%lx\n", error.csr); + + return port_err_clear(port, error.csr); +} + +void fme_hw_uinit(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return; + + 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); + } +} + +int fme_hw_init(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i, ret; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + 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; + } + } + } + + return 0; +} + +void port_hw_uinit(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i; + + 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); + } +} + +int port_hw_init(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i, 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; + } + } + } + + return 0; +} + +/* + * FIXME: we should get msix vec count during pci enumeration instead of + * below hardcode value. + */ +#define FPGA_MSIX_VEC_COUNT 20 +/* irq set buffer length for interrupt */ +#define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \ + sizeof(int) * FPGA_MSIX_VEC_COUNT) + +/* only support msix for now*/ +static int vfio_msix_enable_block(s32 vfio_dev_fd, unsigned int vec_start, + unsigned int count, s32 *fds) +{ + char irq_set_buf[MSIX_IRQ_SET_BUF_LEN]; + struct vfio_irq_set *irq_set; + int len, ret; + int *fd_ptr; + + len = sizeof(irq_set_buf); + + irq_set = (struct vfio_irq_set *)irq_set_buf; + irq_set->argsz = len; + irq_set->count = count; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; + irq_set->start = vec_start; + + fd_ptr = (int *)&irq_set->data; + memcpy(fd_ptr, fds, sizeof(int) * count); + + ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set); + if (ret) + printf("Error enabling MSI-X interrupts\n"); + + return ret; +} + +int fpga_msix_set_block(struct feature *feature, unsigned int start, + unsigned int count, s32 *fds) +{ + struct feature_irq_ctx *ctx = feature->ctx; + unsigned int i; + int ret; + + if (start >= feature->ctx_num || start + count > feature->ctx_num) + return -EINVAL; + + /* assume that each feature has continuous vector space in msix*/ + ret = vfio_msix_enable_block(feature->vfio_dev_fd, + ctx[start].idx, count, fds); + if (!ret) { + for (i = 0; i < count; i++) + ctx[i].eventfd = fds[i]; + } + + return ret; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h new file mode 100644 index 0000000..cd114fb --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_FEATURE_DEV_H_ +#define _IFPGA_FEATURE_DEV_H_ + +#include "ifpga_hw.h" + +static inline struct ifpga_port_hw * +get_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return NULL; + + return &hw->port[port_id]; +} + +#define ifpga_for_each_feature(hw, feature) \ + for ((feature) = (hw)->sub_feature; \ + (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++) + +static inline struct feature * +get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(fme, feature) { + if (feature->id == id) + return feature; + } + + return NULL; +} + +static inline struct feature * +get_port_feature_by_id(struct ifpga_port_hw *port, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(port, feature) { + 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; +} + +static inline void * +get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index) +{ + return port->sub_feature[index].addr; +} + +static inline bool +is_fme_feature_present(struct ifpga_fme_hw *fme, int index) +{ + return !!get_fme_feature_ioaddr_by_index(fme, index); +} + +static inline bool +is_port_feature_present(struct ifpga_port_hw *port, int index) +{ + return !!get_port_feature_ioaddr_by_index(port, index); +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid); + +int __fpga_port_disable(struct ifpga_port_hw *port); +void __fpga_port_enable(struct ifpga_port_hw *port); + +static inline int fpga_port_disable(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_disable(port); + spinlock_unlock(&port->lock); + return ret; +} + +static inline int fpga_port_enable(struct ifpga_port_hw *port) +{ + spinlock_lock(&port->lock); + __fpga_port_enable(port); + spinlock_unlock(&port->lock); + + return 0; +} + +static inline int __fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + ret = __fpga_port_disable(port); + if (ret) + return ret; + + __fpga_port_enable(port); + + return 0; +} + +static inline int fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_reset(port); + spinlock_unlock(&port->lock); + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +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); +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set); + +int fme_hw_init(struct ifpga_fme_hw *fme); +void fme_hw_uinit(struct ifpga_fme_hw *fme); +void port_hw_uinit(struct ifpga_port_hw *port); +int port_hw_init(struct ifpga_port_hw *port); +int port_clear_error(struct ifpga_port_hw *port); +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; + +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); + +/* This struct is used when parsing uafu irq_set */ +struct fpga_uafu_irq_set { + u32 start; + u32 count; + s32 *evtfds; +}; + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set); + +extern struct feature_ops port_hdr_ops; +extern struct feature_ops port_error_ops; +extern struct feature_ops port_stp_ops; +extern struct feature_ops port_uint_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 new file mode 100644 index 0000000..4be60c0 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -0,0 +1,734 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PWR_THRESHOLD_MAX 0x7F + +int fme_get_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +/* fme private feature head */ +static int fme_hdr_init(struct feature *feature) +{ + struct feature_fme_header *fme_hdr; + + fme_hdr = (struct feature_fme_header *)feature->addr; + + dev_info(NULL, "FME HDR Init.\n"); + dev_info(NULL, "FME cap %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + return 0; +} + +static void fme_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME HDR UInit.\n"); +} + +static int fme_hdr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&fme_hdr->header); + *revision = header.revision; + + return 0; +} + +static int fme_hdr_get_ports_num(struct ifpga_fme_hw *fme, u64 *ports_num) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *ports_num = fme_capability.num_ports; + + return 0; +} + +static int fme_hdr_get_cache_size(struct ifpga_fme_hw *fme, u64 *cache_size) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *cache_size = fme_capability.cache_size; + + return 0; +} + +static int fme_hdr_get_version(struct ifpga_fme_hw *fme, u64 *version) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *version = fme_capability.fabric_verid; + + return 0; +} + +static int fme_hdr_get_socket_id(struct ifpga_fme_hw *fme, u64 *socket_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *socket_id = fme_capability.socket_id; + + return 0; +} + +static int fme_hdr_get_bitstream_id(struct ifpga_fme_hw *fme, + u64 *bitstream_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_id = readq(&fme_hdr->bitstream_id); + + return 0; +} + +static int fme_hdr_get_bitstream_metadata(struct ifpga_fme_hw *fme, + u64 *bitstream_metadata) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_metadata = readq(&fme_hdr->bitstream_md); + + return 0; +} + +static int +fme_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_HDR_PROP_REVISION: + return fme_hdr_get_revision(fme, &prop->data); + case FME_HDR_PROP_PORTS_NUM: + return fme_hdr_get_ports_num(fme, &prop->data); + case FME_HDR_PROP_CACHE_SIZE: + return fme_hdr_get_cache_size(fme, &prop->data); + case FME_HDR_PROP_VERSION: + return fme_hdr_get_version(fme, &prop->data); + case FME_HDR_PROP_SOCKET_ID: + return fme_hdr_get_socket_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_ID: + return fme_hdr_get_bitstream_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_METADATA: + return fme_hdr_get_bitstream_metadata(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_hdr_ops = { + .init = fme_hdr_init, + .uinit = fme_hdr_uinit, + .get_prop = fme_hdr_get_prop, +}; + +/* thermal management */ +static int fme_thermal_get_threshold1(struct ifpga_fme_hw *fme, u64 *thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1 = temp_threshold.tmp_thshold1; + + return 0; +} + +static int fme_thermal_set_threshold1(struct ifpga_fme_hw *fme, u64 thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres1 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres1 == 0) { + tmp_threshold.tmp_thshold1_enable = 0; + tmp_threshold.tmp_thshold1 = thres1; + } else { + tmp_threshold.tmp_thshold1_enable = 1; + tmp_threshold.tmp_thshold1 = thres1; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold2(struct ifpga_fme_hw *fme, u64 *thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres2 = temp_threshold.tmp_thshold2; + + return 0; +} + +static int fme_thermal_set_threshold2(struct ifpga_fme_hw *fme, u64 thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres2 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres2 == 0) { + tmp_threshold.tmp_thshold2_enable = 0; + tmp_threshold.tmp_thshold2 = thres2; + } else { + tmp_threshold.tmp_thshold2_enable = 1; + tmp_threshold.tmp_thshold2 = thres2; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold_trip(struct ifpga_fme_hw *fme, + u64 *thres_trip) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres_trip = temp_threshold.therm_trip_thshold; + + return 0; +} + +static int fme_thermal_get_threshold1_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold1_status; + + return 0; +} + +static int fme_thermal_get_threshold2_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold2_status; + + return 0; +} + +static int fme_thermal_get_threshold1_policy(struct ifpga_fme_hw *fme, + u64 *thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_policy = temp_threshold.thshold_policy; + + return 0; +} + +static int fme_thermal_set_threshold1_policy(struct ifpga_fme_hw *fme, + u64 thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold tmp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + + if (thres1_policy == 0) { + tmp_threshold.thshold_policy = 0; + } else if (thres1_policy == 1) { + tmp_threshold.thshold_policy = 1; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_temperature(struct ifpga_fme_hw *fme, u64 *temp) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_temp_rdsensor_fmt1 temp_rdsensor_fmt1; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_rdsensor_fmt1.csr = readq(&thermal->rdsensor_fm1); + *temp = temp_rdsensor_fmt1.fpga_temp; + + return 0; +} + +static int fme_thermal_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_thermal *fme_thermal + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + struct feature_header header; + + header.csr = readq(&fme_thermal->header); + *revision = header.revision; + + return 0; +} + +#define FME_THERMAL_CAP_NO_TMP_THRESHOLD 0x1 + +static int fme_thermal_mgmt_init(struct feature *feature) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold_cap thermal_cap; + + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt Init.\n"); + + fme_thermal = (struct feature_fme_thermal *)feature->addr; + thermal_cap.csr = readq(&fme_thermal->threshold_cap); + + dev_info(NULL, "FME thermal cap %llx.\n", + (unsigned long long)fme_thermal->threshold_cap.csr); + + if (thermal_cap.tmp_thshold_disabled) + feature->cap |= FME_THERMAL_CAP_NO_TMP_THRESHOLD; + + return 0; +} + +static void fme_thermal_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt UInit.\n"); +} + +static int +fme_thermal_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_set_threshold1(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_set_threshold2(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_set_threshold1_policy(fme, prop->data); + } + + return -ENOENT; +} + +static int +fme_thermal_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD && + prop->prop_id != FME_THERMAL_PROP_TEMPERATURE && + prop->prop_id != FME_THERMAL_PROP_REVISION) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_get_threshold1(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_get_threshold2(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD_TRIP: + return fme_thermal_get_threshold_trip(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_REACHED: + return fme_thermal_get_threshold1_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2_REACHED: + return fme_thermal_get_threshold2_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_get_threshold1_policy(fme, &prop->data); + case FME_THERMAL_PROP_TEMPERATURE: + return fme_thermal_get_temperature(fme, &prop->data); + case FME_THERMAL_PROP_REVISION: + return fme_thermal_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_thermal_mgmt_ops = { + .init = fme_thermal_mgmt_init, + .uinit = fme_thermal_mgmt_uinit, + .get_prop = fme_thermal_get_prop, + .set_prop = fme_thermal_set_prop, +}; + +static int fme_pwr_get_consumed(struct ifpga_fme_hw *fme, u64 *consumed) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *consumed = pm_status.pwr_consumed; + + return 0; +} + +static int fme_pwr_get_threshold1(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold1; + + return 0; +} + +static int fme_pwr_set_threshold1(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold1 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold2(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold2; + + return 0; +} + +static int fme_pwr_set_threshold2(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold2 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold1_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold1_status; + + return 0; +} + +static int fme_pwr_get_threshold2_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold2_status; + + return 0; +} + +static int fme_pwr_get_rtl(struct ifpga_fme_hw *fme, u64 *rtl) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *rtl = pm_status.fpga_latency_report; + + return 0; +} + +static int fme_pwr_get_xeon_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_xeon_limit xeon_limit; + + xeon_limit.csr = readq(&fme_power->xeon_limit); + + if (!xeon_limit.enable) + xeon_limit.pwr_limit = 0; + + *limit = xeon_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_fpga_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_fpga_limit fpga_limit; + + fpga_limit.csr = readq(&fme_power->fpga_limit); + + if (!fpga_limit.enable) + fpga_limit.pwr_limit = 0; + + *limit = fpga_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_header header; + + header.csr = readq(&fme_power->header); + *revision = header.revision; + + return 0; +} + +static int fme_power_mgmt_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt Init.\n"); + + return 0; +} + +static void fme_power_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt UInit.\n"); +} + +static int fme_power_mgmt_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_CONSUMED: + return fme_pwr_get_consumed(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_get_threshold1(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_get_threshold2(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1_STATUS: + return fme_pwr_get_threshold1_status(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2_STATUS: + return fme_pwr_get_threshold2_status(fme, &prop->data); + case FME_PWR_PROP_RTL: + return fme_pwr_get_rtl(fme, &prop->data); + case FME_PWR_PROP_XEON_LIMIT: + return fme_pwr_get_xeon_limit(fme, &prop->data); + case FME_PWR_PROP_FPGA_LIMIT: + return fme_pwr_get_fpga_limit(fme, &prop->data); + case FME_PWR_PROP_REVISION: + return fme_pwr_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_power_mgmt_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_set_threshold1(fme, prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_set_threshold2(fme, prop->data); + } + + return -ENOENT; +} + +struct 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, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c new file mode 100644 index 0000000..1773b87 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_dperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_clk_ctr clk; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + clk.afu_interf_clock = readq(&dperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_dperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_dperf *dperf; + struct feature_header header; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + header.csr = readq(&dperf->header); + *revision = header.revision; + + return 0; +} + +#define DPERF_TIMEOUT 30 + +static bool fabric_pobj_is_enabled(int port_id, + struct feature_fme_dperf *dperf) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + + ctl.csr = readq(&dperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum dperf_fab_events fab_event) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dfpmon_fab_ctr ctr; + struct feature_fme_dperf *dperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, dperf)) + goto exit; + + ctl.csr = readq(&dperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &dperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &dperf->fab_ctr, DPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&dperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_dperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, DPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, DPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(mmio_read, DPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, DPERF_FAB_MMIO_WR); + +static int fme_dperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_dperf *dperf; + int status; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + status = fabric_pobj_is_enabled(port_id, dperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_dperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dperf *dperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, dperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&dperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_dperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_dperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 + +static int fme_global_dperf_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf Init.\n"); + + return 0; +} + +static void fme_global_dperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf UInit.\n"); +} + +static int fme_dperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_dperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_dperf_get_fab_port_pcie0_read(fme, sub, &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_dperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* MMIO_READ */ + return fme_dperf_get_fab_port_mmio_read(fme, sub, &prop->data); + case 0x5: /* MMIO_WRITE */ + return fme_dperf_get_fab_port_mmio_write(fme, sub, &prop->data); + case 0x6: /* ENABLE */ + return fme_dperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_dperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_dperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_dperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_dperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_dperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE - fab root only prop */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_dperf_set_fab_freeze(fme, prop->data); + case 0x6: /* ENABLE - fab both root and sub */ + return fme_dperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_dperf_ops = { + .init = fme_global_dperf_init, + .uinit = fme_global_dperf_uinit, + .get_prop = fme_global_dperf_get_prop, + .set_prop = fme_global_dperf_set_prop, + +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c new file mode 100644 index 0000000..33c241e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static int fme_err_get_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + + fme_error0.csr = readq(&fme_err->fme_err); + *val = fme_error0.csr; + + return 0; +} + +static int fme_err_get_first_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_first_error fme_first_err; + + fme_first_err.csr = readq(&fme_err->fme_first_err); + *val = fme_first_err.err_reg_status; + + return 0; +} + +static int fme_err_get_next_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_next_error fme_next_err; + + fme_next_err.csr = readq(&fme_err->fme_next_err); + *val = fme_next_err.err_reg_status; + + return 0; +} + +static int fme_err_set_clear(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_ERROR0_MASK, &fme_err->fme_err_mask); + + fme_error0.csr = readq(&fme_err->fme_err); + if (val != fme_error0.csr) { + ret = -EBUSY; + goto exit; + } + + fme_first_err.csr = readq(&fme_err->fme_first_err); + fme_next_err.csr = readq(&fme_err->fme_next_err); + + writeq(fme_error0.csr & FME_ERROR0_MASK, &fme_err->fme_err); + writeq(fme_first_err.csr & FME_FIRST_ERROR_MASK, + &fme_err->fme_first_err); + writeq(fme_next_err.csr & FME_NEXT_ERROR_MASK, + &fme_err->fme_next_err); + +exit: + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_revision(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_header header; + + header.csr = readq(&fme_err->header); + *val = header.revision; + + return 0; +} + +static int fme_err_get_pcie0_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + + pcie0_err.csr = readq(&fme_err->pcie0_err); + *val = pcie0_err.csr; + + return 0; +} + +static int fme_err_set_pcie0_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE0_ERROR_MASK, &fme_err->pcie0_err_mask); + + pcie0_err.csr = readq(&fme_err->pcie0_err); + if (val != pcie0_err.csr) + ret = -EBUSY; + else + writeq(pcie0_err.csr & FME_PCIE0_ERROR_MASK, + &fme_err->pcie0_err); + + writeq(0UL, &fme_err->pcie0_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_pcie1_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + + pcie1_err.csr = readq(&fme_err->pcie1_err); + *val = pcie1_err.csr; + + return 0; +} + +static int fme_err_set_pcie1_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE1_ERROR_MASK, &fme_err->pcie1_err_mask); + + pcie1_err.csr = readq(&fme_err->pcie1_err); + if (val != pcie1_err.csr) + ret = -EBUSY; + else + writeq(pcie1_err.csr & FME_PCIE1_ERROR_MASK, + &fme_err->pcie1_err); + + writeq(0UL, &fme_err->pcie1_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_nonfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_nonfaterror ras_nonfaterr; + + ras_nonfaterr.csr = readq(&fme_err->ras_nonfaterr); + *val = ras_nonfaterr.csr; + + return 0; +} + +static int fme_err_get_catfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_catfaterror ras_catfaterr; + + ras_catfaterr.csr = readq(&fme_err->ras_catfaterr); + *val = ras_catfaterr.csr; + + return 0; +} + +static int fme_err_get_inject_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + *val = ras_error_inj.csr & FME_RAS_ERROR_INJ_MASK; + + return 0; +} + +static int fme_err_set_inject_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + spinlock_lock(&fme->lock); + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + + if (val <= FME_RAS_ERROR_INJ_MASK) { + ras_error_inj.csr = val; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(ras_error_inj.csr, &fme_err->ras_error_inj); + spinlock_unlock(&fme->lock); + + return 0; +} + +static void fme_error_enable(struct ifpga_fme_hw *fme) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + writeq(0UL, &fme_err->pcie0_err_mask); + writeq(0UL, &fme_err->pcie1_err_mask); + writeq(0UL, &fme_err->ras_nonfat_mask); + writeq(0UL, &fme_err->ras_catfat_mask); +} + +static int fme_global_error_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = feature->parent; + + fme_error_enable(fme); + + if (feature->ctx_num) + fme->capability |= FPGA_FME_CAP_ERR_IRQ; + + return 0; +} + +static void fme_global_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int fme_err_fme_err_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* ERRORS */ + return fme_err_get_errors(fme, &prop->data); + case 0x2: /* FIRST_ERROR */ + return fme_err_get_first_error(fme, &prop->data); + case 0x3: /* NEXT_ERROR */ + return fme_err_get_next_error(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x5: /* REVISION */ + return fme_err_get_revision(fme, &prop->data); + case 0x6: /* PCIE0_ERRORS */ + return fme_err_get_pcie0_errors(fme, &prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_get_pcie1_errors(fme, &prop->data); + case 0x8: /* NONFATAL_ERRORS */ + return fme_err_get_nonfatal_errors(fme, &prop->data); + case 0x9: /* CATFATAL_ERRORS */ + return fme_err_get_catfatal_errors(fme, &prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_get_inject_errors(fme, &prop->data); + case 0xb: /* REVISION*/ + return fme_err_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_get_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_err_fme_err_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x4: /* CLEAR */ + return fme_err_set_clear(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x6: /* PCIE0_ERRORS */ + return fme_err_set_pcie0_errors(fme, prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_set_pcie1_errors(fme, prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_set_inject_errors(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_set_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_set_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_global_err_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_fme_err_irq_set *err_irq_set = + (struct fpga_fme_err_irq_set *)irq_set; + struct ifpga_fme_hw *fme; + int ret; + + fme = (struct ifpga_fme_hw *)feature->parent; + + spinlock_lock(&fme->lock); + if (!(fme->capability & FPGA_FME_CAP_ERR_IRQ)) { + spinlock_unlock(&fme->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&fme->lock); + + return ret; +} + +struct feature_ops fme_global_err_ops = { + .init = fme_global_error_init, + .uinit = fme_global_error_uinit, + .get_prop = fme_global_error_get_prop, + .set_prop = fme_global_error_set_prop, + .set_irq = fme_global_err_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c new file mode 100644 index 0000000..e6c40a1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c @@ -0,0 +1,715 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_iperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_clk_ctr clk; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + clk.afu_interf_clock = readq(&iperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_iperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_iperf *iperf; + struct feature_header header; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + header.csr = readq(&iperf->header); + *revision = header.revision; + + return 0; +} + +static int fme_iperf_get_cache_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + *freeze = (u64)ctl.freeze; + return 0; +} + +static int fme_iperf_set_cache_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->ch_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define IPERF_TIMEOUT 30 + +static u64 read_cache_counter(struct ifpga_fme_hw *fme, + u8 channel, enum iperf_cache_events event) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + struct feature_fme_ifpmon_ch_ctr ctr0, ctr1; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* set channel access type and cache event code. */ + ctl.csr = readq(&iperf->ch_ctl); + ctl.cci_chsel = channel; + ctl.cache_event = event; + writeq(ctl.csr, &iperf->ch_ctl); + + /* check the event type in the counter registers */ + ctr0.event_code = event; + + if (fpga_wait_register_field(event_code, ctr0, + &iperf->ch_ctr0, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched cache event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr0.csr = readq(&iperf->ch_ctr0); + ctr1.csr = readq(&iperf->ch_ctr1); + counter = ctr0.cache_counter + ctr1.cache_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define CACHE_SHOW(name, type, event) \ +static int fme_iperf_get_cache_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_cache_counter(fme, type, event); \ + return 0; \ +} + +CACHE_SHOW(read_hit, CACHE_CHANNEL_RD, IPERF_CACHE_RD_HIT); +CACHE_SHOW(read_miss, CACHE_CHANNEL_RD, IPERF_CACHE_RD_MISS); +CACHE_SHOW(write_hit, CACHE_CHANNEL_WR, IPERF_CACHE_WR_HIT); +CACHE_SHOW(write_miss, CACHE_CHANNEL_WR, IPERF_CACHE_WR_MISS); +CACHE_SHOW(hold_request, CACHE_CHANNEL_RD, IPERF_CACHE_HOLD_REQ); +CACHE_SHOW(tx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_TX_REQ_STALL); +CACHE_SHOW(rx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_RX_REQ_STALL); +CACHE_SHOW(rx_eviction, CACHE_CHANNEL_RD, IPERF_CACHE_EVICTIONS); +CACHE_SHOW(data_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_DATA_WR_PORT_CONTEN); +CACHE_SHOW(tag_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_TAG_WR_PORT_CONTEN); + +static int fme_iperf_get_vtd_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_vtd_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->vtd_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static u64 read_iommu_sip_counter(struct ifpga_fme_hw *fme, + enum iperf_vtd_sip_events event) +{ + struct feature_fme_ifpmon_vtd_sip_ctl sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr sip_ctr; + struct feature_fme_iperf *iperf; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + sip_ctl.csr = readq(&iperf->vtd_sip_ctl); + sip_ctl.vtd_evtcode = event; + writeq(sip_ctl.csr, &iperf->vtd_sip_ctl); + + sip_ctr.event_code = event; + + if (fpga_wait_register_field(event_code, sip_ctr, + &iperf->vtd_sip_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd SIP event type in counter registers\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + sip_ctr.csr = readq(&iperf->vtd_sip_ctr); + counter = sip_ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_SIP_SHOW(name, event) \ +static int fme_iperf_get_vtd_sip_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_iommu_sip_counter(fme, event); \ + return 0; \ +} + +VTD_SIP_SHOW(iotlb_4k_hit, IPERF_VTD_SIP_IOTLB_4K_HIT); +VTD_SIP_SHOW(iotlb_2m_hit, IPERF_VTD_SIP_IOTLB_2M_HIT); +VTD_SIP_SHOW(iotlb_1g_hit, IPERF_VTD_SIP_IOTLB_1G_HIT); +VTD_SIP_SHOW(slpwc_l3_hit, IPERF_VTD_SIP_SLPWC_L3_HIT); +VTD_SIP_SHOW(slpwc_l4_hit, IPERF_VTD_SIP_SLPWC_L4_HIT); +VTD_SIP_SHOW(rcc_hit, IPERF_VTD_SIP_RCC_HIT); +VTD_SIP_SHOW(iotlb_4k_miss, IPERF_VTD_SIP_IOTLB_4K_MISS); +VTD_SIP_SHOW(iotlb_2m_miss, IPERF_VTD_SIP_IOTLB_2M_MISS); +VTD_SIP_SHOW(iotlb_1g_miss, IPERF_VTD_SIP_IOTLB_1G_MISS); +VTD_SIP_SHOW(slpwc_l3_miss, IPERF_VTD_SIP_SLPWC_L3_MISS); +VTD_SIP_SHOW(slpwc_l4_miss, IPERF_VTD_SIP_SLPWC_L4_MISS); +VTD_SIP_SHOW(rcc_miss, IPERF_VTD_SIP_RCC_MISS); + +static u64 read_iommu_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_vtd_events base_event) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_ifpmon_vtd_ctr ctr; + struct feature_fme_iperf *iperf; + enum iperf_vtd_events event = base_event + port_id; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.vtd_evtcode = event; + writeq(ctl.csr, &iperf->vtd_ctl); + + ctr.event_code = event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->vtd_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->vtd_ctr); + counter = ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_PORT_SHOW(name, base_event) \ +static int fme_iperf_get_vtd_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_iommu_counter(fme, port_id, base_event); \ + return 0; \ +} + +VTD_PORT_SHOW(read_transaction, IPERF_VTD_AFU_MEM_RD_TRANS); +VTD_PORT_SHOW(write_transaction, IPERF_VTD_AFU_MEM_WR_TRANS); +VTD_PORT_SHOW(devtlb_read_hit, IPERF_VTD_AFU_DEVTLB_RD_HIT); +VTD_PORT_SHOW(devtlb_write_hit, IPERF_VTD_AFU_DEVTLB_WR_HIT); +VTD_PORT_SHOW(devtlb_4k_fill, IPERF_VTD_DEVTLB_4K_FILL); +VTD_PORT_SHOW(devtlb_2m_fill, IPERF_VTD_DEVTLB_2M_FILL); +VTD_PORT_SHOW(devtlb_1g_fill, IPERF_VTD_DEVTLB_1G_FILL); + +static bool fabric_pobj_is_enabled(u8 port_id, struct feature_fme_iperf *iperf) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + + ctl.csr = readq(&iperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_fab_events fab_event) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_ifpmon_fab_ctr ctr; + struct feature_fme_iperf *iperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, iperf)) + goto exit; + + ctl.csr = readq(&iperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &iperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->fab_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_iperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, IPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, IPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(pcie1_read, IPERF_FAB_PCIE1_RD); +FAB_PORT_SHOW(pcie1_write, IPERF_FAB_PCIE1_WR); +FAB_PORT_SHOW(upi_read, IPERF_FAB_UPI_RD); +FAB_PORT_SHOW(upi_write, IPERF_FAB_UPI_WR); +FAB_PORT_SHOW(mmio_read, IPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, IPERF_FAB_MMIO_WR); + +static int fme_iperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_iperf *iperf; + int status; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + status = fabric_pobj_is_enabled(port_id, iperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_iperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, iperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&iperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_iperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 +#define FME_IPERF_CAP_IOMMU 0x1 + +static int fme_global_iperf_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme; + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + + dev_info(NULL, "FME global_iperf Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + /* check if iommu is not supported on this device. */ + fme_capability.csr = readq(&fme_hdr->capability); + dev_info(NULL, "FME HEAD fme_capability %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + if (fme_capability.iommu_support) + feature->cap |= FME_IPERF_CAP_IOMMU; + + return 0; +} + +static void fme_global_iperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_iperf UInit.\n"); +} + +static int fme_iperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_iperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_iperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_cache_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_cache_freeze(fme, &prop->data); + case 0x2: /* READ_HIT */ + return fme_iperf_get_cache_read_hit(fme, &prop->data); + case 0x3: /* READ_MISS */ + return fme_iperf_get_cache_read_miss(fme, &prop->data); + case 0x4: /* WRITE_HIT */ + return fme_iperf_get_cache_write_hit(fme, &prop->data); + case 0x5: /* WRITE_MISS */ + return fme_iperf_get_cache_write_miss(fme, &prop->data); + case 0x6: /* HOLD_REQUEST */ + return fme_iperf_get_cache_hold_request(fme, &prop->data); + case 0x7: /* TX_REQ_STALL */ + return fme_iperf_get_cache_tx_req_stall(fme, &prop->data); + case 0x8: /* RX_REQ_STALL */ + return fme_iperf_get_cache_rx_req_stall(fme, &prop->data); + case 0x9: /* RX_EVICTION */ + return fme_iperf_get_cache_rx_eviction(fme, &prop->data); + case 0xa: /* DATA_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_data_write_port_contention(fme, + &prop->data); + case 0xb: /* TAG_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_tag_write_port_contention(fme, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_vtd_freeze(fme, &prop->data); + case 0x2: /* IOTLB_4K_HIT */ + return fme_iperf_get_vtd_sip_iotlb_4k_hit(fme, &prop->data); + case 0x3: /* IOTLB_2M_HIT */ + return fme_iperf_get_vtd_sip_iotlb_2m_hit(fme, &prop->data); + case 0x4: /* IOTLB_1G_HIT */ + return fme_iperf_get_vtd_sip_iotlb_1g_hit(fme, &prop->data); + case 0x5: /* SLPWC_L3_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l3_hit(fme, &prop->data); + case 0x6: /* SLPWC_L4_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l4_hit(fme, &prop->data); + case 0x7: /* RCC_HIT */ + return fme_iperf_get_vtd_sip_rcc_hit(fme, &prop->data); + case 0x8: /* IOTLB_4K_MISS */ + return fme_iperf_get_vtd_sip_iotlb_4k_miss(fme, &prop->data); + case 0x9: /* IOTLB_2M_MISS */ + return fme_iperf_get_vtd_sip_iotlb_2m_miss(fme, &prop->data); + case 0xa: /* IOTLB_1G_MISS */ + return fme_iperf_get_vtd_sip_iotlb_1g_miss(fme, &prop->data); + case 0xb: /* SLPWC_L3_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l3_miss(fme, &prop->data); + case 0xc: /* SLPWC_L4_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l4_miss(fme, &prop->data); + case 0xd: /* RCC_MISS */ + return fme_iperf_get_vtd_sip_rcc_miss(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_sub_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub > PERF_MAX_PORT_NUM) + return -ENOENT; + + switch (id) { + case 0xe: /* READ_TRANSACTION */ + return fme_iperf_get_vtd_port_read_transaction(fme, sub, + &prop->data); + case 0xf: /* WRITE_TRANSACTION */ + return fme_iperf_get_vtd_port_write_transaction(fme, sub, + &prop->data); + case 0x10: /* DEVTLB_READ_HIT */ + return fme_iperf_get_vtd_port_devtlb_read_hit(fme, sub, + &prop->data); + case 0x11: /* DEVTLB_WRITE_HIT */ + return fme_iperf_get_vtd_port_devtlb_write_hit(fme, sub, + &prop->data); + case 0x12: /* DEVTLB_4K_FILL */ + return fme_iperf_get_vtd_port_devtlb_4k_fill(fme, sub, + &prop->data); + case 0x13: /* DEVTLB_2M_FILL */ + return fme_iperf_get_vtd_port_devtlb_2m_fill(fme, sub, + &prop->data); + case 0x14: /* DEVTLB_1G_FILL */ + return fme_iperf_get_vtd_port_devtlb_1g_fill(fme, sub, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED) + return fme_iperf_vtd_root_get_prop(feature, prop); + + return fme_iperf_vtd_sub_get_prop(feature, prop); +} + +static int fme_iperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + /* Other properties are present for both top and sub levels */ + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_iperf_get_fab_port_pcie0_read(fme, sub, + &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_iperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* PCIE1_READ */ + return fme_iperf_get_fab_port_pcie1_read(fme, sub, + &prop->data); + case 0x5: /* PCIE1_WRITE */ + return fme_iperf_get_fab_port_pcie1_write(fme, sub, + &prop->data); + case 0x6: /* UPI_READ */ + return fme_iperf_get_fab_port_upi_read(fme, sub, + &prop->data); + case 0x7: /* UPI_WRITE */ + return fme_iperf_get_fab_port_upi_write(fme, sub, + &prop->data); + case 0x8: /* MMIO_READ */ + return fme_iperf_get_fab_port_mmio_read(fme, sub, + &prop->data); + case 0x9: /* MMIO_WRITE */ + return fme_iperf_get_fab_port_mmio_write(fme, sub, + &prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_get_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_get_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_iperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_iperf_cache_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_cache_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_vtd_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_vtd_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_set_fab_freeze(fme, prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_set_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_set_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_iperf_ops = { + .init = fme_global_iperf_init, + .uinit = fme_global_iperf_uinit, + .get_prop = fme_global_iperf_get_prop, + .set_prop = fme_global_iperf_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c new file mode 100644 index 0000000..6192fa7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c @@ -0,0 +1,372 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#if defined(RTE_ARCH_X86_64) +static inline void copy512(const void *src, void *dst) +{ + asm volatile("vmovdqu64 (%0), %%zmm0;" + "vmovntdq %%zmm0, (%1);" + : + : "r"(src), "r"(dst)); +} +#else +static inline void copy512(const void *src, void *dst) +{ + UNUSED(src); + UNUSED(dst); + WARN_ON(1); +} +#endif + +static u64 +pr_err_handle(struct feature_fme_pr *fme_pr) +{ + struct feature_fme_pr_status fme_pr_status; + unsigned long err_code; + u64 fme_pr_error; + int i; + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + if (!fme_pr_status.pr_status) + return 0; + + err_code = readq(&fme_pr->ccip_fme_pr_err); + fme_pr_error = err_code; + + for (i = 0; i < PR_MAX_ERR_NUM; i++) { + if (err_code & (1 << i)) + dev_info(NULL, "%s\n", pr_err_msg[i]); + } + + writeq(fme_pr_error, &fme_pr->ccip_fme_pr_err); + return fme_pr_error; +} + +static int fme_pr_write_init(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + if (info->flags != FPGA_MGR_PARTIAL_RECONFIG) + return -EINVAL; + + dev_info(fme_dev, "resetting PR before initiated PR\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + fme_pr_ctl.pr_reset_ack = 1; + + if (fpga_wait_register_field(pr_reset_ack, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 0; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "waiting for PR resource in HW to be initialized and ready\n"); + + fme_pr_status.pr_host_status = PR_HOST_STATUS_IDLE; + + if (fpga_wait_register_field(pr_host_status, fme_pr_status, + &fme_pr->ccip_fme_pr_status, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "check if have any previous PR error\n"); + pr_err_handle(fme_pr); + return 0; +} + +static int fme_pr_write(struct ifpga_fme_hw *fme_dev, + int port_id, const char *buf, size_t count, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + struct feature_fme_pr_data fme_pr_data; + int delay, pr_credit; + int ret = 0; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + dev_info(fme_dev, "set PR port ID and start request\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_regionid = port_id; + fme_pr_ctl.pr_start_req = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "pushing data from bitstream to HW\n"); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + + while (count > 0) { + delay = 0; + while (pr_credit <= 1) { + if (delay++ > PR_WAIT_TIMEOUT) { + dev_err(fme_dev, "maximum try\n"); + + info->pr_err = pr_err_handle(fme_pr); + return info->pr_err ? -EIO : -ETIMEDOUT; + } + udelay(1); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + }; + + if (count >= fme_dev->pr_bandwidth) { + switch (fme_dev->pr_bandwidth) { + case 4: + fme_pr_data.rsvd = 0; + fme_pr_data.pr_data_raw = *((const u32 *)buf); + writeq(fme_pr_data.csr, + &fme_pr->ccip_fme_pr_data); + break; + case 64: + copy512(buf, &fme_pr->fme_pr_data1); + break; + default: + ret = -EFAULT; + goto done; + } + + buf += fme_dev->pr_bandwidth; + count -= fme_dev->pr_bandwidth; + pr_credit--; + } else { + WARN_ON(1); + return -EINVAL; + goto done; + } + } + +done: + return ret; +} + +static int fme_pr_write_complete(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_push_complete = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "green bitstream push complete\n"); + dev_info(fme_dev, "waiting for HW to release PR resource\n"); + + fme_pr_ctl.pr_start_req = 0; + + if (fpga_wait_register_field(pr_start_req, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + printf("maximum try.\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "PR operation complete, checking status\n"); + info->pr_err = pr_err_handle(fme_pr); + if (info->pr_err) + return -EIO; + + dev_info(fme_dev, "PR done successfully\n"); + return 0; +} + +static int fpga_pr_buf_load(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info, const char *buf, + size_t count) +{ + int ret; + + info->state = FPGA_PR_STATE_WRITE_INIT; + ret = fme_pr_write_init(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error preparing FPGA for writing\n"); + info->state = FPGA_PR_STATE_WRITE_INIT_ERR; + return ret; + } + + /* + * Write the FPGA image to the FPGA. + */ + info->state = FPGA_PR_STATE_WRITE; + ret = fme_pr_write(fme_dev, info->port_id, buf, count, info); + if (ret) { + dev_err(fme_dev, "Error while writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_ERR; + return ret; + } + + /* + * After all the FPGA image has been written, do the device specific + * steps to finish and set the FPGA into operating mode. + */ + info->state = FPGA_PR_STATE_WRITE_COMPLETE; + ret = fme_pr_write_complete(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error after writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_COMPLETE_ERR; + return ret; + } + info->state = FPGA_PR_STATE_DONE; + + return 0; +} + +static int fme_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + struct ifpga_fme_hw *fme = &hw->fme; + struct fpga_pr_info info; + struct ifpga_port_hw *port; + int ret = 0; + + if (!buffer || size == 0) + return -EINVAL; + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + /* + * Padding extra zeros to align PR buffer with PR bandwidth, HW will + * ignore these zeros automatically. + */ + size = ALIGN(size, fme->pr_bandwidth); + + /* get fme header region */ + fme_hdr = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_HEADER); + if (!fme_hdr) + return -EINVAL; + + /* check port id */ + fme_capability.csr = readq(&fme_hdr->capability); + if (port_id >= fme_capability.num_ports) { + dev_err(fme, "port number more than maximum\n"); + return -EINVAL; + } + + memset(&info, 0, sizeof(struct fpga_pr_info)); + info.flags = FPGA_MGR_PARTIAL_RECONFIG; + info.port_id = port_id; + + spinlock_lock(&fme->lock); + + /* get port device by port_id */ + port = &hw->port[port_id]; + + /* Disable Port before PR */ + fpga_port_disable(port); + + ret = fpga_pr_buf_load(fme, &info, (void *)buffer, size); + + *status = info.pr_err; + + /* Re-enable Port after PR finished */ + fpga_port_enable(port); + spinlock_unlock(&fme->lock); + + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, u64 *status) +{ + struct bts_header *bts_hdr; + void *buf; + struct ifpga_port_hw *port; + int ret; + + if (!buffer || size == 0) { + dev_err(hw, "invalid parameter\n"); + return -EINVAL; + } + + bts_hdr = (struct bts_header *)buffer; + + if (is_valid_bts(bts_hdr)) { + dev_info(hw, "this is a valid bitsteam..\n"); + size -= (sizeof(struct bts_header) + + bts_hdr->metadata_len); + buf = (u8 *)buffer + sizeof(struct bts_header) + + bts_hdr->metadata_len; + } else { + return -EINVAL; + } + + /* clean port error before do PR */ + port = &hw->port[port_id]; + ret = port_clear_error(port); + if (ret) { + dev_err(hw, "port cannot clear error\n"); + return -EINVAL; + } + + return fme_pr(hw, port_id, buf, size, status); +} + +static int fme_pr_mgmt_init(struct feature *feature) +{ + struct feature_fme_pr *fme_pr; + struct feature_header fme_pr_header; + struct ifpga_fme_hw *fme; + + dev_info(NULL, "FME PR MGMT Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + + fme_pr = (struct feature_fme_pr *)feature->addr; + + fme_pr_header.csr = readq(&fme_pr->header); + if (fme_pr_header.revision == 2) { + dev_info(NULL, "using 512-bit PR\n"); + fme->pr_bandwidth = 64; + } else { + dev_info(NULL, "using 32-bit PR\n"); + fme->pr_bandwidth = 4; + } + + return 0; +} + +static void fme_pr_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME PR MGMT UInit.\n"); +} + +struct 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 new file mode 100644 index 0000000..a20520c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_HW_H_ +#define _IFPGA_HW_H_ + +#include "ifpga_defines.h" +#include "opae_ifpga_hw_api.h" + +enum ifpga_feature_state { + IFPGA_FEATURE_UNUSED = 0, + IFPGA_FEATURE_ATTACHED, +}; + +struct feature_irq_ctx { + int eventfd; + int idx; +}; + +struct feature { + enum ifpga_feature_state state; + const char *name; + u64 id; + u8 *addr; + uint64_t phys_addr; + u32 size; + int revision; + u64 cap; + int vfio_dev_fd; + struct feature_irq_ctx *ctx; + unsigned int ctx_num; + + void *parent; /* to parent hw data structure */ + + struct feature_ops *ops;/* callback to this private feature */ +}; + +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); +}; + +enum ifpga_fme_state { + IFPGA_FME_UNUSED = 0, + IFPGA_FME_IMPLEMENTED, +}; + +struct ifpga_fme_hw { + enum ifpga_fme_state state; + + struct feature sub_feature[FME_FEATURE_ID_MAX]; + spinlock_t lock; /* protect hardware access */ + + void *parent; /* pointer to ifpga_hw */ + + /* provied by HEADER feature */ + u32 port_num; + struct uuid bitstream_id; + u64 bitstream_md; + size_t pr_bandwidth; + u32 socket_id; + u32 fabric_version_id; + u32 cache_size; + + u32 capability; +}; + +enum ifpga_port_state { + IFPGA_PORT_UNUSED = 0, + IFPGA_PORT_ATTACHED, + IFPGA_PORT_DETACHED, +}; + +struct ifpga_port_hw { + enum ifpga_port_state state; + + struct feature sub_feature[PORT_FEATURE_ID_MAX]; + spinlock_t lock; /* protect access to hw */ + + void *parent; /* pointer to ifpga_hw */ + + int port_id; /* provied by HEADER feature */ + struct uuid afu_id; /* provied by User AFU feature */ + + unsigned int disable_count; + + u32 capability; + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ + u8 *stp_addr; + u32 stp_size; +}; + +#define AFU_MAX_REGION 1 + +struct ifpga_afu_info { + struct opae_reg_region region[AFU_MAX_REGION]; + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct ifpga_hw { + struct opae_adapter *adapter; + struct opae_adapter_data_pci *pci_data; + + struct ifpga_fme_hw fme; + struct ifpga_port_hw port[MAX_FPGA_PORT_NUM]; +}; + +static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) +{ + return hw->fme.state != IFPGA_FME_UNUSED; +} + +static inline bool is_valid_port_id(struct ifpga_hw *hw, u32 port_id) +{ + if (port_id >= MAX_FPGA_PORT_NUM || + hw->port[port_id].state != IFPGA_PORT_ATTACHED) + return false; + + return true; +} +#endif /* _IFPGA_HW_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c new file mode 100644 index 0000000..8ab1bdb --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c @@ -0,0 +1,408 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +static int port_get_revision(struct ifpga_port_hw *port, u64 *revision) +{ + struct feature_port_header *port_hdr + = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&port_hdr->header); + + *revision = header.revision; + + return 0; +} + +static int port_get_portidx(struct ifpga_port_hw *port, u64 *idx) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + capability.csr = readq(&port_hdr->capability); + *idx = capability.port_number; + + return 0; +} + +static int port_get_latency_tolerance(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + control.csr = readq(&port_hdr->control); + *val = control.latency_tolerance; + + return 0; +} + +static int port_get_ap1_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap1_event; + + return 0; +} + +static int port_set_ap1_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap1_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_ap2_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap2_event; + + return 0; +} + +static int port_set_ap2_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap2_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_power_state(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.power_state; + + return 0; +} + +static int port_get_userclk_freqcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_hdr_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port hdr Init.\n"); + + fpga_port_reset(port); + + return 0; +} + +static void port_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port hdr uinit.\n"); +} + +static int port_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_REVISION: + return port_get_revision(port, &prop->data); + case PORT_HDR_PROP_PORTIDX: + return port_get_portidx(port, &prop->data); + case PORT_HDR_PROP_LATENCY_TOLERANCE: + return port_get_latency_tolerance(port, &prop->data); + case PORT_HDR_PROP_AP1_EVENT: + return port_get_ap1_event(port, &prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_get_ap2_event(port, &prop->data); + case PORT_HDR_PROP_POWER_STATE: + return port_get_power_state(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_get_userclk_freqcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_get_userclk_freqcntrcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQSTS: + return port_get_userclk_freqsts(port, &prop->data); + case PORT_HDR_PROP_USERCLK_CNTRSTS: + return port_get_userclk_freqcntrsts(port, &prop->data); + } + + return -ENOENT; +} + +static int port_hdr_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_AP1_EVENT: + return port_set_ap1_event(port, prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_set_ap2_event(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_set_userclk_freqcmd(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_set_userclk_freqcntrcmd(port, prop->data); + } + + return -ENOENT; +} + +struct feature_ops 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) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port stp Init.\n"); + + spinlock_lock(&port->lock); + port->stp_addr = feature->addr; + port->stp_size = feature->size; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_stp_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port stp uinit.\n"); +} + +struct feature_ops port_stp_ops = { + .init = port_stp_init, + .uinit = port_stp_uinit, +}; + +static int port_uint_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "PORT UINT Init.\n"); + + spinlock_lock(&port->lock); + if (feature->ctx_num) { + port->capability |= FPGA_PORT_CAP_UAFU_IRQ; + port->num_uafu_irqs = feature->ctx_num; + } + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_uint_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT UINT UInit.\n"); +} + +static int port_uint_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_uafu_irq_set *uafu_irq_set = irq_set; + struct ifpga_port_hw *port = feature->parent; + int ret; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_UAFU_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, uafu_irq_set->start, + uafu_irq_set->count, uafu_irq_set->evtfds); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_uint_ops = { + .init = port_uint_init, + .uinit = port_uint_uinit, + .set_irq = port_uint_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c new file mode 100644 index 0000000..3be0f5e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static int port_err_get_revision(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_header header; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + header.csr = readq(&port_err->header); + *val = header.revision; + + return 0; +} + +static int port_err_get_errors(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + *val = error.csr; + + return 0; +} + +static int port_err_get_first_error(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_first_err_key first_error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + first_error.csr = readq(&port_err->port_first_error); + *val = first_error.csr; + + return 0; +} + +static int port_err_get_first_malformed_req_lsb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req0 malreq0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq0.header_lsb = readq(&port_err->malreq0); + *val = malreq0.header_lsb; + + return 0; +} + +static int port_err_get_first_malformed_req_msb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req1 malreq1; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq1.header_msb = readq(&port_err->malreq1); + *val = malreq1.header_msb; + + return 0; +} + +static int port_err_set_clear(struct ifpga_port_hw *port, u64 val) +{ + int ret; + + spinlock_lock(&port->lock); + ret = port_err_clear(port, val); + spinlock_unlock(&port->lock); + + return ret; +} + +static int port_error_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port error Init.\n"); + + spinlock_lock(&port->lock); + port_err_mask(port, false); + if (feature->ctx_num) + port->capability |= FPGA_PORT_CAP_ERR_IRQ; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int port_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_ERR_PROP_REVISION: + return port_err_get_revision(port, &prop->data); + case PORT_ERR_PROP_ERRORS: + return port_err_get_errors(port, &prop->data); + case PORT_ERR_PROP_FIRST_ERROR: + return port_err_get_first_error(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB: + return port_err_get_first_malformed_req_lsb(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB: + return port_err_get_first_malformed_req_msb(port, &prop->data); + } + + return -ENOENT; +} + +static int port_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + if (prop->prop_id == PORT_ERR_PROP_CLEAR) + return port_err_set_clear(port, prop->data); + + return -ENOENT; +} + +static int port_error_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_port_err_irq_set *err_irq_set = irq_set; + struct ifpga_port_hw *port; + int ret; + + port = feature->parent; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_ERR_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_error_ops = { + .init = port_error_init, + .uinit = port_error_uinit, + .get_prop = port_error_get_prop, + .set_prop = port_error_set_prop, + .set_irq = port_error_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/meson.build b/drivers/raw/ifpga_rawdev/base/meson.build new file mode 100644 index 0000000..cb65535 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/meson.build @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +sources = [ + 'ifpga_api.c', + 'ifpga_enumerate.c', + 'ifpga_feature_dev.c', + 'ifpga_fme.c', + 'ifpga_fme_iperf.c', + 'ifpga_fme_dperf.c', + 'ifpga_fme_error.c', + 'ifpga_port.c', + 'ifpga_port_error.c', + 'ifpga_fme_pr.c', + 'opae_hw_api.c', + 'opae_ifpga_hw_api.c', + 'opae_debug.c' +] + +error_cflags = ['-Wno-sign-compare', '-Wno-unused-value', + '-Wno-format', '-Wno-unused-but-set-variable', + '-Wno-strict-aliasing' +] +c_args = cflags +foreach flag: error_cflags + if cc.has_argument(flag) + c_args += flag + endif +endforeach + +base_lib = static_library('ifpga_rawdev_base', sources, + dependencies: static_rte_eal, + c_args: c_args) +base_objs = base_lib.extract_all_objects() diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.c b/drivers/raw/ifpga_rawdev/base/opae_debug.c new file mode 100644 index 0000000..024d7d2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.c @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#define OPAE_HW_DEBUG + +#include "opae_hw_api.h" +#include "opae_debug.h" + +void opae_manager_dump(struct opae_manager *mgr) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Manger %s\n", mgr->name); + opae_log("OPAE Manger OPs = %p\n", mgr->ops); + opae_log("OPAE Manager Private Data = %p\n", mgr->data); + opae_log("OPAE Adapter(parent) = %p\n", mgr->adapter); + opae_log("==========================\n"); +} + +void opae_bridge_dump(struct opae_bridge *br) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Bridge %s\n", br->name); + opae_log("OPAE Bridge ID = %d\n", br->id); + opae_log("OPAE Bridge OPs = %p\n", br->ops); + opae_log("OPAE Bridge Private Data = %p\n", br->data); + opae_log("OPAE Accelerator(under this bridge) = %p\n", br->acc); + opae_log("==========================\n"); +} + +void opae_accelerator_dump(struct opae_accelerator *acc) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Accelerator %s\n", acc->name); + opae_log("OPAE Accelerator Index = %d\n", acc->index); + opae_log("OPAE Accelerator OPs = %p\n", acc->ops); + opae_log("OPAE Accelerator Private Data = %p\n", acc->data); + opae_log("OPAE Bridge (upstream) = %p\n", acc->br); + opae_log("OPAE Manager (upstream) = %p\n", acc->mgr); + opae_log("==========================\n"); + + if (acc->br) + opae_bridge_dump(acc->br); +} + +static void opae_adapter_data_dump(void *data) +{ + struct opae_adapter_data *d = data; + struct opae_adapter_data_pci *d_pci; + struct opae_reg_region *r; + int i; + + opae_log("=====%s=====\n", __func__); + + switch (d->type) { + case OPAE_FPGA_PCI: + d_pci = (struct opae_adapter_data_pci *)d; + + opae_log("OPAE Adapter Type = PCI\n"); + opae_log("PCI Device ID: 0x%04x\n", d_pci->device_id); + opae_log("PCI Vendor ID: 0x%04x\n", d_pci->vendor_id); + + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + r = &d_pci->region[i]; + opae_log("PCI Bar %d: phy(%llx) len(%llx) addr(%p)\n", + i, (unsigned long long)r->phys_addr, + (unsigned long long)r->len, r->addr); + } + break; + case OPAE_FPGA_NET: + break; + } + + opae_log("==========================\n"); +} + +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) { + if (adapter->mgr) + opae_manager_dump(adapter->mgr); + + opae_adapter_for_each_acc(adapter, acc) + opae_accelerator_dump(acc); + + if (adapter->data) + opae_adapter_data_dump(adapter->data); + } + + opae_log("==========================\n"); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.h b/drivers/raw/ifpga_rawdev/base/opae_debug.h new file mode 100644 index 0000000..a03dff9 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_DEBUG_H_ +#define _OPAE_DEBUG_H_ + +#ifdef OPAE_HW_DEBUG +#define opae_log(fmt, args...) printf(fmt, ## args) +#else +#define opae_log(fme, args...) do {} while (0) +#endif + +void opae_manager_dump(struct opae_manager *mgr); +void opae_bridge_dump(struct opae_bridge *br); +void opae_accelerator_dump(struct opae_accelerator *acc); +void opae_adapter_dump(struct opae_adapter *adapter, int verbose); + +#endif /* _OPAE_DEBUG_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c new file mode 100644 index 0000000..a533dfe --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -0,0 +1,381 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_hw_api.h" +#include "opae_debug.h" +#include "ifpga_api.h" + +/* OPAE Bridge Functions */ + +/** + * opae_bridge_alloc - alloc opae_bridge data structure + * @name: bridge name. + * @ops: ops of this bridge. + * @data: private data of this bridge. + * + * Return opae_bridge on success, otherwise NULL. + */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data) +{ + struct opae_bridge *br = opae_zmalloc(sizeof(*br)); + + if (!br) + return NULL; + + br->name = name; + br->ops = ops; + br->data = data; + + opae_log("%s %p\n", __func__, br); + + return br; +} + +/** + * opae_bridge_reset - reset opae_bridge + * @br: bridge to be reset. + * + * Return: 0 on success, otherwise error code. + */ +int opae_bridge_reset(struct opae_bridge *br) +{ + if (!br) + return -EINVAL; + + if (br->ops && br->ops->reset) + return br->ops->reset(br); + + opae_log("%s no ops\n", __func__); + + return -ENOENT; +} + +/* Accelerator Functions */ + +/** + * opae_accelerator_alloc - alloc opae_accelerator data structure + * @name: accelerator name. + * @ops: ops of this accelerator. + * @data: private data of this accelerator. + * + * Return: opae_accelerator on success, otherwise NULL. + */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data) +{ + struct opae_accelerator *acc = opae_zmalloc(sizeof(*acc)); + + if (!acc) + return NULL; + + acc->name = name; + acc->ops = ops; + acc->data = data; + + opae_log("%s %p\n", __func__, acc); + + return acc; +} + +/** + * opae_acc_reg_read - read accelerator's register from its reg region. + * @acc: accelerator to read. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: read operation width, e.g 4 byte = 32bit read. + * @data: data to store the value read from the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->read) + return acc->ops->read(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_reg_write - write to accelerator's register from its reg region. + * @acc: accelerator to write. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: write operation width, e.g 4 byte = 32bit write. + * @data: data stored the value to write to the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->write) + return acc->ops->write(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_get_info - get information of an accelerator. + * @acc: targeted accelerator + * @info: accelerator info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_info) + return acc->ops->get_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_get_region_info - get information of an accelerator register region. + * @acc: targeted accelerator + * @info: accelerator region info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_region_info) + return acc->ops->get_region_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_set_irq - set an accelerator's irq. + * @acc: targeted accelerator + * @start: start vector number + * @count: count of vectors to be set from the start vector + * @evtfds: event fds to be notified when corresponding irqs happens + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + if (!acc || !acc->data) + return -EINVAL; + + if (start + count <= start) + return -EINVAL; + + if (acc->ops && acc->ops->set_irq) + return acc->ops->set_irq(acc, start, count, evtfds); + + return -ENOENT; +} + +/** + * opae_acc_get_uuid - get accelerator's UUID. + * @acc: targeted accelerator + * @uuid: a pointer to UUID + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + if (!acc || !uuid) + return -EINVAL; + + if (acc->ops && acc->ops->get_uuid) + return acc->ops->get_uuid(acc, uuid); + + return -ENOENT; +} + +/* Manager Functions */ + +/** + * opae_manager_alloc - alloc opae_manager data structure + * @name: manager name. + * @ops: ops of this manager. + * @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) +{ + struct opae_manager *mgr = opae_zmalloc(sizeof(*mgr)); + + if (!mgr) + return NULL; + + mgr->name = name; + mgr->ops = ops; + mgr->data = data; + + opae_log("%s %p\n", __func__, mgr); + + return mgr; +} + +/** + * opae_manager_flash - flash a reconfiguration image via opae_manager + * @mgr: opae_manager for flash. + * @id: id of target region (accelerator). + * @buf: image data buffer. + * @size: buffer size. + * @status: status to store flash result. + * + * Return: 0 on success, otherwise error code. + */ +int opae_manager_flash(struct opae_manager *mgr, int id, void *buf, u32 size, + u64 *status) +{ + if (!mgr) + return -EINVAL; + + if (mgr && mgr->ops && mgr->ops->flash) + return mgr->ops->flash(mgr, id, buf, size, status); + + return -ENOENT; +} + +/* Adapter Functions */ + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @type: opae_adapter_type. + * + * Return: opae_adapter_data on success, otherwise NULL. + */ +void *opae_adapter_data_alloc(enum opae_adapter_type type) +{ + struct opae_adapter_data *data; + int size; + + switch (type) { + case OPAE_FPGA_PCI: + size = sizeof(struct opae_adapter_data_pci); + break; + case OPAE_FPGA_NET: + size = sizeof(struct opae_adapter_data_net); + break; + default: + size = sizeof(struct opae_adapter_data); + break; + } + + data = opae_zmalloc(size); + if (!data) + return NULL; + + data->type = type; + + return data; +} + +static struct opae_adapter_ops *match_ops(struct opae_adapter *adapter) +{ + struct opae_adapter_data *data; + + if (!adapter || !adapter->data) + return NULL; + + data = adapter->data; + + if (data->type == OPAE_FPGA_PCI) + return &ifpga_adapter_ops; + + return NULL; +} + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @name: adapter name. + * @data: private data of this adapter. + * + * Return: opae_adapter on success, otherwise NULL. + */ +struct opae_adapter *opae_adapter_alloc(const char *name, void *data) +{ + struct opae_adapter *adapter = opae_zmalloc(sizeof(*adapter)); + + if (!adapter) + return NULL; + + TAILQ_INIT(&adapter->acc_list); + adapter->data = data; + adapter->name = name; + adapter->ops = match_ops(adapter); + + return adapter; +} + +/** + * opae_adapter_enumerate - enumerate this adapter + * @adapter: adapter to enumerate. + * + * Return: 0 on success, otherwise error code. + */ +int opae_adapter_enumerate(struct opae_adapter *adapter) +{ + int ret = -ENOENT; + + if (!adapter) + return -EINVAL; + + if (adapter->ops && adapter->ops->enumerate) + ret = adapter->ops->enumerate(adapter); + + if (!ret) + opae_adapter_dump(adapter, 1); + + return ret; +} + +/** + * opae_adapter_destroy - destroy this adapter + * @adapter: adapter to destroy. + * + * destroy things allocated during adapter enumeration. + */ +void opae_adapter_destroy(struct opae_adapter *adapter) +{ + if (adapter && adapter->ops && adapter->ops->destroy) + adapter->ops->destroy(adapter); +} + +/** + * opae_adapter_get_acc - find and return accelerator with matched id + * @adapter: adapter to find the accelerator. + * @acc_id: id (index) of the accelerator. + * + * destroy things allocated during adapter enumeration. + */ +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id) +{ + struct opae_accelerator *acc = NULL; + + if (!adapter) + return NULL; + + opae_adapter_for_each_acc(adapter, acc) + if (acc->index == acc_id) + return acc; + + return NULL; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h new file mode 100644 index 0000000..4bbc9df --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_HW_API_H_ +#define _OPAE_HW_API_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> + +#include "opae_osdep.h" + +#ifndef PCI_MAX_RESOURCE +#define PCI_MAX_RESOURCE 6 +#endif + +struct opae_adapter; + +enum opae_adapter_type { + OPAE_FPGA_PCI, + OPAE_FPGA_NET, +}; + +/* OPAE Manager Data Structure */ +struct opae_manager_ops; + +/* + * opae_manager has pointer to its parent adapter, as it could be able to manage + * all components on this FPGA device (adapter). If not the case, don't set this + * adapter, which limit opae_manager ops to manager itself. + */ +struct opae_manager { + const char *name; + struct opae_adapter *adapter; + struct opae_manager_ops *ops; + void *data; +}; + +/* FIXME: add more management ops, e.g power/thermal and etc */ +struct opae_manager_ops { + int (*flash)(struct opae_manager *mgr, int id, void *buffer, + u32 size, u64 *status); +}; + +/* OPAE Manager APIs */ +struct opae_manager * +opae_manager_alloc(const char *name, struct opae_manager_ops *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); + +/* OPAE Bridge Data Structure */ +struct opae_bridge_ops; + +/* + * opae_bridge only has pointer to its downstream accelerator. + */ +struct opae_bridge { + const char *name; + int id; + struct opae_accelerator *acc; + struct opae_bridge_ops *ops; + void *data; +}; + +struct opae_bridge_ops { + int (*reset)(struct opae_bridge *br); +}; + +/* OPAE Bridge APIs */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data); +int opae_bridge_reset(struct opae_bridge *br); +#define opae_bridge_free(br) opae_free(br) + +/* OPAE Acceleraotr Data Structure */ +struct opae_accelerator_ops; + +/* + * opae_accelerator has pointer to its upstream bridge(port). + * In some cases, if we allow same user to do PR on its own accelerator, then + * set the manager pointer during the enumeration. But in other cases, the PR + * functions only could be done via manager in another module / thread / service + * / application for better protection. + */ +struct opae_accelerator { + TAILQ_ENTRY(opae_accelerator) node; + const char *name; + int index; + struct opae_bridge *br; + struct opae_manager *mgr; + struct opae_accelerator_ops *ops; + void *data; +}; + +struct opae_acc_info { + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct opae_acc_region_info { + u32 flags; +#define ACC_REGION_READ (1 << 0) +#define ACC_REGION_WRITE (1 << 1) +#define ACC_REGION_MMIO (1 << 2) + u32 index; + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_accelerator_ops { + int (*read)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*write)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*get_info)(struct opae_accelerator *acc, + struct opae_acc_info *info); + int (*get_region_info)(struct opae_accelerator *acc, + struct opae_acc_region_info *info); + int (*set_irq)(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); + int (*get_uuid)(struct opae_accelerator *acc, + struct uuid *uuid); +}; + +/* OPAE accelerator APIs */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data); +#define opae_accelerator_free(acc) opae_free(acc) +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info); +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info); +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid); + +static inline struct opae_bridge * +opae_acc_get_br(struct opae_accelerator *acc) +{ + return acc ? acc->br : NULL; +} + +static inline struct opae_manager * +opae_acc_get_mgr(struct opae_accelerator *acc) +{ + return acc ? acc->mgr : NULL; +} + +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + +#define opae_acc_reg_read64(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 8, data) +#define opae_acc_reg_write64(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 8, data) +#define opae_acc_reg_read32(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 4, data) +#define opae_acc_reg_write32(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 4, data) +#define opae_acc_reg_read16(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 2, data) +#define opae_acc_reg_write16(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 2, data) +#define opae_acc_reg_read8(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 1, data) +#define opae_acc_reg_write8(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 1, data) + +/*for data stream read/write*/ +int opae_acc_data_read(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); +int opae_acc_data_write(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); + +/* OPAE Adapter Data Structure */ +struct opae_adapter_data { + enum opae_adapter_type type; +}; + +struct opae_reg_region { + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_adapter_data_pci { + enum opae_adapter_type type; + u16 device_id; + u16 vendor_id; + struct opae_reg_region region[PCI_MAX_RESOURCE]; + int vfio_dev_fd; /* VFIO device file descriptor */ +}; + +/* FIXME: OPAE_FPGA_NET type */ +struct opae_adapter_data_net { + enum opae_adapter_type type; +}; + +struct opae_adapter_ops { + int (*enumerate)(struct opae_adapter *adapter); + void (*destroy)(struct opae_adapter *adapter); +}; + +TAILQ_HEAD(opae_accelerator_list, opae_accelerator); + +#define opae_adapter_for_each_acc(adatper, acc) \ + TAILQ_FOREACH(acc, &adapter->acc_list, node) + +struct opae_adapter { + const char *name; + struct opae_manager *mgr; + struct opae_accelerator_list acc_list; + struct opae_adapter_ops *ops; + void *data; +}; + +/* OPAE Adapter APIs */ +void *opae_adapter_data_alloc(enum opae_adapter_type type); +#define opae_adapter_data_free(data) opae_free(data) + +struct opae_adapter *opae_adapter_alloc(const char *name, void *data); +#define opae_adapter_free(adapter) opae_free(adapter) + +int opae_adapter_enumerate(struct opae_adapter *adapter); +void opae_adapter_destroy(struct opae_adapter *adapter); +static inline struct opae_manager * +opae_adapter_get_mgr(struct opae_adapter *adapter) +{ + return adapter ? adapter->mgr : NULL; +} + +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id); + +static inline void opae_adapter_add_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_INSERT_TAIL(&adapter->acc_list, acc, node); +} + +static inline void opae_adapter_remove_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_REMOVE(&adapter->acc_list, acc, node); +} +#endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c new file mode 100644 index 0000000..a40c8da --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_ifpga_hw_api.h" +#include "ifpga_api.h" + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data || !fme_info) + return -EINVAL; + + fme = mgr->data; + + spinlock_lock(&fme->lock); + fme_info->capability = fme->capability; + spinlock_unlock(&fme->lock); + + return 0; +} + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_irq(fme->parent, FEATURE_FIU_ID_FME, 0, + IFPGA_FME_FEATURE_ID_GLOBAL_ERR, err_irq_set); +} + +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_get_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !port_info) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + port_info->capability = port->capability; + port_info->num_uafu_irqs = port->num_uafu_irqs; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !info) + return -EINVAL; + + /* Only support STP region now */ + if (info->index != PORT_REGION_INDEX_STP) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + info->addr = (u64)port->stp_addr; + info->size = port->stp_size; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_ERROR, err_irq_set); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h new file mode 100644 index 0000000..65086cf --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_IFPGA_HW_API_H_ +#define _OPAE_IFPGA_HW_API_H_ + +#include "opae_hw_api.h" + +/** + * struct feature_prop - data structure for feature property + * @feature_id: id of this feature. + * @prop_id: id of this property under this feature. + * @data: property value to set/get. + */ +struct feature_prop { + u64 feature_id; + u64 prop_id; + u64 data; +}; + +#define IFPGA_FIU_ID_FME 0x0 +#define IFPGA_FIU_ID_PORT 0x1 + +#define IFPGA_FME_FEATURE_ID_HEADER 0x0 +#define IFPGA_FME_FEATURE_ID_THERMAL_MGMT 0x1 +#define IFPGA_FME_FEATURE_ID_POWER_MGMT 0x2 +#define IFPGA_FME_FEATURE_ID_GLOBAL_IPERF 0x3 +#define IFPGA_FME_FEATURE_ID_GLOBAL_ERR 0x4 +#define IFPGA_FME_FEATURE_ID_PR_MGMT 0x5 +#define IFPGA_FME_FEATURE_ID_HSSI 0x6 +#define IFPGA_FME_FEATURE_ID_GLOBAL_DPERF 0x7 + +#define IFPGA_PORT_FEATURE_ID_HEADER 0x0 +#define IFPGA_PORT_FEATURE_ID_AFU 0xff +#define IFPGA_PORT_FEATURE_ID_ERROR 0x10 +#define IFPGA_PORT_FEATURE_ID_UMSG 0x11 +#define IFPGA_PORT_FEATURE_ID_UINT 0x12 +#define IFPGA_PORT_FEATURE_ID_STP 0x13 + +/* + * PROP format (TOP + SUB + ID) + * + * (~0x0) means this field is unused. + */ +#define PROP_TOP GENMASK(31, 24) +#define PROP_TOP_UNUSED 0xff +#define PROP_SUB GENMASK(23, 16) +#define PROP_SUB_UNUSED 0xff +#define PROP_ID GENMASK(15, 0) + +#define PROP(_top, _sub, _id) \ + (SET_FIELD(PROP_TOP, _top) | SET_FIELD(PROP_SUB, _sub) |\ + SET_FIELD(PROP_ID, _id)) + +/* FME head feature's properties*/ +#define FME_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define FME_HDR_PROP_PORTS_NUM 0x2 /* RDONLY */ +#define FME_HDR_PROP_CACHE_SIZE 0x3 /* RDONLY */ +#define FME_HDR_PROP_VERSION 0x4 /* RDONLY */ +#define FME_HDR_PROP_SOCKET_ID 0x5 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_ID 0x6 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_METADATA 0x7 /* RDONLY */ + +/* FME error reporting feature's properties */ +/* FME error reporting properties format */ +#define ERR_PROP(_top, _id) PROP(_top, 0xff, _id) +#define ERR_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define ERR_PROP_TOP_FME_ERR 0x1 +#define ERR_PROP_ROOT(_id) ERR_PROP(0xff, _id) +#define ERR_PROP_FME_ERR(_id) ERR_PROP(ERR_PROP_TOP_FME_ERR, _id) + +#define FME_ERR_PROP_ERRORS ERR_PROP_FME_ERR(0x1) +#define FME_ERR_PROP_FIRST_ERROR ERR_PROP_FME_ERR(0x2) +#define FME_ERR_PROP_NEXT_ERROR ERR_PROP_FME_ERR(0x3) +#define FME_ERR_PROP_CLEAR ERR_PROP_FME_ERR(0x4) /* WO */ +#define FME_ERR_PROP_REVISION ERR_PROP_ROOT(0x5) +#define FME_ERR_PROP_PCIE0_ERRORS ERR_PROP_ROOT(0x6) /* RW */ +#define FME_ERR_PROP_PCIE1_ERRORS ERR_PROP_ROOT(0x7) /* RW */ +#define FME_ERR_PROP_NONFATAL_ERRORS ERR_PROP_ROOT(0x8) +#define FME_ERR_PROP_CATFATAL_ERRORS ERR_PROP_ROOT(0x9) +#define FME_ERR_PROP_INJECT_ERRORS ERR_PROP_ROOT(0xa) /* RW */ + +/* FME thermal feature's properties */ +#define FME_THERMAL_PROP_THRESHOLD1 0x1 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD2 0x2 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD_TRIP 0x3 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_REACHED 0x4 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD2_REACHED 0x5 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_POLICY 0x6 /* RW */ +#define FME_THERMAL_PROP_TEMPERATURE 0x7 /* RDONLY */ +#define FME_THERMAL_PROP_REVISION 0x8 /* RDONLY */ + +/* FME power feature's properties */ +#define FME_PWR_PROP_CONSUMED 0x1 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD1 0x2 /* RW */ +#define FME_PWR_PROP_THRESHOLD2 0x3 /* RW */ +#define FME_PWR_PROP_THRESHOLD1_STATUS 0x4 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD2_STATUS 0x5 /* RDONLY */ +#define FME_PWR_PROP_RTL 0x6 /* RDONLY */ +#define FME_PWR_PROP_XEON_LIMIT 0x7 /* RDONLY */ +#define FME_PWR_PROP_FPGA_LIMIT 0x8 /* RDONLY */ +#define FME_PWR_PROP_REVISION 0x9 /* RDONLY */ + +/* FME iperf/dperf PROP format */ +#define PERF_PROP_TOP_CACHE 0x1 +#define PERF_PROP_TOP_VTD 0x2 +#define PERF_PROP_TOP_FAB 0x3 +#define PERF_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define PERF_PROP_SUB_UNUSED PROP_SUB_UNUSED + +#define PERF_PROP_ROOT(_id) PROP(0xff, 0xff, _id) +#define PERF_PROP_CACHE(_id) PROP(PERF_PROP_TOP_CACHE, 0xff, _id) +#define PERF_PROP_VTD(_sub, _id) PROP(PERF_PROP_TOP_VTD, _sub, _id) +#define PERF_PROP_VTD_ROOT(_id) PROP(PERF_PROP_TOP_VTD, 0xff, _id) +#define PERF_PROP_FAB(_sub, _id) PROP(PERF_PROP_TOP_FAB, _sub, _id) +#define PERF_PROP_FAB_ROOT(_id) PROP(PERF_PROP_TOP_FAB, 0xff, _id) + +/* FME iperf feature's properties */ +#define FME_IPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_IPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* iperf CACHE properties */ +#define FME_IPERF_PROP_CACHE_FREEZE PERF_PROP_CACHE(0x1) /* RW */ +#define FME_IPERF_PROP_CACHE_READ_HIT PERF_PROP_CACHE(0x2) +#define FME_IPERF_PROP_CACHE_READ_MISS PERF_PROP_CACHE(0x3) +#define FME_IPERF_PROP_CACHE_WRITE_HIT PERF_PROP_CACHE(0x4) +#define FME_IPERF_PROP_CACHE_WRITE_MISS PERF_PROP_CACHE(0x5) +#define FME_IPERF_PROP_CACHE_HOLD_REQUEST PERF_PROP_CACHE(0x6) +#define FME_IPERF_PROP_CACHE_TX_REQ_STALL PERF_PROP_CACHE(0x7) +#define FME_IPERF_PROP_CACHE_RX_REQ_STALL PERF_PROP_CACHE(0x8) +#define FME_IPERF_PROP_CACHE_RX_EVICTION PERF_PROP_CACHE(0x9) +#define FME_IPERF_PROP_CACHE_DATA_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xa) +#define FME_IPERF_PROP_CACHE_TAG_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xb) +/* iperf VTD properties */ +#define FME_IPERF_PROP_VTD_FREEZE PERF_PROP_VTD_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_HIT PERF_PROP_VTD_ROOT(0x2) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_HIT PERF_PROP_VTD_ROOT(0x3) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_HIT PERF_PROP_VTD_ROOT(0x4) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_HIT PERF_PROP_VTD_ROOT(0x5) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_HIT PERF_PROP_VTD_ROOT(0x6) +#define FME_IPERF_PROP_VTD_SIP_RCC_HIT PERF_PROP_VTD_ROOT(0x7) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_MISS PERF_PROP_VTD_ROOT(0x8) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_MISS PERF_PROP_VTD_ROOT(0x9) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_MISS PERF_PROP_VTD_ROOT(0xa) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_MISS PERF_PROP_VTD_ROOT(0xb) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_MISS PERF_PROP_VTD_ROOT(0xc) +#define FME_IPERF_PROP_VTD_SIP_RCC_MISS PERF_PROP_VTD_ROOT(0xd) +#define FME_IPERF_PROP_VTD_PORT_READ_TRANSACTION(n) PERF_PROP_VTD(n, 0xe) +#define FME_IPERF_PROP_VTD_PORT_WRITE_TRANSACTION(n) PERF_PROP_VTD(n, 0xf) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_READ_HIT(n) PERF_PROP_VTD(n, 0x10) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_WRITE_HIT(n) PERF_PROP_VTD(n, 0x11) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_4K_FILL(n) PERF_PROP_VTD(n, 0x12) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_2M_FILL(n) PERF_PROP_VTD(n, 0x13) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_1G_FILL(n) PERF_PROP_VTD(n, 0x14) +/* iperf FAB properties */ +#define FME_IPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_IPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_IPERF_PROP_FAB_PCIE1_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_IPERF_PROP_FAB_PCIE1_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_IPERF_PROP_FAB_UPI_READ PERF_PROP_FAB_ROOT(0x6) +#define FME_IPERF_PROP_FAB_PORT_UPI_READ(n) PERF_PROP_FAB(n, 0x6) +#define FME_IPERF_PROP_FAB_UPI_WRITE PERF_PROP_FAB_ROOT(0x7) +#define FME_IPERF_PROP_FAB_PORT_UPI_WRITE(n) PERF_PROP_FAB(n, 0x7) +#define FME_IPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x8) +#define FME_IPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x8) +#define FME_IPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x9) +#define FME_IPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x9) +#define FME_IPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0xa) /* RW */ +#define FME_IPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0xa) /* RW */ + +/* FME dperf properties */ +#define FME_DPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_DPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* dperf FAB properties */ +#define FME_DPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_DPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_DPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_DPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_DPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_DPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_DPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_DPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0x6) /* RW */ +#define FME_DPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0x6) /* RW */ + +/*PORT hdr feature's properties*/ +#define PORT_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_HDR_PROP_PORTIDX 0x2 /* RDONLY */ +#define PORT_HDR_PROP_LATENCY_TOLERANCE 0x3 /* RDONLY */ +#define PORT_HDR_PROP_AP1_EVENT 0x4 /* RW */ +#define PORT_HDR_PROP_AP2_EVENT 0x5 /* RW */ +#define PORT_HDR_PROP_POWER_STATE 0x6 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_FREQCMD 0x7 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQCNTRCMD 0x8 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQSTS 0x9 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_CNTRSTS 0xa /* RDONLY */ + +/*PORT error feature's properties*/ +#define PORT_ERR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_ERR_PROP_ERRORS 0x2 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_ERROR 0x3 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB 0x4 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB 0x5 /* RDONLY */ +#define PORT_ERR_PROP_CLEAR 0x6 /* WRONLY */ + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop); +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop); + +/* + * Retrieve information about the fpga fme. + * Driver fills the info in provided struct fpga_fme_info. + */ +struct fpga_fme_info { + u32 capability; /* The capability of FME device */ +#define FPGA_FME_CAP_ERR_IRQ (1 << 0) /* Support fme error interrupt */ +}; + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info); + +/* Set eventfd information for ifpga FME error interrupt */ +struct fpga_fme_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set); + +/* + * Retrieve information about the fpga port. + * Driver fills the info in provided struct fpga_port_info. + */ +struct fpga_port_info { + u32 capability; /* The capability of port device */ +#define FPGA_PORT_CAP_ERR_IRQ (1 << 0) /* Support port error interrupt */ +#define FPGA_PORT_CAP_UAFU_IRQ (1 << 1) /* Support uafu error interrupt */ + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ +}; + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info); +/* + * Retrieve region information about the fpga port. + * Driver needs to fill the index of struct fpga_port_region_info. + */ +struct fpga_port_region_info { + u32 index; +#define PORT_REGION_INDEX_STP (1 << 1) /* Signal Tap Region */ + u64 size; /* Region Size */ + u64 addr; /* Base address of the region */ +}; + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info); + +/* Set eventfd information for ifpga port error interrupt */ +struct fpga_port_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set); + +#endif /* _OPAE_IFPGA_HW_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h new file mode 100644 index 0000000..e9da710 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_OSDEP_H +#define _OPAE_OSDEP_H + +#include <string.h> +#include <stdbool.h> + +#ifdef RTE_LIBRTE_EAL +#include "osdep_rte/osdep_generic.h" +#else +#include "osdep_raw/osdep_generic.h" +#endif + +#include <asm/types.h> + +#define __iomem + +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef uint64_t dma_addr_t; + +struct uuid { + u8 b[16]; +}; + +#ifndef LINUX_MACROS +#ifndef BITS_PER_LONG +#define BITS_PER_LONG (__SIZEOF_LONG__ * 8) +#endif +#ifndef BIT +#define BIT(a) (1UL << (a)) +#endif /* BIT */ +#ifndef BIT_ULL +#define BIT_ULL(a) (1ULL << (a)) +#endif /* BIT_ULL */ +#ifndef GENMASK +#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#endif /* GENMASK */ +#ifndef GENMASK_ULL +#define GENMASK_ULL(h, l) (((U64_C(1) << ((h) - (l) + 1)) - 1) << (l)) +#endif /* GENMASK_ULL */ +#endif /* LINUX_MACROS */ + +#define SET_FIELD(m, v) (((v) << (__builtin_ffsll(m) - 1)) & (m)) +#define GET_FIELD(m, v) (((v) & (m)) >> (__builtin_ffsll(m) - 1)) + +#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) +#define pr_info(y, args...) dev_info(0, y, ##args) + +#ifndef WARN_ON +#define WARN_ON(x) do { \ + int ret = !!(x); \ + if (unlikely(ret)) \ + pr_warn("WARN_ON: \"" #x "\" at %s:%d\n", __func__, __LINE__); \ +} while (0) +#endif + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define udelay(x) opae_udelay(x) +#define msleep(x) opae_udelay(1000 * (x)) +#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000)) + +#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 new file mode 100644 index 0000000..895a1d8 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OSDEP_RAW_GENERIC_H +#define _OSDEP_RAW_GENERIC_H + +#define compiler_barrier() (asm volatile ("" : : : "memory")) + +#define io_wmb() compiler_barrier() +#define io_rmb() compiler_barrier() + +static inline uint8_t opae_readb(const volatile void *addr) +{ + uint8_t val; + + val = *(const volatile uint8_t *)addr; + io_rmb(); + return val; +} + +static inline uint16_t opae_readw(const volatile void *addr) +{ + uint16_t val; + + val = *(const volatile uint16_t *)addr; + io_rmb(); + return val; +} + +static inline uint32_t opae_readl(const volatile void *addr) +{ + uint32_t val; + + val = *(const volatile uint32_t *)addr; + io_rmb(); + return val; +} + +static inline uint64_t opae_readq(const volatile void *addr) +{ + uint64_t val; + + val = *(const volatile uint64_t *)addr; + io_rmb(); + return val; +} + +static inline void opae_writeb(uint8_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint8_t *)addr = value; +} + +static inline void opae_writew(uint16_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint16_t *)addr = value; +} + +static inline void opae_writel(uint32_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint32_t *)addr = value; +} + +static inline void opae_writeq(uint64_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint64_t *)addr = value; +} + +#define opae_free(addr) free(addr) + +#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 new file mode 100644 index 0000000..76902e2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OSDEP_RTE_GENERIC_H +#define _OSDEP_RTE_GENERIC_H + +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_spinlock.h> +#include <rte_log.h> +#include <rte_io.h> +#include <rte_malloc.h> + +#define dev_printf(level, fmt, args...) \ + RTE_LOG(level, PMD, "osdep_rte: " fmt, ## args) + +#define osdep_panic(...) rte_panic(...) + +#define opae_udelay(x) rte_delay_us(x) + +#define opae_readb(addr) rte_read8(addr) +#define opae_readw(addr) rte_read16(addr) +#define opae_readl(addr) rte_read32(addr) +#define opae_readq(addr) rte_read64(addr) +#define opae_writeb(value, addr) rte_write8(value, addr) +#define opae_writew(value, addr) rte_write16(value, addr) +#define opae_writel(value, addr) rte_write32(value, addr) +#define opae_writeq(value, addr) rte_write64(value, addr) + +#define opae_malloc(size) rte_malloc(NULL, size, 0) +#define opae_zmalloc(size) rte_zmalloc(NULL, size, 0) +#define opae_free(addr) rte_free(addr) + +#define ARRAY_SIZE(arr) RTE_DIM(arr) + +#define min(a, b) RTE_MIN(a, b) +#define max(a, b) RTE_MAX(a, b) + +#define spinlock_t rte_spinlock_t +#define spinlock_init(x) rte_spinlock_init(x) +#define spinlock_lock(x) rte_spinlock_lock(x) +#define spinlock_unlock(x) rte_spinlock_unlock(x) + +#endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v9 2/4] iFPGA: Add Intel FPGA OPAE Share Code 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 2/4] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen @ 2018-05-08 14:45 ` Thomas Monjalon 2018-05-09 1:24 ` Xu, Rosen 0 siblings, 1 reply; 149+ messages in thread From: Thomas Monjalon @ 2018-05-08 14:45 UTC (permalink / raw) To: Xu, Rosen Cc: dev, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Xu, Yilun 08/05/2018 16:19, Xu, Rosen: > --- /dev/null > +++ b/drivers/raw/ifpga_rawdev/base/README > @@ -0,0 +1,31 @@ > +.. > + > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation > + */ > + > +Intel® iFPGA driver > +================== There is a strange character in this title. You can use (R) or nothing. Please make sure that the title is well underlined. ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v9 2/4] iFPGA: Add Intel FPGA OPAE Share Code 2018-05-08 14:45 ` Thomas Monjalon @ 2018-05-09 1:24 ` Xu, Rosen 0 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-09 1:24 UTC (permalink / raw) To: Thomas Monjalon Cc: dev, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet, Xu, Yilun Hi Thomas, > -----Original Message----- > From: Thomas Monjalon [mailto:thomas@monjalon.net] > Sent: Tuesday, May 08, 2018 22:45 > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com; Xu, Yilun <yilun.xu@intel.com> > Subject: Re: [PATCH v9 2/4] iFPGA: Add Intel FPGA OPAE Share Code > > 08/05/2018 16:19, Xu, Rosen: > > --- /dev/null > > +++ b/drivers/raw/ifpga_rawdev/base/README > > @@ -0,0 +1,31 @@ > > +.. > > + > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > +Intel® iFPGA driver > > +================== > > There is a strange character in this title. You can use (R) or nothing. > Please make sure that the title is well underlined. I will fix it in v10. ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v9 3/4] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-08 14:18 ` [dpdk-dev] [PATCH v9 0/4] Introduce Intel FPGA BUS Xu, Rosen 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 1/4] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 2/4] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen @ 2018-05-08 14:19 ` Xu, Rosen 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 4/4] iFPGA: add document for iFPGA driver Xu, Rosen 3 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-08 14:19 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Yanglong Wu From: Rosen Xu <rosen.xu@intel.com> Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev library. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> Signed-off-by: Figo zhang <tianfei.zhang@intel.com> Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> --- config/common_base | 1 + drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 ++ drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 608 +++++++++++++++++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ drivers/raw/ifpga_rawdev/meson.build | 15 + .../ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map | 4 + drivers/raw/meson.build | 2 +- mk/rte.app.mk | 4 +- 9 files changed, 706 insertions(+), 2 deletions(-) create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/meson.build create mode 100644 drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map diff --git a/config/common_base b/config/common_base index 7b79e37..1127136 100644 --- a/config/common_base +++ b/config/common_base @@ -152,6 +152,7 @@ CONFIG_RTE_LIBRTE_VDEV_BUS=y # Compile the Intel FPGA bus # CONFIG_RTE_LIBRTE_IFPGA_BUS=y +CONFIG_RTE_LIBRTE_IFPGA_RAWDEV=y # # Compile ARK PMD diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index 2eb2787..d29898b 100644 --- a/drivers/raw/Makefile +++ b/drivers/raw/Makefile @@ -9,5 +9,6 @@ ifeq ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += dpaa2_cmdif DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += dpaa2_qdma endif +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/raw/ifpga_rawdev/Makefile b/drivers/raw/ifpga_rawdev/Makefile new file mode 100644 index 0000000..a4bee7e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/Makefile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_ifpga_rawdev.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_bus_vdev +LDLIBS += -lrte_kvargs +LDLIBS += -lrte_bus_pci +LDLIBS += -lrte_bus_ifpga + +EXPORT_MAP := rte_pmd_ifpga_rawdev_version.map + +LIBABIVER := 1 + +VPATH += $(SRCDIR)/base + +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_RAWDEV) += ifpga_rawdev.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c new file mode 100644 index 0000000..81d9edf --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c @@ -0,0 +1,608 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <rte_log.h> +#include <rte_bus.h> +#include <rte_eal_memconfig.h> +#include <rte_malloc.h> +#include <rte_devargs.h> +#include <rte_memcpy.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include <rte_errno.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> +#include <rte_bus_vdev.h> + +#include "base/opae_hw_api.h" +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_common.h" +#include "ifpga_logs.h" +#include "ifpga_rawdev.h" + +int ifpga_rawdev_logtype; + +#define PCI_VENDOR_ID_INTEL 0x8086 +/* PCI Device ID */ +#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 +/* 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 RTE_MAX_RAW_DEVICE 10 + +static const struct rte_pci_id pci_ifpga_map[] = { + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_6_X) }, + { 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) }, + { .vendor_id = 0, /* sentinel */ }, +}; + +static int +ifpga_fill_afu_dev(struct opae_accelerator *acc, + struct rte_afu_device *afu_dev) +{ + struct rte_mem_resource *res = afu_dev->mem_resource; + struct opae_acc_region_info region_info; + struct opae_acc_info info; + unsigned long i; + int ret; + + ret = opae_acc_get_info(acc, &info); + if (ret) + return ret; + + if (info.num_regions > PCI_MAX_RESOURCE) + return -EFAULT; + + afu_dev->num_region = info.num_regions; + + for (i = 0; i < info.num_regions; i++) { + region_info.index = i; + ret = opae_acc_get_region_info(acc, ®ion_info); + if (ret) + return ret; + + if ((region_info.flags & ACC_REGION_MMIO) && + (region_info.flags & ACC_REGION_READ) && + (region_info.flags & ACC_REGION_WRITE)) { + res[i].phys_addr = region_info.phys_addr; + res[i].len = region_info.len; + res[i].addr = region_info.addr; + } else + return -EFAULT; + } + + return 0; +} + +static void +ifpga_rawdev_info_get(struct rte_rawdev *dev, + rte_rawdev_obj_t dev_info) +{ + struct opae_adapter *adapter; + struct opae_accelerator *acc; + struct rte_afu_device *afu_dev; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + if (!dev_info) { + IFPGA_RAWDEV_PMD_ERR("Invalid request"); + return; + } + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return; + + afu_dev = dev_info; + afu_dev->rawdev = dev; + + /* find opae_accelerator and fill info into afu_device */ + opae_adapter_for_each_acc(adapter, acc) { + if (acc->index != afu_dev->id.port) + continue; + + if (ifpga_fill_afu_dev(acc, afu_dev)) { + IFPGA_RAWDEV_PMD_ERR("cannot get info\n"); + return; + } + } +} + +static int +ifpga_rawdev_start(struct rte_rawdev *dev) +{ + int ret = 0; + struct opae_adapter *adapter; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + return ret; +} + +static void +ifpga_rawdev_stop(struct rte_rawdev *dev) +{ + dev->started = 0; +} + +static int +ifpga_rawdev_close(struct rte_rawdev *dev) +{ + return dev ? 0:1; +} + +static int +ifpga_rawdev_reset(struct rte_rawdev *dev) +{ + return dev ? 0:1; +} + +static int +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, + u64 *status) +{ + + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_accelerator *acc; + struct opae_bridge *br; + int ret; + + adapter = ifpga_rawdev_get_priv(raw_dev); + if (!adapter) + return -ENODEV; + + mgr = opae_adapter_get_mgr(adapter); + if (!mgr) + return -ENODEV; + + acc = opae_adapter_get_acc(adapter, port_id); + if (!acc) + return -ENODEV; + + br = opae_acc_get_br(acc); + if (!br) + return -ENODEV; + + ret = opae_manager_flash(mgr, port_id, buffer, size, status); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("%s pr error %d\n", __func__, ret); + return ret; + } + + ret = opae_bridge_reset(br); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("%s reset port:%d error %d\n", + __func__, port_id, ret); + return ret; + } + + return ret; +} + +static int +rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, + const char *file_name) +{ + struct stat file_stat; + int file_fd; + int ret = 0; + u32 buffer_size; + void *buffer; + u64 pr_error; + + if (!file_name) + return -EINVAL; + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + IFPGA_RAWDEV_PMD_ERR("%s: open file error: %s\n", + __func__, file_name); + IFPGA_RAWDEV_PMD_ERR("Message : %s\n", strerror(errno)); + return -EINVAL; + } + ret = stat(file_name, &file_stat); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("stat on bitstream file failed: %s\n", + file_name); + return -EINVAL; + } + buffer_size = file_stat.st_size; + IFPGA_RAWDEV_PMD_INFO("bitstream file size: %u\n", buffer_size); + buffer = rte_malloc(NULL, buffer_size, 0); + if (!buffer) { + ret = -ENOMEM; + goto close_fd; + } + + /*read the raw data*/ + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { + ret = -EINVAL; + goto free_buffer; + } + + /*do PR now*/ + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); + IFPGA_RAWDEV_PMD_INFO("downloading to device port %d....%s.\n", port_id, + ret ? "failed" : "success"); + if (ret) { + ret = -EINVAL; + goto free_buffer; + } + +free_buffer: + if (buffer) + rte_free(buffer); +close_fd: + close(file_fd); + file_fd = 0; + return ret; +} + +static int +ifpga_rawdev_pr(struct rte_rawdev *dev, + rte_rawdev_obj_t pr_conf) +{ + struct opae_adapter *adapter; + struct rte_afu_pr_conf *afu_pr_conf; + int ret; + struct uuid uuid; + struct opae_accelerator *acc; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + if (!pr_conf) + return -EINVAL; + + afu_pr_conf = pr_conf; + + if (afu_pr_conf->pr_enable) { + ret = rte_fpga_do_pr(dev, + afu_pr_conf->afu_id.port, + afu_pr_conf->bs_path); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("do pr error %d\n", ret); + return ret; + } + } + + acc = opae_adapter_get_acc(adapter, afu_pr_conf->afu_id.port); + if (!acc) + return -ENODEV; + + ret = opae_acc_get_uuid(acc, &uuid); + if (ret) + return ret; + + memcpy(&afu_pr_conf->afu_id.uuid.uuid_low, uuid.b, sizeof(u64)); + memcpy(&afu_pr_conf->afu_id.uuid.uuid_high, uuid.b + 8, sizeof(u64)); + + IFPGA_RAWDEV_PMD_INFO("%s: uuid_l=0x%lx, uuid_h=0x%lx\n", __func__, + (u64)afu_pr_conf->afu_id.uuid.uuid_low, + (u64)afu_pr_conf->afu_id.uuid.uuid_high); + + return 0; +} + +static const struct rte_rawdev_ops ifpga_rawdev_ops = { + .dev_info_get = ifpga_rawdev_info_get, + .dev_configure = NULL, + .dev_start = ifpga_rawdev_start, + .dev_stop = ifpga_rawdev_stop, + .dev_close = ifpga_rawdev_close, + .dev_reset = ifpga_rawdev_reset, + + .queue_def_conf = NULL, + .queue_setup = NULL, + .queue_release = NULL, + + .attr_get = NULL, + .attr_set = NULL, + + .enqueue_bufs = NULL, + .dequeue_bufs = NULL, + + .dump = NULL, + + .xstats_get = NULL, + .xstats_get_names = NULL, + .xstats_get_by_name = NULL, + .xstats_reset = NULL, + + .firmware_status_get = NULL, + .firmware_version_get = NULL, + .firmware_load = ifpga_rawdev_pr, + .firmware_unload = NULL, + + .dev_selftest = NULL, +}; + +static int +ifpga_rawdev_create(struct rte_pci_device *pci_dev, + int socket_id) +{ + int ret = 0; + struct rte_rawdev *rawdev = NULL; + struct opae_adapter *adapter = NULL; + struct opae_manager *mgr = NULL; + struct opae_adapter_data_pci *data = NULL; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + int i; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + goto cleanup; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id()); + + /* Allocate device structure */ + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct opae_adapter), + socket_id); + if (rawdev == NULL) { + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); + ret = -EINVAL; + goto cleanup; + } + + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API */ + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); + if (!data) { + ret = -ENOMEM; + goto cleanup; + } + + /* init opae_adapter_data_pci for device specific information */ + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + data->region[i].phys_addr = pci_dev->mem_resource[i].phys_addr; + data->region[i].len = pci_dev->mem_resource[i].len; + data->region[i].addr = pci_dev->mem_resource[i].addr; + } + data->device_id = pci_dev->id.device_id; + data->vendor_id = pci_dev->id.vendor_id; + + /* create a opae_adapter based on above device data */ + adapter = opae_adapter_alloc(pci_dev->device.name, data); + if (!adapter) { + ret = -ENOMEM; + goto free_adapter_data; + } + + rawdev->dev_ops = &ifpga_rawdev_ops; + rawdev->device = &pci_dev->device; + rawdev->driver_name = pci_dev->device.driver->name; + + rawdev->dev_private = adapter; + + /* must enumerate the adapter before use it */ + ret = opae_adapter_enumerate(adapter); + if (ret) + goto free_adapter; + + /* get opae_manager to rawdev */ + mgr = opae_adapter_get_mgr(adapter); + if (mgr) { + /* PF function */ + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); + } + + return ret; + +free_adapter: + if (adapter) + opae_adapter_free(adapter); +free_adapter_data: + if (data) + opae_adapter_data_free(data); +cleanup: + if (rawdev) + rte_rawdev_pmd_release(rawdev); + + return ret; +} + +static int +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) +{ + int ret; + struct rte_rawdev *rawdev; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + struct opae_adapter *adapter; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + return ret; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", + name, rte_socket_id()); + + rawdev = rte_rawdev_pmd_get_named_dev(name); + if (!rawdev) { + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name); + return -EINVAL; + } + + adapter = ifpga_rawdev_get_priv(rawdev); + if (!adapter) + return -ENODEV; + + opae_adapter_data_free(adapter->data); + opae_adapter_free(adapter); + + /* rte_rawdev_close is called by pmd_release */ + ret = rte_rawdev_pmd_release(rawdev); + if (ret) + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); + + return ret; +} + +static int +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()); +} + +static int +ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) +{ + return ifpga_rawdev_destroy(pci_dev); +} + +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { + .id_table = pci_ifpga_map, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, + .probe = ifpga_rawdev_pci_probe, + .remove = ifpga_rawdev_pci_remove, +}; + +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | uio_pci_generic | vfio-pci"); + +RTE_INIT(ifpga_rawdev_init_log); +static void +ifpga_rawdev_init_log(void) +{ + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); + if (ifpga_rawdev_logtype >= 0) + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +static int +ifpga_cfg_probe(struct rte_vdev_device *dev) +{ + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + int port; + char *name = NULL; + char dev_name[RTE_RAWDEV_NAME_MAX_LEN]; + + devargs = dev->device.devargs; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &ifpga_get_string_arg, &name) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, + IFPGA_ARG_PORT, + &ifpga_get_integer32_arg, + &port) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + memset(dev_name, 0, sizeof(dev_name)); + snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s", + port, name); + + rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), + dev_name, devargs->args); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +static int +ifpga_cfg_remove(struct rte_vdev_device *vdev) +{ + IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p", + vdev); + + return 0; +} + +static struct rte_vdev_driver ifpga_cfg_driver = { + .probe = ifpga_cfg_probe, + .remove = ifpga_cfg_remove, +}; + +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, + "bdf=<string> " + "port=<int> " + "afu_bts=<path>"); + diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h new file mode 100644 index 0000000..c7759b8 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_RAWDEV_H_ +#define _IFPGA_RAWDEV_H_ + +extern int ifpga_rawdev_logtype; + +#define IFPGA_RAWDEV_PMD_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_rawdev_logtype, "ifgpa: " fmt, \ + ##args) + +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") + +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) +#define IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) +#define IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) +#define IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) + +enum ifpga_rawdev_device_state { + IFPGA_IDLE, + IFPGA_READY, + IFPGA_ERROR +}; + +static inline struct opae_adapter * +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) +{ + return rawdev->dev_private; +} + +#endif /* _IFPGA_RAWDEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/meson.build b/drivers/raw/ifpga_rawdev/meson.build new file mode 100644 index 0000000..6725687 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/meson.build @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +version = 1 + +subdir('base') +objs = [base_objs] + +deps += ['rawdev', 'pci', 'bus_pci', 'kvargs', + 'bus_vdev', 'bus_ifpga'] +sources = files('ifpga_rawdev.c') + +includes += include_directories('base') + +allow_experimental_apis = true diff --git a/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map new file mode 100644 index 0000000..9b9ab1a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map @@ -0,0 +1,4 @@ +DPDK_18.05 { + + local: *; +}; diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build index 34dfac4..a61cdcc 100644 --- a/drivers/raw/meson.build +++ b/drivers/raw/meson.build @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright 2018 NXP -drivers = ['skeleton_rawdev', 'dpaa2_cmdif', 'dpaa2_qdma'] +drivers = ['skeleton_rawdev', 'dpaa2_cmdif', 'dpaa2_qdma', 'ifpga_rawdev'] std_deps = ['rawdev'] config_flag_fmt = 'RTE_LIBRTE_PMD_@0@_RAWDEV' driver_name_fmt = 'rte_pmd_@0@' diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 3861e1a..6018390 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -256,9 +256,11 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += -lrte_pmd_dpaa2_cmdif _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += -lrte_pmd_dpaa2_qdma 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_IFPGA_RAWDEV) += -lrte_ifpga_rawdev +endif # CONFIG_RTE_LIBRTE_IFPGA_BUS endif # CONFIG_RTE_LIBRTE_RAWDEV - endif # !CONFIG_RTE_BUILD_SHARED_LIBS _LDLIBS-y += --no-whole-archive -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v9 4/4] iFPGA: add document for iFPGA driver 2018-05-08 14:18 ` [dpdk-dev] [PATCH v9 0/4] Introduce Intel FPGA BUS Xu, Rosen ` (2 preceding siblings ...) 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 3/4] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen @ 2018-05-08 14:19 ` Xu, Rosen 2018-05-08 14:49 ` Thomas Monjalon 3 siblings, 1 reply; 149+ messages in thread From: Xu, Rosen @ 2018-05-08 14:19 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: Rosen Xu <rosen.xu@intel.com> add some introduction, motivation and usage for iFPGA driver. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> --- doc/guides/rawdevs/ifpga_rawdev.rst | 112 +++++++++++++++++++++++++++++++++ doc/guides/rawdevs/index.rst | 1 + doc/guides/rel_notes/release_18_05.rst | 13 ++++ 3 files changed, 126 insertions(+) create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst diff --git a/doc/guides/rawdevs/ifpga_rawdev.rst b/doc/guides/rawdevs/ifpga_rawdev.rst new file mode 100644 index 0000000..37ae4cc --- /dev/null +++ b/doc/guides/rawdevs/ifpga_rawdev.rst @@ -0,0 +1,112 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2018 Intel Corporation. + +IFPGA Rawdev Driver +====================== + +FPGA is used more and more widely in Cloud and NFV, one primary reason is +that FPGA not only provides ASIC performance but also it's more flexible +than ASIC. + +FPGA uses Partial Reconfigure (PR) Parts of Bit Stream to achieve its +flexibility. That means one FPGA Device Bit Stream is divided into many Parts +of Bit Stream(each Part of Bit Stream is defined as AFU-Accelerated Function +Unit), and each AFU is a hardware acceleration unit which can be dynamically +reloaded respectively. + +By PR (Partial Reconfiguration) AFUs, one FPGA resources can be time-shared by +different users. FPGA hot upgrade and fault tolerance can be provided easily. + +The SW IFPGA Rawdev Driver (**ifpga_rawdev**) provides a Rawdev driver +that utilizes Intel FPGA Software Stack OPAE(Open Programmable Acceleration +Engine) for FPGA management. + +Implementation details +---------------------- + +Each instance of IFPGA Rawdev Driver is probed by Intel FpgaDev. In coordination +with OPAE share code IFPGA Rawdev Driver provides common FPGA management ops +for FPGA operation, OPAE provides all following operations: +- FPGA PR (Partial Reconfiguration) management +- FPGA AFUs Identifying +- FPGA Thermal Management +- FPGA Power Management +- FPGA Performance reporting +- FPGA Remote Debug + +All configuration parameters are taken by vdev_ifpga_cfg driver. Besides +configuration, vdev_ifpga_cfg driver also hot plugs in IFPGA Bus. + +All of the AFUs of one FPGA may share same PCI BDF and AFUs scan depend on +IFPGA Rawdev Driver so IFPGA Bus takes AFU device scan and AFU drivers probe. +All AFU device driver bind to AFU device by its UUID (Universally Unique +Identifier). + +To avoid unnecessary code duplication and ensure maximum performance, +handling of AFU devices is left to different PMDs; all the design as +summarized by the following block diagram:: + + +---------------------------------------------------------------+ + | Application(s) | + +----------------------------.----------------------------------+ + | + | + +----------------------------'----------------------------------+ + | DPDK Framework (APIs) | + +----------|------------|--------.---------------------|--------+ + / \ | + / \ | + +-------'-------+ +-------'-------+ +--------'--------+ + | Eth PMD | | Crypto PMD | | | + +-------.-------+ +-------.-------+ | | + | | | | + | | | | + +-------'-------+ +-------'-------+ | IFPGA | + | Eth AFU Dev | |Crypto AFU Dev | | Rawdev Driver | + +-------.-------+ +-------.-------+ |(OPAE Share Code)| + | | | | + | | Rawdev | | + +-------'------------------'-------+ Ops | | + | IFPGA Bus | -------->| | + +-----------------.----------------+ +--------.--------+ + | | + Hot-plugin -->| | + | | + +-----------------'------------------+ +--------'--------+ + | vdev_ifpga_cfg driver | | Intel FpgaDev | + +------------------------------------+ +-----------------+ + +Build options +------------- + +- ``CONFIG_RTE_LIBRTE_IFPGA_BUS`` (default ``y``) + + Toggle compilation of IFPGA Bus library. + +- ``CONFIG_RTE_LIBRTE_IFPGA_RAWDEV`` (default ``y``) + + Toggle compilation of the ``ifpga_rawdev`` driver. + +Run-time parameters +------------------- + +This driver is invoked automatically in systems added with Intel FPGA, +but PR and IFPGA Bus scan is trigged by command line using +``--vdev 'net_ifpga_cfg`` EAL option. + +The following device parameters are supported: + +- ``ifpga`` [string] + + Provide a specific Intel FPGA device PCI BDF. Can be provided multiple + times for additional instances. + +- ``port`` [int] + + Each FPGA can provide many channels to PR AFU by software, each channels + is identified by this parameter. + +- ``afu_bts`` [string] + + If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and + identifies AFU Bit Stream file. diff --git a/doc/guides/rawdevs/index.rst b/doc/guides/rawdevs/index.rst index 7769083..7c3bd95 100644 --- a/doc/guides/rawdevs/index.rst +++ b/doc/guides/rawdevs/index.rst @@ -13,3 +13,4 @@ application through rawdev API. dpaa2_cmdif dpaa2_qdma + ifpga_rawdev diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst index 7187348..f5241a1 100644 --- a/doc/guides/rel_notes/release_18_05.rst +++ b/doc/guides/rel_notes/release_18_05.rst @@ -183,6 +183,19 @@ New Features stats/xstats on shared memory from secondary process, and also pdump packets on those virtual devices. +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** + + The Ifpga Bus library provides support for integrating any Intel FPGA device with + the DPDK framework. It provides Intel FPGA Partial Bit Stream AFU(Accelerated + Function Unit) scan and drivers prove. + +* **Added IFPGA(Intel FPGA) Rawdev Driver.** + + Added a new Rawdev driver called IFPGA(Intel FPGA) Rawdev Driver, which cooperates + with OPAE(Open Programmable Acceleration Engine) share code provides common FPGA + management ops for FPGA operation. + + See the :doc:`../rawdevs/ifpga_rawdev` programmer's guide for more details. API Changes ----------- -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v9 4/4] iFPGA: add document for iFPGA driver 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 4/4] iFPGA: add document for iFPGA driver Xu, Rosen @ 2018-05-08 14:49 ` Thomas Monjalon 0 siblings, 0 replies; 149+ messages in thread From: Thomas Monjalon @ 2018-05-08 14:49 UTC (permalink / raw) To: Xu, Rosen Cc: dev, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet 08/05/2018 16:19, Xu, Rosen: > From: Rosen Xu <rosen.xu@intel.com> > > add some introduction, motivation and usage for iFPGA driver. > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > Signed-off-by: Figo Zhang <tianfei.zhang@intel.com> > --- > doc/guides/rawdevs/ifpga_rawdev.rst | 112 +++++++++++++++++++++++++++++++++ > doc/guides/rawdevs/index.rst | 1 + Given the document size is small, it is better to squash it in the patch with the code itself. > doc/guides/rel_notes/release_18_05.rst | 13 ++++ Better to squash the release notes parts in relevant patches (1 and 3). You need also to update the MAINTAINERS file in patches 1, 2 and 3. ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v10 0/3] Introduce Intel FPGA BUS 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (12 preceding siblings ...) 2018-05-08 14:18 ` [dpdk-dev] [PATCH v9 0/4] Introduce Intel FPGA BUS Xu, Rosen @ 2018-05-09 7:43 ` Xu, Rosen 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen ` (2 more replies) 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 0/3] Introduce Intel FPGA BUS Xu, Rosen ` (3 subsequent siblings) 17 siblings, 3 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-09 7:43 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: "Xu, Rosen" <rosen.xu@intel.com> Intel FPGA BUS in DPDK ------------------------- This patch set introduces Intel FPGA BUS support in DPDK. v10 updates: =========== - Add prefix rte_ for exported symbols - Fix alphabetical order error - Fix share code title well underlined comments - Squash the release notes parts in relevant patches - Update the MAINTAINERS file in patches 1, 2 and 3 v9 updates: ========== - Rebase ifpga_rawdev on QDMA and CMDIF driver - Split and squash the patch 4(v8 patch) into patch 2 and patch 3 v8 updates: ========== - Fix some comments from Shreyansh Jain - Patch 3 and Patch 5 will continue rebase when qcom patches merging into mainline - add Shreyansh Jain's Acked-by v7 updates: ========== - Fix some comments from DPDK community - Fix the CLANG compile error - Fix the meson build warring. v6 updates: =========== - Add documentation - Add meson build script - Split new patch for OPAE share code v5 updates: =========== - Fixed SHARED LIB Build issue - Changed command name to IFPGA Rawdev name, so remove pci library datastruct and function. - Fixed PATCH v2/v3/v4 comments v4 updates: =========== - Remove all modifications from eal - Create vdev to take IFPGA parameters configuration - AFU Device Driver bind to AFU Device by uuid - Take more test in scenario of Multi-FPGA System v3 updates: =========== - Remove all modifications of bus scan and probe - FPGA BUS Scan is trigged by hotplug of Rawdev - Took Modifications of comments - Move AFU Device to IFPGA - FPGA BUS Scan depend on it's IFPGA Rawdev - Add Build Macros for FPGA BUS and IFPGA Rawdev Questions ========= Why not PCI Bus? All of the AFUs of one FPGA may share same PCI BDF. Why not vdev Bus? Because AFUs depend on Rawdev, and it's hardware specpic. Motivation ========== FPGA is used more and more widely in Cloud and NFV, one primary reason is that FPGA not only provide ASIC performance but also it's more flexible than ASIC. FPGA use Partial Reconfigure(PR) Parts of Bitstream to achieve its flexibility. Another reason is that one FPGA can be shared by different Users, and each User can use some of AFUs of One FPGA. That means One FPGA Device Bitstream is divided into many Parts of Bitstream(each Part of Bitstream is defined as AFU-Accelerated Function Unit), and each AFU is a Hardware Acceleration Unit and it can dynamically Reload respectively. Proposed Solution ================= - Involve Rawdev to take FPGA Partial Configuration(Download/PR) - Defined FPGA-BUS for Acceleration Drivers of AFUs - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver. FPGA-BUS scan is called, but AFU depend on Rawdev, so this scan doesn't trig AFU device create. - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their dirves are also probed. Scope ===== The Intel FPGA BUS implementation is target towards various FPGA Devices use PR to provide many Acceleration Function. Specific PMDs may also bind to its AFU. And Applications don't care they are using ASIC Acceleration or FPGA AFU Acceleration. Status ===== With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable Acceleration Engine) Share Code, Intel FPGA BUS runs well in Intel PSG FPGA Cards. Rosen Xu (2): bus/ifpga: Add Intel FPGA BUS Library iFPGA: Add Intel FPGA BUS Rawdev Driver Tianfei Zhang (1): iFPGA: Add Intel FPGA OPAE Share Code MAINTAINERS | 11 + config/common_base | 10 + doc/guides/rawdevs/ifpga_rawdev.rst | 112 ++ doc/guides/rawdevs/index.rst | 1 + doc/guides/rel_notes/release_18_05.rst | 13 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 + drivers/bus/ifpga/ifpga_bus.c | 501 ++++++ drivers/bus/ifpga/ifpga_common.c | 88 ++ drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 + drivers/bus/ifpga/meson.build | 8 + drivers/bus/ifpga/rte_bus_ifpga.h | 160 ++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/bus/meson.build | 2 +- drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 + drivers/raw/ifpga_rawdev/base/Makefile | 30 + drivers/raw/ifpga_rawdev/base/README | 31 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 294 ++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 28 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 57 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1661 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 824 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 11 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 314 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 164 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 734 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 301 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 403 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 715 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 372 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 127 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 408 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 165 ++ drivers/raw/ifpga_rawdev/base/meson.build | 34 + drivers/raw/ifpga_rawdev/base/opae_debug.c | 99 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 19 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 381 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 253 +++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 145 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 279 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 81 + .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 75 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 45 + drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 608 +++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 + drivers/raw/ifpga_rawdev/meson.build | 15 + .../ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map | 4 + drivers/raw/meson.build | 2 +- mk/rte.app.mk | 5 +- 51 files changed, 9753 insertions(+), 3 deletions(-) create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/meson.build create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/README create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/meson.build create mode 100644 drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 0/3] Introduce Intel FPGA BUS Xu, Rosen @ 2018-05-09 7:43 ` Xu, Rosen 2018-05-10 8:43 ` Wu, Jingjing 2018-05-10 12:26 ` Zhang, Qi Z 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 2/3] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2 siblings, 2 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-09 7:43 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: Rosen Xu <rosen.xu@intel.com> Defined FPGA-BUS for Acceleration Drivers of AFUs 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver, it will be covered in following patches. 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their drivers are also probed. This patch will introduce rte_afu_device which describe the AFU device listed in the FPGA-BUS. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> --- MAINTAINERS | 4 + config/common_base | 5 + doc/guides/rel_notes/release_18_05.rst | 5 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 ++ drivers/bus/ifpga/ifpga_bus.c | 501 ++++++++++++++++++++++++++++ drivers/bus/ifpga/ifpga_common.c | 88 +++++ drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 ++ drivers/bus/ifpga/meson.build | 8 + drivers/bus/ifpga/rte_bus_ifpga.h | 160 +++++++++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/bus/meson.build | 2 +- mk/rte.app.mk | 1 + 14 files changed, 865 insertions(+), 1 deletion(-) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/meson.build create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map diff --git a/MAINTAINERS b/MAINTAINERS index 7105920..fa0c5b1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -383,6 +383,10 @@ F: drivers/mempool/bucket/ Bus Drivers ----------- +Intel FPGA buses +M: Rosen Xu <rosen.xu@intel.com> +F: drivers/bus/ifpga/ + NXP buses M: Hemant Agrawal <hemant.agrawal@nxp.com> M: Shreyansh Jain <shreyansh.jain@nxp.com> diff --git a/config/common_base b/config/common_base index 0d181ac..1440316 100644 --- a/config/common_base +++ b/config/common_base @@ -139,6 +139,11 @@ CONFIG_RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS=n CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n # +# Compile the Intel FPGA bus +# +CONFIG_RTE_LIBRTE_IFPGA_BUS=y + +# # Compile PCI bus driver # CONFIG_RTE_LIBRTE_PCI_BUS=y diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst index 7187348..265950a 100644 --- a/doc/guides/rel_notes/release_18_05.rst +++ b/doc/guides/rel_notes/release_18_05.rst @@ -183,6 +183,11 @@ New Features stats/xstats on shared memory from secondary process, and also pdump packets on those virtual devices. +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** + + The Ifpga Bus library provides support for integrating any Intel FPGA device with + the DPDK framework. It provides Intel FPGA Partial Bit Stream AFU(Accelerated + Function Unit) scan and drivers prove. API Changes ----------- diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index c251b65..ef7f247 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -7,6 +7,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa ifeq ($(CONFIG_RTE_EAL_VFIO),y) DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc endif +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile new file mode 100644 index 0000000..3ff3bdb --- /dev/null +++ b/drivers/bus/ifpga/Makefile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_bus_ifpga.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_kvargs + +# versioning export map +EXPORT_MAP := rte_bus_ifpga_version.map + +# library version +LIBABIVER := 1 + +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c + +# +# Export include files +# +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index 0000000..e144c01 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -0,0 +1,501 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_bus_logtype; + +/* Forward declaration to access Intel FPGA bus + * on which iFPGA devices are connected + */ +static struct rte_bus rte_ifpga_bus; + +/** Double linked list of IFPGA device. */ +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); + +static struct ifpga_device_list ifpga_device_list = + TAILQ_HEAD_INITIALIZER(ifpga_device_list); +static struct afu_driver_list afu_driver_list = + TAILQ_HEAD_INITIALIZER(afu_driver_list); + + +/* register a ifpga bus based driver */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver) +{ + RTE_VERIFY(driver); + + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); +} + +/* un-register a fpga bus based driver */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) +{ + TAILQ_REMOVE(&afu_driver_list, driver, next); +} + +static struct rte_ifpga_device * +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + if (rdev && + ifpga_dev->rdev && + ifpga_dev->rdev == rdev) + return ifpga_dev; + } + return NULL; +} + +static struct rte_afu_device * +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, + const struct rte_afu_id *afu_id) +{ + struct rte_afu_device *afu_dev = NULL; + + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) + return afu_dev; + } + return NULL; +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static struct rte_afu_device * +ifpga_scan_one(struct rte_devargs *devargs, + struct rte_ifpga_device *ifpga_dev) +{ + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_afu_pr_conf afu_pr_conf; + int ret = 0; + char *path = NULL; + + memset(&afu_pr_conf, 0, sizeof(struct rte_afu_pr_conf)); + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, + &rte_ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, + &rte_ifpga_get_string_arg, &path) < 0) { + IFPGA_BUS_ERR("Failed to parse %s", + IFPGA_AFU_BTS); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_AFU_BTS); + goto end; + } + + afu_pr_conf.afu_id.uuid.uuid_low = 0; + afu_pr_conf.afu_id.uuid.uuid_high = 0; + afu_pr_conf.pr_enable = path?1:0; + + rawdev = ifpga_dev->rdev; + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) + goto end; + + afu_dev = calloc(1, sizeof(*afu_dev)); + if (!afu_dev) + goto end; + + afu_dev->device.devargs = devargs; + afu_dev->device.numa_node = SOCKET_ID_ANY; + afu_dev->device.name = devargs->name; + afu_dev->rawdev = rawdev; + afu_dev->id.uuid.uuid_low = 0; + afu_dev->id.uuid.uuid_high = 0; + afu_dev->id.port = afu_pr_conf.afu_id.port; + afu_dev->ifpga_dev = ifpga_dev; + + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); + + if (rawdev->dev_ops && + rawdev->dev_ops->dev_start && + rawdev->dev_ops->dev_start(rawdev)) + goto free_dev; + + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); + if (rawdev->dev_ops->firmware_load && + rawdev->dev_ops->firmware_load(rawdev, + &afu_pr_conf)){ + IFPGA_BUS_ERR("firmware load error %d\n", ret); + goto free_dev; + } + afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; + afu_dev->id.uuid.uuid_high = afu_pr_conf.afu_id.uuid.uuid_high; + + return afu_dev; + +free_dev: + free(afu_dev); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (path) + free(path); + + return NULL; +} + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static int +ifpga_scan(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + char *name = NULL; + char name1[RTE_RAWDEV_NAME_MAX_LEN]; + struct rte_afu_device *afu_dev = NULL; + + /* for FPGA devices we scan the devargs_list populated via cmdline */ + RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { + if (devargs->bus != &rte_ifpga_bus) + continue; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &rte_ifpga_get_string_arg, &name) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + memset(name1, 0, sizeof(name1)); + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", name); + + rawdev = rte_rawdev_pmd_get_named_dev(name1); + if (!rawdev) + goto end; + + if (ifpga_find_ifpga_dev(rawdev)) + continue; + + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); + if (!ifpga_dev) + goto end; + + ifpga_dev->rdev = rawdev; + TAILQ_INIT(&ifpga_dev->afu_list); + + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); + afu_dev = ifpga_scan_one(devargs, ifpga_dev); + if (afu_dev != NULL) + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, next); + } + +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +/* + * Match the AFU Driver and AFU Device using the ID Table + */ +static int +rte_afu_match(const struct rte_afu_driver *afu_drv, + const struct rte_afu_device *afu_dev) +{ + const struct rte_afu_uuid *id_table; + + for (id_table = afu_drv->id_table; + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); + id_table++) { + /* check if device's identifiers match the driver's ones */ + if ((id_table->uuid_low != afu_dev->id.uuid.uuid_low) || + id_table->uuid_high != + afu_dev->id.uuid.uuid_high) + continue; + + return 1; + } + + return 0; +} + +static int +ifpga_probe_one_driver(struct rte_afu_driver *drv, + struct rte_afu_device *afu_dev) +{ + int ret; + + if (!rte_afu_match(drv, afu_dev)) + /* Match of device and driver failed */ + return 1; + + /* reference driver structure */ + afu_dev->driver = drv; + afu_dev->device.driver = &drv->driver; + + /* call the driver probe() function */ + ret = drv->probe(afu_dev); + if (ret) { + afu_dev->driver = NULL; + afu_dev->device.driver = NULL; + } + + return ret; +} + +static int +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) +{ + struct rte_afu_driver *drv = NULL; + int ret = 0; + + if (afu_dev == NULL) + return -1; + + /* Check if a driver is already loaded */ + if (afu_dev->driver != NULL) + return 0; + + TAILQ_FOREACH(drv, &afu_driver_list, next) { + if (ifpga_probe_one_driver(drv, afu_dev)) { + ret = -1; + break; + } + } + return ret; +} + +/* + * Scan the content of the Intel FPGA bus, and call the probe() function for + * all registered drivers that have a matching entry in its id_table + * for discovered devices. + */ +static int +ifpga_probe(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev = NULL; + int ret = 0; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + + if (afu_dev->device.driver) + continue; + + ret = ifpga_probe_all_drivers(afu_dev); + if (ret < 0) + IFPGA_BUS_ERR("failed to initialize %s device\n", + rte_ifpga_device_name(afu_dev)); + } + } + + return ret; +} + +static int +ifpga_plug(struct rte_device *dev) +{ + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); +} + +static int +ifpga_remove_driver(struct rte_afu_device *afu_dev) +{ + const char *name; + const struct rte_afu_driver *driver; + + name = rte_ifpga_device_name(afu_dev); + if (!afu_dev->device.driver) { + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); + return 1; + } + + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); + return driver->remove(afu_dev); +} + +static int +ifpga_unplug(struct rte_device *dev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_devargs *devargs = NULL; + int ret; + + if (dev == NULL) + return -EINVAL; + + afu_dev = RTE_DEV_TO_AFU(dev); + if (!dev) + return -ENOENT; + + ifpga_dev = afu_dev->ifpga_dev; + devargs = dev->devargs; + + ret = ifpga_remove_driver(afu_dev); + if (ret) + return ret; + + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); + + rte_devargs_remove(devargs->bus->name, devargs->name); + free(afu_dev); + return 0; + +} + +static struct rte_device * +ifpga_find_device(const struct rte_device *start, + rte_dev_cmp_t cmp, const void *data) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (start && &afu_dev->device == start) { + start = NULL; + continue; + } + if (cmp(&afu_dev->device, data) == 0) + return &afu_dev->device; + } + } + return NULL; +} +static int +ifpga_parse(const char *name, void *addr) +{ + int *out = addr; + struct rte_rawdev *rawdev = NULL; + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; + char *c1 = NULL, *c2 = NULL; + int port = IFPGA_BUS_DEV_PORT_MAX; + char str_port[8]; + int str_port_len = 0; + int ret; + + memset(str_port, 0, 8); + c1 = strchr(name, '|'); + if (c1 != NULL) { + str_port_len = c1-name; + c2 = c1+1; + } + + if (str_port_len < 8 && + str_port_len > 0) { + memcpy(str_port, name, str_port_len); + ret = sscanf(str_port, "%d", &port); + if (ret == -1) + return 0; + } + + memset(rawdev_name, 0, sizeof(rawdev_name)); + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", c2); + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev && + (addr != NULL)) + *out = port; + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev) + return 0; + else + return 1; +} + +static struct rte_bus rte_ifpga_bus = { + .scan = ifpga_scan, + .probe = ifpga_probe, + .find_device = ifpga_find_device, + .plug = ifpga_plug, + .unplug = ifpga_unplug, + .parse = ifpga_parse, +}; + +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); + +RTE_INIT(ifpga_init_log) +{ + ifpga_bus_logtype = rte_log_register("bus.ifpga"); + if (ifpga_bus_logtype >= 0) + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); +} diff --git a/drivers/bus/ifpga/ifpga_common.c b/drivers/bus/ifpga/ifpga_common.c new file mode 100644 index 0000000..78e2eae --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int rte_ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(char **)extra_args = strdup(value); + + if (!*(char **)extra_args) + return -ENOMEM; + + return 0; +} +int rte_ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(int *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(uint64_t *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_unsigned_long(const char *str, int base) +{ + unsigned long num; + char *end = NULL; + + errno = 0; + + num = strtoul(str, &end, base); + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) + return -1; + + return num; +} + +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1) +{ + if ((afu_id0->uuid.uuid_low == afu_id1->uuid.uuid_low) && + (afu_id0->uuid.uuid_high == afu_id1->uuid.uuid_high) && + (afu_id0->port == afu_id1->port)) { + return 0; + } else + return 1; +} diff --git a/drivers/bus/ifpga/ifpga_common.h b/drivers/bus/ifpga/ifpga_common.h new file mode 100644 index 0000000..f9254b9 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMMON_H_ +#define _IFPGA_COMMON_H_ + +int rte_ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int rte_ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_unsigned_long(const char *str, int base); +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1); + +#endif /* _IFPGA_COMMON_H_ */ diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index 0000000..873e0a4 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_logs.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_LOGS_H_ +#define _IFPGA_LOGS_H_ + +#include <rte_log.h> + +extern int ifpga_bus_logtype; + +#define IFPGA_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") + +#define IFPGA_BUS_DEBUG(fmt, args...) \ + IFPGA_BUS_LOG(DEBUG, fmt, ## args) +#define IFPGA_BUS_INFO(fmt, args...) \ + IFPGA_BUS_LOG(INFO, fmt, ## args) +#define IFPGA_BUS_ERR(fmt, args...) \ + IFPGA_BUS_LOG(ERR, fmt, ## args) +#define IFPGA_BUS_WARN(fmt, args...) \ + IFPGA_BUS_LOG(WARNING, fmt, ## args) + +#endif /* _IFPGA_BUS_LOGS_H_ */ diff --git a/drivers/bus/ifpga/meson.build b/drivers/bus/ifpga/meson.build new file mode 100644 index 0000000..c9b08c8 --- /dev/null +++ b/drivers/bus/ifpga/meson.build @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2018 Intel Corporation + +deps += ['pci', 'kvargs', 'rawdev'] +install_headers('rte_bus_ifpga.h') +sources = files('ifpga_common.c', 'ifpga_bus.c') + +allow_experimental_apis = true diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h new file mode 100644 index 0000000..5c559e1 --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga.h @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _RTE_BUS_IFPGA_H_ +#define _RTE_BUS_IFPGA_H_ + +/** + * @file + * + * RTE Intel FPGA Bus Interface + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_bus.h> +#include <rte_pci.h> + +/** Name of Intel FPGA Bus */ +#define IFPGA_BUS_NAME ifpga + +/* Forward declarations */ +struct rte_afu_device; + +/** List of Intel AFU devices */ +TAILQ_HEAD(afu_device_list, rte_afu_device); +/** Double linked list of AFU device drivers. */ +TAILQ_HEAD(afu_driver_list, rte_afu_driver); + +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 + +struct rte_afu_uuid { + uint64_t uuid_low; + uint64_t uuid_high; +} __attribute__ ((packed)); + +#define IFPGA_BUS_DEV_PORT_MAX 4 + +/** + * A structure describing an ID for a AFU driver. Each driver provides a + * table of these IDs for each device that it supports. + */ +struct rte_afu_id { + struct rte_afu_uuid uuid; + int port; /**< port number */ +} __attribute__ ((packed)); + +/** + * A structure PR (Partial Reconfiguration) configuration AFU driver. + */ + +struct rte_afu_pr_conf { + struct rte_afu_id afu_id; + int pr_enable; + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +}; + +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) + +/** + * A structure describing a fpga device. + */ +struct rte_ifpga_device { + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ + struct rte_rawdev *rdev; + struct afu_device_list afu_list; /**< List of AFU devices */ +}; + +/** + * A structure describing a AFU device. + */ +struct rte_afu_device { + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ + struct rte_device device; /**< Inherit core device */ + struct rte_rawdev *rawdev; /**< Point Rawdev */ + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ + struct rte_afu_id id; /**< AFU id within FPGA. */ + uint32_t num_region; /**< number of regions found */ + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; + /**< AFU Memory Resource */ + struct rte_intr_handle intr_handle; /**< Interrupt handle */ + struct rte_afu_driver *driver; /**< Associated driver */ + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +} __attribute__ ((packed)); + +/** + * @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_DRV_TO_AFU_CONST(ptr) \ + container_of(ptr, const struct rte_afu_driver, driver) + +/** + * Initialisation function for the driver called during FPGA BUS probing. + */ +typedef int (afu_probe_t)(struct rte_afu_device *); + +/** + * Uninitialisation function for the driver called during hotplugging. + */ +typedef int (afu_remove_t)(struct rte_afu_device *); + +/** + * A structure describing a AFU device. + */ +struct rte_afu_driver { + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ + struct rte_driver driver; /**< Inherit core driver. */ + afu_probe_t *probe; /**< Device Probe function. */ + afu_remove_t *remove; /**< Device Remove function. */ + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ + uint32_t drv_flags; /**< Flags contolling handling of device. */ +}; + +static inline const char * +rte_ifpga_device_name(const struct rte_afu_device *afu) +{ + if (afu && afu->device.name) + return afu->device.name; + return NULL; +} + +/** + * Register a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be registered. + */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver); + +/** + * Unregister a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be unregistered. + */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); + +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ +RTE_INIT(afudrvinitfn_ ##afudrv);\ +static const char *afudrvinit_ ## nm ## _alias;\ +static void afudrvinitfn_ ##afudrv(void)\ +{\ + (afudrv).driver.name = RTE_STR(nm);\ + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ + rte_ifpga_driver_register(&afudrv);\ +} \ +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) + +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ +static const char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) + +#endif /* _RTE_BUS_IFPGA_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map new file mode 100644 index 0000000..a027979 --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map @@ -0,0 +1,10 @@ +DPDK_18.05 { + global: + + rte_ifpga_get_integer32_arg; + rte_ifpga_get_string_arg; + rte_ifpga_driver_register; + rte_ifpga_driver_unregister; + + local: *; +}; diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build index 58dfbe2..52c755d 100644 --- a/drivers/bus/meson.build +++ b/drivers/bus/meson.build @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel Corporation -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] +drivers = ['dpaa', 'fslmc', 'ifpga', 'pci', 'vdev'] std_deps = ['eal'] config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' driver_name_fmt = 'rte_bus_@0@' diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 26f3563..3861e1a 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -255,6 +255,7 @@ ifeq ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += -lrte_pmd_dpaa2_cmdif _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += -lrte_pmd_dpaa2_qdma endif # CONFIG_RTE_LIBRTE_FSLMC_BUS +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga endif # CONFIG_RTE_LIBRTE_RAWDEV -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen @ 2018-05-10 8:43 ` Wu, Jingjing 2018-05-10 12:20 ` Xu, Rosen 2018-05-10 12:26 ` Zhang, Qi Z 1 sibling, 1 reply; 149+ messages in thread From: Wu, Jingjing @ 2018-05-10 8:43 UTC (permalink / raw) To: Xu, Rosen, dev, thomas Cc: Xu, Rosen, Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet Hi, Rosen Few comments below. Thanks Jingjing [......] > +static struct rte_ifpga_device * > +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) > +{ > + struct rte_ifpga_device *ifpga_dev = NULL; > + > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > + if (rdev && rdev -> ifpage_dev ?? > + ifpga_dev->rdev && > + ifpga_dev->rdev == rdev) > + return ifpga_dev; > + } > + return NULL; > +} > + > +static struct rte_afu_device * > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > + const struct rte_afu_id *afu_id) > +{ > + struct rte_afu_device *afu_dev = NULL; > + > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) Add checking afu_dev? [...] > +static int > +ifpga_parse(const char *name, void *addr) > +{ > + int *out = addr; > + struct rte_rawdev *rawdev = NULL; > + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; > + char *c1 = NULL, *c2 = NULL; According to coding style, we need to two lines for the definition like: char *c1 = NULL; char *c2 = NULL; > + int port = IFPGA_BUS_DEV_PORT_MAX; > + char str_port[8]; > + int str_port_len = 0; > + int ret; > + > + memset(str_port, 0, 8); > + c1 = strchr(name, '|'); > + if (c1 != NULL) { > + str_port_len = c1-name; According to coding style, spaces are required around opreations. > + c2 = c1+1; > + } ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-10 8:43 ` Wu, Jingjing @ 2018-05-10 12:20 ` Xu, Rosen 2018-05-10 22:39 ` Wu, Jingjing 0 siblings, 1 reply; 149+ messages in thread From: Xu, Rosen @ 2018-05-10 12:20 UTC (permalink / raw) To: Wu, Jingjing, dev, thomas Cc: Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet Hi Jingjing, > -----Original Message----- > From: Wu, Jingjing > Sent: Thursday, May 10, 2018 16:44 > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; thomas@monjalon.net > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > Library > > Hi, Rosen > > Few comments below. Thanks a lot Jingjing. > > Thanks > Jingjing > > [......] > > +static struct rte_ifpga_device * > > +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) { > > + struct rte_ifpga_device *ifpga_dev = NULL; > > + > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > + if (rdev && > rdev -> ifpage_dev ?? Rdev doesn't has this variable. > > + ifpga_dev->rdev && > > + ifpga_dev->rdev == rdev) > > + return ifpga_dev; > > + } > > + return NULL; > > +} > > + > > +static struct rte_afu_device * > > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > > + const struct rte_afu_id *afu_id) > > +{ > > + struct rte_afu_device *afu_dev = NULL; > > + > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > Add checking afu_dev? Fixed. > [...] > > > +static int > > +ifpga_parse(const char *name, void *addr) { > > + int *out = addr; > > + struct rte_rawdev *rawdev = NULL; > > + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; > > + char *c1 = NULL, *c2 = NULL; > According to coding style, we need to two lines for the definition like: > char *c1 = NULL; > char *c2 = NULL; Fixed > > + int port = IFPGA_BUS_DEV_PORT_MAX; > > + char str_port[8]; > > + int str_port_len = 0; > > + int ret; > > + > > + memset(str_port, 0, 8); > > + c1 = strchr(name, '|'); > > + if (c1 != NULL) { > > + str_port_len = c1-name; > According to coding style, spaces are required around opreations. Fixed. > > + c2 = c1+1; > > + } ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-10 12:20 ` Xu, Rosen @ 2018-05-10 22:39 ` Wu, Jingjing 2018-05-11 3:18 ` Xu, Rosen 0 siblings, 1 reply; 149+ messages in thread From: Wu, Jingjing @ 2018-05-10 22:39 UTC (permalink / raw) To: Xu, Rosen, dev, thomas Cc: Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet > -----Original Message----- > From: Xu, Rosen > Sent: Thursday, May 10, 2018 8:21 PM > To: Wu, Jingjing <jingjing.wu@intel.com>; dev@dpdk.org; thomas@monjalon.net > Cc: Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, Declan > <declan.doherty@intel.com>; Richardson, Bruce <bruce.richardson@intel.com>; > shreyansh.jain@nxp.com; Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; Liu, Song > <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; gaetan.rivet@6wind.com > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library > > Hi Jingjing, > > > -----Original Message----- > > From: Wu, Jingjing > > Sent: Thursday, May 10, 2018 16:44 > > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; thomas@monjalon.net > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > > gaetan.rivet@6wind.com > > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > > Library > > > > Hi, Rosen > > > > Few comments below. > > Thanks a lot Jingjing. > > > > > Thanks > > Jingjing > > > > [......] > > > +static struct rte_ifpga_device * > > > +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) { > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > + > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > + if (rdev && > > rdev -> ifpage_dev ?? > > Rdev doesn't has this variable. I mean "if (ifpag_dev" & to replace "rdev" > > > > + ifpga_dev->rdev && > > > + ifpga_dev->rdev == rdev) > > > + return ifpga_dev; > > > + } > > > + return NULL; > > > +} > > > + > > > +static struct rte_afu_device * > > > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > > > + const struct rte_afu_id *afu_id) > > > +{ > > > + struct rte_afu_device *afu_dev = NULL; > > > + > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > > Add checking afu_dev? > > Fixed. > > > [...] > > > > > +static int > > > +ifpga_parse(const char *name, void *addr) { > > > + int *out = addr; > > > + struct rte_rawdev *rawdev = NULL; > > > + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; > > > + char *c1 = NULL, *c2 = NULL; > > According to coding style, we need to two lines for the definition like: > > char *c1 = NULL; > > char *c2 = NULL; > > Fixed > > > > + int port = IFPGA_BUS_DEV_PORT_MAX; > > > + char str_port[8]; > > > + int str_port_len = 0; > > > + int ret; > > > + > > > + memset(str_port, 0, 8); > > > + c1 = strchr(name, '|'); > > > + if (c1 != NULL) { > > > + str_port_len = c1-name; > > According to coding style, spaces are required around opreations. > > Fixed. > > > > + c2 = c1+1; > > > + } ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-10 22:39 ` Wu, Jingjing @ 2018-05-11 3:18 ` Xu, Rosen 0 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-11 3:18 UTC (permalink / raw) To: Wu, Jingjing, dev, thomas Cc: Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet Hi Jingjing, > -----Original Message----- > From: Wu, Jingjing > Sent: Friday, May 11, 2018 6:40 > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; thomas@monjalon.net > Cc: Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, Declan > <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > Library > > > > > -----Original Message----- > > From: Xu, Rosen > > Sent: Thursday, May 10, 2018 8:21 PM > > To: Wu, Jingjing <jingjing.wu@intel.com>; dev@dpdk.org; > > thomas@monjalon.net > > Cc: Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, Declan > > <declan.doherty@intel.com>; Richardson, Bruce > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > > <ferruh.yigit@intel.com>; Ananyev, Konstantin > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > > Library > > > > Hi Jingjing, > > > > > -----Original Message----- > > > From: Wu, Jingjing > > > Sent: Thursday, May 10, 2018 16:44 > > > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; > > > thomas@monjalon.net > > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > > <roy.fan.zhang@intel.com>; Doherty, Declan > > > <declan.doherty@intel.com>; Richardson, Bruce > > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > > > <ferruh.yigit@intel.com>; Ananyev, Konstantin > > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA > > > BUS Library > > > > > > Hi, Rosen > > > > > > Few comments below. > > > > Thanks a lot Jingjing. > > > > > > > > Thanks > > > Jingjing > > > > > > [......] > > > > +static struct rte_ifpga_device * > > > > +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) { > > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > > + > > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > > + if (rdev && > > > rdev -> ifpage_dev ?? > > > > Rdev doesn't has this variable. > I mean "if (ifpag_dev" & to replace "rdev" I will fixed it in patch v12. > > > > > > + ifpga_dev->rdev && > > > > + ifpga_dev->rdev == rdev) > > > > + return ifpga_dev; > > > > + } > > > > + return NULL; > > > > +} > > > > + > > > > +static struct rte_afu_device * > > > > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > > > > + const struct rte_afu_id *afu_id) { > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + > > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > > > Add checking afu_dev? > > > > Fixed. > > > > > [...] > > > > > > > +static int > > > > +ifpga_parse(const char *name, void *addr) { > > > > + int *out = addr; > > > > + struct rte_rawdev *rawdev = NULL; > > > > + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; > > > > + char *c1 = NULL, *c2 = NULL; > > > According to coding style, we need to two lines for the definition like: > > > char *c1 = NULL; > > > char *c2 = NULL; > > > > Fixed > > > > > > + int port = IFPGA_BUS_DEV_PORT_MAX; > > > > + char str_port[8]; > > > > + int str_port_len = 0; > > > > + int ret; > > > > + > > > > + memset(str_port, 0, 8); > > > > + c1 = strchr(name, '|'); > > > > + if (c1 != NULL) { > > > > + str_port_len = c1-name; > > > According to coding style, spaces are required around opreations. > > > > Fixed. > > > > > > + c2 = c1+1; > > > > + } ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen 2018-05-10 8:43 ` Wu, Jingjing @ 2018-05-10 12:26 ` Zhang, Qi Z 2018-05-10 13:29 ` Xu, Rosen 1 sibling, 1 reply; 149+ messages in thread From: Zhang, Qi Z @ 2018-05-10 12:26 UTC (permalink / raw) To: Xu, Rosen, dev, thomas Cc: Xu, Rosen, Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet Hi Rosen: > -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > Sent: Wednesday, May 9, 2018 3:43 PM > To: dev@dpdk.org; thomas@monjalon.net > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library > > From: Rosen Xu <rosen.xu@intel.com> > > Defined FPGA-BUS for Acceleration Drivers of AFUs > > 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe > Intel FPGA Rawdev Driver, it will be covered in following patches. > > 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. > This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs > will be created and their drivers are also probed. > > This patch will introduce rte_afu_device which describe the AFU device listed in > the FPGA-BUS. > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > --- > MAINTAINERS | 4 + > config/common_base | 5 + > doc/guides/rel_notes/release_18_05.rst | 5 + > drivers/bus/Makefile | 1 + > drivers/bus/ifpga/Makefile | 32 ++ > drivers/bus/ifpga/ifpga_bus.c | 501 > ++++++++++++++++++++++++++++ > drivers/bus/ifpga/ifpga_common.c | 88 +++++ > drivers/bus/ifpga/ifpga_common.h | 18 + > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > drivers/bus/ifpga/meson.build | 8 + > drivers/bus/ifpga/rte_bus_ifpga.h | 160 +++++++++ > drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + > drivers/bus/meson.build | 2 +- > mk/rte.app.mk | 1 + > 14 files changed, 865 insertions(+), 1 deletion(-) create mode 100644 > drivers/bus/ifpga/Makefile create mode 100644 > drivers/bus/ifpga/ifpga_bus.c create mode 100644 > drivers/bus/ifpga/ifpga_common.c create mode 100644 > drivers/bus/ifpga/ifpga_common.h create mode 100644 > drivers/bus/ifpga/ifpga_logs.h create mode 100644 > drivers/bus/ifpga/meson.build create mode 100644 > drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 > drivers/bus/ifpga/rte_bus_ifpga_version.map > > diff --git a/MAINTAINERS b/MAINTAINERS > index 7105920..fa0c5b1 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -383,6 +383,10 @@ F: drivers/mempool/bucket/ Bus Drivers > ----------- > > +Intel FPGA buses > +M: Rosen Xu <rosen.xu@intel.com> > +F: drivers/bus/ifpga/ > + > NXP buses > M: Hemant Agrawal <hemant.agrawal@nxp.com> > M: Shreyansh Jain <shreyansh.jain@nxp.com> diff --git > a/config/common_base b/config/common_base index 0d181ac..1440316 > 100644 > --- a/config/common_base > +++ b/config/common_base > @@ -139,6 +139,11 @@ > CONFIG_RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS=n > CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n > > # > +# Compile the Intel FPGA bus > +# > +CONFIG_RTE_LIBRTE_IFPGA_BUS=y > + > +# > # Compile PCI bus driver > # > CONFIG_RTE_LIBRTE_PCI_BUS=y > diff --git a/doc/guides/rel_notes/release_18_05.rst > b/doc/guides/rel_notes/release_18_05.rst > index 7187348..265950a 100644 > --- a/doc/guides/rel_notes/release_18_05.rst > +++ b/doc/guides/rel_notes/release_18_05.rst > @@ -183,6 +183,11 @@ New Features > stats/xstats on shared memory from secondary process, and also pdump > packets on > those virtual devices. > > +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** > + > + The Ifpga Bus library provides support for integrating any Intel FPGA > + device with the DPDK framework. It provides Intel FPGA Partial Bit > + Stream AFU(Accelerated Function Unit) scan and drivers prove. > > API Changes > ----------- > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index > c251b65..ef7f247 100644 > --- a/drivers/bus/Makefile > +++ b/drivers/bus/Makefile > @@ -7,6 +7,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa ifeq > ($(CONFIG_RTE_EAL_VFIO),y) > DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc endif > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > > diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile new file > mode 100644 index 0000000..3ff3bdb > --- /dev/null > +++ b/drivers/bus/ifpga/Makefile > @@ -0,0 +1,32 @@ > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > +Corporation > + > +include $(RTE_SDK)/mk/rte.vars.mk > + > +# > +# library name > +# > +LIB = librte_bus_ifpga.a > + > +CFLAGS += -DALLOW_EXPERIMENTAL_API > +CFLAGS += -O3 > +CFLAGS += $(WERROR_FLAGS) > +LDLIBS += -lrte_eal > +LDLIBS += -lrte_rawdev > +LDLIBS += -lrte_kvargs > + > +# versioning export map > +EXPORT_MAP := rte_bus_ifpga_version.map > + > +# library version > +LIBABIVER := 1 > + > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c > + > +# > +# Export include files > +# > +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h > + > +include $(RTE_SDK)/mk/rte.lib.mk > diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c new > file mode 100644 index 0000000..e144c01 > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_bus.c > @@ -0,0 +1,501 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation */ > + > +#include <string.h> > +#include <inttypes.h> > +#include <stdint.h> > +#include <stdlib.h> > +#include <stdio.h> > +#include <sys/queue.h> > +#include <sys/mman.h> > +#include <sys/types.h> > +#include <unistd.h> > +#include <fcntl.h> > + > +#include <rte_errno.h> > +#include <rte_bus.h> > +#include <rte_per_lcore.h> > +#include <rte_memory.h> > +#include <rte_memzone.h> > +#include <rte_eal.h> > +#include <rte_common.h> > + > +#include <rte_devargs.h> > +#include <rte_kvargs.h> > +#include <rte_alarm.h> > + > +#include "rte_rawdev.h" > +#include "rte_rawdev_pmd.h" > +#include "rte_bus_ifpga.h" > +#include "ifpga_logs.h" > +#include "ifpga_common.h" > + > +int ifpga_bus_logtype; > + > +/* Forward declaration to access Intel FPGA bus > + * on which iFPGA devices are connected */ static struct rte_bus > +rte_ifpga_bus; > + > +/** Double linked list of IFPGA device. */ > +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); > + > +static struct ifpga_device_list ifpga_device_list = > + TAILQ_HEAD_INITIALIZER(ifpga_device_list); > +static struct afu_driver_list afu_driver_list = > + TAILQ_HEAD_INITIALIZER(afu_driver_list); > + > + > +/* register a ifpga bus based driver */ void > +rte_ifpga_driver_register(struct rte_afu_driver *driver) { > + RTE_VERIFY(driver); > + > + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); } > + > +/* un-register a fpga bus based driver */ void > +rte_ifpga_driver_unregister(struct rte_afu_driver *driver) { > + TAILQ_REMOVE(&afu_driver_list, driver, next); } > + > +static struct rte_ifpga_device * > +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) { > + struct rte_ifpga_device *ifpga_dev = NULL; > + > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > + if (rdev && > + ifpga_dev->rdev && > + ifpga_dev->rdev == rdev) > + return ifpga_dev; > + } > + return NULL; > +} > + > +static struct rte_afu_device * > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > + const struct rte_afu_id *afu_id) > +{ > + struct rte_afu_device *afu_dev = NULL; > + > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > + return afu_dev; > + } > + return NULL; > +} > + > +static const char * const valid_args[] = { > +#define IFPGA_ARG_NAME "ifpga" > + IFPGA_ARG_NAME, > +#define IFPGA_ARG_PORT "port" > + IFPGA_ARG_PORT, > +#define IFPGA_AFU_BTS "afu_bts" > + IFPGA_AFU_BTS, > + NULL > +}; > + > +/* > + * Scan the content of the FPGA bus, and the devices in the devices > + * list > + */ > +static struct rte_afu_device * > +ifpga_scan_one(struct rte_devargs *devargs, > + struct rte_ifpga_device *ifpga_dev) usually ifpag_dev should be the first parameter here, and devargs follows > +{ > + struct rte_kvargs *kvlist = NULL; > + struct rte_rawdev *rawdev = NULL; > + struct rte_afu_device *afu_dev = NULL; > + struct rte_afu_pr_conf afu_pr_conf; > + int ret = 0; > + char *path = NULL; > + > + memset(&afu_pr_conf, 0, sizeof(struct rte_afu_pr_conf)); > + > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > + if (!kvlist) { > + IFPGA_BUS_ERR("error when parsing param"); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, > + &rte_ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { > + IFPGA_BUS_ERR("error to parse %s", > + IFPGA_ARG_PORT); > + goto end; > + } > + } else { > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_ARG_PORT); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, > + &rte_ifpga_get_string_arg, &path) < 0) { > + IFPGA_BUS_ERR("Failed to parse %s", > + IFPGA_AFU_BTS); > + goto end; > + } > + } else { > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_AFU_BTS); > + goto end; > + } > + > + afu_pr_conf.afu_id.uuid.uuid_low = 0; > + afu_pr_conf.afu_id.uuid.uuid_high = 0; > + afu_pr_conf.pr_enable = path?1:0; > + > + rawdev = ifpga_dev->rdev; > + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) > + goto end; > + > + afu_dev = calloc(1, sizeof(*afu_dev)); > + if (!afu_dev) > + goto end; > + > + afu_dev->device.devargs = devargs; > + afu_dev->device.numa_node = SOCKET_ID_ANY; > + afu_dev->device.name = devargs->name; > + afu_dev->rawdev = rawdev; > + afu_dev->id.uuid.uuid_low = 0; > + afu_dev->id.uuid.uuid_high = 0; > + afu_dev->id.port = afu_pr_conf.afu_id.port; > + afu_dev->ifpga_dev = ifpga_dev; > + > + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) > + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); > + > + if (rawdev->dev_ops && > + rawdev->dev_ops->dev_start && > + rawdev->dev_ops->dev_start(rawdev)) > + goto free_dev; > + > + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); > + if (rawdev->dev_ops->firmware_load && > + rawdev->dev_ops->firmware_load(rawdev, > + &afu_pr_conf)){ > + IFPGA_BUS_ERR("firmware load error %d\n", ret); > + goto free_dev; > + } > + afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; > + afu_dev->id.uuid.uuid_high = afu_pr_conf.afu_id.uuid.uuid_high; > + > + return afu_dev; > + > +free_dev: > + free(afu_dev); > +end: > + if (kvlist) > + rte_kvargs_free(kvlist); > + if (path) > + free(path); > + > + return NULL; > +} > + > +/* > + * Scan the content of the FPGA bus, and the devices in the devices > + * list > + */ > +static int > +ifpga_scan(void) > +{ > + struct rte_ifpga_device *ifpga_dev; > + struct rte_devargs *devargs; > + struct rte_kvargs *kvlist = NULL; > + struct rte_rawdev *rawdev = NULL; > + char *name = NULL; > + char name1[RTE_RAWDEV_NAME_MAX_LEN]; > + struct rte_afu_device *afu_dev = NULL; > + > + /* for FPGA devices we scan the devargs_list populated via cmdline */ I didn't see "--ifpga" is supported by cmdline, either you need to add corresponding parser or correct the comment here. > + RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { IFPGA_BUS_NAME to replace "ifpga" here. > + if (devargs->bus != &rte_ifpga_bus) > + continue; > + > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > + if (!kvlist) { > + IFPGA_BUS_ERR("error when parsing param"); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, > + &rte_ifpga_get_string_arg, &name) < 0) { > + IFPGA_BUS_ERR("error to parse %s", > + IFPGA_ARG_NAME); > + goto end; > + } > + } else { > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_ARG_NAME); > + goto end; > + } > + > + memset(name1, 0, sizeof(name1)); > + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", > name); > + > + rawdev = rte_rawdev_pmd_get_named_dev(name1); > + if (!rawdev) > + goto end; > + > + if (ifpga_find_ifpga_dev(rawdev)) > + continue; > + > + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); > + if (!ifpga_dev) > + goto end; > + > + ifpga_dev->rdev = rawdev; > + TAILQ_INIT(&ifpga_dev->afu_list); > + > + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); > + afu_dev = ifpga_scan_one(devargs, ifpga_dev); > + if (afu_dev != NULL) > + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, next); I don't understand why we need afu_list?, seems we only add a new afu_dev into the list after create a new ifpga_dev, Is there any another place that we add one to list to make it reasonable? it looks like either a 1:1 or 1:0 for ifpga_dev:afu_dev? > + } > + > +end: > + if (kvlist) > + rte_kvargs_free(kvlist); > + if (name) > + free(name); > + > + return 0; > +} > + > +/* > + * Match the AFU Driver and AFU Device using the ID Table */ static > +int rte_afu_match(const struct rte_afu_driver *afu_drv, > + const struct rte_afu_device *afu_dev) { > + const struct rte_afu_uuid *id_table; > + > + for (id_table = afu_drv->id_table; > + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); > + id_table++) { > + /* check if device's identifiers match the driver's ones */ > + if ((id_table->uuid_low != afu_dev->id.uuid.uuid_low) || > + id_table->uuid_high != > + afu_dev->id.uuid.uuid_high) > + continue; > + > + return 1; > + } > + > + return 0; > +} > + > +static int > +ifpga_probe_one_driver(struct rte_afu_driver *drv, > + struct rte_afu_device *afu_dev) > +{ > + int ret; > + > + if (!rte_afu_match(drv, afu_dev)) > + /* Match of device and driver failed */ > + return 1; > + > + /* reference driver structure */ > + afu_dev->driver = drv; > + afu_dev->device.driver = &drv->driver; > + > + /* call the driver probe() function */ > + ret = drv->probe(afu_dev); > + if (ret) { > + afu_dev->driver = NULL; > + afu_dev->device.driver = NULL; > + } > + > + return ret; > +} > + > +static int > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) { > + struct rte_afu_driver *drv = NULL; > + int ret = 0; > + > + if (afu_dev == NULL) > + return -1; > + > + /* Check if a driver is already loaded */ > + if (afu_dev->driver != NULL) > + return 0; > + > + TAILQ_FOREACH(drv, &afu_driver_list, next) { > + if (ifpga_probe_one_driver(drv, afu_dev)) { > + ret = -1; > + break; > + } > + } > + return ret; > +} > + > +/* > + * Scan the content of the Intel FPGA bus, and call the probe() > +function for > + * all registered drivers that have a matching entry in its id_table > + * for discovered devices. > + */ > +static int > +ifpga_probe(void) > +{ > + struct rte_ifpga_device *ifpga_dev; > + struct rte_afu_device *afu_dev = NULL; > + int ret = 0; > + > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > + > + if (afu_dev->device.driver) > + continue; > + > + ret = ifpga_probe_all_drivers(afu_dev); > + if (ret < 0) > + IFPGA_BUS_ERR("failed to initialize %s device\n", > + rte_ifpga_device_name(afu_dev)); > + } > + } > + > + return ret; > +} > + > +static int > +ifpga_plug(struct rte_device *dev) > +{ > + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); > +} > + > +static int > +ifpga_remove_driver(struct rte_afu_device *afu_dev) { > + const char *name; > + const struct rte_afu_driver *driver; > + > + name = rte_ifpga_device_name(afu_dev); > + if (!afu_dev->device.driver) { > + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); > + return 1; > + } > + > + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); > + return driver->remove(afu_dev); > +} > + > +static int > +ifpga_unplug(struct rte_device *dev) > +{ > + struct rte_ifpga_device *ifpga_dev = NULL; > + struct rte_afu_device *afu_dev = NULL; > + struct rte_devargs *devargs = NULL; > + int ret; > + > + if (dev == NULL) > + return -EINVAL; > + > + afu_dev = RTE_DEV_TO_AFU(dev); > + if (!dev) > + return -ENOENT; > + > + ifpga_dev = afu_dev->ifpga_dev; > + devargs = dev->devargs; > + > + ret = ifpga_remove_driver(afu_dev); So what is the device type that be plugged into the ifgpa bus? ifpga_dev or afu_dev? If its afu_dev, why we need ifpga_dev? If it is ifpga_dev, we need remove ifpga_dev from ifpga_device_list here. > + if (ret) > + return ret; > + > + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); > + > + rte_devargs_remove(devargs->bus->name, devargs->name); > + free(afu_dev); > + return 0; > + > +} > + > +static struct rte_device * > +ifpga_find_device(const struct rte_device *start, > + rte_dev_cmp_t cmp, const void *data) > +{ > + struct rte_ifpga_device *ifpga_dev; > + struct rte_afu_device *afu_dev; > + > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > + if (start && &afu_dev->device == start) { > + start = NULL; > + continue; > + } > + if (cmp(&afu_dev->device, data) == 0) > + return &afu_dev->device; > + } > + } > + return NULL; > +} > +static int > +ifpga_parse(const char *name, void *addr) { > + int *out = addr; > + struct rte_rawdev *rawdev = NULL; > + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; > + char *c1 = NULL, *c2 = NULL; > + int port = IFPGA_BUS_DEV_PORT_MAX; > + char str_port[8]; > + int str_port_len = 0; > + int ret; > + > + memset(str_port, 0, 8); > + c1 = strchr(name, '|'); > + if (c1 != NULL) { > + str_port_len = c1-name; > + c2 = c1+1; > + } > + > + if (str_port_len < 8 && > + str_port_len > 0) { > + memcpy(str_port, name, str_port_len); > + ret = sscanf(str_port, "%d", &port); > + if (ret == -1) > + return 0; > + } > + > + memset(rawdev_name, 0, sizeof(rawdev_name)); > + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", c2); > + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); > + > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > + rawdev && > + (addr != NULL)) > + *out = port; > + > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > + rawdev) > + return 0; > + else > + return 1; > +} > + > +static struct rte_bus rte_ifpga_bus = { > + .scan = ifpga_scan, > + .probe = ifpga_probe, > + .find_device = ifpga_find_device, > + .plug = ifpga_plug, > + .unplug = ifpga_unplug, > + .parse = ifpga_parse, > +}; > + > +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); > + > +RTE_INIT(ifpga_init_log) > +{ > + ifpga_bus_logtype = rte_log_register("bus.ifpga"); > + if (ifpga_bus_logtype >= 0) > + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); } > diff --git a/drivers/bus/ifpga/ifpga_common.c > b/drivers/bus/ifpga/ifpga_common.c > new file mode 100644 > index 0000000..78e2eae > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_common.c > @@ -0,0 +1,88 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation */ > + > +#include <string.h> > +#include <inttypes.h> > +#include <stdint.h> > +#include <stdlib.h> > +#include <stdio.h> > +#include <sys/queue.h> > +#include <sys/mman.h> > +#include <sys/types.h> > +#include <unistd.h> > +#include <fcntl.h> > + > +#include <rte_errno.h> > +#include <rte_bus.h> > +#include <rte_per_lcore.h> > +#include <rte_memory.h> > +#include <rte_memzone.h> > +#include <rte_eal.h> > +#include <rte_common.h> > + > +#include <rte_devargs.h> > +#include <rte_kvargs.h> > +#include <rte_alarm.h> > + > +#include "rte_bus_ifpga.h" > +#include "ifpga_logs.h" > +#include "ifpga_common.h" > + > +int rte_ifpga_get_string_arg(const char *key __rte_unused, > + const char *value, void *extra_args) > +{ > + if (!value || !extra_args) > + return -EINVAL; > + > + *(char **)extra_args = strdup(value); > + > + if (!*(char **)extra_args) > + return -ENOMEM; > + > + return 0; > +} > +int rte_ifpga_get_integer32_arg(const char *key __rte_unused, > + const char *value, void *extra_args) > +{ > + if (!value || !extra_args) > + return -EINVAL; > + > + *(int *)extra_args = strtoull(value, NULL, 0); > + > + return 0; > +} > +int ifpga_get_integer64_arg(const char *key __rte_unused, > + const char *value, void *extra_args) > +{ > + if (!value || !extra_args) > + return -EINVAL; > + > + *(uint64_t *)extra_args = strtoull(value, NULL, 0); > + > + return 0; > +} > +int ifpga_get_unsigned_long(const char *str, int base) { > + unsigned long num; > + char *end = NULL; > + > + errno = 0; > + > + num = strtoul(str, &end, base); > + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) > + return -1; > + > + return num; > +} > + > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > + const struct rte_afu_id *afu_id1) > +{ > + if ((afu_id0->uuid.uuid_low == afu_id1->uuid.uuid_low) && > + (afu_id0->uuid.uuid_high == afu_id1->uuid.uuid_high) && > + (afu_id0->port == afu_id1->port)) { > + return 0; > + } else > + return 1; > +} > diff --git a/drivers/bus/ifpga/ifpga_common.h > b/drivers/bus/ifpga/ifpga_common.h > new file mode 100644 > index 0000000..f9254b9 > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_common.h > @@ -0,0 +1,18 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation */ > + > +#ifndef _IFPGA_COMMON_H_ > +#define _IFPGA_COMMON_H_ > + > +int rte_ifpga_get_string_arg(const char *key __rte_unused, > + const char *value, void *extra_args); > +int rte_ifpga_get_integer32_arg(const char *key __rte_unused, > + const char *value, void *extra_args); > +int ifpga_get_integer64_arg(const char *key __rte_unused, > + const char *value, void *extra_args); > +int ifpga_get_unsigned_long(const char *str, int base); int > +ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > + const struct rte_afu_id *afu_id1); > + > +#endif /* _IFPGA_COMMON_H_ */ > diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h > new file mode 100644 index 0000000..873e0a4 > --- /dev/null > +++ b/drivers/bus/ifpga/ifpga_logs.h > @@ -0,0 +1,31 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation */ > + > +#ifndef _IFPGA_LOGS_H_ > +#define _IFPGA_LOGS_H_ > + > +#include <rte_log.h> > + > +extern int ifpga_bus_logtype; > + > +#define IFPGA_LOG(level, fmt, args...) \ > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > + __func__, ##args) > + > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > + __func__, ##args) > + > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > + > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) > +#define IFPGA_BUS_INFO(fmt, args...) \ > + IFPGA_BUS_LOG(INFO, fmt, ## args) > +#define IFPGA_BUS_ERR(fmt, args...) \ > + IFPGA_BUS_LOG(ERR, fmt, ## args) > +#define IFPGA_BUS_WARN(fmt, args...) \ > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > + > +#endif /* _IFPGA_BUS_LOGS_H_ */ > diff --git a/drivers/bus/ifpga/meson.build b/drivers/bus/ifpga/meson.build > new file mode 100644 index 0000000..c9b08c8 > --- /dev/null > +++ b/drivers/bus/ifpga/meson.build > @@ -0,0 +1,8 @@ > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2010-2018 Intel > +Corporation > + > +deps += ['pci', 'kvargs', 'rawdev'] > +install_headers('rte_bus_ifpga.h') > +sources = files('ifpga_common.c', 'ifpga_bus.c') > + > +allow_experimental_apis = true > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h > b/drivers/bus/ifpga/rte_bus_ifpga.h > new file mode 100644 > index 0000000..5c559e1 > --- /dev/null > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > @@ -0,0 +1,160 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation */ > + > +#ifndef _RTE_BUS_IFPGA_H_ > +#define _RTE_BUS_IFPGA_H_ > + > +/** > + * @file > + * > + * RTE Intel FPGA Bus Interface > + */ > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#include <rte_bus.h> > +#include <rte_pci.h> > + > +/** Name of Intel FPGA Bus */ > +#define IFPGA_BUS_NAME ifpga > + > +/* Forward declarations */ > +struct rte_afu_device; > + > +/** List of Intel AFU devices */ > +TAILQ_HEAD(afu_device_list, rte_afu_device); > +/** Double linked list of AFU device drivers. */ > +TAILQ_HEAD(afu_driver_list, rte_afu_driver); > + > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > + > +struct rte_afu_uuid { > + uint64_t uuid_low; > + uint64_t uuid_high; > +} __attribute__ ((packed)); > + > +#define IFPGA_BUS_DEV_PORT_MAX 4 > + > +/** > + * A structure describing an ID for a AFU driver. Each driver provides > +a > + * table of these IDs for each device that it supports. > + */ > +struct rte_afu_id { > + struct rte_afu_uuid uuid; > + int port; /**< port number */ > +} __attribute__ ((packed)); > + > +/** > + * A structure PR (Partial Reconfiguration) configuration AFU driver. > + */ > + > +struct rte_afu_pr_conf { > + struct rte_afu_id afu_id; > + int pr_enable; > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > +}; > + > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > + > +/** > + * A structure describing a fpga device. > + */ > +struct rte_ifpga_device { > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ > + struct rte_rawdev *rdev; > + struct afu_device_list afu_list; /**< List of AFU devices */ }; > + > +/** > + * A structure describing a AFU device. > + */ > +struct rte_afu_device { > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ > + struct rte_device device; /**< Inherit core device */ > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > + struct rte_afu_id id; /**< AFU id within FPGA. */ > + uint32_t num_region; /**< number of regions found */ > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > + /**< AFU Memory Resource */ > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > + struct rte_afu_driver *driver; /**< Associated driver */ > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > +} __attribute__ ((packed)); > + > +/** > + * @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_DRV_TO_AFU_CONST(ptr) \ > + container_of(ptr, const struct rte_afu_driver, driver) > + > +/** > + * Initialisation function for the driver called during FPGA BUS probing. typo: Initialization > + */ > +typedef int (afu_probe_t)(struct rte_afu_device *); > + > +/** > + * Uninitialisation function for the driver called during hotplugging. typo: Unintialization > + */ > +typedef int (afu_remove_t)(struct rte_afu_device *); > + > +/** > + * A structure describing a AFU device. > + */ > +struct rte_afu_driver { > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > + struct rte_driver driver; /**< Inherit core driver. */ > + afu_probe_t *probe; /**< Device Probe function. > */ > + afu_remove_t *remove; /**< Device Remove > function. */ > + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ > + uint32_t drv_flags; /**< Flags contolling handling of device. */ Typo Controlling And what is "flags controlling handling of device?" > +}; > + > +static inline const char * > +rte_ifpga_device_name(const struct rte_afu_device *afu) { > + if (afu && afu->device.name) > + return afu->device.name; > + return NULL; > +} > + > +/** > + * Register a ifpga afu device driver. > + * > + * @param driver > + * A pointer to a rte_afu_driver structure describing the driver > + * to be registered. > + */ > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); > + > +/** > + * Unregister a ifpga afu device driver. > + * > + * @param driver > + * A pointer to a rte_afu_driver structure describing the driver > + * to be unregistered. > + */ > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > + > +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ RTE_INIT(afudrvinitfn_ > +##afudrv);\ static const char *afudrvinit_ ## nm ## _alias;\ static > +void afudrvinitfn_ ##afudrv(void)\ {\ > + (afudrv).driver.name = RTE_STR(nm);\ > + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ > + rte_ifpga_driver_register(&afudrv);\ > +} \ > +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) > + > +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ static const char > +*afudrvinit_ ## nm ## _alias = RTE_STR(alias) > + > +#endif /* _RTE_BUS_IFPGA_H_ */ > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map > b/drivers/bus/ifpga/rte_bus_ifpga_version.map > new file mode 100644 > index 0000000..a027979 > --- /dev/null > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > @@ -0,0 +1,10 @@ > +DPDK_18.05 { > + global: > + > + rte_ifpga_get_integer32_arg; > + rte_ifpga_get_string_arg; > + rte_ifpga_driver_register; > + rte_ifpga_driver_unregister; > + > + local: *; > +}; > diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build index > 58dfbe2..52c755d 100644 > --- a/drivers/bus/meson.build > +++ b/drivers/bus/meson.build > @@ -1,7 +1,7 @@ > # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel > Corporation > > -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] > +drivers = ['dpaa', 'fslmc', 'ifpga', 'pci', 'vdev'] > std_deps = ['eal'] > config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' > driver_name_fmt = 'rte_bus_@0@' > diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 26f3563..3861e1a 100644 > --- a/mk/rte.app.mk > +++ b/mk/rte.app.mk > @@ -255,6 +255,7 @@ ifeq > ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += > -lrte_pmd_dpaa2_cmdif > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += > -lrte_pmd_dpaa2_qdma endif # CONFIG_RTE_LIBRTE_FSLMC_BUS > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga > endif # CONFIG_RTE_LIBRTE_RAWDEV > > > -- > 1.8.3.1 Regards Qi ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-10 12:26 ` Zhang, Qi Z @ 2018-05-10 13:29 ` Xu, Rosen 2018-05-10 13:48 ` Zhang, Qi Z 2018-05-10 13:51 ` Xu, Rosen 0 siblings, 2 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-10 13:29 UTC (permalink / raw) To: Zhang, Qi Z, dev, thomas Cc: Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet Hi Qi, > -----Original Message----- > From: Zhang, Qi Z > Sent: Thursday, May 10, 2018 20:27 > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; thomas@monjalon.net > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > Library > > Hi Rosen: > > > -----Original Message----- > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > > Sent: Wednesday, May 9, 2018 3:43 PM > > To: dev@dpdk.org; thomas@monjalon.net > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > > Richardson, Bruce <bruce.richardson@intel.com>; > > shreyansh.jain@nxp.com; Yigit, Ferruh <ferruh.yigit@intel.com>; > > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Tianfei > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > Subject: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > > Library > > > > From: Rosen Xu <rosen.xu@intel.com> > > > > Defined FPGA-BUS for Acceleration Drivers of AFUs > > > > 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, > > probe Intel FPGA Rawdev Driver, it will be covered in following patches. > > > > 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. > > This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan > > the AFUs will be created and their drivers are also probed. > > > > This patch will introduce rte_afu_device which describe the AFU device > > listed in the FPGA-BUS. > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > > --- > > MAINTAINERS | 4 + > > config/common_base | 5 + > > doc/guides/rel_notes/release_18_05.rst | 5 + > > drivers/bus/Makefile | 1 + > > drivers/bus/ifpga/Makefile | 32 ++ > > drivers/bus/ifpga/ifpga_bus.c | 501 > > ++++++++++++++++++++++++++++ > > drivers/bus/ifpga/ifpga_common.c | 88 +++++ > > drivers/bus/ifpga/ifpga_common.h | 18 + > > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > > drivers/bus/ifpga/meson.build | 8 + > > drivers/bus/ifpga/rte_bus_ifpga.h | 160 +++++++++ > > drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + > > drivers/bus/meson.build | 2 +- > > mk/rte.app.mk | 1 + > > 14 files changed, 865 insertions(+), 1 deletion(-) create mode > > 100644 drivers/bus/ifpga/Makefile create mode 100644 > > drivers/bus/ifpga/ifpga_bus.c create mode 100644 > > drivers/bus/ifpga/ifpga_common.c create mode 100644 > > drivers/bus/ifpga/ifpga_common.h create mode 100644 > > drivers/bus/ifpga/ifpga_logs.h create mode 100644 > > drivers/bus/ifpga/meson.build create mode 100644 > > drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 > > drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > diff --git a/MAINTAINERS b/MAINTAINERS index 7105920..fa0c5b1 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -383,6 +383,10 @@ F: drivers/mempool/bucket/ Bus Drivers > > ----------- > > > > +Intel FPGA buses > > +M: Rosen Xu <rosen.xu@intel.com> > > +F: drivers/bus/ifpga/ > > + > > NXP buses > > M: Hemant Agrawal <hemant.agrawal@nxp.com> > > M: Shreyansh Jain <shreyansh.jain@nxp.com> diff --git > > a/config/common_base b/config/common_base index 0d181ac..1440316 > > 100644 > > --- a/config/common_base > > +++ b/config/common_base > > @@ -139,6 +139,11 @@ > > CONFIG_RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS=n > > CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n > > > > # > > +# Compile the Intel FPGA bus > > +# > > +CONFIG_RTE_LIBRTE_IFPGA_BUS=y > > + > > +# > > # Compile PCI bus driver > > # > > CONFIG_RTE_LIBRTE_PCI_BUS=y > > diff --git a/doc/guides/rel_notes/release_18_05.rst > > b/doc/guides/rel_notes/release_18_05.rst > > index 7187348..265950a 100644 > > --- a/doc/guides/rel_notes/release_18_05.rst > > +++ b/doc/guides/rel_notes/release_18_05.rst > > @@ -183,6 +183,11 @@ New Features > > stats/xstats on shared memory from secondary process, and also > > pdump packets on > > those virtual devices. > > > > +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** > > + > > + The Ifpga Bus library provides support for integrating any Intel > > + FPGA device with the DPDK framework. It provides Intel FPGA Partial > > + Bit Stream AFU(Accelerated Function Unit) scan and drivers prove. > > > > API Changes > > ----------- > > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index > > c251b65..ef7f247 100644 > > --- a/drivers/bus/Makefile > > +++ b/drivers/bus/Makefile > > @@ -7,6 +7,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa ifeq > > ($(CONFIG_RTE_EAL_VFIO),y) > > DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc endif > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > > > > diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile > > new file mode 100644 index 0000000..3ff3bdb > > --- /dev/null > > +++ b/drivers/bus/ifpga/Makefile > > @@ -0,0 +1,32 @@ > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > > +Corporation > > + > > +include $(RTE_SDK)/mk/rte.vars.mk > > + > > +# > > +# library name > > +# > > +LIB = librte_bus_ifpga.a > > + > > +CFLAGS += -DALLOW_EXPERIMENTAL_API > > +CFLAGS += -O3 > > +CFLAGS += $(WERROR_FLAGS) > > +LDLIBS += -lrte_eal > > +LDLIBS += -lrte_rawdev > > +LDLIBS += -lrte_kvargs > > + > > +# versioning export map > > +EXPORT_MAP := rte_bus_ifpga_version.map > > + > > +# library version > > +LIBABIVER := 1 > > + > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c > > + > > +# > > +# Export include files > > +# > > +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h > > + > > +include $(RTE_SDK)/mk/rte.lib.mk > > diff --git a/drivers/bus/ifpga/ifpga_bus.c > > b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index > > 0000000..e144c01 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_bus.c > > @@ -0,0 +1,501 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > +#include <string.h> > > +#include <inttypes.h> > > +#include <stdint.h> > > +#include <stdlib.h> > > +#include <stdio.h> > > +#include <sys/queue.h> > > +#include <sys/mman.h> > > +#include <sys/types.h> > > +#include <unistd.h> > > +#include <fcntl.h> > > + > > +#include <rte_errno.h> > > +#include <rte_bus.h> > > +#include <rte_per_lcore.h> > > +#include <rte_memory.h> > > +#include <rte_memzone.h> > > +#include <rte_eal.h> > > +#include <rte_common.h> > > + > > +#include <rte_devargs.h> > > +#include <rte_kvargs.h> > > +#include <rte_alarm.h> > > + > > +#include "rte_rawdev.h" > > +#include "rte_rawdev_pmd.h" > > +#include "rte_bus_ifpga.h" > > +#include "ifpga_logs.h" > > +#include "ifpga_common.h" > > + > > +int ifpga_bus_logtype; > > + > > +/* Forward declaration to access Intel FPGA bus > > + * on which iFPGA devices are connected */ static struct rte_bus > > +rte_ifpga_bus; > > + > > +/** Double linked list of IFPGA device. */ > > +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); > > + > > +static struct ifpga_device_list ifpga_device_list = > > + TAILQ_HEAD_INITIALIZER(ifpga_device_list); > > +static struct afu_driver_list afu_driver_list = > > + TAILQ_HEAD_INITIALIZER(afu_driver_list); > > + > > + > > +/* register a ifpga bus based driver */ void > > +rte_ifpga_driver_register(struct rte_afu_driver *driver) { > > + RTE_VERIFY(driver); > > + > > + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); } > > + > > +/* un-register a fpga bus based driver */ void > > +rte_ifpga_driver_unregister(struct rte_afu_driver *driver) { > > + TAILQ_REMOVE(&afu_driver_list, driver, next); } > > + > > +static struct rte_ifpga_device * > > +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) { > > + struct rte_ifpga_device *ifpga_dev = NULL; > > + > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > + if (rdev && > > + ifpga_dev->rdev && > > + ifpga_dev->rdev == rdev) > > + return ifpga_dev; > > + } > > + return NULL; > > +} > > + > > +static struct rte_afu_device * > > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > > + const struct rte_afu_id *afu_id) > > +{ > > + struct rte_afu_device *afu_dev = NULL; > > + > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > > + return afu_dev; > > + } > > + return NULL; > > +} > > + > > +static const char * const valid_args[] = { > > +#define IFPGA_ARG_NAME "ifpga" > > + IFPGA_ARG_NAME, > > +#define IFPGA_ARG_PORT "port" > > + IFPGA_ARG_PORT, > > +#define IFPGA_AFU_BTS "afu_bts" > > + IFPGA_AFU_BTS, > > + NULL > > +}; > > + > > +/* > > + * Scan the content of the FPGA bus, and the devices in the devices > > + * list > > + */ > > +static struct rte_afu_device * > > +ifpga_scan_one(struct rte_devargs *devargs, > > + struct rte_ifpga_device *ifpga_dev) > > usually ifpag_dev should be the first parameter here, and devargs follows Fixed. > > +{ > > + struct rte_kvargs *kvlist = NULL; > > + struct rte_rawdev *rawdev = NULL; > > + struct rte_afu_device *afu_dev = NULL; > > + struct rte_afu_pr_conf afu_pr_conf; > > + int ret = 0; > > + char *path = NULL; > > + > > + memset(&afu_pr_conf, 0, sizeof(struct rte_afu_pr_conf)); > > + > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > + if (!kvlist) { > > + IFPGA_BUS_ERR("error when parsing param"); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, > > + &rte_ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) > { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_PORT); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_PORT); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, > > + &rte_ifpga_get_string_arg, &path) < 0) { > > + IFPGA_BUS_ERR("Failed to parse %s", > > + IFPGA_AFU_BTS); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_AFU_BTS); > > + goto end; > > + } > > + > > + afu_pr_conf.afu_id.uuid.uuid_low = 0; > > + afu_pr_conf.afu_id.uuid.uuid_high = 0; > > + afu_pr_conf.pr_enable = path?1:0; > > + > > + rawdev = ifpga_dev->rdev; > > + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) > > + goto end; > > + > > + afu_dev = calloc(1, sizeof(*afu_dev)); > > + if (!afu_dev) > > + goto end; > > + > > + afu_dev->device.devargs = devargs; > > + afu_dev->device.numa_node = SOCKET_ID_ANY; > > + afu_dev->device.name = devargs->name; > > + afu_dev->rawdev = rawdev; > > + afu_dev->id.uuid.uuid_low = 0; > > + afu_dev->id.uuid.uuid_high = 0; > > + afu_dev->id.port = afu_pr_conf.afu_id.port; > > + afu_dev->ifpga_dev = ifpga_dev; > > + > > + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) > > + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); > > + > > + if (rawdev->dev_ops && > > + rawdev->dev_ops->dev_start && > > + rawdev->dev_ops->dev_start(rawdev)) > > + goto free_dev; > > + > > + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); > > + if (rawdev->dev_ops->firmware_load && > > + rawdev->dev_ops->firmware_load(rawdev, > > + &afu_pr_conf)){ > > + IFPGA_BUS_ERR("firmware load error %d\n", ret); > > + goto free_dev; > > + } > > + afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; > > + afu_dev->id.uuid.uuid_high = afu_pr_conf.afu_id.uuid.uuid_high; > > + > > + return afu_dev; > > + > > +free_dev: > > + free(afu_dev); > > +end: > > + if (kvlist) > > + rte_kvargs_free(kvlist); > > + if (path) > > + free(path); > > + > > + return NULL; > > +} > > + > > +/* > > + * Scan the content of the FPGA bus, and the devices in the devices > > + * list > > + */ > > +static int > > +ifpga_scan(void) > > +{ > > + struct rte_ifpga_device *ifpga_dev; > > + struct rte_devargs *devargs; > > + struct rte_kvargs *kvlist = NULL; > > + struct rte_rawdev *rawdev = NULL; > > + char *name = NULL; > > + char name1[RTE_RAWDEV_NAME_MAX_LEN]; > > + struct rte_afu_device *afu_dev = NULL; > > + > > + /* for FPGA devices we scan the devargs_list populated via cmdline > > +*/ > > I didn't see "--ifpga" is supported by cmdline, either you need to add > corresponding parser or correct the comment here. To be honestly, ifpga_scan() is called by hotplug, lib_rte hotplug function will construct it. > > + RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { > > > IFPGA_BUS_NAME to replace "ifpga" here. > > > + if (devargs->bus != &rte_ifpga_bus) > > + continue; > > + > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > + if (!kvlist) { > > + IFPGA_BUS_ERR("error when parsing param"); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, > > + &rte_ifpga_get_string_arg, &name) < 0) { > > + IFPGA_BUS_ERR("error to parse %s", > > + IFPGA_ARG_NAME); > > + goto end; > > + } > > + } else { > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > + IFPGA_ARG_NAME); > > + goto end; > > + } > > + > > + memset(name1, 0, sizeof(name1)); > > + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, > "IFPGA:%s", > > name); > > + > > + rawdev = rte_rawdev_pmd_get_named_dev(name1); > > + if (!rawdev) > > + goto end; > > + > > + if (ifpga_find_ifpga_dev(rawdev)) > > + continue; > > + > > + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); > > + if (!ifpga_dev) > > + goto end; > > + > > + ifpga_dev->rdev = rawdev; > > + TAILQ_INIT(&ifpga_dev->afu_list); > > + > > + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); > > + afu_dev = ifpga_scan_one(devargs, ifpga_dev); > > + if (afu_dev != NULL) > > + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, > next); > > I don't understand why we need afu_list?, seems we only add a new afu_dev > into the list after create a new ifpga_dev, Is there any another place that we > add one to list to make it reasonable? it looks like either a 1:1 or 1:0 for > ifpga_dev:afu_dev? One FPAG may support more than one AFU. > > + } > > + > > +end: > > + if (kvlist) > > + rte_kvargs_free(kvlist); > > + if (name) > > + free(name); > > + > > + return 0; > > +} > > + > > +/* > > + * Match the AFU Driver and AFU Device using the ID Table */ static > > +int rte_afu_match(const struct rte_afu_driver *afu_drv, > > + const struct rte_afu_device *afu_dev) { > > + const struct rte_afu_uuid *id_table; > > + > > + for (id_table = afu_drv->id_table; > > + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); > > + id_table++) { > > + /* check if device's identifiers match the driver's ones */ > > + if ((id_table->uuid_low != afu_dev->id.uuid.uuid_low) || > > + id_table->uuid_high != > > + afu_dev->id.uuid.uuid_high) > > + continue; > > + > > + return 1; > > + } > > + > > + return 0; > > +} > > + > > +static int > > +ifpga_probe_one_driver(struct rte_afu_driver *drv, > > + struct rte_afu_device *afu_dev) > > +{ > > + int ret; > > + > > + if (!rte_afu_match(drv, afu_dev)) > > + /* Match of device and driver failed */ > > + return 1; > > + > > + /* reference driver structure */ > > + afu_dev->driver = drv; > > + afu_dev->device.driver = &drv->driver; > > + > > + /* call the driver probe() function */ > > + ret = drv->probe(afu_dev); > > + if (ret) { > > + afu_dev->driver = NULL; > > + afu_dev->device.driver = NULL; > > + } > > + > > + return ret; > > +} > > + > > +static int > > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) { > > + struct rte_afu_driver *drv = NULL; > > + int ret = 0; > > + > > + if (afu_dev == NULL) > > + return -1; > > + > > + /* Check if a driver is already loaded */ > > + if (afu_dev->driver != NULL) > > + return 0; > > + > > + TAILQ_FOREACH(drv, &afu_driver_list, next) { > > + if (ifpga_probe_one_driver(drv, afu_dev)) { > > + ret = -1; > > + break; > > + } > > + } > > + return ret; > > +} > > + > > +/* > > + * Scan the content of the Intel FPGA bus, and call the probe() > > +function for > > + * all registered drivers that have a matching entry in its id_table > > + * for discovered devices. > > + */ > > +static int > > +ifpga_probe(void) > > +{ > > + struct rte_ifpga_device *ifpga_dev; > > + struct rte_afu_device *afu_dev = NULL; > > + int ret = 0; > > + > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > + > > + if (afu_dev->device.driver) > > + continue; > > + > > + ret = ifpga_probe_all_drivers(afu_dev); > > + if (ret < 0) > > + IFPGA_BUS_ERR("failed to initialize %s > device\n", > > + rte_ifpga_device_name(afu_dev)); > > + } > > + } > > + > > + return ret; > > +} > > + > > +static int > > +ifpga_plug(struct rte_device *dev) > > +{ > > + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); > > +} > > + > > +static int > > +ifpga_remove_driver(struct rte_afu_device *afu_dev) { > > + const char *name; > > + const struct rte_afu_driver *driver; > > + > > + name = rte_ifpga_device_name(afu_dev); > > + if (!afu_dev->device.driver) { > > + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); > > + return 1; > > + } > > + > > + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); > > + return driver->remove(afu_dev); > > +} > > + > > +static int > > +ifpga_unplug(struct rte_device *dev) > > +{ > > + struct rte_ifpga_device *ifpga_dev = NULL; > > + struct rte_afu_device *afu_dev = NULL; > > + struct rte_devargs *devargs = NULL; > > + int ret; > > + > > + if (dev == NULL) > > + return -EINVAL; > > + > > + afu_dev = RTE_DEV_TO_AFU(dev); > > + if (!dev) > > + return -ENOENT; > > + > > + ifpga_dev = afu_dev->ifpga_dev; > > + devargs = dev->devargs; > > + > > + ret = ifpga_remove_driver(afu_dev); > > So what is the device type that be plugged into the ifgpa bus? > ifpga_dev or afu_dev? If its afu_dev, why we need ifpga_dev? > If it is ifpga_dev, we need remove ifpga_dev from ifpga_device_list here. The device type that be plugged into the ifpga bus is afu_dev. And each afu_dev will be added into one ifpga_dev. Each FPGA device bind to ifpga_dev. > > + if (ret) > > + return ret; > > + > > + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); > > + > > + rte_devargs_remove(devargs->bus->name, devargs->name); > > + free(afu_dev); > > + return 0; > > + > > +} > > + > > +static struct rte_device * > > +ifpga_find_device(const struct rte_device *start, > > + rte_dev_cmp_t cmp, const void *data) { > > + struct rte_ifpga_device *ifpga_dev; > > + struct rte_afu_device *afu_dev; > > + > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > + if (start && &afu_dev->device == start) { > > + start = NULL; > > + continue; > > + } > > + if (cmp(&afu_dev->device, data) == 0) > > + return &afu_dev->device; > > + } > > + } > > + return NULL; > > +} > > +static int > > +ifpga_parse(const char *name, void *addr) { > > + int *out = addr; > > + struct rte_rawdev *rawdev = NULL; > > + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; > > + char *c1 = NULL, *c2 = NULL; > > + int port = IFPGA_BUS_DEV_PORT_MAX; > > + char str_port[8]; > > + int str_port_len = 0; > > + int ret; > > + > > + memset(str_port, 0, 8); > > + c1 = strchr(name, '|'); > > + if (c1 != NULL) { > > + str_port_len = c1-name; > > + c2 = c1+1; > > + } > > + > > + if (str_port_len < 8 && > > + str_port_len > 0) { > > + memcpy(str_port, name, str_port_len); > > + ret = sscanf(str_port, "%d", &port); > > + if (ret == -1) > > + return 0; > > + } > > + > > + memset(rawdev_name, 0, sizeof(rawdev_name)); > > + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", > c2); > > + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); > > + > > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > > + rawdev && > > + (addr != NULL)) > > + *out = port; > > + > > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > > + rawdev) > > + return 0; > > + else > > + return 1; > > +} > > + > > +static struct rte_bus rte_ifpga_bus = { > > + .scan = ifpga_scan, > > + .probe = ifpga_probe, > > + .find_device = ifpga_find_device, > > + .plug = ifpga_plug, > > + .unplug = ifpga_unplug, > > + .parse = ifpga_parse, > > +}; > > + > > +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); > > + > > +RTE_INIT(ifpga_init_log) > > +{ > > + ifpga_bus_logtype = rte_log_register("bus.ifpga"); > > + if (ifpga_bus_logtype >= 0) > > + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); } > > diff --git a/drivers/bus/ifpga/ifpga_common.c > > b/drivers/bus/ifpga/ifpga_common.c > > new file mode 100644 > > index 0000000..78e2eae > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_common.c > > @@ -0,0 +1,88 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > +#include <string.h> > > +#include <inttypes.h> > > +#include <stdint.h> > > +#include <stdlib.h> > > +#include <stdio.h> > > +#include <sys/queue.h> > > +#include <sys/mman.h> > > +#include <sys/types.h> > > +#include <unistd.h> > > +#include <fcntl.h> > > + > > +#include <rte_errno.h> > > +#include <rte_bus.h> > > +#include <rte_per_lcore.h> > > +#include <rte_memory.h> > > +#include <rte_memzone.h> > > +#include <rte_eal.h> > > +#include <rte_common.h> > > + > > +#include <rte_devargs.h> > > +#include <rte_kvargs.h> > > +#include <rte_alarm.h> > > + > > +#include "rte_bus_ifpga.h" > > +#include "ifpga_logs.h" > > +#include "ifpga_common.h" > > + > > +int rte_ifpga_get_string_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) { > > + if (!value || !extra_args) > > + return -EINVAL; > > + > > + *(char **)extra_args = strdup(value); > > + > > + if (!*(char **)extra_args) > > + return -ENOMEM; > > + > > + return 0; > > +} > > +int rte_ifpga_get_integer32_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) { > > + if (!value || !extra_args) > > + return -EINVAL; > > + > > + *(int *)extra_args = strtoull(value, NULL, 0); > > + > > + return 0; > > +} > > +int ifpga_get_integer64_arg(const char *key __rte_unused, > > + const char *value, void *extra_args) { > > + if (!value || !extra_args) > > + return -EINVAL; > > + > > + *(uint64_t *)extra_args = strtoull(value, NULL, 0); > > + > > + return 0; > > +} > > +int ifpga_get_unsigned_long(const char *str, int base) { > > + unsigned long num; > > + char *end = NULL; > > + > > + errno = 0; > > + > > + num = strtoul(str, &end, base); > > + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) > > + return -1; > > + > > + return num; > > +} > > + > > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > + const struct rte_afu_id *afu_id1) > > +{ > > + if ((afu_id0->uuid.uuid_low == afu_id1->uuid.uuid_low) && > > + (afu_id0->uuid.uuid_high == afu_id1->uuid.uuid_high) && > > + (afu_id0->port == afu_id1->port)) { > > + return 0; > > + } else > > + return 1; > > +} > > diff --git a/drivers/bus/ifpga/ifpga_common.h > > b/drivers/bus/ifpga/ifpga_common.h > > new file mode 100644 > > index 0000000..f9254b9 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_common.h > > @@ -0,0 +1,18 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > +#ifndef _IFPGA_COMMON_H_ > > +#define _IFPGA_COMMON_H_ > > + > > +int rte_ifpga_get_string_arg(const char *key __rte_unused, > > + const char *value, void *extra_args); int > > +rte_ifpga_get_integer32_arg(const char *key __rte_unused, > > + const char *value, void *extra_args); int > > +ifpga_get_integer64_arg(const char *key __rte_unused, > > + const char *value, void *extra_args); int > > +ifpga_get_unsigned_long(const char *str, int base); int > > +ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > + const struct rte_afu_id *afu_id1); > > + > > +#endif /* _IFPGA_COMMON_H_ */ > > diff --git a/drivers/bus/ifpga/ifpga_logs.h > > b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index > > 0000000..873e0a4 > > --- /dev/null > > +++ b/drivers/bus/ifpga/ifpga_logs.h > > @@ -0,0 +1,31 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > +#ifndef _IFPGA_LOGS_H_ > > +#define _IFPGA_LOGS_H_ > > + > > +#include <rte_log.h> > > + > > +extern int ifpga_bus_logtype; > > + > > +#define IFPGA_LOG(level, fmt, args...) \ > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > + __func__, ##args) > > + > > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > + __func__, ##args) > > + > > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > > + > > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) > > +#define IFPGA_BUS_INFO(fmt, args...) \ > > + IFPGA_BUS_LOG(INFO, fmt, ## args) > > +#define IFPGA_BUS_ERR(fmt, args...) \ > > + IFPGA_BUS_LOG(ERR, fmt, ## args) > > +#define IFPGA_BUS_WARN(fmt, args...) \ > > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > > + > > +#endif /* _IFPGA_BUS_LOGS_H_ */ > > diff --git a/drivers/bus/ifpga/meson.build > > b/drivers/bus/ifpga/meson.build new file mode 100644 index > > 0000000..c9b08c8 > > --- /dev/null > > +++ b/drivers/bus/ifpga/meson.build > > @@ -0,0 +1,8 @@ > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2010-2018 > > +Intel Corporation > > + > > +deps += ['pci', 'kvargs', 'rawdev'] > > +install_headers('rte_bus_ifpga.h') > > +sources = files('ifpga_common.c', 'ifpga_bus.c') > > + > > +allow_experimental_apis = true > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h > > b/drivers/bus/ifpga/rte_bus_ifpga.h > > new file mode 100644 > > index 0000000..5c559e1 > > --- /dev/null > > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > > @@ -0,0 +1,160 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > +#ifndef _RTE_BUS_IFPGA_H_ > > +#define _RTE_BUS_IFPGA_H_ > > + > > +/** > > + * @file > > + * > > + * RTE Intel FPGA Bus Interface > > + */ > > + > > +#ifdef __cplusplus > > +extern "C" { > > +#endif > > + > > +#include <rte_bus.h> > > +#include <rte_pci.h> > > + > > +/** Name of Intel FPGA Bus */ > > +#define IFPGA_BUS_NAME ifpga > > + > > +/* Forward declarations */ > > +struct rte_afu_device; > > + > > +/** List of Intel AFU devices */ > > +TAILQ_HEAD(afu_device_list, rte_afu_device); > > +/** Double linked list of AFU device drivers. */ > > +TAILQ_HEAD(afu_driver_list, rte_afu_driver); > > + > > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > > + > > +struct rte_afu_uuid { > > + uint64_t uuid_low; > > + uint64_t uuid_high; > > +} __attribute__ ((packed)); > > + > > +#define IFPGA_BUS_DEV_PORT_MAX 4 > > + > > +/** > > + * A structure describing an ID for a AFU driver. Each driver > > +provides a > > + * table of these IDs for each device that it supports. > > + */ > > +struct rte_afu_id { > > + struct rte_afu_uuid uuid; > > + int port; /**< port number */ > > +} __attribute__ ((packed)); > > + > > +/** > > + * A structure PR (Partial Reconfiguration) configuration AFU driver. > > + */ > > + > > +struct rte_afu_pr_conf { > > + struct rte_afu_id afu_id; > > + int pr_enable; > > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > +}; > > + > > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > > + > > +/** > > + * A structure describing a fpga device. > > + */ > > +struct rte_ifpga_device { > > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ > > + struct rte_rawdev *rdev; > > + struct afu_device_list afu_list; /**< List of AFU devices */ }; > > + > > +/** > > + * A structure describing a AFU device. > > + */ > > +struct rte_afu_device { > > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ > > + struct rte_device device; /**< Inherit core device */ > > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > > + struct rte_afu_id id; /**< AFU id within FPGA. */ > > + uint32_t num_region; /**< number of regions found */ > > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > > + /**< AFU Memory Resource > */ > > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > > + struct rte_afu_driver *driver; /**< Associated driver */ > > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > +} __attribute__ ((packed)); > > + > > +/** > > + * @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_DRV_TO_AFU_CONST(ptr) \ > > + container_of(ptr, const struct rte_afu_driver, driver) > > + > > +/** > > + * Initialisation function for the driver called during FPGA BUS probing. > > > typo: Initialization Fixed. > > + */ > > +typedef int (afu_probe_t)(struct rte_afu_device *); > > + > > +/** > > + * Uninitialisation function for the driver called during hotplugging. > > typo: Unintialization Fixed. > > + */ > > +typedef int (afu_remove_t)(struct rte_afu_device *); > > + > > +/** > > + * A structure describing a AFU device. > > + */ > > +struct rte_afu_driver { > > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > > + struct rte_driver driver; /**< Inherit core driver. */ > > + afu_probe_t *probe; /**< Device Probe function. > > */ > > + afu_remove_t *remove; /**< Device Remove > > function. */ > > + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ > > + uint32_t drv_flags; /**< Flags contolling handling of device. */ > > Typo Controlling > And what is "flags controlling handling of device?" This variable is not used, so I have removed it. > > +}; > > + > > +static inline const char * > > +rte_ifpga_device_name(const struct rte_afu_device *afu) { > > + if (afu && afu->device.name) > > + return afu->device.name; > > + return NULL; > > +} > > + > > +/** > > + * Register a ifpga afu device driver. > > + * > > + * @param driver > > + * A pointer to a rte_afu_driver structure describing the driver > > + * to be registered. > > + */ > > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); > > + > > +/** > > + * Unregister a ifpga afu device driver. > > + * > > + * @param driver > > + * A pointer to a rte_afu_driver structure describing the driver > > + * to be unregistered. > > + */ > > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > > + > > +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ RTE_INIT(afudrvinitfn_ > > +##afudrv);\ static const char *afudrvinit_ ## nm ## _alias;\ static > > +void afudrvinitfn_ ##afudrv(void)\ {\ > > + (afudrv).driver.name = RTE_STR(nm);\ > > + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ > > + rte_ifpga_driver_register(&afudrv);\ > > +} \ > > +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) > > + > > +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ static const char > > +*afudrvinit_ ## nm ## _alias = RTE_STR(alias) > > + > > +#endif /* _RTE_BUS_IFPGA_H_ */ > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map > > b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > new file mode 100644 > > index 0000000..a027979 > > --- /dev/null > > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > @@ -0,0 +1,10 @@ > > +DPDK_18.05 { > > + global: > > + > > + rte_ifpga_get_integer32_arg; > > + rte_ifpga_get_string_arg; > > + rte_ifpga_driver_register; > > + rte_ifpga_driver_unregister; > > + > > + local: *; > > +}; > > diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build index > > 58dfbe2..52c755d 100644 > > --- a/drivers/bus/meson.build > > +++ b/drivers/bus/meson.build > > @@ -1,7 +1,7 @@ > > # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel > > Corporation > > > > -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] > > +drivers = ['dpaa', 'fslmc', 'ifpga', 'pci', 'vdev'] > > std_deps = ['eal'] > > config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' > > driver_name_fmt = 'rte_bus_@0@' > > diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 26f3563..3861e1a > > 100644 > > --- a/mk/rte.app.mk > > +++ b/mk/rte.app.mk > > @@ -255,6 +255,7 @@ ifeq > > ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += > > -lrte_pmd_dpaa2_cmdif > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += > > -lrte_pmd_dpaa2_qdma endif # CONFIG_RTE_LIBRTE_FSLMC_BUS > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga > > endif # CONFIG_RTE_LIBRTE_RAWDEV > > > > > > -- > > 1.8.3.1 > > Regards > Qi ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-10 13:29 ` Xu, Rosen @ 2018-05-10 13:48 ` Zhang, Qi Z 2018-05-10 13:58 ` Xu, Rosen 2018-05-10 13:51 ` Xu, Rosen 1 sibling, 1 reply; 149+ messages in thread From: Zhang, Qi Z @ 2018-05-10 13:48 UTC (permalink / raw) To: Xu, Rosen, dev, thomas Cc: Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet > -----Original Message----- > From: Xu, Rosen > Sent: Thursday, May 10, 2018 9:29 PM > To: Zhang, Qi Z <qi.z.zhang@intel.com>; dev@dpdk.org; > thomas@monjalon.net > Cc: Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, Declan > <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library > > Hi Qi, > > > -----Original Message----- > > From: Zhang, Qi Z > > Sent: Thursday, May 10, 2018 20:27 > > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; > thomas@monjalon.net > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > > Richardson, Bruce <bruce.richardson@intel.com>; > > shreyansh.jain@nxp.com; Yigit, Ferruh <ferruh.yigit@intel.com>; > > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Tianfei > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > > Library > > > > Hi Rosen: > > > > > -----Original Message----- > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > > > Sent: Wednesday, May 9, 2018 3:43 PM > > > To: dev@dpdk.org; thomas@monjalon.net > > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > > <roy.fan.zhang@intel.com>; Doherty, Declan > > > <declan.doherty@intel.com>; Richardson, Bruce > > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > > > <ferruh.yigit@intel.com>; Ananyev, Konstantin > > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > > Subject: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > > > Library > > > > > > From: Rosen Xu <rosen.xu@intel.com> > > > > > > Defined FPGA-BUS for Acceleration Drivers of AFUs > > > > > > 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, > > > probe Intel FPGA Rawdev Driver, it will be covered in following patches. > > > > > > 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. > > > This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan > > > the AFUs will be created and their drivers are also probed. > > > > > > This patch will introduce rte_afu_device which describe the AFU > > > device listed in the FPGA-BUS. > > > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > > > --- > > > MAINTAINERS | 4 + > > > config/common_base | 5 + > > > doc/guides/rel_notes/release_18_05.rst | 5 + > > > drivers/bus/Makefile | 1 + > > > drivers/bus/ifpga/Makefile | 32 ++ > > > drivers/bus/ifpga/ifpga_bus.c | 501 > > > ++++++++++++++++++++++++++++ > > > drivers/bus/ifpga/ifpga_common.c | 88 +++++ > > > drivers/bus/ifpga/ifpga_common.h | 18 + > > > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > > > drivers/bus/ifpga/meson.build | 8 + > > > drivers/bus/ifpga/rte_bus_ifpga.h | 160 +++++++++ > > > drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + > > > drivers/bus/meson.build | 2 +- > > > mk/rte.app.mk | 1 + > > > 14 files changed, 865 insertions(+), 1 deletion(-) create mode > > > 100644 drivers/bus/ifpga/Makefile create mode 100644 > > > drivers/bus/ifpga/ifpga_bus.c create mode 100644 > > > drivers/bus/ifpga/ifpga_common.c create mode 100644 > > > drivers/bus/ifpga/ifpga_common.h create mode 100644 > > > drivers/bus/ifpga/ifpga_logs.h create mode 100644 > > > drivers/bus/ifpga/meson.build create mode 100644 > > > drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 > > > drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > > > diff --git a/MAINTAINERS b/MAINTAINERS index 7105920..fa0c5b1 100644 > > > --- a/MAINTAINERS > > > +++ b/MAINTAINERS > > > @@ -383,6 +383,10 @@ F: drivers/mempool/bucket/ Bus Drivers > > > ----------- > > > > > > +Intel FPGA buses > > > +M: Rosen Xu <rosen.xu@intel.com> > > > +F: drivers/bus/ifpga/ > > > + > > > NXP buses > > > M: Hemant Agrawal <hemant.agrawal@nxp.com> > > > M: Shreyansh Jain <shreyansh.jain@nxp.com> diff --git > > > a/config/common_base b/config/common_base index 0d181ac..1440316 > > > 100644 > > > --- a/config/common_base > > > +++ b/config/common_base > > > @@ -139,6 +139,11 @@ > > > CONFIG_RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS=n > > > CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n > > > > > > # > > > +# Compile the Intel FPGA bus > > > +# > > > +CONFIG_RTE_LIBRTE_IFPGA_BUS=y > > > + > > > +# > > > # Compile PCI bus driver > > > # > > > CONFIG_RTE_LIBRTE_PCI_BUS=y > > > diff --git a/doc/guides/rel_notes/release_18_05.rst > > > b/doc/guides/rel_notes/release_18_05.rst > > > index 7187348..265950a 100644 > > > --- a/doc/guides/rel_notes/release_18_05.rst > > > +++ b/doc/guides/rel_notes/release_18_05.rst > > > @@ -183,6 +183,11 @@ New Features > > > stats/xstats on shared memory from secondary process, and also > > > pdump packets on > > > those virtual devices. > > > > > > +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** > > > + > > > + The Ifpga Bus library provides support for integrating any Intel > > > + FPGA device with the DPDK framework. It provides Intel FPGA > > > + Partial Bit Stream AFU(Accelerated Function Unit) scan and drivers > prove. > > > > > > API Changes > > > ----------- > > > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index > > > c251b65..ef7f247 100644 > > > --- a/drivers/bus/Makefile > > > +++ b/drivers/bus/Makefile > > > @@ -7,6 +7,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa ifeq > > > ($(CONFIG_RTE_EAL_VFIO),y) > > > DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc endif > > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > > > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > > > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > > > > > > diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile > > > new file mode 100644 index 0000000..3ff3bdb > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/Makefile > > > @@ -0,0 +1,32 @@ > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > > > +Corporation > > > + > > > +include $(RTE_SDK)/mk/rte.vars.mk > > > + > > > +# > > > +# library name > > > +# > > > +LIB = librte_bus_ifpga.a > > > + > > > +CFLAGS += -DALLOW_EXPERIMENTAL_API > > > +CFLAGS += -O3 > > > +CFLAGS += $(WERROR_FLAGS) > > > +LDLIBS += -lrte_eal > > > +LDLIBS += -lrte_rawdev > > > +LDLIBS += -lrte_kvargs > > > + > > > +# versioning export map > > > +EXPORT_MAP := rte_bus_ifpga_version.map > > > + > > > +# library version > > > +LIBABIVER := 1 > > > + > > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c > > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c > > > + > > > +# > > > +# Export include files > > > +# > > > +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h > > > + > > > +include $(RTE_SDK)/mk/rte.lib.mk > > > diff --git a/drivers/bus/ifpga/ifpga_bus.c > > > b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index > > > 0000000..e144c01 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/ifpga_bus.c > > > @@ -0,0 +1,501 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > + > > > +#include <string.h> > > > +#include <inttypes.h> > > > +#include <stdint.h> > > > +#include <stdlib.h> > > > +#include <stdio.h> > > > +#include <sys/queue.h> > > > +#include <sys/mman.h> > > > +#include <sys/types.h> > > > +#include <unistd.h> > > > +#include <fcntl.h> > > > + > > > +#include <rte_errno.h> > > > +#include <rte_bus.h> > > > +#include <rte_per_lcore.h> > > > +#include <rte_memory.h> > > > +#include <rte_memzone.h> > > > +#include <rte_eal.h> > > > +#include <rte_common.h> > > > + > > > +#include <rte_devargs.h> > > > +#include <rte_kvargs.h> > > > +#include <rte_alarm.h> > > > + > > > +#include "rte_rawdev.h" > > > +#include "rte_rawdev_pmd.h" > > > +#include "rte_bus_ifpga.h" > > > +#include "ifpga_logs.h" > > > +#include "ifpga_common.h" > > > + > > > +int ifpga_bus_logtype; > > > + > > > +/* Forward declaration to access Intel FPGA bus > > > + * on which iFPGA devices are connected */ static struct rte_bus > > > +rte_ifpga_bus; > > > + > > > +/** Double linked list of IFPGA device. */ > > > +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); > > > + > > > +static struct ifpga_device_list ifpga_device_list = > > > + TAILQ_HEAD_INITIALIZER(ifpga_device_list); > > > +static struct afu_driver_list afu_driver_list = > > > + TAILQ_HEAD_INITIALIZER(afu_driver_list); > > > + > > > + > > > +/* register a ifpga bus based driver */ void > > > +rte_ifpga_driver_register(struct rte_afu_driver *driver) { > > > + RTE_VERIFY(driver); > > > + > > > + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); } > > > + > > > +/* un-register a fpga bus based driver */ void > > > +rte_ifpga_driver_unregister(struct rte_afu_driver *driver) { > > > + TAILQ_REMOVE(&afu_driver_list, driver, next); } > > > + > > > +static struct rte_ifpga_device * > > > +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) { > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > + > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > + if (rdev && > > > + ifpga_dev->rdev && > > > + ifpga_dev->rdev == rdev) > > > + return ifpga_dev; > > > + } > > > + return NULL; > > > +} > > > + > > > +static struct rte_afu_device * > > > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > > > + const struct rte_afu_id *afu_id) > > > +{ > > > + struct rte_afu_device *afu_dev = NULL; > > > + > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > > > + return afu_dev; > > > + } > > > + return NULL; > > > +} > > > + > > > +static const char * const valid_args[] = { > > > +#define IFPGA_ARG_NAME "ifpga" > > > + IFPGA_ARG_NAME, > > > +#define IFPGA_ARG_PORT "port" > > > + IFPGA_ARG_PORT, > > > +#define IFPGA_AFU_BTS "afu_bts" > > > + IFPGA_AFU_BTS, > > > + NULL > > > +}; > > > + > > > +/* > > > + * Scan the content of the FPGA bus, and the devices in the devices > > > + * list > > > + */ > > > +static struct rte_afu_device * > > > +ifpga_scan_one(struct rte_devargs *devargs, > > > + struct rte_ifpga_device *ifpga_dev) > > > > usually ifpag_dev should be the first parameter here, and devargs > > follows > > Fixed. > > > > +{ > > > + struct rte_kvargs *kvlist = NULL; > > > + struct rte_rawdev *rawdev = NULL; > > > + struct rte_afu_device *afu_dev = NULL; > > > + struct rte_afu_pr_conf afu_pr_conf; > > > + int ret = 0; > > > + char *path = NULL; > > > + > > > + memset(&afu_pr_conf, 0, sizeof(struct rte_afu_pr_conf)); > > > + > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > + if (!kvlist) { > > > + IFPGA_BUS_ERR("error when parsing param"); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, > > > + &rte_ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) > > { > > > + IFPGA_BUS_ERR("error to parse %s", > > > + IFPGA_ARG_PORT); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > + IFPGA_ARG_PORT); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, > > > + &rte_ifpga_get_string_arg, &path) < 0) { > > > + IFPGA_BUS_ERR("Failed to parse %s", > > > + IFPGA_AFU_BTS); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > + IFPGA_AFU_BTS); > > > + goto end; > > > + } > > > + > > > + afu_pr_conf.afu_id.uuid.uuid_low = 0; > > > + afu_pr_conf.afu_id.uuid.uuid_high = 0; > > > + afu_pr_conf.pr_enable = path?1:0; > > > + > > > + rawdev = ifpga_dev->rdev; > > > + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) > > > + goto end; > > > + > > > + afu_dev = calloc(1, sizeof(*afu_dev)); > > > + if (!afu_dev) > > > + goto end; > > > + > > > + afu_dev->device.devargs = devargs; > > > + afu_dev->device.numa_node = SOCKET_ID_ANY; > > > + afu_dev->device.name = devargs->name; > > > + afu_dev->rawdev = rawdev; > > > + afu_dev->id.uuid.uuid_low = 0; > > > + afu_dev->id.uuid.uuid_high = 0; > > > + afu_dev->id.port = afu_pr_conf.afu_id.port; > > > + afu_dev->ifpga_dev = ifpga_dev; > > > + > > > + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) > > > + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); > > > + > > > + if (rawdev->dev_ops && > > > + rawdev->dev_ops->dev_start && > > > + rawdev->dev_ops->dev_start(rawdev)) > > > + goto free_dev; > > > + > > > + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); > > > + if (rawdev->dev_ops->firmware_load && > > > + rawdev->dev_ops->firmware_load(rawdev, > > > + &afu_pr_conf)){ > > > + IFPGA_BUS_ERR("firmware load error %d\n", ret); > > > + goto free_dev; > > > + } > > > + afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; > > > + afu_dev->id.uuid.uuid_high = afu_pr_conf.afu_id.uuid.uuid_high; > > > + > > > + return afu_dev; > > > + > > > +free_dev: > > > + free(afu_dev); > > > +end: > > > + if (kvlist) > > > + rte_kvargs_free(kvlist); > > > + if (path) > > > + free(path); > > > + > > > + return NULL; > > > +} > > > + > > > +/* > > > + * Scan the content of the FPGA bus, and the devices in the devices > > > + * list > > > + */ > > > +static int > > > +ifpga_scan(void) > > > +{ > > > + struct rte_ifpga_device *ifpga_dev; > > > + struct rte_devargs *devargs; > > > + struct rte_kvargs *kvlist = NULL; > > > + struct rte_rawdev *rawdev = NULL; > > > + char *name = NULL; > > > + char name1[RTE_RAWDEV_NAME_MAX_LEN]; > > > + struct rte_afu_device *afu_dev = NULL; > > > + > > > + /* for FPGA devices we scan the devargs_list populated via cmdline > > > +*/ > > > > I didn't see "--ifpga" is supported by cmdline, either you need to add > > corresponding parser or correct the comment here. > > To be honestly, ifpga_scan() is called by hotplug, lib_rte hotplug function will > construct it. OK, after review patch 3, I saw it, that make sense. > > > > + RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { > > > > > > IFPGA_BUS_NAME to replace "ifpga" here. > > > > > + if (devargs->bus != &rte_ifpga_bus) > > > + continue; > > > + > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > + if (!kvlist) { > > > + IFPGA_BUS_ERR("error when parsing param"); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, > > > + &rte_ifpga_get_string_arg, &name) < 0) { > > > + IFPGA_BUS_ERR("error to parse %s", > > > + IFPGA_ARG_NAME); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > + IFPGA_ARG_NAME); > > > + goto end; > > > + } > > > + > > > + memset(name1, 0, sizeof(name1)); > > > + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, > > "IFPGA:%s", > > > name); > > > + > > > + rawdev = rte_rawdev_pmd_get_named_dev(name1); > > > + if (!rawdev) > > > + goto end; > > > + > > > + if (ifpga_find_ifpga_dev(rawdev)) > > > + continue; > > > + > > > + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); > > > + if (!ifpga_dev) > > > + goto end; > > > + > > > + ifpga_dev->rdev = rawdev; > > > + TAILQ_INIT(&ifpga_dev->afu_list); > > > + > > > + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); > > > + afu_dev = ifpga_scan_one(devargs, ifpga_dev); > > > + if (afu_dev != NULL) > > > + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, > > next); > > > > I don't understand why we need afu_list?, seems we only add a new > > afu_dev into the list after create a new ifpga_dev, Is there any > > another place that we add one to list to make it reasonable? it looks > > like either a 1:1 or 1:0 for ifpga_dev:afu_dev? > > One FPAG may support more than one AFU. But in your implementation, it is not possible that an ifpga_dev contains multiple afu_dev > > > > + } > > > + > > > +end: > > > + if (kvlist) > > > + rte_kvargs_free(kvlist); > > > + if (name) > > > + free(name); > > > + > > > + return 0; > > > +} > > > + > > > +/* > > > + * Match the AFU Driver and AFU Device using the ID Table */ > > > +static int rte_afu_match(const struct rte_afu_driver *afu_drv, > > > + const struct rte_afu_device *afu_dev) { > > > + const struct rte_afu_uuid *id_table; > > > + > > > + for (id_table = afu_drv->id_table; > > > + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); > > > + id_table++) { > > > + /* check if device's identifiers match the driver's ones */ > > > + if ((id_table->uuid_low != afu_dev->id.uuid.uuid_low) || > > > + id_table->uuid_high != > > > + afu_dev->id.uuid.uuid_high) > > > + continue; > > > + > > > + return 1; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +static int > > > +ifpga_probe_one_driver(struct rte_afu_driver *drv, > > > + struct rte_afu_device *afu_dev) > > > +{ > > > + int ret; > > > + > > > + if (!rte_afu_match(drv, afu_dev)) > > > + /* Match of device and driver failed */ > > > + return 1; > > > + > > > + /* reference driver structure */ > > > + afu_dev->driver = drv; > > > + afu_dev->device.driver = &drv->driver; > > > + > > > + /* call the driver probe() function */ > > > + ret = drv->probe(afu_dev); > > > + if (ret) { > > > + afu_dev->driver = NULL; > > > + afu_dev->device.driver = NULL; > > > + } > > > + > > > + return ret; > > > +} > > > + > > > +static int > > > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) { > > > + struct rte_afu_driver *drv = NULL; > > > + int ret = 0; > > > + > > > + if (afu_dev == NULL) > > > + return -1; > > > + > > > + /* Check if a driver is already loaded */ > > > + if (afu_dev->driver != NULL) > > > + return 0; > > > + > > > + TAILQ_FOREACH(drv, &afu_driver_list, next) { > > > + if (ifpga_probe_one_driver(drv, afu_dev)) { > > > + ret = -1; > > > + break; > > > + } > > > + } > > > + return ret; > > > +} > > > + > > > +/* > > > + * Scan the content of the Intel FPGA bus, and call the probe() > > > +function for > > > + * all registered drivers that have a matching entry in its > > > +id_table > > > + * for discovered devices. > > > + */ > > > +static int > > > +ifpga_probe(void) > > > +{ > > > + struct rte_ifpga_device *ifpga_dev; > > > + struct rte_afu_device *afu_dev = NULL; > > > + int ret = 0; > > > + > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > + > > > + if (afu_dev->device.driver) > > > + continue; > > > + > > > + ret = ifpga_probe_all_drivers(afu_dev); > > > + if (ret < 0) > > > + IFPGA_BUS_ERR("failed to initialize %s > > device\n", > > > + rte_ifpga_device_name(afu_dev)); > > > + } > > > + } > > > + > > > + return ret; > > > +} > > > + > > > +static int > > > +ifpga_plug(struct rte_device *dev) > > > +{ > > > + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); > > > +} > > > + > > > +static int > > > +ifpga_remove_driver(struct rte_afu_device *afu_dev) { > > > + const char *name; > > > + const struct rte_afu_driver *driver; > > > + > > > + name = rte_ifpga_device_name(afu_dev); > > > + if (!afu_dev->device.driver) { > > > + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); > > > + return 1; > > > + } > > > + > > > + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); > > > + return driver->remove(afu_dev); > > > +} > > > + > > > +static int > > > +ifpga_unplug(struct rte_device *dev) { > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > + struct rte_afu_device *afu_dev = NULL; > > > + struct rte_devargs *devargs = NULL; > > > + int ret; > > > + > > > + if (dev == NULL) > > > + return -EINVAL; > > > + > > > + afu_dev = RTE_DEV_TO_AFU(dev); > > > + if (!dev) > > > + return -ENOENT; > > > + > > > + ifpga_dev = afu_dev->ifpga_dev; > > > + devargs = dev->devargs; > > > + > > > + ret = ifpga_remove_driver(afu_dev); > > > > So what is the device type that be plugged into the ifgpa bus? > > ifpga_dev or afu_dev? If its afu_dev, why we need ifpga_dev? > > If it is ifpga_dev, we need remove ifpga_dev from ifpga_device_list here. > > The device type that be plugged into the ifpga bus is afu_dev. In DPDK, we have rte_pci_device for pci bus and rte_vdev_device for vdev bus Now we have rte_ifpga_device not for ifgpa bus but rte_afu_device, it is a little bit confuse here > And each afu_dev will be added into one ifpga_dev. > Each FPGA device bind to ifpga_dev. So what is the relationship between ifpga_dev and raw_dev? > > > > + if (ret) > > > + return ret; > > > + > > > + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); > > > + > > > + rte_devargs_remove(devargs->bus->name, devargs->name); > > > + free(afu_dev); > > > + return 0; > > > + > > > +} > > > + > > > +static struct rte_device * > > > +ifpga_find_device(const struct rte_device *start, > > > + rte_dev_cmp_t cmp, const void *data) { > > > + struct rte_ifpga_device *ifpga_dev; > > > + struct rte_afu_device *afu_dev; > > > + > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > + if (start && &afu_dev->device == start) { > > > + start = NULL; > > > + continue; > > > + } > > > + if (cmp(&afu_dev->device, data) == 0) > > > + return &afu_dev->device; > > > + } > > > + } > > > + return NULL; > > > +} > > > +static int > > > +ifpga_parse(const char *name, void *addr) { > > > + int *out = addr; > > > + struct rte_rawdev *rawdev = NULL; > > > + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; > > > + char *c1 = NULL, *c2 = NULL; > > > + int port = IFPGA_BUS_DEV_PORT_MAX; > > > + char str_port[8]; > > > + int str_port_len = 0; > > > + int ret; > > > + > > > + memset(str_port, 0, 8); > > > + c1 = strchr(name, '|'); > > > + if (c1 != NULL) { > > > + str_port_len = c1-name; > > > + c2 = c1+1; > > > + } > > > + > > > + if (str_port_len < 8 && > > > + str_port_len > 0) { > > > + memcpy(str_port, name, str_port_len); > > > + ret = sscanf(str_port, "%d", &port); > > > + if (ret == -1) > > > + return 0; > > > + } > > > + > > > + memset(rawdev_name, 0, sizeof(rawdev_name)); > > > + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", > > c2); > > > + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); > > > + > > > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > > > + rawdev && > > > + (addr != NULL)) > > > + *out = port; > > > + > > > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > > > + rawdev) > > > + return 0; > > > + else > > > + return 1; > > > +} > > > + > > > +static struct rte_bus rte_ifpga_bus = { > > > + .scan = ifpga_scan, > > > + .probe = ifpga_probe, > > > + .find_device = ifpga_find_device, > > > + .plug = ifpga_plug, > > > + .unplug = ifpga_unplug, > > > + .parse = ifpga_parse, > > > +}; > > > + > > > +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); > > > + > > > +RTE_INIT(ifpga_init_log) > > > +{ > > > + ifpga_bus_logtype = rte_log_register("bus.ifpga"); > > > + if (ifpga_bus_logtype >= 0) > > > + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); } > > > diff --git a/drivers/bus/ifpga/ifpga_common.c > > > b/drivers/bus/ifpga/ifpga_common.c > > > new file mode 100644 > > > index 0000000..78e2eae > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/ifpga_common.c > > > @@ -0,0 +1,88 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > + > > > +#include <string.h> > > > +#include <inttypes.h> > > > +#include <stdint.h> > > > +#include <stdlib.h> > > > +#include <stdio.h> > > > +#include <sys/queue.h> > > > +#include <sys/mman.h> > > > +#include <sys/types.h> > > > +#include <unistd.h> > > > +#include <fcntl.h> > > > + > > > +#include <rte_errno.h> > > > +#include <rte_bus.h> > > > +#include <rte_per_lcore.h> > > > +#include <rte_memory.h> > > > +#include <rte_memzone.h> > > > +#include <rte_eal.h> > > > +#include <rte_common.h> > > > + > > > +#include <rte_devargs.h> > > > +#include <rte_kvargs.h> > > > +#include <rte_alarm.h> > > > + > > > +#include "rte_bus_ifpga.h" > > > +#include "ifpga_logs.h" > > > +#include "ifpga_common.h" > > > + > > > +int rte_ifpga_get_string_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args) { > > > + if (!value || !extra_args) > > > + return -EINVAL; > > > + > > > + *(char **)extra_args = strdup(value); > > > + > > > + if (!*(char **)extra_args) > > > + return -ENOMEM; > > > + > > > + return 0; > > > +} > > > +int rte_ifpga_get_integer32_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args) { > > > + if (!value || !extra_args) > > > + return -EINVAL; > > > + > > > + *(int *)extra_args = strtoull(value, NULL, 0); > > > + > > > + return 0; > > > +} > > > +int ifpga_get_integer64_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args) { > > > + if (!value || !extra_args) > > > + return -EINVAL; > > > + > > > + *(uint64_t *)extra_args = strtoull(value, NULL, 0); > > > + > > > + return 0; > > > +} > > > +int ifpga_get_unsigned_long(const char *str, int base) { > > > + unsigned long num; > > > + char *end = NULL; > > > + > > > + errno = 0; > > > + > > > + num = strtoul(str, &end, base); > > > + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) > > > + return -1; > > > + > > > + return num; > > > +} > > > + > > > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > > + const struct rte_afu_id *afu_id1) > > > +{ > > > + if ((afu_id0->uuid.uuid_low == afu_id1->uuid.uuid_low) && > > > + (afu_id0->uuid.uuid_high == afu_id1->uuid.uuid_high) && > > > + (afu_id0->port == afu_id1->port)) { > > > + return 0; > > > + } else > > > + return 1; > > > +} > > > diff --git a/drivers/bus/ifpga/ifpga_common.h > > > b/drivers/bus/ifpga/ifpga_common.h > > > new file mode 100644 > > > index 0000000..f9254b9 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/ifpga_common.h > > > @@ -0,0 +1,18 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > + > > > +#ifndef _IFPGA_COMMON_H_ > > > +#define _IFPGA_COMMON_H_ > > > + > > > +int rte_ifpga_get_string_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args); int > > > +rte_ifpga_get_integer32_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args); int > > > +ifpga_get_integer64_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args); int > > > +ifpga_get_unsigned_long(const char *str, int base); int > > > +ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > > + const struct rte_afu_id *afu_id1); > > > + > > > +#endif /* _IFPGA_COMMON_H_ */ > > > diff --git a/drivers/bus/ifpga/ifpga_logs.h > > > b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index > > > 0000000..873e0a4 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/ifpga_logs.h > > > @@ -0,0 +1,31 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > + > > > +#ifndef _IFPGA_LOGS_H_ > > > +#define _IFPGA_LOGS_H_ > > > + > > > +#include <rte_log.h> > > > + > > > +extern int ifpga_bus_logtype; > > > + > > > +#define IFPGA_LOG(level, fmt, args...) \ > > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > > + __func__, ##args) > > > + > > > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > > + __func__, ##args) > > > + > > > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > > > + > > > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > > > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) #define IFPGA_BUS_INFO(fmt, > > > +args...) \ > > > + IFPGA_BUS_LOG(INFO, fmt, ## args) > > > +#define IFPGA_BUS_ERR(fmt, args...) \ > > > + IFPGA_BUS_LOG(ERR, fmt, ## args) > > > +#define IFPGA_BUS_WARN(fmt, args...) \ > > > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > > > + > > > +#endif /* _IFPGA_BUS_LOGS_H_ */ > > > diff --git a/drivers/bus/ifpga/meson.build > > > b/drivers/bus/ifpga/meson.build new file mode 100644 index > > > 0000000..c9b08c8 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/meson.build > > > @@ -0,0 +1,8 @@ > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2010-2018 > > > +Intel Corporation > > > + > > > +deps += ['pci', 'kvargs', 'rawdev'] > > > +install_headers('rte_bus_ifpga.h') > > > +sources = files('ifpga_common.c', 'ifpga_bus.c') > > > + > > > +allow_experimental_apis = true > > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h > > > b/drivers/bus/ifpga/rte_bus_ifpga.h > > > new file mode 100644 > > > index 0000000..5c559e1 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > > > @@ -0,0 +1,160 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > + > > > +#ifndef _RTE_BUS_IFPGA_H_ > > > +#define _RTE_BUS_IFPGA_H_ > > > + > > > +/** > > > + * @file > > > + * > > > + * RTE Intel FPGA Bus Interface > > > + */ > > > + > > > +#ifdef __cplusplus > > > +extern "C" { > > > +#endif > > > + > > > +#include <rte_bus.h> > > > +#include <rte_pci.h> > > > + > > > +/** Name of Intel FPGA Bus */ > > > +#define IFPGA_BUS_NAME ifpga > > > + > > > +/* Forward declarations */ > > > +struct rte_afu_device; > > > + > > > +/** List of Intel AFU devices */ > > > +TAILQ_HEAD(afu_device_list, rte_afu_device); > > > +/** Double linked list of AFU device drivers. */ > > > +TAILQ_HEAD(afu_driver_list, rte_afu_driver); > > > + > > > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > > > + > > > +struct rte_afu_uuid { > > > + uint64_t uuid_low; > > > + uint64_t uuid_high; > > > +} __attribute__ ((packed)); > > > + > > > +#define IFPGA_BUS_DEV_PORT_MAX 4 > > > + > > > +/** > > > + * A structure describing an ID for a AFU driver. Each driver > > > +provides a > > > + * table of these IDs for each device that it supports. > > > + */ > > > +struct rte_afu_id { > > > + struct rte_afu_uuid uuid; > > > + int port; /**< port number */ > > > +} __attribute__ ((packed)); > > > + > > > +/** > > > + * A structure PR (Partial Reconfiguration) configuration AFU driver. > > > + */ > > > + > > > +struct rte_afu_pr_conf { > > > + struct rte_afu_id afu_id; > > > + int pr_enable; > > > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > > +}; > > > + > > > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > > > + > > > +/** > > > + * A structure describing a fpga device. > > > + */ > > > +struct rte_ifpga_device { > > > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ > > > + struct rte_rawdev *rdev; > > > + struct afu_device_list afu_list; /**< List of AFU devices */ }; > > > + > > > +/** > > > + * A structure describing a AFU device. > > > + */ > > > +struct rte_afu_device { > > > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ > > > + struct rte_device device; /**< Inherit core device */ > > > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > > > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > > > + struct rte_afu_id id; /**< AFU id within FPGA. */ > > > + uint32_t num_region; /**< number of regions found */ > > > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > > > + /**< AFU Memory Resource > > */ > > > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > > > + struct rte_afu_driver *driver; /**< Associated driver */ > > > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > > +} __attribute__ ((packed)); > > > + > > > +/** > > > + * @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_DRV_TO_AFU_CONST(ptr) \ > > > + container_of(ptr, const struct rte_afu_driver, driver) > > > + > > > +/** > > > + * Initialisation function for the driver called during FPGA BUS probing. > > > > > > typo: Initialization > > Fixed. > > > > + */ > > > +typedef int (afu_probe_t)(struct rte_afu_device *); > > > + > > > +/** > > > + * Uninitialisation function for the driver called during hotplugging. > > > > typo: Unintialization > > Fixed. > > > > + */ > > > +typedef int (afu_remove_t)(struct rte_afu_device *); > > > + > > > +/** > > > + * A structure describing a AFU device. > > > + */ > > > +struct rte_afu_driver { > > > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > > > + struct rte_driver driver; /**< Inherit core driver. */ > > > + afu_probe_t *probe; /**< Device Probe function. > > > */ > > > + afu_remove_t *remove; /**< Device Remove > > > function. */ > > > + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ > > > + uint32_t drv_flags; /**< Flags contolling handling of device. */ > > > > Typo Controlling > > And what is "flags controlling handling of device?" > > This variable is not used, so I have removed it. > > > > +}; > > > + > > > +static inline const char * > > > +rte_ifpga_device_name(const struct rte_afu_device *afu) { > > > + if (afu && afu->device.name) > > > + return afu->device.name; > > > + return NULL; > > > +} > > > + > > > +/** > > > + * Register a ifpga afu device driver. > > > + * > > > + * @param driver > > > + * A pointer to a rte_afu_driver structure describing the driver > > > + * to be registered. > > > + */ > > > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); > > > + > > > +/** > > > + * Unregister a ifpga afu device driver. > > > + * > > > + * @param driver > > > + * A pointer to a rte_afu_driver structure describing the driver > > > + * to be unregistered. > > > + */ > > > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > > > + > > > +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ RTE_INIT(afudrvinitfn_ > > > +##afudrv);\ static const char *afudrvinit_ ## nm ## _alias;\ static > > > +void afudrvinitfn_ ##afudrv(void)\ {\ > > > + (afudrv).driver.name = RTE_STR(nm);\ > > > + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ > > > + rte_ifpga_driver_register(&afudrv);\ > > > +} \ > > > +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) > > > + > > > +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ static const char > > > +*afudrvinit_ ## nm ## _alias = RTE_STR(alias) > > > + > > > +#endif /* _RTE_BUS_IFPGA_H_ */ > > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > new file mode 100644 > > > index 0000000..a027979 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > @@ -0,0 +1,10 @@ > > > +DPDK_18.05 { > > > + global: > > > + > > > + rte_ifpga_get_integer32_arg; > > > + rte_ifpga_get_string_arg; > > > + rte_ifpga_driver_register; > > > + rte_ifpga_driver_unregister; > > > + > > > + local: *; > > > +}; > > > diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build index > > > 58dfbe2..52c755d 100644 > > > --- a/drivers/bus/meson.build > > > +++ b/drivers/bus/meson.build > > > @@ -1,7 +1,7 @@ > > > # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel > > > Corporation > > > > > > -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] > > > +drivers = ['dpaa', 'fslmc', 'ifpga', 'pci', 'vdev'] > > > std_deps = ['eal'] > > > config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' > > > driver_name_fmt = 'rte_bus_@0@' > > > diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 26f3563..3861e1a > > > 100644 > > > --- a/mk/rte.app.mk > > > +++ b/mk/rte.app.mk > > > @@ -255,6 +255,7 @@ ifeq > > > ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) > > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += > > > -lrte_pmd_dpaa2_cmdif > > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += > > > -lrte_pmd_dpaa2_qdma endif # CONFIG_RTE_LIBRTE_FSLMC_BUS > > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga > > > endif # CONFIG_RTE_LIBRTE_RAWDEV > > > > > > > > > -- > > > 1.8.3.1 > > > > Regards > > Qi ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-10 13:48 ` Zhang, Qi Z @ 2018-05-10 13:58 ` Xu, Rosen 2018-05-10 14:11 ` Zhang, Qi Z 0 siblings, 1 reply; 149+ messages in thread From: Xu, Rosen @ 2018-05-10 13:58 UTC (permalink / raw) To: Zhang, Qi Z, dev, thomas Cc: Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet Hi Qi, > -----Original Message----- > From: Zhang, Qi Z > Sent: Thursday, May 10, 2018 21:49 > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; thomas@monjalon.net > Cc: Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, Declan > <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > Library > > > > > -----Original Message----- > > From: Xu, Rosen > > Sent: Thursday, May 10, 2018 9:29 PM > > To: Zhang, Qi Z <qi.z.zhang@intel.com>; dev@dpdk.org; > > thomas@monjalon.net > > Cc: Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, Declan > > <declan.doherty@intel.com>; Richardson, Bruce > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > > <ferruh.yigit@intel.com>; Ananyev, Konstantin > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > > Library > > > > Hi Qi, > > > > > -----Original Message----- > > > From: Zhang, Qi Z > > > Sent: Thursday, May 10, 2018 20:27 > > > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; > > thomas@monjalon.net > > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > > <roy.fan.zhang@intel.com>; Doherty, Declan > > > <declan.doherty@intel.com>; Richardson, Bruce > > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > > > <ferruh.yigit@intel.com>; Ananyev, Konstantin > > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA > > > BUS Library > > > > > > Hi Rosen: > > > > > > > -----Original Message----- > > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > > > > Sent: Wednesday, May 9, 2018 3:43 PM > > > > To: dev@dpdk.org; thomas@monjalon.net > > > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > > > <roy.fan.zhang@intel.com>; Doherty, Declan > > > > <declan.doherty@intel.com>; Richardson, Bruce > > > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, > > > > Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > > > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > > > Subject: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > > > > Library > > > > > > > > From: Rosen Xu <rosen.xu@intel.com> > > > > > > > > Defined FPGA-BUS for Acceleration Drivers of AFUs > > > > > > > > 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan > > > > Process, probe Intel FPGA Rawdev Driver, it will be covered in following > patches. > > > > > > > > 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. > > > > This scan is trigged by hotplug of IFPGA Rawdev probe, in this > > > > scan the AFUs will be created and their drivers are also probed. > > > > > > > > This patch will introduce rte_afu_device which describe the AFU > > > > device listed in the FPGA-BUS. > > > > > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > > > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > > > > --- > > > > MAINTAINERS | 4 + > > > > config/common_base | 5 + > > > > doc/guides/rel_notes/release_18_05.rst | 5 + > > > > drivers/bus/Makefile | 1 + > > > > drivers/bus/ifpga/Makefile | 32 ++ > > > > drivers/bus/ifpga/ifpga_bus.c | 501 > > > > ++++++++++++++++++++++++++++ > > > > drivers/bus/ifpga/ifpga_common.c | 88 +++++ > > > > drivers/bus/ifpga/ifpga_common.h | 18 + > > > > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > > > > drivers/bus/ifpga/meson.build | 8 + > > > > drivers/bus/ifpga/rte_bus_ifpga.h | 160 +++++++++ > > > > drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + > > > > drivers/bus/meson.build | 2 +- > > > > mk/rte.app.mk | 1 + > > > > 14 files changed, 865 insertions(+), 1 deletion(-) create mode > > > > 100644 drivers/bus/ifpga/Makefile create mode 100644 > > > > drivers/bus/ifpga/ifpga_bus.c create mode 100644 > > > > drivers/bus/ifpga/ifpga_common.c create mode 100644 > > > > drivers/bus/ifpga/ifpga_common.h create mode 100644 > > > > drivers/bus/ifpga/ifpga_logs.h create mode 100644 > > > > drivers/bus/ifpga/meson.build create mode 100644 > > > > drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 > > > > drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > > > > > diff --git a/MAINTAINERS b/MAINTAINERS index 7105920..fa0c5b1 > > > > 100644 > > > > --- a/MAINTAINERS > > > > +++ b/MAINTAINERS > > > > @@ -383,6 +383,10 @@ F: drivers/mempool/bucket/ Bus Drivers > > > > ----------- > > > > > > > > +Intel FPGA buses > > > > +M: Rosen Xu <rosen.xu@intel.com> > > > > +F: drivers/bus/ifpga/ > > > > + > > > > NXP buses > > > > M: Hemant Agrawal <hemant.agrawal@nxp.com> > > > > M: Shreyansh Jain <shreyansh.jain@nxp.com> diff --git > > > > a/config/common_base b/config/common_base index > 0d181ac..1440316 > > > > 100644 > > > > --- a/config/common_base > > > > +++ b/config/common_base > > > > @@ -139,6 +139,11 @@ > > > > CONFIG_RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS=n > > > > CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n > > > > > > > > # > > > > +# Compile the Intel FPGA bus > > > > +# > > > > +CONFIG_RTE_LIBRTE_IFPGA_BUS=y > > > > + > > > > +# > > > > # Compile PCI bus driver > > > > # > > > > CONFIG_RTE_LIBRTE_PCI_BUS=y > > > > diff --git a/doc/guides/rel_notes/release_18_05.rst > > > > b/doc/guides/rel_notes/release_18_05.rst > > > > index 7187348..265950a 100644 > > > > --- a/doc/guides/rel_notes/release_18_05.rst > > > > +++ b/doc/guides/rel_notes/release_18_05.rst > > > > @@ -183,6 +183,11 @@ New Features > > > > stats/xstats on shared memory from secondary process, and also > > > > pdump packets on > > > > those virtual devices. > > > > > > > > +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** > > > > + > > > > + The Ifpga Bus library provides support for integrating any > > > > + Intel FPGA device with the DPDK framework. It provides Intel > > > > + FPGA Partial Bit Stream AFU(Accelerated Function Unit) scan and > > > > + drivers > > prove. > > > > > > > > API Changes > > > > ----------- > > > > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index > > > > c251b65..ef7f247 100644 > > > > --- a/drivers/bus/Makefile > > > > +++ b/drivers/bus/Makefile > > > > @@ -7,6 +7,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa > ifeq > > > > ($(CONFIG_RTE_EAL_VFIO),y) > > > > DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc endif > > > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > > > > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > > > > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > > > > > > > > diff --git a/drivers/bus/ifpga/Makefile > > > > b/drivers/bus/ifpga/Makefile new file mode 100644 index > > > > 0000000..3ff3bdb > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/Makefile > > > > @@ -0,0 +1,32 @@ > > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > > > > +Corporation > > > > + > > > > +include $(RTE_SDK)/mk/rte.vars.mk > > > > + > > > > +# > > > > +# library name > > > > +# > > > > +LIB = librte_bus_ifpga.a > > > > + > > > > +CFLAGS += -DALLOW_EXPERIMENTAL_API CFLAGS += -O3 CFLAGS += > > > > +$(WERROR_FLAGS) LDLIBS += -lrte_eal LDLIBS += -lrte_rawdev LDLIBS > > > > ++= -lrte_kvargs > > > > + > > > > +# versioning export map > > > > +EXPORT_MAP := rte_bus_ifpga_version.map > > > > + > > > > +# library version > > > > +LIBABIVER := 1 > > > > + > > > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c > > > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c > > > > + > > > > +# > > > > +# Export include files > > > > +# > > > > +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += > rte_bus_ifpga.h > > > > + > > > > +include $(RTE_SDK)/mk/rte.lib.mk > > > > diff --git a/drivers/bus/ifpga/ifpga_bus.c > > > > b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index > > > > 0000000..e144c01 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/ifpga_bus.c > > > > @@ -0,0 +1,501 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > + > > > > +#include <string.h> > > > > +#include <inttypes.h> > > > > +#include <stdint.h> > > > > +#include <stdlib.h> > > > > +#include <stdio.h> > > > > +#include <sys/queue.h> > > > > +#include <sys/mman.h> > > > > +#include <sys/types.h> > > > > +#include <unistd.h> > > > > +#include <fcntl.h> > > > > + > > > > +#include <rte_errno.h> > > > > +#include <rte_bus.h> > > > > +#include <rte_per_lcore.h> > > > > +#include <rte_memory.h> > > > > +#include <rte_memzone.h> > > > > +#include <rte_eal.h> > > > > +#include <rte_common.h> > > > > + > > > > +#include <rte_devargs.h> > > > > +#include <rte_kvargs.h> > > > > +#include <rte_alarm.h> > > > > + > > > > +#include "rte_rawdev.h" > > > > +#include "rte_rawdev_pmd.h" > > > > +#include "rte_bus_ifpga.h" > > > > +#include "ifpga_logs.h" > > > > +#include "ifpga_common.h" > > > > + > > > > +int ifpga_bus_logtype; > > > > + > > > > +/* Forward declaration to access Intel FPGA bus > > > > + * on which iFPGA devices are connected */ static struct rte_bus > > > > +rte_ifpga_bus; > > > > + > > > > +/** Double linked list of IFPGA device. */ > > > > +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); > > > > + > > > > +static struct ifpga_device_list ifpga_device_list = > > > > + TAILQ_HEAD_INITIALIZER(ifpga_device_list); > > > > +static struct afu_driver_list afu_driver_list = > > > > + TAILQ_HEAD_INITIALIZER(afu_driver_list); > > > > + > > > > + > > > > +/* register a ifpga bus based driver */ void > > > > +rte_ifpga_driver_register(struct rte_afu_driver *driver) { > > > > + RTE_VERIFY(driver); > > > > + > > > > + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); } > > > > + > > > > +/* un-register a fpga bus based driver */ void > > > > +rte_ifpga_driver_unregister(struct rte_afu_driver *driver) { > > > > + TAILQ_REMOVE(&afu_driver_list, driver, next); } > > > > + > > > > +static struct rte_ifpga_device * > > > > +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) { > > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > > + > > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > > + if (rdev && > > > > + ifpga_dev->rdev && > > > > + ifpga_dev->rdev == rdev) > > > > + return ifpga_dev; > > > > + } > > > > + return NULL; > > > > +} > > > > + > > > > +static struct rte_afu_device * > > > > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > > > > + const struct rte_afu_id *afu_id) { > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + > > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > > > > + return afu_dev; > > > > + } > > > > + return NULL; > > > > +} > > > > + > > > > +static const char * const valid_args[] = { > > > > +#define IFPGA_ARG_NAME "ifpga" > > > > + IFPGA_ARG_NAME, > > > > +#define IFPGA_ARG_PORT "port" > > > > + IFPGA_ARG_PORT, > > > > +#define IFPGA_AFU_BTS "afu_bts" > > > > + IFPGA_AFU_BTS, > > > > + NULL > > > > +}; > > > > + > > > > +/* > > > > + * Scan the content of the FPGA bus, and the devices in the > > > > +devices > > > > + * list > > > > + */ > > > > +static struct rte_afu_device * > > > > +ifpga_scan_one(struct rte_devargs *devargs, > > > > + struct rte_ifpga_device *ifpga_dev) > > > > > > usually ifpag_dev should be the first parameter here, and devargs > > > follows > > > > Fixed. > > > > > > +{ > > > > + struct rte_kvargs *kvlist = NULL; > > > > + struct rte_rawdev *rawdev = NULL; > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + struct rte_afu_pr_conf afu_pr_conf; > > > > + int ret = 0; > > > > + char *path = NULL; > > > > + > > > > + memset(&afu_pr_conf, 0, sizeof(struct rte_afu_pr_conf)); > > > > + > > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > > + if (!kvlist) { > > > > + IFPGA_BUS_ERR("error when parsing param"); > > > > + goto end; > > > > + } > > > > + > > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, > > > > + &rte_ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) > > > { > > > > + IFPGA_BUS_ERR("error to parse %s", > > > > + IFPGA_ARG_PORT); > > > > + goto end; > > > > + } > > > > + } else { > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > + IFPGA_ARG_PORT); > > > > + goto end; > > > > + } > > > > + > > > > + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { > > > > + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, > > > > + &rte_ifpga_get_string_arg, &path) < 0) { > > > > + IFPGA_BUS_ERR("Failed to parse %s", > > > > + IFPGA_AFU_BTS); > > > > + goto end; > > > > + } > > > > + } else { > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > + IFPGA_AFU_BTS); > > > > + goto end; > > > > + } > > > > + > > > > + afu_pr_conf.afu_id.uuid.uuid_low = 0; > > > > + afu_pr_conf.afu_id.uuid.uuid_high = 0; > > > > + afu_pr_conf.pr_enable = path?1:0; > > > > + > > > > + rawdev = ifpga_dev->rdev; > > > > + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) > > > > + goto end; > > > > + > > > > + afu_dev = calloc(1, sizeof(*afu_dev)); > > > > + if (!afu_dev) > > > > + goto end; > > > > + > > > > + afu_dev->device.devargs = devargs; > > > > + afu_dev->device.numa_node = SOCKET_ID_ANY; > > > > + afu_dev->device.name = devargs->name; > > > > + afu_dev->rawdev = rawdev; > > > > + afu_dev->id.uuid.uuid_low = 0; > > > > + afu_dev->id.uuid.uuid_high = 0; > > > > + afu_dev->id.port = afu_pr_conf.afu_id.port; > > > > + afu_dev->ifpga_dev = ifpga_dev; > > > > + > > > > + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) > > > > + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); > > > > + > > > > + if (rawdev->dev_ops && > > > > + rawdev->dev_ops->dev_start && > > > > + rawdev->dev_ops->dev_start(rawdev)) > > > > + goto free_dev; > > > > + > > > > + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); > > > > + if (rawdev->dev_ops->firmware_load && > > > > + rawdev->dev_ops->firmware_load(rawdev, > > > > + &afu_pr_conf)){ > > > > + IFPGA_BUS_ERR("firmware load error %d\n", ret); > > > > + goto free_dev; > > > > + } > > > > + afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; > > > > + afu_dev->id.uuid.uuid_high = afu_pr_conf.afu_id.uuid.uuid_high; > > > > + > > > > + return afu_dev; > > > > + > > > > +free_dev: > > > > + free(afu_dev); > > > > +end: > > > > + if (kvlist) > > > > + rte_kvargs_free(kvlist); > > > > + if (path) > > > > + free(path); > > > > + > > > > + return NULL; > > > > +} > > > > + > > > > +/* > > > > + * Scan the content of the FPGA bus, and the devices in the > > > > +devices > > > > + * list > > > > + */ > > > > +static int > > > > +ifpga_scan(void) > > > > +{ > > > > + struct rte_ifpga_device *ifpga_dev; > > > > + struct rte_devargs *devargs; > > > > + struct rte_kvargs *kvlist = NULL; > > > > + struct rte_rawdev *rawdev = NULL; > > > > + char *name = NULL; > > > > + char name1[RTE_RAWDEV_NAME_MAX_LEN]; > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + > > > > + /* for FPGA devices we scan the devargs_list populated via > > > > +cmdline */ > > > > > > I didn't see "--ifpga" is supported by cmdline, either you need to > > > add corresponding parser or correct the comment here. > > > > To be honestly, ifpga_scan() is called by hotplug, lib_rte hotplug > > function will construct it. > > OK, after review patch 3, I saw it, that make sense. > > > > > > + RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { > > > > > > > > > IFPGA_BUS_NAME to replace "ifpga" here. > > > > > > > + if (devargs->bus != &rte_ifpga_bus) > > > > + continue; > > > > + > > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > > + if (!kvlist) { > > > > + IFPGA_BUS_ERR("error when parsing param"); > > > > + goto end; > > > > + } > > > > + > > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { > > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, > > > > + &rte_ifpga_get_string_arg, &name) < 0) { > > > > + IFPGA_BUS_ERR("error to parse %s", > > > > + IFPGA_ARG_NAME); > > > > + goto end; > > > > + } > > > > + } else { > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > + IFPGA_ARG_NAME); > > > > + goto end; > > > > + } > > > > + > > > > + memset(name1, 0, sizeof(name1)); > > > > + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, > > > "IFPGA:%s", > > > > name); > > > > + > > > > + rawdev = rte_rawdev_pmd_get_named_dev(name1); > > > > + if (!rawdev) > > > > + goto end; > > > > + > > > > + if (ifpga_find_ifpga_dev(rawdev)) > > > > + continue; > > > > + > > > > + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); > > > > + if (!ifpga_dev) > > > > + goto end; > > > > + > > > > + ifpga_dev->rdev = rawdev; > > > > + TAILQ_INIT(&ifpga_dev->afu_list); > > > > + > > > > + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); > > > > + afu_dev = ifpga_scan_one(devargs, ifpga_dev); > > > > + if (afu_dev != NULL) > > > > + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, > > > next); > > > > > > I don't understand why we need afu_list?, seems we only add a new > > > afu_dev into the list after create a new ifpga_dev, Is there any > > > another place that we add one to list to make it reasonable? it > > > looks like either a 1:1 or 1:0 for ifpga_dev:afu_dev? > > > > One FPAG may support more than one AFU. > > But in your implementation, it is not possible that an ifpga_dev contains > multiple afu_dev All afu_devs are listed to ifpga_dev, and each afu_dev can be added and deleted by user. > > > > > > + } > > > > + > > > > +end: > > > > + if (kvlist) > > > > + rte_kvargs_free(kvlist); > > > > + if (name) > > > > + free(name); > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +/* > > > > + * Match the AFU Driver and AFU Device using the ID Table */ > > > > +static int rte_afu_match(const struct rte_afu_driver *afu_drv, > > > > + const struct rte_afu_device *afu_dev) { > > > > + const struct rte_afu_uuid *id_table; > > > > + > > > > + for (id_table = afu_drv->id_table; > > > > + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); > > > > + id_table++) { > > > > + /* check if device's identifiers match the driver's ones */ > > > > + if ((id_table->uuid_low != afu_dev->id.uuid.uuid_low) || > > > > + id_table->uuid_high != > > > > + afu_dev->id.uuid.uuid_high) > > > > + continue; > > > > + > > > > + return 1; > > > > + } > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int > > > > +ifpga_probe_one_driver(struct rte_afu_driver *drv, > > > > + struct rte_afu_device *afu_dev) { > > > > + int ret; > > > > + > > > > + if (!rte_afu_match(drv, afu_dev)) > > > > + /* Match of device and driver failed */ > > > > + return 1; > > > > + > > > > + /* reference driver structure */ > > > > + afu_dev->driver = drv; > > > > + afu_dev->device.driver = &drv->driver; > > > > + > > > > + /* call the driver probe() function */ > > > > + ret = drv->probe(afu_dev); > > > > + if (ret) { > > > > + afu_dev->driver = NULL; > > > > + afu_dev->device.driver = NULL; > > > > + } > > > > + > > > > + return ret; > > > > +} > > > > + > > > > +static int > > > > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) { > > > > + struct rte_afu_driver *drv = NULL; > > > > + int ret = 0; > > > > + > > > > + if (afu_dev == NULL) > > > > + return -1; > > > > + > > > > + /* Check if a driver is already loaded */ > > > > + if (afu_dev->driver != NULL) > > > > + return 0; > > > > + > > > > + TAILQ_FOREACH(drv, &afu_driver_list, next) { > > > > + if (ifpga_probe_one_driver(drv, afu_dev)) { > > > > + ret = -1; > > > > + break; > > > > + } > > > > + } > > > > + return ret; > > > > +} > > > > + > > > > +/* > > > > + * Scan the content of the Intel FPGA bus, and call the probe() > > > > +function for > > > > + * all registered drivers that have a matching entry in its > > > > +id_table > > > > + * for discovered devices. > > > > + */ > > > > +static int > > > > +ifpga_probe(void) > > > > +{ > > > > + struct rte_ifpga_device *ifpga_dev; > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + int ret = 0; > > > > + > > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > > + > > > > + if (afu_dev->device.driver) > > > > + continue; > > > > + > > > > + ret = ifpga_probe_all_drivers(afu_dev); > > > > + if (ret < 0) > > > > + IFPGA_BUS_ERR("failed to initialize %s > > > device\n", > > > > + rte_ifpga_device_name(afu_dev)); > > > > + } > > > > + } > > > > + > > > > + return ret; > > > > +} > > > > + > > > > +static int > > > > +ifpga_plug(struct rte_device *dev) { > > > > + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); > > > > +} > > > > + > > > > +static int > > > > +ifpga_remove_driver(struct rte_afu_device *afu_dev) { > > > > + const char *name; > > > > + const struct rte_afu_driver *driver; > > > > + > > > > + name = rte_ifpga_device_name(afu_dev); > > > > + if (!afu_dev->device.driver) { > > > > + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); > > > > + return 1; > > > > + } > > > > + > > > > + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); > > > > + return driver->remove(afu_dev); > > > > +} > > > > + > > > > +static int > > > > +ifpga_unplug(struct rte_device *dev) { > > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + struct rte_devargs *devargs = NULL; > > > > + int ret; > > > > + > > > > + if (dev == NULL) > > > > + return -EINVAL; > > > > + > > > > + afu_dev = RTE_DEV_TO_AFU(dev); > > > > + if (!dev) > > > > + return -ENOENT; > > > > + > > > > + ifpga_dev = afu_dev->ifpga_dev; > > > > + devargs = dev->devargs; > > > > + > > > > + ret = ifpga_remove_driver(afu_dev); > > > > > > So what is the device type that be plugged into the ifgpa bus? > > > ifpga_dev or afu_dev? If its afu_dev, why we need ifpga_dev? > > > If it is ifpga_dev, we need remove ifpga_dev from ifpga_device_list here. > > > > The device type that be plugged into the ifpga bus is afu_dev. > > In DPDK, we have rte_pci_device for pci bus and rte_vdev_device for vdev > bus Now we have rte_ifpga_device not for ifgpa bus but rte_afu_device, it is > a little bit confuse here The relationship of this items is descripted in ifpga_rawdev.rst. > > And each afu_dev will be added into one ifpga_dev. > > Each FPGA device bind to ifpga_dev. > > So what is the relationship between ifpga_dev and raw_dev? One FPGA as a PCI device will probe ifpga_rawdev. For management afu_dev, we create ifpga_dev in ifpga_bus. > > > > > > + if (ret) > > > > + return ret; > > > > + > > > > + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); > > > > + > > > > + rte_devargs_remove(devargs->bus->name, devargs->name); > > > > + free(afu_dev); > > > > + return 0; > > > > + > > > > +} > > > > + > > > > +static struct rte_device * > > > > +ifpga_find_device(const struct rte_device *start, > > > > + rte_dev_cmp_t cmp, const void *data) { > > > > + struct rte_ifpga_device *ifpga_dev; > > > > + struct rte_afu_device *afu_dev; > > > > + > > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > > + if (start && &afu_dev->device == start) { > > > > + start = NULL; > > > > + continue; > > > > + } > > > > + if (cmp(&afu_dev->device, data) == 0) > > > > + return &afu_dev->device; > > > > + } > > > > + } > > > > + return NULL; > > > > +} > > > > +static int > > > > +ifpga_parse(const char *name, void *addr) { > > > > + int *out = addr; > > > > + struct rte_rawdev *rawdev = NULL; > > > > + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; > > > > + char *c1 = NULL, *c2 = NULL; > > > > + int port = IFPGA_BUS_DEV_PORT_MAX; > > > > + char str_port[8]; > > > > + int str_port_len = 0; > > > > + int ret; > > > > + > > > > + memset(str_port, 0, 8); > > > > + c1 = strchr(name, '|'); > > > > + if (c1 != NULL) { > > > > + str_port_len = c1-name; > > > > + c2 = c1+1; > > > > + } > > > > + > > > > + if (str_port_len < 8 && > > > > + str_port_len > 0) { > > > > + memcpy(str_port, name, str_port_len); > > > > + ret = sscanf(str_port, "%d", &port); > > > > + if (ret == -1) > > > > + return 0; > > > > + } > > > > + > > > > + memset(rawdev_name, 0, sizeof(rawdev_name)); > > > > + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", > > > c2); > > > > + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); > > > > + > > > > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > > > > + rawdev && > > > > + (addr != NULL)) > > > > + *out = port; > > > > + > > > > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > > > > + rawdev) > > > > + return 0; > > > > + else > > > > + return 1; > > > > +} > > > > + > > > > +static struct rte_bus rte_ifpga_bus = { > > > > + .scan = ifpga_scan, > > > > + .probe = ifpga_probe, > > > > + .find_device = ifpga_find_device, > > > > + .plug = ifpga_plug, > > > > + .unplug = ifpga_unplug, > > > > + .parse = ifpga_parse, > > > > +}; > > > > + > > > > +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); > > > > + > > > > +RTE_INIT(ifpga_init_log) > > > > +{ > > > > + ifpga_bus_logtype = rte_log_register("bus.ifpga"); > > > > + if (ifpga_bus_logtype >= 0) > > > > + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); } > > > > diff --git a/drivers/bus/ifpga/ifpga_common.c > > > > b/drivers/bus/ifpga/ifpga_common.c > > > > new file mode 100644 > > > > index 0000000..78e2eae > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/ifpga_common.c > > > > @@ -0,0 +1,88 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > + > > > > +#include <string.h> > > > > +#include <inttypes.h> > > > > +#include <stdint.h> > > > > +#include <stdlib.h> > > > > +#include <stdio.h> > > > > +#include <sys/queue.h> > > > > +#include <sys/mman.h> > > > > +#include <sys/types.h> > > > > +#include <unistd.h> > > > > +#include <fcntl.h> > > > > + > > > > +#include <rte_errno.h> > > > > +#include <rte_bus.h> > > > > +#include <rte_per_lcore.h> > > > > +#include <rte_memory.h> > > > > +#include <rte_memzone.h> > > > > +#include <rte_eal.h> > > > > +#include <rte_common.h> > > > > + > > > > +#include <rte_devargs.h> > > > > +#include <rte_kvargs.h> > > > > +#include <rte_alarm.h> > > > > + > > > > +#include "rte_bus_ifpga.h" > > > > +#include "ifpga_logs.h" > > > > +#include "ifpga_common.h" > > > > + > > > > +int rte_ifpga_get_string_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args) { > > > > + if (!value || !extra_args) > > > > + return -EINVAL; > > > > + > > > > + *(char **)extra_args = strdup(value); > > > > + > > > > + if (!*(char **)extra_args) > > > > + return -ENOMEM; > > > > + > > > > + return 0; > > > > +} > > > > +int rte_ifpga_get_integer32_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args) { > > > > + if (!value || !extra_args) > > > > + return -EINVAL; > > > > + > > > > + *(int *)extra_args = strtoull(value, NULL, 0); > > > > + > > > > + return 0; > > > > +} > > > > +int ifpga_get_integer64_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args) { > > > > + if (!value || !extra_args) > > > > + return -EINVAL; > > > > + > > > > + *(uint64_t *)extra_args = strtoull(value, NULL, 0); > > > > + > > > > + return 0; > > > > +} > > > > +int ifpga_get_unsigned_long(const char *str, int base) { > > > > + unsigned long num; > > > > + char *end = NULL; > > > > + > > > > + errno = 0; > > > > + > > > > + num = strtoul(str, &end, base); > > > > + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) > > > > + return -1; > > > > + > > > > + return num; > > > > +} > > > > + > > > > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > > > + const struct rte_afu_id *afu_id1) { > > > > + if ((afu_id0->uuid.uuid_low == afu_id1->uuid.uuid_low) && > > > > + (afu_id0->uuid.uuid_high == afu_id1->uuid.uuid_high) && > > > > + (afu_id0->port == afu_id1->port)) { > > > > + return 0; > > > > + } else > > > > + return 1; > > > > +} > > > > diff --git a/drivers/bus/ifpga/ifpga_common.h > > > > b/drivers/bus/ifpga/ifpga_common.h > > > > new file mode 100644 > > > > index 0000000..f9254b9 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/ifpga_common.h > > > > @@ -0,0 +1,18 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > + > > > > +#ifndef _IFPGA_COMMON_H_ > > > > +#define _IFPGA_COMMON_H_ > > > > + > > > > +int rte_ifpga_get_string_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args); int > > > > +rte_ifpga_get_integer32_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args); int > > > > +ifpga_get_integer64_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args); int > > > > +ifpga_get_unsigned_long(const char *str, int base); int > > > > +ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > > > + const struct rte_afu_id *afu_id1); > > > > + > > > > +#endif /* _IFPGA_COMMON_H_ */ > > > > diff --git a/drivers/bus/ifpga/ifpga_logs.h > > > > b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index > > > > 0000000..873e0a4 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/ifpga_logs.h > > > > @@ -0,0 +1,31 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > + > > > > +#ifndef _IFPGA_LOGS_H_ > > > > +#define _IFPGA_LOGS_H_ > > > > + > > > > +#include <rte_log.h> > > > > + > > > > +extern int ifpga_bus_logtype; > > > > + > > > > +#define IFPGA_LOG(level, fmt, args...) \ > > > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > > > + __func__, ##args) > > > > + > > > > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > > > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > > > + __func__, ##args) > > > > + > > > > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > > > > + > > > > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > > > > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) #define IFPGA_BUS_INFO(fmt, > > > > +args...) \ > > > > + IFPGA_BUS_LOG(INFO, fmt, ## args) #define IFPGA_BUS_ERR(fmt, > > > > +args...) \ > > > > + IFPGA_BUS_LOG(ERR, fmt, ## args) #define IFPGA_BUS_WARN(fmt, > > > > +args...) \ > > > > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > > > > + > > > > +#endif /* _IFPGA_BUS_LOGS_H_ */ > > > > diff --git a/drivers/bus/ifpga/meson.build > > > > b/drivers/bus/ifpga/meson.build new file mode 100644 index > > > > 0000000..c9b08c8 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/meson.build > > > > @@ -0,0 +1,8 @@ > > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2010-2018 > > > > +Intel Corporation > > > > + > > > > +deps += ['pci', 'kvargs', 'rawdev'] > > > > +install_headers('rte_bus_ifpga.h') > > > > +sources = files('ifpga_common.c', 'ifpga_bus.c') > > > > + > > > > +allow_experimental_apis = true > > > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h > > > > b/drivers/bus/ifpga/rte_bus_ifpga.h > > > > new file mode 100644 > > > > index 0000000..5c559e1 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > > > > @@ -0,0 +1,160 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > + > > > > +#ifndef _RTE_BUS_IFPGA_H_ > > > > +#define _RTE_BUS_IFPGA_H_ > > > > + > > > > +/** > > > > + * @file > > > > + * > > > > + * RTE Intel FPGA Bus Interface > > > > + */ > > > > + > > > > +#ifdef __cplusplus > > > > +extern "C" { > > > > +#endif > > > > + > > > > +#include <rte_bus.h> > > > > +#include <rte_pci.h> > > > > + > > > > +/** Name of Intel FPGA Bus */ > > > > +#define IFPGA_BUS_NAME ifpga > > > > + > > > > +/* Forward declarations */ > > > > +struct rte_afu_device; > > > > + > > > > +/** List of Intel AFU devices */ > > > > +TAILQ_HEAD(afu_device_list, rte_afu_device); > > > > +/** Double linked list of AFU device drivers. */ > > > > +TAILQ_HEAD(afu_driver_list, rte_afu_driver); > > > > + > > > > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > > > > + > > > > +struct rte_afu_uuid { > > > > + uint64_t uuid_low; > > > > + uint64_t uuid_high; > > > > +} __attribute__ ((packed)); > > > > + > > > > +#define IFPGA_BUS_DEV_PORT_MAX 4 > > > > + > > > > +/** > > > > + * A structure describing an ID for a AFU driver. Each driver > > > > +provides a > > > > + * table of these IDs for each device that it supports. > > > > + */ > > > > +struct rte_afu_id { > > > > + struct rte_afu_uuid uuid; > > > > + int port; /**< port number */ > > > > +} __attribute__ ((packed)); > > > > + > > > > +/** > > > > + * A structure PR (Partial Reconfiguration) configuration AFU driver. > > > > + */ > > > > + > > > > +struct rte_afu_pr_conf { > > > > + struct rte_afu_id afu_id; > > > > + int pr_enable; > > > > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > > > +}; > > > > + > > > > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > > > > + > > > > +/** > > > > + * A structure describing a fpga device. > > > > + */ > > > > +struct rte_ifpga_device { > > > > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ > > > > + struct rte_rawdev *rdev; > > > > + struct afu_device_list afu_list; /**< List of AFU devices */ }; > > > > + > > > > +/** > > > > + * A structure describing a AFU device. > > > > + */ > > > > +struct rte_afu_device { > > > > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ > > > > + struct rte_device device; /**< Inherit core device */ > > > > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > > > > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > > > > + struct rte_afu_id id; /**< AFU id within FPGA. */ > > > > + uint32_t num_region; /**< number of regions found */ > > > > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > > > > + /**< AFU Memory Resource > > > */ > > > > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > > > > + struct rte_afu_driver *driver; /**< Associated driver */ > > > > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > > > +} __attribute__ ((packed)); > > > > + > > > > +/** > > > > + * @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_DRV_TO_AFU_CONST(ptr) \ > > > > + container_of(ptr, const struct rte_afu_driver, driver) > > > > + > > > > +/** > > > > + * Initialisation function for the driver called during FPGA BUS probing. > > > > > > > > > typo: Initialization > > > > Fixed. > > > > > > + */ > > > > +typedef int (afu_probe_t)(struct rte_afu_device *); > > > > + > > > > +/** > > > > + * Uninitialisation function for the driver called during hotplugging. > > > > > > typo: Unintialization > > > > Fixed. > > > > > > + */ > > > > +typedef int (afu_remove_t)(struct rte_afu_device *); > > > > + > > > > +/** > > > > + * A structure describing a AFU device. > > > > + */ > > > > +struct rte_afu_driver { > > > > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > > > > + struct rte_driver driver; /**< Inherit core driver. */ > > > > + afu_probe_t *probe; /**< Device Probe function. > > > > */ > > > > + afu_remove_t *remove; /**< Device Remove > > > > function. */ > > > > + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ > > > > + uint32_t drv_flags; /**< Flags contolling handling of device. */ > > > > > > Typo Controlling > > > And what is "flags controlling handling of device?" > > > > This variable is not used, so I have removed it. > > > > > > +}; > > > > + > > > > +static inline const char * > > > > +rte_ifpga_device_name(const struct rte_afu_device *afu) { > > > > + if (afu && afu->device.name) > > > > + return afu->device.name; > > > > + return NULL; > > > > +} > > > > + > > > > +/** > > > > + * Register a ifpga afu device driver. > > > > + * > > > > + * @param driver > > > > + * A pointer to a rte_afu_driver structure describing the driver > > > > + * to be registered. > > > > + */ > > > > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); > > > > + > > > > +/** > > > > + * Unregister a ifpga afu device driver. > > > > + * > > > > + * @param driver > > > > + * A pointer to a rte_afu_driver structure describing the driver > > > > + * to be unregistered. > > > > + */ > > > > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > > > > + > > > > +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ RTE_INIT(afudrvinitfn_ > > > > +##afudrv);\ static const char *afudrvinit_ ## nm ## _alias;\ > > > > +static void afudrvinitfn_ ##afudrv(void)\ {\ > > > > + (afudrv).driver.name = RTE_STR(nm);\ > > > > + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ > > > > + rte_ifpga_driver_register(&afudrv);\ > > > > +} \ > > > > +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) > > > > + > > > > +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ static const char > > > > +*afudrvinit_ ## nm ## _alias = RTE_STR(alias) > > > > + > > > > +#endif /* _RTE_BUS_IFPGA_H_ */ > > > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > new file mode 100644 > > > > index 0000000..a027979 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > @@ -0,0 +1,10 @@ > > > > +DPDK_18.05 { > > > > + global: > > > > + > > > > + rte_ifpga_get_integer32_arg; > > > > + rte_ifpga_get_string_arg; > > > > + rte_ifpga_driver_register; > > > > + rte_ifpga_driver_unregister; > > > > + > > > > + local: *; > > > > +}; > > > > diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build > > > > index 58dfbe2..52c755d 100644 > > > > --- a/drivers/bus/meson.build > > > > +++ b/drivers/bus/meson.build > > > > @@ -1,7 +1,7 @@ > > > > # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 > > > > Intel Corporation > > > > > > > > -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] > > > > +drivers = ['dpaa', 'fslmc', 'ifpga', 'pci', 'vdev'] > > > > std_deps = ['eal'] > > > > config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' > > > > driver_name_fmt = 'rte_bus_@0@' > > > > diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 26f3563..3861e1a > > > > 100644 > > > > --- a/mk/rte.app.mk > > > > +++ b/mk/rte.app.mk > > > > @@ -255,6 +255,7 @@ ifeq > > > > ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) > > > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += > > > > -lrte_pmd_dpaa2_cmdif > > > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += > > > > -lrte_pmd_dpaa2_qdma endif # CONFIG_RTE_LIBRTE_FSLMC_BUS > > > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga > > > > endif # CONFIG_RTE_LIBRTE_RAWDEV > > > > > > > > > > > > -- > > > > 1.8.3.1 > > > > > > Regards > > > Qi ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-10 13:58 ` Xu, Rosen @ 2018-05-10 14:11 ` Zhang, Qi Z 0 siblings, 0 replies; 149+ messages in thread From: Zhang, Qi Z @ 2018-05-10 14:11 UTC (permalink / raw) To: Xu, Rosen, dev, thomas Cc: Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet > -----Original Message----- > From: Xu, Rosen > Sent: Thursday, May 10, 2018 9:58 PM > To: Zhang, Qi Z <qi.z.zhang@intel.com>; dev@dpdk.org; > thomas@monjalon.net > Cc: Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, Declan > <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library > > Hi Qi, > > > -----Original Message----- > > From: Zhang, Qi Z > > Sent: Thursday, May 10, 2018 21:49 > > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; > thomas@monjalon.net > > Cc: Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, Declan > > <declan.doherty@intel.com>; Richardson, Bruce > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > > <ferruh.yigit@intel.com>; Ananyev, Konstantin > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > > Library > > > > > > > > > -----Original Message----- > > > From: Xu, Rosen > > > Sent: Thursday, May 10, 2018 9:29 PM > > > To: Zhang, Qi Z <qi.z.zhang@intel.com>; dev@dpdk.org; > > > thomas@monjalon.net > > > Cc: Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, Declan > > > <declan.doherty@intel.com>; Richardson, Bruce > > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > > > <ferruh.yigit@intel.com>; Ananyev, Konstantin > > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA > > > BUS Library > > > > > > Hi Qi, > > > > > > > -----Original Message----- > > > > From: Zhang, Qi Z > > > > Sent: Thursday, May 10, 2018 20:27 > > > > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; > > > thomas@monjalon.net > > > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > > > <roy.fan.zhang@intel.com>; Doherty, Declan > > > > <declan.doherty@intel.com>; Richardson, Bruce > > > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, > > > > Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > > > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > > > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA > > > > BUS Library > > > > > > > > Hi Rosen: > > > > > > > > > -----Original Message----- > > > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > > > > > Sent: Wednesday, May 9, 2018 3:43 PM > > > > > To: dev@dpdk.org; thomas@monjalon.net > > > > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > > > > <roy.fan.zhang@intel.com>; Doherty, Declan > > > > > <declan.doherty@intel.com>; Richardson, Bruce > > > > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, > > > > > Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > > > > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > > > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, > > > > > Hao <hao.wu@intel.com>; gaetan.rivet@6wind.com > > > > > Subject: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA > > > > > BUS Library > > > > > > > > > > From: Rosen Xu <rosen.xu@intel.com> > > > > > > > > > > Defined FPGA-BUS for Acceleration Drivers of AFUs > > > > > > > > > > 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan > > > > > Process, probe Intel FPGA Rawdev Driver, it will be covered in > > > > > following > > patches. > > > > > > > > > > 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. > > > > > This scan is trigged by hotplug of IFPGA Rawdev probe, in this > > > > > scan the AFUs will be created and their drivers are also probed. > > > > > > > > > > This patch will introduce rte_afu_device which describe the AFU > > > > > device listed in the FPGA-BUS. > > > > > > > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > > > > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > > > > > --- > > > > > MAINTAINERS | 4 + > > > > > config/common_base | 5 + > > > > > doc/guides/rel_notes/release_18_05.rst | 5 + > > > > > drivers/bus/Makefile | 1 + > > > > > drivers/bus/ifpga/Makefile | 32 ++ > > > > > drivers/bus/ifpga/ifpga_bus.c | 501 > > > > > ++++++++++++++++++++++++++++ > > > > > drivers/bus/ifpga/ifpga_common.c | 88 +++++ > > > > > drivers/bus/ifpga/ifpga_common.h | 18 + > > > > > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > > > > > drivers/bus/ifpga/meson.build | 8 + > > > > > drivers/bus/ifpga/rte_bus_ifpga.h | 160 +++++++++ > > > > > drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + > > > > > drivers/bus/meson.build | 2 +- > > > > > mk/rte.app.mk | 1 + > > > > > 14 files changed, 865 insertions(+), 1 deletion(-) create mode > > > > > 100644 drivers/bus/ifpga/Makefile create mode 100644 > > > > > drivers/bus/ifpga/ifpga_bus.c create mode 100644 > > > > > drivers/bus/ifpga/ifpga_common.c create mode 100644 > > > > > drivers/bus/ifpga/ifpga_common.h create mode 100644 > > > > > drivers/bus/ifpga/ifpga_logs.h create mode 100644 > > > > > drivers/bus/ifpga/meson.build create mode 100644 > > > > > drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 > > > > > drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > > > > > > > diff --git a/MAINTAINERS b/MAINTAINERS index 7105920..fa0c5b1 > > > > > 100644 > > > > > --- a/MAINTAINERS > > > > > +++ b/MAINTAINERS > > > > > @@ -383,6 +383,10 @@ F: drivers/mempool/bucket/ Bus Drivers > > > > > ----------- > > > > > > > > > > +Intel FPGA buses > > > > > +M: Rosen Xu <rosen.xu@intel.com> > > > > > +F: drivers/bus/ifpga/ > > > > > + > > > > > NXP buses > > > > > M: Hemant Agrawal <hemant.agrawal@nxp.com> > > > > > M: Shreyansh Jain <shreyansh.jain@nxp.com> diff --git > > > > > a/config/common_base b/config/common_base index > > 0d181ac..1440316 > > > > > 100644 > > > > > --- a/config/common_base > > > > > +++ b/config/common_base > > > > > @@ -139,6 +139,11 @@ > > > > > CONFIG_RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS=n > > > > > CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n > > > > > > > > > > # > > > > > +# Compile the Intel FPGA bus > > > > > +# > > > > > +CONFIG_RTE_LIBRTE_IFPGA_BUS=y > > > > > + > > > > > +# > > > > > # Compile PCI bus driver > > > > > # > > > > > CONFIG_RTE_LIBRTE_PCI_BUS=y > > > > > diff --git a/doc/guides/rel_notes/release_18_05.rst > > > > > b/doc/guides/rel_notes/release_18_05.rst > > > > > index 7187348..265950a 100644 > > > > > --- a/doc/guides/rel_notes/release_18_05.rst > > > > > +++ b/doc/guides/rel_notes/release_18_05.rst > > > > > @@ -183,6 +183,11 @@ New Features > > > > > stats/xstats on shared memory from secondary process, and > > > > > also pdump packets on > > > > > those virtual devices. > > > > > > > > > > +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** > > > > > + > > > > > + The Ifpga Bus library provides support for integrating any > > > > > + Intel FPGA device with the DPDK framework. It provides Intel > > > > > + FPGA Partial Bit Stream AFU(Accelerated Function Unit) scan > > > > > + and drivers > > > prove. > > > > > > > > > > API Changes > > > > > ----------- > > > > > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index > > > > > c251b65..ef7f247 100644 > > > > > --- a/drivers/bus/Makefile > > > > > +++ b/drivers/bus/Makefile > > > > > @@ -7,6 +7,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa > > ifeq > > > > > ($(CONFIG_RTE_EAL_VFIO),y) > > > > > DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc endif > > > > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > > > > > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > > > > > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > > > > > > > > > > diff --git a/drivers/bus/ifpga/Makefile > > > > > b/drivers/bus/ifpga/Makefile new file mode 100644 index > > > > > 0000000..3ff3bdb > > > > > --- /dev/null > > > > > +++ b/drivers/bus/ifpga/Makefile > > > > > @@ -0,0 +1,32 @@ > > > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 > > > > > +Intel Corporation > > > > > + > > > > > +include $(RTE_SDK)/mk/rte.vars.mk > > > > > + > > > > > +# > > > > > +# library name > > > > > +# > > > > > +LIB = librte_bus_ifpga.a > > > > > + > > > > > +CFLAGS += -DALLOW_EXPERIMENTAL_API CFLAGS += -O3 CFLAGS += > > > > > +$(WERROR_FLAGS) LDLIBS += -lrte_eal LDLIBS += -lrte_rawdev > > > > > +LDLIBS > > > > > ++= -lrte_kvargs > > > > > + > > > > > +# versioning export map > > > > > +EXPORT_MAP := rte_bus_ifpga_version.map > > > > > + > > > > > +# library version > > > > > +LIBABIVER := 1 > > > > > + > > > > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c > > > > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c > > > > > + > > > > > +# > > > > > +# Export include files > > > > > +# > > > > > +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += > > rte_bus_ifpga.h > > > > > + > > > > > +include $(RTE_SDK)/mk/rte.lib.mk > > > > > diff --git a/drivers/bus/ifpga/ifpga_bus.c > > > > > b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index > > > > > 0000000..e144c01 > > > > > --- /dev/null > > > > > +++ b/drivers/bus/ifpga/ifpga_bus.c > > > > > @@ -0,0 +1,501 @@ > > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > > + > > > > > +#include <string.h> > > > > > +#include <inttypes.h> > > > > > +#include <stdint.h> > > > > > +#include <stdlib.h> > > > > > +#include <stdio.h> > > > > > +#include <sys/queue.h> > > > > > +#include <sys/mman.h> > > > > > +#include <sys/types.h> > > > > > +#include <unistd.h> > > > > > +#include <fcntl.h> > > > > > + > > > > > +#include <rte_errno.h> > > > > > +#include <rte_bus.h> > > > > > +#include <rte_per_lcore.h> > > > > > +#include <rte_memory.h> > > > > > +#include <rte_memzone.h> > > > > > +#include <rte_eal.h> > > > > > +#include <rte_common.h> > > > > > + > > > > > +#include <rte_devargs.h> > > > > > +#include <rte_kvargs.h> > > > > > +#include <rte_alarm.h> > > > > > + > > > > > +#include "rte_rawdev.h" > > > > > +#include "rte_rawdev_pmd.h" > > > > > +#include "rte_bus_ifpga.h" > > > > > +#include "ifpga_logs.h" > > > > > +#include "ifpga_common.h" > > > > > + > > > > > +int ifpga_bus_logtype; > > > > > + > > > > > +/* Forward declaration to access Intel FPGA bus > > > > > + * on which iFPGA devices are connected */ static struct > > > > > +rte_bus rte_ifpga_bus; > > > > > + > > > > > +/** Double linked list of IFPGA device. */ > > > > > +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); > > > > > + > > > > > +static struct ifpga_device_list ifpga_device_list = > > > > > + TAILQ_HEAD_INITIALIZER(ifpga_device_list); > > > > > +static struct afu_driver_list afu_driver_list = > > > > > + TAILQ_HEAD_INITIALIZER(afu_driver_list); > > > > > + > > > > > + > > > > > +/* register a ifpga bus based driver */ void > > > > > +rte_ifpga_driver_register(struct rte_afu_driver *driver) { > > > > > + RTE_VERIFY(driver); > > > > > + > > > > > + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); } > > > > > + > > > > > +/* un-register a fpga bus based driver */ void > > > > > +rte_ifpga_driver_unregister(struct rte_afu_driver *driver) { > > > > > + TAILQ_REMOVE(&afu_driver_list, driver, next); } > > > > > + > > > > > +static struct rte_ifpga_device * ifpga_find_ifpga_dev(const > > > > > +struct rte_rawdev *rdev) { > > > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > > > + > > > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > > > + if (rdev && > > > > > + ifpga_dev->rdev && > > > > > + ifpga_dev->rdev == rdev) > > > > > + return ifpga_dev; > > > > > + } > > > > > + return NULL; > > > > > +} > > > > > + > > > > > +static struct rte_afu_device * > > > > > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > > > > > + const struct rte_afu_id *afu_id) { > > > > > + struct rte_afu_device *afu_dev = NULL; > > > > > + > > > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > > > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > > > > > + return afu_dev; > > > > > + } > > > > > + return NULL; > > > > > +} > > > > > + > > > > > +static const char * const valid_args[] = { > > > > > +#define IFPGA_ARG_NAME "ifpga" > > > > > + IFPGA_ARG_NAME, > > > > > +#define IFPGA_ARG_PORT "port" > > > > > + IFPGA_ARG_PORT, > > > > > +#define IFPGA_AFU_BTS "afu_bts" > > > > > + IFPGA_AFU_BTS, > > > > > + NULL > > > > > +}; > > > > > + > > > > > +/* > > > > > + * Scan the content of the FPGA bus, and the devices in the > > > > > +devices > > > > > + * list > > > > > + */ > > > > > +static struct rte_afu_device * > > > > > +ifpga_scan_one(struct rte_devargs *devargs, > > > > > + struct rte_ifpga_device *ifpga_dev) > > > > > > > > usually ifpag_dev should be the first parameter here, and devargs > > > > follows > > > > > > Fixed. > > > > > > > > +{ > > > > > + struct rte_kvargs *kvlist = NULL; > > > > > + struct rte_rawdev *rawdev = NULL; > > > > > + struct rte_afu_device *afu_dev = NULL; > > > > > + struct rte_afu_pr_conf afu_pr_conf; > > > > > + int ret = 0; > > > > > + char *path = NULL; > > > > > + > > > > > + memset(&afu_pr_conf, 0, sizeof(struct rte_afu_pr_conf)); > > > > > + > > > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > > > + if (!kvlist) { > > > > > + IFPGA_BUS_ERR("error when parsing param"); > > > > > + goto end; > > > > > + } > > > > > + > > > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > > > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, > > > > > + &rte_ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) > > > > { > > > > > + IFPGA_BUS_ERR("error to parse %s", > > > > > + IFPGA_ARG_PORT); > > > > > + goto end; > > > > > + } > > > > > + } else { > > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > > + IFPGA_ARG_PORT); > > > > > + goto end; > > > > > + } > > > > > + > > > > > + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { > > > > > + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, > > > > > + &rte_ifpga_get_string_arg, &path) < 0) { > > > > > + IFPGA_BUS_ERR("Failed to parse %s", > > > > > + IFPGA_AFU_BTS); > > > > > + goto end; > > > > > + } > > > > > + } else { > > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > > + IFPGA_AFU_BTS); > > > > > + goto end; > > > > > + } > > > > > + > > > > > + afu_pr_conf.afu_id.uuid.uuid_low = 0; > > > > > + afu_pr_conf.afu_id.uuid.uuid_high = 0; > > > > > + afu_pr_conf.pr_enable = path?1:0; > > > > > + > > > > > + rawdev = ifpga_dev->rdev; > > > > > + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) > > > > > + goto end; > > > > > + > > > > > + afu_dev = calloc(1, sizeof(*afu_dev)); > > > > > + if (!afu_dev) > > > > > + goto end; > > > > > + > > > > > + afu_dev->device.devargs = devargs; > > > > > + afu_dev->device.numa_node = SOCKET_ID_ANY; > > > > > + afu_dev->device.name = devargs->name; > > > > > + afu_dev->rawdev = rawdev; > > > > > + afu_dev->id.uuid.uuid_low = 0; > > > > > + afu_dev->id.uuid.uuid_high = 0; > > > > > + afu_dev->id.port = afu_pr_conf.afu_id.port; > > > > > + afu_dev->ifpga_dev = ifpga_dev; > > > > > + > > > > > + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) > > > > > + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); > > > > > + > > > > > + if (rawdev->dev_ops && > > > > > + rawdev->dev_ops->dev_start && > > > > > + rawdev->dev_ops->dev_start(rawdev)) > > > > > + goto free_dev; > > > > > + > > > > > + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); > > > > > + if (rawdev->dev_ops->firmware_load && > > > > > + rawdev->dev_ops->firmware_load(rawdev, > > > > > + &afu_pr_conf)){ > > > > > + IFPGA_BUS_ERR("firmware load error %d\n", ret); > > > > > + goto free_dev; > > > > > + } > > > > > + afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; > > > > > + afu_dev->id.uuid.uuid_high = > > > > > +afu_pr_conf.afu_id.uuid.uuid_high; > > > > > + > > > > > + return afu_dev; > > > > > + > > > > > +free_dev: > > > > > + free(afu_dev); > > > > > +end: > > > > > + if (kvlist) > > > > > + rte_kvargs_free(kvlist); > > > > > + if (path) > > > > > + free(path); > > > > > + > > > > > + return NULL; > > > > > +} > > > > > + > > > > > +/* > > > > > + * Scan the content of the FPGA bus, and the devices in the > > > > > +devices > > > > > + * list > > > > > + */ > > > > > +static int > > > > > +ifpga_scan(void) > > > > > +{ > > > > > + struct rte_ifpga_device *ifpga_dev; > > > > > + struct rte_devargs *devargs; > > > > > + struct rte_kvargs *kvlist = NULL; > > > > > + struct rte_rawdev *rawdev = NULL; > > > > > + char *name = NULL; > > > > > + char name1[RTE_RAWDEV_NAME_MAX_LEN]; > > > > > + struct rte_afu_device *afu_dev = NULL; > > > > > + > > > > > + /* for FPGA devices we scan the devargs_list populated via > > > > > +cmdline */ > > > > > > > > I didn't see "--ifpga" is supported by cmdline, either you need to > > > > add corresponding parser or correct the comment here. > > > > > > To be honestly, ifpga_scan() is called by hotplug, lib_rte hotplug > > > function will construct it. > > > > OK, after review patch 3, I saw it, that make sense. > > > > > > > > + RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { > > > > > > > > > > > > IFPGA_BUS_NAME to replace "ifpga" here. > > > > > > > > > + if (devargs->bus != &rte_ifpga_bus) > > > > > + continue; > > > > > + > > > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > > > + if (!kvlist) { > > > > > + IFPGA_BUS_ERR("error when parsing param"); > > > > > + goto end; > > > > > + } > > > > > + > > > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { > > > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, > > > > > + &rte_ifpga_get_string_arg, &name) < 0) { > > > > > + IFPGA_BUS_ERR("error to parse %s", > > > > > + IFPGA_ARG_NAME); > > > > > + goto end; > > > > > + } > > > > > + } else { > > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > > + IFPGA_ARG_NAME); > > > > > + goto end; > > > > > + } > > > > > + > > > > > + memset(name1, 0, sizeof(name1)); > > > > > + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, > > > > "IFPGA:%s", > > > > > name); > > > > > + > > > > > + rawdev = rte_rawdev_pmd_get_named_dev(name1); > > > > > + if (!rawdev) > > > > > + goto end; > > > > > + > > > > > + if (ifpga_find_ifpga_dev(rawdev)) > > > > > + continue; > > > > > + > > > > > + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); > > > > > + if (!ifpga_dev) > > > > > + goto end; > > > > > + > > > > > + ifpga_dev->rdev = rawdev; > > > > > + TAILQ_INIT(&ifpga_dev->afu_list); > > > > > + > > > > > + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); > > > > > + afu_dev = ifpga_scan_one(devargs, ifpga_dev); > > > > > + if (afu_dev != NULL) > > > > > + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, > > > > next); > > > > > > > > I don't understand why we need afu_list?, seems we only add a new > > > > afu_dev into the list after create a new ifpga_dev, Is there any > > > > another place that we add one to list to make it reasonable? it > > > > looks like either a 1:1 or 1:0 for ifpga_dev:afu_dev? > > > > > > One FPAG may support more than one AFU. > > > > But in your implementation, it is not possible that an ifpga_dev > > contains multiple afu_dev > > All afu_devs are listed to ifpga_dev, and each afu_dev can be added and > deleted by user. Could you show me an example, how this happen, what APIs user can add an rte_afu_device to an rte_ifpga_device? > > > > > > > > > + } > > > > > + > > > > > +end: > > > > > + if (kvlist) > > > > > + rte_kvargs_free(kvlist); > > > > > + if (name) > > > > > + free(name); > > > > > + > > > > > + return 0; > > > > > +} > > > > > + > > > > > +/* > > > > > + * Match the AFU Driver and AFU Device using the ID Table */ > > > > > +static int rte_afu_match(const struct rte_afu_driver *afu_drv, > > > > > + const struct rte_afu_device *afu_dev) { > > > > > + const struct rte_afu_uuid *id_table; > > > > > + > > > > > + for (id_table = afu_drv->id_table; > > > > > + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); > > > > > + id_table++) { > > > > > + /* check if device's identifiers match the driver's ones */ > > > > > + if ((id_table->uuid_low != afu_dev->id.uuid.uuid_low) || > > > > > + id_table->uuid_high != > > > > > + afu_dev->id.uuid.uuid_high) > > > > > + continue; > > > > > + > > > > > + return 1; > > > > > + } > > > > > + > > > > > + return 0; > > > > > +} > > > > > + > > > > > +static int > > > > > +ifpga_probe_one_driver(struct rte_afu_driver *drv, > > > > > + struct rte_afu_device *afu_dev) { > > > > > + int ret; > > > > > + > > > > > + if (!rte_afu_match(drv, afu_dev)) > > > > > + /* Match of device and driver failed */ > > > > > + return 1; > > > > > + > > > > > + /* reference driver structure */ > > > > > + afu_dev->driver = drv; > > > > > + afu_dev->device.driver = &drv->driver; > > > > > + > > > > > + /* call the driver probe() function */ > > > > > + ret = drv->probe(afu_dev); > > > > > + if (ret) { > > > > > + afu_dev->driver = NULL; > > > > > + afu_dev->device.driver = NULL; > > > > > + } > > > > > + > > > > > + return ret; > > > > > +} > > > > > + > > > > > +static int > > > > > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) { > > > > > + struct rte_afu_driver *drv = NULL; > > > > > + int ret = 0; > > > > > + > > > > > + if (afu_dev == NULL) > > > > > + return -1; > > > > > + > > > > > + /* Check if a driver is already loaded */ > > > > > + if (afu_dev->driver != NULL) > > > > > + return 0; > > > > > + > > > > > + TAILQ_FOREACH(drv, &afu_driver_list, next) { > > > > > + if (ifpga_probe_one_driver(drv, afu_dev)) { > > > > > + ret = -1; > > > > > + break; > > > > > + } > > > > > + } > > > > > + return ret; > > > > > +} > > > > > + > > > > > +/* > > > > > + * Scan the content of the Intel FPGA bus, and call the probe() > > > > > +function for > > > > > + * all registered drivers that have a matching entry in its > > > > > +id_table > > > > > + * for discovered devices. > > > > > + */ > > > > > +static int > > > > > +ifpga_probe(void) > > > > > +{ > > > > > + struct rte_ifpga_device *ifpga_dev; > > > > > + struct rte_afu_device *afu_dev = NULL; > > > > > + int ret = 0; > > > > > + > > > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > > > + > > > > > + if (afu_dev->device.driver) > > > > > + continue; > > > > > + > > > > > + ret = ifpga_probe_all_drivers(afu_dev); > > > > > + if (ret < 0) > > > > > + IFPGA_BUS_ERR("failed to initialize %s > > > > device\n", > > > > > + rte_ifpga_device_name(afu_dev)); > > > > > + } > > > > > + } > > > > > + > > > > > + return ret; > > > > > +} > > > > > + > > > > > +static int > > > > > +ifpga_plug(struct rte_device *dev) { > > > > > + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); > > > > > +} > > > > > + > > > > > +static int > > > > > +ifpga_remove_driver(struct rte_afu_device *afu_dev) { > > > > > + const char *name; > > > > > + const struct rte_afu_driver *driver; > > > > > + > > > > > + name = rte_ifpga_device_name(afu_dev); > > > > > + if (!afu_dev->device.driver) { > > > > > + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); > > > > > + return 1; > > > > > + } > > > > > + > > > > > + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); > > > > > + return driver->remove(afu_dev); } > > > > > + > > > > > +static int > > > > > +ifpga_unplug(struct rte_device *dev) { > > > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > > > + struct rte_afu_device *afu_dev = NULL; > > > > > + struct rte_devargs *devargs = NULL; > > > > > + int ret; > > > > > + > > > > > + if (dev == NULL) > > > > > + return -EINVAL; > > > > > + > > > > > + afu_dev = RTE_DEV_TO_AFU(dev); > > > > > + if (!dev) > > > > > + return -ENOENT; > > > > > + > > > > > + ifpga_dev = afu_dev->ifpga_dev; > > > > > + devargs = dev->devargs; > > > > > + > > > > > + ret = ifpga_remove_driver(afu_dev); > > > > > > > > So what is the device type that be plugged into the ifgpa bus? > > > > ifpga_dev or afu_dev? If its afu_dev, why we need ifpga_dev? > > > > If it is ifpga_dev, we need remove ifpga_dev from ifpga_device_list here. > > > > > > The device type that be plugged into the ifpga bus is afu_dev. > > > > In DPDK, we have rte_pci_device for pci bus and rte_vdev_device for > > vdev bus Now we have rte_ifpga_device not for ifgpa bus but > > rte_afu_device, it is a little bit confuse here > > The relationship of this items is descripted in ifpga_rawdev.rst. > > > > And each afu_dev will be added into one ifpga_dev. > > > Each FPGA device bind to ifpga_dev. > > > > So what is the relationship between ifpga_dev and raw_dev? > > One FPGA as a PCI device will probe ifpga_rawdev. > For management afu_dev, we create ifpga_dev in ifpga_bus. So 1 ifpga_dev map to 1 raw device? > > > > > > > > > + if (ret) > > > > > + return ret; > > > > > + > > > > > + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); > > > > > + > > > > > + rte_devargs_remove(devargs->bus->name, devargs->name); > > > > > + free(afu_dev); > > > > > + return 0; > > > > > + > > > > > +} > > > > > + > > > > > +static struct rte_device * > > > > > +ifpga_find_device(const struct rte_device *start, > > > > > + rte_dev_cmp_t cmp, const void *data) { > > > > > + struct rte_ifpga_device *ifpga_dev; > > > > > + struct rte_afu_device *afu_dev; > > > > > + > > > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > > > + if (start && &afu_dev->device == start) { > > > > > + start = NULL; > > > > > + continue; > > > > > + } > > > > > + if (cmp(&afu_dev->device, data) == 0) > > > > > + return &afu_dev->device; > > > > > + } > > > > > + } > > > > > + return NULL; > > > > > +} > > > > > +static int > > > > > +ifpga_parse(const char *name, void *addr) { > > > > > + int *out = addr; > > > > > + struct rte_rawdev *rawdev = NULL; > > > > > + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; > > > > > + char *c1 = NULL, *c2 = NULL; > > > > > + int port = IFPGA_BUS_DEV_PORT_MAX; > > > > > + char str_port[8]; > > > > > + int str_port_len = 0; > > > > > + int ret; > > > > > + > > > > > + memset(str_port, 0, 8); > > > > > + c1 = strchr(name, '|'); > > > > > + if (c1 != NULL) { > > > > > + str_port_len = c1-name; > > > > > + c2 = c1+1; > > > > > + } > > > > > + > > > > > + if (str_port_len < 8 && > > > > > + str_port_len > 0) { > > > > > + memcpy(str_port, name, str_port_len); > > > > > + ret = sscanf(str_port, "%d", &port); > > > > > + if (ret == -1) > > > > > + return 0; > > > > > + } > > > > > + > > > > > + memset(rawdev_name, 0, sizeof(rawdev_name)); > > > > > + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, > "IFPGA:%s", > > > > c2); > > > > > + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); > > > > > + > > > > > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > > > > > + rawdev && > > > > > + (addr != NULL)) > > > > > + *out = port; > > > > > + > > > > > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > > > > > + rawdev) > > > > > + return 0; > > > > > + else > > > > > + return 1; > > > > > +} > > > > > + > > > > > +static struct rte_bus rte_ifpga_bus = { > > > > > + .scan = ifpga_scan, > > > > > + .probe = ifpga_probe, > > > > > + .find_device = ifpga_find_device, > > > > > + .plug = ifpga_plug, > > > > > + .unplug = ifpga_unplug, > > > > > + .parse = ifpga_parse, > > > > > +}; > > > > > + > > > > > +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); > > > > > + > > > > > +RTE_INIT(ifpga_init_log) > > > > > +{ > > > > > + ifpga_bus_logtype = rte_log_register("bus.ifpga"); > > > > > + if (ifpga_bus_logtype >= 0) > > > > > + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); } > > > > > diff --git a/drivers/bus/ifpga/ifpga_common.c > > > > > b/drivers/bus/ifpga/ifpga_common.c > > > > > new file mode 100644 > > > > > index 0000000..78e2eae > > > > > --- /dev/null > > > > > +++ b/drivers/bus/ifpga/ifpga_common.c > > > > > @@ -0,0 +1,88 @@ > > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > > + > > > > > +#include <string.h> > > > > > +#include <inttypes.h> > > > > > +#include <stdint.h> > > > > > +#include <stdlib.h> > > > > > +#include <stdio.h> > > > > > +#include <sys/queue.h> > > > > > +#include <sys/mman.h> > > > > > +#include <sys/types.h> > > > > > +#include <unistd.h> > > > > > +#include <fcntl.h> > > > > > + > > > > > +#include <rte_errno.h> > > > > > +#include <rte_bus.h> > > > > > +#include <rte_per_lcore.h> > > > > > +#include <rte_memory.h> > > > > > +#include <rte_memzone.h> > > > > > +#include <rte_eal.h> > > > > > +#include <rte_common.h> > > > > > + > > > > > +#include <rte_devargs.h> > > > > > +#include <rte_kvargs.h> > > > > > +#include <rte_alarm.h> > > > > > + > > > > > +#include "rte_bus_ifpga.h" > > > > > +#include "ifpga_logs.h" > > > > > +#include "ifpga_common.h" > > > > > + > > > > > +int rte_ifpga_get_string_arg(const char *key __rte_unused, > > > > > + const char *value, void *extra_args) { > > > > > + if (!value || !extra_args) > > > > > + return -EINVAL; > > > > > + > > > > > + *(char **)extra_args = strdup(value); > > > > > + > > > > > + if (!*(char **)extra_args) > > > > > + return -ENOMEM; > > > > > + > > > > > + return 0; > > > > > +} > > > > > +int rte_ifpga_get_integer32_arg(const char *key __rte_unused, > > > > > + const char *value, void *extra_args) { > > > > > + if (!value || !extra_args) > > > > > + return -EINVAL; > > > > > + > > > > > + *(int *)extra_args = strtoull(value, NULL, 0); > > > > > + > > > > > + return 0; > > > > > +} > > > > > +int ifpga_get_integer64_arg(const char *key __rte_unused, > > > > > + const char *value, void *extra_args) { > > > > > + if (!value || !extra_args) > > > > > + return -EINVAL; > > > > > + > > > > > + *(uint64_t *)extra_args = strtoull(value, NULL, 0); > > > > > + > > > > > + return 0; > > > > > +} > > > > > +int ifpga_get_unsigned_long(const char *str, int base) { > > > > > + unsigned long num; > > > > > + char *end = NULL; > > > > > + > > > > > + errno = 0; > > > > > + > > > > > + num = strtoul(str, &end, base); > > > > > + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) > > > > > + return -1; > > > > > + > > > > > + return num; > > > > > +} > > > > > + > > > > > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > > > > + const struct rte_afu_id *afu_id1) { > > > > > + if ((afu_id0->uuid.uuid_low == afu_id1->uuid.uuid_low) && > > > > > + (afu_id0->uuid.uuid_high == afu_id1->uuid.uuid_high) && > > > > > + (afu_id0->port == afu_id1->port)) { > > > > > + return 0; > > > > > + } else > > > > > + return 1; > > > > > +} > > > > > diff --git a/drivers/bus/ifpga/ifpga_common.h > > > > > b/drivers/bus/ifpga/ifpga_common.h > > > > > new file mode 100644 > > > > > index 0000000..f9254b9 > > > > > --- /dev/null > > > > > +++ b/drivers/bus/ifpga/ifpga_common.h > > > > > @@ -0,0 +1,18 @@ > > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > > + > > > > > +#ifndef _IFPGA_COMMON_H_ > > > > > +#define _IFPGA_COMMON_H_ > > > > > + > > > > > +int rte_ifpga_get_string_arg(const char *key __rte_unused, > > > > > + const char *value, void *extra_args); int > > > > > +rte_ifpga_get_integer32_arg(const char *key __rte_unused, > > > > > + const char *value, void *extra_args); int > > > > > +ifpga_get_integer64_arg(const char *key __rte_unused, > > > > > + const char *value, void *extra_args); int > > > > > +ifpga_get_unsigned_long(const char *str, int base); int > > > > > +ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > > > > + const struct rte_afu_id *afu_id1); > > > > > + > > > > > +#endif /* _IFPGA_COMMON_H_ */ > > > > > diff --git a/drivers/bus/ifpga/ifpga_logs.h > > > > > b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index > > > > > 0000000..873e0a4 > > > > > --- /dev/null > > > > > +++ b/drivers/bus/ifpga/ifpga_logs.h > > > > > @@ -0,0 +1,31 @@ > > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > > + > > > > > +#ifndef _IFPGA_LOGS_H_ > > > > > +#define _IFPGA_LOGS_H_ > > > > > + > > > > > +#include <rte_log.h> > > > > > + > > > > > +extern int ifpga_bus_logtype; > > > > > + > > > > > +#define IFPGA_LOG(level, fmt, args...) \ > > > > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > > > > + __func__, ##args) > > > > > + > > > > > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > > > > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > > > > + __func__, ##args) > > > > > + > > > > > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > > > > > + > > > > > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > > > > > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) #define IFPGA_BUS_INFO(fmt, > > > > > +args...) \ > > > > > + IFPGA_BUS_LOG(INFO, fmt, ## args) #define IFPGA_BUS_ERR(fmt, > > > > > +args...) \ > > > > > + IFPGA_BUS_LOG(ERR, fmt, ## args) #define IFPGA_BUS_WARN(fmt, > > > > > +args...) \ > > > > > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > > > > > + > > > > > +#endif /* _IFPGA_BUS_LOGS_H_ */ > > > > > diff --git a/drivers/bus/ifpga/meson.build > > > > > b/drivers/bus/ifpga/meson.build new file mode 100644 index > > > > > 0000000..c9b08c8 > > > > > --- /dev/null > > > > > +++ b/drivers/bus/ifpga/meson.build > > > > > @@ -0,0 +1,8 @@ > > > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) > > > > > +2010-2018 Intel Corporation > > > > > + > > > > > +deps += ['pci', 'kvargs', 'rawdev'] > > > > > +install_headers('rte_bus_ifpga.h') > > > > > +sources = files('ifpga_common.c', 'ifpga_bus.c') > > > > > + > > > > > +allow_experimental_apis = true > > > > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h > > > > > b/drivers/bus/ifpga/rte_bus_ifpga.h > > > > > new file mode 100644 > > > > > index 0000000..5c559e1 > > > > > --- /dev/null > > > > > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > > > > > @@ -0,0 +1,160 @@ > > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > > + > > > > > +#ifndef _RTE_BUS_IFPGA_H_ > > > > > +#define _RTE_BUS_IFPGA_H_ > > > > > + > > > > > +/** > > > > > + * @file > > > > > + * > > > > > + * RTE Intel FPGA Bus Interface */ > > > > > + > > > > > +#ifdef __cplusplus > > > > > +extern "C" { > > > > > +#endif > > > > > + > > > > > +#include <rte_bus.h> > > > > > +#include <rte_pci.h> > > > > > + > > > > > +/** Name of Intel FPGA Bus */ > > > > > +#define IFPGA_BUS_NAME ifpga > > > > > + > > > > > +/* Forward declarations */ > > > > > +struct rte_afu_device; > > > > > + > > > > > +/** List of Intel AFU devices */ TAILQ_HEAD(afu_device_list, > > > > > +rte_afu_device); > > > > > +/** Double linked list of AFU device drivers. */ > > > > > +TAILQ_HEAD(afu_driver_list, rte_afu_driver); > > > > > + > > > > > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > > > > > + > > > > > +struct rte_afu_uuid { > > > > > + uint64_t uuid_low; > > > > > + uint64_t uuid_high; > > > > > +} __attribute__ ((packed)); > > > > > + > > > > > +#define IFPGA_BUS_DEV_PORT_MAX 4 > > > > > + > > > > > +/** > > > > > + * A structure describing an ID for a AFU driver. Each driver > > > > > +provides a > > > > > + * table of these IDs for each device that it supports. > > > > > + */ > > > > > +struct rte_afu_id { > > > > > + struct rte_afu_uuid uuid; > > > > > + int port; /**< port number */ > > > > > +} __attribute__ ((packed)); > > > > > + > > > > > +/** > > > > > + * A structure PR (Partial Reconfiguration) configuration AFU driver. > > > > > + */ > > > > > + > > > > > +struct rte_afu_pr_conf { > > > > > + struct rte_afu_id afu_id; > > > > > + int pr_enable; > > > > > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > > > > +}; > > > > > + > > > > > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > > > > > + > > > > > +/** > > > > > + * A structure describing a fpga device. > > > > > + */ > > > > > +struct rte_ifpga_device { > > > > > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. > */ > > > > > + struct rte_rawdev *rdev; > > > > > + struct afu_device_list afu_list; /**< List of AFU devices */ > > > > > +}; > > > > > + > > > > > +/** > > > > > + * A structure describing a AFU device. > > > > > + */ > > > > > +struct rte_afu_device { > > > > > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. > */ > > > > > + struct rte_device device; /**< Inherit core device */ > > > > > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > > > > > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > > > > > + struct rte_afu_id id; /**< AFU id within FPGA. > */ > > > > > + uint32_t num_region; /**< number of regions found */ > > > > > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > > > > > + /**< AFU Memory Resource > > > > */ > > > > > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > > > > > + struct rte_afu_driver *driver; /**< Associated driver */ > > > > > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > > > > +} __attribute__ ((packed)); > > > > > + > > > > > +/** > > > > > + * @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_DRV_TO_AFU_CONST(ptr) \ > > > > > + container_of(ptr, const struct rte_afu_driver, driver) > > > > > + > > > > > +/** > > > > > + * Initialisation function for the driver called during FPGA BUS probing. > > > > > > > > > > > > typo: Initialization > > > > > > Fixed. > > > > > > > > + */ > > > > > +typedef int (afu_probe_t)(struct rte_afu_device *); > > > > > + > > > > > +/** > > > > > + * Uninitialisation function for the driver called during hotplugging. > > > > > > > > typo: Unintialization > > > > > > Fixed. > > > > > > > > + */ > > > > > +typedef int (afu_remove_t)(struct rte_afu_device *); > > > > > + > > > > > +/** > > > > > + * A structure describing a AFU device. > > > > > + */ > > > > > +struct rte_afu_driver { > > > > > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > > > > > + struct rte_driver driver; /**< Inherit core driver. */ > > > > > + afu_probe_t *probe; /**< Device Probe > function. > > > > > */ > > > > > + afu_remove_t *remove; /**< Device Remove > > > > > function. */ > > > > > + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. > */ > > > > > + uint32_t drv_flags; /**< Flags contolling handling of device. > */ > > > > > > > > Typo Controlling > > > > And what is "flags controlling handling of device?" > > > > > > This variable is not used, so I have removed it. > > > > > > > > +}; > > > > > + > > > > > +static inline const char * > > > > > +rte_ifpga_device_name(const struct rte_afu_device *afu) { > > > > > + if (afu && afu->device.name) > > > > > + return afu->device.name; > > > > > + return NULL; > > > > > +} > > > > > + > > > > > +/** > > > > > + * Register a ifpga afu device driver. > > > > > + * > > > > > + * @param driver > > > > > + * A pointer to a rte_afu_driver structure describing the driver > > > > > + * to be registered. > > > > > + */ > > > > > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); > > > > > + > > > > > +/** > > > > > + * Unregister a ifpga afu device driver. > > > > > + * > > > > > + * @param driver > > > > > + * A pointer to a rte_afu_driver structure describing the driver > > > > > + * to be unregistered. > > > > > + */ > > > > > +void rte_ifpga_driver_unregister(struct rte_afu_driver > > > > > +*driver); > > > > > + > > > > > +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ > > > > > +RTE_INIT(afudrvinitfn_ ##afudrv);\ static const char > > > > > +*afudrvinit_ ## nm ## _alias;\ static void afudrvinitfn_ ##afudrv(void)\ > {\ > > > > > + (afudrv).driver.name = RTE_STR(nm);\ > > > > > + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ > > > > > + rte_ifpga_driver_register(&afudrv);\ > > > > > +} \ > > > > > +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) > > > > > + > > > > > +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ static const > > > > > +char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) > > > > > + > > > > > +#endif /* _RTE_BUS_IFPGA_H_ */ > > > > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > > b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > > new file mode 100644 > > > > > index 0000000..a027979 > > > > > --- /dev/null > > > > > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > > @@ -0,0 +1,10 @@ > > > > > +DPDK_18.05 { > > > > > + global: > > > > > + > > > > > + rte_ifpga_get_integer32_arg; > > > > > + rte_ifpga_get_string_arg; > > > > > + rte_ifpga_driver_register; > > > > > + rte_ifpga_driver_unregister; > > > > > + > > > > > + local: *; > > > > > +}; > > > > > diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build > > > > > index 58dfbe2..52c755d 100644 > > > > > --- a/drivers/bus/meson.build > > > > > +++ b/drivers/bus/meson.build > > > > > @@ -1,7 +1,7 @@ > > > > > # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 > > > > > Intel Corporation > > > > > > > > > > -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] > > > > > +drivers = ['dpaa', 'fslmc', 'ifpga', 'pci', 'vdev'] > > > > > std_deps = ['eal'] > > > > > config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' > > > > > driver_name_fmt = 'rte_bus_@0@' > > > > > diff --git a/mk/rte.app.mk b/mk/rte.app.mk index > > > > > 26f3563..3861e1a > > > > > 100644 > > > > > --- a/mk/rte.app.mk > > > > > +++ b/mk/rte.app.mk > > > > > @@ -255,6 +255,7 @@ ifeq > > > > > ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) > > > > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += > > > > > -lrte_pmd_dpaa2_cmdif > > > > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += > > > > > -lrte_pmd_dpaa2_qdma endif # CONFIG_RTE_LIBRTE_FSLMC_BUS > > > > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga > > > > > endif # CONFIG_RTE_LIBRTE_RAWDEV > > > > > > > > > > > > > > > -- > > > > > 1.8.3.1 > > > > > > > > Regards > > > > Qi ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-10 13:29 ` Xu, Rosen 2018-05-10 13:48 ` Zhang, Qi Z @ 2018-05-10 13:51 ` Xu, Rosen 2018-05-10 13:58 ` Zhang, Qi Z 2018-05-10 14:49 ` Thomas Monjalon 1 sibling, 2 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-10 13:51 UTC (permalink / raw) To: Xu, Rosen, Zhang, Qi Z, dev, thomas Cc: Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet Hi Qi, I miss one comment, so I fix it in this email. > -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > Sent: Thursday, May 10, 2018 21:29 > To: Zhang, Qi Z <qi.z.zhang@intel.com>; dev@dpdk.org; > thomas@monjalon.net > Cc: Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, Declan > <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: Re: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > Library > > Hi Qi, > > > -----Original Message----- > > From: Zhang, Qi Z > > Sent: Thursday, May 10, 2018 20:27 > > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; > thomas@monjalon.net > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > > Richardson, Bruce <bruce.richardson@intel.com>; > > shreyansh.jain@nxp.com; Yigit, Ferruh <ferruh.yigit@intel.com>; > > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Tianfei > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > > Library > > > > Hi Rosen: > > > > > -----Original Message----- > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > > > Sent: Wednesday, May 9, 2018 3:43 PM > > > To: dev@dpdk.org; thomas@monjalon.net > > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > > <roy.fan.zhang@intel.com>; Doherty, Declan > > > <declan.doherty@intel.com>; Richardson, Bruce > > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > > > <ferruh.yigit@intel.com>; Ananyev, Konstantin > > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > > Subject: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > > > Library > > > > > > From: Rosen Xu <rosen.xu@intel.com> > > > > > > Defined FPGA-BUS for Acceleration Drivers of AFUs > > > > > > 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, > > > probe Intel FPGA Rawdev Driver, it will be covered in following patches. > > > > > > 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. > > > This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan > > > the AFUs will be created and their drivers are also probed. > > > > > > This patch will introduce rte_afu_device which describe the AFU > > > device listed in the FPGA-BUS. > > > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > > > --- > > > MAINTAINERS | 4 + > > > config/common_base | 5 + > > > doc/guides/rel_notes/release_18_05.rst | 5 + > > > drivers/bus/Makefile | 1 + > > > drivers/bus/ifpga/Makefile | 32 ++ > > > drivers/bus/ifpga/ifpga_bus.c | 501 > > > ++++++++++++++++++++++++++++ > > > drivers/bus/ifpga/ifpga_common.c | 88 +++++ > > > drivers/bus/ifpga/ifpga_common.h | 18 + > > > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > > > drivers/bus/ifpga/meson.build | 8 + > > > drivers/bus/ifpga/rte_bus_ifpga.h | 160 +++++++++ > > > drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + > > > drivers/bus/meson.build | 2 +- > > > mk/rte.app.mk | 1 + > > > 14 files changed, 865 insertions(+), 1 deletion(-) create mode > > > 100644 drivers/bus/ifpga/Makefile create mode 100644 > > > drivers/bus/ifpga/ifpga_bus.c create mode 100644 > > > drivers/bus/ifpga/ifpga_common.c create mode 100644 > > > drivers/bus/ifpga/ifpga_common.h create mode 100644 > > > drivers/bus/ifpga/ifpga_logs.h create mode 100644 > > > drivers/bus/ifpga/meson.build create mode 100644 > > > drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 > > > drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > > > diff --git a/MAINTAINERS b/MAINTAINERS index 7105920..fa0c5b1 100644 > > > --- a/MAINTAINERS > > > +++ b/MAINTAINERS > > > @@ -383,6 +383,10 @@ F: drivers/mempool/bucket/ Bus Drivers > > > ----------- > > > > > > +Intel FPGA buses > > > +M: Rosen Xu <rosen.xu@intel.com> > > > +F: drivers/bus/ifpga/ > > > + > > > NXP buses > > > M: Hemant Agrawal <hemant.agrawal@nxp.com> > > > M: Shreyansh Jain <shreyansh.jain@nxp.com> diff --git > > > a/config/common_base b/config/common_base index 0d181ac..1440316 > > > 100644 > > > --- a/config/common_base > > > +++ b/config/common_base > > > @@ -139,6 +139,11 @@ > > > CONFIG_RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS=n > > > CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n > > > > > > # > > > +# Compile the Intel FPGA bus > > > +# > > > +CONFIG_RTE_LIBRTE_IFPGA_BUS=y > > > + > > > +# > > > # Compile PCI bus driver > > > # > > > CONFIG_RTE_LIBRTE_PCI_BUS=y > > > diff --git a/doc/guides/rel_notes/release_18_05.rst > > > b/doc/guides/rel_notes/release_18_05.rst > > > index 7187348..265950a 100644 > > > --- a/doc/guides/rel_notes/release_18_05.rst > > > +++ b/doc/guides/rel_notes/release_18_05.rst > > > @@ -183,6 +183,11 @@ New Features > > > stats/xstats on shared memory from secondary process, and also > > > pdump packets on > > > those virtual devices. > > > > > > +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** > > > + > > > + The Ifpga Bus library provides support for integrating any Intel > > > + FPGA device with the DPDK framework. It provides Intel FPGA > > > + Partial Bit Stream AFU(Accelerated Function Unit) scan and drivers > prove. > > > > > > API Changes > > > ----------- > > > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index > > > c251b65..ef7f247 100644 > > > --- a/drivers/bus/Makefile > > > +++ b/drivers/bus/Makefile > > > @@ -7,6 +7,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa ifeq > > > ($(CONFIG_RTE_EAL_VFIO),y) > > > DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc endif > > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > > > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > > > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > > > > > > diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile > > > new file mode 100644 index 0000000..3ff3bdb > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/Makefile > > > @@ -0,0 +1,32 @@ > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > > > +Corporation > > > + > > > +include $(RTE_SDK)/mk/rte.vars.mk > > > + > > > +# > > > +# library name > > > +# > > > +LIB = librte_bus_ifpga.a > > > + > > > +CFLAGS += -DALLOW_EXPERIMENTAL_API > > > +CFLAGS += -O3 > > > +CFLAGS += $(WERROR_FLAGS) > > > +LDLIBS += -lrte_eal > > > +LDLIBS += -lrte_rawdev > > > +LDLIBS += -lrte_kvargs > > > + > > > +# versioning export map > > > +EXPORT_MAP := rte_bus_ifpga_version.map > > > + > > > +# library version > > > +LIBABIVER := 1 > > > + > > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c > > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c > > > + > > > +# > > > +# Export include files > > > +# > > > +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h > > > + > > > +include $(RTE_SDK)/mk/rte.lib.mk > > > diff --git a/drivers/bus/ifpga/ifpga_bus.c > > > b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index > > > 0000000..e144c01 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/ifpga_bus.c > > > @@ -0,0 +1,501 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > + > > > +#include <string.h> > > > +#include <inttypes.h> > > > +#include <stdint.h> > > > +#include <stdlib.h> > > > +#include <stdio.h> > > > +#include <sys/queue.h> > > > +#include <sys/mman.h> > > > +#include <sys/types.h> > > > +#include <unistd.h> > > > +#include <fcntl.h> > > > + > > > +#include <rte_errno.h> > > > +#include <rte_bus.h> > > > +#include <rte_per_lcore.h> > > > +#include <rte_memory.h> > > > +#include <rte_memzone.h> > > > +#include <rte_eal.h> > > > +#include <rte_common.h> > > > + > > > +#include <rte_devargs.h> > > > +#include <rte_kvargs.h> > > > +#include <rte_alarm.h> > > > + > > > +#include "rte_rawdev.h" > > > +#include "rte_rawdev_pmd.h" > > > +#include "rte_bus_ifpga.h" > > > +#include "ifpga_logs.h" > > > +#include "ifpga_common.h" > > > + > > > +int ifpga_bus_logtype; > > > + > > > +/* Forward declaration to access Intel FPGA bus > > > + * on which iFPGA devices are connected */ static struct rte_bus > > > +rte_ifpga_bus; > > > + > > > +/** Double linked list of IFPGA device. */ > > > +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); > > > + > > > +static struct ifpga_device_list ifpga_device_list = > > > + TAILQ_HEAD_INITIALIZER(ifpga_device_list); > > > +static struct afu_driver_list afu_driver_list = > > > + TAILQ_HEAD_INITIALIZER(afu_driver_list); > > > + > > > + > > > +/* register a ifpga bus based driver */ void > > > +rte_ifpga_driver_register(struct rte_afu_driver *driver) { > > > + RTE_VERIFY(driver); > > > + > > > + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); } > > > + > > > +/* un-register a fpga bus based driver */ void > > > +rte_ifpga_driver_unregister(struct rte_afu_driver *driver) { > > > + TAILQ_REMOVE(&afu_driver_list, driver, next); } > > > + > > > +static struct rte_ifpga_device * > > > +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) { > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > + > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > + if (rdev && > > > + ifpga_dev->rdev && > > > + ifpga_dev->rdev == rdev) > > > + return ifpga_dev; > > > + } > > > + return NULL; > > > +} > > > + > > > +static struct rte_afu_device * > > > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > > > + const struct rte_afu_id *afu_id) > > > +{ > > > + struct rte_afu_device *afu_dev = NULL; > > > + > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > > > + return afu_dev; > > > + } > > > + return NULL; > > > +} > > > + > > > +static const char * const valid_args[] = { > > > +#define IFPGA_ARG_NAME "ifpga" > > > + IFPGA_ARG_NAME, > > > +#define IFPGA_ARG_PORT "port" > > > + IFPGA_ARG_PORT, > > > +#define IFPGA_AFU_BTS "afu_bts" > > > + IFPGA_AFU_BTS, > > > + NULL > > > +}; > > > + > > > +/* > > > + * Scan the content of the FPGA bus, and the devices in the devices > > > + * list > > > + */ > > > +static struct rte_afu_device * > > > +ifpga_scan_one(struct rte_devargs *devargs, > > > + struct rte_ifpga_device *ifpga_dev) > > > > usually ifpag_dev should be the first parameter here, and devargs > > follows > > Fixed. > > > > +{ > > > + struct rte_kvargs *kvlist = NULL; > > > + struct rte_rawdev *rawdev = NULL; > > > + struct rte_afu_device *afu_dev = NULL; > > > + struct rte_afu_pr_conf afu_pr_conf; > > > + int ret = 0; > > > + char *path = NULL; > > > + > > > + memset(&afu_pr_conf, 0, sizeof(struct rte_afu_pr_conf)); > > > + > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > + if (!kvlist) { > > > + IFPGA_BUS_ERR("error when parsing param"); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, > > > + &rte_ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) > > { > > > + IFPGA_BUS_ERR("error to parse %s", > > > + IFPGA_ARG_PORT); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > + IFPGA_ARG_PORT); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, > > > + &rte_ifpga_get_string_arg, &path) < 0) { > > > + IFPGA_BUS_ERR("Failed to parse %s", > > > + IFPGA_AFU_BTS); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > + IFPGA_AFU_BTS); > > > + goto end; > > > + } > > > + > > > + afu_pr_conf.afu_id.uuid.uuid_low = 0; > > > + afu_pr_conf.afu_id.uuid.uuid_high = 0; > > > + afu_pr_conf.pr_enable = path?1:0; > > > + > > > + rawdev = ifpga_dev->rdev; > > > + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) > > > + goto end; > > > + > > > + afu_dev = calloc(1, sizeof(*afu_dev)); > > > + if (!afu_dev) > > > + goto end; > > > + > > > + afu_dev->device.devargs = devargs; > > > + afu_dev->device.numa_node = SOCKET_ID_ANY; > > > + afu_dev->device.name = devargs->name; > > > + afu_dev->rawdev = rawdev; > > > + afu_dev->id.uuid.uuid_low = 0; > > > + afu_dev->id.uuid.uuid_high = 0; > > > + afu_dev->id.port = afu_pr_conf.afu_id.port; > > > + afu_dev->ifpga_dev = ifpga_dev; > > > + > > > + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) > > > + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); > > > + > > > + if (rawdev->dev_ops && > > > + rawdev->dev_ops->dev_start && > > > + rawdev->dev_ops->dev_start(rawdev)) > > > + goto free_dev; > > > + > > > + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); > > > + if (rawdev->dev_ops->firmware_load && > > > + rawdev->dev_ops->firmware_load(rawdev, > > > + &afu_pr_conf)){ > > > + IFPGA_BUS_ERR("firmware load error %d\n", ret); > > > + goto free_dev; > > > + } > > > + afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; > > > + afu_dev->id.uuid.uuid_high = afu_pr_conf.afu_id.uuid.uuid_high; > > > + > > > + return afu_dev; > > > + > > > +free_dev: > > > + free(afu_dev); > > > +end: > > > + if (kvlist) > > > + rte_kvargs_free(kvlist); > > > + if (path) > > > + free(path); > > > + > > > + return NULL; > > > +} > > > + > > > +/* > > > + * Scan the content of the FPGA bus, and the devices in the devices > > > + * list > > > + */ > > > +static int > > > +ifpga_scan(void) > > > +{ > > > + struct rte_ifpga_device *ifpga_dev; > > > + struct rte_devargs *devargs; > > > + struct rte_kvargs *kvlist = NULL; > > > + struct rte_rawdev *rawdev = NULL; > > > + char *name = NULL; > > > + char name1[RTE_RAWDEV_NAME_MAX_LEN]; > > > + struct rte_afu_device *afu_dev = NULL; > > > + > > > + /* for FPGA devices we scan the devargs_list populated via cmdline > > > +*/ > > > > I didn't see "--ifpga" is supported by cmdline, either you need to add > > corresponding parser or correct the comment here. > > To be honestly, ifpga_scan() is called by hotplug, lib_rte hotplug function will > construct it. > > > > + RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { > > > > > > IFPGA_BUS_NAME to replace "ifpga" here. IFPGA_BUS_NAME is used in some Macros, so I use IFPGA_ARG_NAME. > > > + if (devargs->bus != &rte_ifpga_bus) > > > + continue; > > > + > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > + if (!kvlist) { > > > + IFPGA_BUS_ERR("error when parsing param"); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, > > > + &rte_ifpga_get_string_arg, &name) < 0) { > > > + IFPGA_BUS_ERR("error to parse %s", > > > + IFPGA_ARG_NAME); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > + IFPGA_ARG_NAME); > > > + goto end; > > > + } > > > + > > > + memset(name1, 0, sizeof(name1)); > > > + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, > > "IFPGA:%s", > > > name); > > > + > > > + rawdev = rte_rawdev_pmd_get_named_dev(name1); > > > + if (!rawdev) > > > + goto end; > > > + > > > + if (ifpga_find_ifpga_dev(rawdev)) > > > + continue; > > > + > > > + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); > > > + if (!ifpga_dev) > > > + goto end; > > > + > > > + ifpga_dev->rdev = rawdev; > > > + TAILQ_INIT(&ifpga_dev->afu_list); > > > + > > > + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); > > > + afu_dev = ifpga_scan_one(devargs, ifpga_dev); > > > + if (afu_dev != NULL) > > > + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, > > next); > > > > I don't understand why we need afu_list?, seems we only add a new > > afu_dev into the list after create a new ifpga_dev, Is there any > > another place that we add one to list to make it reasonable? it looks > > like either a 1:1 or 1:0 for ifpga_dev:afu_dev? > > One FPAG may support more than one AFU. > > > > + } > > > + > > > +end: > > > + if (kvlist) > > > + rte_kvargs_free(kvlist); > > > + if (name) > > > + free(name); > > > + > > > + return 0; > > > +} > > > + > > > +/* > > > + * Match the AFU Driver and AFU Device using the ID Table */ > > > +static int rte_afu_match(const struct rte_afu_driver *afu_drv, > > > + const struct rte_afu_device *afu_dev) { > > > + const struct rte_afu_uuid *id_table; > > > + > > > + for (id_table = afu_drv->id_table; > > > + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); > > > + id_table++) { > > > + /* check if device's identifiers match the driver's ones */ > > > + if ((id_table->uuid_low != afu_dev->id.uuid.uuid_low) || > > > + id_table->uuid_high != > > > + afu_dev->id.uuid.uuid_high) > > > + continue; > > > + > > > + return 1; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +static int > > > +ifpga_probe_one_driver(struct rte_afu_driver *drv, > > > + struct rte_afu_device *afu_dev) > > > +{ > > > + int ret; > > > + > > > + if (!rte_afu_match(drv, afu_dev)) > > > + /* Match of device and driver failed */ > > > + return 1; > > > + > > > + /* reference driver structure */ > > > + afu_dev->driver = drv; > > > + afu_dev->device.driver = &drv->driver; > > > + > > > + /* call the driver probe() function */ > > > + ret = drv->probe(afu_dev); > > > + if (ret) { > > > + afu_dev->driver = NULL; > > > + afu_dev->device.driver = NULL; > > > + } > > > + > > > + return ret; > > > +} > > > + > > > +static int > > > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) { > > > + struct rte_afu_driver *drv = NULL; > > > + int ret = 0; > > > + > > > + if (afu_dev == NULL) > > > + return -1; > > > + > > > + /* Check if a driver is already loaded */ > > > + if (afu_dev->driver != NULL) > > > + return 0; > > > + > > > + TAILQ_FOREACH(drv, &afu_driver_list, next) { > > > + if (ifpga_probe_one_driver(drv, afu_dev)) { > > > + ret = -1; > > > + break; > > > + } > > > + } > > > + return ret; > > > +} > > > + > > > +/* > > > + * Scan the content of the Intel FPGA bus, and call the probe() > > > +function for > > > + * all registered drivers that have a matching entry in its > > > +id_table > > > + * for discovered devices. > > > + */ > > > +static int > > > +ifpga_probe(void) > > > +{ > > > + struct rte_ifpga_device *ifpga_dev; > > > + struct rte_afu_device *afu_dev = NULL; > > > + int ret = 0; > > > + > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > + > > > + if (afu_dev->device.driver) > > > + continue; > > > + > > > + ret = ifpga_probe_all_drivers(afu_dev); > > > + if (ret < 0) > > > + IFPGA_BUS_ERR("failed to initialize %s > > device\n", > > > + rte_ifpga_device_name(afu_dev)); > > > + } > > > + } > > > + > > > + return ret; > > > +} > > > + > > > +static int > > > +ifpga_plug(struct rte_device *dev) > > > +{ > > > + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); > > > +} > > > + > > > +static int > > > +ifpga_remove_driver(struct rte_afu_device *afu_dev) { > > > + const char *name; > > > + const struct rte_afu_driver *driver; > > > + > > > + name = rte_ifpga_device_name(afu_dev); > > > + if (!afu_dev->device.driver) { > > > + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); > > > + return 1; > > > + } > > > + > > > + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); > > > + return driver->remove(afu_dev); > > > +} > > > + > > > +static int > > > +ifpga_unplug(struct rte_device *dev) { > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > + struct rte_afu_device *afu_dev = NULL; > > > + struct rte_devargs *devargs = NULL; > > > + int ret; > > > + > > > + if (dev == NULL) > > > + return -EINVAL; > > > + > > > + afu_dev = RTE_DEV_TO_AFU(dev); > > > + if (!dev) > > > + return -ENOENT; > > > + > > > + ifpga_dev = afu_dev->ifpga_dev; > > > + devargs = dev->devargs; > > > + > > > + ret = ifpga_remove_driver(afu_dev); > > > > So what is the device type that be plugged into the ifgpa bus? > > ifpga_dev or afu_dev? If its afu_dev, why we need ifpga_dev? > > If it is ifpga_dev, we need remove ifpga_dev from ifpga_device_list here. > > The device type that be plugged into the ifpga bus is afu_dev. > And each afu_dev will be added into one ifpga_dev. > Each FPGA device bind to ifpga_dev. > > > > + if (ret) > > > + return ret; > > > + > > > + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); > > > + > > > + rte_devargs_remove(devargs->bus->name, devargs->name); > > > + free(afu_dev); > > > + return 0; > > > + > > > +} > > > + > > > +static struct rte_device * > > > +ifpga_find_device(const struct rte_device *start, > > > + rte_dev_cmp_t cmp, const void *data) { > > > + struct rte_ifpga_device *ifpga_dev; > > > + struct rte_afu_device *afu_dev; > > > + > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > + if (start && &afu_dev->device == start) { > > > + start = NULL; > > > + continue; > > > + } > > > + if (cmp(&afu_dev->device, data) == 0) > > > + return &afu_dev->device; > > > + } > > > + } > > > + return NULL; > > > +} > > > +static int > > > +ifpga_parse(const char *name, void *addr) { > > > + int *out = addr; > > > + struct rte_rawdev *rawdev = NULL; > > > + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; > > > + char *c1 = NULL, *c2 = NULL; > > > + int port = IFPGA_BUS_DEV_PORT_MAX; > > > + char str_port[8]; > > > + int str_port_len = 0; > > > + int ret; > > > + > > > + memset(str_port, 0, 8); > > > + c1 = strchr(name, '|'); > > > + if (c1 != NULL) { > > > + str_port_len = c1-name; > > > + c2 = c1+1; > > > + } > > > + > > > + if (str_port_len < 8 && > > > + str_port_len > 0) { > > > + memcpy(str_port, name, str_port_len); > > > + ret = sscanf(str_port, "%d", &port); > > > + if (ret == -1) > > > + return 0; > > > + } > > > + > > > + memset(rawdev_name, 0, sizeof(rawdev_name)); > > > + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", > > c2); > > > + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); > > > + > > > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > > > + rawdev && > > > + (addr != NULL)) > > > + *out = port; > > > + > > > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > > > + rawdev) > > > + return 0; > > > + else > > > + return 1; > > > +} > > > + > > > +static struct rte_bus rte_ifpga_bus = { > > > + .scan = ifpga_scan, > > > + .probe = ifpga_probe, > > > + .find_device = ifpga_find_device, > > > + .plug = ifpga_plug, > > > + .unplug = ifpga_unplug, > > > + .parse = ifpga_parse, > > > +}; > > > + > > > +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); > > > + > > > +RTE_INIT(ifpga_init_log) > > > +{ > > > + ifpga_bus_logtype = rte_log_register("bus.ifpga"); > > > + if (ifpga_bus_logtype >= 0) > > > + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); } > > > diff --git a/drivers/bus/ifpga/ifpga_common.c > > > b/drivers/bus/ifpga/ifpga_common.c > > > new file mode 100644 > > > index 0000000..78e2eae > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/ifpga_common.c > > > @@ -0,0 +1,88 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > + > > > +#include <string.h> > > > +#include <inttypes.h> > > > +#include <stdint.h> > > > +#include <stdlib.h> > > > +#include <stdio.h> > > > +#include <sys/queue.h> > > > +#include <sys/mman.h> > > > +#include <sys/types.h> > > > +#include <unistd.h> > > > +#include <fcntl.h> > > > + > > > +#include <rte_errno.h> > > > +#include <rte_bus.h> > > > +#include <rte_per_lcore.h> > > > +#include <rte_memory.h> > > > +#include <rte_memzone.h> > > > +#include <rte_eal.h> > > > +#include <rte_common.h> > > > + > > > +#include <rte_devargs.h> > > > +#include <rte_kvargs.h> > > > +#include <rte_alarm.h> > > > + > > > +#include "rte_bus_ifpga.h" > > > +#include "ifpga_logs.h" > > > +#include "ifpga_common.h" > > > + > > > +int rte_ifpga_get_string_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args) { > > > + if (!value || !extra_args) > > > + return -EINVAL; > > > + > > > + *(char **)extra_args = strdup(value); > > > + > > > + if (!*(char **)extra_args) > > > + return -ENOMEM; > > > + > > > + return 0; > > > +} > > > +int rte_ifpga_get_integer32_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args) { > > > + if (!value || !extra_args) > > > + return -EINVAL; > > > + > > > + *(int *)extra_args = strtoull(value, NULL, 0); > > > + > > > + return 0; > > > +} > > > +int ifpga_get_integer64_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args) { > > > + if (!value || !extra_args) > > > + return -EINVAL; > > > + > > > + *(uint64_t *)extra_args = strtoull(value, NULL, 0); > > > + > > > + return 0; > > > +} > > > +int ifpga_get_unsigned_long(const char *str, int base) { > > > + unsigned long num; > > > + char *end = NULL; > > > + > > > + errno = 0; > > > + > > > + num = strtoul(str, &end, base); > > > + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) > > > + return -1; > > > + > > > + return num; > > > +} > > > + > > > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > > + const struct rte_afu_id *afu_id1) > > > +{ > > > + if ((afu_id0->uuid.uuid_low == afu_id1->uuid.uuid_low) && > > > + (afu_id0->uuid.uuid_high == afu_id1->uuid.uuid_high) && > > > + (afu_id0->port == afu_id1->port)) { > > > + return 0; > > > + } else > > > + return 1; > > > +} > > > diff --git a/drivers/bus/ifpga/ifpga_common.h > > > b/drivers/bus/ifpga/ifpga_common.h > > > new file mode 100644 > > > index 0000000..f9254b9 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/ifpga_common.h > > > @@ -0,0 +1,18 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > + > > > +#ifndef _IFPGA_COMMON_H_ > > > +#define _IFPGA_COMMON_H_ > > > + > > > +int rte_ifpga_get_string_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args); int > > > +rte_ifpga_get_integer32_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args); int > > > +ifpga_get_integer64_arg(const char *key __rte_unused, > > > + const char *value, void *extra_args); int > > > +ifpga_get_unsigned_long(const char *str, int base); int > > > +ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > > + const struct rte_afu_id *afu_id1); > > > + > > > +#endif /* _IFPGA_COMMON_H_ */ > > > diff --git a/drivers/bus/ifpga/ifpga_logs.h > > > b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index > > > 0000000..873e0a4 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/ifpga_logs.h > > > @@ -0,0 +1,31 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > + > > > +#ifndef _IFPGA_LOGS_H_ > > > +#define _IFPGA_LOGS_H_ > > > + > > > +#include <rte_log.h> > > > + > > > +extern int ifpga_bus_logtype; > > > + > > > +#define IFPGA_LOG(level, fmt, args...) \ > > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > > + __func__, ##args) > > > + > > > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > > + __func__, ##args) > > > + > > > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > > > + > > > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > > > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) #define IFPGA_BUS_INFO(fmt, > > > +args...) \ > > > + IFPGA_BUS_LOG(INFO, fmt, ## args) > > > +#define IFPGA_BUS_ERR(fmt, args...) \ > > > + IFPGA_BUS_LOG(ERR, fmt, ## args) > > > +#define IFPGA_BUS_WARN(fmt, args...) \ > > > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > > > + > > > +#endif /* _IFPGA_BUS_LOGS_H_ */ > > > diff --git a/drivers/bus/ifpga/meson.build > > > b/drivers/bus/ifpga/meson.build new file mode 100644 index > > > 0000000..c9b08c8 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/meson.build > > > @@ -0,0 +1,8 @@ > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2010-2018 > > > +Intel Corporation > > > + > > > +deps += ['pci', 'kvargs', 'rawdev'] > > > +install_headers('rte_bus_ifpga.h') > > > +sources = files('ifpga_common.c', 'ifpga_bus.c') > > > + > > > +allow_experimental_apis = true > > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h > > > b/drivers/bus/ifpga/rte_bus_ifpga.h > > > new file mode 100644 > > > index 0000000..5c559e1 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > > > @@ -0,0 +1,160 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > + > > > +#ifndef _RTE_BUS_IFPGA_H_ > > > +#define _RTE_BUS_IFPGA_H_ > > > + > > > +/** > > > + * @file > > > + * > > > + * RTE Intel FPGA Bus Interface > > > + */ > > > + > > > +#ifdef __cplusplus > > > +extern "C" { > > > +#endif > > > + > > > +#include <rte_bus.h> > > > +#include <rte_pci.h> > > > + > > > +/** Name of Intel FPGA Bus */ > > > +#define IFPGA_BUS_NAME ifpga > > > + > > > +/* Forward declarations */ > > > +struct rte_afu_device; > > > + > > > +/** List of Intel AFU devices */ > > > +TAILQ_HEAD(afu_device_list, rte_afu_device); > > > +/** Double linked list of AFU device drivers. */ > > > +TAILQ_HEAD(afu_driver_list, rte_afu_driver); > > > + > > > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > > > + > > > +struct rte_afu_uuid { > > > + uint64_t uuid_low; > > > + uint64_t uuid_high; > > > +} __attribute__ ((packed)); > > > + > > > +#define IFPGA_BUS_DEV_PORT_MAX 4 > > > + > > > +/** > > > + * A structure describing an ID for a AFU driver. Each driver > > > +provides a > > > + * table of these IDs for each device that it supports. > > > + */ > > > +struct rte_afu_id { > > > + struct rte_afu_uuid uuid; > > > + int port; /**< port number */ > > > +} __attribute__ ((packed)); > > > + > > > +/** > > > + * A structure PR (Partial Reconfiguration) configuration AFU driver. > > > + */ > > > + > > > +struct rte_afu_pr_conf { > > > + struct rte_afu_id afu_id; > > > + int pr_enable; > > > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > > +}; > > > + > > > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > > > + > > > +/** > > > + * A structure describing a fpga device. > > > + */ > > > +struct rte_ifpga_device { > > > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ > > > + struct rte_rawdev *rdev; > > > + struct afu_device_list afu_list; /**< List of AFU devices */ }; > > > + > > > +/** > > > + * A structure describing a AFU device. > > > + */ > > > +struct rte_afu_device { > > > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ > > > + struct rte_device device; /**< Inherit core device */ > > > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > > > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > > > + struct rte_afu_id id; /**< AFU id within FPGA. */ > > > + uint32_t num_region; /**< number of regions found */ > > > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > > > + /**< AFU Memory Resource > > */ > > > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > > > + struct rte_afu_driver *driver; /**< Associated driver */ > > > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > > +} __attribute__ ((packed)); > > > + > > > +/** > > > + * @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_DRV_TO_AFU_CONST(ptr) \ > > > + container_of(ptr, const struct rte_afu_driver, driver) > > > + > > > +/** > > > + * Initialisation function for the driver called during FPGA BUS probing. > > > > > > typo: Initialization > > Fixed. > > > > + */ > > > +typedef int (afu_probe_t)(struct rte_afu_device *); > > > + > > > +/** > > > + * Uninitialisation function for the driver called during hotplugging. > > > > typo: Unintialization > > Fixed. > > > > + */ > > > +typedef int (afu_remove_t)(struct rte_afu_device *); > > > + > > > +/** > > > + * A structure describing a AFU device. > > > + */ > > > +struct rte_afu_driver { > > > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > > > + struct rte_driver driver; /**< Inherit core driver. */ > > > + afu_probe_t *probe; /**< Device Probe function. > > > */ > > > + afu_remove_t *remove; /**< Device Remove > > > function. */ > > > + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ > > > + uint32_t drv_flags; /**< Flags contolling handling of device. */ > > > > Typo Controlling > > And what is "flags controlling handling of device?" > > This variable is not used, so I have removed it. > > > > +}; > > > + > > > +static inline const char * > > > +rte_ifpga_device_name(const struct rte_afu_device *afu) { > > > + if (afu && afu->device.name) > > > + return afu->device.name; > > > + return NULL; > > > +} > > > + > > > +/** > > > + * Register a ifpga afu device driver. > > > + * > > > + * @param driver > > > + * A pointer to a rte_afu_driver structure describing the driver > > > + * to be registered. > > > + */ > > > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); > > > + > > > +/** > > > + * Unregister a ifpga afu device driver. > > > + * > > > + * @param driver > > > + * A pointer to a rte_afu_driver structure describing the driver > > > + * to be unregistered. > > > + */ > > > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > > > + > > > +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ RTE_INIT(afudrvinitfn_ > > > +##afudrv);\ static const char *afudrvinit_ ## nm ## _alias;\ static > > > +void afudrvinitfn_ ##afudrv(void)\ {\ > > > + (afudrv).driver.name = RTE_STR(nm);\ > > > + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ > > > + rte_ifpga_driver_register(&afudrv);\ > > > +} \ > > > +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) > > > + > > > +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ static const char > > > +*afudrvinit_ ## nm ## _alias = RTE_STR(alias) > > > + > > > +#endif /* _RTE_BUS_IFPGA_H_ */ > > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > new file mode 100644 > > > index 0000000..a027979 > > > --- /dev/null > > > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > @@ -0,0 +1,10 @@ > > > +DPDK_18.05 { > > > + global: > > > + > > > + rte_ifpga_get_integer32_arg; > > > + rte_ifpga_get_string_arg; > > > + rte_ifpga_driver_register; > > > + rte_ifpga_driver_unregister; > > > + > > > + local: *; > > > +}; > > > diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build index > > > 58dfbe2..52c755d 100644 > > > --- a/drivers/bus/meson.build > > > +++ b/drivers/bus/meson.build > > > @@ -1,7 +1,7 @@ > > > # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel > > > Corporation > > > > > > -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] > > > +drivers = ['dpaa', 'fslmc', 'ifpga', 'pci', 'vdev'] > > > std_deps = ['eal'] > > > config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' > > > driver_name_fmt = 'rte_bus_@0@' > > > diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 26f3563..3861e1a > > > 100644 > > > --- a/mk/rte.app.mk > > > +++ b/mk/rte.app.mk > > > @@ -255,6 +255,7 @@ ifeq > > > ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) > > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += > > > -lrte_pmd_dpaa2_cmdif > > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += > > > -lrte_pmd_dpaa2_qdma endif # CONFIG_RTE_LIBRTE_FSLMC_BUS > > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga > > > endif # CONFIG_RTE_LIBRTE_RAWDEV > > > > > > > > > -- > > > 1.8.3.1 > > > > Regards > > Qi ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-10 13:51 ` Xu, Rosen @ 2018-05-10 13:58 ` Zhang, Qi Z 2018-05-10 14:49 ` Thomas Monjalon 1 sibling, 0 replies; 149+ messages in thread From: Zhang, Qi Z @ 2018-05-10 13:58 UTC (permalink / raw) To: Xu, Rosen, dev, thomas Cc: Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet > -----Original Message----- > From: Xu, Rosen > Sent: Thursday, May 10, 2018 9:51 PM > To: Xu, Rosen <rosen.xu@intel.com>; Zhang, Qi Z <qi.z.zhang@intel.com>; > dev@dpdk.org; thomas@monjalon.net > Cc: Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, Declan > <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library > > Hi Qi, > > I miss one comment, so I fix it in this email. > > > -----Original Message----- > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > > Sent: Thursday, May 10, 2018 21:29 > > To: Zhang, Qi Z <qi.z.zhang@intel.com>; dev@dpdk.org; > > thomas@monjalon.net > > Cc: Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, Declan > > <declan.doherty@intel.com>; Richardson, Bruce > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > > <ferruh.yigit@intel.com>; Ananyev, Konstantin > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > Subject: Re: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > > Library > > > > Hi Qi, > > > > > -----Original Message----- > > > From: Zhang, Qi Z > > > Sent: Thursday, May 10, 2018 20:27 > > > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; > > thomas@monjalon.net > > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > > <roy.fan.zhang@intel.com>; Doherty, Declan > > > <declan.doherty@intel.com>; Richardson, Bruce > > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > > > <ferruh.yigit@intel.com>; Ananyev, Konstantin > > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > > Subject: RE: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA > > > BUS Library > > > > > > Hi Rosen: > > > > > > > -----Original Message----- > > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > > > > Sent: Wednesday, May 9, 2018 3:43 PM > > > > To: dev@dpdk.org; thomas@monjalon.net > > > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > > > <roy.fan.zhang@intel.com>; Doherty, Declan > > > > <declan.doherty@intel.com>; Richardson, Bruce > > > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, > > > > Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > > > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > > > Subject: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS > > > > Library > > > > > > > > From: Rosen Xu <rosen.xu@intel.com> > > > > > > > > Defined FPGA-BUS for Acceleration Drivers of AFUs > > > > > > > > 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan > > > > Process, probe Intel FPGA Rawdev Driver, it will be covered in following > patches. > > > > > > > > 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. > > > > This scan is trigged by hotplug of IFPGA Rawdev probe, in this > > > > scan the AFUs will be created and their drivers are also probed. > > > > > > > > This patch will introduce rte_afu_device which describe the AFU > > > > device listed in the FPGA-BUS. > > > > > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > > > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > > > > --- > > > > MAINTAINERS | 4 + > > > > config/common_base | 5 + > > > > doc/guides/rel_notes/release_18_05.rst | 5 + > > > > drivers/bus/Makefile | 1 + > > > > drivers/bus/ifpga/Makefile | 32 ++ > > > > drivers/bus/ifpga/ifpga_bus.c | 501 > > > > ++++++++++++++++++++++++++++ > > > > drivers/bus/ifpga/ifpga_common.c | 88 +++++ > > > > drivers/bus/ifpga/ifpga_common.h | 18 + > > > > drivers/bus/ifpga/ifpga_logs.h | 31 ++ > > > > drivers/bus/ifpga/meson.build | 8 + > > > > drivers/bus/ifpga/rte_bus_ifpga.h | 160 +++++++++ > > > > drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + > > > > drivers/bus/meson.build | 2 +- > > > > mk/rte.app.mk | 1 + > > > > 14 files changed, 865 insertions(+), 1 deletion(-) create mode > > > > 100644 drivers/bus/ifpga/Makefile create mode 100644 > > > > drivers/bus/ifpga/ifpga_bus.c create mode 100644 > > > > drivers/bus/ifpga/ifpga_common.c create mode 100644 > > > > drivers/bus/ifpga/ifpga_common.h create mode 100644 > > > > drivers/bus/ifpga/ifpga_logs.h create mode 100644 > > > > drivers/bus/ifpga/meson.build create mode 100644 > > > > drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 > > > > drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > > > > > diff --git a/MAINTAINERS b/MAINTAINERS index 7105920..fa0c5b1 > > > > 100644 > > > > --- a/MAINTAINERS > > > > +++ b/MAINTAINERS > > > > @@ -383,6 +383,10 @@ F: drivers/mempool/bucket/ Bus Drivers > > > > ----------- > > > > > > > > +Intel FPGA buses > > > > +M: Rosen Xu <rosen.xu@intel.com> > > > > +F: drivers/bus/ifpga/ > > > > + > > > > NXP buses > > > > M: Hemant Agrawal <hemant.agrawal@nxp.com> > > > > M: Shreyansh Jain <shreyansh.jain@nxp.com> diff --git > > > > a/config/common_base b/config/common_base index 0d181ac..1440316 > > > > 100644 > > > > --- a/config/common_base > > > > +++ b/config/common_base > > > > @@ -139,6 +139,11 @@ > > > > CONFIG_RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS=n > > > > CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n > > > > > > > > # > > > > +# Compile the Intel FPGA bus > > > > +# > > > > +CONFIG_RTE_LIBRTE_IFPGA_BUS=y > > > > + > > > > +# > > > > # Compile PCI bus driver > > > > # > > > > CONFIG_RTE_LIBRTE_PCI_BUS=y > > > > diff --git a/doc/guides/rel_notes/release_18_05.rst > > > > b/doc/guides/rel_notes/release_18_05.rst > > > > index 7187348..265950a 100644 > > > > --- a/doc/guides/rel_notes/release_18_05.rst > > > > +++ b/doc/guides/rel_notes/release_18_05.rst > > > > @@ -183,6 +183,11 @@ New Features > > > > stats/xstats on shared memory from secondary process, and also > > > > pdump packets on > > > > those virtual devices. > > > > > > > > +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** > > > > + > > > > + The Ifpga Bus library provides support for integrating any > > > > + Intel FPGA device with the DPDK framework. It provides Intel > > > > + FPGA Partial Bit Stream AFU(Accelerated Function Unit) scan and > > > > + drivers > > prove. > > > > > > > > API Changes > > > > ----------- > > > > diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index > > > > c251b65..ef7f247 100644 > > > > --- a/drivers/bus/Makefile > > > > +++ b/drivers/bus/Makefile > > > > @@ -7,6 +7,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa > ifeq > > > > ($(CONFIG_RTE_EAL_VFIO),y) > > > > DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc endif > > > > +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga > > > > DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci > > > > DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev > > > > > > > > diff --git a/drivers/bus/ifpga/Makefile > > > > b/drivers/bus/ifpga/Makefile new file mode 100644 index > > > > 0000000..3ff3bdb > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/Makefile > > > > @@ -0,0 +1,32 @@ > > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > > > > +Corporation > > > > + > > > > +include $(RTE_SDK)/mk/rte.vars.mk > > > > + > > > > +# > > > > +# library name > > > > +# > > > > +LIB = librte_bus_ifpga.a > > > > + > > > > +CFLAGS += -DALLOW_EXPERIMENTAL_API CFLAGS += -O3 CFLAGS += > > > > +$(WERROR_FLAGS) LDLIBS += -lrte_eal LDLIBS += -lrte_rawdev LDLIBS > > > > ++= -lrte_kvargs > > > > + > > > > +# versioning export map > > > > +EXPORT_MAP := rte_bus_ifpga_version.map > > > > + > > > > +# library version > > > > +LIBABIVER := 1 > > > > + > > > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c > > > > +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c > > > > + > > > > +# > > > > +# Export include files > > > > +# > > > > +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h > > > > + > > > > +include $(RTE_SDK)/mk/rte.lib.mk > > > > diff --git a/drivers/bus/ifpga/ifpga_bus.c > > > > b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index > > > > 0000000..e144c01 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/ifpga_bus.c > > > > @@ -0,0 +1,501 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > + > > > > +#include <string.h> > > > > +#include <inttypes.h> > > > > +#include <stdint.h> > > > > +#include <stdlib.h> > > > > +#include <stdio.h> > > > > +#include <sys/queue.h> > > > > +#include <sys/mman.h> > > > > +#include <sys/types.h> > > > > +#include <unistd.h> > > > > +#include <fcntl.h> > > > > + > > > > +#include <rte_errno.h> > > > > +#include <rte_bus.h> > > > > +#include <rte_per_lcore.h> > > > > +#include <rte_memory.h> > > > > +#include <rte_memzone.h> > > > > +#include <rte_eal.h> > > > > +#include <rte_common.h> > > > > + > > > > +#include <rte_devargs.h> > > > > +#include <rte_kvargs.h> > > > > +#include <rte_alarm.h> > > > > + > > > > +#include "rte_rawdev.h" > > > > +#include "rte_rawdev_pmd.h" > > > > +#include "rte_bus_ifpga.h" > > > > +#include "ifpga_logs.h" > > > > +#include "ifpga_common.h" > > > > + > > > > +int ifpga_bus_logtype; > > > > + > > > > +/* Forward declaration to access Intel FPGA bus > > > > + * on which iFPGA devices are connected */ static struct rte_bus > > > > +rte_ifpga_bus; > > > > + > > > > +/** Double linked list of IFPGA device. */ > > > > +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); > > > > + > > > > +static struct ifpga_device_list ifpga_device_list = > > > > + TAILQ_HEAD_INITIALIZER(ifpga_device_list); > > > > +static struct afu_driver_list afu_driver_list = > > > > + TAILQ_HEAD_INITIALIZER(afu_driver_list); > > > > + > > > > + > > > > +/* register a ifpga bus based driver */ void > > > > +rte_ifpga_driver_register(struct rte_afu_driver *driver) { > > > > + RTE_VERIFY(driver); > > > > + > > > > + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); } > > > > + > > > > +/* un-register a fpga bus based driver */ void > > > > +rte_ifpga_driver_unregister(struct rte_afu_driver *driver) { > > > > + TAILQ_REMOVE(&afu_driver_list, driver, next); } > > > > + > > > > +static struct rte_ifpga_device * > > > > +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) { > > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > > + > > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > > + if (rdev && > > > > + ifpga_dev->rdev && > > > > + ifpga_dev->rdev == rdev) > > > > + return ifpga_dev; > > > > + } > > > > + return NULL; > > > > +} > > > > + > > > > +static struct rte_afu_device * > > > > +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, > > > > + const struct rte_afu_id *afu_id) { > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + > > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > > + if (!ifpga_afu_id_cmp(&afu_dev->id, afu_id)) > > > > + return afu_dev; > > > > + } > > > > + return NULL; > > > > +} > > > > + > > > > +static const char * const valid_args[] = { > > > > +#define IFPGA_ARG_NAME "ifpga" > > > > + IFPGA_ARG_NAME, > > > > +#define IFPGA_ARG_PORT "port" > > > > + IFPGA_ARG_PORT, > > > > +#define IFPGA_AFU_BTS "afu_bts" > > > > + IFPGA_AFU_BTS, > > > > + NULL > > > > +}; > > > > + > > > > +/* > > > > + * Scan the content of the FPGA bus, and the devices in the > > > > +devices > > > > + * list > > > > + */ > > > > +static struct rte_afu_device * > > > > +ifpga_scan_one(struct rte_devargs *devargs, > > > > + struct rte_ifpga_device *ifpga_dev) > > > > > > usually ifpag_dev should be the first parameter here, and devargs > > > follows > > > > Fixed. > > > > > > +{ > > > > + struct rte_kvargs *kvlist = NULL; > > > > + struct rte_rawdev *rawdev = NULL; > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + struct rte_afu_pr_conf afu_pr_conf; > > > > + int ret = 0; > > > > + char *path = NULL; > > > > + > > > > + memset(&afu_pr_conf, 0, sizeof(struct rte_afu_pr_conf)); > > > > + > > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > > + if (!kvlist) { > > > > + IFPGA_BUS_ERR("error when parsing param"); > > > > + goto end; > > > > + } > > > > + > > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, > > > > + &rte_ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) > > > { > > > > + IFPGA_BUS_ERR("error to parse %s", > > > > + IFPGA_ARG_PORT); > > > > + goto end; > > > > + } > > > > + } else { > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > + IFPGA_ARG_PORT); > > > > + goto end; > > > > + } > > > > + > > > > + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { > > > > + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, > > > > + &rte_ifpga_get_string_arg, &path) < 0) { > > > > + IFPGA_BUS_ERR("Failed to parse %s", > > > > + IFPGA_AFU_BTS); > > > > + goto end; > > > > + } > > > > + } else { > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > + IFPGA_AFU_BTS); > > > > + goto end; > > > > + } > > > > + > > > > + afu_pr_conf.afu_id.uuid.uuid_low = 0; > > > > + afu_pr_conf.afu_id.uuid.uuid_high = 0; > > > > + afu_pr_conf.pr_enable = path?1:0; > > > > + > > > > + rawdev = ifpga_dev->rdev; > > > > + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) > > > > + goto end; > > > > + > > > > + afu_dev = calloc(1, sizeof(*afu_dev)); > > > > + if (!afu_dev) > > > > + goto end; > > > > + > > > > + afu_dev->device.devargs = devargs; > > > > + afu_dev->device.numa_node = SOCKET_ID_ANY; > > > > + afu_dev->device.name = devargs->name; > > > > + afu_dev->rawdev = rawdev; > > > > + afu_dev->id.uuid.uuid_low = 0; > > > > + afu_dev->id.uuid.uuid_high = 0; > > > > + afu_dev->id.port = afu_pr_conf.afu_id.port; > > > > + afu_dev->ifpga_dev = ifpga_dev; > > > > + > > > > + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) > > > > + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); > > > > + > > > > + if (rawdev->dev_ops && > > > > + rawdev->dev_ops->dev_start && > > > > + rawdev->dev_ops->dev_start(rawdev)) > > > > + goto free_dev; > > > > + > > > > + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); > > > > + if (rawdev->dev_ops->firmware_load && > > > > + rawdev->dev_ops->firmware_load(rawdev, > > > > + &afu_pr_conf)){ > > > > + IFPGA_BUS_ERR("firmware load error %d\n", ret); > > > > + goto free_dev; > > > > + } > > > > + afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; > > > > + afu_dev->id.uuid.uuid_high = afu_pr_conf.afu_id.uuid.uuid_high; > > > > + > > > > + return afu_dev; > > > > + > > > > +free_dev: > > > > + free(afu_dev); > > > > +end: > > > > + if (kvlist) > > > > + rte_kvargs_free(kvlist); > > > > + if (path) > > > > + free(path); > > > > + > > > > + return NULL; > > > > +} > > > > + > > > > +/* > > > > + * Scan the content of the FPGA bus, and the devices in the > > > > +devices > > > > + * list > > > > + */ > > > > +static int > > > > +ifpga_scan(void) > > > > +{ > > > > + struct rte_ifpga_device *ifpga_dev; > > > > + struct rte_devargs *devargs; > > > > + struct rte_kvargs *kvlist = NULL; > > > > + struct rte_rawdev *rawdev = NULL; > > > > + char *name = NULL; > > > > + char name1[RTE_RAWDEV_NAME_MAX_LEN]; > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + > > > > + /* for FPGA devices we scan the devargs_list populated via > > > > +cmdline */ > > > > > > I didn't see "--ifpga" is supported by cmdline, either you need to > > > add corresponding parser or correct the comment here. > > > > To be honestly, ifpga_scan() is called by hotplug, lib_rte hotplug > > function will construct it. > > > > > > + RTE_EAL_DEVARGS_FOREACH("ifpga", devargs) { > > > > > > > > > IFPGA_BUS_NAME to replace "ifpga" here. > > IFPGA_BUS_NAME is used in some Macros, so I use IFPGA_ARG_NAME. Though they have the same value, but different meanings, the first argument of RTE_EAL_DEVARGS_FOREACH actually is "busname", we should parse bus name here. Though not a big deal, but I don't know why we can't use IFPGA_BUS_NAME? > > > > > + if (devargs->bus != &rte_ifpga_bus) > > > > + continue; > > > > + > > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > > + if (!kvlist) { > > > > + IFPGA_BUS_ERR("error when parsing param"); > > > > + goto end; > > > > + } > > > > + > > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { > > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, > > > > + &rte_ifpga_get_string_arg, &name) < 0) { > > > > + IFPGA_BUS_ERR("error to parse %s", > > > > + IFPGA_ARG_NAME); > > > > + goto end; > > > > + } > > > > + } else { > > > > + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", > > > > + IFPGA_ARG_NAME); > > > > + goto end; > > > > + } > > > > + > > > > + memset(name1, 0, sizeof(name1)); > > > > + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, > > > "IFPGA:%s", > > > > name); > > > > + > > > > + rawdev = rte_rawdev_pmd_get_named_dev(name1); > > > > + if (!rawdev) > > > > + goto end; > > > > + > > > > + if (ifpga_find_ifpga_dev(rawdev)) > > > > + continue; > > > > + > > > > + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); > > > > + if (!ifpga_dev) > > > > + goto end; > > > > + > > > > + ifpga_dev->rdev = rawdev; > > > > + TAILQ_INIT(&ifpga_dev->afu_list); > > > > + > > > > + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); > > > > + afu_dev = ifpga_scan_one(devargs, ifpga_dev); > > > > + if (afu_dev != NULL) > > > > + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, > > > next); > > > > > > I don't understand why we need afu_list?, seems we only add a new > > > afu_dev into the list after create a new ifpga_dev, Is there any > > > another place that we add one to list to make it reasonable? it > > > looks like either a 1:1 or 1:0 for ifpga_dev:afu_dev? > > > > One FPAG may support more than one AFU. > > > > > > + } > > > > + > > > > +end: > > > > + if (kvlist) > > > > + rte_kvargs_free(kvlist); > > > > + if (name) > > > > + free(name); > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +/* > > > > + * Match the AFU Driver and AFU Device using the ID Table */ > > > > +static int rte_afu_match(const struct rte_afu_driver *afu_drv, > > > > + const struct rte_afu_device *afu_dev) { > > > > + const struct rte_afu_uuid *id_table; > > > > + > > > > + for (id_table = afu_drv->id_table; > > > > + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); > > > > + id_table++) { > > > > + /* check if device's identifiers match the driver's ones */ > > > > + if ((id_table->uuid_low != afu_dev->id.uuid.uuid_low) || > > > > + id_table->uuid_high != > > > > + afu_dev->id.uuid.uuid_high) > > > > + continue; > > > > + > > > > + return 1; > > > > + } > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int > > > > +ifpga_probe_one_driver(struct rte_afu_driver *drv, > > > > + struct rte_afu_device *afu_dev) { > > > > + int ret; > > > > + > > > > + if (!rte_afu_match(drv, afu_dev)) > > > > + /* Match of device and driver failed */ > > > > + return 1; > > > > + > > > > + /* reference driver structure */ > > > > + afu_dev->driver = drv; > > > > + afu_dev->device.driver = &drv->driver; > > > > + > > > > + /* call the driver probe() function */ > > > > + ret = drv->probe(afu_dev); > > > > + if (ret) { > > > > + afu_dev->driver = NULL; > > > > + afu_dev->device.driver = NULL; > > > > + } > > > > + > > > > + return ret; > > > > +} > > > > + > > > > +static int > > > > +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) { > > > > + struct rte_afu_driver *drv = NULL; > > > > + int ret = 0; > > > > + > > > > + if (afu_dev == NULL) > > > > + return -1; > > > > + > > > > + /* Check if a driver is already loaded */ > > > > + if (afu_dev->driver != NULL) > > > > + return 0; > > > > + > > > > + TAILQ_FOREACH(drv, &afu_driver_list, next) { > > > > + if (ifpga_probe_one_driver(drv, afu_dev)) { > > > > + ret = -1; > > > > + break; > > > > + } > > > > + } > > > > + return ret; > > > > +} > > > > + > > > > +/* > > > > + * Scan the content of the Intel FPGA bus, and call the probe() > > > > +function for > > > > + * all registered drivers that have a matching entry in its > > > > +id_table > > > > + * for discovered devices. > > > > + */ > > > > +static int > > > > +ifpga_probe(void) > > > > +{ > > > > + struct rte_ifpga_device *ifpga_dev; > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + int ret = 0; > > > > + > > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > > + > > > > + if (afu_dev->device.driver) > > > > + continue; > > > > + > > > > + ret = ifpga_probe_all_drivers(afu_dev); > > > > + if (ret < 0) > > > > + IFPGA_BUS_ERR("failed to initialize %s > > > device\n", > > > > + rte_ifpga_device_name(afu_dev)); > > > > + } > > > > + } > > > > + > > > > + return ret; > > > > +} > > > > + > > > > +static int > > > > +ifpga_plug(struct rte_device *dev) { > > > > + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); > > > > +} > > > > + > > > > +static int > > > > +ifpga_remove_driver(struct rte_afu_device *afu_dev) { > > > > + const char *name; > > > > + const struct rte_afu_driver *driver; > > > > + > > > > + name = rte_ifpga_device_name(afu_dev); > > > > + if (!afu_dev->device.driver) { > > > > + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); > > > > + return 1; > > > > + } > > > > + > > > > + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); > > > > + return driver->remove(afu_dev); > > > > +} > > > > + > > > > +static int > > > > +ifpga_unplug(struct rte_device *dev) { > > > > + struct rte_ifpga_device *ifpga_dev = NULL; > > > > + struct rte_afu_device *afu_dev = NULL; > > > > + struct rte_devargs *devargs = NULL; > > > > + int ret; > > > > + > > > > + if (dev == NULL) > > > > + return -EINVAL; > > > > + > > > > + afu_dev = RTE_DEV_TO_AFU(dev); > > > > + if (!dev) > > > > + return -ENOENT; > > > > + > > > > + ifpga_dev = afu_dev->ifpga_dev; > > > > + devargs = dev->devargs; > > > > + > > > > + ret = ifpga_remove_driver(afu_dev); > > > > > > So what is the device type that be plugged into the ifgpa bus? > > > ifpga_dev or afu_dev? If its afu_dev, why we need ifpga_dev? > > > If it is ifpga_dev, we need remove ifpga_dev from ifpga_device_list here. > > > > The device type that be plugged into the ifpga bus is afu_dev. > > And each afu_dev will be added into one ifpga_dev. > > Each FPGA device bind to ifpga_dev. > > > > > > + if (ret) > > > > + return ret; > > > > + > > > > + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); > > > > + > > > > + rte_devargs_remove(devargs->bus->name, devargs->name); > > > > + free(afu_dev); > > > > + return 0; > > > > + > > > > +} > > > > + > > > > +static struct rte_device * > > > > +ifpga_find_device(const struct rte_device *start, > > > > + rte_dev_cmp_t cmp, const void *data) { > > > > + struct rte_ifpga_device *ifpga_dev; > > > > + struct rte_afu_device *afu_dev; > > > > + > > > > + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { > > > > + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { > > > > + if (start && &afu_dev->device == start) { > > > > + start = NULL; > > > > + continue; > > > > + } > > > > + if (cmp(&afu_dev->device, data) == 0) > > > > + return &afu_dev->device; > > > > + } > > > > + } > > > > + return NULL; > > > > +} > > > > +static int > > > > +ifpga_parse(const char *name, void *addr) { > > > > + int *out = addr; > > > > + struct rte_rawdev *rawdev = NULL; > > > > + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; > > > > + char *c1 = NULL, *c2 = NULL; > > > > + int port = IFPGA_BUS_DEV_PORT_MAX; > > > > + char str_port[8]; > > > > + int str_port_len = 0; > > > > + int ret; > > > > + > > > > + memset(str_port, 0, 8); > > > > + c1 = strchr(name, '|'); > > > > + if (c1 != NULL) { > > > > + str_port_len = c1-name; > > > > + c2 = c1+1; > > > > + } > > > > + > > > > + if (str_port_len < 8 && > > > > + str_port_len > 0) { > > > > + memcpy(str_port, name, str_port_len); > > > > + ret = sscanf(str_port, "%d", &port); > > > > + if (ret == -1) > > > > + return 0; > > > > + } > > > > + > > > > + memset(rawdev_name, 0, sizeof(rawdev_name)); > > > > + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, > "IFPGA:%s", > > > c2); > > > > + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); > > > > + > > > > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > > > > + rawdev && > > > > + (addr != NULL)) > > > > + *out = port; > > > > + > > > > + if ((port < IFPGA_BUS_DEV_PORT_MAX) && > > > > + rawdev) > > > > + return 0; > > > > + else > > > > + return 1; > > > > +} > > > > + > > > > +static struct rte_bus rte_ifpga_bus = { > > > > + .scan = ifpga_scan, > > > > + .probe = ifpga_probe, > > > > + .find_device = ifpga_find_device, > > > > + .plug = ifpga_plug, > > > > + .unplug = ifpga_unplug, > > > > + .parse = ifpga_parse, > > > > +}; > > > > + > > > > +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); > > > > + > > > > +RTE_INIT(ifpga_init_log) > > > > +{ > > > > + ifpga_bus_logtype = rte_log_register("bus.ifpga"); > > > > + if (ifpga_bus_logtype >= 0) > > > > + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); } > > > > diff --git a/drivers/bus/ifpga/ifpga_common.c > > > > b/drivers/bus/ifpga/ifpga_common.c > > > > new file mode 100644 > > > > index 0000000..78e2eae > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/ifpga_common.c > > > > @@ -0,0 +1,88 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > + > > > > +#include <string.h> > > > > +#include <inttypes.h> > > > > +#include <stdint.h> > > > > +#include <stdlib.h> > > > > +#include <stdio.h> > > > > +#include <sys/queue.h> > > > > +#include <sys/mman.h> > > > > +#include <sys/types.h> > > > > +#include <unistd.h> > > > > +#include <fcntl.h> > > > > + > > > > +#include <rte_errno.h> > > > > +#include <rte_bus.h> > > > > +#include <rte_per_lcore.h> > > > > +#include <rte_memory.h> > > > > +#include <rte_memzone.h> > > > > +#include <rte_eal.h> > > > > +#include <rte_common.h> > > > > + > > > > +#include <rte_devargs.h> > > > > +#include <rte_kvargs.h> > > > > +#include <rte_alarm.h> > > > > + > > > > +#include "rte_bus_ifpga.h" > > > > +#include "ifpga_logs.h" > > > > +#include "ifpga_common.h" > > > > + > > > > +int rte_ifpga_get_string_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args) { > > > > + if (!value || !extra_args) > > > > + return -EINVAL; > > > > + > > > > + *(char **)extra_args = strdup(value); > > > > + > > > > + if (!*(char **)extra_args) > > > > + return -ENOMEM; > > > > + > > > > + return 0; > > > > +} > > > > +int rte_ifpga_get_integer32_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args) { > > > > + if (!value || !extra_args) > > > > + return -EINVAL; > > > > + > > > > + *(int *)extra_args = strtoull(value, NULL, 0); > > > > + > > > > + return 0; > > > > +} > > > > +int ifpga_get_integer64_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args) { > > > > + if (!value || !extra_args) > > > > + return -EINVAL; > > > > + > > > > + *(uint64_t *)extra_args = strtoull(value, NULL, 0); > > > > + > > > > + return 0; > > > > +} > > > > +int ifpga_get_unsigned_long(const char *str, int base) { > > > > + unsigned long num; > > > > + char *end = NULL; > > > > + > > > > + errno = 0; > > > > + > > > > + num = strtoul(str, &end, base); > > > > + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) > > > > + return -1; > > > > + > > > > + return num; > > > > +} > > > > + > > > > +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > > > + const struct rte_afu_id *afu_id1) { > > > > + if ((afu_id0->uuid.uuid_low == afu_id1->uuid.uuid_low) && > > > > + (afu_id0->uuid.uuid_high == afu_id1->uuid.uuid_high) && > > > > + (afu_id0->port == afu_id1->port)) { > > > > + return 0; > > > > + } else > > > > + return 1; > > > > +} > > > > diff --git a/drivers/bus/ifpga/ifpga_common.h > > > > b/drivers/bus/ifpga/ifpga_common.h > > > > new file mode 100644 > > > > index 0000000..f9254b9 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/ifpga_common.h > > > > @@ -0,0 +1,18 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > + > > > > +#ifndef _IFPGA_COMMON_H_ > > > > +#define _IFPGA_COMMON_H_ > > > > + > > > > +int rte_ifpga_get_string_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args); int > > > > +rte_ifpga_get_integer32_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args); int > > > > +ifpga_get_integer64_arg(const char *key __rte_unused, > > > > + const char *value, void *extra_args); int > > > > +ifpga_get_unsigned_long(const char *str, int base); int > > > > +ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, > > > > + const struct rte_afu_id *afu_id1); > > > > + > > > > +#endif /* _IFPGA_COMMON_H_ */ > > > > diff --git a/drivers/bus/ifpga/ifpga_logs.h > > > > b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index > > > > 0000000..873e0a4 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/ifpga_logs.h > > > > @@ -0,0 +1,31 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > + > > > > +#ifndef _IFPGA_LOGS_H_ > > > > +#define _IFPGA_LOGS_H_ > > > > + > > > > +#include <rte_log.h> > > > > + > > > > +extern int ifpga_bus_logtype; > > > > + > > > > +#define IFPGA_LOG(level, fmt, args...) \ > > > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > > > + __func__, ##args) > > > > + > > > > +#define IFPGA_BUS_LOG(level, fmt, args...) \ > > > > + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ > > > > + __func__, ##args) > > > > + > > > > +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") > > > > + > > > > +#define IFPGA_BUS_DEBUG(fmt, args...) \ > > > > + IFPGA_BUS_LOG(DEBUG, fmt, ## args) #define IFPGA_BUS_INFO(fmt, > > > > +args...) \ > > > > + IFPGA_BUS_LOG(INFO, fmt, ## args) #define IFPGA_BUS_ERR(fmt, > > > > +args...) \ > > > > + IFPGA_BUS_LOG(ERR, fmt, ## args) #define IFPGA_BUS_WARN(fmt, > > > > +args...) \ > > > > + IFPGA_BUS_LOG(WARNING, fmt, ## args) > > > > + > > > > +#endif /* _IFPGA_BUS_LOGS_H_ */ > > > > diff --git a/drivers/bus/ifpga/meson.build > > > > b/drivers/bus/ifpga/meson.build new file mode 100644 index > > > > 0000000..c9b08c8 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/meson.build > > > > @@ -0,0 +1,8 @@ > > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2010-2018 > > > > +Intel Corporation > > > > + > > > > +deps += ['pci', 'kvargs', 'rawdev'] > > > > +install_headers('rte_bus_ifpga.h') > > > > +sources = files('ifpga_common.c', 'ifpga_bus.c') > > > > + > > > > +allow_experimental_apis = true > > > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h > > > > b/drivers/bus/ifpga/rte_bus_ifpga.h > > > > new file mode 100644 > > > > index 0000000..5c559e1 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/rte_bus_ifpga.h > > > > @@ -0,0 +1,160 @@ > > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > > + > > > > +#ifndef _RTE_BUS_IFPGA_H_ > > > > +#define _RTE_BUS_IFPGA_H_ > > > > + > > > > +/** > > > > + * @file > > > > + * > > > > + * RTE Intel FPGA Bus Interface > > > > + */ > > > > + > > > > +#ifdef __cplusplus > > > > +extern "C" { > > > > +#endif > > > > + > > > > +#include <rte_bus.h> > > > > +#include <rte_pci.h> > > > > + > > > > +/** Name of Intel FPGA Bus */ > > > > +#define IFPGA_BUS_NAME ifpga > > > > + > > > > +/* Forward declarations */ > > > > +struct rte_afu_device; > > > > + > > > > +/** List of Intel AFU devices */ > > > > +TAILQ_HEAD(afu_device_list, rte_afu_device); > > > > +/** Double linked list of AFU device drivers. */ > > > > +TAILQ_HEAD(afu_driver_list, rte_afu_driver); > > > > + > > > > +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 > > > > + > > > > +struct rte_afu_uuid { > > > > + uint64_t uuid_low; > > > > + uint64_t uuid_high; > > > > +} __attribute__ ((packed)); > > > > + > > > > +#define IFPGA_BUS_DEV_PORT_MAX 4 > > > > + > > > > +/** > > > > + * A structure describing an ID for a AFU driver. Each driver > > > > +provides a > > > > + * table of these IDs for each device that it supports. > > > > + */ > > > > +struct rte_afu_id { > > > > + struct rte_afu_uuid uuid; > > > > + int port; /**< port number */ > > > > +} __attribute__ ((packed)); > > > > + > > > > +/** > > > > + * A structure PR (Partial Reconfiguration) configuration AFU driver. > > > > + */ > > > > + > > > > +struct rte_afu_pr_conf { > > > > + struct rte_afu_id afu_id; > > > > + int pr_enable; > > > > + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > > > +}; > > > > + > > > > +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) > > > > + > > > > +/** > > > > + * A structure describing a fpga device. > > > > + */ > > > > +struct rte_ifpga_device { > > > > + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. > */ > > > > + struct rte_rawdev *rdev; > > > > + struct afu_device_list afu_list; /**< List of AFU devices */ }; > > > > + > > > > +/** > > > > + * A structure describing a AFU device. > > > > + */ > > > > +struct rte_afu_device { > > > > + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. > */ > > > > + struct rte_device device; /**< Inherit core device */ > > > > + struct rte_rawdev *rawdev; /**< Point Rawdev */ > > > > + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > > > > + struct rte_afu_id id; /**< AFU id within FPGA. > */ > > > > + uint32_t num_region; /**< number of regions found */ > > > > + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; > > > > + /**< AFU Memory Resource > > > */ > > > > + struct rte_intr_handle intr_handle; /**< Interrupt handle */ > > > > + struct rte_afu_driver *driver; /**< Associated driver */ > > > > + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; > > > > +} __attribute__ ((packed)); > > > > + > > > > +/** > > > > + * @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_DRV_TO_AFU_CONST(ptr) \ > > > > + container_of(ptr, const struct rte_afu_driver, driver) > > > > + > > > > +/** > > > > + * Initialisation function for the driver called during FPGA BUS probing. > > > > > > > > > typo: Initialization > > > > Fixed. > > > > > > + */ > > > > +typedef int (afu_probe_t)(struct rte_afu_device *); > > > > + > > > > +/** > > > > + * Uninitialisation function for the driver called during hotplugging. > > > > > > typo: Unintialization > > > > Fixed. > > > > > > + */ > > > > +typedef int (afu_remove_t)(struct rte_afu_device *); > > > > + > > > > +/** > > > > + * A structure describing a AFU device. > > > > + */ > > > > +struct rte_afu_driver { > > > > + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ > > > > + struct rte_driver driver; /**< Inherit core driver. */ > > > > + afu_probe_t *probe; /**< Device Probe > function. > > > > */ > > > > + afu_remove_t *remove; /**< Device Remove > > > > function. */ > > > > + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. > */ > > > > + uint32_t drv_flags; /**< Flags contolling handling of device. > */ > > > > > > Typo Controlling > > > And what is "flags controlling handling of device?" > > > > This variable is not used, so I have removed it. > > > > > > +}; > > > > + > > > > +static inline const char * > > > > +rte_ifpga_device_name(const struct rte_afu_device *afu) { > > > > + if (afu && afu->device.name) > > > > + return afu->device.name; > > > > + return NULL; > > > > +} > > > > + > > > > +/** > > > > + * Register a ifpga afu device driver. > > > > + * > > > > + * @param driver > > > > + * A pointer to a rte_afu_driver structure describing the driver > > > > + * to be registered. > > > > + */ > > > > +void rte_ifpga_driver_register(struct rte_afu_driver *driver); > > > > + > > > > +/** > > > > + * Unregister a ifpga afu device driver. > > > > + * > > > > + * @param driver > > > > + * A pointer to a rte_afu_driver structure describing the driver > > > > + * to be unregistered. > > > > + */ > > > > +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); > > > > + > > > > +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ RTE_INIT(afudrvinitfn_ > > > > +##afudrv);\ static const char *afudrvinit_ ## nm ## _alias;\ > > > > +static void afudrvinitfn_ ##afudrv(void)\ {\ > > > > + (afudrv).driver.name = RTE_STR(nm);\ > > > > + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ > > > > + rte_ifpga_driver_register(&afudrv);\ > > > > +} \ > > > > +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) > > > > + > > > > +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ static const char > > > > +*afudrvinit_ ## nm ## _alias = RTE_STR(alias) > > > > + > > > > +#endif /* _RTE_BUS_IFPGA_H_ */ > > > > diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > new file mode 100644 > > > > index 0000000..a027979 > > > > --- /dev/null > > > > +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map > > > > @@ -0,0 +1,10 @@ > > > > +DPDK_18.05 { > > > > + global: > > > > + > > > > + rte_ifpga_get_integer32_arg; > > > > + rte_ifpga_get_string_arg; > > > > + rte_ifpga_driver_register; > > > > + rte_ifpga_driver_unregister; > > > > + > > > > + local: *; > > > > +}; > > > > diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build > > > > index 58dfbe2..52c755d 100644 > > > > --- a/drivers/bus/meson.build > > > > +++ b/drivers/bus/meson.build > > > > @@ -1,7 +1,7 @@ > > > > # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 > > > > Intel Corporation > > > > > > > > -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] > > > > +drivers = ['dpaa', 'fslmc', 'ifpga', 'pci', 'vdev'] > > > > std_deps = ['eal'] > > > > config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' > > > > driver_name_fmt = 'rte_bus_@0@' > > > > diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 26f3563..3861e1a > > > > 100644 > > > > --- a/mk/rte.app.mk > > > > +++ b/mk/rte.app.mk > > > > @@ -255,6 +255,7 @@ ifeq > > > > ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) > > > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += > > > > -lrte_pmd_dpaa2_cmdif > > > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += > > > > -lrte_pmd_dpaa2_qdma endif # CONFIG_RTE_LIBRTE_FSLMC_BUS > > > > +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga > > > > endif # CONFIG_RTE_LIBRTE_RAWDEV > > > > > > > > > > > > -- > > > > 1.8.3.1 > > > > > > Regards > > > Qi ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-10 13:51 ` Xu, Rosen 2018-05-10 13:58 ` Zhang, Qi Z @ 2018-05-10 14:49 ` Thomas Monjalon 1 sibling, 0 replies; 149+ messages in thread From: Thomas Monjalon @ 2018-05-10 14:49 UTC (permalink / raw) To: Xu, Rosen, Zhang, Qi Z Cc: dev, Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet 10/05/2018 15:51, Xu, Rosen: > Hi Qi, > > I miss one comment, so I fix it in this email. In order to avoid missing comments, and to ease reading for others, please remove the useless context lines when replying. ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v10 2/3] iFPGA: Add Intel FPGA OPAE Share Code 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 0/3] Introduce Intel FPGA BUS Xu, Rosen 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen @ 2018-05-09 7:43 ` Xu, Rosen 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-09 7:43 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Xu, Yilun From: Tianfei Zhang <tianfei.zhang@intel.com> This patch adds Intel FPGA Open Programmable Acceleration Engine (OPAE)[1] base driver code, in order to support Intel FPGA devices under DPDK. The base code currently supports Intel FPGA solutions including integrated solution (Intel(R) Xeon(R) CPU with FPGAs) and discrete solution (Intel(R) Programmable Acceleration Card with Intel(R) Arria(R) 10 FPGA) and it could be extended to support more FPGA devices in the future. Please refer to [1][2] for more introduction on OPAE and Intel FPGAs. [1] https://01.org/OPAE [2] https://www.altera.com/solutions/acceleration-hub/overview.html Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> Signed-off-by: Wu, Hao <hao.wu@intel.com> Signed-off-by: Xu, Yilun <yilun.xu@intel.com> --- MAINTAINERS | 4 + drivers/raw/ifpga_rawdev/base/Makefile | 30 + drivers/raw/ifpga_rawdev/base/README | 31 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 294 ++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 28 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 57 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1661 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 824 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 11 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 314 ++++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 164 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 734 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 301 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 403 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 715 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 372 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 127 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 408 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 165 ++ drivers/raw/ifpga_rawdev/base/meson.build | 34 + drivers/raw/ifpga_rawdev/base/opae_debug.c | 99 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 19 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 381 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 253 +++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 145 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 279 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 81 + .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 75 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 45 + 29 files changed, 8054 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/README create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h diff --git a/MAINTAINERS b/MAINTAINERS index fa0c5b1..9c27d5a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -850,6 +850,10 @@ F: doc/guides/eventdevs/opdl.rst Rawdev Drivers -------------- +Intel FPGA +M: Tianfei zhang <tianfei.zhang@intel.com> +F: drivers/raw/ifpga_rawdev/base/ + NXP DPAA2 QDMA M: Nipun Gupta <nipun.gupta@nxp.com> F: drivers/raw/dpaa2_qdma/ diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile new file mode 100644 index 0000000..ade3551 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -0,0 +1,30 @@ +#SPDX-License-Identifier: BSD-3-Clause +#Copyright(c) 2010-2018 Intel Corporation + +ifneq ($(CONFIG_RTE_LIBRTE_EAL),) +OSDEP := osdep_rte +else +OSDEP := osdep_raw +endif + +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev/base/$(OSDEP) + +SRCS-y += ifpga_api.c +SRCS-y += ifpga_enumerate.c +SRCS-y += ifpga_feature_dev.c +SRCS-y += ifpga_fme.c +SRCS-y += ifpga_fme_iperf.c +SRCS-y += ifpga_fme_dperf.c +SRCS-y += ifpga_fme_error.c +SRCS-y += ifpga_port.c +SRCS-y += ifpga_port_error.c +SRCS-y += opae_hw_api.c +SRCS-y += opae_ifpga_hw_api.c +SRCS-y += opae_debug.c +SRCS-y += ifpga_fme_pr.c + +ifeq ($(CONFIG_RTE_TOOLCHAIN_CLANG),y) + CFLAGS_ifpga_fme_pr.o += -march=knl +endif + +SRCS-y += $(wildcard $(SRCDIR)/base/$(OSDEP)/*.c) diff --git a/drivers/raw/ifpga_rawdev/base/README b/drivers/raw/ifpga_rawdev/base/README new file mode 100644 index 0000000..5bc2ed0 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/README @@ -0,0 +1,31 @@ +.. + +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +Intel iFPGA driver +================== + +This directory contains source code of Intel FPGA driver released by +the team which develops Intel FPGA Open Programmable Acceleration Engine (OPAE). +The directory of base/ contains the original source package. The base code +currently supports Intel FPGA solutions including integrated solution (Intel(R) +Xeon(R) CPU with FPGAs) and discrete solution (Intel(R) Programmable Acceleration +Card with Intel(R) Arria(R) 10 FPGA) and it could be extended to support more FPGA +devices in the future. + +Please refer to [1][2] for more introduction on OPAE and Intel FPGAs. + +[1] https://01.org/OPAE +[2] https://www.altera.com/solutions/acceleration-hub/overview.html + + +Updating the driver +=================== + +NOTE: The source code in this directory should not be modified apart from +the following file(s): + + osdep_raw/osdep_generic.h + osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.c b/drivers/raw/ifpga_rawdev/base/ifpga_api.c new file mode 100644 index 0000000..540e171 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -0,0 +1,294 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_api.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +#include "opae_hw_api.h" + +/* Accelerator APIs */ +static int ifpga_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return fpga_get_afu_uuid(port, uuid); +} + +static int ifpga_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + struct fpga_uafu_irq_set irq_set; + + if (!br || !br->data) + return -EINVAL; + + if (start >= afu_info->num_irqs || start + count > afu_info->num_irqs) + return -EINVAL; + + port = br->data; + + irq_set.start = start; + irq_set.count = count; + irq_set.evtfds = evtfds; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_UINT, &irq_set); +} + +static int ifpga_acc_get_info(struct opae_accelerator *acc, + struct opae_acc_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -ENODEV; + + info->num_regions = afu_info->num_regions; + info->num_irqs = afu_info->num_irqs; + + return 0; +} + +static int ifpga_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -EINVAL; + + if (info->index >= afu_info->num_regions) + return -EINVAL; + + /* always one RW region only for AFU now */ + info->flags = ACC_REGION_READ | ACC_REGION_WRITE | ACC_REGION_MMIO; + info->len = afu_info->region[info->index].len; + info->addr = afu_info->region[info->index].addr; + + return 0; +} + +static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + switch (byte) { + case 8: + *(u64 *)data = opae_readq(region->addr + offset); + break; + case 4: + *(u32 *)data = opae_readl(region->addr + offset); + break; + case 2: + *(u16 *)data = opae_readw(region->addr + offset); + break; + case 1: + *(u8 *)data = opae_readb(region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ifpga_acc_write(struct opae_accelerator *acc, + unsigned int region_idx, u64 offset, + unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + /* normal mmio case */ + switch (byte) { + case 8: + opae_writeq(*(u64 *)data, region->addr + offset); + break; + case 4: + opae_writel(*(u32 *)data, region->addr + offset); + break; + case 2: + opae_writew(*(u16 *)data, region->addr + offset); + break; + case 1: + opae_writeb(*(u8 *)data, region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +struct opae_accelerator_ops ifpga_acc_ops = { + .read = ifpga_acc_read, + .write = ifpga_acc_write, + .set_irq = ifpga_acc_set_irq, + .get_info = ifpga_acc_get_info, + .get_region_info = ifpga_acc_get_region_info, + .get_uuid = ifpga_acc_get_uuid, +}; + +/* Bridge APIs */ + +static int ifpga_br_reset(struct opae_bridge *br) +{ + struct ifpga_port_hw *port = br->data; + + return fpga_port_reset(port); +} + +struct opae_bridge_ops ifpga_br_ops = { + .reset = ifpga_br_reset, +}; + +/* Manager APIs */ +static int ifpga_mgr_flash(struct opae_manager *mgr, int id, void *buf, + u32 size, u64 *status) +{ + struct ifpga_fme_hw *fme = mgr->data; + struct ifpga_hw *hw = fme->parent; + + return ifpga_pr(hw, id, buf, size, status); +} + +struct opae_manager_ops ifpga_mgr_ops = { + .flash = ifpga_mgr_flash, +}; + +/* Adapter APIs */ +static int ifpga_adapter_enumerate(struct opae_adapter *adapter) +{ + struct ifpga_hw *hw = malloc(sizeof(*hw)); + + if (hw) { + memset(hw, 0, sizeof(*hw)); + hw->pci_data = adapter->data; + hw->adapter = adapter; + if (ifpga_bus_enumerate(hw)) + goto error; + return ifpga_bus_init(hw); + } + +error: + return -ENOMEM; +} + +struct opae_adapter_ops ifpga_adapter_ops = { + .enumerate = ifpga_adapter_enumerate, +}; + +/** + * ifpga_pr - do the partial reconfiguration for a given port device + * @hw: pointer to the HW structure + * @port_id: the port device id + * @buffer: the buffer of the bitstream + * @size: the size of the bitstream + * @status: hardware status including PR error code if return -EIO. + * + * @return + * - 0: Success, partial reconfiguration finished. + * - <0: Error code returned in partial reconfiguration. + **/ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return do_pr(hw, port_id, buffer, size, status); +} + +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_get_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_get_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set) +{ + if (!hw || !irq_set) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_irq(&hw->fme, feature_id, irq_set); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_irq(&hw->port[port_id], feature_id, irq_set); + } + + return -ENOENT; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.h b/drivers/raw/ifpga_rawdev/base/ifpga_api.h new file mode 100644 index 0000000..dae7ca1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_API_H_ +#define _IFPGA_API_H_ + +#include "opae_hw_api.h" +#include "ifpga_hw.h" + +extern struct opae_adapter_ops ifpga_adapter_ops; +extern struct opae_manager_ops ifpga_mgr_ops; +extern struct opae_bridge_ops ifpga_br_ops; +extern struct opae_accelerator_ops ifpga_acc_ops; + +/* common APIs */ +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set); + +/* FME APIs */ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +#endif /* _IFPGA_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_compat.h b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h new file mode 100644 index 0000000..78b904e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMPAT_H_ +#define _IFPGA_COMPAT_H_ + +#include "opae_osdep.h" + +#undef container_of +#define container_of(ptr, type, member) ({ \ + typeof(((type *)0)->member)(*__mptr) = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) +#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE) + +#define readl(addr) opae_readl(addr) +#define readq(addr) opae_readq(addr) +#define writel(value, addr) opae_writel(value, addr) +#define writeq(value, addr) opae_writeq(value, addr) + +#define malloc(size) opae_malloc(size) +#define zmalloc(size) opae_zmalloc(size) +#define free(size) opae_free(size) + +/* + * Wait register's _field to be changed to the given value (_expect's _field) + * by polling with given interval and timeout. + */ +#define fpga_wait_register_field(_field, _expect, _reg_addr, _timeout, _invl)\ +({ \ + int wait = 0; \ + int ret = -ETIMEDOUT; \ + typeof(_expect) value; \ + for (; wait <= _timeout; wait += _invl) { \ + value.csr = readq(_reg_addr); \ + if (_expect._field == value._field) { \ + ret = 0; \ + break; \ + } \ + udelay(_invl); \ + } \ + ret; \ +}) + +#define __maybe_unused __attribute__((__unused__)) + +#define UNUSED(x) (void)(x) + +#endif /* _IFPGA_COMPAT_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h new file mode 100644 index 0000000..8989280 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -0,0 +1,1661 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_DEFINES_H_ +#define _IFPGA_DEFINES_H_ + +#include "ifpga_compat.h" + +#define MAX_FPGA_PORT_NUM 4 + +#define FME_FEATURE_HEADER "fme_hdr" +#define FME_FEATURE_THERMAL_MGMT "fme_thermal" +#define FME_FEATURE_POWER_MGMT "fme_power" +#define FME_FEATURE_GLOBAL_IPERF "fme_iperf" +#define FME_FEATURE_GLOBAL_ERR "fme_error" +#define FME_FEATURE_PR_MGMT "fme_pr" +#define FME_FEATURE_HSSI_ETH "fme_hssi" +#define FME_FEATURE_GLOBAL_DPERF "fme_dperf" +#define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" + +#define PORT_FEATURE_HEADER "port_hdr" +#define PORT_FEATURE_UAFU "port_uafu" +#define PORT_FEATURE_ERR "port_err" +#define PORT_FEATURE_UMSG "port_umsg" +#define PORT_FEATURE_PR "port_pr" +#define PORT_FEATURE_UINT "port_uint" +#define PORT_FEATURE_STP "port_stp" + +/* + * do not check the revision id as id may be dynamic under + * some cases, e.g, UAFU. + */ +#define SKIP_REVISION_CHECK 0xff + +#define FME_HEADER_REVISION 1 +#define FME_THERMAL_MGMT_REVISION 0 +#define FME_POWER_MGMT_REVISION 1 +#define FME_GLOBAL_IPERF_REVISION 1 +#define FME_GLOBAL_ERR_REVISION 1 +#define FME_PR_MGMT_REVISION 2 +#define FME_HSSI_ETH_REVISION 0 +#define FME_GLOBAL_DPERF_REVISION 0 +#define FME_QSPI_REVISION 0 + +#define PORT_HEADER_REVISION 0 +/* UAFU's header info depends on the downloaded GBS */ +#define PORT_UAFU_REVISION SKIP_REVISION_CHECK +#define PORT_ERR_REVISION 1 +#define PORT_UMSG_REVISION 0 +#define PORT_UINT_REVISION 0 +#define PORT_STP_REVISION 1 + +#define FEATURE_TYPE_AFU 0x1 +#define FEATURE_TYPE_BBB 0x2 +#define FEATURE_TYPE_PRIVATE 0x3 +#define FEATURE_TYPE_FIU 0x4 + +#define FEATURE_FIU_ID_FME 0x0 +#define FEATURE_FIU_ID_PORT 0x1 + +#define FEATURE_ID_HEADER 0x0 +#define FEATURE_ID_AFU 0xff + +enum fpga_id_type { + FME_ID, + PORT_ID, + 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, +}; + +/* + * All headers and structures must be byte-packed to match the spec. + */ +#pragma pack(1) + +struct feature_header { + union { + u64 csr; + struct { + u16 id:12; + u8 revision:4; + u32 next_header_offset:24; + u8 end_of_list:1; + u32 reserved:19; + u8 type:4; + }; + }; +}; + +struct feature_bbb_header { + struct uuid guid; +}; + +struct feature_afu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fiu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fme_capability { + union { + u64 csr; + struct { + u8 fabric_verid; /* Fabric version ID */ + u8 socket_id:1; /* Socket id */ + u8 rsvd1:3; /* Reserved */ + /* pci0 link available yes /no */ + u8 pci0_link_avile:1; + /* pci1 link available yes /no */ + u8 pci1_link_avile:1; + /* Coherent (QPI/UPI) link available yes /no */ + u8 qpi_link_avile:1; + u8 rsvd2:1; /* Reserved */ + /* IOMMU or VT-d supported yes/no */ + u8 iommu_support:1; + u8 num_ports:3; /* Number of ports */ + u8 sf_fab_ctl:1; /* Internal validation bit */ + u8 rsvd3:3; /* Reserved */ + /* + * Address width supported in bits + * BXT -0x26 , SKX -0x30 + */ + u8 address_width_bits:6; + u8 rsvd4:2; /* Reserved */ + /* Size of cache supported in kb */ + u16 cache_size:12; + u8 cache_assoc:4; /* Cache Associativity */ + u16 rsvd5:15; /* Reserved */ + u8 lock_bit:1; /* Lock bit */ + }; + }; +}; + +#define FME_AFU_ACCESS_PF 0 +#define FME_AFU_ACCESS_VF 1 + +struct feature_fme_port { + union { + u64 csr; + struct { + u32 port_offset:24; + u8 reserved1; + u8 port_bar:3; + u32 reserved2:20; + u8 afu_access_control:1; + u8 reserved3:4; + u8 port_implemented:1; + u8 reserved4:3; + }; + }; +}; + +struct feature_fme_fab_status { + union { + u64 csr; + struct { + u8 upilink_status:4; /* UPI Link Status */ + u8 rsvd1:4; /* Reserved */ + u8 pci0link_status:1; /* pci0 link status */ + u8 rsvd2:3; /* Reserved */ + u8 pci1link_status:1; /* pci1 link status */ + u64 rsvd3:51; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_base { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Base Address of memory range */ + u8 protected_base_addrss:4; + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_limit { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Limit Address of memory range */ + u8 protected_limit_addrss:4; + u16 rsvd2:11; /* Reserved */ + u8 enable:1; /* Enable GENPROTRANGE check */ + u32 rsvd3; /* Reserved */ + }; + }; +}; + +struct feature_fme_dxe_lock { + union { + u64 csr; + struct { + /* + * Determines write access to the DXE region CSRs + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_early_lock:1; + /* + * Determines write access to the HSSI CSR + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_late_lock:1; + u64 rsvd:62; + }; + }; +}; + +#define HSSI_ID_NO_HASSI 0 +#define HSSI_ID_PCIE_RP 1 +#define HSSI_ID_ETHERNET 2 + +struct feature_fme_bitstream_id { + union { + u64 csr; + struct { + u32 gitrepo_hash:32; /* GIT repository hash */ + /* + * HSSI configuration identifier: + * 0 - No HSSI + * 1 - PCIe-RP + * 2 - Ethernet + */ + u8 hssi_id:4; + u16 rsvd1:12; /* Reserved */ + /* Bitstream version patch number */ + u8 bs_verpatch:4; + /* Bitstream version minor number */ + u8 bs_verminor:4; + /* Bitstream version major number */ + u8 bs_vermajor:4; + /* Bitstream version debug number */ + u8 bs_verdebug:4; + }; + }; +}; + +struct feature_fme_bitstream_md { + union { + u64 csr; + struct { + /* Seed number userd for synthesis flow */ + u8 synth_seed:4; + /* Synthesis date(day number - 2 digits) */ + u8 synth_day:8; + /* Synthesis date(month number - 2 digits) */ + u8 synth_month:8; + /* Synthesis date(year number - 2 digits) */ + u8 synth_year:8; + u64 rsvd:36; /* Reserved */ + }; + }; +}; + +struct feature_fme_iommu_ctrl { + union { + u64 csr; + struct { + /* Disables IOMMU prefetcher for C0 channel */ + u8 prefetch_disableC0:1; + /* Disables IOMMU prefetcher for C1 channel */ + u8 prefetch_disableC1:1; + /* Disables IOMMU partial cache line writes */ + u8 prefetch_wrdisable:1; + u8 rsvd1:1; /* Reserved */ + /* + * Select counter and read value from register + * iommu_stat.dbg_counters + * 0 - Number of 4K page translation response + * 1 - Number of 2M page translation response + * 2 - Number of 1G page translation response + */ + u8 counter_sel:2; + u32 rsvd2:26; /* Reserved */ + /* Connected to IOMMU SIP Capabilities */ + u32 capecap_defeature; + }; + }; +}; + +struct feature_fme_iommu_stat { + union { + u64 csr; + struct { + /* Translation Enable bit from IOMMU SIP */ + u8 translation_enable:1; + /* Drain request in progress */ + u8 drain_req_inprog:1; + /* Invalidation current state */ + u8 inv_state:3; + /* C0 Response Buffer current state */ + u8 respbuffer_stateC0:3; + /* C1 Response Buffer current state */ + u8 respbuffer_stateC1:3; + /* Last request ID to IOMMU SIP */ + u8 last_reqID:4; + /* Last IOMMU SIP response ID value */ + u8 last_respID:4; + /* Last IOMMU SIP response status value */ + u8 last_respstatus:3; + /* C0 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC0:1; + /* C1 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC1:1; + /* C0 Request FIFO is not empty */ + u8 reqFIFO_notemptyC0:1; + /* C1 Request FIFO is not empty */ + u8 reqFIFO_notemptyC1:1; + /* C0 Response FIFO is not empty */ + u8 respFIFO_notemptyC0:1; + /* C1 Response FIFO is not empty */ + u8 respFIFO_notemptyC1:1; + /* C0 Response FIFO overflow detected */ + u8 respFIFO_overflowC0:1; + /* C1 Response FIFO overflow detected */ + u8 respFIFO_overflowC1:1; + /* C0 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC0:1; + /* C1 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC1:1; + /* Request FIFO overflow detected */ + u8 reqFIFO_overflow:1; + /* IOMMU memory read in progress */ + u8 memrd_inprog:1; + /* IOMMU memory write in progress */ + u8 memwr_inprog:1; + u8 rsvd1:1; /* Reserved */ + /* Value of counter selected by iommu_ctl.counter_sel */ + u16 dbg_counters:16; + u16 rsvd2:12; /* Reserved */ + }; + }; +}; + +struct feature_fme_pcie0_ctrl { + union { + u64 csr; + struct { + u64 vtd_bar_lock:1; /* Lock VT-D BAR register */ + u64 rsvd1:3; + u64 rciep:1; /* Configure PCIE0 as RCiEP */ + u64 rsvd2:59; + }; + }; +}; + +struct feature_fme_llpr_smrr_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR rule is valid or not */ + /* + * SMRR memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR2 rule is valid or not */ + /* + * SMRR2 memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_meseg_base { + union { + u64 csr; + struct { + /* A[45:19] of base address memory range */ + u64 me_base:27; + u64 rsvd:37; + }; + }; +}; + +struct feature_fme_llpr_meseg_limit { + union { + u64 csr; + struct { + /* A[45:19] of limit address memory range */ + u64 me_limit:27; + u64 rsvd1:4; + u64 enable:1; /* Enable LLPR MESEG rule */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 reserved; + u64 scratchpad; + struct feature_fme_capability capability; + struct feature_fme_port port[MAX_FPGA_PORT_NUM]; + struct feature_fme_fab_status fab_status; + struct feature_fme_bitstream_id bitstream_id; + struct feature_fme_bitstream_md bitstream_md; + struct feature_fme_genprotrange2_base genprotrange2_base; + struct feature_fme_genprotrange2_limit genprotrange2_limit; + struct feature_fme_dxe_lock dxe_lock; + struct feature_fme_iommu_ctrl iommu_ctrl; + struct feature_fme_iommu_stat iommu_stat; + struct feature_fme_pcie0_ctrl pcie0_control; + struct feature_fme_llpr_smrr_base smrr_base; + struct feature_fme_llpr_smrr_mask smrr_mask; + struct feature_fme_llpr_smrr2_base smrr2_base; + struct feature_fme_llpr_smrr2_mask smrr2_mask; + struct feature_fme_llpr_meseg_base meseg_base; + struct feature_fme_llpr_meseg_limit meseg_limit; +}; + +struct feature_port_capability { + union { + u64 csr; + struct { + u8 port_number:2; /* Port Number 0-3 */ + u8 rsvd1:6; /* Reserved */ + u16 mmio_size; /* User MMIO size in KB */ + u8 rsvd2; /* Reserved */ + u8 sp_intr_num:4; /* Supported interrupts num */ + u32 rsvd3:28; /* Reserved */ + }; + }; +}; + +struct feature_port_control { + union { + u64 csr; + struct { + u8 port_sftrst:1; /* Port Soft Reset */ + u8 rsvd1:1; /* Reserved */ + u8 latency_tolerance:1;/* '1' >= 40us, '0' < 40us */ + u8 rsvd2:1; /* Reserved */ + u8 port_sftrst_ack:1; /* HW ACK for Soft Reset */ + u64 rsvd3:59; /* Reserved */ + }; + }; +}; + +#define PORT_POWER_STATE_NORMAL 0 +#define PORT_POWER_STATE_AP1 1 +#define PORT_POWER_STATE_AP2 2 +#define PORT_POWER_STATE_AP6 6 + +struct feature_port_status { + union { + u64 csr; + struct { + u8 port_freeze:1; /* '1' - freezed '0' - normal */ + u8 rsvd1:7; /* Reserved */ + u8 power_state:4; /* Power State */ + u8 ap1_event:1; /* AP1 event was detected */ + u8 ap2_event:1; /* AP2 event was detected */ + u64 rsvd2:50; /* Reserved */ + }; + }; +}; + +/* Port Header Register Set */ +struct feature_port_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 port_mailbox; + u64 scratchpad; + struct feature_port_capability capability; + struct feature_port_control control; + struct feature_port_status status; + u64 rsvd2; + u64 user_clk_freq_cmd0; + u64 user_clk_freq_cmd1; + u64 user_clk_freq_sts0; + u64 user_clk_freq_sts1; +}; + +struct feature_fme_tmp_threshold { + union { + u64 csr; + struct { + u8 tmp_thshold1:7; /* temperature Threshold 1 */ + /* temperature Threshold 1 enable/disable */ + u8 tmp_thshold1_enable:1; + u8 tmp_thshold2:7; /* temperature Threshold 2 */ + /* temperature Threshold 2 enable /disable */ + u8 tmp_thshold2_enable:1; + u8 pro_hot_setpoint:7; /* Proc Hot set point */ + u8 rsvd4:1; /* Reserved */ + u8 therm_trip_thshold:7; /* Thermeal Trip Threshold */ + u8 rsvd3:1; /* Reserved */ + u8 thshold1_status:1; /* Threshold 1 Status */ + u8 thshold2_status:1; /* Threshold 2 Status */ + u8 rsvd5:1; /* Reserved */ + /* Thermeal Trip Threshold status */ + u8 therm_trip_thshold_status:1; + u8 rsvd6:4; /* Reserved */ + /* Validation mode- Force Proc Hot */ + u8 valmodeforce:1; + /* Validation mode - Therm trip Hot */ + u8 valmodetherm:1; + u8 rsvd2:2; /* Reserved */ + u8 thshold_policy:1; /* threshold policy */ + u32 rsvd:19; /* Reserved */ + }; + }; +}; + +/* Temperature Sensor Read values format 1 */ +struct feature_fme_temp_rdsensor_fmt1 { + union { + u64 csr; + struct { + /* Reads out FPGA temperature in celsius */ + u8 fpga_temp:7; + u8 rsvd0:1; /* Reserved */ + /* Temperature reading sequence number */ + u16 tmp_reading_seq_num; + /* Temperature reading is valid */ + u8 tmp_reading_valid:1; + u8 rsvd1:7; /* Reserved */ + u16 dbg_mode:10; /* Debug mode */ + u32 rsvd2:22; /* Reserved */ + }; + }; +}; + +/* Temperature sensor read values format 2 */ +struct feature_fme_temp_rdsensor_fmt2 { + u64 rsvd; /* Reserved */ +}; + +/* Temperature Threshold Capability Register */ +struct feature_fme_tmp_threshold_cap { + union { + u64 csr; + struct { + /* Temperature Threshold Unsupported */ + u8 tmp_thshold_disabled:1; + u64 rsvd:63; /* Reserved */ + }; + }; +}; + +/* FME THERNAL FEATURE */ +struct feature_fme_thermal { + struct feature_header header; + struct feature_fme_tmp_threshold threshold; + struct feature_fme_temp_rdsensor_fmt1 rdsensor_fm1; + struct feature_fme_temp_rdsensor_fmt2 rdsensor_fm2; + struct feature_fme_tmp_threshold_cap threshold_cap; +}; + +/* Power Status register */ +struct feature_fme_pm_status { + union { + u64 csr; + struct { + /* FPGA Power consumed, The format is to be defined */ + u32 pwr_consumed:18; + /* FPGA Latency Tolerance Reporting */ + u8 fpga_latency_report:1; + u64 rsvd:45; /* Reserved */ + }; + }; +}; + +/* AP Thresholds */ +struct feature_fme_pm_ap_threshold { + union { + u64 csr; + struct { + /* + * Number of clocks (5ns period) for assertion + * of FME_data + */ + u8 threshold1:7; + u8 rsvd1:1; + u8 threshold2:7; + u8 rsvd2:1; + u8 threshold1_status:1; + u8 threshold2_status:1; + u64 rsvd3:46; /* Reserved */ + }; + }; +}; + +/* Xeon Power Limit */ +struct feature_fme_pm_xeon_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FPGA Power Limit */ +struct feature_fme_pm_fpga_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FME POWER FEATURE */ +struct feature_fme_power { + struct feature_header header; + struct feature_fme_pm_status status; + struct feature_fme_pm_ap_threshold threshold; + struct feature_fme_pm_xeon_limit xeon_limit; + struct feature_fme_pm_fpga_limit fpga_limit; +}; + +#define CACHE_CHANNEL_RD 0 +#define CACHE_CHANNEL_WR 1 + +enum iperf_cache_events { + IPERF_CACHE_RD_HIT, + IPERF_CACHE_WR_HIT, + IPERF_CACHE_RD_MISS, + IPERF_CACHE_WR_MISS, + IPERF_CACHE_RSVD, /* reserved */ + IPERF_CACHE_HOLD_REQ, + IPERF_CACHE_DATA_WR_PORT_CONTEN, + IPERF_CACHE_TAG_WR_PORT_CONTEN, + IPERF_CACHE_TX_REQ_STALL, + IPERF_CACHE_RX_REQ_STALL, + IPERF_CACHE_EVICTIONS, +}; + +/* FPMON Cache Control */ +struct feature_fme_ifpmon_ch_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd1:7; /* Reserved */ + u8 freeze:1; /* Freeze if set to 1 */ + u8 rsvd2:7; /* Reserved */ + u8 cache_event:4; /* Select the cache event */ + u8 cci_chsel:1; /* Select the channel */ + u64 rsvd3:43; /* Reserved */ + }; + }; +}; + +/* FPMON Cache Counter */ +struct feature_fme_ifpmon_ch_ctr { + union { + u64 csr; + struct { + /* Cache Counter for even addresse */ + u64 cache_counter:48; + u16 rsvd:12; /* Reserved */ + /* Cache Event being reported */ + u8 event_code:4; + }; + }; +}; + +enum iperf_fab_events { + IPERF_FAB_PCIE0_RD, + IPERF_FAB_PCIE0_WR, + IPERF_FAB_PCIE1_RD, + IPERF_FAB_PCIE1_WR, + IPERF_FAB_UPI_RD, + IPERF_FAB_UPI_WR, + IPERF_FAB_MMIO_RD, + IPERF_FAB_MMIO_WR, +}; + +#define FAB_DISABLE_FILTER 0 +#define FAB_ENABLE_FILTER 1 + +/* FPMON FAB Control */ +struct feature_fme_ifpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_ifpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_ifpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +enum iperf_vtd_events { + IPERF_VTD_AFU_MEM_RD_TRANS, + IPERF_VTD_AFU_MEM_WR_TRANS, + IPERF_VTD_AFU_DEVTLB_RD_HIT, + IPERF_VTD_AFU_DEVTLB_WR_HIT, + IPERF_VTD_DEVTLB_4K_FILL, + IPERF_VTD_DEVTLB_2M_FILL, + IPERF_VTD_DEVTLB_1G_FILL, +}; + +/* VT-d control register */ +struct feature_fme_ifpmon_vtd_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d event counter */ +struct feature_fme_ifpmon_vtd_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +enum iperf_vtd_sip_events { + IPERF_VTD_SIP_IOTLB_4K_HIT, + IPERF_VTD_SIP_IOTLB_2M_HIT, + IPERF_VTD_SIP_IOTLB_1G_HIT, + IPERF_VTD_SIP_SLPWC_L3_HIT, + IPERF_VTD_SIP_SLPWC_L4_HIT, + IPERF_VTD_SIP_RCC_HIT, + IPERF_VTD_SIP_IOTLB_4K_MISS, + IPERF_VTD_SIP_IOTLB_2M_MISS, + IPERF_VTD_SIP_IOTLB_1G_MISS, + IPERF_VTD_SIP_SLPWC_L3_MISS, + IPERF_VTD_SIP_SLPWC_L4_MISS, + IPERF_VTD_SIP_RCC_MISS, +}; + +/* VT-d SIP control register */ +struct feature_fme_ifpmon_vtd_sip_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d SIP event counter */ +struct feature_fme_ifpmon_vtd_sip_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +/* FME IPERF FEATURE */ +struct feature_fme_iperf { + struct feature_header header; + struct feature_fme_ifpmon_ch_ctl ch_ctl; + struct feature_fme_ifpmon_ch_ctr ch_ctr0; + struct feature_fme_ifpmon_ch_ctr ch_ctr1; + struct feature_fme_ifpmon_fab_ctl fab_ctl; + struct feature_fme_ifpmon_fab_ctr fab_ctr; + struct feature_fme_ifpmon_clk_ctr clk; + struct feature_fme_ifpmon_vtd_ctl vtd_ctl; + struct feature_fme_ifpmon_vtd_ctr vtd_ctr; + struct feature_fme_ifpmon_vtd_sip_ctl vtd_sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr vtd_sip_ctr; +}; + +enum dperf_fab_events { + DPERF_FAB_PCIE0_RD, + DPERF_FAB_PCIE0_WR, + DPERF_FAB_MMIO_RD = 6, + DPERF_FAB_MMIO_WR, +}; + +/* FPMON FAB Control */ +struct feature_fme_dfpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_dfpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_dfpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +/* FME DPERF FEATURE */ +struct feature_fme_dperf { + struct feature_header header; + u64 rsvd[3]; + struct feature_fme_dfpmon_fab_ctl fab_ctl; + struct feature_fme_dfpmon_fab_ctr fab_ctr; + struct feature_fme_dfpmon_clk_ctr clk; +}; + +struct feature_fme_error0 { +#define FME_ERROR0_MASK 0xFFUL +#define FME_ERROR0_MASK_DEFAULT 0x40UL /* pcode workaround */ + union { + u64 csr; + struct { + u8 fabric_err:1; /* Fabric error */ + u8 fabfifo_overflow:1; /* Fabric fifo overflow */ + u8 kticdc_parity_err:2;/* KTI CDC Parity Error */ + u8 iommu_parity_err:1; /* IOMMU Parity error */ + /* AFU PF/VF access mismatch detected */ + u8 afu_acc_mode_err:1; + u8 mbp_err:1; /* Indicates an MBP event */ + /* PCIE0 CDC Parity Error */ + u8 pcie0cdc_parity_err:5; + /* PCIE1 CDC Parity Error */ + u8 pcie1cdc_parity_err:5; + /* CVL CDC Parity Error */ + u8 cvlcdc_parity_err:3; + u64 rsvd:44; /* Reserved */ + }; + }; +}; + +/* PCIe0 Error Status register */ +struct feature_fme_pcie0_error { +#define FME_PCIE0_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:52; /* Reserved */ + u8 vfnumb_err:1; /* Number of error VF */ + u8 funct_type_err:1; /* Virtual (1) or Physical */ + }; + }; +}; + +/* PCIe1 Error Status register */ +struct feature_fme_pcie1_error { +#define FME_PCIE1_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:54; /* Reserved */ + }; + }; +}; + +/* FME First Error register */ +struct feature_fme_first_error { +#define FME_FIRST_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered first + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered first + */ + u8 errReg_id:4; + }; + }; +}; + +/* FME Next Error register */ +struct feature_fme_next_error { +#define FME_NEXT_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered second + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered second + */ + u8 errReg_id:4; + }; + }; +}; + +/* RAS Non Fatal Error Status register */ +struct feature_fme_ras_nonfaterror { + union { + u64 csr; + struct { + /* thremal threshold AP1 */ + u8 temp_thresh_ap1:1; + /* thremal threshold AP2 */ + u8 temp_thresh_ap2:1; + u8 pcie_error:1; /* pcie Error */ + u8 portfatal_error:1; /* port fatal error */ + u8 proc_hot:1; /* Indicates a ProcHot event */ + /* Indicates an AFU PF/VF access mismatch */ + u8 afu_acc_mode_err:1; + /* Injected nonfata Error */ + u8 injected_nonfata_err:1; + u8 rsvd1:2; + /* Temperature threshold triggered AP6*/ + u8 temp_thresh_AP6:1; + /* Power threshold triggered AP1 */ + u8 power_thresh_AP1:1; + /* Power threshold triggered AP2 */ + u8 power_thresh_AP2:1; + /* Indicates a MBP event */ + u8 mbp_err:1; + u64 rsvd2:51; /* Reserved */ + }; + }; +}; + +/* RAS Catastrophic Fatal Error Status register */ +struct feature_fme_ras_catfaterror { + union { + u64 csr; + struct { + /* KTI Link layer error detected */ + u8 ktilink_fatal_err:1; + /* tag-n-cache error detected */ + u8 tagcch_fatal_err:1; + /* CCI error detected */ + u8 cci_fatal_err:1; + /* KTI Protocol error detected */ + u8 ktiprpto_fatal_err:1; + /* Fatal DRAM error detected */ + u8 dram_fatal_err:1; + /* IOMMU detected */ + u8 iommu_fatal_err:1; + /* Fabric Fatal Error */ + u8 fabric_fatal_err:1; + /* PCIe possion Error */ + u8 pcie_poison_err:1; + /* Injected fatal Error */ + u8 inject_fata_err:1; + /* Catastrophic CRC Error */ + u8 crc_catast_err:1; + /* Catastrophic Thermal Error */ + u8 therm_catast_err:1; + /* Injected Catastrophic Error */ + u8 injected_catast_err:1; + u64 rsvd:52; + }; + }; +}; + +/* RAS Error injection register */ +struct feature_fme_ras_error_inj { +#define FME_RAS_ERROR_INJ_MASK 0x7UL + union { + u64 csr; + struct { + u8 catast_error:1; /* Catastrophic error flag */ + u8 fatal_error:1; /* Fatal error flag */ + u8 nonfatal_error:1; /* NonFatal error flag */ + u64 rsvd:61; /* Reserved */ + }; + }; +}; + +/* FME error capabilities */ +struct feature_fme_error_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* FME ERR FEATURE */ +struct feature_fme_err { + struct feature_header header; + struct feature_fme_error0 fme_err_mask; + struct feature_fme_error0 fme_err; + struct feature_fme_pcie0_error pcie0_err_mask; + struct feature_fme_pcie0_error pcie0_err; + struct feature_fme_pcie1_error pcie1_err_mask; + struct feature_fme_pcie1_error pcie1_err; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + struct feature_fme_ras_nonfaterror ras_nonfat_mask; + struct feature_fme_ras_nonfaterror ras_nonfaterr; + struct feature_fme_ras_catfaterror ras_catfat_mask; + struct feature_fme_ras_catfaterror ras_catfaterr; + struct feature_fme_ras_error_inj ras_error_inj; + struct feature_fme_error_capability fme_err_capability; +}; + +/* FME Partial Reconfiguration Control */ +struct feature_fme_pr_ctl { + union { + u64 csr; + struct { + u8 pr_reset:1; /* Reset PR Engine */ + u8 rsvd3:3; /* Reserved */ + u8 pr_reset_ack:1; /* Reset PR Engine Ack */ + u8 rsvd4:3; /* Reserved */ + u8 pr_regionid:2; /* PR Region ID */ + u8 rsvd1:2; /* Reserved */ + u8 pr_start_req:1; /* PR Start Request */ + u8 pr_push_complete:1; /* PR Data push complete */ + u8 pr_kind:1; /* PR Data push complete */ + u32 rsvd:17; /* Reserved */ + u32 config_data; /* Config data TBD */ + }; + }; +}; + +/* FME Partial Reconfiguration Status */ +struct feature_fme_pr_status { + union { + u64 csr; + struct { + u16 pr_credit:9; /* PR Credits */ + u8 rsvd2:7; /* Reserved */ + u8 pr_status:1; /* PR status */ + u8 rsvd:3; /* Reserved */ + /* Altra PR Controller Block status */ + u8 pr_controller_status:3; + u8 rsvd1:1; /* Reserved */ + u8 pr_host_status:4; /* PR Host status */ + u8 rsvd3:4; /* Reserved */ + /* Security Block Status fields (TBD) */ + u32 security_bstatus; + }; + }; +}; + +/* FME Partial Reconfiguration Data */ +struct feature_fme_pr_data { + union { + u64 csr; /* PR data from the raw-binary file */ + struct { + /* PR data from the raw-binary file */ + u32 pr_data_raw; + u32 rsvd; + }; + }; +}; + +/* FME PR Public Key */ +struct feature_fme_pr_key { + u64 key; /* FME PR Public Hash */ +}; + +/* FME PR FEATURE */ +struct feature_fme_pr { + struct feature_header header; + /*Partial Reconfiguration control */ + struct feature_fme_pr_ctl ccip_fme_pr_control; + + /* Partial Reconfiguration Status */ + struct feature_fme_pr_status ccip_fme_pr_status; + + /* Partial Reconfiguration data */ + struct feature_fme_pr_data ccip_fme_pr_data; + + /* Partial Reconfiguration data */ + u64 ccip_fme_pr_err; + + u64 rsvd1[3]; + + /* Partial Reconfiguration data registers */ + u64 fme_pr_data1; + u64 fme_pr_data2; + u64 fme_pr_data3; + u64 fme_pr_data4; + u64 fme_pr_data5; + u64 fme_pr_data6; + u64 fme_pr_data7; + u64 fme_pr_data8; + + u64 rsvd2[5]; + + /* PR Interface ID */ + u64 fme_pr_intfc_id_l; + u64 fme_pr_intfc_id_h; + + /* MSIX filed to be Added */ +}; + +/* FME HSSI Control */ +struct feature_fme_hssi_eth_ctrl { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u16 address:16; /* HSSI address */ + /* + * HSSI comamnd + * 0x0 - No request + * 0x08 - SW register RD request + * 0x10 - SW register WR request + * 0x40 - Auxiliar bus RD request + * 0x80 - Auxiliar bus WR request + */ + u16 cmd:16; + }; + }; +}; + +/* FME HSSI Status */ +struct feature_fme_hssi_eth_stat { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u8 acknowledge:1; /* HSSI acknowledge */ + u8 spare:1; /* HSSI spare */ + u32 rsvd:30; /* Reserved */ + }; + }; +}; + +/* FME HSSI FEATURE */ +struct feature_fme_hssi { + struct feature_header header; + struct feature_fme_hssi_eth_ctrl hssi_control; + struct feature_fme_hssi_eth_stat hssi_status; +}; + +#define PORT_ERR_MASK 0xfff0703ff001f +struct feature_port_err_key { + union { + u64 csr; + struct { + /* Tx Channel0: Overflow */ + u8 tx_ch0_overflow:1; + /* Tx Channel0: Invalid request encoding */ + u8 tx_ch0_invaldreq :1; + /* Tx Channel0: Request with cl_len=3 not supported */ + u8 tx_ch0_cl_len3:1; + /* Tx Channel0: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch0_cl_len2:1; + /* Tx Channel0: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch0_cl_len4:1; + + u16 rsvd1:4; /* Reserved */ + + /* AFU MMIO RD received while PORT is in reset */ + u8 mmio_rd_whilerst:1; + /* AFU MMIO WR received while PORT is in reset */ + u8 mmio_wr_whilerst:1; + + u16 rsvd2:5; /* Reserved */ + + /* Tx Channel1: Overflow */ + u8 tx_ch1_overflow:1; + /* Tx Channel1: Invalid request encoding */ + u8 tx_ch1_invaldreq:1; + /* Tx Channel1: Request with cl_len=3 not supported */ + u8 tx_ch1_cl_len3:1; + /* Tx Channel1: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch1_cl_len2:1; + /* Tx Channel1: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch1_cl_len4:1; + + /* Tx Channel1: Insufficient data payload */ + u8 tx_ch1_insuff_data:1; + /* Tx Channel1: Data payload overrun */ + u8 tx_ch1_data_overrun:1; + /* Tx Channel1 : Incorrect address */ + u8 tx_ch1_incorr_addr:1; + /* Tx Channel1 : NON-Zero SOP Detected */ + u8 tx_ch1_nzsop:1; + /* Tx Channel1 : Illegal VC_SEL, atomic request VLO */ + u8 tx_ch1_illegal_vcsel:1; + + u8 rsvd3:6; /* Reserved */ + + /* MMIO Read Timeout in AFU */ + u8 mmioread_timeout:1; + + /* Tx Channel2: FIFO Overflow */ + u8 tx_ch2_fifo_overflow:1; + + /* MMIO read is not matching pending request */ + u8 unexp_mmio_resp:1; + + u8 rsvd4:5; /* Reserved */ + + /* Number of pending Requests: counter overflow */ + u8 tx_req_counter_overflow:1; + /* Req with Address violating SMM Range */ + u8 llpr_smrr_err:1; + /* Req with Address violating second SMM Range */ + u8 llpr_smrr2_err:1; + /* Req with Address violating ME Stolen message */ + u8 llpr_mesg_err:1; + /* Req with Address violating Generic Protected Range */ + u8 genprot_range_err:1; + /* Req with Address violating Legacy Range low */ + u8 legrange_low_err:1; + /* Req with Address violating Legacy Range High */ + u8 legrange_high_err:1; + /* Req with Address violating VGA memory range */ + u8 vgmem_range_err:1; + u8 page_fault_err:1; /* Page fault */ + u8 pmr_err:1; /* PMR Error */ + u8 ap6_event:1; /* AP6 event */ + /* VF FLR detected on Port with PF access control */ + u8 vfflr_access_err:1; + u16 rsvd5:12; /* Reserved */ + }; + }; +}; + +/* Port first error register, not contain all error bits in error register. */ +struct feature_port_first_err_key { + union { + u64 csr; + struct { + u8 tx_ch0_overflow:1; + u8 tx_ch0_invaldreq :1; + u8 tx_ch0_cl_len3:1; + u8 tx_ch0_cl_len2:1; + u8 tx_ch0_cl_len4:1; + u8 rsvd1:4; /* Reserved */ + u8 mmio_rd_whilerst:1; + u8 mmio_wr_whilerst:1; + u8 rsvd2:5; /* Reserved */ + u8 tx_ch1_overflow:1; + u8 tx_ch1_invaldreq:1; + u8 tx_ch1_cl_len3:1; + u8 tx_ch1_cl_len2:1; + u8 tx_ch1_cl_len4:1; + u8 tx_ch1_insuff_data:1; + u8 tx_ch1_data_overrun:1; + u8 tx_ch1_incorr_addr:1; + u8 tx_ch1_nzsop:1; + u8 tx_ch1_illegal_vcsel:1; + u8 rsvd3:6; /* Reserved */ + u8 mmioread_timeout:1; + u8 tx_ch2_fifo_overflow:1; + u8 rsvd4:6; /* Reserved */ + u8 tx_req_counter_overflow:1; + u32 rsvd5:23; /* Reserved */ + }; + }; +}; + +/* Port malformed Req0 */ +struct feature_port_malformed_req0 { + u64 header_lsb; +}; + +/* Port malformed Req1 */ +struct feature_port_malformed_req1 { + u64 header_msb; +}; + +/* Port debug register */ +struct feature_port_debug { + u64 port_debug; +}; + +/* Port error capabilities */ +struct feature_port_err_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE ERROR */ +struct feature_port_error { + struct feature_header header; + struct feature_port_err_key error_mask; + struct feature_port_err_key port_error; + struct feature_port_first_err_key port_first_error; + struct feature_port_malformed_req0 malreq0; + struct feature_port_malformed_req1 malreq1; + struct feature_port_debug port_debug; + struct feature_port_err_capability error_capability; +}; + +/* Port UMSG Capability */ +struct feature_port_umsg_cap { + union { + u64 csr; + struct { + /* Number of umsg allocated to this port */ + u8 umsg_allocated; + /* Enable / Disable UMsg engine for this port */ + u8 umsg_enable:1; + /* Usmg initialization status */ + u8 umsg_init_complete:1; + /* IOMMU can not translate the umsg base address */ + u8 umsg_trans_error:1; + u64 rsvd:53; /* Reserved */ + }; + }; +}; + +/* Port UMSG base address */ +struct feature_port_umsg_baseaddr { + union { + u64 csr; + struct { + u64 base_addr:48; /* 48 bit physical address */ + u16 rsvd; /* Reserved */ + }; + }; +}; + +struct feature_port_umsg_mode { + union { + u64 csr; + struct { + u32 umsg_hint_enable; /* UMSG hint enable/disable */ + u32 rsvd; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE UMSG */ +struct feature_port_umsg { + struct feature_header header; + struct feature_port_umsg_cap capability; + struct feature_port_umsg_baseaddr baseaddr; + struct feature_port_umsg_mode mode; +}; + +#define UMSG_EN_POLL_INVL 10 /* us */ +#define UMSG_EN_POLL_TIMEOUT 1000 /* us */ + +/* Port UINT Capability */ +struct feature_port_uint_cap { + union { + u64 csr; + struct { + u16 intr_num:12; /* Supported interrupts num */ + /* First MSI-X vector table entry number */ + u16 first_vec_num:12; + u64 rsvd:40; + }; + }; +}; + +/* PORT FEATURE UINT */ +struct feature_port_uint { + struct feature_header header; + struct feature_port_uint_cap capability; +}; + +/* STP region supports mmap operation, so use page aligned size. */ +#define PORT_FEATURE_STP_REGION_SIZE PAGE_ALIGN(sizeof(struct feature_port_stp)) + +/* Port STP status register (for debug only)*/ +struct feature_port_stp_status { + union { + u64 csr; + struct { + /* SLD Hub end-point read/write timeout */ + u8 sld_ep_timeout:1; + /* Remote STP in reset/disable */ + u8 rstp_disabled:1; + u8 unsupported_read:1; + /* MMIO timeout detected and faked with a response */ + u8 mmio_timeout:1; + u8 txfifo_count:4; + u8 rxfifo_count:4; + u8 txfifo_overflow:1; + u8 txfifo_underflow:1; + u8 rxfifo_overflow:1; + u8 rxfifo_underflow:1; + /* Number of MMIO write requests */ + u16 write_requests; + /* Number of MMIO read requests */ + u16 read_requests; + /* Number of MMIO read responses */ + u16 read_responses; + }; + }; +}; + +/* + * PORT FEATURE STP + * Most registers in STP region are not touched by driver, but mmapped to user + * space. So they are not defined in below data structure, as its actual size + * is 0x18c per spec. + */ +struct feature_port_stp { + struct feature_header header; + struct feature_port_stp_status stp_status; +}; + +/** + * enum fpga_pr_states - fpga PR states + * @FPGA_PR_STATE_UNKNOWN: can't determine state + * @FPGA_PR_STATE_WRITE_INIT: preparing FPGA for programming + * @FPGA_PR_STATE_WRITE_INIT_ERR: Error during WRITE_INIT stage + * @FPGA_PR_STATE_WRITE: writing image to FPGA + * @FPGA_PR_STATE_WRITE_ERR: Error while writing FPGA + * @FPGA_PR_STATE_WRITE_COMPLETE: Doing post programming steps + * @FPGA_PR_STATE_WRITE_COMPLETE_ERR: Error during WRITE_COMPLETE + * @FPGA_PR_STATE_OPERATING: FPGA PR done + */ +enum fpga_pr_states { + /* canot determine state states */ + FPGA_PR_STATE_UNKNOWN, + + /* write sequence: init, write, complete */ + FPGA_PR_STATE_WRITE_INIT, + FPGA_PR_STATE_WRITE_INIT_ERR, + FPGA_PR_STATE_WRITE, + FPGA_PR_STATE_WRITE_ERR, + FPGA_PR_STATE_WRITE_COMPLETE, + FPGA_PR_STATE_WRITE_COMPLETE_ERR, + + /* FPGA PR done */ + FPGA_PR_STATE_DONE, +}; + +/* + * FPGA Manager flags + * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported + */ +#define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + +/** + * struct fpga_pr_info - specific information to a FPGA PR + * @flags: boolean flags as defined above + * @pr_err: PR error code + * @state: fpga manager state + * @port_id: port id + */ +struct fpga_pr_info { + u32 flags; + u64 pr_err; + enum fpga_pr_states state; + int port_id; +}; + +#define DEFINE_FPGA_PR_ERR_MSG(_name_) \ +static const char * const _name_[] = { \ + "PR operation error detected", \ + "PR CRC error detected", \ + "PR incompatiable bitstream error detected", \ + "PR IP protocol error detected", \ + "PR FIFO overflow error detected", \ + "PR timeout error detected", \ + "PR secure load error detected", \ +} + +#define RST_POLL_INVL 10 /* us */ +#define RST_POLL_TIMEOUT 1000 /* us */ + +#define PR_WAIT_TIMEOUT 15000000 + +#define PR_HOST_STATUS_IDLE 0 +#define PR_MAX_ERR_NUM 7 + +DEFINE_FPGA_PR_ERR_MSG(pr_err_msg); + +/* + * green bitstream header must be byte-packed to match the + * real file format. + */ +struct bts_header { + u64 guid_h; + u64 guid_l; + u32 metadata_len; +}; + +#define GBS_GUID_H 0x414750466e6f6558 +#define GBS_GUID_L 0x31303076534247b7 +#define is_valid_bts(bts_hdr) \ + (((bts_hdr)->guid_h == GBS_GUID_H) && \ + ((bts_hdr)->guid_l == GBS_GUID_L)) + +#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 new file mode 100644 index 0000000..10a8f06 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -0,0 +1,824 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_hw_api.h" +#include "ifpga_api.h" + +#include "ifpga_hw.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +struct build_feature_devs_info { + struct opae_adapter_data_pci *pci_data; + + struct ifpga_afu_info *acc_info; + + void *fiu; + enum fpga_id_type current_type; + int current_port_id; + + void *ioaddr; + void *ioend; + uint64_t phys_addr; + int current_bar; + + void *pfme_hdr; + + struct ifpga_hw *hw; +}; + +struct feature_info { + const char *name; + uint32_t resource_size; + int feature_index; + int revision_id; + unsigned int vec_start; + unsigned int vec_cnt; + + struct feature_ops *ops; +}; + +/* 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, + } +}; + +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 = &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 = &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 = &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 = &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 + }, +}; + +static u64 feature_id(void __iomem *start) +{ + struct feature_header header; + + header.csr = readq(start); + + switch (header.type) { + case FEATURE_TYPE_FIU: + return FEATURE_ID_HEADER; + case FEATURE_TYPE_PRIVATE: + return header.id; + case FEATURE_TYPE_AFU: + return FEATURE_ID_AFU; + } + + WARN_ON(1); + return 0; +} + +static int +build_info_add_sub_feature(struct build_feature_devs_info *binfo, + struct feature_info *finfo, void __iomem *start) +{ + 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; + } + + 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->phys_addr = binfo->phys_addr + + ((u8 *)start - (u8 *)binfo->ioaddr); + + if (vec_cnt) { + if (vec_start + vec_cnt <= vec_start) + return -EINVAL; + + ctx = zmalloc(sizeof(*ctx) * vec_cnt); + if (!ctx) + return -ENOMEM; + + for (i = 0; i < vec_cnt; i++) { + ctx[i].eventfd = -1; + ctx[i].idx = vec_start + i; + } + } + + feature->ctx = ctx; + feature->ctx_num = vec_cnt; + feature->vfio_dev_fd = binfo->pci_data->vfio_dev_fd; + + return ret; +} + +static int +create_feature_instance(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + struct feature_header *hdr = start; + + if (((u8 *)binfo->ioend - (u8 *)start) < finfo->resource_size) + return -EINVAL; + + 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); +} + +/* + * UAFU GUID is dynamic as it can be changed after FME downloads different + * Green Bitstream to the port, so we treat the unknown GUIDs which are + * attached on port's feature list as UAFU. + */ +static bool feature_is_UAFU(struct build_feature_devs_info *binfo) +{ + if (binfo->current_type != PORT_ID) + return false; + + return true; +} + +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; + struct ifpga_afu_info *info; + void *start = (void *)hdr; + int ret; + + 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; + } + + if (ret) + return ret; + + /* FIXME: need to figure out a better name */ + info = 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->num_regions = 1; + + binfo->acc_info = info; + + return ret; +} + +static int parse_feature_afus(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + int ret; + struct feature_afu_header *afu_hdr, header; + u8 __iomem *start; + u8 __iomem *end = binfo->ioend; + + start = (u8 __iomem *)hdr; + for (; start < end; start += header.next_afu) { + if (end - start < + (unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr))) + return -EINVAL; + + hdr = (struct feature_header *)start; + afu_hdr = (struct feature_afu_header *)(hdr + 1); + header.csr = readq(&afu_hdr->csr); + + if (feature_is_UAFU(binfo)) { + ret = parse_feature_port_uafu(binfo, hdr); + if (ret) + return ret; + } + + if (!header.next_afu) + break; + } + + return 0; +} + +/* create and register proper private data */ +static int build_info_commit_dev(struct build_feature_devs_info *binfo) +{ + struct ifpga_afu_info *info = binfo->acc_info; + struct ifpga_hw *hw = binfo->hw; + struct opae_manager *mgr; + struct opae_bridge *br; + struct opae_accelerator *acc; + + if (!binfo->fiu) + return 0; + + if (binfo->current_type == PORT_ID) { + /* return error if no valid acc info data structure */ + if (!info) + return -EFAULT; + + br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops, + binfo->fiu); + if (!br) + return -ENOMEM; + + br->id = binfo->current_port_id; + + /* update irq info */ + info->num_irqs = port_features[PORT_FEATURE_ID_UINT].vec_cnt; + + acc = opae_accelerator_alloc(hw->adapter->name, + &ifpga_acc_ops, info); + if (!acc) { + opae_bridge_free(br); + return -ENOMEM; + } + + acc->br = br; + acc->index = br->id; + + opae_adapter_add_acc(hw->adapter, acc); + + } else if (binfo->current_type == FME_ID) { + mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops, + binfo->fiu); + if (!mgr) + return -ENOMEM; + + mgr->adapter = hw->adapter; + hw->adapter->mgr = mgr; + } + + binfo->fiu = NULL; + + return 0; +} + +static int +build_info_create_dev(struct build_feature_devs_info *binfo, + enum fpga_id_type type, unsigned int index) +{ + int ret; + + ret = build_info_commit_dev(binfo); + if (ret) + return ret; + + binfo->current_type = type; + + if (type == FME_ID) { + binfo->fiu = &binfo->hw->fme; + } else if (type == PORT_ID) { + binfo->fiu = &binfo->hw->port[index]; + binfo->current_port_id = index; + } + + return 0; +} + +static int parse_feature_fme(struct build_feature_devs_info *binfo, + struct feature_header *start) +{ + struct ifpga_hw *hw = binfo->hw; + struct ifpga_fme_hw *fme = &hw->fme; + int ret; + + ret = build_info_create_dev(binfo, FME_ID, 0); + if (ret) + return ret; + + /* Update FME states */ + fme->state = IFPGA_FME_IMPLEMENTED; + fme->parent = hw; + spinlock_init(&fme->lock); + + return create_feature_instance(binfo, start, + &fme_features[FME_FEATURE_ID_HEADER]); +} + +static int parse_feature_port(struct build_feature_devs_info *binfo, + void __iomem *start) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + struct ifpga_hw *hw = binfo->hw; + struct ifpga_port_hw *port; + unsigned int port_id; + int ret; + + /* Get current port's id */ + port_hdr = (struct feature_port_header *)start; + capability.csr = readq(&port_hdr->capability); + port_id = capability.port_number; + + ret = build_info_create_dev(binfo, PORT_ID, port_id); + if (ret) + return ret; + + /*found a Port device*/ + port = &hw->port[port_id]; + port->port_id = binfo->current_port_id; + port->parent = hw; + port->state = IFPGA_PORT_ATTACHED; + spinlock_init(&port->lock); + + return create_feature_instance(binfo, start, + &port_features[PORT_FEATURE_ID_HEADER]); +} + +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); +} + +static int parse_feature_fiu(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + struct feature_fiu_header *fiu_hdr, fiu_header; + u8 __iomem *start = (u8 __iomem *)hdr; + int ret; + + header.csr = readq(hdr); + + switch (header.id) { + case FEATURE_FIU_ID_FME: + ret = parse_feature_fme(binfo, hdr); + binfo->pfme_hdr = hdr; + if (ret) + return ret; + break; + case FEATURE_FIU_ID_PORT: + ret = parse_feature_port(binfo, hdr); + enable_port_uafu(binfo, hdr); + if (ret) + return ret; + + /* Check Port FIU's next_afu pointer to User AFU DFH */ + fiu_hdr = (struct feature_fiu_header *)(hdr + 1); + fiu_header.csr = readq(&fiu_hdr->csr); + + if (fiu_header.next_afu) { + start += fiu_header.next_afu; + ret = parse_feature_afus(binfo, + (struct feature_header *)start); + if (ret) + return ret; + } else { + dev_info(binfo, "No AFUs detected on Port\n"); + } + + break; + default: + dev_info(binfo, "FIU TYPE %d is not supported yet.\n", + header.id); + } + + return 0; +} + +static void parse_feature_irqs(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + finfo->vec_start = 0; + finfo->vec_cnt = 0; + + UNUSED(binfo); + + if (!strcmp(finfo->name, PORT_FEATURE_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; + } else { + dev_debug(binfo, "UAFU doesn't support interrupt\n"); + } + } else if (!strcmp(finfo->name, PORT_FEATURE_ERR)) { + 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; + } else { + dev_debug(&binfo, "Port error doesn't support interrupt\n"); + } + + } else if (!strcmp(finfo->name, FME_FEATURE_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; + } else { + dev_debug(&binfo, "FME error doesn't support interrupt\n"); + } + } +} + +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; + } + + parse_feature_irqs(binfo, hdr, &fme_features[header.id]); + + return create_feature_instance(binfo, hdr, &fme_features[header.id]); +} + +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; + + 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]); + + return create_feature_instance(binfo, hdr, &port_features[id]); +} + +static int parse_feature_private(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + + header.csr = readq(hdr); + + switch (binfo->current_type) { + case FME_ID: + return parse_feature_fme_private(binfo, hdr); + case PORT_ID: + return parse_feature_port_private(binfo, hdr); + default: + dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n", + header.id, binfo->current_type); + } + return 0; +} + +static int parse_feature(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + int ret = 0; + + header.csr = readq(hdr); + + switch (header.type) { + case FEATURE_TYPE_AFU: + ret = parse_feature_afus(binfo, hdr); + break; + case FEATURE_TYPE_PRIVATE: + ret = parse_feature_private(binfo, hdr); + break; + case FEATURE_TYPE_FIU: + ret = parse_feature_fiu(binfo, hdr); + break; + default: + dev_err(binfo, "Feature Type %x is not supported.\n", + hdr->type); + }; + + return ret; +} + +static int +parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start) +{ + struct feature_header *hdr, header; + u8 __iomem *end = (u8 __iomem *)binfo->ioend; + int ret = 0; + + for (; start < end; start += header.next_header_offset) { + if (end - start < (unsigned int)sizeof(*hdr)) { + dev_err(binfo, "The region is too small to contain a feature.\n"); + ret = -EINVAL; + break; + } + + hdr = (struct feature_header *)start; + ret = parse_feature(binfo, hdr); + if (ret) + return ret; + + header.csr = readq(hdr); + if (!header.next_header_offset) + break; + } + + return build_info_commit_dev(binfo); +} + +/* switch the memory mapping to BAR# @bar */ +static int parse_switch_to(struct build_feature_devs_info *binfo, int bar) +{ + struct opae_adapter_data_pci *pci_data = binfo->pci_data; + + if (!pci_data->region[bar].addr) + return -ENOMEM; + + binfo->ioaddr = pci_data->region[bar].addr; + binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len; + binfo->phys_addr = pci_data->region[bar].phys_addr; + binfo->current_bar = bar; + + return 0; +} + +static int parse_ports_from_fme(struct build_feature_devs_info *binfo) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_port port; + int i = 0, ret = 0; + + if (!binfo->pfme_hdr) { + dev_info(binfo, "VF is detected.\n"); + return ret; + } + + fme_hdr = binfo->pfme_hdr; + + do { + port.csr = readq(&fme_hdr->port[i]); + if (!port.port_implemented) + break; + + /* skip port which only could be accessed via VF */ + if (port.afu_access_control == FME_AFU_ACCESS_VF) + continue; + + ret = parse_switch_to(binfo, port.port_bar); + if (ret) + break; + + ret = parse_feature_list(binfo, + (u8 __iomem *)binfo->ioaddr + + port.port_offset); + if (ret) + break; + } while (++i < MAX_FPGA_PORT_NUM); + + return ret; +} + +static struct build_feature_devs_info * +build_info_alloc_and_init(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + + binfo = zmalloc(sizeof(*binfo)); + if (!binfo) + return binfo; + + binfo->hw = hw; + binfo->pci_data = hw->pci_data; + + /* fpga feature list starts from BAR 0 */ + if (parse_switch_to(binfo, 0)) { + free(binfo); + return NULL; + } + + return binfo; +} + +static void build_info_free(struct build_feature_devs_info *binfo) +{ + free(binfo); +} + +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; + + 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]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr: 0x%lx\n", + feature->name, (unsigned long long)feature->addr, + (unsigned long long)feature->addr + feature->size - 1, + feature->phys_addr); + } + + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) { + port = &hw->port[i]; + + if (port->state != IFPGA_PORT_ATTACHED) + continue; + + dev_info(hw, "port device: %d\n", port->port_id); + + for (j = 0; j < PORT_FEATURE_ID_MAX; j++) { + feature = &port->sub_feature[j]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr:0x%lx\n", + feature->name, + (unsigned long long)feature->addr, + (unsigned long long)feature->addr + + feature->size - 1, + feature->phys_addr); + } + } +} + +int ifpga_bus_enumerate(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + int ret; + + binfo = build_info_alloc_and_init(hw); + if (!binfo) + return -ENOMEM; + + ret = parse_feature_list(binfo, binfo->ioaddr); + if (ret) + goto exit; + + ret = parse_ports_from_fme(binfo); + if (ret) + goto exit; + + ifpga_print_device_feature_list(hw); + +exit: + build_info_free(binfo); + return ret; +} + +int ifpga_bus_init(struct ifpga_hw *hw) +{ + int i; + + fme_hw_init(&hw->fme); + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) + port_hw_init(&hw->port[i]); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h new file mode 100644 index 0000000..14131e3 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_ENUMERATE_H_ +#define _IFPGA_ENUMERATE_H_ + +int ifpga_bus_init(struct ifpga_hw *hw); +int ifpga_bus_enumerate(struct ifpga_hw *hw); + +#endif /* _IFPGA_ENUMERATE_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c new file mode 100644 index 0000000..6d14523 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -0,0 +1,314 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <linux/vfio.h> +#include <sys/ioctl.h> + +#include "ifpga_feature_dev.h" + +/* + * Enable Port by clear the port soft reset bit, which is set by default. + * The AFU is unable to respond to any MMIO access while in reset. + * __fpga_port_enable function should only be used after __fpga_port_disable + * function. + */ +void __fpga_port_enable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + WARN_ON(!port->disable_count); + + if (--port->disable_count != 0) + return; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x0; + writeq(control.csr, &port_hdr->control); +} + +int __fpga_port_disable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + if (port->disable_count++ != 0) + return 0; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + /* Set port soft reset */ + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x1; + writeq(control.csr, &port_hdr->control); + + /* + * HW sets ack bit to 1 when all outstanding requests have been drained + * on this port and minimum soft reset pulse width has elapsed. + * Driver polls port_soft_reset_ack to determine if reset done by HW. + */ + control.port_sftrst_ack = 1; + + if (fpga_wait_register_field(port_sftrst_ack, control, + &port_hdr->control, RST_POLL_TIMEOUT, + RST_POLL_INVL)) { + dev_err(port, "timeout, fail to reset device\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) +{ + struct feature_port_header *port_hdr; + u64 guidl, guidh; + + port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU); + + spinlock_lock(&port->lock); + guidl = readq(&port_hdr->afu_header.guid.b[0]); + guidh = readq(&port_hdr->afu_header.guid.b[8]); + spinlock_unlock(&port->lock); + + printf("%s: guidl=0x%lx, guidh=0x%lx\n", __func__, guidl, guidh); + + memcpy(uuid->b, &guidl, sizeof(u64)); + memcpy(uuid->b + 8, &guidh, sizeof(u64)); + + return 0; +} + +/* Mask / Unmask Port Errors by the Error Mask register. */ +void port_err_mask(struct ifpga_port_hw *port, bool mask) +{ + struct feature_port_error *port_err; + struct feature_port_err_key err_mask; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + if (mask) + err_mask.csr = PORT_ERR_MASK; + else + err_mask.csr = 0; + + writeq(err_mask.csr, &port_err->error_mask); +} + +/* Clear All Port Errors. */ +int port_err_clear(struct ifpga_port_hw *port, u64 err) +{ + struct feature_port_header *port_hdr; + struct feature_port_error *port_err; + struct feature_port_err_key mask; + struct feature_port_first_err_key first; + struct feature_port_status status; + int ret = 0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + /* + * Clear All Port Errors + * + * - Check for AP6 State + * - Halt Port by keeping Port in reset + * - Set PORT Error mask to all 1 to mask errors + * - Clear all errors + * - Set Port mask to all 0 to enable errors + * - All errors start capturing new errors + * - Enable Port by pulling the port out of reset + */ + + /* If device is still in AP6 state, can not clear any error.*/ + status.csr = readq(&port_hdr->status); + if (status.power_state == PORT_POWER_STATE_AP6) { + dev_err(dev, "Could not clear errors, device in AP6 state.\n"); + return -EBUSY; + } + + /* Halt Port by keeping Port in reset */ + ret = __fpga_port_disable(port); + if (ret) + return ret; + + /* Mask all errors */ + port_err_mask(port, true); + + /* Clear errors if err input matches with current port errors.*/ + mask.csr = readq(&port_err->port_error); + + if (mask.csr == err) { + writeq(mask.csr, &port_err->port_error); + + first.csr = readq(&port_err->port_first_error); + writeq(first.csr, &port_err->port_first_error); + } else { + ret = -EBUSY; + } + + /* Clear mask */ + port_err_mask(port, false); + + /* Enable the Port by clear the reset */ + __fpga_port_enable(port); + + return ret; +} + +int port_clear_error(struct ifpga_port_hw *port) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + + dev_info(port, "read port error: 0x%lx\n", error.csr); + + return port_err_clear(port, error.csr); +} + +void fme_hw_uinit(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return; + + 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); + } +} + +int fme_hw_init(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i, ret; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + 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; + } + } + } + + return 0; +} + +void port_hw_uinit(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i; + + 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); + } +} + +int port_hw_init(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i, 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; + } + } + } + + return 0; +} + +/* + * FIXME: we should get msix vec count during pci enumeration instead of + * below hardcode value. + */ +#define FPGA_MSIX_VEC_COUNT 20 +/* irq set buffer length for interrupt */ +#define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \ + sizeof(int) * FPGA_MSIX_VEC_COUNT) + +/* only support msix for now*/ +static int vfio_msix_enable_block(s32 vfio_dev_fd, unsigned int vec_start, + unsigned int count, s32 *fds) +{ + char irq_set_buf[MSIX_IRQ_SET_BUF_LEN]; + struct vfio_irq_set *irq_set; + int len, ret; + int *fd_ptr; + + len = sizeof(irq_set_buf); + + irq_set = (struct vfio_irq_set *)irq_set_buf; + irq_set->argsz = len; + irq_set->count = count; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; + irq_set->start = vec_start; + + fd_ptr = (int *)&irq_set->data; + memcpy(fd_ptr, fds, sizeof(int) * count); + + ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set); + if (ret) + printf("Error enabling MSI-X interrupts\n"); + + return ret; +} + +int fpga_msix_set_block(struct feature *feature, unsigned int start, + unsigned int count, s32 *fds) +{ + struct feature_irq_ctx *ctx = feature->ctx; + unsigned int i; + int ret; + + if (start >= feature->ctx_num || start + count > feature->ctx_num) + return -EINVAL; + + /* assume that each feature has continuous vector space in msix*/ + ret = vfio_msix_enable_block(feature->vfio_dev_fd, + ctx[start].idx, count, fds); + if (!ret) { + for (i = 0; i < count; i++) + ctx[i].eventfd = fds[i]; + } + + return ret; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h new file mode 100644 index 0000000..cd114fb --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_FEATURE_DEV_H_ +#define _IFPGA_FEATURE_DEV_H_ + +#include "ifpga_hw.h" + +static inline struct ifpga_port_hw * +get_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return NULL; + + return &hw->port[port_id]; +} + +#define ifpga_for_each_feature(hw, feature) \ + for ((feature) = (hw)->sub_feature; \ + (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++) + +static inline struct feature * +get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(fme, feature) { + if (feature->id == id) + return feature; + } + + return NULL; +} + +static inline struct feature * +get_port_feature_by_id(struct ifpga_port_hw *port, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(port, feature) { + 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; +} + +static inline void * +get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index) +{ + return port->sub_feature[index].addr; +} + +static inline bool +is_fme_feature_present(struct ifpga_fme_hw *fme, int index) +{ + return !!get_fme_feature_ioaddr_by_index(fme, index); +} + +static inline bool +is_port_feature_present(struct ifpga_port_hw *port, int index) +{ + return !!get_port_feature_ioaddr_by_index(port, index); +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid); + +int __fpga_port_disable(struct ifpga_port_hw *port); +void __fpga_port_enable(struct ifpga_port_hw *port); + +static inline int fpga_port_disable(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_disable(port); + spinlock_unlock(&port->lock); + return ret; +} + +static inline int fpga_port_enable(struct ifpga_port_hw *port) +{ + spinlock_lock(&port->lock); + __fpga_port_enable(port); + spinlock_unlock(&port->lock); + + return 0; +} + +static inline int __fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + ret = __fpga_port_disable(port); + if (ret) + return ret; + + __fpga_port_enable(port); + + return 0; +} + +static inline int fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_reset(port); + spinlock_unlock(&port->lock); + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +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); +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set); + +int fme_hw_init(struct ifpga_fme_hw *fme); +void fme_hw_uinit(struct ifpga_fme_hw *fme); +void port_hw_uinit(struct ifpga_port_hw *port); +int port_hw_init(struct ifpga_port_hw *port); +int port_clear_error(struct ifpga_port_hw *port); +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; + +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); + +/* This struct is used when parsing uafu irq_set */ +struct fpga_uafu_irq_set { + u32 start; + u32 count; + s32 *evtfds; +}; + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set); + +extern struct feature_ops port_hdr_ops; +extern struct feature_ops port_error_ops; +extern struct feature_ops port_stp_ops; +extern struct feature_ops port_uint_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 new file mode 100644 index 0000000..4be60c0 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -0,0 +1,734 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PWR_THRESHOLD_MAX 0x7F + +int fme_get_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +/* fme private feature head */ +static int fme_hdr_init(struct feature *feature) +{ + struct feature_fme_header *fme_hdr; + + fme_hdr = (struct feature_fme_header *)feature->addr; + + dev_info(NULL, "FME HDR Init.\n"); + dev_info(NULL, "FME cap %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + return 0; +} + +static void fme_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME HDR UInit.\n"); +} + +static int fme_hdr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&fme_hdr->header); + *revision = header.revision; + + return 0; +} + +static int fme_hdr_get_ports_num(struct ifpga_fme_hw *fme, u64 *ports_num) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *ports_num = fme_capability.num_ports; + + return 0; +} + +static int fme_hdr_get_cache_size(struct ifpga_fme_hw *fme, u64 *cache_size) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *cache_size = fme_capability.cache_size; + + return 0; +} + +static int fme_hdr_get_version(struct ifpga_fme_hw *fme, u64 *version) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *version = fme_capability.fabric_verid; + + return 0; +} + +static int fme_hdr_get_socket_id(struct ifpga_fme_hw *fme, u64 *socket_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *socket_id = fme_capability.socket_id; + + return 0; +} + +static int fme_hdr_get_bitstream_id(struct ifpga_fme_hw *fme, + u64 *bitstream_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_id = readq(&fme_hdr->bitstream_id); + + return 0; +} + +static int fme_hdr_get_bitstream_metadata(struct ifpga_fme_hw *fme, + u64 *bitstream_metadata) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_metadata = readq(&fme_hdr->bitstream_md); + + return 0; +} + +static int +fme_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_HDR_PROP_REVISION: + return fme_hdr_get_revision(fme, &prop->data); + case FME_HDR_PROP_PORTS_NUM: + return fme_hdr_get_ports_num(fme, &prop->data); + case FME_HDR_PROP_CACHE_SIZE: + return fme_hdr_get_cache_size(fme, &prop->data); + case FME_HDR_PROP_VERSION: + return fme_hdr_get_version(fme, &prop->data); + case FME_HDR_PROP_SOCKET_ID: + return fme_hdr_get_socket_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_ID: + return fme_hdr_get_bitstream_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_METADATA: + return fme_hdr_get_bitstream_metadata(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_hdr_ops = { + .init = fme_hdr_init, + .uinit = fme_hdr_uinit, + .get_prop = fme_hdr_get_prop, +}; + +/* thermal management */ +static int fme_thermal_get_threshold1(struct ifpga_fme_hw *fme, u64 *thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1 = temp_threshold.tmp_thshold1; + + return 0; +} + +static int fme_thermal_set_threshold1(struct ifpga_fme_hw *fme, u64 thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres1 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres1 == 0) { + tmp_threshold.tmp_thshold1_enable = 0; + tmp_threshold.tmp_thshold1 = thres1; + } else { + tmp_threshold.tmp_thshold1_enable = 1; + tmp_threshold.tmp_thshold1 = thres1; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold2(struct ifpga_fme_hw *fme, u64 *thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres2 = temp_threshold.tmp_thshold2; + + return 0; +} + +static int fme_thermal_set_threshold2(struct ifpga_fme_hw *fme, u64 thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres2 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres2 == 0) { + tmp_threshold.tmp_thshold2_enable = 0; + tmp_threshold.tmp_thshold2 = thres2; + } else { + tmp_threshold.tmp_thshold2_enable = 1; + tmp_threshold.tmp_thshold2 = thres2; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold_trip(struct ifpga_fme_hw *fme, + u64 *thres_trip) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres_trip = temp_threshold.therm_trip_thshold; + + return 0; +} + +static int fme_thermal_get_threshold1_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold1_status; + + return 0; +} + +static int fme_thermal_get_threshold2_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold2_status; + + return 0; +} + +static int fme_thermal_get_threshold1_policy(struct ifpga_fme_hw *fme, + u64 *thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_policy = temp_threshold.thshold_policy; + + return 0; +} + +static int fme_thermal_set_threshold1_policy(struct ifpga_fme_hw *fme, + u64 thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold tmp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + + if (thres1_policy == 0) { + tmp_threshold.thshold_policy = 0; + } else if (thres1_policy == 1) { + tmp_threshold.thshold_policy = 1; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_temperature(struct ifpga_fme_hw *fme, u64 *temp) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_temp_rdsensor_fmt1 temp_rdsensor_fmt1; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_rdsensor_fmt1.csr = readq(&thermal->rdsensor_fm1); + *temp = temp_rdsensor_fmt1.fpga_temp; + + return 0; +} + +static int fme_thermal_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_thermal *fme_thermal + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + struct feature_header header; + + header.csr = readq(&fme_thermal->header); + *revision = header.revision; + + return 0; +} + +#define FME_THERMAL_CAP_NO_TMP_THRESHOLD 0x1 + +static int fme_thermal_mgmt_init(struct feature *feature) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold_cap thermal_cap; + + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt Init.\n"); + + fme_thermal = (struct feature_fme_thermal *)feature->addr; + thermal_cap.csr = readq(&fme_thermal->threshold_cap); + + dev_info(NULL, "FME thermal cap %llx.\n", + (unsigned long long)fme_thermal->threshold_cap.csr); + + if (thermal_cap.tmp_thshold_disabled) + feature->cap |= FME_THERMAL_CAP_NO_TMP_THRESHOLD; + + return 0; +} + +static void fme_thermal_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt UInit.\n"); +} + +static int +fme_thermal_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_set_threshold1(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_set_threshold2(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_set_threshold1_policy(fme, prop->data); + } + + return -ENOENT; +} + +static int +fme_thermal_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD && + prop->prop_id != FME_THERMAL_PROP_TEMPERATURE && + prop->prop_id != FME_THERMAL_PROP_REVISION) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_get_threshold1(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_get_threshold2(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD_TRIP: + return fme_thermal_get_threshold_trip(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_REACHED: + return fme_thermal_get_threshold1_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2_REACHED: + return fme_thermal_get_threshold2_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_get_threshold1_policy(fme, &prop->data); + case FME_THERMAL_PROP_TEMPERATURE: + return fme_thermal_get_temperature(fme, &prop->data); + case FME_THERMAL_PROP_REVISION: + return fme_thermal_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_thermal_mgmt_ops = { + .init = fme_thermal_mgmt_init, + .uinit = fme_thermal_mgmt_uinit, + .get_prop = fme_thermal_get_prop, + .set_prop = fme_thermal_set_prop, +}; + +static int fme_pwr_get_consumed(struct ifpga_fme_hw *fme, u64 *consumed) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *consumed = pm_status.pwr_consumed; + + return 0; +} + +static int fme_pwr_get_threshold1(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold1; + + return 0; +} + +static int fme_pwr_set_threshold1(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold1 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold2(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold2; + + return 0; +} + +static int fme_pwr_set_threshold2(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold2 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold1_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold1_status; + + return 0; +} + +static int fme_pwr_get_threshold2_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold2_status; + + return 0; +} + +static int fme_pwr_get_rtl(struct ifpga_fme_hw *fme, u64 *rtl) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *rtl = pm_status.fpga_latency_report; + + return 0; +} + +static int fme_pwr_get_xeon_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_xeon_limit xeon_limit; + + xeon_limit.csr = readq(&fme_power->xeon_limit); + + if (!xeon_limit.enable) + xeon_limit.pwr_limit = 0; + + *limit = xeon_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_fpga_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_fpga_limit fpga_limit; + + fpga_limit.csr = readq(&fme_power->fpga_limit); + + if (!fpga_limit.enable) + fpga_limit.pwr_limit = 0; + + *limit = fpga_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_header header; + + header.csr = readq(&fme_power->header); + *revision = header.revision; + + return 0; +} + +static int fme_power_mgmt_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt Init.\n"); + + return 0; +} + +static void fme_power_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt UInit.\n"); +} + +static int fme_power_mgmt_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_CONSUMED: + return fme_pwr_get_consumed(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_get_threshold1(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_get_threshold2(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1_STATUS: + return fme_pwr_get_threshold1_status(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2_STATUS: + return fme_pwr_get_threshold2_status(fme, &prop->data); + case FME_PWR_PROP_RTL: + return fme_pwr_get_rtl(fme, &prop->data); + case FME_PWR_PROP_XEON_LIMIT: + return fme_pwr_get_xeon_limit(fme, &prop->data); + case FME_PWR_PROP_FPGA_LIMIT: + return fme_pwr_get_fpga_limit(fme, &prop->data); + case FME_PWR_PROP_REVISION: + return fme_pwr_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_power_mgmt_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_set_threshold1(fme, prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_set_threshold2(fme, prop->data); + } + + return -ENOENT; +} + +struct 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, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c new file mode 100644 index 0000000..1773b87 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_dperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_clk_ctr clk; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + clk.afu_interf_clock = readq(&dperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_dperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_dperf *dperf; + struct feature_header header; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + header.csr = readq(&dperf->header); + *revision = header.revision; + + return 0; +} + +#define DPERF_TIMEOUT 30 + +static bool fabric_pobj_is_enabled(int port_id, + struct feature_fme_dperf *dperf) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + + ctl.csr = readq(&dperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum dperf_fab_events fab_event) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dfpmon_fab_ctr ctr; + struct feature_fme_dperf *dperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, dperf)) + goto exit; + + ctl.csr = readq(&dperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &dperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &dperf->fab_ctr, DPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&dperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_dperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, DPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, DPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(mmio_read, DPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, DPERF_FAB_MMIO_WR); + +static int fme_dperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_dperf *dperf; + int status; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + status = fabric_pobj_is_enabled(port_id, dperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_dperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dperf *dperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, dperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&dperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_dperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_dperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 + +static int fme_global_dperf_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf Init.\n"); + + return 0; +} + +static void fme_global_dperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf UInit.\n"); +} + +static int fme_dperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_dperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_dperf_get_fab_port_pcie0_read(fme, sub, &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_dperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* MMIO_READ */ + return fme_dperf_get_fab_port_mmio_read(fme, sub, &prop->data); + case 0x5: /* MMIO_WRITE */ + return fme_dperf_get_fab_port_mmio_write(fme, sub, &prop->data); + case 0x6: /* ENABLE */ + return fme_dperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_dperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_dperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_dperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_dperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_dperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE - fab root only prop */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_dperf_set_fab_freeze(fme, prop->data); + case 0x6: /* ENABLE - fab both root and sub */ + return fme_dperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_dperf_ops = { + .init = fme_global_dperf_init, + .uinit = fme_global_dperf_uinit, + .get_prop = fme_global_dperf_get_prop, + .set_prop = fme_global_dperf_set_prop, + +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c new file mode 100644 index 0000000..33c241e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static int fme_err_get_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + + fme_error0.csr = readq(&fme_err->fme_err); + *val = fme_error0.csr; + + return 0; +} + +static int fme_err_get_first_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_first_error fme_first_err; + + fme_first_err.csr = readq(&fme_err->fme_first_err); + *val = fme_first_err.err_reg_status; + + return 0; +} + +static int fme_err_get_next_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_next_error fme_next_err; + + fme_next_err.csr = readq(&fme_err->fme_next_err); + *val = fme_next_err.err_reg_status; + + return 0; +} + +static int fme_err_set_clear(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_ERROR0_MASK, &fme_err->fme_err_mask); + + fme_error0.csr = readq(&fme_err->fme_err); + if (val != fme_error0.csr) { + ret = -EBUSY; + goto exit; + } + + fme_first_err.csr = readq(&fme_err->fme_first_err); + fme_next_err.csr = readq(&fme_err->fme_next_err); + + writeq(fme_error0.csr & FME_ERROR0_MASK, &fme_err->fme_err); + writeq(fme_first_err.csr & FME_FIRST_ERROR_MASK, + &fme_err->fme_first_err); + writeq(fme_next_err.csr & FME_NEXT_ERROR_MASK, + &fme_err->fme_next_err); + +exit: + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_revision(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_header header; + + header.csr = readq(&fme_err->header); + *val = header.revision; + + return 0; +} + +static int fme_err_get_pcie0_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + + pcie0_err.csr = readq(&fme_err->pcie0_err); + *val = pcie0_err.csr; + + return 0; +} + +static int fme_err_set_pcie0_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE0_ERROR_MASK, &fme_err->pcie0_err_mask); + + pcie0_err.csr = readq(&fme_err->pcie0_err); + if (val != pcie0_err.csr) + ret = -EBUSY; + else + writeq(pcie0_err.csr & FME_PCIE0_ERROR_MASK, + &fme_err->pcie0_err); + + writeq(0UL, &fme_err->pcie0_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_pcie1_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + + pcie1_err.csr = readq(&fme_err->pcie1_err); + *val = pcie1_err.csr; + + return 0; +} + +static int fme_err_set_pcie1_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE1_ERROR_MASK, &fme_err->pcie1_err_mask); + + pcie1_err.csr = readq(&fme_err->pcie1_err); + if (val != pcie1_err.csr) + ret = -EBUSY; + else + writeq(pcie1_err.csr & FME_PCIE1_ERROR_MASK, + &fme_err->pcie1_err); + + writeq(0UL, &fme_err->pcie1_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_nonfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_nonfaterror ras_nonfaterr; + + ras_nonfaterr.csr = readq(&fme_err->ras_nonfaterr); + *val = ras_nonfaterr.csr; + + return 0; +} + +static int fme_err_get_catfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_catfaterror ras_catfaterr; + + ras_catfaterr.csr = readq(&fme_err->ras_catfaterr); + *val = ras_catfaterr.csr; + + return 0; +} + +static int fme_err_get_inject_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + *val = ras_error_inj.csr & FME_RAS_ERROR_INJ_MASK; + + return 0; +} + +static int fme_err_set_inject_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + spinlock_lock(&fme->lock); + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + + if (val <= FME_RAS_ERROR_INJ_MASK) { + ras_error_inj.csr = val; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(ras_error_inj.csr, &fme_err->ras_error_inj); + spinlock_unlock(&fme->lock); + + return 0; +} + +static void fme_error_enable(struct ifpga_fme_hw *fme) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + writeq(0UL, &fme_err->pcie0_err_mask); + writeq(0UL, &fme_err->pcie1_err_mask); + writeq(0UL, &fme_err->ras_nonfat_mask); + writeq(0UL, &fme_err->ras_catfat_mask); +} + +static int fme_global_error_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = feature->parent; + + fme_error_enable(fme); + + if (feature->ctx_num) + fme->capability |= FPGA_FME_CAP_ERR_IRQ; + + return 0; +} + +static void fme_global_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int fme_err_fme_err_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* ERRORS */ + return fme_err_get_errors(fme, &prop->data); + case 0x2: /* FIRST_ERROR */ + return fme_err_get_first_error(fme, &prop->data); + case 0x3: /* NEXT_ERROR */ + return fme_err_get_next_error(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x5: /* REVISION */ + return fme_err_get_revision(fme, &prop->data); + case 0x6: /* PCIE0_ERRORS */ + return fme_err_get_pcie0_errors(fme, &prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_get_pcie1_errors(fme, &prop->data); + case 0x8: /* NONFATAL_ERRORS */ + return fme_err_get_nonfatal_errors(fme, &prop->data); + case 0x9: /* CATFATAL_ERRORS */ + return fme_err_get_catfatal_errors(fme, &prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_get_inject_errors(fme, &prop->data); + case 0xb: /* REVISION*/ + return fme_err_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_get_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_err_fme_err_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x4: /* CLEAR */ + return fme_err_set_clear(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x6: /* PCIE0_ERRORS */ + return fme_err_set_pcie0_errors(fme, prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_set_pcie1_errors(fme, prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_set_inject_errors(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_set_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_set_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_global_err_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_fme_err_irq_set *err_irq_set = + (struct fpga_fme_err_irq_set *)irq_set; + struct ifpga_fme_hw *fme; + int ret; + + fme = (struct ifpga_fme_hw *)feature->parent; + + spinlock_lock(&fme->lock); + if (!(fme->capability & FPGA_FME_CAP_ERR_IRQ)) { + spinlock_unlock(&fme->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&fme->lock); + + return ret; +} + +struct feature_ops fme_global_err_ops = { + .init = fme_global_error_init, + .uinit = fme_global_error_uinit, + .get_prop = fme_global_error_get_prop, + .set_prop = fme_global_error_set_prop, + .set_irq = fme_global_err_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c new file mode 100644 index 0000000..e6c40a1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c @@ -0,0 +1,715 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_iperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_clk_ctr clk; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + clk.afu_interf_clock = readq(&iperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_iperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_iperf *iperf; + struct feature_header header; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + header.csr = readq(&iperf->header); + *revision = header.revision; + + return 0; +} + +static int fme_iperf_get_cache_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + *freeze = (u64)ctl.freeze; + return 0; +} + +static int fme_iperf_set_cache_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->ch_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define IPERF_TIMEOUT 30 + +static u64 read_cache_counter(struct ifpga_fme_hw *fme, + u8 channel, enum iperf_cache_events event) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + struct feature_fme_ifpmon_ch_ctr ctr0, ctr1; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* set channel access type and cache event code. */ + ctl.csr = readq(&iperf->ch_ctl); + ctl.cci_chsel = channel; + ctl.cache_event = event; + writeq(ctl.csr, &iperf->ch_ctl); + + /* check the event type in the counter registers */ + ctr0.event_code = event; + + if (fpga_wait_register_field(event_code, ctr0, + &iperf->ch_ctr0, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched cache event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr0.csr = readq(&iperf->ch_ctr0); + ctr1.csr = readq(&iperf->ch_ctr1); + counter = ctr0.cache_counter + ctr1.cache_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define CACHE_SHOW(name, type, event) \ +static int fme_iperf_get_cache_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_cache_counter(fme, type, event); \ + return 0; \ +} + +CACHE_SHOW(read_hit, CACHE_CHANNEL_RD, IPERF_CACHE_RD_HIT); +CACHE_SHOW(read_miss, CACHE_CHANNEL_RD, IPERF_CACHE_RD_MISS); +CACHE_SHOW(write_hit, CACHE_CHANNEL_WR, IPERF_CACHE_WR_HIT); +CACHE_SHOW(write_miss, CACHE_CHANNEL_WR, IPERF_CACHE_WR_MISS); +CACHE_SHOW(hold_request, CACHE_CHANNEL_RD, IPERF_CACHE_HOLD_REQ); +CACHE_SHOW(tx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_TX_REQ_STALL); +CACHE_SHOW(rx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_RX_REQ_STALL); +CACHE_SHOW(rx_eviction, CACHE_CHANNEL_RD, IPERF_CACHE_EVICTIONS); +CACHE_SHOW(data_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_DATA_WR_PORT_CONTEN); +CACHE_SHOW(tag_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_TAG_WR_PORT_CONTEN); + +static int fme_iperf_get_vtd_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_vtd_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->vtd_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static u64 read_iommu_sip_counter(struct ifpga_fme_hw *fme, + enum iperf_vtd_sip_events event) +{ + struct feature_fme_ifpmon_vtd_sip_ctl sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr sip_ctr; + struct feature_fme_iperf *iperf; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + sip_ctl.csr = readq(&iperf->vtd_sip_ctl); + sip_ctl.vtd_evtcode = event; + writeq(sip_ctl.csr, &iperf->vtd_sip_ctl); + + sip_ctr.event_code = event; + + if (fpga_wait_register_field(event_code, sip_ctr, + &iperf->vtd_sip_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd SIP event type in counter registers\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + sip_ctr.csr = readq(&iperf->vtd_sip_ctr); + counter = sip_ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_SIP_SHOW(name, event) \ +static int fme_iperf_get_vtd_sip_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_iommu_sip_counter(fme, event); \ + return 0; \ +} + +VTD_SIP_SHOW(iotlb_4k_hit, IPERF_VTD_SIP_IOTLB_4K_HIT); +VTD_SIP_SHOW(iotlb_2m_hit, IPERF_VTD_SIP_IOTLB_2M_HIT); +VTD_SIP_SHOW(iotlb_1g_hit, IPERF_VTD_SIP_IOTLB_1G_HIT); +VTD_SIP_SHOW(slpwc_l3_hit, IPERF_VTD_SIP_SLPWC_L3_HIT); +VTD_SIP_SHOW(slpwc_l4_hit, IPERF_VTD_SIP_SLPWC_L4_HIT); +VTD_SIP_SHOW(rcc_hit, IPERF_VTD_SIP_RCC_HIT); +VTD_SIP_SHOW(iotlb_4k_miss, IPERF_VTD_SIP_IOTLB_4K_MISS); +VTD_SIP_SHOW(iotlb_2m_miss, IPERF_VTD_SIP_IOTLB_2M_MISS); +VTD_SIP_SHOW(iotlb_1g_miss, IPERF_VTD_SIP_IOTLB_1G_MISS); +VTD_SIP_SHOW(slpwc_l3_miss, IPERF_VTD_SIP_SLPWC_L3_MISS); +VTD_SIP_SHOW(slpwc_l4_miss, IPERF_VTD_SIP_SLPWC_L4_MISS); +VTD_SIP_SHOW(rcc_miss, IPERF_VTD_SIP_RCC_MISS); + +static u64 read_iommu_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_vtd_events base_event) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_ifpmon_vtd_ctr ctr; + struct feature_fme_iperf *iperf; + enum iperf_vtd_events event = base_event + port_id; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.vtd_evtcode = event; + writeq(ctl.csr, &iperf->vtd_ctl); + + ctr.event_code = event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->vtd_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->vtd_ctr); + counter = ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_PORT_SHOW(name, base_event) \ +static int fme_iperf_get_vtd_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_iommu_counter(fme, port_id, base_event); \ + return 0; \ +} + +VTD_PORT_SHOW(read_transaction, IPERF_VTD_AFU_MEM_RD_TRANS); +VTD_PORT_SHOW(write_transaction, IPERF_VTD_AFU_MEM_WR_TRANS); +VTD_PORT_SHOW(devtlb_read_hit, IPERF_VTD_AFU_DEVTLB_RD_HIT); +VTD_PORT_SHOW(devtlb_write_hit, IPERF_VTD_AFU_DEVTLB_WR_HIT); +VTD_PORT_SHOW(devtlb_4k_fill, IPERF_VTD_DEVTLB_4K_FILL); +VTD_PORT_SHOW(devtlb_2m_fill, IPERF_VTD_DEVTLB_2M_FILL); +VTD_PORT_SHOW(devtlb_1g_fill, IPERF_VTD_DEVTLB_1G_FILL); + +static bool fabric_pobj_is_enabled(u8 port_id, struct feature_fme_iperf *iperf) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + + ctl.csr = readq(&iperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_fab_events fab_event) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_ifpmon_fab_ctr ctr; + struct feature_fme_iperf *iperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, iperf)) + goto exit; + + ctl.csr = readq(&iperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &iperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->fab_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_iperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, IPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, IPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(pcie1_read, IPERF_FAB_PCIE1_RD); +FAB_PORT_SHOW(pcie1_write, IPERF_FAB_PCIE1_WR); +FAB_PORT_SHOW(upi_read, IPERF_FAB_UPI_RD); +FAB_PORT_SHOW(upi_write, IPERF_FAB_UPI_WR); +FAB_PORT_SHOW(mmio_read, IPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, IPERF_FAB_MMIO_WR); + +static int fme_iperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_iperf *iperf; + int status; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + status = fabric_pobj_is_enabled(port_id, iperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_iperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, iperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&iperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_iperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 +#define FME_IPERF_CAP_IOMMU 0x1 + +static int fme_global_iperf_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme; + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + + dev_info(NULL, "FME global_iperf Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + /* check if iommu is not supported on this device. */ + fme_capability.csr = readq(&fme_hdr->capability); + dev_info(NULL, "FME HEAD fme_capability %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + if (fme_capability.iommu_support) + feature->cap |= FME_IPERF_CAP_IOMMU; + + return 0; +} + +static void fme_global_iperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_iperf UInit.\n"); +} + +static int fme_iperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_iperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_iperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_cache_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_cache_freeze(fme, &prop->data); + case 0x2: /* READ_HIT */ + return fme_iperf_get_cache_read_hit(fme, &prop->data); + case 0x3: /* READ_MISS */ + return fme_iperf_get_cache_read_miss(fme, &prop->data); + case 0x4: /* WRITE_HIT */ + return fme_iperf_get_cache_write_hit(fme, &prop->data); + case 0x5: /* WRITE_MISS */ + return fme_iperf_get_cache_write_miss(fme, &prop->data); + case 0x6: /* HOLD_REQUEST */ + return fme_iperf_get_cache_hold_request(fme, &prop->data); + case 0x7: /* TX_REQ_STALL */ + return fme_iperf_get_cache_tx_req_stall(fme, &prop->data); + case 0x8: /* RX_REQ_STALL */ + return fme_iperf_get_cache_rx_req_stall(fme, &prop->data); + case 0x9: /* RX_EVICTION */ + return fme_iperf_get_cache_rx_eviction(fme, &prop->data); + case 0xa: /* DATA_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_data_write_port_contention(fme, + &prop->data); + case 0xb: /* TAG_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_tag_write_port_contention(fme, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_vtd_freeze(fme, &prop->data); + case 0x2: /* IOTLB_4K_HIT */ + return fme_iperf_get_vtd_sip_iotlb_4k_hit(fme, &prop->data); + case 0x3: /* IOTLB_2M_HIT */ + return fme_iperf_get_vtd_sip_iotlb_2m_hit(fme, &prop->data); + case 0x4: /* IOTLB_1G_HIT */ + return fme_iperf_get_vtd_sip_iotlb_1g_hit(fme, &prop->data); + case 0x5: /* SLPWC_L3_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l3_hit(fme, &prop->data); + case 0x6: /* SLPWC_L4_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l4_hit(fme, &prop->data); + case 0x7: /* RCC_HIT */ + return fme_iperf_get_vtd_sip_rcc_hit(fme, &prop->data); + case 0x8: /* IOTLB_4K_MISS */ + return fme_iperf_get_vtd_sip_iotlb_4k_miss(fme, &prop->data); + case 0x9: /* IOTLB_2M_MISS */ + return fme_iperf_get_vtd_sip_iotlb_2m_miss(fme, &prop->data); + case 0xa: /* IOTLB_1G_MISS */ + return fme_iperf_get_vtd_sip_iotlb_1g_miss(fme, &prop->data); + case 0xb: /* SLPWC_L3_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l3_miss(fme, &prop->data); + case 0xc: /* SLPWC_L4_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l4_miss(fme, &prop->data); + case 0xd: /* RCC_MISS */ + return fme_iperf_get_vtd_sip_rcc_miss(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_sub_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub > PERF_MAX_PORT_NUM) + return -ENOENT; + + switch (id) { + case 0xe: /* READ_TRANSACTION */ + return fme_iperf_get_vtd_port_read_transaction(fme, sub, + &prop->data); + case 0xf: /* WRITE_TRANSACTION */ + return fme_iperf_get_vtd_port_write_transaction(fme, sub, + &prop->data); + case 0x10: /* DEVTLB_READ_HIT */ + return fme_iperf_get_vtd_port_devtlb_read_hit(fme, sub, + &prop->data); + case 0x11: /* DEVTLB_WRITE_HIT */ + return fme_iperf_get_vtd_port_devtlb_write_hit(fme, sub, + &prop->data); + case 0x12: /* DEVTLB_4K_FILL */ + return fme_iperf_get_vtd_port_devtlb_4k_fill(fme, sub, + &prop->data); + case 0x13: /* DEVTLB_2M_FILL */ + return fme_iperf_get_vtd_port_devtlb_2m_fill(fme, sub, + &prop->data); + case 0x14: /* DEVTLB_1G_FILL */ + return fme_iperf_get_vtd_port_devtlb_1g_fill(fme, sub, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED) + return fme_iperf_vtd_root_get_prop(feature, prop); + + return fme_iperf_vtd_sub_get_prop(feature, prop); +} + +static int fme_iperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + /* Other properties are present for both top and sub levels */ + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_iperf_get_fab_port_pcie0_read(fme, sub, + &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_iperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* PCIE1_READ */ + return fme_iperf_get_fab_port_pcie1_read(fme, sub, + &prop->data); + case 0x5: /* PCIE1_WRITE */ + return fme_iperf_get_fab_port_pcie1_write(fme, sub, + &prop->data); + case 0x6: /* UPI_READ */ + return fme_iperf_get_fab_port_upi_read(fme, sub, + &prop->data); + case 0x7: /* UPI_WRITE */ + return fme_iperf_get_fab_port_upi_write(fme, sub, + &prop->data); + case 0x8: /* MMIO_READ */ + return fme_iperf_get_fab_port_mmio_read(fme, sub, + &prop->data); + case 0x9: /* MMIO_WRITE */ + return fme_iperf_get_fab_port_mmio_write(fme, sub, + &prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_get_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_get_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_iperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_iperf_cache_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_cache_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_vtd_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_vtd_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_set_fab_freeze(fme, prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_set_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_set_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_iperf_ops = { + .init = fme_global_iperf_init, + .uinit = fme_global_iperf_uinit, + .get_prop = fme_global_iperf_get_prop, + .set_prop = fme_global_iperf_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c new file mode 100644 index 0000000..6192fa7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c @@ -0,0 +1,372 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#if defined(RTE_ARCH_X86_64) +static inline void copy512(const void *src, void *dst) +{ + asm volatile("vmovdqu64 (%0), %%zmm0;" + "vmovntdq %%zmm0, (%1);" + : + : "r"(src), "r"(dst)); +} +#else +static inline void copy512(const void *src, void *dst) +{ + UNUSED(src); + UNUSED(dst); + WARN_ON(1); +} +#endif + +static u64 +pr_err_handle(struct feature_fme_pr *fme_pr) +{ + struct feature_fme_pr_status fme_pr_status; + unsigned long err_code; + u64 fme_pr_error; + int i; + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + if (!fme_pr_status.pr_status) + return 0; + + err_code = readq(&fme_pr->ccip_fme_pr_err); + fme_pr_error = err_code; + + for (i = 0; i < PR_MAX_ERR_NUM; i++) { + if (err_code & (1 << i)) + dev_info(NULL, "%s\n", pr_err_msg[i]); + } + + writeq(fme_pr_error, &fme_pr->ccip_fme_pr_err); + return fme_pr_error; +} + +static int fme_pr_write_init(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + if (info->flags != FPGA_MGR_PARTIAL_RECONFIG) + return -EINVAL; + + dev_info(fme_dev, "resetting PR before initiated PR\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + fme_pr_ctl.pr_reset_ack = 1; + + if (fpga_wait_register_field(pr_reset_ack, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 0; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "waiting for PR resource in HW to be initialized and ready\n"); + + fme_pr_status.pr_host_status = PR_HOST_STATUS_IDLE; + + if (fpga_wait_register_field(pr_host_status, fme_pr_status, + &fme_pr->ccip_fme_pr_status, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "check if have any previous PR error\n"); + pr_err_handle(fme_pr); + return 0; +} + +static int fme_pr_write(struct ifpga_fme_hw *fme_dev, + int port_id, const char *buf, size_t count, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + struct feature_fme_pr_data fme_pr_data; + int delay, pr_credit; + int ret = 0; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + dev_info(fme_dev, "set PR port ID and start request\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_regionid = port_id; + fme_pr_ctl.pr_start_req = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "pushing data from bitstream to HW\n"); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + + while (count > 0) { + delay = 0; + while (pr_credit <= 1) { + if (delay++ > PR_WAIT_TIMEOUT) { + dev_err(fme_dev, "maximum try\n"); + + info->pr_err = pr_err_handle(fme_pr); + return info->pr_err ? -EIO : -ETIMEDOUT; + } + udelay(1); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + }; + + if (count >= fme_dev->pr_bandwidth) { + switch (fme_dev->pr_bandwidth) { + case 4: + fme_pr_data.rsvd = 0; + fme_pr_data.pr_data_raw = *((const u32 *)buf); + writeq(fme_pr_data.csr, + &fme_pr->ccip_fme_pr_data); + break; + case 64: + copy512(buf, &fme_pr->fme_pr_data1); + break; + default: + ret = -EFAULT; + goto done; + } + + buf += fme_dev->pr_bandwidth; + count -= fme_dev->pr_bandwidth; + pr_credit--; + } else { + WARN_ON(1); + return -EINVAL; + goto done; + } + } + +done: + return ret; +} + +static int fme_pr_write_complete(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_push_complete = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "green bitstream push complete\n"); + dev_info(fme_dev, "waiting for HW to release PR resource\n"); + + fme_pr_ctl.pr_start_req = 0; + + if (fpga_wait_register_field(pr_start_req, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + printf("maximum try.\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "PR operation complete, checking status\n"); + info->pr_err = pr_err_handle(fme_pr); + if (info->pr_err) + return -EIO; + + dev_info(fme_dev, "PR done successfully\n"); + return 0; +} + +static int fpga_pr_buf_load(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info, const char *buf, + size_t count) +{ + int ret; + + info->state = FPGA_PR_STATE_WRITE_INIT; + ret = fme_pr_write_init(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error preparing FPGA for writing\n"); + info->state = FPGA_PR_STATE_WRITE_INIT_ERR; + return ret; + } + + /* + * Write the FPGA image to the FPGA. + */ + info->state = FPGA_PR_STATE_WRITE; + ret = fme_pr_write(fme_dev, info->port_id, buf, count, info); + if (ret) { + dev_err(fme_dev, "Error while writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_ERR; + return ret; + } + + /* + * After all the FPGA image has been written, do the device specific + * steps to finish and set the FPGA into operating mode. + */ + info->state = FPGA_PR_STATE_WRITE_COMPLETE; + ret = fme_pr_write_complete(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error after writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_COMPLETE_ERR; + return ret; + } + info->state = FPGA_PR_STATE_DONE; + + return 0; +} + +static int fme_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + struct ifpga_fme_hw *fme = &hw->fme; + struct fpga_pr_info info; + struct ifpga_port_hw *port; + int ret = 0; + + if (!buffer || size == 0) + return -EINVAL; + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + /* + * Padding extra zeros to align PR buffer with PR bandwidth, HW will + * ignore these zeros automatically. + */ + size = ALIGN(size, fme->pr_bandwidth); + + /* get fme header region */ + fme_hdr = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_HEADER); + if (!fme_hdr) + return -EINVAL; + + /* check port id */ + fme_capability.csr = readq(&fme_hdr->capability); + if (port_id >= fme_capability.num_ports) { + dev_err(fme, "port number more than maximum\n"); + return -EINVAL; + } + + memset(&info, 0, sizeof(struct fpga_pr_info)); + info.flags = FPGA_MGR_PARTIAL_RECONFIG; + info.port_id = port_id; + + spinlock_lock(&fme->lock); + + /* get port device by port_id */ + port = &hw->port[port_id]; + + /* Disable Port before PR */ + fpga_port_disable(port); + + ret = fpga_pr_buf_load(fme, &info, (void *)buffer, size); + + *status = info.pr_err; + + /* Re-enable Port after PR finished */ + fpga_port_enable(port); + spinlock_unlock(&fme->lock); + + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, u64 *status) +{ + struct bts_header *bts_hdr; + void *buf; + struct ifpga_port_hw *port; + int ret; + + if (!buffer || size == 0) { + dev_err(hw, "invalid parameter\n"); + return -EINVAL; + } + + bts_hdr = (struct bts_header *)buffer; + + if (is_valid_bts(bts_hdr)) { + dev_info(hw, "this is a valid bitsteam..\n"); + size -= (sizeof(struct bts_header) + + bts_hdr->metadata_len); + buf = (u8 *)buffer + sizeof(struct bts_header) + + bts_hdr->metadata_len; + } else { + return -EINVAL; + } + + /* clean port error before do PR */ + port = &hw->port[port_id]; + ret = port_clear_error(port); + if (ret) { + dev_err(hw, "port cannot clear error\n"); + return -EINVAL; + } + + return fme_pr(hw, port_id, buf, size, status); +} + +static int fme_pr_mgmt_init(struct feature *feature) +{ + struct feature_fme_pr *fme_pr; + struct feature_header fme_pr_header; + struct ifpga_fme_hw *fme; + + dev_info(NULL, "FME PR MGMT Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + + fme_pr = (struct feature_fme_pr *)feature->addr; + + fme_pr_header.csr = readq(&fme_pr->header); + if (fme_pr_header.revision == 2) { + dev_info(NULL, "using 512-bit PR\n"); + fme->pr_bandwidth = 64; + } else { + dev_info(NULL, "using 32-bit PR\n"); + fme->pr_bandwidth = 4; + } + + return 0; +} + +static void fme_pr_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME PR MGMT UInit.\n"); +} + +struct 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 new file mode 100644 index 0000000..a20520c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_HW_H_ +#define _IFPGA_HW_H_ + +#include "ifpga_defines.h" +#include "opae_ifpga_hw_api.h" + +enum ifpga_feature_state { + IFPGA_FEATURE_UNUSED = 0, + IFPGA_FEATURE_ATTACHED, +}; + +struct feature_irq_ctx { + int eventfd; + int idx; +}; + +struct feature { + enum ifpga_feature_state state; + const char *name; + u64 id; + u8 *addr; + uint64_t phys_addr; + u32 size; + int revision; + u64 cap; + int vfio_dev_fd; + struct feature_irq_ctx *ctx; + unsigned int ctx_num; + + void *parent; /* to parent hw data structure */ + + struct feature_ops *ops;/* callback to this private feature */ +}; + +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); +}; + +enum ifpga_fme_state { + IFPGA_FME_UNUSED = 0, + IFPGA_FME_IMPLEMENTED, +}; + +struct ifpga_fme_hw { + enum ifpga_fme_state state; + + struct feature sub_feature[FME_FEATURE_ID_MAX]; + spinlock_t lock; /* protect hardware access */ + + void *parent; /* pointer to ifpga_hw */ + + /* provied by HEADER feature */ + u32 port_num; + struct uuid bitstream_id; + u64 bitstream_md; + size_t pr_bandwidth; + u32 socket_id; + u32 fabric_version_id; + u32 cache_size; + + u32 capability; +}; + +enum ifpga_port_state { + IFPGA_PORT_UNUSED = 0, + IFPGA_PORT_ATTACHED, + IFPGA_PORT_DETACHED, +}; + +struct ifpga_port_hw { + enum ifpga_port_state state; + + struct feature sub_feature[PORT_FEATURE_ID_MAX]; + spinlock_t lock; /* protect access to hw */ + + void *parent; /* pointer to ifpga_hw */ + + int port_id; /* provied by HEADER feature */ + struct uuid afu_id; /* provied by User AFU feature */ + + unsigned int disable_count; + + u32 capability; + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ + u8 *stp_addr; + u32 stp_size; +}; + +#define AFU_MAX_REGION 1 + +struct ifpga_afu_info { + struct opae_reg_region region[AFU_MAX_REGION]; + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct ifpga_hw { + struct opae_adapter *adapter; + struct opae_adapter_data_pci *pci_data; + + struct ifpga_fme_hw fme; + struct ifpga_port_hw port[MAX_FPGA_PORT_NUM]; +}; + +static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) +{ + return hw->fme.state != IFPGA_FME_UNUSED; +} + +static inline bool is_valid_port_id(struct ifpga_hw *hw, u32 port_id) +{ + if (port_id >= MAX_FPGA_PORT_NUM || + hw->port[port_id].state != IFPGA_PORT_ATTACHED) + return false; + + return true; +} +#endif /* _IFPGA_HW_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c new file mode 100644 index 0000000..8ab1bdb --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c @@ -0,0 +1,408 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +static int port_get_revision(struct ifpga_port_hw *port, u64 *revision) +{ + struct feature_port_header *port_hdr + = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&port_hdr->header); + + *revision = header.revision; + + return 0; +} + +static int port_get_portidx(struct ifpga_port_hw *port, u64 *idx) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + capability.csr = readq(&port_hdr->capability); + *idx = capability.port_number; + + return 0; +} + +static int port_get_latency_tolerance(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + control.csr = readq(&port_hdr->control); + *val = control.latency_tolerance; + + return 0; +} + +static int port_get_ap1_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap1_event; + + return 0; +} + +static int port_set_ap1_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap1_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_ap2_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap2_event; + + return 0; +} + +static int port_set_ap2_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap2_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_power_state(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.power_state; + + return 0; +} + +static int port_get_userclk_freqcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_hdr_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port hdr Init.\n"); + + fpga_port_reset(port); + + return 0; +} + +static void port_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port hdr uinit.\n"); +} + +static int port_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_REVISION: + return port_get_revision(port, &prop->data); + case PORT_HDR_PROP_PORTIDX: + return port_get_portidx(port, &prop->data); + case PORT_HDR_PROP_LATENCY_TOLERANCE: + return port_get_latency_tolerance(port, &prop->data); + case PORT_HDR_PROP_AP1_EVENT: + return port_get_ap1_event(port, &prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_get_ap2_event(port, &prop->data); + case PORT_HDR_PROP_POWER_STATE: + return port_get_power_state(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_get_userclk_freqcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_get_userclk_freqcntrcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQSTS: + return port_get_userclk_freqsts(port, &prop->data); + case PORT_HDR_PROP_USERCLK_CNTRSTS: + return port_get_userclk_freqcntrsts(port, &prop->data); + } + + return -ENOENT; +} + +static int port_hdr_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_AP1_EVENT: + return port_set_ap1_event(port, prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_set_ap2_event(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_set_userclk_freqcmd(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_set_userclk_freqcntrcmd(port, prop->data); + } + + return -ENOENT; +} + +struct feature_ops 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) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port stp Init.\n"); + + spinlock_lock(&port->lock); + port->stp_addr = feature->addr; + port->stp_size = feature->size; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_stp_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port stp uinit.\n"); +} + +struct feature_ops port_stp_ops = { + .init = port_stp_init, + .uinit = port_stp_uinit, +}; + +static int port_uint_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "PORT UINT Init.\n"); + + spinlock_lock(&port->lock); + if (feature->ctx_num) { + port->capability |= FPGA_PORT_CAP_UAFU_IRQ; + port->num_uafu_irqs = feature->ctx_num; + } + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_uint_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT UINT UInit.\n"); +} + +static int port_uint_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_uafu_irq_set *uafu_irq_set = irq_set; + struct ifpga_port_hw *port = feature->parent; + int ret; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_UAFU_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, uafu_irq_set->start, + uafu_irq_set->count, uafu_irq_set->evtfds); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_uint_ops = { + .init = port_uint_init, + .uinit = port_uint_uinit, + .set_irq = port_uint_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c new file mode 100644 index 0000000..3be0f5e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static int port_err_get_revision(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_header header; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + header.csr = readq(&port_err->header); + *val = header.revision; + + return 0; +} + +static int port_err_get_errors(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + *val = error.csr; + + return 0; +} + +static int port_err_get_first_error(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_first_err_key first_error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + first_error.csr = readq(&port_err->port_first_error); + *val = first_error.csr; + + return 0; +} + +static int port_err_get_first_malformed_req_lsb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req0 malreq0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq0.header_lsb = readq(&port_err->malreq0); + *val = malreq0.header_lsb; + + return 0; +} + +static int port_err_get_first_malformed_req_msb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req1 malreq1; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq1.header_msb = readq(&port_err->malreq1); + *val = malreq1.header_msb; + + return 0; +} + +static int port_err_set_clear(struct ifpga_port_hw *port, u64 val) +{ + int ret; + + spinlock_lock(&port->lock); + ret = port_err_clear(port, val); + spinlock_unlock(&port->lock); + + return ret; +} + +static int port_error_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port error Init.\n"); + + spinlock_lock(&port->lock); + port_err_mask(port, false); + if (feature->ctx_num) + port->capability |= FPGA_PORT_CAP_ERR_IRQ; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int port_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_ERR_PROP_REVISION: + return port_err_get_revision(port, &prop->data); + case PORT_ERR_PROP_ERRORS: + return port_err_get_errors(port, &prop->data); + case PORT_ERR_PROP_FIRST_ERROR: + return port_err_get_first_error(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB: + return port_err_get_first_malformed_req_lsb(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB: + return port_err_get_first_malformed_req_msb(port, &prop->data); + } + + return -ENOENT; +} + +static int port_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + if (prop->prop_id == PORT_ERR_PROP_CLEAR) + return port_err_set_clear(port, prop->data); + + return -ENOENT; +} + +static int port_error_set_irq(struct feature *feature, void *irq_set) +{ + struct fpga_port_err_irq_set *err_irq_set = irq_set; + struct ifpga_port_hw *port; + int ret; + + port = feature->parent; + + spinlock_lock(&port->lock); + if (!(port->capability & FPGA_PORT_CAP_ERR_IRQ)) { + spinlock_unlock(&port->lock); + return -ENODEV; + } + + ret = fpga_msix_set_block(feature, 0, 1, &err_irq_set->evtfd); + spinlock_unlock(&port->lock); + + return ret; +} + +struct feature_ops port_error_ops = { + .init = port_error_init, + .uinit = port_error_uinit, + .get_prop = port_error_get_prop, + .set_prop = port_error_set_prop, + .set_irq = port_error_set_irq, +}; diff --git a/drivers/raw/ifpga_rawdev/base/meson.build b/drivers/raw/ifpga_rawdev/base/meson.build new file mode 100644 index 0000000..cb65535 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/meson.build @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +sources = [ + 'ifpga_api.c', + 'ifpga_enumerate.c', + 'ifpga_feature_dev.c', + 'ifpga_fme.c', + 'ifpga_fme_iperf.c', + 'ifpga_fme_dperf.c', + 'ifpga_fme_error.c', + 'ifpga_port.c', + 'ifpga_port_error.c', + 'ifpga_fme_pr.c', + 'opae_hw_api.c', + 'opae_ifpga_hw_api.c', + 'opae_debug.c' +] + +error_cflags = ['-Wno-sign-compare', '-Wno-unused-value', + '-Wno-format', '-Wno-unused-but-set-variable', + '-Wno-strict-aliasing' +] +c_args = cflags +foreach flag: error_cflags + if cc.has_argument(flag) + c_args += flag + endif +endforeach + +base_lib = static_library('ifpga_rawdev_base', sources, + dependencies: static_rte_eal, + c_args: c_args) +base_objs = base_lib.extract_all_objects() diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.c b/drivers/raw/ifpga_rawdev/base/opae_debug.c new file mode 100644 index 0000000..024d7d2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.c @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#define OPAE_HW_DEBUG + +#include "opae_hw_api.h" +#include "opae_debug.h" + +void opae_manager_dump(struct opae_manager *mgr) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Manger %s\n", mgr->name); + opae_log("OPAE Manger OPs = %p\n", mgr->ops); + opae_log("OPAE Manager Private Data = %p\n", mgr->data); + opae_log("OPAE Adapter(parent) = %p\n", mgr->adapter); + opae_log("==========================\n"); +} + +void opae_bridge_dump(struct opae_bridge *br) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Bridge %s\n", br->name); + opae_log("OPAE Bridge ID = %d\n", br->id); + opae_log("OPAE Bridge OPs = %p\n", br->ops); + opae_log("OPAE Bridge Private Data = %p\n", br->data); + opae_log("OPAE Accelerator(under this bridge) = %p\n", br->acc); + opae_log("==========================\n"); +} + +void opae_accelerator_dump(struct opae_accelerator *acc) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Accelerator %s\n", acc->name); + opae_log("OPAE Accelerator Index = %d\n", acc->index); + opae_log("OPAE Accelerator OPs = %p\n", acc->ops); + opae_log("OPAE Accelerator Private Data = %p\n", acc->data); + opae_log("OPAE Bridge (upstream) = %p\n", acc->br); + opae_log("OPAE Manager (upstream) = %p\n", acc->mgr); + opae_log("==========================\n"); + + if (acc->br) + opae_bridge_dump(acc->br); +} + +static void opae_adapter_data_dump(void *data) +{ + struct opae_adapter_data *d = data; + struct opae_adapter_data_pci *d_pci; + struct opae_reg_region *r; + int i; + + opae_log("=====%s=====\n", __func__); + + switch (d->type) { + case OPAE_FPGA_PCI: + d_pci = (struct opae_adapter_data_pci *)d; + + opae_log("OPAE Adapter Type = PCI\n"); + opae_log("PCI Device ID: 0x%04x\n", d_pci->device_id); + opae_log("PCI Vendor ID: 0x%04x\n", d_pci->vendor_id); + + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + r = &d_pci->region[i]; + opae_log("PCI Bar %d: phy(%llx) len(%llx) addr(%p)\n", + i, (unsigned long long)r->phys_addr, + (unsigned long long)r->len, r->addr); + } + break; + case OPAE_FPGA_NET: + break; + } + + opae_log("==========================\n"); +} + +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) { + if (adapter->mgr) + opae_manager_dump(adapter->mgr); + + opae_adapter_for_each_acc(adapter, acc) + opae_accelerator_dump(acc); + + if (adapter->data) + opae_adapter_data_dump(adapter->data); + } + + opae_log("==========================\n"); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.h b/drivers/raw/ifpga_rawdev/base/opae_debug.h new file mode 100644 index 0000000..a03dff9 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_DEBUG_H_ +#define _OPAE_DEBUG_H_ + +#ifdef OPAE_HW_DEBUG +#define opae_log(fmt, args...) printf(fmt, ## args) +#else +#define opae_log(fme, args...) do {} while (0) +#endif + +void opae_manager_dump(struct opae_manager *mgr); +void opae_bridge_dump(struct opae_bridge *br); +void opae_accelerator_dump(struct opae_accelerator *acc); +void opae_adapter_dump(struct opae_adapter *adapter, int verbose); + +#endif /* _OPAE_DEBUG_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c new file mode 100644 index 0000000..a533dfe --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -0,0 +1,381 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_hw_api.h" +#include "opae_debug.h" +#include "ifpga_api.h" + +/* OPAE Bridge Functions */ + +/** + * opae_bridge_alloc - alloc opae_bridge data structure + * @name: bridge name. + * @ops: ops of this bridge. + * @data: private data of this bridge. + * + * Return opae_bridge on success, otherwise NULL. + */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data) +{ + struct opae_bridge *br = opae_zmalloc(sizeof(*br)); + + if (!br) + return NULL; + + br->name = name; + br->ops = ops; + br->data = data; + + opae_log("%s %p\n", __func__, br); + + return br; +} + +/** + * opae_bridge_reset - reset opae_bridge + * @br: bridge to be reset. + * + * Return: 0 on success, otherwise error code. + */ +int opae_bridge_reset(struct opae_bridge *br) +{ + if (!br) + return -EINVAL; + + if (br->ops && br->ops->reset) + return br->ops->reset(br); + + opae_log("%s no ops\n", __func__); + + return -ENOENT; +} + +/* Accelerator Functions */ + +/** + * opae_accelerator_alloc - alloc opae_accelerator data structure + * @name: accelerator name. + * @ops: ops of this accelerator. + * @data: private data of this accelerator. + * + * Return: opae_accelerator on success, otherwise NULL. + */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data) +{ + struct opae_accelerator *acc = opae_zmalloc(sizeof(*acc)); + + if (!acc) + return NULL; + + acc->name = name; + acc->ops = ops; + acc->data = data; + + opae_log("%s %p\n", __func__, acc); + + return acc; +} + +/** + * opae_acc_reg_read - read accelerator's register from its reg region. + * @acc: accelerator to read. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: read operation width, e.g 4 byte = 32bit read. + * @data: data to store the value read from the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->read) + return acc->ops->read(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_reg_write - write to accelerator's register from its reg region. + * @acc: accelerator to write. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: write operation width, e.g 4 byte = 32bit write. + * @data: data stored the value to write to the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->write) + return acc->ops->write(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_get_info - get information of an accelerator. + * @acc: targeted accelerator + * @info: accelerator info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_info) + return acc->ops->get_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_get_region_info - get information of an accelerator register region. + * @acc: targeted accelerator + * @info: accelerator region info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_region_info) + return acc->ops->get_region_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_set_irq - set an accelerator's irq. + * @acc: targeted accelerator + * @start: start vector number + * @count: count of vectors to be set from the start vector + * @evtfds: event fds to be notified when corresponding irqs happens + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + if (!acc || !acc->data) + return -EINVAL; + + if (start + count <= start) + return -EINVAL; + + if (acc->ops && acc->ops->set_irq) + return acc->ops->set_irq(acc, start, count, evtfds); + + return -ENOENT; +} + +/** + * opae_acc_get_uuid - get accelerator's UUID. + * @acc: targeted accelerator + * @uuid: a pointer to UUID + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + if (!acc || !uuid) + return -EINVAL; + + if (acc->ops && acc->ops->get_uuid) + return acc->ops->get_uuid(acc, uuid); + + return -ENOENT; +} + +/* Manager Functions */ + +/** + * opae_manager_alloc - alloc opae_manager data structure + * @name: manager name. + * @ops: ops of this manager. + * @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) +{ + struct opae_manager *mgr = opae_zmalloc(sizeof(*mgr)); + + if (!mgr) + return NULL; + + mgr->name = name; + mgr->ops = ops; + mgr->data = data; + + opae_log("%s %p\n", __func__, mgr); + + return mgr; +} + +/** + * opae_manager_flash - flash a reconfiguration image via opae_manager + * @mgr: opae_manager for flash. + * @id: id of target region (accelerator). + * @buf: image data buffer. + * @size: buffer size. + * @status: status to store flash result. + * + * Return: 0 on success, otherwise error code. + */ +int opae_manager_flash(struct opae_manager *mgr, int id, void *buf, u32 size, + u64 *status) +{ + if (!mgr) + return -EINVAL; + + if (mgr && mgr->ops && mgr->ops->flash) + return mgr->ops->flash(mgr, id, buf, size, status); + + return -ENOENT; +} + +/* Adapter Functions */ + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @type: opae_adapter_type. + * + * Return: opae_adapter_data on success, otherwise NULL. + */ +void *opae_adapter_data_alloc(enum opae_adapter_type type) +{ + struct opae_adapter_data *data; + int size; + + switch (type) { + case OPAE_FPGA_PCI: + size = sizeof(struct opae_adapter_data_pci); + break; + case OPAE_FPGA_NET: + size = sizeof(struct opae_adapter_data_net); + break; + default: + size = sizeof(struct opae_adapter_data); + break; + } + + data = opae_zmalloc(size); + if (!data) + return NULL; + + data->type = type; + + return data; +} + +static struct opae_adapter_ops *match_ops(struct opae_adapter *adapter) +{ + struct opae_adapter_data *data; + + if (!adapter || !adapter->data) + return NULL; + + data = adapter->data; + + if (data->type == OPAE_FPGA_PCI) + return &ifpga_adapter_ops; + + return NULL; +} + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @name: adapter name. + * @data: private data of this adapter. + * + * Return: opae_adapter on success, otherwise NULL. + */ +struct opae_adapter *opae_adapter_alloc(const char *name, void *data) +{ + struct opae_adapter *adapter = opae_zmalloc(sizeof(*adapter)); + + if (!adapter) + return NULL; + + TAILQ_INIT(&adapter->acc_list); + adapter->data = data; + adapter->name = name; + adapter->ops = match_ops(adapter); + + return adapter; +} + +/** + * opae_adapter_enumerate - enumerate this adapter + * @adapter: adapter to enumerate. + * + * Return: 0 on success, otherwise error code. + */ +int opae_adapter_enumerate(struct opae_adapter *adapter) +{ + int ret = -ENOENT; + + if (!adapter) + return -EINVAL; + + if (adapter->ops && adapter->ops->enumerate) + ret = adapter->ops->enumerate(adapter); + + if (!ret) + opae_adapter_dump(adapter, 1); + + return ret; +} + +/** + * opae_adapter_destroy - destroy this adapter + * @adapter: adapter to destroy. + * + * destroy things allocated during adapter enumeration. + */ +void opae_adapter_destroy(struct opae_adapter *adapter) +{ + if (adapter && adapter->ops && adapter->ops->destroy) + adapter->ops->destroy(adapter); +} + +/** + * opae_adapter_get_acc - find and return accelerator with matched id + * @adapter: adapter to find the accelerator. + * @acc_id: id (index) of the accelerator. + * + * destroy things allocated during adapter enumeration. + */ +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id) +{ + struct opae_accelerator *acc = NULL; + + if (!adapter) + return NULL; + + opae_adapter_for_each_acc(adapter, acc) + if (acc->index == acc_id) + return acc; + + return NULL; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h new file mode 100644 index 0000000..4bbc9df --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_HW_API_H_ +#define _OPAE_HW_API_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> + +#include "opae_osdep.h" + +#ifndef PCI_MAX_RESOURCE +#define PCI_MAX_RESOURCE 6 +#endif + +struct opae_adapter; + +enum opae_adapter_type { + OPAE_FPGA_PCI, + OPAE_FPGA_NET, +}; + +/* OPAE Manager Data Structure */ +struct opae_manager_ops; + +/* + * opae_manager has pointer to its parent adapter, as it could be able to manage + * all components on this FPGA device (adapter). If not the case, don't set this + * adapter, which limit opae_manager ops to manager itself. + */ +struct opae_manager { + const char *name; + struct opae_adapter *adapter; + struct opae_manager_ops *ops; + void *data; +}; + +/* FIXME: add more management ops, e.g power/thermal and etc */ +struct opae_manager_ops { + int (*flash)(struct opae_manager *mgr, int id, void *buffer, + u32 size, u64 *status); +}; + +/* OPAE Manager APIs */ +struct opae_manager * +opae_manager_alloc(const char *name, struct opae_manager_ops *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); + +/* OPAE Bridge Data Structure */ +struct opae_bridge_ops; + +/* + * opae_bridge only has pointer to its downstream accelerator. + */ +struct opae_bridge { + const char *name; + int id; + struct opae_accelerator *acc; + struct opae_bridge_ops *ops; + void *data; +}; + +struct opae_bridge_ops { + int (*reset)(struct opae_bridge *br); +}; + +/* OPAE Bridge APIs */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data); +int opae_bridge_reset(struct opae_bridge *br); +#define opae_bridge_free(br) opae_free(br) + +/* OPAE Acceleraotr Data Structure */ +struct opae_accelerator_ops; + +/* + * opae_accelerator has pointer to its upstream bridge(port). + * In some cases, if we allow same user to do PR on its own accelerator, then + * set the manager pointer during the enumeration. But in other cases, the PR + * functions only could be done via manager in another module / thread / service + * / application for better protection. + */ +struct opae_accelerator { + TAILQ_ENTRY(opae_accelerator) node; + const char *name; + int index; + struct opae_bridge *br; + struct opae_manager *mgr; + struct opae_accelerator_ops *ops; + void *data; +}; + +struct opae_acc_info { + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct opae_acc_region_info { + u32 flags; +#define ACC_REGION_READ (1 << 0) +#define ACC_REGION_WRITE (1 << 1) +#define ACC_REGION_MMIO (1 << 2) + u32 index; + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_accelerator_ops { + int (*read)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*write)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*get_info)(struct opae_accelerator *acc, + struct opae_acc_info *info); + int (*get_region_info)(struct opae_accelerator *acc, + struct opae_acc_region_info *info); + int (*set_irq)(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); + int (*get_uuid)(struct opae_accelerator *acc, + struct uuid *uuid); +}; + +/* OPAE accelerator APIs */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data); +#define opae_accelerator_free(acc) opae_free(acc) +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info); +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info); +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid); + +static inline struct opae_bridge * +opae_acc_get_br(struct opae_accelerator *acc) +{ + return acc ? acc->br : NULL; +} + +static inline struct opae_manager * +opae_acc_get_mgr(struct opae_accelerator *acc) +{ + return acc ? acc->mgr : NULL; +} + +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + +#define opae_acc_reg_read64(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 8, data) +#define opae_acc_reg_write64(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 8, data) +#define opae_acc_reg_read32(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 4, data) +#define opae_acc_reg_write32(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 4, data) +#define opae_acc_reg_read16(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 2, data) +#define opae_acc_reg_write16(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 2, data) +#define opae_acc_reg_read8(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 1, data) +#define opae_acc_reg_write8(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 1, data) + +/*for data stream read/write*/ +int opae_acc_data_read(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); +int opae_acc_data_write(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); + +/* OPAE Adapter Data Structure */ +struct opae_adapter_data { + enum opae_adapter_type type; +}; + +struct opae_reg_region { + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_adapter_data_pci { + enum opae_adapter_type type; + u16 device_id; + u16 vendor_id; + struct opae_reg_region region[PCI_MAX_RESOURCE]; + int vfio_dev_fd; /* VFIO device file descriptor */ +}; + +/* FIXME: OPAE_FPGA_NET type */ +struct opae_adapter_data_net { + enum opae_adapter_type type; +}; + +struct opae_adapter_ops { + int (*enumerate)(struct opae_adapter *adapter); + void (*destroy)(struct opae_adapter *adapter); +}; + +TAILQ_HEAD(opae_accelerator_list, opae_accelerator); + +#define opae_adapter_for_each_acc(adatper, acc) \ + TAILQ_FOREACH(acc, &adapter->acc_list, node) + +struct opae_adapter { + const char *name; + struct opae_manager *mgr; + struct opae_accelerator_list acc_list; + struct opae_adapter_ops *ops; + void *data; +}; + +/* OPAE Adapter APIs */ +void *opae_adapter_data_alloc(enum opae_adapter_type type); +#define opae_adapter_data_free(data) opae_free(data) + +struct opae_adapter *opae_adapter_alloc(const char *name, void *data); +#define opae_adapter_free(adapter) opae_free(adapter) + +int opae_adapter_enumerate(struct opae_adapter *adapter); +void opae_adapter_destroy(struct opae_adapter *adapter); +static inline struct opae_manager * +opae_adapter_get_mgr(struct opae_adapter *adapter) +{ + return adapter ? adapter->mgr : NULL; +} + +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id); + +static inline void opae_adapter_add_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_INSERT_TAIL(&adapter->acc_list, acc, node); +} + +static inline void opae_adapter_remove_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_REMOVE(&adapter->acc_list, acc, node); +} +#endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c new file mode 100644 index 0000000..a40c8da --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_ifpga_hw_api.h" +#include "ifpga_api.h" + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data || !fme_info) + return -EINVAL; + + fme = mgr->data; + + spinlock_lock(&fme->lock); + fme_info->capability = fme->capability; + spinlock_unlock(&fme->lock); + + return 0; +} + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_irq(fme->parent, FEATURE_FIU_ID_FME, 0, + IFPGA_FME_FEATURE_ID_GLOBAL_ERR, err_irq_set); +} + +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_get_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !port_info) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + port_info->capability = port->capability; + port_info->num_uafu_irqs = port->num_uafu_irqs; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !info) + return -EINVAL; + + /* Only support STP region now */ + if (info->index != PORT_REGION_INDEX_STP) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + info->addr = (u64)port->stp_addr; + info->size = port->stp_size; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_ERROR, err_irq_set); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h new file mode 100644 index 0000000..65086cf --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_IFPGA_HW_API_H_ +#define _OPAE_IFPGA_HW_API_H_ + +#include "opae_hw_api.h" + +/** + * struct feature_prop - data structure for feature property + * @feature_id: id of this feature. + * @prop_id: id of this property under this feature. + * @data: property value to set/get. + */ +struct feature_prop { + u64 feature_id; + u64 prop_id; + u64 data; +}; + +#define IFPGA_FIU_ID_FME 0x0 +#define IFPGA_FIU_ID_PORT 0x1 + +#define IFPGA_FME_FEATURE_ID_HEADER 0x0 +#define IFPGA_FME_FEATURE_ID_THERMAL_MGMT 0x1 +#define IFPGA_FME_FEATURE_ID_POWER_MGMT 0x2 +#define IFPGA_FME_FEATURE_ID_GLOBAL_IPERF 0x3 +#define IFPGA_FME_FEATURE_ID_GLOBAL_ERR 0x4 +#define IFPGA_FME_FEATURE_ID_PR_MGMT 0x5 +#define IFPGA_FME_FEATURE_ID_HSSI 0x6 +#define IFPGA_FME_FEATURE_ID_GLOBAL_DPERF 0x7 + +#define IFPGA_PORT_FEATURE_ID_HEADER 0x0 +#define IFPGA_PORT_FEATURE_ID_AFU 0xff +#define IFPGA_PORT_FEATURE_ID_ERROR 0x10 +#define IFPGA_PORT_FEATURE_ID_UMSG 0x11 +#define IFPGA_PORT_FEATURE_ID_UINT 0x12 +#define IFPGA_PORT_FEATURE_ID_STP 0x13 + +/* + * PROP format (TOP + SUB + ID) + * + * (~0x0) means this field is unused. + */ +#define PROP_TOP GENMASK(31, 24) +#define PROP_TOP_UNUSED 0xff +#define PROP_SUB GENMASK(23, 16) +#define PROP_SUB_UNUSED 0xff +#define PROP_ID GENMASK(15, 0) + +#define PROP(_top, _sub, _id) \ + (SET_FIELD(PROP_TOP, _top) | SET_FIELD(PROP_SUB, _sub) |\ + SET_FIELD(PROP_ID, _id)) + +/* FME head feature's properties*/ +#define FME_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define FME_HDR_PROP_PORTS_NUM 0x2 /* RDONLY */ +#define FME_HDR_PROP_CACHE_SIZE 0x3 /* RDONLY */ +#define FME_HDR_PROP_VERSION 0x4 /* RDONLY */ +#define FME_HDR_PROP_SOCKET_ID 0x5 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_ID 0x6 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_METADATA 0x7 /* RDONLY */ + +/* FME error reporting feature's properties */ +/* FME error reporting properties format */ +#define ERR_PROP(_top, _id) PROP(_top, 0xff, _id) +#define ERR_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define ERR_PROP_TOP_FME_ERR 0x1 +#define ERR_PROP_ROOT(_id) ERR_PROP(0xff, _id) +#define ERR_PROP_FME_ERR(_id) ERR_PROP(ERR_PROP_TOP_FME_ERR, _id) + +#define FME_ERR_PROP_ERRORS ERR_PROP_FME_ERR(0x1) +#define FME_ERR_PROP_FIRST_ERROR ERR_PROP_FME_ERR(0x2) +#define FME_ERR_PROP_NEXT_ERROR ERR_PROP_FME_ERR(0x3) +#define FME_ERR_PROP_CLEAR ERR_PROP_FME_ERR(0x4) /* WO */ +#define FME_ERR_PROP_REVISION ERR_PROP_ROOT(0x5) +#define FME_ERR_PROP_PCIE0_ERRORS ERR_PROP_ROOT(0x6) /* RW */ +#define FME_ERR_PROP_PCIE1_ERRORS ERR_PROP_ROOT(0x7) /* RW */ +#define FME_ERR_PROP_NONFATAL_ERRORS ERR_PROP_ROOT(0x8) +#define FME_ERR_PROP_CATFATAL_ERRORS ERR_PROP_ROOT(0x9) +#define FME_ERR_PROP_INJECT_ERRORS ERR_PROP_ROOT(0xa) /* RW */ + +/* FME thermal feature's properties */ +#define FME_THERMAL_PROP_THRESHOLD1 0x1 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD2 0x2 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD_TRIP 0x3 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_REACHED 0x4 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD2_REACHED 0x5 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_POLICY 0x6 /* RW */ +#define FME_THERMAL_PROP_TEMPERATURE 0x7 /* RDONLY */ +#define FME_THERMAL_PROP_REVISION 0x8 /* RDONLY */ + +/* FME power feature's properties */ +#define FME_PWR_PROP_CONSUMED 0x1 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD1 0x2 /* RW */ +#define FME_PWR_PROP_THRESHOLD2 0x3 /* RW */ +#define FME_PWR_PROP_THRESHOLD1_STATUS 0x4 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD2_STATUS 0x5 /* RDONLY */ +#define FME_PWR_PROP_RTL 0x6 /* RDONLY */ +#define FME_PWR_PROP_XEON_LIMIT 0x7 /* RDONLY */ +#define FME_PWR_PROP_FPGA_LIMIT 0x8 /* RDONLY */ +#define FME_PWR_PROP_REVISION 0x9 /* RDONLY */ + +/* FME iperf/dperf PROP format */ +#define PERF_PROP_TOP_CACHE 0x1 +#define PERF_PROP_TOP_VTD 0x2 +#define PERF_PROP_TOP_FAB 0x3 +#define PERF_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define PERF_PROP_SUB_UNUSED PROP_SUB_UNUSED + +#define PERF_PROP_ROOT(_id) PROP(0xff, 0xff, _id) +#define PERF_PROP_CACHE(_id) PROP(PERF_PROP_TOP_CACHE, 0xff, _id) +#define PERF_PROP_VTD(_sub, _id) PROP(PERF_PROP_TOP_VTD, _sub, _id) +#define PERF_PROP_VTD_ROOT(_id) PROP(PERF_PROP_TOP_VTD, 0xff, _id) +#define PERF_PROP_FAB(_sub, _id) PROP(PERF_PROP_TOP_FAB, _sub, _id) +#define PERF_PROP_FAB_ROOT(_id) PROP(PERF_PROP_TOP_FAB, 0xff, _id) + +/* FME iperf feature's properties */ +#define FME_IPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_IPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* iperf CACHE properties */ +#define FME_IPERF_PROP_CACHE_FREEZE PERF_PROP_CACHE(0x1) /* RW */ +#define FME_IPERF_PROP_CACHE_READ_HIT PERF_PROP_CACHE(0x2) +#define FME_IPERF_PROP_CACHE_READ_MISS PERF_PROP_CACHE(0x3) +#define FME_IPERF_PROP_CACHE_WRITE_HIT PERF_PROP_CACHE(0x4) +#define FME_IPERF_PROP_CACHE_WRITE_MISS PERF_PROP_CACHE(0x5) +#define FME_IPERF_PROP_CACHE_HOLD_REQUEST PERF_PROP_CACHE(0x6) +#define FME_IPERF_PROP_CACHE_TX_REQ_STALL PERF_PROP_CACHE(0x7) +#define FME_IPERF_PROP_CACHE_RX_REQ_STALL PERF_PROP_CACHE(0x8) +#define FME_IPERF_PROP_CACHE_RX_EVICTION PERF_PROP_CACHE(0x9) +#define FME_IPERF_PROP_CACHE_DATA_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xa) +#define FME_IPERF_PROP_CACHE_TAG_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xb) +/* iperf VTD properties */ +#define FME_IPERF_PROP_VTD_FREEZE PERF_PROP_VTD_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_HIT PERF_PROP_VTD_ROOT(0x2) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_HIT PERF_PROP_VTD_ROOT(0x3) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_HIT PERF_PROP_VTD_ROOT(0x4) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_HIT PERF_PROP_VTD_ROOT(0x5) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_HIT PERF_PROP_VTD_ROOT(0x6) +#define FME_IPERF_PROP_VTD_SIP_RCC_HIT PERF_PROP_VTD_ROOT(0x7) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_MISS PERF_PROP_VTD_ROOT(0x8) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_MISS PERF_PROP_VTD_ROOT(0x9) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_MISS PERF_PROP_VTD_ROOT(0xa) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_MISS PERF_PROP_VTD_ROOT(0xb) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_MISS PERF_PROP_VTD_ROOT(0xc) +#define FME_IPERF_PROP_VTD_SIP_RCC_MISS PERF_PROP_VTD_ROOT(0xd) +#define FME_IPERF_PROP_VTD_PORT_READ_TRANSACTION(n) PERF_PROP_VTD(n, 0xe) +#define FME_IPERF_PROP_VTD_PORT_WRITE_TRANSACTION(n) PERF_PROP_VTD(n, 0xf) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_READ_HIT(n) PERF_PROP_VTD(n, 0x10) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_WRITE_HIT(n) PERF_PROP_VTD(n, 0x11) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_4K_FILL(n) PERF_PROP_VTD(n, 0x12) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_2M_FILL(n) PERF_PROP_VTD(n, 0x13) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_1G_FILL(n) PERF_PROP_VTD(n, 0x14) +/* iperf FAB properties */ +#define FME_IPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_IPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_IPERF_PROP_FAB_PCIE1_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_IPERF_PROP_FAB_PCIE1_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_IPERF_PROP_FAB_UPI_READ PERF_PROP_FAB_ROOT(0x6) +#define FME_IPERF_PROP_FAB_PORT_UPI_READ(n) PERF_PROP_FAB(n, 0x6) +#define FME_IPERF_PROP_FAB_UPI_WRITE PERF_PROP_FAB_ROOT(0x7) +#define FME_IPERF_PROP_FAB_PORT_UPI_WRITE(n) PERF_PROP_FAB(n, 0x7) +#define FME_IPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x8) +#define FME_IPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x8) +#define FME_IPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x9) +#define FME_IPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x9) +#define FME_IPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0xa) /* RW */ +#define FME_IPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0xa) /* RW */ + +/* FME dperf properties */ +#define FME_DPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_DPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* dperf FAB properties */ +#define FME_DPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_DPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_DPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_DPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_DPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_DPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_DPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_DPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0x6) /* RW */ +#define FME_DPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0x6) /* RW */ + +/*PORT hdr feature's properties*/ +#define PORT_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_HDR_PROP_PORTIDX 0x2 /* RDONLY */ +#define PORT_HDR_PROP_LATENCY_TOLERANCE 0x3 /* RDONLY */ +#define PORT_HDR_PROP_AP1_EVENT 0x4 /* RW */ +#define PORT_HDR_PROP_AP2_EVENT 0x5 /* RW */ +#define PORT_HDR_PROP_POWER_STATE 0x6 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_FREQCMD 0x7 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQCNTRCMD 0x8 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQSTS 0x9 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_CNTRSTS 0xa /* RDONLY */ + +/*PORT error feature's properties*/ +#define PORT_ERR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_ERR_PROP_ERRORS 0x2 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_ERROR 0x3 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB 0x4 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB 0x5 /* RDONLY */ +#define PORT_ERR_PROP_CLEAR 0x6 /* WRONLY */ + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop); +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop); + +/* + * Retrieve information about the fpga fme. + * Driver fills the info in provided struct fpga_fme_info. + */ +struct fpga_fme_info { + u32 capability; /* The capability of FME device */ +#define FPGA_FME_CAP_ERR_IRQ (1 << 0) /* Support fme error interrupt */ +}; + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info); + +/* Set eventfd information for ifpga FME error interrupt */ +struct fpga_fme_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set); + +/* + * Retrieve information about the fpga port. + * Driver fills the info in provided struct fpga_port_info. + */ +struct fpga_port_info { + u32 capability; /* The capability of port device */ +#define FPGA_PORT_CAP_ERR_IRQ (1 << 0) /* Support port error interrupt */ +#define FPGA_PORT_CAP_UAFU_IRQ (1 << 1) /* Support uafu error interrupt */ + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ +}; + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info); +/* + * Retrieve region information about the fpga port. + * Driver needs to fill the index of struct fpga_port_region_info. + */ +struct fpga_port_region_info { + u32 index; +#define PORT_REGION_INDEX_STP (1 << 1) /* Signal Tap Region */ + u64 size; /* Region Size */ + u64 addr; /* Base address of the region */ +}; + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info); + +/* Set eventfd information for ifpga port error interrupt */ +struct fpga_port_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set); + +#endif /* _OPAE_IFPGA_HW_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h new file mode 100644 index 0000000..e9da710 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_OSDEP_H +#define _OPAE_OSDEP_H + +#include <string.h> +#include <stdbool.h> + +#ifdef RTE_LIBRTE_EAL +#include "osdep_rte/osdep_generic.h" +#else +#include "osdep_raw/osdep_generic.h" +#endif + +#include <asm/types.h> + +#define __iomem + +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef uint64_t dma_addr_t; + +struct uuid { + u8 b[16]; +}; + +#ifndef LINUX_MACROS +#ifndef BITS_PER_LONG +#define BITS_PER_LONG (__SIZEOF_LONG__ * 8) +#endif +#ifndef BIT +#define BIT(a) (1UL << (a)) +#endif /* BIT */ +#ifndef BIT_ULL +#define BIT_ULL(a) (1ULL << (a)) +#endif /* BIT_ULL */ +#ifndef GENMASK +#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#endif /* GENMASK */ +#ifndef GENMASK_ULL +#define GENMASK_ULL(h, l) (((U64_C(1) << ((h) - (l) + 1)) - 1) << (l)) +#endif /* GENMASK_ULL */ +#endif /* LINUX_MACROS */ + +#define SET_FIELD(m, v) (((v) << (__builtin_ffsll(m) - 1)) & (m)) +#define GET_FIELD(m, v) (((v) & (m)) >> (__builtin_ffsll(m) - 1)) + +#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) +#define pr_info(y, args...) dev_info(0, y, ##args) + +#ifndef WARN_ON +#define WARN_ON(x) do { \ + int ret = !!(x); \ + if (unlikely(ret)) \ + pr_warn("WARN_ON: \"" #x "\" at %s:%d\n", __func__, __LINE__); \ +} while (0) +#endif + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define udelay(x) opae_udelay(x) +#define msleep(x) opae_udelay(1000 * (x)) +#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000)) + +#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 new file mode 100644 index 0000000..895a1d8 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OSDEP_RAW_GENERIC_H +#define _OSDEP_RAW_GENERIC_H + +#define compiler_barrier() (asm volatile ("" : : : "memory")) + +#define io_wmb() compiler_barrier() +#define io_rmb() compiler_barrier() + +static inline uint8_t opae_readb(const volatile void *addr) +{ + uint8_t val; + + val = *(const volatile uint8_t *)addr; + io_rmb(); + return val; +} + +static inline uint16_t opae_readw(const volatile void *addr) +{ + uint16_t val; + + val = *(const volatile uint16_t *)addr; + io_rmb(); + return val; +} + +static inline uint32_t opae_readl(const volatile void *addr) +{ + uint32_t val; + + val = *(const volatile uint32_t *)addr; + io_rmb(); + return val; +} + +static inline uint64_t opae_readq(const volatile void *addr) +{ + uint64_t val; + + val = *(const volatile uint64_t *)addr; + io_rmb(); + return val; +} + +static inline void opae_writeb(uint8_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint8_t *)addr = value; +} + +static inline void opae_writew(uint16_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint16_t *)addr = value; +} + +static inline void opae_writel(uint32_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint32_t *)addr = value; +} + +static inline void opae_writeq(uint64_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint64_t *)addr = value; +} + +#define opae_free(addr) free(addr) + +#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 new file mode 100644 index 0000000..76902e2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OSDEP_RTE_GENERIC_H +#define _OSDEP_RTE_GENERIC_H + +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_spinlock.h> +#include <rte_log.h> +#include <rte_io.h> +#include <rte_malloc.h> + +#define dev_printf(level, fmt, args...) \ + RTE_LOG(level, PMD, "osdep_rte: " fmt, ## args) + +#define osdep_panic(...) rte_panic(...) + +#define opae_udelay(x) rte_delay_us(x) + +#define opae_readb(addr) rte_read8(addr) +#define opae_readw(addr) rte_read16(addr) +#define opae_readl(addr) rte_read32(addr) +#define opae_readq(addr) rte_read64(addr) +#define opae_writeb(value, addr) rte_write8(value, addr) +#define opae_writew(value, addr) rte_write16(value, addr) +#define opae_writel(value, addr) rte_write32(value, addr) +#define opae_writeq(value, addr) rte_write64(value, addr) + +#define opae_malloc(size) rte_malloc(NULL, size, 0) +#define opae_zmalloc(size) rte_zmalloc(NULL, size, 0) +#define opae_free(addr) rte_free(addr) + +#define ARRAY_SIZE(arr) RTE_DIM(arr) + +#define min(a, b) RTE_MIN(a, b) +#define max(a, b) RTE_MAX(a, b) + +#define spinlock_t rte_spinlock_t +#define spinlock_init(x) rte_spinlock_init(x) +#define spinlock_lock(x) rte_spinlock_lock(x) +#define spinlock_unlock(x) rte_spinlock_unlock(x) + +#endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 0/3] Introduce Intel FPGA BUS Xu, Rosen 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 2/3] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen @ 2018-05-09 7:43 ` Xu, Rosen 2018-05-09 14:47 ` Thomas Monjalon ` (2 more replies) 2 siblings, 3 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-09 7:43 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Yanglong Wu From: Rosen Xu <rosen.xu@intel.com> Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev library. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> --- MAINTAINERS | 3 + config/common_base | 5 + doc/guides/rawdevs/ifpga_rawdev.rst | 112 ++++ doc/guides/rawdevs/index.rst | 1 + doc/guides/rel_notes/release_18_05.rst | 8 + drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 ++ drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 608 +++++++++++++++++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ drivers/raw/ifpga_rawdev/meson.build | 15 + .../ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map | 4 + drivers/raw/meson.build | 2 +- mk/rte.app.mk | 4 +- 13 files changed, 834 insertions(+), 2 deletions(-) create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/meson.build create mode 100644 drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map diff --git a/MAINTAINERS b/MAINTAINERS index 9c27d5a..a93ce9f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -851,8 +851,11 @@ Rawdev Drivers -------------- Intel FPGA +M: Rosen Xu <rosen.xu@intel.com> M: Tianfei zhang <tianfei.zhang@intel.com> +F: drivers/raw/ifpga_rawdev/ F: drivers/raw/ifpga_rawdev/base/ +F: doc/guides/rawdevs/ifpga_rawdev.rst NXP DPAA2 QDMA M: Nipun Gupta <nipun.gupta@nxp.com> diff --git a/config/common_base b/config/common_base index 1440316..017a15a 100644 --- a/config/common_base +++ b/config/common_base @@ -633,6 +633,11 @@ CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV=n CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV=n # +# Compile PMD for Intel FPGA raw device +# +CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV=y + +# # Compile librte_ring # CONFIG_RTE_LIBRTE_RING=y diff --git a/doc/guides/rawdevs/ifpga_rawdev.rst b/doc/guides/rawdevs/ifpga_rawdev.rst new file mode 100644 index 0000000..37ae4cc --- /dev/null +++ b/doc/guides/rawdevs/ifpga_rawdev.rst @@ -0,0 +1,112 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2018 Intel Corporation. + +IFPGA Rawdev Driver +====================== + +FPGA is used more and more widely in Cloud and NFV, one primary reason is +that FPGA not only provides ASIC performance but also it's more flexible +than ASIC. + +FPGA uses Partial Reconfigure (PR) Parts of Bit Stream to achieve its +flexibility. That means one FPGA Device Bit Stream is divided into many Parts +of Bit Stream(each Part of Bit Stream is defined as AFU-Accelerated Function +Unit), and each AFU is a hardware acceleration unit which can be dynamically +reloaded respectively. + +By PR (Partial Reconfiguration) AFUs, one FPGA resources can be time-shared by +different users. FPGA hot upgrade and fault tolerance can be provided easily. + +The SW IFPGA Rawdev Driver (**ifpga_rawdev**) provides a Rawdev driver +that utilizes Intel FPGA Software Stack OPAE(Open Programmable Acceleration +Engine) for FPGA management. + +Implementation details +---------------------- + +Each instance of IFPGA Rawdev Driver is probed by Intel FpgaDev. In coordination +with OPAE share code IFPGA Rawdev Driver provides common FPGA management ops +for FPGA operation, OPAE provides all following operations: +- FPGA PR (Partial Reconfiguration) management +- FPGA AFUs Identifying +- FPGA Thermal Management +- FPGA Power Management +- FPGA Performance reporting +- FPGA Remote Debug + +All configuration parameters are taken by vdev_ifpga_cfg driver. Besides +configuration, vdev_ifpga_cfg driver also hot plugs in IFPGA Bus. + +All of the AFUs of one FPGA may share same PCI BDF and AFUs scan depend on +IFPGA Rawdev Driver so IFPGA Bus takes AFU device scan and AFU drivers probe. +All AFU device driver bind to AFU device by its UUID (Universally Unique +Identifier). + +To avoid unnecessary code duplication and ensure maximum performance, +handling of AFU devices is left to different PMDs; all the design as +summarized by the following block diagram:: + + +---------------------------------------------------------------+ + | Application(s) | + +----------------------------.----------------------------------+ + | + | + +----------------------------'----------------------------------+ + | DPDK Framework (APIs) | + +----------|------------|--------.---------------------|--------+ + / \ | + / \ | + +-------'-------+ +-------'-------+ +--------'--------+ + | Eth PMD | | Crypto PMD | | | + +-------.-------+ +-------.-------+ | | + | | | | + | | | | + +-------'-------+ +-------'-------+ | IFPGA | + | Eth AFU Dev | |Crypto AFU Dev | | Rawdev Driver | + +-------.-------+ +-------.-------+ |(OPAE Share Code)| + | | | | + | | Rawdev | | + +-------'------------------'-------+ Ops | | + | IFPGA Bus | -------->| | + +-----------------.----------------+ +--------.--------+ + | | + Hot-plugin -->| | + | | + +-----------------'------------------+ +--------'--------+ + | vdev_ifpga_cfg driver | | Intel FpgaDev | + +------------------------------------+ +-----------------+ + +Build options +------------- + +- ``CONFIG_RTE_LIBRTE_IFPGA_BUS`` (default ``y``) + + Toggle compilation of IFPGA Bus library. + +- ``CONFIG_RTE_LIBRTE_IFPGA_RAWDEV`` (default ``y``) + + Toggle compilation of the ``ifpga_rawdev`` driver. + +Run-time parameters +------------------- + +This driver is invoked automatically in systems added with Intel FPGA, +but PR and IFPGA Bus scan is trigged by command line using +``--vdev 'net_ifpga_cfg`` EAL option. + +The following device parameters are supported: + +- ``ifpga`` [string] + + Provide a specific Intel FPGA device PCI BDF. Can be provided multiple + times for additional instances. + +- ``port`` [int] + + Each FPGA can provide many channels to PR AFU by software, each channels + is identified by this parameter. + +- ``afu_bts`` [string] + + If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and + identifies AFU Bit Stream file. diff --git a/doc/guides/rawdevs/index.rst b/doc/guides/rawdevs/index.rst index 7769083..7c3bd95 100644 --- a/doc/guides/rawdevs/index.rst +++ b/doc/guides/rawdevs/index.rst @@ -13,3 +13,4 @@ application through rawdev API. dpaa2_cmdif dpaa2_qdma + ifpga_rawdev diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst index 265950a..f5241a1 100644 --- a/doc/guides/rel_notes/release_18_05.rst +++ b/doc/guides/rel_notes/release_18_05.rst @@ -189,6 +189,14 @@ New Features the DPDK framework. It provides Intel FPGA Partial Bit Stream AFU(Accelerated Function Unit) scan and drivers prove. +* **Added IFPGA(Intel FPGA) Rawdev Driver.** + + Added a new Rawdev driver called IFPGA(Intel FPGA) Rawdev Driver, which cooperates + with OPAE(Open Programmable Acceleration Engine) share code provides common FPGA + management ops for FPGA operation. + + See the :doc:`../rawdevs/ifpga_rawdev` programmer's guide for more details. + API Changes ----------- diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index 2eb2787..8e29b4a 100644 --- a/drivers/raw/Makefile +++ b/drivers/raw/Makefile @@ -9,5 +9,6 @@ ifeq ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += dpaa2_cmdif DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += dpaa2_qdma endif +DIRS-$(CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV) += ifpga_rawdev include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/raw/ifpga_rawdev/Makefile b/drivers/raw/ifpga_rawdev/Makefile new file mode 100644 index 0000000..f3b9d5e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/Makefile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_pmd_ifpga_rawdev.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_bus_vdev +LDLIBS += -lrte_kvargs +LDLIBS += -lrte_bus_pci +LDLIBS += -lrte_bus_ifpga + +EXPORT_MAP := rte_pmd_ifpga_rawdev_version.map + +LIBABIVER := 1 + +VPATH += $(SRCDIR)/base + +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV) += ifpga_rawdev.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c new file mode 100644 index 0000000..32e811c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c @@ -0,0 +1,608 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <rte_log.h> +#include <rte_bus.h> +#include <rte_eal_memconfig.h> +#include <rte_malloc.h> +#include <rte_devargs.h> +#include <rte_memcpy.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include <rte_errno.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> +#include <rte_bus_vdev.h> + +#include "base/opae_hw_api.h" +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_common.h" +#include "ifpga_logs.h" +#include "ifpga_rawdev.h" + +int ifpga_rawdev_logtype; + +#define PCI_VENDOR_ID_INTEL 0x8086 +/* PCI Device ID */ +#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 +/* 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 RTE_MAX_RAW_DEVICE 10 + +static const struct rte_pci_id pci_ifpga_map[] = { + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_6_X) }, + { 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) }, + { .vendor_id = 0, /* sentinel */ }, +}; + +static int +ifpga_fill_afu_dev(struct opae_accelerator *acc, + struct rte_afu_device *afu_dev) +{ + struct rte_mem_resource *res = afu_dev->mem_resource; + struct opae_acc_region_info region_info; + struct opae_acc_info info; + unsigned long i; + int ret; + + ret = opae_acc_get_info(acc, &info); + if (ret) + return ret; + + if (info.num_regions > PCI_MAX_RESOURCE) + return -EFAULT; + + afu_dev->num_region = info.num_regions; + + for (i = 0; i < info.num_regions; i++) { + region_info.index = i; + ret = opae_acc_get_region_info(acc, ®ion_info); + if (ret) + return ret; + + if ((region_info.flags & ACC_REGION_MMIO) && + (region_info.flags & ACC_REGION_READ) && + (region_info.flags & ACC_REGION_WRITE)) { + res[i].phys_addr = region_info.phys_addr; + res[i].len = region_info.len; + res[i].addr = region_info.addr; + } else + return -EFAULT; + } + + return 0; +} + +static void +ifpga_rawdev_info_get(struct rte_rawdev *dev, + rte_rawdev_obj_t dev_info) +{ + struct opae_adapter *adapter; + struct opae_accelerator *acc; + struct rte_afu_device *afu_dev; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + if (!dev_info) { + IFPGA_RAWDEV_PMD_ERR("Invalid request"); + return; + } + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return; + + afu_dev = dev_info; + afu_dev->rawdev = dev; + + /* find opae_accelerator and fill info into afu_device */ + opae_adapter_for_each_acc(adapter, acc) { + if (acc->index != afu_dev->id.port) + continue; + + if (ifpga_fill_afu_dev(acc, afu_dev)) { + IFPGA_RAWDEV_PMD_ERR("cannot get info\n"); + return; + } + } +} + +static int +ifpga_rawdev_start(struct rte_rawdev *dev) +{ + int ret = 0; + struct opae_adapter *adapter; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + return ret; +} + +static void +ifpga_rawdev_stop(struct rte_rawdev *dev) +{ + dev->started = 0; +} + +static int +ifpga_rawdev_close(struct rte_rawdev *dev) +{ + return dev ? 0:1; +} + +static int +ifpga_rawdev_reset(struct rte_rawdev *dev) +{ + return dev ? 0:1; +} + +static int +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, + u64 *status) +{ + + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_accelerator *acc; + struct opae_bridge *br; + int ret; + + adapter = ifpga_rawdev_get_priv(raw_dev); + if (!adapter) + return -ENODEV; + + mgr = opae_adapter_get_mgr(adapter); + if (!mgr) + return -ENODEV; + + acc = opae_adapter_get_acc(adapter, port_id); + if (!acc) + return -ENODEV; + + br = opae_acc_get_br(acc); + if (!br) + return -ENODEV; + + ret = opae_manager_flash(mgr, port_id, buffer, size, status); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("%s pr error %d\n", __func__, ret); + return ret; + } + + ret = opae_bridge_reset(br); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("%s reset port:%d error %d\n", + __func__, port_id, ret); + return ret; + } + + return ret; +} + +static int +rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, + const char *file_name) +{ + struct stat file_stat; + int file_fd; + int ret = 0; + u32 buffer_size; + void *buffer; + u64 pr_error; + + if (!file_name) + return -EINVAL; + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + IFPGA_RAWDEV_PMD_ERR("%s: open file error: %s\n", + __func__, file_name); + IFPGA_RAWDEV_PMD_ERR("Message : %s\n", strerror(errno)); + return -EINVAL; + } + ret = stat(file_name, &file_stat); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("stat on bitstream file failed: %s\n", + file_name); + return -EINVAL; + } + buffer_size = file_stat.st_size; + IFPGA_RAWDEV_PMD_INFO("bitstream file size: %u\n", buffer_size); + buffer = rte_malloc(NULL, buffer_size, 0); + if (!buffer) { + ret = -ENOMEM; + goto close_fd; + } + + /*read the raw data*/ + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { + ret = -EINVAL; + goto free_buffer; + } + + /*do PR now*/ + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); + IFPGA_RAWDEV_PMD_INFO("downloading to device port %d....%s.\n", port_id, + ret ? "failed" : "success"); + if (ret) { + ret = -EINVAL; + goto free_buffer; + } + +free_buffer: + if (buffer) + rte_free(buffer); +close_fd: + close(file_fd); + file_fd = 0; + return ret; +} + +static int +ifpga_rawdev_pr(struct rte_rawdev *dev, + rte_rawdev_obj_t pr_conf) +{ + struct opae_adapter *adapter; + struct rte_afu_pr_conf *afu_pr_conf; + int ret; + struct uuid uuid; + struct opae_accelerator *acc; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + if (!pr_conf) + return -EINVAL; + + afu_pr_conf = pr_conf; + + if (afu_pr_conf->pr_enable) { + ret = rte_fpga_do_pr(dev, + afu_pr_conf->afu_id.port, + afu_pr_conf->bs_path); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("do pr error %d\n", ret); + return ret; + } + } + + acc = opae_adapter_get_acc(adapter, afu_pr_conf->afu_id.port); + if (!acc) + return -ENODEV; + + ret = opae_acc_get_uuid(acc, &uuid); + if (ret) + return ret; + + memcpy(&afu_pr_conf->afu_id.uuid.uuid_low, uuid.b, sizeof(u64)); + memcpy(&afu_pr_conf->afu_id.uuid.uuid_high, uuid.b + 8, sizeof(u64)); + + IFPGA_RAWDEV_PMD_INFO("%s: uuid_l=0x%lx, uuid_h=0x%lx\n", __func__, + (u64)afu_pr_conf->afu_id.uuid.uuid_low, + (u64)afu_pr_conf->afu_id.uuid.uuid_high); + + return 0; +} + +static const struct rte_rawdev_ops ifpga_rawdev_ops = { + .dev_info_get = ifpga_rawdev_info_get, + .dev_configure = NULL, + .dev_start = ifpga_rawdev_start, + .dev_stop = ifpga_rawdev_stop, + .dev_close = ifpga_rawdev_close, + .dev_reset = ifpga_rawdev_reset, + + .queue_def_conf = NULL, + .queue_setup = NULL, + .queue_release = NULL, + + .attr_get = NULL, + .attr_set = NULL, + + .enqueue_bufs = NULL, + .dequeue_bufs = NULL, + + .dump = NULL, + + .xstats_get = NULL, + .xstats_get_names = NULL, + .xstats_get_by_name = NULL, + .xstats_reset = NULL, + + .firmware_status_get = NULL, + .firmware_version_get = NULL, + .firmware_load = ifpga_rawdev_pr, + .firmware_unload = NULL, + + .dev_selftest = NULL, +}; + +static int +ifpga_rawdev_create(struct rte_pci_device *pci_dev, + int socket_id) +{ + int ret = 0; + struct rte_rawdev *rawdev = NULL; + struct opae_adapter *adapter = NULL; + struct opae_manager *mgr = NULL; + struct opae_adapter_data_pci *data = NULL; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + int i; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + goto cleanup; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id()); + + /* Allocate device structure */ + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct opae_adapter), + socket_id); + if (rawdev == NULL) { + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); + ret = -EINVAL; + goto cleanup; + } + + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API */ + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); + if (!data) { + ret = -ENOMEM; + goto cleanup; + } + + /* init opae_adapter_data_pci for device specific information */ + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + data->region[i].phys_addr = pci_dev->mem_resource[i].phys_addr; + data->region[i].len = pci_dev->mem_resource[i].len; + data->region[i].addr = pci_dev->mem_resource[i].addr; + } + data->device_id = pci_dev->id.device_id; + data->vendor_id = pci_dev->id.vendor_id; + + /* create a opae_adapter based on above device data */ + adapter = opae_adapter_alloc(pci_dev->device.name, data); + if (!adapter) { + ret = -ENOMEM; + goto free_adapter_data; + } + + rawdev->dev_ops = &ifpga_rawdev_ops; + rawdev->device = &pci_dev->device; + rawdev->driver_name = pci_dev->device.driver->name; + + rawdev->dev_private = adapter; + + /* must enumerate the adapter before use it */ + ret = opae_adapter_enumerate(adapter); + if (ret) + goto free_adapter; + + /* get opae_manager to rawdev */ + mgr = opae_adapter_get_mgr(adapter); + if (mgr) { + /* PF function */ + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); + } + + return ret; + +free_adapter: + if (adapter) + opae_adapter_free(adapter); +free_adapter_data: + if (data) + opae_adapter_data_free(data); +cleanup: + if (rawdev) + rte_rawdev_pmd_release(rawdev); + + return ret; +} + +static int +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) +{ + int ret; + struct rte_rawdev *rawdev; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + struct opae_adapter *adapter; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + return ret; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", + name, rte_socket_id()); + + rawdev = rte_rawdev_pmd_get_named_dev(name); + if (!rawdev) { + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name); + return -EINVAL; + } + + adapter = ifpga_rawdev_get_priv(rawdev); + if (!adapter) + return -ENODEV; + + opae_adapter_data_free(adapter->data); + opae_adapter_free(adapter); + + /* rte_rawdev_close is called by pmd_release */ + ret = rte_rawdev_pmd_release(rawdev); + if (ret) + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); + + return ret; +} + +static int +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()); +} + +static int +ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) +{ + return ifpga_rawdev_destroy(pci_dev); +} + +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { + .id_table = pci_ifpga_map, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, + .probe = ifpga_rawdev_pci_probe, + .remove = ifpga_rawdev_pci_remove, +}; + +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | uio_pci_generic | vfio-pci"); + +RTE_INIT(ifpga_rawdev_init_log); +static void +ifpga_rawdev_init_log(void) +{ + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); + if (ifpga_rawdev_logtype >= 0) + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +static int +ifpga_cfg_probe(struct rte_vdev_device *dev) +{ + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + int port; + char *name = NULL; + char dev_name[RTE_RAWDEV_NAME_MAX_LEN]; + + devargs = dev->device.devargs; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &rte_ifpga_get_string_arg, &name) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, + IFPGA_ARG_PORT, + &rte_ifpga_get_integer32_arg, + &port) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + memset(dev_name, 0, sizeof(dev_name)); + snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s", + port, name); + + rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), + dev_name, devargs->args); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +static int +ifpga_cfg_remove(struct rte_vdev_device *vdev) +{ + IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p", + vdev); + + return 0; +} + +static struct rte_vdev_driver ifpga_cfg_driver = { + .probe = ifpga_cfg_probe, + .remove = ifpga_cfg_remove, +}; + +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, + "bdf=<string> " + "port=<int> " + "afu_bts=<path>"); + diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h new file mode 100644 index 0000000..c7759b8 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_RAWDEV_H_ +#define _IFPGA_RAWDEV_H_ + +extern int ifpga_rawdev_logtype; + +#define IFPGA_RAWDEV_PMD_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_rawdev_logtype, "ifgpa: " fmt, \ + ##args) + +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") + +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) +#define IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) +#define IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) +#define IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) + +enum ifpga_rawdev_device_state { + IFPGA_IDLE, + IFPGA_READY, + IFPGA_ERROR +}; + +static inline struct opae_adapter * +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) +{ + return rawdev->dev_private; +} + +#endif /* _IFPGA_RAWDEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/meson.build b/drivers/raw/ifpga_rawdev/meson.build new file mode 100644 index 0000000..6725687 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/meson.build @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +version = 1 + +subdir('base') +objs = [base_objs] + +deps += ['rawdev', 'pci', 'bus_pci', 'kvargs', + 'bus_vdev', 'bus_ifpga'] +sources = files('ifpga_rawdev.c') + +includes += include_directories('base') + +allow_experimental_apis = true diff --git a/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map new file mode 100644 index 0000000..9b9ab1a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map @@ -0,0 +1,4 @@ +DPDK_18.05 { + + local: *; +}; diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build index 34dfac4..a61cdcc 100644 --- a/drivers/raw/meson.build +++ b/drivers/raw/meson.build @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright 2018 NXP -drivers = ['skeleton_rawdev', 'dpaa2_cmdif', 'dpaa2_qdma'] +drivers = ['skeleton_rawdev', 'dpaa2_cmdif', 'dpaa2_qdma', 'ifpga_rawdev'] std_deps = ['rawdev'] config_flag_fmt = 'RTE_LIBRTE_PMD_@0@_RAWDEV' driver_name_fmt = 'rte_pmd_@0@' diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 3861e1a..acc0ec3 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -256,9 +256,11 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += -lrte_pmd_dpaa2_cmdif _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += -lrte_pmd_dpaa2_qdma 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 +endif # CONFIG_RTE_LIBRTE_IFPGA_BUS endif # CONFIG_RTE_LIBRTE_RAWDEV - endif # !CONFIG_RTE_BUILD_SHARED_LIBS _LDLIBS-y += --no-whole-archive -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen @ 2018-05-09 14:47 ` Thomas Monjalon 2018-05-09 15:33 ` Zhang, Tianfei 2018-05-10 9:21 ` Wu, Jingjing 2018-05-10 14:24 ` Zhang, Qi Z 2 siblings, 1 reply; 149+ messages in thread From: Thomas Monjalon @ 2018-05-09 14:47 UTC (permalink / raw) To: Xu, Rosen Cc: dev, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Yanglong Wu 09/05/2018 09:43, Xu, Rosen: > From: Rosen Xu <rosen.xu@intel.com> > > Add Intel FPGA BUS Rawdev Driver which is based on > librte_rawdev library. > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> I have a compilation error: drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c:10:15: error: instruction requires: AVX-512 ISA because of vmovdqu64: #if defined(RTE_ARCH_X86_64) static inline void copy512(const void *src, void *dst) { asm volatile("vmovdqu64 (%0), %%zmm0;" "vmovntdq %%zmm0, (%1);" : : "r"(src), "r"(dst)); } #else static inline void copy512(const void *src, void *dst) { UNUSED(src); UNUSED(dst); WARN_ON(1); } #endif I suggest to fix it quickly without waiting a v11 with this: static inline void copy512(const void *src, void *dst) { #ifdef CC_SUPPORT_AVX512F asm volatile("vmovdqu64 (%0), %%zmm0;" "vmovntdq %%zmm0, (%1);" : : "r"(src), "r"(dst)); #else UNUSED(src); UNUSED(dst); WARN_ON(1); #endif } It does not make any runtime detection, but it's better than previously. ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-09 14:47 ` Thomas Monjalon @ 2018-05-09 15:33 ` Zhang, Tianfei 2018-05-09 15:37 ` Bruce Richardson 0 siblings, 1 reply; 149+ messages in thread From: Zhang, Tianfei @ 2018-05-09 15:33 UTC (permalink / raw) To: Thomas Monjalon, Xu, Rosen Cc: dev, Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Liu, Song, Wu, Hao, gaetan.rivet, Wu, Yanglong > -----Original Message----- > From: Thomas Monjalon [mailto:thomas@monjalon.net] > Sent: Wednesday, May 9, 2018 10:47 PM > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, > Declan <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com; Wu, Yanglong <yanglong.wu@intel.com> > Subject: Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev > Driver > > 09/05/2018 09:43, Xu, Rosen: > > From: Rosen Xu <rosen.xu@intel.com> > > > > Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev > > library. > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> > > I have a compilation error: > drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c:10:15: error: > instruction requires: AVX-512 ISA > > because of vmovdqu64: > > #if defined(RTE_ARCH_X86_64) > static inline void copy512(const void *src, void *dst) { > asm volatile("vmovdqu64 (%0), %%zmm0;" > "vmovntdq %%zmm0, (%1);" > : > : "r"(src), "r"(dst)); > } > #else > static inline void copy512(const void *src, void *dst) { > UNUSED(src); > UNUSED(dst); > WARN_ON(1); > } > #endif > > I suggest to fix it quickly without waiting a v11 with this: > > static inline void copy512(const void *src, void *dst) { #ifdef > CC_SUPPORT_AVX512F > asm volatile("vmovdqu64 (%0), %%zmm0;" > "vmovntdq %%zmm0, (%1);" > : > : "r"(src), "r"(dst)); > #else > UNUSED(src); > UNUSED(dst); > WARN_ON(1); > #endif > } > > It does not make any runtime detection, but it's better than previously. > Which linux distribution are you use? We can compile it on Ubuntu 16.04 and RHEL 7.4. We will fix it on V11. ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-09 15:33 ` Zhang, Tianfei @ 2018-05-09 15:37 ` Bruce Richardson 2018-05-09 15:57 ` Zhang, Tianfei 0 siblings, 1 reply; 149+ messages in thread From: Bruce Richardson @ 2018-05-09 15:37 UTC (permalink / raw) To: Zhang, Tianfei Cc: Thomas Monjalon, Xu, Rosen, dev, Zhang, Roy Fan, Doherty, Declan, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Liu, Song, Wu, Hao, gaetan.rivet, Wu, Yanglong On Wed, May 09, 2018 at 04:33:45PM +0100, Zhang, Tianfei wrote: > > > > -----Original Message----- > > From: Thomas Monjalon [mailto:thomas@monjalon.net] > > Sent: Wednesday, May 9, 2018 10:47 PM > > To: Xu, Rosen <rosen.xu@intel.com> > > Cc: dev@dpdk.org; Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, > > Declan <declan.doherty@intel.com>; Richardson, Bruce > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > > <ferruh.yigit@intel.com>; Ananyev, Konstantin > > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > > gaetan.rivet@6wind.com; Wu, Yanglong <yanglong.wu@intel.com> > > Subject: Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev > > Driver > > > > 09/05/2018 09:43, Xu, Rosen: > > > From: Rosen Xu <rosen.xu@intel.com> > > > > > > Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev > > > library. > > > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > > > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > > > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> > > > > I have a compilation error: > > drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c:10:15: error: > > instruction requires: AVX-512 ISA > > > > because of vmovdqu64: > > > > #if defined(RTE_ARCH_X86_64) > > static inline void copy512(const void *src, void *dst) { > > asm volatile("vmovdqu64 (%0), %%zmm0;" > > "vmovntdq %%zmm0, (%1);" > > : > > : "r"(src), "r"(dst)); > > } > > #else > > static inline void copy512(const void *src, void *dst) { > > UNUSED(src); > > UNUSED(dst); > > WARN_ON(1); > > } > > #endif > > > > I suggest to fix it quickly without waiting a v11 with this: > > > > static inline void copy512(const void *src, void *dst) { #ifdef > > CC_SUPPORT_AVX512F > > asm volatile("vmovdqu64 (%0), %%zmm0;" > > "vmovntdq %%zmm0, (%1);" > > : > > : "r"(src), "r"(dst)); > > #else > > UNUSED(src); > > UNUSED(dst); > > WARN_ON(1); > > #endif > > } > > > > It does not make any runtime detection, but it's better than previously. > > > > Which linux distribution are you use? We can compile it on Ubuntu 16.04 and RHEL 7.4. > We will fix it on V11. > This shows up with meson builds for non-avx-512 architectures using clang. The makefile has the following snippet that doesn't have an equivalent in the meson.build file. 26 ifeq ($(CONFIG_RTE_TOOLCHAIN_CLANG),y)$ 27 >-------CFLAGS_ifpga_fme_pr.o += -march=knl$ 28 endif$ However, it does also bring up the questions as to the unconditional use of AVX-512 code? What happens if this code is run on a system without AVX-512 support? Regards, /Bruce ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-09 15:37 ` Bruce Richardson @ 2018-05-09 15:57 ` Zhang, Tianfei 2018-05-10 13:31 ` Xu, Rosen 0 siblings, 1 reply; 149+ messages in thread From: Zhang, Tianfei @ 2018-05-09 15:57 UTC (permalink / raw) To: Richardson, Bruce Cc: Thomas Monjalon, Xu, Rosen, dev, Zhang, Roy Fan, Doherty, Declan, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Liu, Song, Wu, Hao, gaetan.rivet, Wu, Yanglong > -----Original Message----- > From: Richardson, Bruce > Sent: Wednesday, May 9, 2018 11:37 PM > To: Zhang, Tianfei <tianfei.zhang@intel.com> > Cc: Thomas Monjalon <thomas@monjalon.net>; Xu, Rosen > <rosen.xu@intel.com>; dev@dpdk.org; Zhang, Roy Fan > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > shreyansh.jain@nxp.com; Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, > Konstantin <konstantin.ananyev@intel.com>; Liu, Song > <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com; Wu, Yanglong <yanglong.wu@intel.com> > Subject: Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev > Driver > > On Wed, May 09, 2018 at 04:33:45PM +0100, Zhang, Tianfei wrote: > > > > > > > -----Original Message----- > > > From: Thomas Monjalon [mailto:thomas@monjalon.net] > > > Sent: Wednesday, May 9, 2018 10:47 PM > > > To: Xu, Rosen <rosen.xu@intel.com> > > > Cc: dev@dpdk.org; Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, > > > Declan <declan.doherty@intel.com>; Richardson, Bruce > > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > > > <ferruh.yigit@intel.com>; Ananyev, Konstantin > > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > > <hao.wu@intel.com>; gaetan.rivet@6wind.com; Wu, Yanglong > > > <yanglong.wu@intel.com> > > > Subject: Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS > > > Rawdev Driver > > > > > > 09/05/2018 09:43, Xu, Rosen: > > > > From: Rosen Xu <rosen.xu@intel.com> > > > > > > > > Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev > > > > library. > > > > > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > > > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > > > > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > > > > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> > > > > > > I have a compilation error: > > > drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c:10:15: error: > > > instruction requires: AVX-512 ISA > > > > > > because of vmovdqu64: > > > > > > #if defined(RTE_ARCH_X86_64) > > > static inline void copy512(const void *src, void *dst) { > > > asm volatile("vmovdqu64 (%0), %%zmm0;" > > > "vmovntdq %%zmm0, (%1);" > > > : > > > : "r"(src), "r"(dst)); > > > } > > > #else > > > static inline void copy512(const void *src, void *dst) { > > > UNUSED(src); > > > UNUSED(dst); > > > WARN_ON(1); > > > } > > > #endif > > > > > > I suggest to fix it quickly without waiting a v11 with this: > > > > > > static inline void copy512(const void *src, void *dst) { #ifdef > > > CC_SUPPORT_AVX512F > > > asm volatile("vmovdqu64 (%0), %%zmm0;" > > > "vmovntdq %%zmm0, (%1);" > > > : > > > : "r"(src), "r"(dst)); > > > #else > > > UNUSED(src); > > > UNUSED(dst); > > > WARN_ON(1); > > > #endif > > > } > > > > > > It does not make any runtime detection, but it's better than previously. > > > > > > > Which linux distribution are you use? We can compile it on Ubuntu 16.04 > and RHEL 7.4. > > We will fix it on V11. > > > > This shows up with meson builds for non-avx-512 architectures using clang. > The makefile has the following snippet that doesn't have an equivalent in the > meson.build file. > > 26 ifeq ($(CONFIG_RTE_TOOLCHAIN_CLANG),y)$ > 27 >-------CFLAGS_ifpga_fme_pr.o += -march=knl$ > 28 endif$ > > However, it does also bring up the questions as to the unconditional use of > AVX-512 code? What happens if this code is run on a system without > AVX-512 support? This function is for SKY MCP platform (Xeon + FPGA integrated chip) which can accelerate the PR (partial reconfiguration ) function on FPGA. So the SKY support the AVX-512 instruction set. ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-09 15:57 ` Zhang, Tianfei @ 2018-05-10 13:31 ` Xu, Rosen 0 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-10 13:31 UTC (permalink / raw) To: Zhang, Tianfei, Richardson, Bruce Cc: Thomas Monjalon, dev, Zhang, Roy Fan, Doherty, Declan, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Liu, Song, Wu, Hao, gaetan.rivet, Wu, Yanglong Hi Thomas and Bruce, To improve PR speed we involved AVX-512, but AVX-512 is not available in all IA platforms, besides this after we have tested several times, using AVX-512 only improve 1 ms. So this patch we don't use it. > -----Original Message----- > From: Zhang, Tianfei > Sent: Wednesday, May 09, 2018 23:58 > To: Richardson, Bruce <bruce.richardson@intel.com> > Cc: Thomas Monjalon <thomas@monjalon.net>; Xu, Rosen > <rosen.xu@intel.com>; dev@dpdk.org; Zhang, Roy Fan > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > shreyansh.jain@nxp.com; Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, > Konstantin <konstantin.ananyev@intel.com>; Liu, Song <song.liu@intel.com>; > Wu, Hao <hao.wu@intel.com>; gaetan.rivet@6wind.com; Wu, Yanglong > <yanglong.wu@intel.com> > Subject: RE: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev > Driver > > > > > -----Original Message----- > > From: Richardson, Bruce > > Sent: Wednesday, May 9, 2018 11:37 PM > > To: Zhang, Tianfei <tianfei.zhang@intel.com> > > Cc: Thomas Monjalon <thomas@monjalon.net>; Xu, Rosen > > <rosen.xu@intel.com>; dev@dpdk.org; Zhang, Roy Fan > > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > > shreyansh.jain@nxp.com; Yigit, Ferruh <ferruh.yigit@intel.com>; > > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Liu, Song > > <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > > gaetan.rivet@6wind.com; Wu, Yanglong <yanglong.wu@intel.com> > > Subject: Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS > > Rawdev Driver > > > > On Wed, May 09, 2018 at 04:33:45PM +0100, Zhang, Tianfei wrote: > > > > > > > > > > -----Original Message----- > > > > From: Thomas Monjalon [mailto:thomas@monjalon.net] > > > > Sent: Wednesday, May 9, 2018 10:47 PM > > > > To: Xu, Rosen <rosen.xu@intel.com> > > > > Cc: dev@dpdk.org; Zhang, Roy Fan <roy.fan.zhang@intel.com>; > > > > Doherty, Declan <declan.doherty@intel.com>; Richardson, Bruce > > > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, > > > > Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > > > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > > > <hao.wu@intel.com>; gaetan.rivet@6wind.com; Wu, Yanglong > > > > <yanglong.wu@intel.com> > > > > Subject: Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS > > > > Rawdev Driver > > > > > > > > 09/05/2018 09:43, Xu, Rosen: > > > > > From: Rosen Xu <rosen.xu@intel.com> > > > > > > > > > > Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev > > > > > library. > > > > > > > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > > > > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > > > > > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > > > > > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> > > > > > > > > I have a compilation error: > > > > drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c:10:15: error: > > > > instruction requires: AVX-512 ISA > > > > > > > > because of vmovdqu64: > > > > > > > > #if defined(RTE_ARCH_X86_64) > > > > static inline void copy512(const void *src, void *dst) { > > > > asm volatile("vmovdqu64 (%0), %%zmm0;" > > > > "vmovntdq %%zmm0, (%1);" > > > > : > > > > : "r"(src), "r"(dst)); } #else static inline void > > > > copy512(const void *src, void *dst) { > > > > UNUSED(src); > > > > UNUSED(dst); > > > > WARN_ON(1); > > > > } > > > > #endif > > > > > > > > I suggest to fix it quickly without waiting a v11 with this: > > > > > > > > static inline void copy512(const void *src, void *dst) { #ifdef > > > > CC_SUPPORT_AVX512F > > > > asm volatile("vmovdqu64 (%0), %%zmm0;" > > > > "vmovntdq %%zmm0, (%1);" > > > > : > > > > : "r"(src), "r"(dst)); #else > > > > UNUSED(src); > > > > UNUSED(dst); > > > > WARN_ON(1); > > > > #endif > > > > } > > > > > > > > It does not make any runtime detection, but it's better than previously. > > > > > > > > > > Which linux distribution are you use? We can compile it on Ubuntu > > > 16.04 > > and RHEL 7.4. > > > We will fix it on V11. > > > > > > > This shows up with meson builds for non-avx-512 architectures using clang. > > The makefile has the following snippet that doesn't have an equivalent > > in the meson.build file. > > > > 26 ifeq ($(CONFIG_RTE_TOOLCHAIN_CLANG),y)$ > > 27 >-------CFLAGS_ifpga_fme_pr.o += -march=knl$ > > 28 endif$ > > > > However, it does also bring up the questions as to the unconditional > > use of > > AVX-512 code? What happens if this code is run on a system without > > AVX-512 support? > > This function is for SKY MCP platform (Xeon + FPGA integrated chip) which > can accelerate the PR (partial reconfiguration ) function on FPGA. > So the SKY support the AVX-512 instruction set. ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2018-05-09 14:47 ` Thomas Monjalon @ 2018-05-10 9:21 ` Wu, Jingjing 2018-05-10 13:16 ` Xu, Rosen 2018-05-11 3:21 ` Xu, Rosen 2018-05-10 14:24 ` Zhang, Qi Z 2 siblings, 2 replies; 149+ messages in thread From: Wu, Jingjing @ 2018-05-10 9:21 UTC (permalink / raw) To: Xu, Rosen, dev, thomas Cc: Xu, Rosen, Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet, Wu, Yanglong Hi, Rosen Few comments below. Thanks Jingjing [...] > +static int > +ifpga_rawdev_start(struct rte_rawdev *dev) > +{ > + int ret = 0; > + struct opae_adapter *adapter; > + > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > + > + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); > + > + adapter = ifpga_rawdev_get_priv(dev); > + if (!adapter) > + return -ENODEV; > + Set dev->started? > + return ret; > +} [...] > + > +static const struct rte_rawdev_ops ifpga_rawdev_ops = { > + .dev_info_get = ifpga_rawdev_info_get, > + .dev_configure = NULL, If go the declaration of rte_rawdev_configure, you will see "This function must be invoked first before any other function in the API." So I think we need to function for it, even it does nothing. [...] > +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { > + .id_table = pci_ifpga_map, > + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, Is RTE_PCI_DRV_INTR_LSC supported? [...] > +static struct rte_vdev_driver ifpga_cfg_driver = { > + .probe = ifpga_cfg_probe, > + .remove = ifpga_cfg_remove, > +}; > + > +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); I think prefix net_ would mean the device is net device (eth_dev)? How about to change the prefix to raw_? > +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); > +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, > + "bdf=<string> " ifpga=<string>? > + "port=<int> " > + "afu_bts=<path>"); > + ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-10 9:21 ` Wu, Jingjing @ 2018-05-10 13:16 ` Xu, Rosen 2018-05-11 3:21 ` Xu, Rosen 1 sibling, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-10 13:16 UTC (permalink / raw) To: Wu, Jingjing, dev, thomas Cc: Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet, Wu, Yanglong Hi Jingjing, > -----Original Message----- > From: Wu, Jingjing > Sent: Thursday, May 10, 2018 17:21 > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; thomas@monjalon.net > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com; Wu, Yanglong <yanglong.wu@intel.com> > Subject: RE: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev > Driver > > Hi, Rosen > > Few comments below. Thanks a lot. > Thanks > Jingjing > > [...] > > > +static int > > +ifpga_rawdev_start(struct rte_rawdev *dev) { > > + int ret = 0; > > + struct opae_adapter *adapter; > > + > > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > > + > > + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); > > + > > + adapter = ifpga_rawdev_get_priv(dev); > > + if (!adapter) > > + return -ENODEV; > > + > Set dev->started? Rawdev lib enable it. > > + return ret; > > +} > > > [...] > > > + > > +static const struct rte_rawdev_ops ifpga_rawdev_ops = { > > + .dev_info_get = ifpga_rawdev_info_get, > > + .dev_configure = NULL, > If go the declaration of rte_rawdev_configure, you will see "This function > must be invoked first before any other function in the API." > So I think we need to function for it, even it does nothing. For other Rawdev Drivers, no used function pointer is initialized with NULL. > > [...] > > > +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { > > + .id_table = pci_ifpga_map, > > + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | > RTE_PCI_DRV_INTR_LSC, > Is RTE_PCI_DRV_INTR_LSC supported? > > [...] > > > +static struct rte_vdev_driver ifpga_cfg_driver = { > > + .probe = ifpga_cfg_probe, > > + .remove = ifpga_cfg_remove, > > +}; > > + > > +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); > I think prefix net_ would mean the device is net device (eth_dev)? How about > to change the prefix to raw_? I have fixed it both in code and document. > > +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); > > +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, > > + "bdf=<string> " > ifpga=<string>? > > + "port=<int> " > > + "afu_bts=<path>"); > > + ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-10 9:21 ` Wu, Jingjing 2018-05-10 13:16 ` Xu, Rosen @ 2018-05-11 3:21 ` Xu, Rosen 1 sibling, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-11 3:21 UTC (permalink / raw) To: Wu, Jingjing, dev, thomas Cc: Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet, Wu, Yanglong Hi Jingjing, After we have aligned this morning, I will reply your email again. > -----Original Message----- > From: Wu, Jingjing > Sent: Thursday, May 10, 2018 17:21 > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; thomas@monjalon.net > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com; Wu, Yanglong <yanglong.wu@intel.com> > Subject: RE: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev > Driver > > Hi, Rosen > > Few comments below. > > Thanks > Jingjing > > [...] > > > +static int > > +ifpga_rawdev_start(struct rte_rawdev *dev) { > > + int ret = 0; > > + struct opae_adapter *adapter; > > + > > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > > + > > + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); > > + > > + adapter = ifpga_rawdev_get_priv(dev); > > + if (!adapter) > > + return -ENODEV; > > + > Set dev->started? > > + return ret; > > +} Fixed. > > [...] > > > + > > +static const struct rte_rawdev_ops ifpga_rawdev_ops = { > > + .dev_info_get = ifpga_rawdev_info_get, > > + .dev_configure = NULL, > If go the declaration of rte_rawdev_configure, you will see "This function > must be invoked first before any other function in the API." > So I think we need to function for it, even it does nothing. Yes, the rte_rawdev_configure function should not NULL. I have fill it. > > [...] > > > +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { > > + .id_table = pci_ifpga_map, > > + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | > RTE_PCI_DRV_INTR_LSC, > Is RTE_PCI_DRV_INTR_LSC supported? Not supported, and I removed it. > [...] > > > +static struct rte_vdev_driver ifpga_cfg_driver = { > > + .probe = ifpga_cfg_probe, > > + .remove = ifpga_cfg_remove, > > +}; > > + > > +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); > I think prefix net_ would mean the device is net device (eth_dev)? How about > to change the prefix to raw_? > > > +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); > > +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, > > + "bdf=<string> " > ifpga=<string>? Fixed. > > + "port=<int> " > > + "afu_bts=<path>"); > > + ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2018-05-09 14:47 ` Thomas Monjalon 2018-05-10 9:21 ` Wu, Jingjing @ 2018-05-10 14:24 ` Zhang, Qi Z 2018-05-11 3:16 ` Xu, Rosen 2 siblings, 1 reply; 149+ messages in thread From: Zhang, Qi Z @ 2018-05-10 14:24 UTC (permalink / raw) To: Xu, Rosen, dev, thomas Cc: Xu, Rosen, Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet, Wu, Yanglong Hi Rosen: After read this patch, I have below suggestion 1. rte_ifgpa_device is not necessary, since we already have ifgpa bus, it manages all devices on that bus, we don't need another abstraction to manage afu devices, and user can add to or remove from the bus. 2. rename rte_afu_device to rte_ifpga_device , we follow the name rule. 3. data structure looks like below. Struct rte_ifpga_deivce { rte_device device /* backing device */ Rte_raw_device *device /* link to raw pci device */ Struct Rte_afu_info info; /* afu information */ } struct rte_afu_info { struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ struct rte_afu_id id; /**< AFU id within FPGA. */ uint32_t num_region; /**< number of regions found */ .... ... } Regards Qi > -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > Sent: Wednesday, May 9, 2018 3:43 PM > To: dev@dpdk.org; thomas@monjalon.net > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com; Wu, Yanglong <yanglong.wu@intel.com> > Subject: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver > > From: Rosen Xu <rosen.xu@intel.com> > > Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev library. > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> > --- > MAINTAINERS | 3 + > config/common_base | 5 + > doc/guides/rawdevs/ifpga_rawdev.rst | 112 ++++ > doc/guides/rawdevs/index.rst | 1 + > doc/guides/rel_notes/release_18_05.rst | 8 + > drivers/raw/Makefile | 1 + > drivers/raw/ifpga_rawdev/Makefile | 36 ++ > drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 608 > +++++++++++++++++++++ > drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ > drivers/raw/ifpga_rawdev/meson.build | 15 + > .../ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map | 4 + > drivers/raw/meson.build | 2 +- > mk/rte.app.mk | 4 +- > 13 files changed, 834 insertions(+), 2 deletions(-) create mode 100644 > doc/guides/rawdevs/ifpga_rawdev.rst > create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode > 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h > create mode 100644 drivers/raw/ifpga_rawdev/meson.build > create mode 100644 > drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map > > diff --git a/MAINTAINERS b/MAINTAINERS > index 9c27d5a..a93ce9f 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -851,8 +851,11 @@ Rawdev Drivers > -------------- > > Intel FPGA > +M: Rosen Xu <rosen.xu@intel.com> > M: Tianfei zhang <tianfei.zhang@intel.com> > +F: drivers/raw/ifpga_rawdev/ > F: drivers/raw/ifpga_rawdev/base/ > +F: doc/guides/rawdevs/ifpga_rawdev.rst > > NXP DPAA2 QDMA > M: Nipun Gupta <nipun.gupta@nxp.com> > diff --git a/config/common_base b/config/common_base index > 1440316..017a15a 100644 > --- a/config/common_base > +++ b/config/common_base > @@ -633,6 +633,11 @@ > CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV=n > CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV=n > > # > +# Compile PMD for Intel FPGA raw device # > +CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV=y > + > +# > # Compile librte_ring > # > CONFIG_RTE_LIBRTE_RING=y > diff --git a/doc/guides/rawdevs/ifpga_rawdev.rst > b/doc/guides/rawdevs/ifpga_rawdev.rst > new file mode 100644 > index 0000000..37ae4cc > --- /dev/null > +++ b/doc/guides/rawdevs/ifpga_rawdev.rst > @@ -0,0 +1,112 @@ > +.. SPDX-License-Identifier: BSD-3-Clause > + Copyright(c) 2018 Intel Corporation. > + > +IFPGA Rawdev Driver > +====================== > + > +FPGA is used more and more widely in Cloud and NFV, one primary reason > +is that FPGA not only provides ASIC performance but also it's more > +flexible than ASIC. > + > +FPGA uses Partial Reconfigure (PR) Parts of Bit Stream to achieve its > +flexibility. That means one FPGA Device Bit Stream is divided into many > +Parts of Bit Stream(each Part of Bit Stream is defined as > +AFU-Accelerated Function Unit), and each AFU is a hardware acceleration > +unit which can be dynamically reloaded respectively. > + > +By PR (Partial Reconfiguration) AFUs, one FPGA resources can be > +time-shared by different users. FPGA hot upgrade and fault tolerance can be > provided easily. > + > +The SW IFPGA Rawdev Driver (**ifpga_rawdev**) provides a Rawdev driver > +that utilizes Intel FPGA Software Stack OPAE(Open Programmable > +Acceleration > +Engine) for FPGA management. > + > +Implementation details > +---------------------- > + > +Each instance of IFPGA Rawdev Driver is probed by Intel FpgaDev. In > +coordination with OPAE share code IFPGA Rawdev Driver provides common > +FPGA management ops for FPGA operation, OPAE provides all following > operations: > +- FPGA PR (Partial Reconfiguration) management > +- FPGA AFUs Identifying > +- FPGA Thermal Management > +- FPGA Power Management > +- FPGA Performance reporting > +- FPGA Remote Debug > + > +All configuration parameters are taken by vdev_ifpga_cfg driver. > +Besides configuration, vdev_ifpga_cfg driver also hot plugs in IFPGA Bus. > + > +All of the AFUs of one FPGA may share same PCI BDF and AFUs scan depend > +on IFPGA Rawdev Driver so IFPGA Bus takes AFU device scan and AFU drivers > probe. > +All AFU device driver bind to AFU device by its UUID (Universally > +Unique Identifier). > + > +To avoid unnecessary code duplication and ensure maximum performance, > +handling of AFU devices is left to different PMDs; all the design as > +summarized by the following block diagram:: > + > + +---------------------------------------------------------------+ > + | Application(s) > | > + +----------------------------.----------------------------------+ > + | > + | > + +----------------------------'----------------------------------+ > + | DPDK Framework (APIs) > | > + +----------|------------|--------.---------------------|--------+ > + / \ | > + / \ | > + +-------'-------+ +-------'-------+ +--------'--------+ > + | Eth PMD | | Crypto PMD | | > | > + +-------.-------+ +-------.-------+ | | > + | | | > | > + | | | > | > + +-------'-------+ +-------'-------+ | IFPGA | > + | Eth AFU Dev | |Crypto AFU Dev | | Rawdev Driver > | > + +-------.-------+ +-------.-------+ |(OPAE Share Code)| > + | | | > | > + | | Rawdev | > | > + +-------'------------------'-------+ Ops | | > + | IFPGA Bus | -------->| > | > + +-----------------.----------------+ +--------.--------+ > + | | > + Hot-plugin -->| | > + | | > + +-----------------'------------------+ +--------'--------+ > + | vdev_ifpga_cfg driver | | Intel FpgaDev > | > + +------------------------------------+ +-----------------+ > + > +Build options > +------------- > + > +- ``CONFIG_RTE_LIBRTE_IFPGA_BUS`` (default ``y``) > + > + Toggle compilation of IFPGA Bus library. > + > +- ``CONFIG_RTE_LIBRTE_IFPGA_RAWDEV`` (default ``y``) > + > + Toggle compilation of the ``ifpga_rawdev`` driver. > + > +Run-time parameters > +------------------- > + > +This driver is invoked automatically in systems added with Intel FPGA, > +but PR and IFPGA Bus scan is trigged by command line using ``--vdev > +'net_ifpga_cfg`` EAL option. > + > +The following device parameters are supported: > + > +- ``ifpga`` [string] > + > + Provide a specific Intel FPGA device PCI BDF. Can be provided > + multiple times for additional instances. > + > +- ``port`` [int] > + > + Each FPGA can provide many channels to PR AFU by software, each > + channels is identified by this parameter. > + > +- ``afu_bts`` [string] > + > + If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and > + identifies AFU Bit Stream file. > diff --git a/doc/guides/rawdevs/index.rst b/doc/guides/rawdevs/index.rst > index 7769083..7c3bd95 100644 > --- a/doc/guides/rawdevs/index.rst > +++ b/doc/guides/rawdevs/index.rst > @@ -13,3 +13,4 @@ application through rawdev API. > > dpaa2_cmdif > dpaa2_qdma > + ifpga_rawdev > diff --git a/doc/guides/rel_notes/release_18_05.rst > b/doc/guides/rel_notes/release_18_05.rst > index 265950a..f5241a1 100644 > --- a/doc/guides/rel_notes/release_18_05.rst > +++ b/doc/guides/rel_notes/release_18_05.rst > @@ -189,6 +189,14 @@ New Features > the DPDK framework. It provides Intel FPGA Partial Bit Stream > AFU(Accelerated > Function Unit) scan and drivers prove. > > +* **Added IFPGA(Intel FPGA) Rawdev Driver.** > + > + Added a new Rawdev driver called IFPGA(Intel FPGA) Rawdev Driver, > + which cooperates with OPAE(Open Programmable Acceleration Engine) > + share code provides common FPGA management ops for FPGA operation. > + > + See the :doc:`../rawdevs/ifpga_rawdev` programmer's guide for more > details. > + > API Changes > ----------- > > diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index > 2eb2787..8e29b4a 100644 > --- a/drivers/raw/Makefile > +++ b/drivers/raw/Makefile > @@ -9,5 +9,6 @@ ifeq > ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) > DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += dpaa2_cmdif > DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += dpaa2_qdma > endif > +DIRS-$(CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV) += ifpga_rawdev > > include $(RTE_SDK)/mk/rte.subdir.mk > diff --git a/drivers/raw/ifpga_rawdev/Makefile > b/drivers/raw/ifpga_rawdev/Makefile > new file mode 100644 > index 0000000..f3b9d5e > --- /dev/null > +++ b/drivers/raw/ifpga_rawdev/Makefile > @@ -0,0 +1,36 @@ > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > +Corporation > + > +include $(RTE_SDK)/mk/rte.vars.mk > + > +# > +# library name > +# > +LIB = librte_pmd_ifpga_rawdev.a > + > +CFLAGS += -DALLOW_EXPERIMENTAL_API > +CFLAGS += -O3 > +CFLAGS += $(WERROR_FLAGS) > +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga CFLAGS += > +-I$(RTE_SDK)/drivers/raw/ifpga_rawdev > +LDLIBS += -lrte_eal > +LDLIBS += -lrte_rawdev > +LDLIBS += -lrte_bus_vdev > +LDLIBS += -lrte_kvargs > +LDLIBS += -lrte_bus_pci > +LDLIBS += -lrte_bus_ifpga > + > +EXPORT_MAP := rte_pmd_ifpga_rawdev_version.map > + > +LIBABIVER := 1 > + > +VPATH += $(SRCDIR)/base > + > +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile > + > +# > +# all source are stored in SRCS-y > +# > +SRCS-$(CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV) += ifpga_rawdev.c > + > +include $(RTE_SDK)/mk/rte.lib.mk > diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c > b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c > new file mode 100644 > index 0000000..32e811c > --- /dev/null > +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c > @@ -0,0 +1,608 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation */ > + > +#include <string.h> > +#include <dirent.h> > +#include <sys/stat.h> > +#include <unistd.h> > +#include <sys/types.h> > +#include <fcntl.h> > +#include <rte_log.h> > +#include <rte_bus.h> > +#include <rte_eal_memconfig.h> > +#include <rte_malloc.h> > +#include <rte_devargs.h> > +#include <rte_memcpy.h> > +#include <rte_pci.h> > +#include <rte_bus_pci.h> > +#include <rte_kvargs.h> > +#include <rte_alarm.h> > + > +#include <rte_errno.h> > +#include <rte_per_lcore.h> > +#include <rte_memory.h> > +#include <rte_memzone.h> > +#include <rte_eal.h> > +#include <rte_common.h> > +#include <rte_bus_vdev.h> > + > +#include "base/opae_hw_api.h" > +#include "rte_rawdev.h" > +#include "rte_rawdev_pmd.h" > +#include "rte_bus_ifpga.h" > +#include "ifpga_common.h" > +#include "ifpga_logs.h" > +#include "ifpga_rawdev.h" > + > +int ifpga_rawdev_logtype; > + > +#define PCI_VENDOR_ID_INTEL 0x8086 > +/* PCI Device ID */ > +#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 > +/* 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 RTE_MAX_RAW_DEVICE 10 > + > +static const struct rte_pci_id pci_ifpga_map[] = { > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, > PCIE_DEVICE_ID_PF_INT_5_X) }, > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, > PCIE_DEVICE_ID_VF_INT_5_X) }, > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, > PCIE_DEVICE_ID_PF_INT_6_X) }, > + { 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) }, > + { .vendor_id = 0, /* sentinel */ }, > +}; > + > +static int > +ifpga_fill_afu_dev(struct opae_accelerator *acc, > + struct rte_afu_device *afu_dev) > +{ > + struct rte_mem_resource *res = afu_dev->mem_resource; > + struct opae_acc_region_info region_info; > + struct opae_acc_info info; > + unsigned long i; > + int ret; > + > + ret = opae_acc_get_info(acc, &info); > + if (ret) > + return ret; > + > + if (info.num_regions > PCI_MAX_RESOURCE) > + return -EFAULT; > + > + afu_dev->num_region = info.num_regions; > + > + for (i = 0; i < info.num_regions; i++) { > + region_info.index = i; > + ret = opae_acc_get_region_info(acc, ®ion_info); > + if (ret) > + return ret; > + > + if ((region_info.flags & ACC_REGION_MMIO) && > + (region_info.flags & ACC_REGION_READ) && > + (region_info.flags & ACC_REGION_WRITE)) { > + res[i].phys_addr = region_info.phys_addr; > + res[i].len = region_info.len; > + res[i].addr = region_info.addr; > + } else > + return -EFAULT; > + } > + > + return 0; > +} > + > +static void > +ifpga_rawdev_info_get(struct rte_rawdev *dev, > + rte_rawdev_obj_t dev_info) > +{ > + struct opae_adapter *adapter; > + struct opae_accelerator *acc; > + struct rte_afu_device *afu_dev; > + > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > + > + if (!dev_info) { > + IFPGA_RAWDEV_PMD_ERR("Invalid request"); > + return; > + } > + > + adapter = ifpga_rawdev_get_priv(dev); > + if (!adapter) > + return; > + > + afu_dev = dev_info; > + afu_dev->rawdev = dev; > + > + /* find opae_accelerator and fill info into afu_device */ > + opae_adapter_for_each_acc(adapter, acc) { > + if (acc->index != afu_dev->id.port) > + continue; > + > + if (ifpga_fill_afu_dev(acc, afu_dev)) { > + IFPGA_RAWDEV_PMD_ERR("cannot get info\n"); > + return; > + } > + } > +} > + > +static int > +ifpga_rawdev_start(struct rte_rawdev *dev) { > + int ret = 0; > + struct opae_adapter *adapter; > + > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > + > + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); > + > + adapter = ifpga_rawdev_get_priv(dev); > + if (!adapter) > + return -ENODEV; > + > + return ret; > +} > + > +static void > +ifpga_rawdev_stop(struct rte_rawdev *dev) { > + dev->started = 0; > +} > + > +static int > +ifpga_rawdev_close(struct rte_rawdev *dev) { > + return dev ? 0:1; > +} > + > +static int > +ifpga_rawdev_reset(struct rte_rawdev *dev) { > + return dev ? 0:1; > +} > + > +static int > +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, > + u64 *status) > +{ > + > + struct opae_adapter *adapter; > + struct opae_manager *mgr; > + struct opae_accelerator *acc; > + struct opae_bridge *br; > + int ret; > + > + adapter = ifpga_rawdev_get_priv(raw_dev); > + if (!adapter) > + return -ENODEV; > + > + mgr = opae_adapter_get_mgr(adapter); > + if (!mgr) > + return -ENODEV; > + > + acc = opae_adapter_get_acc(adapter, port_id); > + if (!acc) > + return -ENODEV; > + > + br = opae_acc_get_br(acc); > + if (!br) > + return -ENODEV; > + > + ret = opae_manager_flash(mgr, port_id, buffer, size, status); > + if (ret) { > + IFPGA_RAWDEV_PMD_ERR("%s pr error %d\n", __func__, ret); > + return ret; > + } > + > + ret = opae_bridge_reset(br); > + if (ret) { > + IFPGA_RAWDEV_PMD_ERR("%s reset port:%d error %d\n", > + __func__, port_id, ret); > + return ret; > + } > + > + return ret; > +} > + > +static int > +rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, > + const char *file_name) > +{ > + struct stat file_stat; > + int file_fd; > + int ret = 0; > + u32 buffer_size; > + void *buffer; > + u64 pr_error; > + > + if (!file_name) > + return -EINVAL; > + > + file_fd = open(file_name, O_RDONLY); > + if (file_fd < 0) { > + IFPGA_RAWDEV_PMD_ERR("%s: open file error: %s\n", > + __func__, file_name); > + IFPGA_RAWDEV_PMD_ERR("Message : %s\n", strerror(errno)); > + return -EINVAL; > + } > + ret = stat(file_name, &file_stat); > + if (ret) { > + IFPGA_RAWDEV_PMD_ERR("stat on bitstream file failed: %s\n", > + file_name); > + return -EINVAL; > + } > + buffer_size = file_stat.st_size; > + IFPGA_RAWDEV_PMD_INFO("bitstream file size: %u\n", buffer_size); > + buffer = rte_malloc(NULL, buffer_size, 0); > + if (!buffer) { > + ret = -ENOMEM; > + goto close_fd; > + } > + > + /*read the raw data*/ > + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { > + ret = -EINVAL; > + goto free_buffer; > + } > + > + /*do PR now*/ > + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); > + IFPGA_RAWDEV_PMD_INFO("downloading to device port %d....%s.\n", > port_id, > + ret ? "failed" : "success"); > + if (ret) { > + ret = -EINVAL; > + goto free_buffer; > + } > + > +free_buffer: > + if (buffer) > + rte_free(buffer); > +close_fd: > + close(file_fd); > + file_fd = 0; > + return ret; > +} > + > +static int > +ifpga_rawdev_pr(struct rte_rawdev *dev, > + rte_rawdev_obj_t pr_conf) > +{ > + struct opae_adapter *adapter; > + struct rte_afu_pr_conf *afu_pr_conf; > + int ret; > + struct uuid uuid; > + struct opae_accelerator *acc; > + > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > + > + adapter = ifpga_rawdev_get_priv(dev); > + if (!adapter) > + return -ENODEV; > + > + if (!pr_conf) > + return -EINVAL; > + > + afu_pr_conf = pr_conf; > + > + if (afu_pr_conf->pr_enable) { > + ret = rte_fpga_do_pr(dev, > + afu_pr_conf->afu_id.port, > + afu_pr_conf->bs_path); > + if (ret) { > + IFPGA_RAWDEV_PMD_ERR("do pr error %d\n", ret); > + return ret; > + } > + } > + > + acc = opae_adapter_get_acc(adapter, afu_pr_conf->afu_id.port); > + if (!acc) > + return -ENODEV; > + > + ret = opae_acc_get_uuid(acc, &uuid); > + if (ret) > + return ret; > + > + memcpy(&afu_pr_conf->afu_id.uuid.uuid_low, uuid.b, sizeof(u64)); > + memcpy(&afu_pr_conf->afu_id.uuid.uuid_high, uuid.b + 8, sizeof(u64)); > + > + IFPGA_RAWDEV_PMD_INFO("%s: uuid_l=0x%lx, uuid_h=0x%lx\n", > __func__, > + (u64)afu_pr_conf->afu_id.uuid.uuid_low, > + (u64)afu_pr_conf->afu_id.uuid.uuid_high); > + > + return 0; > +} > + > +static const struct rte_rawdev_ops ifpga_rawdev_ops = { > + .dev_info_get = ifpga_rawdev_info_get, > + .dev_configure = NULL, > + .dev_start = ifpga_rawdev_start, > + .dev_stop = ifpga_rawdev_stop, > + .dev_close = ifpga_rawdev_close, > + .dev_reset = ifpga_rawdev_reset, > + > + .queue_def_conf = NULL, > + .queue_setup = NULL, > + .queue_release = NULL, > + > + .attr_get = NULL, > + .attr_set = NULL, > + > + .enqueue_bufs = NULL, > + .dequeue_bufs = NULL, > + > + .dump = NULL, > + > + .xstats_get = NULL, > + .xstats_get_names = NULL, > + .xstats_get_by_name = NULL, > + .xstats_reset = NULL, > + > + .firmware_status_get = NULL, > + .firmware_version_get = NULL, > + .firmware_load = ifpga_rawdev_pr, > + .firmware_unload = NULL, > + > + .dev_selftest = NULL, > +}; > + > +static int > +ifpga_rawdev_create(struct rte_pci_device *pci_dev, > + int socket_id) > +{ > + int ret = 0; > + struct rte_rawdev *rawdev = NULL; > + struct opae_adapter *adapter = NULL; > + struct opae_manager *mgr = NULL; > + struct opae_adapter_data_pci *data = NULL; > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > + int i; > + > + if (!pci_dev) { > + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); > + ret = -EINVAL; > + goto cleanup; > + } > + > + memset(name, 0, sizeof(name)); > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", > + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); > + > + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, > +rte_socket_id()); > + > + /* Allocate device structure */ > + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct opae_adapter), > + socket_id); > + if (rawdev == NULL) { > + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); > + ret = -EINVAL; > + goto cleanup; > + } > + > + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API */ > + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); > + if (!data) { > + ret = -ENOMEM; > + goto cleanup; > + } > + > + /* init opae_adapter_data_pci for device specific information */ > + for (i = 0; i < PCI_MAX_RESOURCE; i++) { > + data->region[i].phys_addr = pci_dev->mem_resource[i].phys_addr; > + data->region[i].len = pci_dev->mem_resource[i].len; > + data->region[i].addr = pci_dev->mem_resource[i].addr; > + } > + data->device_id = pci_dev->id.device_id; > + data->vendor_id = pci_dev->id.vendor_id; > + > + /* create a opae_adapter based on above device data */ > + adapter = opae_adapter_alloc(pci_dev->device.name, data); > + if (!adapter) { > + ret = -ENOMEM; > + goto free_adapter_data; > + } > + > + rawdev->dev_ops = &ifpga_rawdev_ops; > + rawdev->device = &pci_dev->device; > + rawdev->driver_name = pci_dev->device.driver->name; > + > + rawdev->dev_private = adapter; > + > + /* must enumerate the adapter before use it */ > + ret = opae_adapter_enumerate(adapter); > + if (ret) > + goto free_adapter; > + > + /* get opae_manager to rawdev */ > + mgr = opae_adapter_get_mgr(adapter); > + if (mgr) { > + /* PF function */ > + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); > + } > + > + return ret; > + > +free_adapter: > + if (adapter) > + opae_adapter_free(adapter); > +free_adapter_data: > + if (data) > + opae_adapter_data_free(data); > +cleanup: > + if (rawdev) > + rte_rawdev_pmd_release(rawdev); > + > + return ret; > +} > + > +static int > +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) { > + int ret; > + struct rte_rawdev *rawdev; > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > + struct opae_adapter *adapter; > + > + if (!pci_dev) { > + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); > + ret = -EINVAL; > + return ret; > + } > + > + memset(name, 0, sizeof(name)); > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", > + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); > + > + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", > + name, rte_socket_id()); > + > + rawdev = rte_rawdev_pmd_get_named_dev(name); > + if (!rawdev) { > + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name); > + return -EINVAL; > + } > + > + adapter = ifpga_rawdev_get_priv(rawdev); > + if (!adapter) > + return -ENODEV; > + > + opae_adapter_data_free(adapter->data); > + opae_adapter_free(adapter); > + > + /* rte_rawdev_close is called by pmd_release */ > + ret = rte_rawdev_pmd_release(rawdev); > + if (ret) > + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); > + > + return ret; > +} > + > +static int > +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()); } > + > +static int > +ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) { > + return ifpga_rawdev_destroy(pci_dev); > +} > + > +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { > + .id_table = pci_ifpga_map, > + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, > + .probe = ifpga_rawdev_pci_probe, > + .remove = ifpga_rawdev_pci_remove, > +}; > + > +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); > +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, > +rte_ifpga_rawdev_pmd); > +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | > +uio_pci_generic | vfio-pci"); > + > +RTE_INIT(ifpga_rawdev_init_log); > +static void > +ifpga_rawdev_init_log(void) > +{ > + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); > + if (ifpga_rawdev_logtype >= 0) > + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); } > + > +static const char * const valid_args[] = { > +#define IFPGA_ARG_NAME "ifpga" > + IFPGA_ARG_NAME, > +#define IFPGA_ARG_PORT "port" > + IFPGA_ARG_PORT, > +#define IFPGA_AFU_BTS "afu_bts" > + IFPGA_AFU_BTS, > + NULL > +}; > + > +static int > +ifpga_cfg_probe(struct rte_vdev_device *dev) { > + struct rte_devargs *devargs; > + struct rte_kvargs *kvlist = NULL; > + int port; > + char *name = NULL; > + char dev_name[RTE_RAWDEV_NAME_MAX_LEN]; > + > + devargs = dev->device.devargs; > + > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > + if (!kvlist) { > + IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param"); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { > + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, > + &rte_ifpga_get_string_arg, &name) < 0) { > + IFPGA_RAWDEV_PMD_ERR("error to parse %s", > + IFPGA_ARG_NAME); > + goto end; > + } > + } else { > + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_ARG_NAME); > + goto end; > + } > + > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > + if (rte_kvargs_process(kvlist, > + IFPGA_ARG_PORT, > + &rte_ifpga_get_integer32_arg, > + &port) < 0) { > + IFPGA_RAWDEV_PMD_ERR("error to parse %s", > + IFPGA_ARG_PORT); > + goto end; > + } > + } else { > + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", > + IFPGA_ARG_PORT); > + goto end; > + } > + > + memset(dev_name, 0, sizeof(dev_name)); > + snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s", > + port, name); > + > + rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), > + dev_name, devargs->args); > +end: > + if (kvlist) > + rte_kvargs_free(kvlist); > + if (name) > + free(name); > + > + return 0; > +} > + > +static int > +ifpga_cfg_remove(struct rte_vdev_device *vdev) { > + IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p", > + vdev); > + > + return 0; > +} > + > +static struct rte_vdev_driver ifpga_cfg_driver = { > + .probe = ifpga_cfg_probe, > + .remove = ifpga_cfg_remove, > +}; > + > +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); > +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); > +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, > + "bdf=<string> " > + "port=<int> " > + "afu_bts=<path>"); > + > diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > new file mode 100644 > index 0000000..c7759b8 > --- /dev/null > +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > @@ -0,0 +1,37 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2010-2018 Intel Corporation */ > + > +#ifndef _IFPGA_RAWDEV_H_ > +#define _IFPGA_RAWDEV_H_ > + > +extern int ifpga_rawdev_logtype; > + > +#define IFPGA_RAWDEV_PMD_LOG(level, fmt, args...) \ > + rte_log(RTE_LOG_ ## level, ifpga_rawdev_logtype, "ifgpa: " fmt, \ > + ##args) > + > +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() > IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") > + > +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ > + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) #define > +IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ > + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) #define > +IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ > + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) #define > +IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ > + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) > + > +enum ifpga_rawdev_device_state { > + IFPGA_IDLE, > + IFPGA_READY, > + IFPGA_ERROR > +}; > + > +static inline struct opae_adapter * > +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) { > + return rawdev->dev_private; > +} > + > +#endif /* _IFPGA_RAWDEV_H_ */ > diff --git a/drivers/raw/ifpga_rawdev/meson.build > b/drivers/raw/ifpga_rawdev/meson.build > new file mode 100644 > index 0000000..6725687 > --- /dev/null > +++ b/drivers/raw/ifpga_rawdev/meson.build > @@ -0,0 +1,15 @@ > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > +Corporation > + > +version = 1 > + > +subdir('base') > +objs = [base_objs] > + > +deps += ['rawdev', 'pci', 'bus_pci', 'kvargs', > + 'bus_vdev', 'bus_ifpga'] > +sources = files('ifpga_rawdev.c') > + > +includes += include_directories('base') > + > +allow_experimental_apis = true > diff --git a/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map > b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map > new file mode 100644 > index 0000000..9b9ab1a > --- /dev/null > +++ b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map > @@ -0,0 +1,4 @@ > +DPDK_18.05 { > + > + local: *; > +}; > diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build index > 34dfac4..a61cdcc 100644 > --- a/drivers/raw/meson.build > +++ b/drivers/raw/meson.build > @@ -1,7 +1,7 @@ > # SPDX-License-Identifier: BSD-3-Clause # Copyright 2018 NXP > > -drivers = ['skeleton_rawdev', 'dpaa2_cmdif', 'dpaa2_qdma'] > +drivers = ['skeleton_rawdev', 'dpaa2_cmdif', 'dpaa2_qdma', > +'ifpga_rawdev'] > std_deps = ['rawdev'] > config_flag_fmt = 'RTE_LIBRTE_PMD_@0@_RAWDEV' > driver_name_fmt = 'rte_pmd_@0@' > diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 3861e1a..acc0ec3 100644 > --- a/mk/rte.app.mk > +++ b/mk/rte.app.mk > @@ -256,9 +256,11 @@ > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += > -lrte_pmd_dpaa2_cmdif > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += > -lrte_pmd_dpaa2_qdma 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 > +endif # CONFIG_RTE_LIBRTE_IFPGA_BUS > endif # CONFIG_RTE_LIBRTE_RAWDEV > > - > endif # !CONFIG_RTE_BUILD_SHARED_LIBS > > _LDLIBS-y += --no-whole-archive > -- > 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-10 14:24 ` Zhang, Qi Z @ 2018-05-11 3:16 ` Xu, Rosen 2018-05-11 5:36 ` Zhang, Qi Z 0 siblings, 1 reply; 149+ messages in thread From: Xu, Rosen @ 2018-05-11 3:16 UTC (permalink / raw) To: Zhang, Qi Z, dev, thomas Cc: Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet, Wu, Yanglong Hi Qi, > -----Original Message----- > From: Zhang, Qi Z > Sent: Thursday, May 10, 2018 22:24 > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; thomas@monjalon.net > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com; Wu, Yanglong <yanglong.wu@intel.com> > Subject: RE: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev > Driver > > Hi Rosen: > > After read this patch, I have below suggestion > > 1. rte_ifgpa_device is not necessary, since we already have ifgpa bus, > it manages all devices on that bus, we don't need another abstraction to > manage afu devices, and user can add to or remove from the bus. Remove no used definition of rte_ifgpa_device > 2. rename rte_afu_device to rte_ifpga_device , we follow the name > rule. AFU is partial bit stream of FPGA, so AFU and FPGA are different definition. But we define global variables: ifpga_afu_dev_list > 3. data structure looks like below. > > Struct rte_ifpga_deivce { > rte_device device /* backing device */ > Rte_raw_device *device /* link to raw pci device */ > Struct Rte_afu_info info; /* afu information */ > } > > struct rte_afu_info { > struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > struct rte_afu_id id; /**< AFU id within FPGA. */ > uint32_t num_region; /**< number of regions found */ > .... > ... > } For there is not ifpga definition in our patch, so I still keep the definition of rte_afu_dev. Is it ok? > Regards > Qi > > > -----Original Message----- > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > > Sent: Wednesday, May 9, 2018 3:43 PM > > To: dev@dpdk.org; thomas@monjalon.net > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > > Richardson, Bruce <bruce.richardson@intel.com>; > > shreyansh.jain@nxp.com; Yigit, Ferruh <ferruh.yigit@intel.com>; > > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Tianfei > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > <hao.wu@intel.com>; gaetan.rivet@6wind.com; Wu, Yanglong > > <yanglong.wu@intel.com> > > Subject: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev > > Driver > > > > From: Rosen Xu <rosen.xu@intel.com> > > > > Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev library. > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> > > --- > > MAINTAINERS | 3 + > > config/common_base | 5 + > > doc/guides/rawdevs/ifpga_rawdev.rst | 112 ++++ > > doc/guides/rawdevs/index.rst | 1 + > > doc/guides/rel_notes/release_18_05.rst | 8 + > > drivers/raw/Makefile | 1 + > > drivers/raw/ifpga_rawdev/Makefile | 36 ++ > > drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 608 > > +++++++++++++++++++++ > > drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ > > drivers/raw/ifpga_rawdev/meson.build | 15 + > > .../ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map | 4 + > > drivers/raw/meson.build | 2 +- > > mk/rte.app.mk | 4 +- > > 13 files changed, 834 insertions(+), 2 deletions(-) create mode > > 100644 doc/guides/rawdevs/ifpga_rawdev.rst > > create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode > > 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c > > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > create mode 100644 drivers/raw/ifpga_rawdev/meson.build > > create mode 100644 > > drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map > > > > diff --git a/MAINTAINERS b/MAINTAINERS index 9c27d5a..a93ce9f 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -851,8 +851,11 @@ Rawdev Drivers > > -------------- > > > > Intel FPGA > > +M: Rosen Xu <rosen.xu@intel.com> > > M: Tianfei zhang <tianfei.zhang@intel.com> > > +F: drivers/raw/ifpga_rawdev/ > > F: drivers/raw/ifpga_rawdev/base/ > > +F: doc/guides/rawdevs/ifpga_rawdev.rst > > > > NXP DPAA2 QDMA > > M: Nipun Gupta <nipun.gupta@nxp.com> > > diff --git a/config/common_base b/config/common_base index > > 1440316..017a15a 100644 > > --- a/config/common_base > > +++ b/config/common_base > > @@ -633,6 +633,11 @@ > > CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV=n > > CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV=n > > > > # > > +# Compile PMD for Intel FPGA raw device # > > +CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV=y > > + > > +# > > # Compile librte_ring > > # > > CONFIG_RTE_LIBRTE_RING=y > > diff --git a/doc/guides/rawdevs/ifpga_rawdev.rst > > b/doc/guides/rawdevs/ifpga_rawdev.rst > > new file mode 100644 > > index 0000000..37ae4cc > > --- /dev/null > > +++ b/doc/guides/rawdevs/ifpga_rawdev.rst > > @@ -0,0 +1,112 @@ > > +.. SPDX-License-Identifier: BSD-3-Clause > > + Copyright(c) 2018 Intel Corporation. > > + > > +IFPGA Rawdev Driver > > +====================== > > + > > +FPGA is used more and more widely in Cloud and NFV, one primary > > +reason is that FPGA not only provides ASIC performance but also it's > > +more flexible than ASIC. > > + > > +FPGA uses Partial Reconfigure (PR) Parts of Bit Stream to achieve its > > +flexibility. That means one FPGA Device Bit Stream is divided into > > +many Parts of Bit Stream(each Part of Bit Stream is defined as > > +AFU-Accelerated Function Unit), and each AFU is a hardware > > +acceleration unit which can be dynamically reloaded respectively. > > + > > +By PR (Partial Reconfiguration) AFUs, one FPGA resources can be > > +time-shared by different users. FPGA hot upgrade and fault tolerance > > +can be > > provided easily. > > + > > +The SW IFPGA Rawdev Driver (**ifpga_rawdev**) provides a Rawdev > > +driver that utilizes Intel FPGA Software Stack OPAE(Open Programmable > > +Acceleration > > +Engine) for FPGA management. > > + > > +Implementation details > > +---------------------- > > + > > +Each instance of IFPGA Rawdev Driver is probed by Intel FpgaDev. In > > +coordination with OPAE share code IFPGA Rawdev Driver provides > common > > +FPGA management ops for FPGA operation, OPAE provides all following > > operations: > > +- FPGA PR (Partial Reconfiguration) management > > +- FPGA AFUs Identifying > > +- FPGA Thermal Management > > +- FPGA Power Management > > +- FPGA Performance reporting > > +- FPGA Remote Debug > > + > > +All configuration parameters are taken by vdev_ifpga_cfg driver. > > +Besides configuration, vdev_ifpga_cfg driver also hot plugs in IFPGA Bus. > > + > > +All of the AFUs of one FPGA may share same PCI BDF and AFUs scan > > +depend on IFPGA Rawdev Driver so IFPGA Bus takes AFU device scan and > > +AFU drivers > > probe. > > +All AFU device driver bind to AFU device by its UUID (Universally > > +Unique Identifier). > > + > > +To avoid unnecessary code duplication and ensure maximum > performance, > > +handling of AFU devices is left to different PMDs; all the design as > > +summarized by the following block diagram:: > > + > > + +---------------------------------------------------------------+ > > + | Application(s) > > | > > + +----------------------------.----------------------------------+ > > + | > > + | > > + +----------------------------'----------------------------------+ > > + | DPDK Framework (APIs) > > | > > + +----------|------------|--------.---------------------|--------+ > > + / \ | > > + / \ | > > + +-------'-------+ +-------'-------+ +--------'--------+ > > + | Eth PMD | | Crypto PMD | | > > | > > + +-------.-------+ +-------.-------+ | | > > + | | | > > | > > + | | | > > | > > + +-------'-------+ +-------'-------+ | IFPGA | > > + | Eth AFU Dev | |Crypto AFU Dev | | Rawdev Driver > > | > > + +-------.-------+ +-------.-------+ |(OPAE Share Code)| > > + | | | > > | > > + | | Rawdev | > > | > > + +-------'------------------'-------+ Ops | | > > + | IFPGA Bus | -------->| > > | > > + +-----------------.----------------+ +--------.--------+ > > + | | > > + Hot-plugin -->| | > > + | | > > + +-----------------'------------------+ +--------'--------+ > > + | vdev_ifpga_cfg driver | | Intel FpgaDev > > | > > + +------------------------------------+ +-----------------+ > > + > > +Build options > > +------------- > > + > > +- ``CONFIG_RTE_LIBRTE_IFPGA_BUS`` (default ``y``) > > + > > + Toggle compilation of IFPGA Bus library. > > + > > +- ``CONFIG_RTE_LIBRTE_IFPGA_RAWDEV`` (default ``y``) > > + > > + Toggle compilation of the ``ifpga_rawdev`` driver. > > + > > +Run-time parameters > > +------------------- > > + > > +This driver is invoked automatically in systems added with Intel > > +FPGA, but PR and IFPGA Bus scan is trigged by command line using > > +``--vdev 'net_ifpga_cfg`` EAL option. > > + > > +The following device parameters are supported: > > + > > +- ``ifpga`` [string] > > + > > + Provide a specific Intel FPGA device PCI BDF. Can be provided > > + multiple times for additional instances. > > + > > +- ``port`` [int] > > + > > + Each FPGA can provide many channels to PR AFU by software, each > > + channels is identified by this parameter. > > + > > +- ``afu_bts`` [string] > > + > > + If null, the AFU Bit Stream has been PR in FPGA, if not forces PR > > + and identifies AFU Bit Stream file. > > diff --git a/doc/guides/rawdevs/index.rst > > b/doc/guides/rawdevs/index.rst index 7769083..7c3bd95 100644 > > --- a/doc/guides/rawdevs/index.rst > > +++ b/doc/guides/rawdevs/index.rst > > @@ -13,3 +13,4 @@ application through rawdev API. > > > > dpaa2_cmdif > > dpaa2_qdma > > + ifpga_rawdev > > diff --git a/doc/guides/rel_notes/release_18_05.rst > > b/doc/guides/rel_notes/release_18_05.rst > > index 265950a..f5241a1 100644 > > --- a/doc/guides/rel_notes/release_18_05.rst > > +++ b/doc/guides/rel_notes/release_18_05.rst > > @@ -189,6 +189,14 @@ New Features > > the DPDK framework. It provides Intel FPGA Partial Bit Stream > > AFU(Accelerated > > Function Unit) scan and drivers prove. > > > > +* **Added IFPGA(Intel FPGA) Rawdev Driver.** > > + > > + Added a new Rawdev driver called IFPGA(Intel FPGA) Rawdev Driver, > > + which cooperates with OPAE(Open Programmable Acceleration Engine) > > + share code provides common FPGA management ops for FPGA operation. > > + > > + See the :doc:`../rawdevs/ifpga_rawdev` programmer's guide for more > > details. > > + > > API Changes > > ----------- > > > > diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index > > 2eb2787..8e29b4a 100644 > > --- a/drivers/raw/Makefile > > +++ b/drivers/raw/Makefile > > @@ -9,5 +9,6 @@ ifeq > > ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) > > DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += > dpaa2_cmdif > > DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += > dpaa2_qdma endif > > +DIRS-$(CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV) += ifpga_rawdev > > > > include $(RTE_SDK)/mk/rte.subdir.mk > > diff --git a/drivers/raw/ifpga_rawdev/Makefile > > b/drivers/raw/ifpga_rawdev/Makefile > > new file mode 100644 > > index 0000000..f3b9d5e > > --- /dev/null > > +++ b/drivers/raw/ifpga_rawdev/Makefile > > @@ -0,0 +1,36 @@ > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > > +Corporation > > + > > +include $(RTE_SDK)/mk/rte.vars.mk > > + > > +# > > +# library name > > +# > > +LIB = librte_pmd_ifpga_rawdev.a > > + > > +CFLAGS += -DALLOW_EXPERIMENTAL_API > > +CFLAGS += -O3 > > +CFLAGS += $(WERROR_FLAGS) > > +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga CFLAGS += > > +-I$(RTE_SDK)/drivers/raw/ifpga_rawdev > > +LDLIBS += -lrte_eal > > +LDLIBS += -lrte_rawdev > > +LDLIBS += -lrte_bus_vdev > > +LDLIBS += -lrte_kvargs > > +LDLIBS += -lrte_bus_pci > > +LDLIBS += -lrte_bus_ifpga > > + > > +EXPORT_MAP := rte_pmd_ifpga_rawdev_version.map > > + > > +LIBABIVER := 1 > > + > > +VPATH += $(SRCDIR)/base > > + > > +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile > > + > > +# > > +# all source are stored in SRCS-y > > +# > > +SRCS-$(CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV) += ifpga_rawdev.c > > + > > +include $(RTE_SDK)/mk/rte.lib.mk > > diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c > > b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c > > new file mode 100644 > > index 0000000..32e811c > > --- /dev/null > > +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c > > @@ -0,0 +1,608 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > +#include <string.h> > > +#include <dirent.h> > > +#include <sys/stat.h> > > +#include <unistd.h> > > +#include <sys/types.h> > > +#include <fcntl.h> > > +#include <rte_log.h> > > +#include <rte_bus.h> > > +#include <rte_eal_memconfig.h> > > +#include <rte_malloc.h> > > +#include <rte_devargs.h> > > +#include <rte_memcpy.h> > > +#include <rte_pci.h> > > +#include <rte_bus_pci.h> > > +#include <rte_kvargs.h> > > +#include <rte_alarm.h> > > + > > +#include <rte_errno.h> > > +#include <rte_per_lcore.h> > > +#include <rte_memory.h> > > +#include <rte_memzone.h> > > +#include <rte_eal.h> > > +#include <rte_common.h> > > +#include <rte_bus_vdev.h> > > + > > +#include "base/opae_hw_api.h" > > +#include "rte_rawdev.h" > > +#include "rte_rawdev_pmd.h" > > +#include "rte_bus_ifpga.h" > > +#include "ifpga_common.h" > > +#include "ifpga_logs.h" > > +#include "ifpga_rawdev.h" > > + > > +int ifpga_rawdev_logtype; > > + > > +#define PCI_VENDOR_ID_INTEL 0x8086 > > +/* PCI Device ID */ > > +#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 > > +/* 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 RTE_MAX_RAW_DEVICE 10 > > + > > +static const struct rte_pci_id pci_ifpga_map[] = { > > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, > > PCIE_DEVICE_ID_PF_INT_5_X) }, > > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, > > PCIE_DEVICE_ID_VF_INT_5_X) }, > > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, > > PCIE_DEVICE_ID_PF_INT_6_X) }, > > + { 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) }, > > + { .vendor_id = 0, /* sentinel */ }, > > +}; > > + > > +static int > > +ifpga_fill_afu_dev(struct opae_accelerator *acc, > > + struct rte_afu_device *afu_dev) > > +{ > > + struct rte_mem_resource *res = afu_dev->mem_resource; > > + struct opae_acc_region_info region_info; > > + struct opae_acc_info info; > > + unsigned long i; > > + int ret; > > + > > + ret = opae_acc_get_info(acc, &info); > > + if (ret) > > + return ret; > > + > > + if (info.num_regions > PCI_MAX_RESOURCE) > > + return -EFAULT; > > + > > + afu_dev->num_region = info.num_regions; > > + > > + for (i = 0; i < info.num_regions; i++) { > > + region_info.index = i; > > + ret = opae_acc_get_region_info(acc, ®ion_info); > > + if (ret) > > + return ret; > > + > > + if ((region_info.flags & ACC_REGION_MMIO) && > > + (region_info.flags & ACC_REGION_READ) && > > + (region_info.flags & ACC_REGION_WRITE)) { > > + res[i].phys_addr = region_info.phys_addr; > > + res[i].len = region_info.len; > > + res[i].addr = region_info.addr; > > + } else > > + return -EFAULT; > > + } > > + > > + return 0; > > +} > > + > > +static void > > +ifpga_rawdev_info_get(struct rte_rawdev *dev, > > + rte_rawdev_obj_t dev_info) > > +{ > > + struct opae_adapter *adapter; > > + struct opae_accelerator *acc; > > + struct rte_afu_device *afu_dev; > > + > > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > > + > > + if (!dev_info) { > > + IFPGA_RAWDEV_PMD_ERR("Invalid request"); > > + return; > > + } > > + > > + adapter = ifpga_rawdev_get_priv(dev); > > + if (!adapter) > > + return; > > + > > + afu_dev = dev_info; > > + afu_dev->rawdev = dev; > > + > > + /* find opae_accelerator and fill info into afu_device */ > > + opae_adapter_for_each_acc(adapter, acc) { > > + if (acc->index != afu_dev->id.port) > > + continue; > > + > > + if (ifpga_fill_afu_dev(acc, afu_dev)) { > > + IFPGA_RAWDEV_PMD_ERR("cannot get info\n"); > > + return; > > + } > > + } > > +} > > + > > +static int > > +ifpga_rawdev_start(struct rte_rawdev *dev) { > > + int ret = 0; > > + struct opae_adapter *adapter; > > + > > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > > + > > + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); > > + > > + adapter = ifpga_rawdev_get_priv(dev); > > + if (!adapter) > > + return -ENODEV; > > + > > + return ret; > > +} > > + > > +static void > > +ifpga_rawdev_stop(struct rte_rawdev *dev) { > > + dev->started = 0; > > +} > > + > > +static int > > +ifpga_rawdev_close(struct rte_rawdev *dev) { > > + return dev ? 0:1; > > +} > > + > > +static int > > +ifpga_rawdev_reset(struct rte_rawdev *dev) { > > + return dev ? 0:1; > > +} > > + > > +static int > > +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, > > + u64 *status) > > +{ > > + > > + struct opae_adapter *adapter; > > + struct opae_manager *mgr; > > + struct opae_accelerator *acc; > > + struct opae_bridge *br; > > + int ret; > > + > > + adapter = ifpga_rawdev_get_priv(raw_dev); > > + if (!adapter) > > + return -ENODEV; > > + > > + mgr = opae_adapter_get_mgr(adapter); > > + if (!mgr) > > + return -ENODEV; > > + > > + acc = opae_adapter_get_acc(adapter, port_id); > > + if (!acc) > > + return -ENODEV; > > + > > + br = opae_acc_get_br(acc); > > + if (!br) > > + return -ENODEV; > > + > > + ret = opae_manager_flash(mgr, port_id, buffer, size, status); > > + if (ret) { > > + IFPGA_RAWDEV_PMD_ERR("%s pr error %d\n", __func__, > ret); > > + return ret; > > + } > > + > > + ret = opae_bridge_reset(br); > > + if (ret) { > > + IFPGA_RAWDEV_PMD_ERR("%s reset port:%d error %d\n", > > + __func__, port_id, ret); > > + return ret; > > + } > > + > > + return ret; > > +} > > + > > +static int > > +rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, > > + const char *file_name) > > +{ > > + struct stat file_stat; > > + int file_fd; > > + int ret = 0; > > + u32 buffer_size; > > + void *buffer; > > + u64 pr_error; > > + > > + if (!file_name) > > + return -EINVAL; > > + > > + file_fd = open(file_name, O_RDONLY); > > + if (file_fd < 0) { > > + IFPGA_RAWDEV_PMD_ERR("%s: open file error: %s\n", > > + __func__, file_name); > > + IFPGA_RAWDEV_PMD_ERR("Message : %s\n", > strerror(errno)); > > + return -EINVAL; > > + } > > + ret = stat(file_name, &file_stat); > > + if (ret) { > > + IFPGA_RAWDEV_PMD_ERR("stat on bitstream file > failed: %s\n", > > + file_name); > > + return -EINVAL; > > + } > > + buffer_size = file_stat.st_size; > > + IFPGA_RAWDEV_PMD_INFO("bitstream file size: %u\n", buffer_size); > > + buffer = rte_malloc(NULL, buffer_size, 0); > > + if (!buffer) { > > + ret = -ENOMEM; > > + goto close_fd; > > + } > > + > > + /*read the raw data*/ > > + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { > > + ret = -EINVAL; > > + goto free_buffer; > > + } > > + > > + /*do PR now*/ > > + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); > > + IFPGA_RAWDEV_PMD_INFO("downloading to device > port %d....%s.\n", > > port_id, > > + ret ? "failed" : "success"); > > + if (ret) { > > + ret = -EINVAL; > > + goto free_buffer; > > + } > > + > > +free_buffer: > > + if (buffer) > > + rte_free(buffer); > > +close_fd: > > + close(file_fd); > > + file_fd = 0; > > + return ret; > > +} > > + > > +static int > > +ifpga_rawdev_pr(struct rte_rawdev *dev, > > + rte_rawdev_obj_t pr_conf) > > +{ > > + struct opae_adapter *adapter; > > + struct rte_afu_pr_conf *afu_pr_conf; > > + int ret; > > + struct uuid uuid; > > + struct opae_accelerator *acc; > > + > > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > > + > > + adapter = ifpga_rawdev_get_priv(dev); > > + if (!adapter) > > + return -ENODEV; > > + > > + if (!pr_conf) > > + return -EINVAL; > > + > > + afu_pr_conf = pr_conf; > > + > > + if (afu_pr_conf->pr_enable) { > > + ret = rte_fpga_do_pr(dev, > > + afu_pr_conf->afu_id.port, > > + afu_pr_conf->bs_path); > > + if (ret) { > > + IFPGA_RAWDEV_PMD_ERR("do pr error %d\n", ret); > > + return ret; > > + } > > + } > > + > > + acc = opae_adapter_get_acc(adapter, afu_pr_conf->afu_id.port); > > + if (!acc) > > + return -ENODEV; > > + > > + ret = opae_acc_get_uuid(acc, &uuid); > > + if (ret) > > + return ret; > > + > > + memcpy(&afu_pr_conf->afu_id.uuid.uuid_low, uuid.b, sizeof(u64)); > > + memcpy(&afu_pr_conf->afu_id.uuid.uuid_high, uuid.b + 8, > > +sizeof(u64)); > > + > > + IFPGA_RAWDEV_PMD_INFO("%s: uuid_l=0x%lx, uuid_h=0x%lx\n", > > __func__, > > + (u64)afu_pr_conf->afu_id.uuid.uuid_low, > > + (u64)afu_pr_conf->afu_id.uuid.uuid_high); > > + > > + return 0; > > +} > > + > > +static const struct rte_rawdev_ops ifpga_rawdev_ops = { > > + .dev_info_get = ifpga_rawdev_info_get, > > + .dev_configure = NULL, > > + .dev_start = ifpga_rawdev_start, > > + .dev_stop = ifpga_rawdev_stop, > > + .dev_close = ifpga_rawdev_close, > > + .dev_reset = ifpga_rawdev_reset, > > + > > + .queue_def_conf = NULL, > > + .queue_setup = NULL, > > + .queue_release = NULL, > > + > > + .attr_get = NULL, > > + .attr_set = NULL, > > + > > + .enqueue_bufs = NULL, > > + .dequeue_bufs = NULL, > > + > > + .dump = NULL, > > + > > + .xstats_get = NULL, > > + .xstats_get_names = NULL, > > + .xstats_get_by_name = NULL, > > + .xstats_reset = NULL, > > + > > + .firmware_status_get = NULL, > > + .firmware_version_get = NULL, > > + .firmware_load = ifpga_rawdev_pr, > > + .firmware_unload = NULL, > > + > > + .dev_selftest = NULL, > > +}; > > + > > +static int > > +ifpga_rawdev_create(struct rte_pci_device *pci_dev, > > + int socket_id) > > +{ > > + int ret = 0; > > + struct rte_rawdev *rawdev = NULL; > > + struct opae_adapter *adapter = NULL; > > + struct opae_manager *mgr = NULL; > > + struct opae_adapter_data_pci *data = NULL; > > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > > + int i; > > + > > + if (!pci_dev) { > > + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); > > + ret = -EINVAL; > > + goto cleanup; > > + } > > + > > + memset(name, 0, sizeof(name)); > > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, > "IFPGA:%x:%02x.%x", > > + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev- > >addr.function); > > + > > + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, > > +rte_socket_id()); > > + > > + /* Allocate device structure */ > > + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct > opae_adapter), > > + socket_id); > > + if (rawdev == NULL) { > > + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); > > + ret = -EINVAL; > > + goto cleanup; > > + } > > + > > + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API > */ > > + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); > > + if (!data) { > > + ret = -ENOMEM; > > + goto cleanup; > > + } > > + > > + /* init opae_adapter_data_pci for device specific information */ > > + for (i = 0; i < PCI_MAX_RESOURCE; i++) { > > + data->region[i].phys_addr = pci_dev- > >mem_resource[i].phys_addr; > > + data->region[i].len = pci_dev->mem_resource[i].len; > > + data->region[i].addr = pci_dev->mem_resource[i].addr; > > + } > > + data->device_id = pci_dev->id.device_id; > > + data->vendor_id = pci_dev->id.vendor_id; > > + > > + /* create a opae_adapter based on above device data */ > > + adapter = opae_adapter_alloc(pci_dev->device.name, data); > > + if (!adapter) { > > + ret = -ENOMEM; > > + goto free_adapter_data; > > + } > > + > > + rawdev->dev_ops = &ifpga_rawdev_ops; > > + rawdev->device = &pci_dev->device; > > + rawdev->driver_name = pci_dev->device.driver->name; > > + > > + rawdev->dev_private = adapter; > > + > > + /* must enumerate the adapter before use it */ > > + ret = opae_adapter_enumerate(adapter); > > + if (ret) > > + goto free_adapter; > > + > > + /* get opae_manager to rawdev */ > > + mgr = opae_adapter_get_mgr(adapter); > > + if (mgr) { > > + /* PF function */ > > + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); > > + } > > + > > + return ret; > > + > > +free_adapter: > > + if (adapter) > > + opae_adapter_free(adapter); > > +free_adapter_data: > > + if (data) > > + opae_adapter_data_free(data); > > +cleanup: > > + if (rawdev) > > + rte_rawdev_pmd_release(rawdev); > > + > > + return ret; > > +} > > + > > +static int > > +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) { > > + int ret; > > + struct rte_rawdev *rawdev; > > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > > + struct opae_adapter *adapter; > > + > > + if (!pci_dev) { > > + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); > > + ret = -EINVAL; > > + return ret; > > + } > > + > > + memset(name, 0, sizeof(name)); > > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, > "IFPGA:%x:%02x.%x", > > + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev- > >addr.function); > > + > > + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", > > + name, rte_socket_id()); > > + > > + rawdev = rte_rawdev_pmd_get_named_dev(name); > > + if (!rawdev) { > > + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", > name); > > + return -EINVAL; > > + } > > + > > + adapter = ifpga_rawdev_get_priv(rawdev); > > + if (!adapter) > > + return -ENODEV; > > + > > + opae_adapter_data_free(adapter->data); > > + opae_adapter_free(adapter); > > + > > + /* rte_rawdev_close is called by pmd_release */ > > + ret = rte_rawdev_pmd_release(rawdev); > > + if (ret) > > + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); > > + > > + return ret; > > +} > > + > > +static int > > +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()); } > > + > > +static int > > +ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) { > > + return ifpga_rawdev_destroy(pci_dev); } > > + > > +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { > > + .id_table = pci_ifpga_map, > > + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | > RTE_PCI_DRV_INTR_LSC, > > + .probe = ifpga_rawdev_pci_probe, > > + .remove = ifpga_rawdev_pci_remove, > > +}; > > + > > +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, > rte_ifpga_rawdev_pmd); > > +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, > > +rte_ifpga_rawdev_pmd); > > +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | > > +uio_pci_generic | vfio-pci"); > > + > > +RTE_INIT(ifpga_rawdev_init_log); > > +static void > > +ifpga_rawdev_init_log(void) > > +{ > > + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); > > + if (ifpga_rawdev_logtype >= 0) > > + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); } > > + > > +static const char * const valid_args[] = { > > +#define IFPGA_ARG_NAME "ifpga" > > + IFPGA_ARG_NAME, > > +#define IFPGA_ARG_PORT "port" > > + IFPGA_ARG_PORT, > > +#define IFPGA_AFU_BTS "afu_bts" > > + IFPGA_AFU_BTS, > > + NULL > > +}; > > + > > +static int > > +ifpga_cfg_probe(struct rte_vdev_device *dev) { > > + struct rte_devargs *devargs; > > + struct rte_kvargs *kvlist = NULL; > > + int port; > > + char *name = NULL; > > + char dev_name[RTE_RAWDEV_NAME_MAX_LEN]; > > + > > + devargs = dev->device.devargs; > > + > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > + if (!kvlist) { > > + IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing > param"); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, > > + &rte_ifpga_get_string_arg, &name) < 0) { > > + IFPGA_RAWDEV_PMD_ERR("error to parse %s", > > + IFPGA_ARG_NAME); > > + goto end; > > + } > > + } else { > > + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga > bus", > > + IFPGA_ARG_NAME); > > + goto end; > > + } > > + > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > > + if (rte_kvargs_process(kvlist, > > + IFPGA_ARG_PORT, > > + &rte_ifpga_get_integer32_arg, > > + &port) < 0) { > > + IFPGA_RAWDEV_PMD_ERR("error to parse %s", > > + IFPGA_ARG_PORT); > > + goto end; > > + } > > + } else { > > + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga > bus", > > + IFPGA_ARG_PORT); > > + goto end; > > + } > > + > > + memset(dev_name, 0, sizeof(dev_name)); > > + snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s", > > + port, name); > > + > > + rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), > > + dev_name, devargs->args); > > +end: > > + if (kvlist) > > + rte_kvargs_free(kvlist); > > + if (name) > > + free(name); > > + > > + return 0; > > +} > > + > > +static int > > +ifpga_cfg_remove(struct rte_vdev_device *vdev) { > > + IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p", > > + vdev); > > + > > + return 0; > > +} > > + > > +static struct rte_vdev_driver ifpga_cfg_driver = { > > + .probe = ifpga_cfg_probe, > > + .remove = ifpga_cfg_remove, > > +}; > > + > > +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); > > +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); > > +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, > > + "bdf=<string> " > > + "port=<int> " > > + "afu_bts=<path>"); > > + > > diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > new file mode 100644 > > index 0000000..c7759b8 > > --- /dev/null > > +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > @@ -0,0 +1,37 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause > > + * Copyright(c) 2010-2018 Intel Corporation */ > > + > > +#ifndef _IFPGA_RAWDEV_H_ > > +#define _IFPGA_RAWDEV_H_ > > + > > +extern int ifpga_rawdev_logtype; > > + > > +#define IFPGA_RAWDEV_PMD_LOG(level, fmt, args...) \ > > + rte_log(RTE_LOG_ ## level, ifpga_rawdev_logtype, "ifgpa: " fmt, \ > > + ##args) > > + > > +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() > > IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") > > + > > +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ > > + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) #define > > +IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ > > + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) #define > > +IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ > > + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) #define > > +IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ > > + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) > > + > > +enum ifpga_rawdev_device_state { > > + IFPGA_IDLE, > > + IFPGA_READY, > > + IFPGA_ERROR > > +}; > > + > > +static inline struct opae_adapter * > > +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) { > > + return rawdev->dev_private; > > +} > > + > > +#endif /* _IFPGA_RAWDEV_H_ */ > > diff --git a/drivers/raw/ifpga_rawdev/meson.build > > b/drivers/raw/ifpga_rawdev/meson.build > > new file mode 100644 > > index 0000000..6725687 > > --- /dev/null > > +++ b/drivers/raw/ifpga_rawdev/meson.build > > @@ -0,0 +1,15 @@ > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > > +Corporation > > + > > +version = 1 > > + > > +subdir('base') > > +objs = [base_objs] > > + > > +deps += ['rawdev', 'pci', 'bus_pci', 'kvargs', > > + 'bus_vdev', 'bus_ifpga'] > > +sources = files('ifpga_rawdev.c') > > + > > +includes += include_directories('base') > > + > > +allow_experimental_apis = true > > diff --git a/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map > > b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map > > new file mode 100644 > > index 0000000..9b9ab1a > > --- /dev/null > > +++ b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map > > @@ -0,0 +1,4 @@ > > +DPDK_18.05 { > > + > > + local: *; > > +}; > > diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build index > > 34dfac4..a61cdcc 100644 > > --- a/drivers/raw/meson.build > > +++ b/drivers/raw/meson.build > > @@ -1,7 +1,7 @@ > > # SPDX-License-Identifier: BSD-3-Clause # Copyright 2018 NXP > > > > -drivers = ['skeleton_rawdev', 'dpaa2_cmdif', 'dpaa2_qdma'] > > +drivers = ['skeleton_rawdev', 'dpaa2_cmdif', 'dpaa2_qdma', > > +'ifpga_rawdev'] > > std_deps = ['rawdev'] > > config_flag_fmt = 'RTE_LIBRTE_PMD_@0@_RAWDEV' > > driver_name_fmt = 'rte_pmd_@0@' > > diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 3861e1a..acc0ec3 > > 100644 > > --- a/mk/rte.app.mk > > +++ b/mk/rte.app.mk > > @@ -256,9 +256,11 @@ > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += > > -lrte_pmd_dpaa2_cmdif > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += > > -lrte_pmd_dpaa2_qdma 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 > > +endif # CONFIG_RTE_LIBRTE_IFPGA_BUS > > endif # CONFIG_RTE_LIBRTE_RAWDEV > > > > - > > endif # !CONFIG_RTE_BUILD_SHARED_LIBS > > > > _LDLIBS-y += --no-whole-archive > > -- > > 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-11 3:16 ` Xu, Rosen @ 2018-05-11 5:36 ` Zhang, Qi Z 0 siblings, 0 replies; 149+ messages in thread From: Zhang, Qi Z @ 2018-05-11 5:36 UTC (permalink / raw) To: Xu, Rosen, dev, thomas Cc: Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet, Wu, Yanglong > -----Original Message----- > From: Xu, Rosen > Sent: Friday, May 11, 2018 11:17 AM > To: Zhang, Qi Z <qi.z.zhang@intel.com>; dev@dpdk.org; > thomas@monjalon.net > Cc: Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, Declan > <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com; Wu, Yanglong <yanglong.wu@intel.com> > Subject: RE: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev > Driver > > Hi Qi, > > > -----Original Message----- > > From: Zhang, Qi Z > > Sent: Thursday, May 10, 2018 22:24 > > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; > thomas@monjalon.net > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > > Richardson, Bruce <bruce.richardson@intel.com>; > > shreyansh.jain@nxp.com; Yigit, Ferruh <ferruh.yigit@intel.com>; > > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Tianfei > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > <hao.wu@intel.com>; gaetan.rivet@6wind.com; Wu, Yanglong > > <yanglong.wu@intel.com> > > Subject: RE: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS > > Rawdev Driver > > > > Hi Rosen: > > > > After read this patch, I have below suggestion > > > > 1. rte_ifgpa_device is not necessary, since we already have ifgpa > > bus, it manages all devices on that bus, we don't need another > > abstraction to manage afu devices, and user can add to or remove from the > bus. > > Remove no used definition of rte_ifgpa_device OK > > > 2. rename rte_afu_device to rte_ifpga_device , we follow the name > > rule. > > AFU is partial bit stream of FPGA, so AFU and FPGA are different definition. > But we define global variables: ifpga_afu_dev_list I think ifpga is an abstract bus, we could have rte_ifpga_device as an abstract device type, afu is the physical resource the abstract device link to, Name rte_afu_device on ifpga bus looks not consistent to me. Regards Qi > > > 3. data structure looks like below. > > > > Struct rte_ifpga_deivce { > > rte_device device /* backing device */ > > Rte_raw_device *device /* link to raw pci device */ > > Struct Rte_afu_info info; /* afu information */ > > } > > > > struct rte_afu_info { > > struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ > > struct rte_afu_id id; /**< AFU id within FPGA. > */ > > uint32_t num_region; /**< number of regions found */ > > .... > > ... > > } > > For there is not ifpga definition in our patch, so I still keep the definition of > rte_afu_dev. > Is it ok? > > > Regards > > Qi > > > > > -----Original Message----- > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > > > Sent: Wednesday, May 9, 2018 3:43 PM > > > To: dev@dpdk.org; thomas@monjalon.net > > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > > <roy.fan.zhang@intel.com>; Doherty, Declan > > > <declan.doherty@intel.com>; Richardson, Bruce > > > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > > > <ferruh.yigit@intel.com>; Ananyev, Konstantin > > > <konstantin.ananyev@intel.com>; Zhang, Tianfei > > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > > <hao.wu@intel.com>; gaetan.rivet@6wind.com; Wu, Yanglong > > > <yanglong.wu@intel.com> > > > Subject: [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev > > > Driver > > > > > > From: Rosen Xu <rosen.xu@intel.com> > > > > > > Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev library. > > > > > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > > Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> > > > Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> > > > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> > > > --- > > > MAINTAINERS | 3 + > > > config/common_base | 5 + > > > doc/guides/rawdevs/ifpga_rawdev.rst | 112 ++++ > > > doc/guides/rawdevs/index.rst | 1 + > > > doc/guides/rel_notes/release_18_05.rst | 8 + > > > drivers/raw/Makefile | 1 + > > > drivers/raw/ifpga_rawdev/Makefile | 36 ++ > > > drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 608 > > > +++++++++++++++++++++ > > > drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ > > > drivers/raw/ifpga_rawdev/meson.build | 15 + > > > .../ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map | 4 + > > > drivers/raw/meson.build | 2 +- > > > mk/rte.app.mk | 4 +- > > > 13 files changed, 834 insertions(+), 2 deletions(-) create mode > > > 100644 doc/guides/rawdevs/ifpga_rawdev.rst > > > create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode > > > 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c > > > create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > > create mode 100644 drivers/raw/ifpga_rawdev/meson.build > > > create mode 100644 > > > drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map > > > > > > diff --git a/MAINTAINERS b/MAINTAINERS index 9c27d5a..a93ce9f 100644 > > > --- a/MAINTAINERS > > > +++ b/MAINTAINERS > > > @@ -851,8 +851,11 @@ Rawdev Drivers > > > -------------- > > > > > > Intel FPGA > > > +M: Rosen Xu <rosen.xu@intel.com> > > > M: Tianfei zhang <tianfei.zhang@intel.com> > > > +F: drivers/raw/ifpga_rawdev/ > > > F: drivers/raw/ifpga_rawdev/base/ > > > +F: doc/guides/rawdevs/ifpga_rawdev.rst > > > > > > NXP DPAA2 QDMA > > > M: Nipun Gupta <nipun.gupta@nxp.com> diff --git > > > a/config/common_base b/config/common_base index 1440316..017a15a > > > 100644 > > > --- a/config/common_base > > > +++ b/config/common_base > > > @@ -633,6 +633,11 @@ > > > CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV=n > > > CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV=n > > > > > > # > > > +# Compile PMD for Intel FPGA raw device # > > > +CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV=y > > > + > > > +# > > > # Compile librte_ring > > > # > > > CONFIG_RTE_LIBRTE_RING=y > > > diff --git a/doc/guides/rawdevs/ifpga_rawdev.rst > > > b/doc/guides/rawdevs/ifpga_rawdev.rst > > > new file mode 100644 > > > index 0000000..37ae4cc > > > --- /dev/null > > > +++ b/doc/guides/rawdevs/ifpga_rawdev.rst > > > @@ -0,0 +1,112 @@ > > > +.. SPDX-License-Identifier: BSD-3-Clause > > > + Copyright(c) 2018 Intel Corporation. > > > + > > > +IFPGA Rawdev Driver > > > +====================== > > > + > > > +FPGA is used more and more widely in Cloud and NFV, one primary > > > +reason is that FPGA not only provides ASIC performance but also > > > +it's more flexible than ASIC. > > > + > > > +FPGA uses Partial Reconfigure (PR) Parts of Bit Stream to achieve > > > +its flexibility. That means one FPGA Device Bit Stream is divided > > > +into many Parts of Bit Stream(each Part of Bit Stream is defined as > > > +AFU-Accelerated Function Unit), and each AFU is a hardware > > > +acceleration unit which can be dynamically reloaded respectively. > > > + > > > +By PR (Partial Reconfiguration) AFUs, one FPGA resources can be > > > +time-shared by different users. FPGA hot upgrade and fault > > > +tolerance can be > > > provided easily. > > > + > > > +The SW IFPGA Rawdev Driver (**ifpga_rawdev**) provides a Rawdev > > > +driver that utilizes Intel FPGA Software Stack OPAE(Open > > > +Programmable Acceleration > > > +Engine) for FPGA management. > > > + > > > +Implementation details > > > +---------------------- > > > + > > > +Each instance of IFPGA Rawdev Driver is probed by Intel FpgaDev. In > > > +coordination with OPAE share code IFPGA Rawdev Driver provides > > common > > > +FPGA management ops for FPGA operation, OPAE provides all following > > > operations: > > > +- FPGA PR (Partial Reconfiguration) management > > > +- FPGA AFUs Identifying > > > +- FPGA Thermal Management > > > +- FPGA Power Management > > > +- FPGA Performance reporting > > > +- FPGA Remote Debug > > > + > > > +All configuration parameters are taken by vdev_ifpga_cfg driver. > > > +Besides configuration, vdev_ifpga_cfg driver also hot plugs in IFPGA Bus. > > > + > > > +All of the AFUs of one FPGA may share same PCI BDF and AFUs scan > > > +depend on IFPGA Rawdev Driver so IFPGA Bus takes AFU device scan > > > +and AFU drivers > > > probe. > > > +All AFU device driver bind to AFU device by its UUID (Universally > > > +Unique Identifier). > > > + > > > +To avoid unnecessary code duplication and ensure maximum > > performance, > > > +handling of AFU devices is left to different PMDs; all the design > > > +as summarized by the following block diagram:: > > > + > > > + +---------------------------------------------------------------+ > > > + | Application(s) > > > | > > > + +----------------------------.----------------------------------+ > > > + | > > > + | > > > + +----------------------------'----------------------------------+ > > > + | DPDK Framework (APIs) > > > | > > > + +----------|------------|--------.---------------------|--------+ > > > + / \ | > > > + / \ | > > > + +-------'-------+ +-------'-------+ +--------'--------+ > > > + | Eth PMD | | Crypto PMD | | > > > | > > > + +-------.-------+ +-------.-------+ | | > > > + | | | > > > | > > > + | | | > > > | > > > + +-------'-------+ +-------'-------+ | IFPGA | > > > + | Eth AFU Dev | |Crypto AFU Dev | | Rawdev > Driver > > > | > > > + +-------.-------+ +-------.-------+ |(OPAE Share Code)| > > > + | | | > > > | > > > + | | Rawdev | > > > | > > > + +-------'------------------'-------+ Ops | | > > > + | IFPGA Bus | -------->| > > > | > > > + +-----------------.----------------+ +--------.--------+ > > > + | | > > > + Hot-plugin -->| | > > > + | | > > > + +-----------------'------------------+ +--------'--------+ > > > + | vdev_ifpga_cfg driver | | Intel > FpgaDev > > > | > > > + +------------------------------------+ +-----------------+ > > > + > > > +Build options > > > +------------- > > > + > > > +- ``CONFIG_RTE_LIBRTE_IFPGA_BUS`` (default ``y``) > > > + > > > + Toggle compilation of IFPGA Bus library. > > > + > > > +- ``CONFIG_RTE_LIBRTE_IFPGA_RAWDEV`` (default ``y``) > > > + > > > + Toggle compilation of the ``ifpga_rawdev`` driver. > > > + > > > +Run-time parameters > > > +------------------- > > > + > > > +This driver is invoked automatically in systems added with Intel > > > +FPGA, but PR and IFPGA Bus scan is trigged by command line using > > > +``--vdev 'net_ifpga_cfg`` EAL option. > > > + > > > +The following device parameters are supported: > > > + > > > +- ``ifpga`` [string] > > > + > > > + Provide a specific Intel FPGA device PCI BDF. Can be provided > > > + multiple times for additional instances. > > > + > > > +- ``port`` [int] > > > + > > > + Each FPGA can provide many channels to PR AFU by software, each > > > + channels is identified by this parameter. > > > + > > > +- ``afu_bts`` [string] > > > + > > > + If null, the AFU Bit Stream has been PR in FPGA, if not forces PR > > > + and identifies AFU Bit Stream file. > > > diff --git a/doc/guides/rawdevs/index.rst > > > b/doc/guides/rawdevs/index.rst index 7769083..7c3bd95 100644 > > > --- a/doc/guides/rawdevs/index.rst > > > +++ b/doc/guides/rawdevs/index.rst > > > @@ -13,3 +13,4 @@ application through rawdev API. > > > > > > dpaa2_cmdif > > > dpaa2_qdma > > > + ifpga_rawdev > > > diff --git a/doc/guides/rel_notes/release_18_05.rst > > > b/doc/guides/rel_notes/release_18_05.rst > > > index 265950a..f5241a1 100644 > > > --- a/doc/guides/rel_notes/release_18_05.rst > > > +++ b/doc/guides/rel_notes/release_18_05.rst > > > @@ -189,6 +189,14 @@ New Features > > > the DPDK framework. It provides Intel FPGA Partial Bit Stream > > > AFU(Accelerated > > > Function Unit) scan and drivers prove. > > > > > > +* **Added IFPGA(Intel FPGA) Rawdev Driver.** > > > + > > > + Added a new Rawdev driver called IFPGA(Intel FPGA) Rawdev Driver, > > > + which cooperates with OPAE(Open Programmable Acceleration Engine) > > > + share code provides common FPGA management ops for FPGA > operation. > > > + > > > + See the :doc:`../rawdevs/ifpga_rawdev` programmer's guide for > > > + more > > > details. > > > + > > > API Changes > > > ----------- > > > > > > diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index > > > 2eb2787..8e29b4a 100644 > > > --- a/drivers/raw/Makefile > > > +++ b/drivers/raw/Makefile > > > @@ -9,5 +9,6 @@ ifeq > > > ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) > > > DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += > > dpaa2_cmdif > > > DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += > > dpaa2_qdma endif > > > +DIRS-$(CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV) += ifpga_rawdev > > > > > > include $(RTE_SDK)/mk/rte.subdir.mk diff --git > > > a/drivers/raw/ifpga_rawdev/Makefile > > > b/drivers/raw/ifpga_rawdev/Makefile > > > new file mode 100644 > > > index 0000000..f3b9d5e > > > --- /dev/null > > > +++ b/drivers/raw/ifpga_rawdev/Makefile > > > @@ -0,0 +1,36 @@ > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > > > +Corporation > > > + > > > +include $(RTE_SDK)/mk/rte.vars.mk > > > + > > > +# > > > +# library name > > > +# > > > +LIB = librte_pmd_ifpga_rawdev.a > > > + > > > +CFLAGS += -DALLOW_EXPERIMENTAL_API > > > +CFLAGS += -O3 > > > +CFLAGS += $(WERROR_FLAGS) > > > +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga CFLAGS += > > > +-I$(RTE_SDK)/drivers/raw/ifpga_rawdev > > > +LDLIBS += -lrte_eal > > > +LDLIBS += -lrte_rawdev > > > +LDLIBS += -lrte_bus_vdev > > > +LDLIBS += -lrte_kvargs > > > +LDLIBS += -lrte_bus_pci > > > +LDLIBS += -lrte_bus_ifpga > > > + > > > +EXPORT_MAP := rte_pmd_ifpga_rawdev_version.map > > > + > > > +LIBABIVER := 1 > > > + > > > +VPATH += $(SRCDIR)/base > > > + > > > +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile > > > + > > > +# > > > +# all source are stored in SRCS-y > > > +# > > > +SRCS-$(CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV) += ifpga_rawdev.c > > > + > > > +include $(RTE_SDK)/mk/rte.lib.mk > > > diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c > > > b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c > > > new file mode 100644 > > > index 0000000..32e811c > > > --- /dev/null > > > +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c > > > @@ -0,0 +1,608 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > + > > > +#include <string.h> > > > +#include <dirent.h> > > > +#include <sys/stat.h> > > > +#include <unistd.h> > > > +#include <sys/types.h> > > > +#include <fcntl.h> > > > +#include <rte_log.h> > > > +#include <rte_bus.h> > > > +#include <rte_eal_memconfig.h> > > > +#include <rte_malloc.h> > > > +#include <rte_devargs.h> > > > +#include <rte_memcpy.h> > > > +#include <rte_pci.h> > > > +#include <rte_bus_pci.h> > > > +#include <rte_kvargs.h> > > > +#include <rte_alarm.h> > > > + > > > +#include <rte_errno.h> > > > +#include <rte_per_lcore.h> > > > +#include <rte_memory.h> > > > +#include <rte_memzone.h> > > > +#include <rte_eal.h> > > > +#include <rte_common.h> > > > +#include <rte_bus_vdev.h> > > > + > > > +#include "base/opae_hw_api.h" > > > +#include "rte_rawdev.h" > > > +#include "rte_rawdev_pmd.h" > > > +#include "rte_bus_ifpga.h" > > > +#include "ifpga_common.h" > > > +#include "ifpga_logs.h" > > > +#include "ifpga_rawdev.h" > > > + > > > +int ifpga_rawdev_logtype; > > > + > > > +#define PCI_VENDOR_ID_INTEL 0x8086 > > > +/* PCI Device ID */ > > > +#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 > > > +/* 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 RTE_MAX_RAW_DEVICE 10 > > > + > > > +static const struct rte_pci_id pci_ifpga_map[] = { > > > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, > > > PCIE_DEVICE_ID_PF_INT_5_X) }, > > > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, > > > PCIE_DEVICE_ID_VF_INT_5_X) }, > > > + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, > > > PCIE_DEVICE_ID_PF_INT_6_X) }, > > > + { 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) }, > > > + { .vendor_id = 0, /* sentinel */ }, }; > > > + > > > +static int > > > +ifpga_fill_afu_dev(struct opae_accelerator *acc, > > > + struct rte_afu_device *afu_dev) > > > +{ > > > + struct rte_mem_resource *res = afu_dev->mem_resource; > > > + struct opae_acc_region_info region_info; > > > + struct opae_acc_info info; > > > + unsigned long i; > > > + int ret; > > > + > > > + ret = opae_acc_get_info(acc, &info); > > > + if (ret) > > > + return ret; > > > + > > > + if (info.num_regions > PCI_MAX_RESOURCE) > > > + return -EFAULT; > > > + > > > + afu_dev->num_region = info.num_regions; > > > + > > > + for (i = 0; i < info.num_regions; i++) { > > > + region_info.index = i; > > > + ret = opae_acc_get_region_info(acc, ®ion_info); > > > + if (ret) > > > + return ret; > > > + > > > + if ((region_info.flags & ACC_REGION_MMIO) && > > > + (region_info.flags & ACC_REGION_READ) && > > > + (region_info.flags & ACC_REGION_WRITE)) { > > > + res[i].phys_addr = region_info.phys_addr; > > > + res[i].len = region_info.len; > > > + res[i].addr = region_info.addr; > > > + } else > > > + return -EFAULT; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +static void > > > +ifpga_rawdev_info_get(struct rte_rawdev *dev, > > > + rte_rawdev_obj_t dev_info) { > > > + struct opae_adapter *adapter; > > > + struct opae_accelerator *acc; > > > + struct rte_afu_device *afu_dev; > > > + > > > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > > > + > > > + if (!dev_info) { > > > + IFPGA_RAWDEV_PMD_ERR("Invalid request"); > > > + return; > > > + } > > > + > > > + adapter = ifpga_rawdev_get_priv(dev); > > > + if (!adapter) > > > + return; > > > + > > > + afu_dev = dev_info; > > > + afu_dev->rawdev = dev; > > > + > > > + /* find opae_accelerator and fill info into afu_device */ > > > + opae_adapter_for_each_acc(adapter, acc) { > > > + if (acc->index != afu_dev->id.port) > > > + continue; > > > + > > > + if (ifpga_fill_afu_dev(acc, afu_dev)) { > > > + IFPGA_RAWDEV_PMD_ERR("cannot get info\n"); > > > + return; > > > + } > > > + } > > > +} > > > + > > > +static int > > > +ifpga_rawdev_start(struct rte_rawdev *dev) { > > > + int ret = 0; > > > + struct opae_adapter *adapter; > > > + > > > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > > > + > > > + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); > > > + > > > + adapter = ifpga_rawdev_get_priv(dev); > > > + if (!adapter) > > > + return -ENODEV; > > > + > > > + return ret; > > > +} > > > + > > > +static void > > > +ifpga_rawdev_stop(struct rte_rawdev *dev) { > > > + dev->started = 0; > > > +} > > > + > > > +static int > > > +ifpga_rawdev_close(struct rte_rawdev *dev) { > > > + return dev ? 0:1; > > > +} > > > + > > > +static int > > > +ifpga_rawdev_reset(struct rte_rawdev *dev) { > > > + return dev ? 0:1; > > > +} > > > + > > > +static int > > > +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, > > > + u64 *status) > > > +{ > > > + > > > + struct opae_adapter *adapter; > > > + struct opae_manager *mgr; > > > + struct opae_accelerator *acc; > > > + struct opae_bridge *br; > > > + int ret; > > > + > > > + adapter = ifpga_rawdev_get_priv(raw_dev); > > > + if (!adapter) > > > + return -ENODEV; > > > + > > > + mgr = opae_adapter_get_mgr(adapter); > > > + if (!mgr) > > > + return -ENODEV; > > > + > > > + acc = opae_adapter_get_acc(adapter, port_id); > > > + if (!acc) > > > + return -ENODEV; > > > + > > > + br = opae_acc_get_br(acc); > > > + if (!br) > > > + return -ENODEV; > > > + > > > + ret = opae_manager_flash(mgr, port_id, buffer, size, status); > > > + if (ret) { > > > + IFPGA_RAWDEV_PMD_ERR("%s pr error %d\n", __func__, > > ret); > > > + return ret; > > > + } > > > + > > > + ret = opae_bridge_reset(br); > > > + if (ret) { > > > + IFPGA_RAWDEV_PMD_ERR("%s reset port:%d error %d\n", > > > + __func__, port_id, ret); > > > + return ret; > > > + } > > > + > > > + return ret; > > > +} > > > + > > > +static int > > > +rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, > > > + const char *file_name) > > > +{ > > > + struct stat file_stat; > > > + int file_fd; > > > + int ret = 0; > > > + u32 buffer_size; > > > + void *buffer; > > > + u64 pr_error; > > > + > > > + if (!file_name) > > > + return -EINVAL; > > > + > > > + file_fd = open(file_name, O_RDONLY); > > > + if (file_fd < 0) { > > > + IFPGA_RAWDEV_PMD_ERR("%s: open file error: %s\n", > > > + __func__, file_name); > > > + IFPGA_RAWDEV_PMD_ERR("Message : %s\n", > > strerror(errno)); > > > + return -EINVAL; > > > + } > > > + ret = stat(file_name, &file_stat); > > > + if (ret) { > > > + IFPGA_RAWDEV_PMD_ERR("stat on bitstream file > > failed: %s\n", > > > + file_name); > > > + return -EINVAL; > > > + } > > > + buffer_size = file_stat.st_size; > > > + IFPGA_RAWDEV_PMD_INFO("bitstream file size: %u\n", buffer_size); > > > + buffer = rte_malloc(NULL, buffer_size, 0); > > > + if (!buffer) { > > > + ret = -ENOMEM; > > > + goto close_fd; > > > + } > > > + > > > + /*read the raw data*/ > > > + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { > > > + ret = -EINVAL; > > > + goto free_buffer; > > > + } > > > + > > > + /*do PR now*/ > > > + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); > > > + IFPGA_RAWDEV_PMD_INFO("downloading to device > > port %d....%s.\n", > > > port_id, > > > + ret ? "failed" : "success"); > > > + if (ret) { > > > + ret = -EINVAL; > > > + goto free_buffer; > > > + } > > > + > > > +free_buffer: > > > + if (buffer) > > > + rte_free(buffer); > > > +close_fd: > > > + close(file_fd); > > > + file_fd = 0; > > > + return ret; > > > +} > > > + > > > +static int > > > +ifpga_rawdev_pr(struct rte_rawdev *dev, > > > + rte_rawdev_obj_t pr_conf) > > > +{ > > > + struct opae_adapter *adapter; > > > + struct rte_afu_pr_conf *afu_pr_conf; > > > + int ret; > > > + struct uuid uuid; > > > + struct opae_accelerator *acc; > > > + > > > + IFPGA_RAWDEV_PMD_FUNC_TRACE(); > > > + > > > + adapter = ifpga_rawdev_get_priv(dev); > > > + if (!adapter) > > > + return -ENODEV; > > > + > > > + if (!pr_conf) > > > + return -EINVAL; > > > + > > > + afu_pr_conf = pr_conf; > > > + > > > + if (afu_pr_conf->pr_enable) { > > > + ret = rte_fpga_do_pr(dev, > > > + afu_pr_conf->afu_id.port, > > > + afu_pr_conf->bs_path); > > > + if (ret) { > > > + IFPGA_RAWDEV_PMD_ERR("do pr error %d\n", ret); > > > + return ret; > > > + } > > > + } > > > + > > > + acc = opae_adapter_get_acc(adapter, afu_pr_conf->afu_id.port); > > > + if (!acc) > > > + return -ENODEV; > > > + > > > + ret = opae_acc_get_uuid(acc, &uuid); > > > + if (ret) > > > + return ret; > > > + > > > + memcpy(&afu_pr_conf->afu_id.uuid.uuid_low, uuid.b, sizeof(u64)); > > > + memcpy(&afu_pr_conf->afu_id.uuid.uuid_high, uuid.b + 8, > > > +sizeof(u64)); > > > + > > > + IFPGA_RAWDEV_PMD_INFO("%s: uuid_l=0x%lx, uuid_h=0x%lx\n", > > > __func__, > > > + (u64)afu_pr_conf->afu_id.uuid.uuid_low, > > > + (u64)afu_pr_conf->afu_id.uuid.uuid_high); > > > + > > > + return 0; > > > +} > > > + > > > +static const struct rte_rawdev_ops ifpga_rawdev_ops = { > > > + .dev_info_get = ifpga_rawdev_info_get, > > > + .dev_configure = NULL, > > > + .dev_start = ifpga_rawdev_start, > > > + .dev_stop = ifpga_rawdev_stop, > > > + .dev_close = ifpga_rawdev_close, > > > + .dev_reset = ifpga_rawdev_reset, > > > + > > > + .queue_def_conf = NULL, > > > + .queue_setup = NULL, > > > + .queue_release = NULL, > > > + > > > + .attr_get = NULL, > > > + .attr_set = NULL, > > > + > > > + .enqueue_bufs = NULL, > > > + .dequeue_bufs = NULL, > > > + > > > + .dump = NULL, > > > + > > > + .xstats_get = NULL, > > > + .xstats_get_names = NULL, > > > + .xstats_get_by_name = NULL, > > > + .xstats_reset = NULL, > > > + > > > + .firmware_status_get = NULL, > > > + .firmware_version_get = NULL, > > > + .firmware_load = ifpga_rawdev_pr, > > > + .firmware_unload = NULL, > > > + > > > + .dev_selftest = NULL, > > > +}; > > > + > > > +static int > > > +ifpga_rawdev_create(struct rte_pci_device *pci_dev, > > > + int socket_id) > > > +{ > > > + int ret = 0; > > > + struct rte_rawdev *rawdev = NULL; > > > + struct opae_adapter *adapter = NULL; > > > + struct opae_manager *mgr = NULL; > > > + struct opae_adapter_data_pci *data = NULL; > > > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > > > + int i; > > > + > > > + if (!pci_dev) { > > > + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); > > > + ret = -EINVAL; > > > + goto cleanup; > > > + } > > > + > > > + memset(name, 0, sizeof(name)); > > > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, > > "IFPGA:%x:%02x.%x", > > > + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev- > > >addr.function); > > > + > > > + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, > > > +rte_socket_id()); > > > + > > > + /* Allocate device structure */ > > > + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct > > opae_adapter), > > > + socket_id); > > > + if (rawdev == NULL) { > > > + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); > > > + ret = -EINVAL; > > > + goto cleanup; > > > + } > > > + > > > + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API > > */ > > > + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); > > > + if (!data) { > > > + ret = -ENOMEM; > > > + goto cleanup; > > > + } > > > + > > > + /* init opae_adapter_data_pci for device specific information */ > > > + for (i = 0; i < PCI_MAX_RESOURCE; i++) { > > > + data->region[i].phys_addr = pci_dev- > > >mem_resource[i].phys_addr; > > > + data->region[i].len = pci_dev->mem_resource[i].len; > > > + data->region[i].addr = pci_dev->mem_resource[i].addr; > > > + } > > > + data->device_id = pci_dev->id.device_id; > > > + data->vendor_id = pci_dev->id.vendor_id; > > > + > > > + /* create a opae_adapter based on above device data */ > > > + adapter = opae_adapter_alloc(pci_dev->device.name, data); > > > + if (!adapter) { > > > + ret = -ENOMEM; > > > + goto free_adapter_data; > > > + } > > > + > > > + rawdev->dev_ops = &ifpga_rawdev_ops; > > > + rawdev->device = &pci_dev->device; > > > + rawdev->driver_name = pci_dev->device.driver->name; > > > + > > > + rawdev->dev_private = adapter; > > > + > > > + /* must enumerate the adapter before use it */ > > > + ret = opae_adapter_enumerate(adapter); > > > + if (ret) > > > + goto free_adapter; > > > + > > > + /* get opae_manager to rawdev */ > > > + mgr = opae_adapter_get_mgr(adapter); > > > + if (mgr) { > > > + /* PF function */ > > > + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); > > > + } > > > + > > > + return ret; > > > + > > > +free_adapter: > > > + if (adapter) > > > + opae_adapter_free(adapter); > > > +free_adapter_data: > > > + if (data) > > > + opae_adapter_data_free(data); > > > +cleanup: > > > + if (rawdev) > > > + rte_rawdev_pmd_release(rawdev); > > > + > > > + return ret; > > > +} > > > + > > > +static int > > > +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) { > > > + int ret; > > > + struct rte_rawdev *rawdev; > > > + char name[RTE_RAWDEV_NAME_MAX_LEN]; > > > + struct opae_adapter *adapter; > > > + > > > + if (!pci_dev) { > > > + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); > > > + ret = -EINVAL; > > > + return ret; > > > + } > > > + > > > + memset(name, 0, sizeof(name)); > > > + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, > > "IFPGA:%x:%02x.%x", > > > + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev- > > >addr.function); > > > + > > > + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", > > > + name, rte_socket_id()); > > > + > > > + rawdev = rte_rawdev_pmd_get_named_dev(name); > > > + if (!rawdev) { > > > + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", > > name); > > > + return -EINVAL; > > > + } > > > + > > > + adapter = ifpga_rawdev_get_priv(rawdev); > > > + if (!adapter) > > > + return -ENODEV; > > > + > > > + opae_adapter_data_free(adapter->data); > > > + opae_adapter_free(adapter); > > > + > > > + /* rte_rawdev_close is called by pmd_release */ > > > + ret = rte_rawdev_pmd_release(rawdev); > > > + if (ret) > > > + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); > > > + > > > + return ret; > > > +} > > > + > > > +static int > > > +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()); } > > > + > > > +static int > > > +ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) { > > > + return ifpga_rawdev_destroy(pci_dev); } > > > + > > > +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { > > > + .id_table = pci_ifpga_map, > > > + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | > > RTE_PCI_DRV_INTR_LSC, > > > + .probe = ifpga_rawdev_pci_probe, > > > + .remove = ifpga_rawdev_pci_remove, > > > +}; > > > + > > > +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, > > rte_ifpga_rawdev_pmd); > > > +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, > > > +rte_ifpga_rawdev_pmd); > > > +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | > > > +uio_pci_generic | vfio-pci"); > > > + > > > +RTE_INIT(ifpga_rawdev_init_log); > > > +static void > > > +ifpga_rawdev_init_log(void) > > > +{ > > > + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); > > > + if (ifpga_rawdev_logtype >= 0) > > > + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); } > > > + > > > +static const char * const valid_args[] = { > > > +#define IFPGA_ARG_NAME "ifpga" > > > + IFPGA_ARG_NAME, > > > +#define IFPGA_ARG_PORT "port" > > > + IFPGA_ARG_PORT, > > > +#define IFPGA_AFU_BTS "afu_bts" > > > + IFPGA_AFU_BTS, > > > + NULL > > > +}; > > > + > > > +static int > > > +ifpga_cfg_probe(struct rte_vdev_device *dev) { > > > + struct rte_devargs *devargs; > > > + struct rte_kvargs *kvlist = NULL; > > > + int port; > > > + char *name = NULL; > > > + char dev_name[RTE_RAWDEV_NAME_MAX_LEN]; > > > + > > > + devargs = dev->device.devargs; > > > + > > > + kvlist = rte_kvargs_parse(devargs->args, valid_args); > > > + if (!kvlist) { > > > + IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing > > param"); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { > > > + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, > > > + &rte_ifpga_get_string_arg, &name) < 0) { > > > + IFPGA_RAWDEV_PMD_ERR("error to parse %s", > > > + IFPGA_ARG_NAME); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga > > bus", > > > + IFPGA_ARG_NAME); > > > + goto end; > > > + } > > > + > > > + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { > > > + if (rte_kvargs_process(kvlist, > > > + IFPGA_ARG_PORT, > > > + &rte_ifpga_get_integer32_arg, > > > + &port) < 0) { > > > + IFPGA_RAWDEV_PMD_ERR("error to parse %s", > > > + IFPGA_ARG_PORT); > > > + goto end; > > > + } > > > + } else { > > > + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga > > bus", > > > + IFPGA_ARG_PORT); > > > + goto end; > > > + } > > > + > > > + memset(dev_name, 0, sizeof(dev_name)); > > > + snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s", > > > + port, name); > > > + > > > + rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), > > > + dev_name, devargs->args); > > > +end: > > > + if (kvlist) > > > + rte_kvargs_free(kvlist); > > > + if (name) > > > + free(name); > > > + > > > + return 0; > > > +} > > > + > > > +static int > > > +ifpga_cfg_remove(struct rte_vdev_device *vdev) { > > > + IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p", > > > + vdev); > > > + > > > + return 0; > > > +} > > > + > > > +static struct rte_vdev_driver ifpga_cfg_driver = { > > > + .probe = ifpga_cfg_probe, > > > + .remove = ifpga_cfg_remove, > > > +}; > > > + > > > +RTE_PMD_REGISTER_VDEV(net_ifpga_cfg, ifpga_cfg_driver); > > > +RTE_PMD_REGISTER_ALIAS(net_ifpga_cfg, ifpga_cfg); > > > +RTE_PMD_REGISTER_PARAM_STRING(net_ifpga_cfg, > > > + "bdf=<string> " > > > + "port=<int> " > > > + "afu_bts=<path>"); > > > + > > > diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > > b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > > new file mode 100644 > > > index 0000000..c7759b8 > > > --- /dev/null > > > +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h > > > @@ -0,0 +1,37 @@ > > > +/* SPDX-License-Identifier: BSD-3-Clause > > > + * Copyright(c) 2010-2018 Intel Corporation */ > > > + > > > +#ifndef _IFPGA_RAWDEV_H_ > > > +#define _IFPGA_RAWDEV_H_ > > > + > > > +extern int ifpga_rawdev_logtype; > > > + > > > +#define IFPGA_RAWDEV_PMD_LOG(level, fmt, args...) \ > > > + rte_log(RTE_LOG_ ## level, ifpga_rawdev_logtype, "ifgpa: " fmt, \ > > > + ##args) > > > + > > > +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() > > > IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") > > > + > > > +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ > > > + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) #define > > > +IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ > > > + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) #define > > > +IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ > > > + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) #define > > > +IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ > > > + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) > > > + > > > +enum ifpga_rawdev_device_state { > > > + IFPGA_IDLE, > > > + IFPGA_READY, > > > + IFPGA_ERROR > > > +}; > > > + > > > +static inline struct opae_adapter * ifpga_rawdev_get_priv(const > > > +struct rte_rawdev *rawdev) { > > > + return rawdev->dev_private; > > > +} > > > + > > > +#endif /* _IFPGA_RAWDEV_H_ */ > > > diff --git a/drivers/raw/ifpga_rawdev/meson.build > > > b/drivers/raw/ifpga_rawdev/meson.build > > > new file mode 100644 > > > index 0000000..6725687 > > > --- /dev/null > > > +++ b/drivers/raw/ifpga_rawdev/meson.build > > > @@ -0,0 +1,15 @@ > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel > > > +Corporation > > > + > > > +version = 1 > > > + > > > +subdir('base') > > > +objs = [base_objs] > > > + > > > +deps += ['rawdev', 'pci', 'bus_pci', 'kvargs', > > > + 'bus_vdev', 'bus_ifpga'] > > > +sources = files('ifpga_rawdev.c') > > > + > > > +includes += include_directories('base') > > > + > > > +allow_experimental_apis = true > > > diff --git > > > a/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map > > > b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map > > > new file mode 100644 > > > index 0000000..9b9ab1a > > > --- /dev/null > > > +++ b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map > > > @@ -0,0 +1,4 @@ > > > +DPDK_18.05 { > > > + > > > + local: *; > > > +}; > > > diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build index > > > 34dfac4..a61cdcc 100644 > > > --- a/drivers/raw/meson.build > > > +++ b/drivers/raw/meson.build > > > @@ -1,7 +1,7 @@ > > > # SPDX-License-Identifier: BSD-3-Clause # Copyright 2018 NXP > > > > > > -drivers = ['skeleton_rawdev', 'dpaa2_cmdif', 'dpaa2_qdma'] > > > +drivers = ['skeleton_rawdev', 'dpaa2_cmdif', 'dpaa2_qdma', > > > +'ifpga_rawdev'] > > > std_deps = ['rawdev'] > > > config_flag_fmt = 'RTE_LIBRTE_PMD_@0@_RAWDEV' > > > driver_name_fmt = 'rte_pmd_@0@' > > > diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 3861e1a..acc0ec3 > > > 100644 > > > --- a/mk/rte.app.mk > > > +++ b/mk/rte.app.mk > > > @@ -256,9 +256,11 @@ > > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += > > > -lrte_pmd_dpaa2_cmdif > > > _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += > > > -lrte_pmd_dpaa2_qdma 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 > > > +endif # CONFIG_RTE_LIBRTE_IFPGA_BUS > > > endif # CONFIG_RTE_LIBRTE_RAWDEV > > > > > > - > > > endif # !CONFIG_RTE_BUILD_SHARED_LIBS > > > > > > _LDLIBS-y += --no-whole-archive > > > -- > > > 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v11 0/3] Introduce Intel FPGA BUS 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (13 preceding siblings ...) 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 0/3] Introduce Intel FPGA BUS Xu, Rosen @ 2018-05-10 14:00 ` Xu, Rosen 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 1/3] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen ` (2 more replies) 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS Xu, Rosen ` (2 subsequent siblings) 17 siblings, 3 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-10 14:00 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: "Xu, Rosen" <rosen.xu@intel.com> Intel FPGA BUS in DPDK ------------------------- This patch set introduces Intel FPGA BUS support in DPDK. v11 updates: =========== - To improve PR speed OPAE Share Code involved AVX-512, but AVX-512 is not available in all IA platforms, besides this, after we have test several times, using AVX-512 only improve 1 ms. So this patch we don't use it. - Fix comments of patch 1 of Jingjing Wu and Qi Zhang. - Updated configurations parameters form net_ifpga_cfg to ifpga_rawdev_cfg v10 updates: =========== - Add prefix rte_ for exported symbols - Fix alphabetical order error - Fix share code title well underlined comments - Squash the release notes parts in relevant patches - Update the MAINTAINERS file in patches 1, 2 and 3 v9 updates: ========== - Rebase ifpga_rawdev on QDMA and CMDIF driver - Split and squash the patch 4(v8 patch) into patch 2 and patch 3 v8 updates: ========== - Fix some comments from Shreyansh Jain - Patch 3 and Patch 5 will continue rebase when qcom patches merging into mainline - add Shreyansh Jain's Acked-by v7 updates: ========== - Fix some comments from DPDK community - Fix the CLANG compile error - Fix the meson build warring. v6 updates: =========== - Add documentation - Add meson build script - Split new patch for OPAE share code v5 updates: =========== - Fixed SHARED LIB Build issue - Changed command name to IFPGA Rawdev name, so remove pci library datastruct and function. - Fixed PATCH v2/v3/v4 comments v4 updates: =========== - Remove all modifications from eal - Create vdev to take IFPGA parameters configuration - AFU Device Driver bind to AFU Device by uuid - Take more test in scenario of Multi-FPGA System v3 updates: =========== - Remove all modifications of bus scan and probe - FPGA BUS Scan is trigged by hotplug of Rawdev - Took Modifications of comments - Move AFU Device to IFPGA - FPGA BUS Scan depend on it's IFPGA Rawdev - Add Build Macros for FPGA BUS and IFPGA Rawdev Questions ========= Why not PCI Bus? All of the AFUs of one FPGA may share same PCI BDF. Why not vdev Bus? Because AFUs depend on Rawdev, and it's hardware specpic. Motivation ========== FPGA is used more and more widely in Cloud and NFV, one primary reason is that FPGA not only provide ASIC performance but also it's more flexible than ASIC. FPGA use Partial Reconfigure(PR) Parts of Bitstream to achieve its flexibility. Another reason is that one FPGA can be shared by different Users, and each User can use some of AFUs of One FPGA. That means One FPGA Device Bitstream is divided into many Parts of Bitstream(each Part of Bitstream is defined as AFU-Accelerated Function Unit), and each AFU is a Hardware Acceleration Unit and it can dynamically Reload respectively. Proposed Solution ================= - Involve Rawdev to take FPGA Partial Configuration(Download/PR) - Defined FPGA-BUS for Acceleration Drivers of AFUs - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver. FPGA-BUS scan is called, but AFU depend on Rawdev, so this scan doesn't trig AFU device create. - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their dirves are also probed. Scope ===== The Intel FPGA BUS implementation is target towards various FPGA Devices use PR to provide many Acceleration Function. Specific PMDs may also bind to its AFU. And Applications don't care they are using ASIC Acceleration or FPGA AFU Acceleration. Status ===== With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable Acceleration Engine) Share Code, Intel FPGA BUS runs well in Intel PSG FPGA Cards. Rosen Xu (2): bus/ifpga: Add Intel FPGA BUS Library iFPGA: Add Intel FPGA BUS Rawdev Driver Tianfei Zhang (1): iFPGA: Add Intel FPGA OPAE Share Code MAINTAINERS | 11 + config/common_base | 10 + doc/guides/rawdevs/ifpga_rawdev.rst | 112 ++ doc/guides/rawdevs/index.rst | 1 + doc/guides/rel_notes/release_18_05.rst | 13 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 + drivers/bus/ifpga/ifpga_bus.c | 503 ++++++ drivers/bus/ifpga/ifpga_common.c | 88 ++ drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 + drivers/bus/ifpga/meson.build | 8 + drivers/bus/ifpga/rte_bus_ifpga.h | 159 ++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/bus/meson.build | 2 +- drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 + drivers/raw/ifpga_rawdev/base/Makefile | 26 + drivers/raw/ifpga_rawdev/base/README | 31 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 294 ++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 28 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 58 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1662 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 824 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 11 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 255 +++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 164 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 734 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 301 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 381 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 715 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 352 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 127 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 388 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 144 ++ drivers/raw/ifpga_rawdev/base/meson.build | 34 + drivers/raw/ifpga_rawdev/base/opae_debug.c | 99 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 19 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 381 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 253 +++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 145 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 279 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 79 + .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 75 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 45 + drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 608 +++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 + drivers/raw/ifpga_rawdev/meson.build | 15 + .../ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map | 4 + drivers/raw/meson.build | 2 +- mk/rte.app.mk | 5 +- 51 files changed, 9608 insertions(+), 3 deletions(-) create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/meson.build create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/README create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/meson.build create mode 100644 drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v11 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 0/3] Introduce Intel FPGA BUS Xu, Rosen @ 2018-05-10 14:00 ` Xu, Rosen 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 2/3] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-10 14:00 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: Rosen Xu <rosen.xu@intel.com> Defined FPGA-BUS for Acceleration Drivers of AFUs 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver, it will be covered in following patches. 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their drivers are also probed. This patch will introduce rte_afu_device which describe the AFU device listed in the FPGA-BUS. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> --- MAINTAINERS | 4 + config/common_base | 5 + doc/guides/rel_notes/release_18_05.rst | 5 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 ++ drivers/bus/ifpga/ifpga_bus.c | 503 ++++++++++++++++++++++++++++ drivers/bus/ifpga/ifpga_common.c | 88 +++++ drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 ++ drivers/bus/ifpga/meson.build | 8 + drivers/bus/ifpga/rte_bus_ifpga.h | 159 +++++++++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/bus/meson.build | 2 +- mk/rte.app.mk | 1 + 14 files changed, 866 insertions(+), 1 deletion(-) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/meson.build create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map diff --git a/MAINTAINERS b/MAINTAINERS index 7105920..d4870a6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -383,6 +383,10 @@ F: drivers/mempool/bucket/ Bus Drivers ----------- +Intel FPGA bus +M: Rosen Xu <rosen.xu@intel.com> +F: drivers/bus/ifpga/ + NXP buses M: Hemant Agrawal <hemant.agrawal@nxp.com> M: Shreyansh Jain <shreyansh.jain@nxp.com> diff --git a/config/common_base b/config/common_base index 0d181ac..1440316 100644 --- a/config/common_base +++ b/config/common_base @@ -139,6 +139,11 @@ CONFIG_RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS=n CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n # +# Compile the Intel FPGA bus +# +CONFIG_RTE_LIBRTE_IFPGA_BUS=y + +# # Compile PCI bus driver # CONFIG_RTE_LIBRTE_PCI_BUS=y diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst index 7187348..265950a 100644 --- a/doc/guides/rel_notes/release_18_05.rst +++ b/doc/guides/rel_notes/release_18_05.rst @@ -183,6 +183,11 @@ New Features stats/xstats on shared memory from secondary process, and also pdump packets on those virtual devices. +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** + + The Ifpga Bus library provides support for integrating any Intel FPGA device with + the DPDK framework. It provides Intel FPGA Partial Bit Stream AFU(Accelerated + Function Unit) scan and drivers prove. API Changes ----------- diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index c251b65..ef7f247 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -7,6 +7,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa ifeq ($(CONFIG_RTE_EAL_VFIO),y) DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc endif +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile new file mode 100644 index 0000000..3ff3bdb --- /dev/null +++ b/drivers/bus/ifpga/Makefile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_bus_ifpga.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_kvargs + +# versioning export map +EXPORT_MAP := rte_bus_ifpga_version.map + +# library version +LIBABIVER := 1 + +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c + +# +# Export include files +# +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index 0000000..b08f1ad --- /dev/null +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -0,0 +1,503 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_bus_logtype; + +/* Forward declaration to access Intel FPGA bus + * on which iFPGA devices are connected + */ +static struct rte_bus rte_ifpga_bus; + +/** Double linked list of IFPGA device. */ +TAILQ_HEAD(ifpga_device_list, rte_ifpga_device); + +static struct ifpga_device_list ifpga_device_list = + TAILQ_HEAD_INITIALIZER(ifpga_device_list); +static struct afu_driver_list afu_driver_list = + TAILQ_HEAD_INITIALIZER(afu_driver_list); + + +/* register a ifpga bus based driver */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver) +{ + RTE_VERIFY(driver); + + TAILQ_INSERT_TAIL(&afu_driver_list, driver, next); +} + +/* un-register a fpga bus based driver */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) +{ + TAILQ_REMOVE(&afu_driver_list, driver, next); +} + +static struct rte_ifpga_device * +ifpga_find_ifpga_dev(const struct rte_rawdev *rdev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + if (rdev && + ifpga_dev->rdev && + ifpga_dev->rdev == rdev) + return ifpga_dev; + } + return NULL; +} + +static struct rte_afu_device * +ifpga_find_afu_dev(const struct rte_ifpga_device *ifpga_dev, + const struct rte_afu_id *afu_id) +{ + struct rte_afu_device *afu_dev = NULL; + + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (afu_dev && + !ifpga_afu_id_cmp(&afu_dev->id, afu_id)) + return afu_dev; + } + return NULL; +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static struct rte_afu_device * +ifpga_scan_one(struct rte_ifpga_device *ifpga_dev, + struct rte_devargs *devargs) +{ + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_afu_pr_conf afu_pr_conf; + int ret = 0; + char *path = NULL; + + memset(&afu_pr_conf, 0, sizeof(struct rte_afu_pr_conf)); + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, + &rte_ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, + &rte_ifpga_get_string_arg, &path) < 0) { + IFPGA_BUS_ERR("Failed to parse %s", + IFPGA_AFU_BTS); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_AFU_BTS); + goto end; + } + + afu_pr_conf.afu_id.uuid.uuid_low = 0; + afu_pr_conf.afu_id.uuid.uuid_high = 0; + afu_pr_conf.pr_enable = path?1:0; + + rawdev = ifpga_dev->rdev; + if (ifpga_find_afu_dev(ifpga_dev, &afu_pr_conf.afu_id)) + goto end; + + afu_dev = calloc(1, sizeof(*afu_dev)); + if (!afu_dev) + goto end; + + afu_dev->device.devargs = devargs; + afu_dev->device.numa_node = SOCKET_ID_ANY; + afu_dev->device.name = devargs->name; + afu_dev->rawdev = rawdev; + afu_dev->id.uuid.uuid_low = 0; + afu_dev->id.uuid.uuid_high = 0; + afu_dev->id.port = afu_pr_conf.afu_id.port; + afu_dev->ifpga_dev = ifpga_dev; + + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); + + if (rawdev->dev_ops && + rawdev->dev_ops->dev_start && + rawdev->dev_ops->dev_start(rawdev)) + goto free_dev; + + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); + if (rawdev->dev_ops->firmware_load && + rawdev->dev_ops->firmware_load(rawdev, + &afu_pr_conf)){ + IFPGA_BUS_ERR("firmware load error %d\n", ret); + goto free_dev; + } + afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; + afu_dev->id.uuid.uuid_high = afu_pr_conf.afu_id.uuid.uuid_high; + + return afu_dev; + +free_dev: + free(afu_dev); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (path) + free(path); + + return NULL; +} + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static int +ifpga_scan(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + char *name = NULL; + char name1[RTE_RAWDEV_NAME_MAX_LEN]; + struct rte_afu_device *afu_dev = NULL; + + /* for FPGA devices we scan the devargs_list populated via cmdline */ + RTE_EAL_DEVARGS_FOREACH(IFPGA_ARG_NAME, devargs) { + if (devargs->bus != &rte_ifpga_bus) + continue; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &rte_ifpga_get_string_arg, &name) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + memset(name1, 0, sizeof(name1)); + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", name); + + rawdev = rte_rawdev_pmd_get_named_dev(name1); + if (!rawdev) + goto end; + + if (ifpga_find_ifpga_dev(rawdev)) + continue; + + ifpga_dev = calloc(1, sizeof(*ifpga_dev)); + if (!ifpga_dev) + goto end; + + ifpga_dev->rdev = rawdev; + TAILQ_INIT(&ifpga_dev->afu_list); + + TAILQ_INSERT_TAIL(&ifpga_device_list, ifpga_dev, next); + afu_dev = ifpga_scan_one(ifpga_dev, devargs); + if (afu_dev != NULL) + TAILQ_INSERT_TAIL(&ifpga_dev->afu_list, afu_dev, next); + } + +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +/* + * Match the AFU Driver and AFU Device using the ID Table + */ +static int +rte_afu_match(const struct rte_afu_driver *afu_drv, + const struct rte_afu_device *afu_dev) +{ + const struct rte_afu_uuid *id_table; + + for (id_table = afu_drv->id_table; + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); + id_table++) { + /* check if device's identifiers match the driver's ones */ + if ((id_table->uuid_low != afu_dev->id.uuid.uuid_low) || + id_table->uuid_high != + afu_dev->id.uuid.uuid_high) + continue; + + return 1; + } + + return 0; +} + +static int +ifpga_probe_one_driver(struct rte_afu_driver *drv, + struct rte_afu_device *afu_dev) +{ + int ret; + + if (!rte_afu_match(drv, afu_dev)) + /* Match of device and driver failed */ + return 1; + + /* reference driver structure */ + afu_dev->driver = drv; + afu_dev->device.driver = &drv->driver; + + /* call the driver probe() function */ + ret = drv->probe(afu_dev); + if (ret) { + afu_dev->driver = NULL; + afu_dev->device.driver = NULL; + } + + return ret; +} + +static int +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) +{ + struct rte_afu_driver *drv = NULL; + int ret = 0; + + if (afu_dev == NULL) + return -1; + + /* Check if a driver is already loaded */ + if (afu_dev->driver != NULL) + return 0; + + TAILQ_FOREACH(drv, &afu_driver_list, next) { + if (ifpga_probe_one_driver(drv, afu_dev)) { + ret = -1; + break; + } + } + return ret; +} + +/* + * Scan the content of the Intel FPGA bus, and call the probe() function for + * all registered drivers that have a matching entry in its id_table + * for discovered devices. + */ +static int +ifpga_probe(void) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev = NULL; + int ret = 0; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + + if (afu_dev->device.driver) + continue; + + ret = ifpga_probe_all_drivers(afu_dev); + if (ret < 0) + IFPGA_BUS_ERR("failed to initialize %s device\n", + rte_ifpga_device_name(afu_dev)); + } + } + + return ret; +} + +static int +ifpga_plug(struct rte_device *dev) +{ + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); +} + +static int +ifpga_remove_driver(struct rte_afu_device *afu_dev) +{ + const char *name; + const struct rte_afu_driver *driver; + + name = rte_ifpga_device_name(afu_dev); + if (!afu_dev->device.driver) { + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); + return 1; + } + + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); + return driver->remove(afu_dev); +} + +static int +ifpga_unplug(struct rte_device *dev) +{ + struct rte_ifpga_device *ifpga_dev = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_devargs *devargs = NULL; + int ret; + + if (dev == NULL) + return -EINVAL; + + afu_dev = RTE_DEV_TO_AFU(dev); + if (!dev) + return -ENOENT; + + ifpga_dev = afu_dev->ifpga_dev; + devargs = dev->devargs; + + ret = ifpga_remove_driver(afu_dev); + if (ret) + return ret; + + TAILQ_REMOVE(&ifpga_dev->afu_list, afu_dev, next); + + rte_devargs_remove(devargs->bus->name, devargs->name); + free(afu_dev); + return 0; + +} + +static struct rte_device * +ifpga_find_device(const struct rte_device *start, + rte_dev_cmp_t cmp, const void *data) +{ + struct rte_ifpga_device *ifpga_dev; + struct rte_afu_device *afu_dev; + + TAILQ_FOREACH(ifpga_dev, &ifpga_device_list, next) { + TAILQ_FOREACH(afu_dev, &ifpga_dev->afu_list, next) { + if (start && &afu_dev->device == start) { + start = NULL; + continue; + } + if (cmp(&afu_dev->device, data) == 0) + return &afu_dev->device; + } + } + return NULL; +} +static int +ifpga_parse(const char *name, void *addr) +{ + int *out = addr; + struct rte_rawdev *rawdev = NULL; + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; + char *c1 = NULL; + char *c2 = NULL; + int port = IFPGA_BUS_DEV_PORT_MAX; + char str_port[8]; + int str_port_len = 0; + int ret; + + memset(str_port, 0, 8); + c1 = strchr(name, '|'); + if (c1 != NULL) { + str_port_len = c1 - name; + c2 = c1 + 1; + } + + if (str_port_len < 8 && + str_port_len > 0) { + memcpy(str_port, name, str_port_len); + ret = sscanf(str_port, "%d", &port); + if (ret == -1) + return 0; + } + + memset(rawdev_name, 0, sizeof(rawdev_name)); + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", c2); + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev && + (addr != NULL)) + *out = port; + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev) + return 0; + else + return 1; +} + +static struct rte_bus rte_ifpga_bus = { + .scan = ifpga_scan, + .probe = ifpga_probe, + .find_device = ifpga_find_device, + .plug = ifpga_plug, + .unplug = ifpga_unplug, + .parse = ifpga_parse, +}; + +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); + +RTE_INIT(ifpga_init_log) +{ + ifpga_bus_logtype = rte_log_register("bus.ifpga"); + if (ifpga_bus_logtype >= 0) + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); +} diff --git a/drivers/bus/ifpga/ifpga_common.c b/drivers/bus/ifpga/ifpga_common.c new file mode 100644 index 0000000..78e2eae --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int rte_ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(char **)extra_args = strdup(value); + + if (!*(char **)extra_args) + return -ENOMEM; + + return 0; +} +int rte_ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(int *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(uint64_t *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_unsigned_long(const char *str, int base) +{ + unsigned long num; + char *end = NULL; + + errno = 0; + + num = strtoul(str, &end, base); + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) + return -1; + + return num; +} + +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1) +{ + if ((afu_id0->uuid.uuid_low == afu_id1->uuid.uuid_low) && + (afu_id0->uuid.uuid_high == afu_id1->uuid.uuid_high) && + (afu_id0->port == afu_id1->port)) { + return 0; + } else + return 1; +} diff --git a/drivers/bus/ifpga/ifpga_common.h b/drivers/bus/ifpga/ifpga_common.h new file mode 100644 index 0000000..f9254b9 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMMON_H_ +#define _IFPGA_COMMON_H_ + +int rte_ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int rte_ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_unsigned_long(const char *str, int base); +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1); + +#endif /* _IFPGA_COMMON_H_ */ diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index 0000000..873e0a4 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_logs.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_LOGS_H_ +#define _IFPGA_LOGS_H_ + +#include <rte_log.h> + +extern int ifpga_bus_logtype; + +#define IFPGA_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") + +#define IFPGA_BUS_DEBUG(fmt, args...) \ + IFPGA_BUS_LOG(DEBUG, fmt, ## args) +#define IFPGA_BUS_INFO(fmt, args...) \ + IFPGA_BUS_LOG(INFO, fmt, ## args) +#define IFPGA_BUS_ERR(fmt, args...) \ + IFPGA_BUS_LOG(ERR, fmt, ## args) +#define IFPGA_BUS_WARN(fmt, args...) \ + IFPGA_BUS_LOG(WARNING, fmt, ## args) + +#endif /* _IFPGA_BUS_LOGS_H_ */ diff --git a/drivers/bus/ifpga/meson.build b/drivers/bus/ifpga/meson.build new file mode 100644 index 0000000..c9b08c8 --- /dev/null +++ b/drivers/bus/ifpga/meson.build @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2018 Intel Corporation + +deps += ['pci', 'kvargs', 'rawdev'] +install_headers('rte_bus_ifpga.h') +sources = files('ifpga_common.c', 'ifpga_bus.c') + +allow_experimental_apis = true diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h new file mode 100644 index 0000000..fba26cb --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga.h @@ -0,0 +1,159 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _RTE_BUS_IFPGA_H_ +#define _RTE_BUS_IFPGA_H_ + +/** + * @file + * + * RTE Intel FPGA Bus Interface + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_bus.h> +#include <rte_pci.h> + +/** Name of Intel FPGA Bus */ +#define IFPGA_BUS_NAME ifpga + +/* Forward declarations */ +struct rte_afu_device; + +/** List of Intel AFU devices */ +TAILQ_HEAD(afu_device_list, rte_afu_device); +/** Double linked list of AFU device drivers. */ +TAILQ_HEAD(afu_driver_list, rte_afu_driver); + +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 + +struct rte_afu_uuid { + uint64_t uuid_low; + uint64_t uuid_high; +} __attribute__ ((packed)); + +#define IFPGA_BUS_DEV_PORT_MAX 4 + +/** + * A structure describing an ID for a AFU driver. Each driver provides a + * table of these IDs for each device that it supports. + */ +struct rte_afu_id { + struct rte_afu_uuid uuid; + int port; /**< port number */ +} __attribute__ ((packed)); + +/** + * A structure PR (Partial Reconfiguration) configuration AFU driver. + */ + +struct rte_afu_pr_conf { + struct rte_afu_id afu_id; + int pr_enable; + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +}; + +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) + +/** + * A structure describing a fpga device. + */ +struct rte_ifpga_device { + TAILQ_ENTRY(rte_ifpga_device) next; /**< Next in device list. */ + struct rte_rawdev *rdev; + struct afu_device_list afu_list; /**< List of AFU devices */ +}; + +/** + * A structure describing a AFU device. + */ +struct rte_afu_device { + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ + struct rte_device device; /**< Inherit core device */ + struct rte_rawdev *rawdev; /**< Point Rawdev */ + struct rte_ifpga_device *ifpga_dev; /**< Point ifpga device */ + struct rte_afu_id id; /**< AFU id within FPGA. */ + uint32_t num_region; /**< number of regions found */ + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; + /**< AFU Memory Resource */ + struct rte_intr_handle intr_handle; /**< Interrupt handle */ + struct rte_afu_driver *driver; /**< Associated driver */ + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +} __attribute__ ((packed)); + +/** + * @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_DRV_TO_AFU_CONST(ptr) \ + container_of(ptr, const struct rte_afu_driver, driver) + +/** + * Initialization function for the driver called during FPGA BUS probing. + */ +typedef int (afu_probe_t)(struct rte_afu_device *); + +/** + * Uninitialization function for the driver called during hotplugging. + */ +typedef int (afu_remove_t)(struct rte_afu_device *); + +/** + * A structure describing a AFU device. + */ +struct rte_afu_driver { + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ + struct rte_driver driver; /**< Inherit core driver. */ + afu_probe_t *probe; /**< Device Probe function. */ + afu_remove_t *remove; /**< Device Remove function. */ + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ +}; + +static inline const char * +rte_ifpga_device_name(const struct rte_afu_device *afu) +{ + if (afu && afu->device.name) + return afu->device.name; + return NULL; +} + +/** + * Register a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be registered. + */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver); + +/** + * Unregister a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be unregistered. + */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); + +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ +RTE_INIT(afudrvinitfn_ ##afudrv);\ +static const char *afudrvinit_ ## nm ## _alias;\ +static void afudrvinitfn_ ##afudrv(void)\ +{\ + (afudrv).driver.name = RTE_STR(nm);\ + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ + rte_ifpga_driver_register(&afudrv);\ +} \ +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) + +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ +static const char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) + +#endif /* _RTE_BUS_IFPGA_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map new file mode 100644 index 0000000..a027979 --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map @@ -0,0 +1,10 @@ +DPDK_18.05 { + global: + + rte_ifpga_get_integer32_arg; + rte_ifpga_get_string_arg; + rte_ifpga_driver_register; + rte_ifpga_driver_unregister; + + local: *; +}; diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build index 58dfbe2..52c755d 100644 --- a/drivers/bus/meson.build +++ b/drivers/bus/meson.build @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel Corporation -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] +drivers = ['dpaa', 'fslmc', 'ifpga', 'pci', 'vdev'] std_deps = ['eal'] config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' driver_name_fmt = 'rte_bus_@0@' diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 26f3563..3861e1a 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -255,6 +255,7 @@ ifeq ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += -lrte_pmd_dpaa2_cmdif _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += -lrte_pmd_dpaa2_qdma endif # CONFIG_RTE_LIBRTE_FSLMC_BUS +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga endif # CONFIG_RTE_LIBRTE_RAWDEV -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v11 2/3] iFPGA: Add Intel FPGA OPAE Share Code 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 0/3] Introduce Intel FPGA BUS Xu, Rosen 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 1/3] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen @ 2018-05-10 14:00 ` Xu, Rosen 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-10 14:00 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Xu, Yilun From: Tianfei Zhang <tianfei.zhang@intel.com> This patch adds Intel FPGA Open Programmable Acceleration Engine (OPAE)[1] base driver code, in order to support Intel FPGA devices under DPDK. The base code currently supports Intel FPGA solutions including integrated solution (Intel(R) Xeon(R) CPU with FPGAs) and discrete solution (Intel(R) Programmable Acceleration Card with Intel(R) Arria(R) 10 FPGA) and it could be extended to support more FPGA devices in the future. Please refer to [1][2] for more introduction on OPAE and Intel FPGAs. [1] https://01.org/OPAE [2] https://www.altera.com/solutions/acceleration-hub/overview.html Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> Signed-off-by: Wu, Hao <hao.wu@intel.com> Signed-off-by: Xu, Yilun <yilun.xu@intel.com> --- MAINTAINERS | 4 + drivers/raw/ifpga_rawdev/base/Makefile | 26 + drivers/raw/ifpga_rawdev/base/README | 31 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 294 ++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 28 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 58 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1662 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 824 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 11 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 255 +++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 164 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 734 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 301 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 381 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 715 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 352 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 127 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 388 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 144 ++ drivers/raw/ifpga_rawdev/base/meson.build | 34 + drivers/raw/ifpga_rawdev/base/opae_debug.c | 99 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 19 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 381 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 253 +++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 145 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 279 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 79 + .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 75 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 45 + 29 files changed, 7908 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/README create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h diff --git a/MAINTAINERS b/MAINTAINERS index d4870a6..e1a1ef9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -850,6 +850,10 @@ F: doc/guides/eventdevs/opdl.rst Rawdev Drivers -------------- +Intel FPGA +M: Tianfei zhang <tianfei.zhang@intel.com> +F: drivers/raw/ifpga_rawdev/base/ + NXP DPAA2 QDMA M: Nipun Gupta <nipun.gupta@nxp.com> F: drivers/raw/dpaa2_qdma/ diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile new file mode 100644 index 0000000..d79da72 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -0,0 +1,26 @@ +#SPDX-License-Identifier: BSD-3-Clause +#Copyright(c) 2010-2018 Intel Corporation + +ifneq ($(CONFIG_RTE_LIBRTE_EAL),) +OSDEP := osdep_rte +else +OSDEP := osdep_raw +endif + +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev/base/$(OSDEP) + +SRCS-y += ifpga_api.c +SRCS-y += ifpga_enumerate.c +SRCS-y += ifpga_feature_dev.c +SRCS-y += ifpga_fme.c +SRCS-y += ifpga_fme_iperf.c +SRCS-y += ifpga_fme_dperf.c +SRCS-y += ifpga_fme_error.c +SRCS-y += ifpga_port.c +SRCS-y += ifpga_port_error.c +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 += $(wildcard $(SRCDIR)/base/$(OSDEP)/*.c) diff --git a/drivers/raw/ifpga_rawdev/base/README b/drivers/raw/ifpga_rawdev/base/README new file mode 100644 index 0000000..5bc2ed0 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/README @@ -0,0 +1,31 @@ +.. + +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +Intel iFPGA driver +================== + +This directory contains source code of Intel FPGA driver released by +the team which develops Intel FPGA Open Programmable Acceleration Engine (OPAE). +The directory of base/ contains the original source package. The base code +currently supports Intel FPGA solutions including integrated solution (Intel(R) +Xeon(R) CPU with FPGAs) and discrete solution (Intel(R) Programmable Acceleration +Card with Intel(R) Arria(R) 10 FPGA) and it could be extended to support more FPGA +devices in the future. + +Please refer to [1][2] for more introduction on OPAE and Intel FPGAs. + +[1] https://01.org/OPAE +[2] https://www.altera.com/solutions/acceleration-hub/overview.html + + +Updating the driver +=================== + +NOTE: The source code in this directory should not be modified apart from +the following file(s): + + osdep_raw/osdep_generic.h + osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.c b/drivers/raw/ifpga_rawdev/base/ifpga_api.c new file mode 100644 index 0000000..540e171 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -0,0 +1,294 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_api.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +#include "opae_hw_api.h" + +/* Accelerator APIs */ +static int ifpga_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return fpga_get_afu_uuid(port, uuid); +} + +static int ifpga_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + struct fpga_uafu_irq_set irq_set; + + if (!br || !br->data) + return -EINVAL; + + if (start >= afu_info->num_irqs || start + count > afu_info->num_irqs) + return -EINVAL; + + port = br->data; + + irq_set.start = start; + irq_set.count = count; + irq_set.evtfds = evtfds; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_UINT, &irq_set); +} + +static int ifpga_acc_get_info(struct opae_accelerator *acc, + struct opae_acc_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -ENODEV; + + info->num_regions = afu_info->num_regions; + info->num_irqs = afu_info->num_irqs; + + return 0; +} + +static int ifpga_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -EINVAL; + + if (info->index >= afu_info->num_regions) + return -EINVAL; + + /* always one RW region only for AFU now */ + info->flags = ACC_REGION_READ | ACC_REGION_WRITE | ACC_REGION_MMIO; + info->len = afu_info->region[info->index].len; + info->addr = afu_info->region[info->index].addr; + + return 0; +} + +static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + switch (byte) { + case 8: + *(u64 *)data = opae_readq(region->addr + offset); + break; + case 4: + *(u32 *)data = opae_readl(region->addr + offset); + break; + case 2: + *(u16 *)data = opae_readw(region->addr + offset); + break; + case 1: + *(u8 *)data = opae_readb(region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ifpga_acc_write(struct opae_accelerator *acc, + unsigned int region_idx, u64 offset, + unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + /* normal mmio case */ + switch (byte) { + case 8: + opae_writeq(*(u64 *)data, region->addr + offset); + break; + case 4: + opae_writel(*(u32 *)data, region->addr + offset); + break; + case 2: + opae_writew(*(u16 *)data, region->addr + offset); + break; + case 1: + opae_writeb(*(u8 *)data, region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +struct opae_accelerator_ops ifpga_acc_ops = { + .read = ifpga_acc_read, + .write = ifpga_acc_write, + .set_irq = ifpga_acc_set_irq, + .get_info = ifpga_acc_get_info, + .get_region_info = ifpga_acc_get_region_info, + .get_uuid = ifpga_acc_get_uuid, +}; + +/* Bridge APIs */ + +static int ifpga_br_reset(struct opae_bridge *br) +{ + struct ifpga_port_hw *port = br->data; + + return fpga_port_reset(port); +} + +struct opae_bridge_ops ifpga_br_ops = { + .reset = ifpga_br_reset, +}; + +/* Manager APIs */ +static int ifpga_mgr_flash(struct opae_manager *mgr, int id, void *buf, + u32 size, u64 *status) +{ + struct ifpga_fme_hw *fme = mgr->data; + struct ifpga_hw *hw = fme->parent; + + return ifpga_pr(hw, id, buf, size, status); +} + +struct opae_manager_ops ifpga_mgr_ops = { + .flash = ifpga_mgr_flash, +}; + +/* Adapter APIs */ +static int ifpga_adapter_enumerate(struct opae_adapter *adapter) +{ + struct ifpga_hw *hw = malloc(sizeof(*hw)); + + if (hw) { + memset(hw, 0, sizeof(*hw)); + hw->pci_data = adapter->data; + hw->adapter = adapter; + if (ifpga_bus_enumerate(hw)) + goto error; + return ifpga_bus_init(hw); + } + +error: + return -ENOMEM; +} + +struct opae_adapter_ops ifpga_adapter_ops = { + .enumerate = ifpga_adapter_enumerate, +}; + +/** + * ifpga_pr - do the partial reconfiguration for a given port device + * @hw: pointer to the HW structure + * @port_id: the port device id + * @buffer: the buffer of the bitstream + * @size: the size of the bitstream + * @status: hardware status including PR error code if return -EIO. + * + * @return + * - 0: Success, partial reconfiguration finished. + * - <0: Error code returned in partial reconfiguration. + **/ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return do_pr(hw, port_id, buffer, size, status); +} + +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_get_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_get_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set) +{ + if (!hw || !irq_set) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_irq(&hw->fme, feature_id, irq_set); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_irq(&hw->port[port_id], feature_id, irq_set); + } + + return -ENOENT; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.h b/drivers/raw/ifpga_rawdev/base/ifpga_api.h new file mode 100644 index 0000000..dae7ca1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_API_H_ +#define _IFPGA_API_H_ + +#include "opae_hw_api.h" +#include "ifpga_hw.h" + +extern struct opae_adapter_ops ifpga_adapter_ops; +extern struct opae_manager_ops ifpga_mgr_ops; +extern struct opae_bridge_ops ifpga_br_ops; +extern struct opae_accelerator_ops ifpga_acc_ops; + +/* common APIs */ +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set); + +/* FME APIs */ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +#endif /* _IFPGA_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_compat.h b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h new file mode 100644 index 0000000..931c893 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMPAT_H_ +#define _IFPGA_COMPAT_H_ + +#include "opae_osdep.h" + +#undef container_of +#define container_of(ptr, type, member) ({ \ + typeof(((type *)0)->member)(*__mptr) = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +#define IFPGA_PAGE_SHIFT 12 +#define IFPGA_PAGE_SIZE (1 << IFPGA_PAGE_SHIFT) +#define IFPGA_PAGE_MASK (~(IFPGA_PAGE_SIZE - 1)) +#define IFPGA_PAGE_ALIGN(addr) (((addr) + IFPGA_PAGE_SIZE - 1)\ + & IFPGA_PAGE_MASK) +#define IFPGA_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) +#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), IFPGA_PAGE_SIZE) + +#define readl(addr) opae_readl(addr) +#define readq(addr) opae_readq(addr) +#define writel(value, addr) opae_writel(value, addr) +#define writeq(value, addr) opae_writeq(value, addr) + +#define malloc(size) opae_malloc(size) +#define zmalloc(size) opae_zmalloc(size) +#define free(size) opae_free(size) + +/* + * Wait register's _field to be changed to the given value (_expect's _field) + * by polling with given interval and timeout. + */ +#define fpga_wait_register_field(_field, _expect, _reg_addr, _timeout, _invl)\ +({ \ + int wait = 0; \ + int ret = -ETIMEDOUT; \ + typeof(_expect) value; \ + for (; wait <= _timeout; wait += _invl) { \ + value.csr = readq(_reg_addr); \ + if (_expect._field == value._field) { \ + ret = 0; \ + break; \ + } \ + udelay(_invl); \ + } \ + ret; \ +}) + +#define __maybe_unused __attribute__((__unused__)) + +#define UNUSED(x) (void)(x) + +#endif /* _IFPGA_COMPAT_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h new file mode 100644 index 0000000..bb1e4b9 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -0,0 +1,1662 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_DEFINES_H_ +#define _IFPGA_DEFINES_H_ + +#include "ifpga_compat.h" + +#define MAX_FPGA_PORT_NUM 4 + +#define FME_FEATURE_HEADER "fme_hdr" +#define FME_FEATURE_THERMAL_MGMT "fme_thermal" +#define FME_FEATURE_POWER_MGMT "fme_power" +#define FME_FEATURE_GLOBAL_IPERF "fme_iperf" +#define FME_FEATURE_GLOBAL_ERR "fme_error" +#define FME_FEATURE_PR_MGMT "fme_pr" +#define FME_FEATURE_HSSI_ETH "fme_hssi" +#define FME_FEATURE_GLOBAL_DPERF "fme_dperf" +#define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" + +#define PORT_FEATURE_HEADER "port_hdr" +#define PORT_FEATURE_UAFU "port_uafu" +#define PORT_FEATURE_ERR "port_err" +#define PORT_FEATURE_UMSG "port_umsg" +#define PORT_FEATURE_PR "port_pr" +#define PORT_FEATURE_UINT "port_uint" +#define PORT_FEATURE_STP "port_stp" + +/* + * do not check the revision id as id may be dynamic under + * some cases, e.g, UAFU. + */ +#define SKIP_REVISION_CHECK 0xff + +#define FME_HEADER_REVISION 1 +#define FME_THERMAL_MGMT_REVISION 0 +#define FME_POWER_MGMT_REVISION 1 +#define FME_GLOBAL_IPERF_REVISION 1 +#define FME_GLOBAL_ERR_REVISION 1 +#define FME_PR_MGMT_REVISION 2 +#define FME_HSSI_ETH_REVISION 0 +#define FME_GLOBAL_DPERF_REVISION 0 +#define FME_QSPI_REVISION 0 + +#define PORT_HEADER_REVISION 0 +/* UAFU's header info depends on the downloaded GBS */ +#define PORT_UAFU_REVISION SKIP_REVISION_CHECK +#define PORT_ERR_REVISION 1 +#define PORT_UMSG_REVISION 0 +#define PORT_UINT_REVISION 0 +#define PORT_STP_REVISION 1 + +#define FEATURE_TYPE_AFU 0x1 +#define FEATURE_TYPE_BBB 0x2 +#define FEATURE_TYPE_PRIVATE 0x3 +#define FEATURE_TYPE_FIU 0x4 + +#define FEATURE_FIU_ID_FME 0x0 +#define FEATURE_FIU_ID_PORT 0x1 + +#define FEATURE_ID_HEADER 0x0 +#define FEATURE_ID_AFU 0xff + +enum fpga_id_type { + FME_ID, + PORT_ID, + 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, +}; + +/* + * All headers and structures must be byte-packed to match the spec. + */ +#pragma pack(1) + +struct feature_header { + union { + u64 csr; + struct { + u16 id:12; + u8 revision:4; + u32 next_header_offset:24; + u8 end_of_list:1; + u32 reserved:19; + u8 type:4; + }; + }; +}; + +struct feature_bbb_header { + struct uuid guid; +}; + +struct feature_afu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fiu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fme_capability { + union { + u64 csr; + struct { + u8 fabric_verid; /* Fabric version ID */ + u8 socket_id:1; /* Socket id */ + u8 rsvd1:3; /* Reserved */ + /* pci0 link available yes /no */ + u8 pci0_link_avile:1; + /* pci1 link available yes /no */ + u8 pci1_link_avile:1; + /* Coherent (QPI/UPI) link available yes /no */ + u8 qpi_link_avile:1; + u8 rsvd2:1; /* Reserved */ + /* IOMMU or VT-d supported yes/no */ + u8 iommu_support:1; + u8 num_ports:3; /* Number of ports */ + u8 sf_fab_ctl:1; /* Internal validation bit */ + u8 rsvd3:3; /* Reserved */ + /* + * Address width supported in bits + * BXT -0x26 , SKX -0x30 + */ + u8 address_width_bits:6; + u8 rsvd4:2; /* Reserved */ + /* Size of cache supported in kb */ + u16 cache_size:12; + u8 cache_assoc:4; /* Cache Associativity */ + u16 rsvd5:15; /* Reserved */ + u8 lock_bit:1; /* Lock bit */ + }; + }; +}; + +#define FME_AFU_ACCESS_PF 0 +#define FME_AFU_ACCESS_VF 1 + +struct feature_fme_port { + union { + u64 csr; + struct { + u32 port_offset:24; + u8 reserved1; + u8 port_bar:3; + u32 reserved2:20; + u8 afu_access_control:1; + u8 reserved3:4; + u8 port_implemented:1; + u8 reserved4:3; + }; + }; +}; + +struct feature_fme_fab_status { + union { + u64 csr; + struct { + u8 upilink_status:4; /* UPI Link Status */ + u8 rsvd1:4; /* Reserved */ + u8 pci0link_status:1; /* pci0 link status */ + u8 rsvd2:3; /* Reserved */ + u8 pci1link_status:1; /* pci1 link status */ + u64 rsvd3:51; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_base { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Base Address of memory range */ + u8 protected_base_addrss:4; + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_limit { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Limit Address of memory range */ + u8 protected_limit_addrss:4; + u16 rsvd2:11; /* Reserved */ + u8 enable:1; /* Enable GENPROTRANGE check */ + u32 rsvd3; /* Reserved */ + }; + }; +}; + +struct feature_fme_dxe_lock { + union { + u64 csr; + struct { + /* + * Determines write access to the DXE region CSRs + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_early_lock:1; + /* + * Determines write access to the HSSI CSR + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_late_lock:1; + u64 rsvd:62; + }; + }; +}; + +#define HSSI_ID_NO_HASSI 0 +#define HSSI_ID_PCIE_RP 1 +#define HSSI_ID_ETHERNET 2 + +struct feature_fme_bitstream_id { + union { + u64 csr; + struct { + u32 gitrepo_hash:32; /* GIT repository hash */ + /* + * HSSI configuration identifier: + * 0 - No HSSI + * 1 - PCIe-RP + * 2 - Ethernet + */ + u8 hssi_id:4; + u16 rsvd1:12; /* Reserved */ + /* Bitstream version patch number */ + u8 bs_verpatch:4; + /* Bitstream version minor number */ + u8 bs_verminor:4; + /* Bitstream version major number */ + u8 bs_vermajor:4; + /* Bitstream version debug number */ + u8 bs_verdebug:4; + }; + }; +}; + +struct feature_fme_bitstream_md { + union { + u64 csr; + struct { + /* Seed number userd for synthesis flow */ + u8 synth_seed:4; + /* Synthesis date(day number - 2 digits) */ + u8 synth_day:8; + /* Synthesis date(month number - 2 digits) */ + u8 synth_month:8; + /* Synthesis date(year number - 2 digits) */ + u8 synth_year:8; + u64 rsvd:36; /* Reserved */ + }; + }; +}; + +struct feature_fme_iommu_ctrl { + union { + u64 csr; + struct { + /* Disables IOMMU prefetcher for C0 channel */ + u8 prefetch_disableC0:1; + /* Disables IOMMU prefetcher for C1 channel */ + u8 prefetch_disableC1:1; + /* Disables IOMMU partial cache line writes */ + u8 prefetch_wrdisable:1; + u8 rsvd1:1; /* Reserved */ + /* + * Select counter and read value from register + * iommu_stat.dbg_counters + * 0 - Number of 4K page translation response + * 1 - Number of 2M page translation response + * 2 - Number of 1G page translation response + */ + u8 counter_sel:2; + u32 rsvd2:26; /* Reserved */ + /* Connected to IOMMU SIP Capabilities */ + u32 capecap_defeature; + }; + }; +}; + +struct feature_fme_iommu_stat { + union { + u64 csr; + struct { + /* Translation Enable bit from IOMMU SIP */ + u8 translation_enable:1; + /* Drain request in progress */ + u8 drain_req_inprog:1; + /* Invalidation current state */ + u8 inv_state:3; + /* C0 Response Buffer current state */ + u8 respbuffer_stateC0:3; + /* C1 Response Buffer current state */ + u8 respbuffer_stateC1:3; + /* Last request ID to IOMMU SIP */ + u8 last_reqID:4; + /* Last IOMMU SIP response ID value */ + u8 last_respID:4; + /* Last IOMMU SIP response status value */ + u8 last_respstatus:3; + /* C0 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC0:1; + /* C1 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC1:1; + /* C0 Request FIFO is not empty */ + u8 reqFIFO_notemptyC0:1; + /* C1 Request FIFO is not empty */ + u8 reqFIFO_notemptyC1:1; + /* C0 Response FIFO is not empty */ + u8 respFIFO_notemptyC0:1; + /* C1 Response FIFO is not empty */ + u8 respFIFO_notemptyC1:1; + /* C0 Response FIFO overflow detected */ + u8 respFIFO_overflowC0:1; + /* C1 Response FIFO overflow detected */ + u8 respFIFO_overflowC1:1; + /* C0 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC0:1; + /* C1 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC1:1; + /* Request FIFO overflow detected */ + u8 reqFIFO_overflow:1; + /* IOMMU memory read in progress */ + u8 memrd_inprog:1; + /* IOMMU memory write in progress */ + u8 memwr_inprog:1; + u8 rsvd1:1; /* Reserved */ + /* Value of counter selected by iommu_ctl.counter_sel */ + u16 dbg_counters:16; + u16 rsvd2:12; /* Reserved */ + }; + }; +}; + +struct feature_fme_pcie0_ctrl { + union { + u64 csr; + struct { + u64 vtd_bar_lock:1; /* Lock VT-D BAR register */ + u64 rsvd1:3; + u64 rciep:1; /* Configure PCIE0 as RCiEP */ + u64 rsvd2:59; + }; + }; +}; + +struct feature_fme_llpr_smrr_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR rule is valid or not */ + /* + * SMRR memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR2 rule is valid or not */ + /* + * SMRR2 memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_meseg_base { + union { + u64 csr; + struct { + /* A[45:19] of base address memory range */ + u64 me_base:27; + u64 rsvd:37; + }; + }; +}; + +struct feature_fme_llpr_meseg_limit { + union { + u64 csr; + struct { + /* A[45:19] of limit address memory range */ + u64 me_limit:27; + u64 rsvd1:4; + u64 enable:1; /* Enable LLPR MESEG rule */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 reserved; + u64 scratchpad; + struct feature_fme_capability capability; + struct feature_fme_port port[MAX_FPGA_PORT_NUM]; + struct feature_fme_fab_status fab_status; + struct feature_fme_bitstream_id bitstream_id; + struct feature_fme_bitstream_md bitstream_md; + struct feature_fme_genprotrange2_base genprotrange2_base; + struct feature_fme_genprotrange2_limit genprotrange2_limit; + struct feature_fme_dxe_lock dxe_lock; + struct feature_fme_iommu_ctrl iommu_ctrl; + struct feature_fme_iommu_stat iommu_stat; + struct feature_fme_pcie0_ctrl pcie0_control; + struct feature_fme_llpr_smrr_base smrr_base; + struct feature_fme_llpr_smrr_mask smrr_mask; + struct feature_fme_llpr_smrr2_base smrr2_base; + struct feature_fme_llpr_smrr2_mask smrr2_mask; + struct feature_fme_llpr_meseg_base meseg_base; + struct feature_fme_llpr_meseg_limit meseg_limit; +}; + +struct feature_port_capability { + union { + u64 csr; + struct { + u8 port_number:2; /* Port Number 0-3 */ + u8 rsvd1:6; /* Reserved */ + u16 mmio_size; /* User MMIO size in KB */ + u8 rsvd2; /* Reserved */ + u8 sp_intr_num:4; /* Supported interrupts num */ + u32 rsvd3:28; /* Reserved */ + }; + }; +}; + +struct feature_port_control { + union { + u64 csr; + struct { + u8 port_sftrst:1; /* Port Soft Reset */ + u8 rsvd1:1; /* Reserved */ + u8 latency_tolerance:1;/* '1' >= 40us, '0' < 40us */ + u8 rsvd2:1; /* Reserved */ + u8 port_sftrst_ack:1; /* HW ACK for Soft Reset */ + u64 rsvd3:59; /* Reserved */ + }; + }; +}; + +#define PORT_POWER_STATE_NORMAL 0 +#define PORT_POWER_STATE_AP1 1 +#define PORT_POWER_STATE_AP2 2 +#define PORT_POWER_STATE_AP6 6 + +struct feature_port_status { + union { + u64 csr; + struct { + u8 port_freeze:1; /* '1' - freezed '0' - normal */ + u8 rsvd1:7; /* Reserved */ + u8 power_state:4; /* Power State */ + u8 ap1_event:1; /* AP1 event was detected */ + u8 ap2_event:1; /* AP2 event was detected */ + u64 rsvd2:50; /* Reserved */ + }; + }; +}; + +/* Port Header Register Set */ +struct feature_port_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 port_mailbox; + u64 scratchpad; + struct feature_port_capability capability; + struct feature_port_control control; + struct feature_port_status status; + u64 rsvd2; + u64 user_clk_freq_cmd0; + u64 user_clk_freq_cmd1; + u64 user_clk_freq_sts0; + u64 user_clk_freq_sts1; +}; + +struct feature_fme_tmp_threshold { + union { + u64 csr; + struct { + u8 tmp_thshold1:7; /* temperature Threshold 1 */ + /* temperature Threshold 1 enable/disable */ + u8 tmp_thshold1_enable:1; + u8 tmp_thshold2:7; /* temperature Threshold 2 */ + /* temperature Threshold 2 enable /disable */ + u8 tmp_thshold2_enable:1; + u8 pro_hot_setpoint:7; /* Proc Hot set point */ + u8 rsvd4:1; /* Reserved */ + u8 therm_trip_thshold:7; /* Thermeal Trip Threshold */ + u8 rsvd3:1; /* Reserved */ + u8 thshold1_status:1; /* Threshold 1 Status */ + u8 thshold2_status:1; /* Threshold 2 Status */ + u8 rsvd5:1; /* Reserved */ + /* Thermeal Trip Threshold status */ + u8 therm_trip_thshold_status:1; + u8 rsvd6:4; /* Reserved */ + /* Validation mode- Force Proc Hot */ + u8 valmodeforce:1; + /* Validation mode - Therm trip Hot */ + u8 valmodetherm:1; + u8 rsvd2:2; /* Reserved */ + u8 thshold_policy:1; /* threshold policy */ + u32 rsvd:19; /* Reserved */ + }; + }; +}; + +/* Temperature Sensor Read values format 1 */ +struct feature_fme_temp_rdsensor_fmt1 { + union { + u64 csr; + struct { + /* Reads out FPGA temperature in celsius */ + u8 fpga_temp:7; + u8 rsvd0:1; /* Reserved */ + /* Temperature reading sequence number */ + u16 tmp_reading_seq_num; + /* Temperature reading is valid */ + u8 tmp_reading_valid:1; + u8 rsvd1:7; /* Reserved */ + u16 dbg_mode:10; /* Debug mode */ + u32 rsvd2:22; /* Reserved */ + }; + }; +}; + +/* Temperature sensor read values format 2 */ +struct feature_fme_temp_rdsensor_fmt2 { + u64 rsvd; /* Reserved */ +}; + +/* Temperature Threshold Capability Register */ +struct feature_fme_tmp_threshold_cap { + union { + u64 csr; + struct { + /* Temperature Threshold Unsupported */ + u8 tmp_thshold_disabled:1; + u64 rsvd:63; /* Reserved */ + }; + }; +}; + +/* FME THERNAL FEATURE */ +struct feature_fme_thermal { + struct feature_header header; + struct feature_fme_tmp_threshold threshold; + struct feature_fme_temp_rdsensor_fmt1 rdsensor_fm1; + struct feature_fme_temp_rdsensor_fmt2 rdsensor_fm2; + struct feature_fme_tmp_threshold_cap threshold_cap; +}; + +/* Power Status register */ +struct feature_fme_pm_status { + union { + u64 csr; + struct { + /* FPGA Power consumed, The format is to be defined */ + u32 pwr_consumed:18; + /* FPGA Latency Tolerance Reporting */ + u8 fpga_latency_report:1; + u64 rsvd:45; /* Reserved */ + }; + }; +}; + +/* AP Thresholds */ +struct feature_fme_pm_ap_threshold { + union { + u64 csr; + struct { + /* + * Number of clocks (5ns period) for assertion + * of FME_data + */ + u8 threshold1:7; + u8 rsvd1:1; + u8 threshold2:7; + u8 rsvd2:1; + u8 threshold1_status:1; + u8 threshold2_status:1; + u64 rsvd3:46; /* Reserved */ + }; + }; +}; + +/* Xeon Power Limit */ +struct feature_fme_pm_xeon_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FPGA Power Limit */ +struct feature_fme_pm_fpga_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FME POWER FEATURE */ +struct feature_fme_power { + struct feature_header header; + struct feature_fme_pm_status status; + struct feature_fme_pm_ap_threshold threshold; + struct feature_fme_pm_xeon_limit xeon_limit; + struct feature_fme_pm_fpga_limit fpga_limit; +}; + +#define CACHE_CHANNEL_RD 0 +#define CACHE_CHANNEL_WR 1 + +enum iperf_cache_events { + IPERF_CACHE_RD_HIT, + IPERF_CACHE_WR_HIT, + IPERF_CACHE_RD_MISS, + IPERF_CACHE_WR_MISS, + IPERF_CACHE_RSVD, /* reserved */ + IPERF_CACHE_HOLD_REQ, + IPERF_CACHE_DATA_WR_PORT_CONTEN, + IPERF_CACHE_TAG_WR_PORT_CONTEN, + IPERF_CACHE_TX_REQ_STALL, + IPERF_CACHE_RX_REQ_STALL, + IPERF_CACHE_EVICTIONS, +}; + +/* FPMON Cache Control */ +struct feature_fme_ifpmon_ch_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd1:7; /* Reserved */ + u8 freeze:1; /* Freeze if set to 1 */ + u8 rsvd2:7; /* Reserved */ + u8 cache_event:4; /* Select the cache event */ + u8 cci_chsel:1; /* Select the channel */ + u64 rsvd3:43; /* Reserved */ + }; + }; +}; + +/* FPMON Cache Counter */ +struct feature_fme_ifpmon_ch_ctr { + union { + u64 csr; + struct { + /* Cache Counter for even addresse */ + u64 cache_counter:48; + u16 rsvd:12; /* Reserved */ + /* Cache Event being reported */ + u8 event_code:4; + }; + }; +}; + +enum iperf_fab_events { + IPERF_FAB_PCIE0_RD, + IPERF_FAB_PCIE0_WR, + IPERF_FAB_PCIE1_RD, + IPERF_FAB_PCIE1_WR, + IPERF_FAB_UPI_RD, + IPERF_FAB_UPI_WR, + IPERF_FAB_MMIO_RD, + IPERF_FAB_MMIO_WR, +}; + +#define FAB_DISABLE_FILTER 0 +#define FAB_ENABLE_FILTER 1 + +/* FPMON FAB Control */ +struct feature_fme_ifpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_ifpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_ifpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +enum iperf_vtd_events { + IPERF_VTD_AFU_MEM_RD_TRANS, + IPERF_VTD_AFU_MEM_WR_TRANS, + IPERF_VTD_AFU_DEVTLB_RD_HIT, + IPERF_VTD_AFU_DEVTLB_WR_HIT, + IPERF_VTD_DEVTLB_4K_FILL, + IPERF_VTD_DEVTLB_2M_FILL, + IPERF_VTD_DEVTLB_1G_FILL, +}; + +/* VT-d control register */ +struct feature_fme_ifpmon_vtd_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d event counter */ +struct feature_fme_ifpmon_vtd_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +enum iperf_vtd_sip_events { + IPERF_VTD_SIP_IOTLB_4K_HIT, + IPERF_VTD_SIP_IOTLB_2M_HIT, + IPERF_VTD_SIP_IOTLB_1G_HIT, + IPERF_VTD_SIP_SLPWC_L3_HIT, + IPERF_VTD_SIP_SLPWC_L4_HIT, + IPERF_VTD_SIP_RCC_HIT, + IPERF_VTD_SIP_IOTLB_4K_MISS, + IPERF_VTD_SIP_IOTLB_2M_MISS, + IPERF_VTD_SIP_IOTLB_1G_MISS, + IPERF_VTD_SIP_SLPWC_L3_MISS, + IPERF_VTD_SIP_SLPWC_L4_MISS, + IPERF_VTD_SIP_RCC_MISS, +}; + +/* VT-d SIP control register */ +struct feature_fme_ifpmon_vtd_sip_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d SIP event counter */ +struct feature_fme_ifpmon_vtd_sip_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +/* FME IPERF FEATURE */ +struct feature_fme_iperf { + struct feature_header header; + struct feature_fme_ifpmon_ch_ctl ch_ctl; + struct feature_fme_ifpmon_ch_ctr ch_ctr0; + struct feature_fme_ifpmon_ch_ctr ch_ctr1; + struct feature_fme_ifpmon_fab_ctl fab_ctl; + struct feature_fme_ifpmon_fab_ctr fab_ctr; + struct feature_fme_ifpmon_clk_ctr clk; + struct feature_fme_ifpmon_vtd_ctl vtd_ctl; + struct feature_fme_ifpmon_vtd_ctr vtd_ctr; + struct feature_fme_ifpmon_vtd_sip_ctl vtd_sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr vtd_sip_ctr; +}; + +enum dperf_fab_events { + DPERF_FAB_PCIE0_RD, + DPERF_FAB_PCIE0_WR, + DPERF_FAB_MMIO_RD = 6, + DPERF_FAB_MMIO_WR, +}; + +/* FPMON FAB Control */ +struct feature_fme_dfpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_dfpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_dfpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +/* FME DPERF FEATURE */ +struct feature_fme_dperf { + struct feature_header header; + u64 rsvd[3]; + struct feature_fme_dfpmon_fab_ctl fab_ctl; + struct feature_fme_dfpmon_fab_ctr fab_ctr; + struct feature_fme_dfpmon_clk_ctr clk; +}; + +struct feature_fme_error0 { +#define FME_ERROR0_MASK 0xFFUL +#define FME_ERROR0_MASK_DEFAULT 0x40UL /* pcode workaround */ + union { + u64 csr; + struct { + u8 fabric_err:1; /* Fabric error */ + u8 fabfifo_overflow:1; /* Fabric fifo overflow */ + u8 kticdc_parity_err:2;/* KTI CDC Parity Error */ + u8 iommu_parity_err:1; /* IOMMU Parity error */ + /* AFU PF/VF access mismatch detected */ + u8 afu_acc_mode_err:1; + u8 mbp_err:1; /* Indicates an MBP event */ + /* PCIE0 CDC Parity Error */ + u8 pcie0cdc_parity_err:5; + /* PCIE1 CDC Parity Error */ + u8 pcie1cdc_parity_err:5; + /* CVL CDC Parity Error */ + u8 cvlcdc_parity_err:3; + u64 rsvd:44; /* Reserved */ + }; + }; +}; + +/* PCIe0 Error Status register */ +struct feature_fme_pcie0_error { +#define FME_PCIE0_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:52; /* Reserved */ + u8 vfnumb_err:1; /* Number of error VF */ + u8 funct_type_err:1; /* Virtual (1) or Physical */ + }; + }; +}; + +/* PCIe1 Error Status register */ +struct feature_fme_pcie1_error { +#define FME_PCIE1_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:54; /* Reserved */ + }; + }; +}; + +/* FME First Error register */ +struct feature_fme_first_error { +#define FME_FIRST_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered first + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered first + */ + u8 errReg_id:4; + }; + }; +}; + +/* FME Next Error register */ +struct feature_fme_next_error { +#define FME_NEXT_ERROR_MASK ((1UL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered second + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered second + */ + u8 errReg_id:4; + }; + }; +}; + +/* RAS Non Fatal Error Status register */ +struct feature_fme_ras_nonfaterror { + union { + u64 csr; + struct { + /* thremal threshold AP1 */ + u8 temp_thresh_ap1:1; + /* thremal threshold AP2 */ + u8 temp_thresh_ap2:1; + u8 pcie_error:1; /* pcie Error */ + u8 portfatal_error:1; /* port fatal error */ + u8 proc_hot:1; /* Indicates a ProcHot event */ + /* Indicates an AFU PF/VF access mismatch */ + u8 afu_acc_mode_err:1; + /* Injected nonfata Error */ + u8 injected_nonfata_err:1; + u8 rsvd1:2; + /* Temperature threshold triggered AP6*/ + u8 temp_thresh_AP6:1; + /* Power threshold triggered AP1 */ + u8 power_thresh_AP1:1; + /* Power threshold triggered AP2 */ + u8 power_thresh_AP2:1; + /* Indicates a MBP event */ + u8 mbp_err:1; + u64 rsvd2:51; /* Reserved */ + }; + }; +}; + +/* RAS Catastrophic Fatal Error Status register */ +struct feature_fme_ras_catfaterror { + union { + u64 csr; + struct { + /* KTI Link layer error detected */ + u8 ktilink_fatal_err:1; + /* tag-n-cache error detected */ + u8 tagcch_fatal_err:1; + /* CCI error detected */ + u8 cci_fatal_err:1; + /* KTI Protocol error detected */ + u8 ktiprpto_fatal_err:1; + /* Fatal DRAM error detected */ + u8 dram_fatal_err:1; + /* IOMMU detected */ + u8 iommu_fatal_err:1; + /* Fabric Fatal Error */ + u8 fabric_fatal_err:1; + /* PCIe possion Error */ + u8 pcie_poison_err:1; + /* Injected fatal Error */ + u8 inject_fata_err:1; + /* Catastrophic CRC Error */ + u8 crc_catast_err:1; + /* Catastrophic Thermal Error */ + u8 therm_catast_err:1; + /* Injected Catastrophic Error */ + u8 injected_catast_err:1; + u64 rsvd:52; + }; + }; +}; + +/* RAS Error injection register */ +struct feature_fme_ras_error_inj { +#define FME_RAS_ERROR_INJ_MASK 0x7UL + union { + u64 csr; + struct { + u8 catast_error:1; /* Catastrophic error flag */ + u8 fatal_error:1; /* Fatal error flag */ + u8 nonfatal_error:1; /* NonFatal error flag */ + u64 rsvd:61; /* Reserved */ + }; + }; +}; + +/* FME error capabilities */ +struct feature_fme_error_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* FME ERR FEATURE */ +struct feature_fme_err { + struct feature_header header; + struct feature_fme_error0 fme_err_mask; + struct feature_fme_error0 fme_err; + struct feature_fme_pcie0_error pcie0_err_mask; + struct feature_fme_pcie0_error pcie0_err; + struct feature_fme_pcie1_error pcie1_err_mask; + struct feature_fme_pcie1_error pcie1_err; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + struct feature_fme_ras_nonfaterror ras_nonfat_mask; + struct feature_fme_ras_nonfaterror ras_nonfaterr; + struct feature_fme_ras_catfaterror ras_catfat_mask; + struct feature_fme_ras_catfaterror ras_catfaterr; + struct feature_fme_ras_error_inj ras_error_inj; + struct feature_fme_error_capability fme_err_capability; +}; + +/* FME Partial Reconfiguration Control */ +struct feature_fme_pr_ctl { + union { + u64 csr; + struct { + u8 pr_reset:1; /* Reset PR Engine */ + u8 rsvd3:3; /* Reserved */ + u8 pr_reset_ack:1; /* Reset PR Engine Ack */ + u8 rsvd4:3; /* Reserved */ + u8 pr_regionid:2; /* PR Region ID */ + u8 rsvd1:2; /* Reserved */ + u8 pr_start_req:1; /* PR Start Request */ + u8 pr_push_complete:1; /* PR Data push complete */ + u8 pr_kind:1; /* PR Data push complete */ + u32 rsvd:17; /* Reserved */ + u32 config_data; /* Config data TBD */ + }; + }; +}; + +/* FME Partial Reconfiguration Status */ +struct feature_fme_pr_status { + union { + u64 csr; + struct { + u16 pr_credit:9; /* PR Credits */ + u8 rsvd2:7; /* Reserved */ + u8 pr_status:1; /* PR status */ + u8 rsvd:3; /* Reserved */ + /* Altra PR Controller Block status */ + u8 pr_controller_status:3; + u8 rsvd1:1; /* Reserved */ + u8 pr_host_status:4; /* PR Host status */ + u8 rsvd3:4; /* Reserved */ + /* Security Block Status fields (TBD) */ + u32 security_bstatus; + }; + }; +}; + +/* FME Partial Reconfiguration Data */ +struct feature_fme_pr_data { + union { + u64 csr; /* PR data from the raw-binary file */ + struct { + /* PR data from the raw-binary file */ + u32 pr_data_raw; + u32 rsvd; + }; + }; +}; + +/* FME PR Public Key */ +struct feature_fme_pr_key { + u64 key; /* FME PR Public Hash */ +}; + +/* FME PR FEATURE */ +struct feature_fme_pr { + struct feature_header header; + /*Partial Reconfiguration control */ + struct feature_fme_pr_ctl ccip_fme_pr_control; + + /* Partial Reconfiguration Status */ + struct feature_fme_pr_status ccip_fme_pr_status; + + /* Partial Reconfiguration data */ + struct feature_fme_pr_data ccip_fme_pr_data; + + /* Partial Reconfiguration data */ + u64 ccip_fme_pr_err; + + u64 rsvd1[3]; + + /* Partial Reconfiguration data registers */ + u64 fme_pr_data1; + u64 fme_pr_data2; + u64 fme_pr_data3; + u64 fme_pr_data4; + u64 fme_pr_data5; + u64 fme_pr_data6; + u64 fme_pr_data7; + u64 fme_pr_data8; + + u64 rsvd2[5]; + + /* PR Interface ID */ + u64 fme_pr_intfc_id_l; + u64 fme_pr_intfc_id_h; + + /* MSIX filed to be Added */ +}; + +/* FME HSSI Control */ +struct feature_fme_hssi_eth_ctrl { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u16 address:16; /* HSSI address */ + /* + * HSSI comamnd + * 0x0 - No request + * 0x08 - SW register RD request + * 0x10 - SW register WR request + * 0x40 - Auxiliar bus RD request + * 0x80 - Auxiliar bus WR request + */ + u16 cmd:16; + }; + }; +}; + +/* FME HSSI Status */ +struct feature_fme_hssi_eth_stat { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u8 acknowledge:1; /* HSSI acknowledge */ + u8 spare:1; /* HSSI spare */ + u32 rsvd:30; /* Reserved */ + }; + }; +}; + +/* FME HSSI FEATURE */ +struct feature_fme_hssi { + struct feature_header header; + struct feature_fme_hssi_eth_ctrl hssi_control; + struct feature_fme_hssi_eth_stat hssi_status; +}; + +#define PORT_ERR_MASK 0xfff0703ff001f +struct feature_port_err_key { + union { + u64 csr; + struct { + /* Tx Channel0: Overflow */ + u8 tx_ch0_overflow:1; + /* Tx Channel0: Invalid request encoding */ + u8 tx_ch0_invaldreq :1; + /* Tx Channel0: Request with cl_len=3 not supported */ + u8 tx_ch0_cl_len3:1; + /* Tx Channel0: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch0_cl_len2:1; + /* Tx Channel0: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch0_cl_len4:1; + + u16 rsvd1:4; /* Reserved */ + + /* AFU MMIO RD received while PORT is in reset */ + u8 mmio_rd_whilerst:1; + /* AFU MMIO WR received while PORT is in reset */ + u8 mmio_wr_whilerst:1; + + u16 rsvd2:5; /* Reserved */ + + /* Tx Channel1: Overflow */ + u8 tx_ch1_overflow:1; + /* Tx Channel1: Invalid request encoding */ + u8 tx_ch1_invaldreq:1; + /* Tx Channel1: Request with cl_len=3 not supported */ + u8 tx_ch1_cl_len3:1; + /* Tx Channel1: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch1_cl_len2:1; + /* Tx Channel1: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch1_cl_len4:1; + + /* Tx Channel1: Insufficient data payload */ + u8 tx_ch1_insuff_data:1; + /* Tx Channel1: Data payload overrun */ + u8 tx_ch1_data_overrun:1; + /* Tx Channel1 : Incorrect address */ + u8 tx_ch1_incorr_addr:1; + /* Tx Channel1 : NON-Zero SOP Detected */ + u8 tx_ch1_nzsop:1; + /* Tx Channel1 : Illegal VC_SEL, atomic request VLO */ + u8 tx_ch1_illegal_vcsel:1; + + u8 rsvd3:6; /* Reserved */ + + /* MMIO Read Timeout in AFU */ + u8 mmioread_timeout:1; + + /* Tx Channel2: FIFO Overflow */ + u8 tx_ch2_fifo_overflow:1; + + /* MMIO read is not matching pending request */ + u8 unexp_mmio_resp:1; + + u8 rsvd4:5; /* Reserved */ + + /* Number of pending Requests: counter overflow */ + u8 tx_req_counter_overflow:1; + /* Req with Address violating SMM Range */ + u8 llpr_smrr_err:1; + /* Req with Address violating second SMM Range */ + u8 llpr_smrr2_err:1; + /* Req with Address violating ME Stolen message */ + u8 llpr_mesg_err:1; + /* Req with Address violating Generic Protected Range */ + u8 genprot_range_err:1; + /* Req with Address violating Legacy Range low */ + u8 legrange_low_err:1; + /* Req with Address violating Legacy Range High */ + u8 legrange_high_err:1; + /* Req with Address violating VGA memory range */ + u8 vgmem_range_err:1; + u8 page_fault_err:1; /* Page fault */ + u8 pmr_err:1; /* PMR Error */ + u8 ap6_event:1; /* AP6 event */ + /* VF FLR detected on Port with PF access control */ + u8 vfflr_access_err:1; + u16 rsvd5:12; /* Reserved */ + }; + }; +}; + +/* Port first error register, not contain all error bits in error register. */ +struct feature_port_first_err_key { + union { + u64 csr; + struct { + u8 tx_ch0_overflow:1; + u8 tx_ch0_invaldreq :1; + u8 tx_ch0_cl_len3:1; + u8 tx_ch0_cl_len2:1; + u8 tx_ch0_cl_len4:1; + u8 rsvd1:4; /* Reserved */ + u8 mmio_rd_whilerst:1; + u8 mmio_wr_whilerst:1; + u8 rsvd2:5; /* Reserved */ + u8 tx_ch1_overflow:1; + u8 tx_ch1_invaldreq:1; + u8 tx_ch1_cl_len3:1; + u8 tx_ch1_cl_len2:1; + u8 tx_ch1_cl_len4:1; + u8 tx_ch1_insuff_data:1; + u8 tx_ch1_data_overrun:1; + u8 tx_ch1_incorr_addr:1; + u8 tx_ch1_nzsop:1; + u8 tx_ch1_illegal_vcsel:1; + u8 rsvd3:6; /* Reserved */ + u8 mmioread_timeout:1; + u8 tx_ch2_fifo_overflow:1; + u8 rsvd4:6; /* Reserved */ + u8 tx_req_counter_overflow:1; + u32 rsvd5:23; /* Reserved */ + }; + }; +}; + +/* Port malformed Req0 */ +struct feature_port_malformed_req0 { + u64 header_lsb; +}; + +/* Port malformed Req1 */ +struct feature_port_malformed_req1 { + u64 header_msb; +}; + +/* Port debug register */ +struct feature_port_debug { + u64 port_debug; +}; + +/* Port error capabilities */ +struct feature_port_err_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE ERROR */ +struct feature_port_error { + struct feature_header header; + struct feature_port_err_key error_mask; + struct feature_port_err_key port_error; + struct feature_port_first_err_key port_first_error; + struct feature_port_malformed_req0 malreq0; + struct feature_port_malformed_req1 malreq1; + struct feature_port_debug port_debug; + struct feature_port_err_capability error_capability; +}; + +/* Port UMSG Capability */ +struct feature_port_umsg_cap { + union { + u64 csr; + struct { + /* Number of umsg allocated to this port */ + u8 umsg_allocated; + /* Enable / Disable UMsg engine for this port */ + u8 umsg_enable:1; + /* Usmg initialization status */ + u8 umsg_init_complete:1; + /* IOMMU can not translate the umsg base address */ + u8 umsg_trans_error:1; + u64 rsvd:53; /* Reserved */ + }; + }; +}; + +/* Port UMSG base address */ +struct feature_port_umsg_baseaddr { + union { + u64 csr; + struct { + u64 base_addr:48; /* 48 bit physical address */ + u16 rsvd; /* Reserved */ + }; + }; +}; + +struct feature_port_umsg_mode { + union { + u64 csr; + struct { + u32 umsg_hint_enable; /* UMSG hint enable/disable */ + u32 rsvd; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE UMSG */ +struct feature_port_umsg { + struct feature_header header; + struct feature_port_umsg_cap capability; + struct feature_port_umsg_baseaddr baseaddr; + struct feature_port_umsg_mode mode; +}; + +#define UMSG_EN_POLL_INVL 10 /* us */ +#define UMSG_EN_POLL_TIMEOUT 1000 /* us */ + +/* Port UINT Capability */ +struct feature_port_uint_cap { + union { + u64 csr; + struct { + u16 intr_num:12; /* Supported interrupts num */ + /* First MSI-X vector table entry number */ + u16 first_vec_num:12; + u64 rsvd:40; + }; + }; +}; + +/* PORT FEATURE UINT */ +struct feature_port_uint { + struct feature_header header; + struct feature_port_uint_cap capability; +}; + +/* STP region supports mmap operation, so use page aligned size. */ +#define PORT_FEATURE_STP_REGION_SIZE \ + IFPGA_PAGE_ALIGN(sizeof(struct feature_port_stp)) + +/* Port STP status register (for debug only)*/ +struct feature_port_stp_status { + union { + u64 csr; + struct { + /* SLD Hub end-point read/write timeout */ + u8 sld_ep_timeout:1; + /* Remote STP in reset/disable */ + u8 rstp_disabled:1; + u8 unsupported_read:1; + /* MMIO timeout detected and faked with a response */ + u8 mmio_timeout:1; + u8 txfifo_count:4; + u8 rxfifo_count:4; + u8 txfifo_overflow:1; + u8 txfifo_underflow:1; + u8 rxfifo_overflow:1; + u8 rxfifo_underflow:1; + /* Number of MMIO write requests */ + u16 write_requests; + /* Number of MMIO read requests */ + u16 read_requests; + /* Number of MMIO read responses */ + u16 read_responses; + }; + }; +}; + +/* + * PORT FEATURE STP + * Most registers in STP region are not touched by driver, but mmapped to user + * space. So they are not defined in below data structure, as its actual size + * is 0x18c per spec. + */ +struct feature_port_stp { + struct feature_header header; + struct feature_port_stp_status stp_status; +}; + +/** + * enum fpga_pr_states - fpga PR states + * @FPGA_PR_STATE_UNKNOWN: can't determine state + * @FPGA_PR_STATE_WRITE_INIT: preparing FPGA for programming + * @FPGA_PR_STATE_WRITE_INIT_ERR: Error during WRITE_INIT stage + * @FPGA_PR_STATE_WRITE: writing image to FPGA + * @FPGA_PR_STATE_WRITE_ERR: Error while writing FPGA + * @FPGA_PR_STATE_WRITE_COMPLETE: Doing post programming steps + * @FPGA_PR_STATE_WRITE_COMPLETE_ERR: Error during WRITE_COMPLETE + * @FPGA_PR_STATE_OPERATING: FPGA PR done + */ +enum fpga_pr_states { + /* canot determine state states */ + FPGA_PR_STATE_UNKNOWN, + + /* write sequence: init, write, complete */ + FPGA_PR_STATE_WRITE_INIT, + FPGA_PR_STATE_WRITE_INIT_ERR, + FPGA_PR_STATE_WRITE, + FPGA_PR_STATE_WRITE_ERR, + FPGA_PR_STATE_WRITE_COMPLETE, + FPGA_PR_STATE_WRITE_COMPLETE_ERR, + + /* FPGA PR done */ + FPGA_PR_STATE_DONE, +}; + +/* + * FPGA Manager flags + * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported + */ +#define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + +/** + * struct fpga_pr_info - specific information to a FPGA PR + * @flags: boolean flags as defined above + * @pr_err: PR error code + * @state: fpga manager state + * @port_id: port id + */ +struct fpga_pr_info { + u32 flags; + u64 pr_err; + enum fpga_pr_states state; + int port_id; +}; + +#define DEFINE_FPGA_PR_ERR_MSG(_name_) \ +static const char * const _name_[] = { \ + "PR operation error detected", \ + "PR CRC error detected", \ + "PR incompatiable bitstream error detected", \ + "PR IP protocol error detected", \ + "PR FIFO overflow error detected", \ + "PR timeout error detected", \ + "PR secure load error detected", \ +} + +#define RST_POLL_INVL 10 /* us */ +#define RST_POLL_TIMEOUT 1000 /* us */ + +#define PR_WAIT_TIMEOUT 15000000 + +#define PR_HOST_STATUS_IDLE 0 +#define PR_MAX_ERR_NUM 7 + +DEFINE_FPGA_PR_ERR_MSG(pr_err_msg); + +/* + * green bitstream header must be byte-packed to match the + * real file format. + */ +struct bts_header { + u64 guid_h; + u64 guid_l; + u32 metadata_len; +}; + +#define GBS_GUID_H 0x414750466e6f6558 +#define GBS_GUID_L 0x31303076534247b7 +#define is_valid_bts(bts_hdr) \ + (((bts_hdr)->guid_h == GBS_GUID_H) && \ + ((bts_hdr)->guid_l == GBS_GUID_L)) + +#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 new file mode 100644 index 0000000..10a8f06 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -0,0 +1,824 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_hw_api.h" +#include "ifpga_api.h" + +#include "ifpga_hw.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +struct build_feature_devs_info { + struct opae_adapter_data_pci *pci_data; + + struct ifpga_afu_info *acc_info; + + void *fiu; + enum fpga_id_type current_type; + int current_port_id; + + void *ioaddr; + void *ioend; + uint64_t phys_addr; + int current_bar; + + void *pfme_hdr; + + struct ifpga_hw *hw; +}; + +struct feature_info { + const char *name; + uint32_t resource_size; + int feature_index; + int revision_id; + unsigned int vec_start; + unsigned int vec_cnt; + + struct feature_ops *ops; +}; + +/* 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, + } +}; + +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 = &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 = &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 = &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 = &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 + }, +}; + +static u64 feature_id(void __iomem *start) +{ + struct feature_header header; + + header.csr = readq(start); + + switch (header.type) { + case FEATURE_TYPE_FIU: + return FEATURE_ID_HEADER; + case FEATURE_TYPE_PRIVATE: + return header.id; + case FEATURE_TYPE_AFU: + return FEATURE_ID_AFU; + } + + WARN_ON(1); + return 0; +} + +static int +build_info_add_sub_feature(struct build_feature_devs_info *binfo, + struct feature_info *finfo, void __iomem *start) +{ + 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; + } + + 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->phys_addr = binfo->phys_addr + + ((u8 *)start - (u8 *)binfo->ioaddr); + + if (vec_cnt) { + if (vec_start + vec_cnt <= vec_start) + return -EINVAL; + + ctx = zmalloc(sizeof(*ctx) * vec_cnt); + if (!ctx) + return -ENOMEM; + + for (i = 0; i < vec_cnt; i++) { + ctx[i].eventfd = -1; + ctx[i].idx = vec_start + i; + } + } + + feature->ctx = ctx; + feature->ctx_num = vec_cnt; + feature->vfio_dev_fd = binfo->pci_data->vfio_dev_fd; + + return ret; +} + +static int +create_feature_instance(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + struct feature_header *hdr = start; + + if (((u8 *)binfo->ioend - (u8 *)start) < finfo->resource_size) + return -EINVAL; + + 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); +} + +/* + * UAFU GUID is dynamic as it can be changed after FME downloads different + * Green Bitstream to the port, so we treat the unknown GUIDs which are + * attached on port's feature list as UAFU. + */ +static bool feature_is_UAFU(struct build_feature_devs_info *binfo) +{ + if (binfo->current_type != PORT_ID) + return false; + + return true; +} + +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; + struct ifpga_afu_info *info; + void *start = (void *)hdr; + int ret; + + 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; + } + + if (ret) + return ret; + + /* FIXME: need to figure out a better name */ + info = 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->num_regions = 1; + + binfo->acc_info = info; + + return ret; +} + +static int parse_feature_afus(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + int ret; + struct feature_afu_header *afu_hdr, header; + u8 __iomem *start; + u8 __iomem *end = binfo->ioend; + + start = (u8 __iomem *)hdr; + for (; start < end; start += header.next_afu) { + if (end - start < + (unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr))) + return -EINVAL; + + hdr = (struct feature_header *)start; + afu_hdr = (struct feature_afu_header *)(hdr + 1); + header.csr = readq(&afu_hdr->csr); + + if (feature_is_UAFU(binfo)) { + ret = parse_feature_port_uafu(binfo, hdr); + if (ret) + return ret; + } + + if (!header.next_afu) + break; + } + + return 0; +} + +/* create and register proper private data */ +static int build_info_commit_dev(struct build_feature_devs_info *binfo) +{ + struct ifpga_afu_info *info = binfo->acc_info; + struct ifpga_hw *hw = binfo->hw; + struct opae_manager *mgr; + struct opae_bridge *br; + struct opae_accelerator *acc; + + if (!binfo->fiu) + return 0; + + if (binfo->current_type == PORT_ID) { + /* return error if no valid acc info data structure */ + if (!info) + return -EFAULT; + + br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops, + binfo->fiu); + if (!br) + return -ENOMEM; + + br->id = binfo->current_port_id; + + /* update irq info */ + info->num_irqs = port_features[PORT_FEATURE_ID_UINT].vec_cnt; + + acc = opae_accelerator_alloc(hw->adapter->name, + &ifpga_acc_ops, info); + if (!acc) { + opae_bridge_free(br); + return -ENOMEM; + } + + acc->br = br; + acc->index = br->id; + + opae_adapter_add_acc(hw->adapter, acc); + + } else if (binfo->current_type == FME_ID) { + mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops, + binfo->fiu); + if (!mgr) + return -ENOMEM; + + mgr->adapter = hw->adapter; + hw->adapter->mgr = mgr; + } + + binfo->fiu = NULL; + + return 0; +} + +static int +build_info_create_dev(struct build_feature_devs_info *binfo, + enum fpga_id_type type, unsigned int index) +{ + int ret; + + ret = build_info_commit_dev(binfo); + if (ret) + return ret; + + binfo->current_type = type; + + if (type == FME_ID) { + binfo->fiu = &binfo->hw->fme; + } else if (type == PORT_ID) { + binfo->fiu = &binfo->hw->port[index]; + binfo->current_port_id = index; + } + + return 0; +} + +static int parse_feature_fme(struct build_feature_devs_info *binfo, + struct feature_header *start) +{ + struct ifpga_hw *hw = binfo->hw; + struct ifpga_fme_hw *fme = &hw->fme; + int ret; + + ret = build_info_create_dev(binfo, FME_ID, 0); + if (ret) + return ret; + + /* Update FME states */ + fme->state = IFPGA_FME_IMPLEMENTED; + fme->parent = hw; + spinlock_init(&fme->lock); + + return create_feature_instance(binfo, start, + &fme_features[FME_FEATURE_ID_HEADER]); +} + +static int parse_feature_port(struct build_feature_devs_info *binfo, + void __iomem *start) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + struct ifpga_hw *hw = binfo->hw; + struct ifpga_port_hw *port; + unsigned int port_id; + int ret; + + /* Get current port's id */ + port_hdr = (struct feature_port_header *)start; + capability.csr = readq(&port_hdr->capability); + port_id = capability.port_number; + + ret = build_info_create_dev(binfo, PORT_ID, port_id); + if (ret) + return ret; + + /*found a Port device*/ + port = &hw->port[port_id]; + port->port_id = binfo->current_port_id; + port->parent = hw; + port->state = IFPGA_PORT_ATTACHED; + spinlock_init(&port->lock); + + return create_feature_instance(binfo, start, + &port_features[PORT_FEATURE_ID_HEADER]); +} + +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); +} + +static int parse_feature_fiu(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + struct feature_fiu_header *fiu_hdr, fiu_header; + u8 __iomem *start = (u8 __iomem *)hdr; + int ret; + + header.csr = readq(hdr); + + switch (header.id) { + case FEATURE_FIU_ID_FME: + ret = parse_feature_fme(binfo, hdr); + binfo->pfme_hdr = hdr; + if (ret) + return ret; + break; + case FEATURE_FIU_ID_PORT: + ret = parse_feature_port(binfo, hdr); + enable_port_uafu(binfo, hdr); + if (ret) + return ret; + + /* Check Port FIU's next_afu pointer to User AFU DFH */ + fiu_hdr = (struct feature_fiu_header *)(hdr + 1); + fiu_header.csr = readq(&fiu_hdr->csr); + + if (fiu_header.next_afu) { + start += fiu_header.next_afu; + ret = parse_feature_afus(binfo, + (struct feature_header *)start); + if (ret) + return ret; + } else { + dev_info(binfo, "No AFUs detected on Port\n"); + } + + break; + default: + dev_info(binfo, "FIU TYPE %d is not supported yet.\n", + header.id); + } + + return 0; +} + +static void parse_feature_irqs(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + finfo->vec_start = 0; + finfo->vec_cnt = 0; + + UNUSED(binfo); + + if (!strcmp(finfo->name, PORT_FEATURE_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; + } else { + dev_debug(binfo, "UAFU doesn't support interrupt\n"); + } + } else if (!strcmp(finfo->name, PORT_FEATURE_ERR)) { + 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; + } else { + dev_debug(&binfo, "Port error doesn't support interrupt\n"); + } + + } else if (!strcmp(finfo->name, FME_FEATURE_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; + } else { + dev_debug(&binfo, "FME error doesn't support interrupt\n"); + } + } +} + +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; + } + + parse_feature_irqs(binfo, hdr, &fme_features[header.id]); + + return create_feature_instance(binfo, hdr, &fme_features[header.id]); +} + +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; + + 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]); + + return create_feature_instance(binfo, hdr, &port_features[id]); +} + +static int parse_feature_private(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + + header.csr = readq(hdr); + + switch (binfo->current_type) { + case FME_ID: + return parse_feature_fme_private(binfo, hdr); + case PORT_ID: + return parse_feature_port_private(binfo, hdr); + default: + dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n", + header.id, binfo->current_type); + } + return 0; +} + +static int parse_feature(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + int ret = 0; + + header.csr = readq(hdr); + + switch (header.type) { + case FEATURE_TYPE_AFU: + ret = parse_feature_afus(binfo, hdr); + break; + case FEATURE_TYPE_PRIVATE: + ret = parse_feature_private(binfo, hdr); + break; + case FEATURE_TYPE_FIU: + ret = parse_feature_fiu(binfo, hdr); + break; + default: + dev_err(binfo, "Feature Type %x is not supported.\n", + hdr->type); + }; + + return ret; +} + +static int +parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start) +{ + struct feature_header *hdr, header; + u8 __iomem *end = (u8 __iomem *)binfo->ioend; + int ret = 0; + + for (; start < end; start += header.next_header_offset) { + if (end - start < (unsigned int)sizeof(*hdr)) { + dev_err(binfo, "The region is too small to contain a feature.\n"); + ret = -EINVAL; + break; + } + + hdr = (struct feature_header *)start; + ret = parse_feature(binfo, hdr); + if (ret) + return ret; + + header.csr = readq(hdr); + if (!header.next_header_offset) + break; + } + + return build_info_commit_dev(binfo); +} + +/* switch the memory mapping to BAR# @bar */ +static int parse_switch_to(struct build_feature_devs_info *binfo, int bar) +{ + struct opae_adapter_data_pci *pci_data = binfo->pci_data; + + if (!pci_data->region[bar].addr) + return -ENOMEM; + + binfo->ioaddr = pci_data->region[bar].addr; + binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len; + binfo->phys_addr = pci_data->region[bar].phys_addr; + binfo->current_bar = bar; + + return 0; +} + +static int parse_ports_from_fme(struct build_feature_devs_info *binfo) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_port port; + int i = 0, ret = 0; + + if (!binfo->pfme_hdr) { + dev_info(binfo, "VF is detected.\n"); + return ret; + } + + fme_hdr = binfo->pfme_hdr; + + do { + port.csr = readq(&fme_hdr->port[i]); + if (!port.port_implemented) + break; + + /* skip port which only could be accessed via VF */ + if (port.afu_access_control == FME_AFU_ACCESS_VF) + continue; + + ret = parse_switch_to(binfo, port.port_bar); + if (ret) + break; + + ret = parse_feature_list(binfo, + (u8 __iomem *)binfo->ioaddr + + port.port_offset); + if (ret) + break; + } while (++i < MAX_FPGA_PORT_NUM); + + return ret; +} + +static struct build_feature_devs_info * +build_info_alloc_and_init(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + + binfo = zmalloc(sizeof(*binfo)); + if (!binfo) + return binfo; + + binfo->hw = hw; + binfo->pci_data = hw->pci_data; + + /* fpga feature list starts from BAR 0 */ + if (parse_switch_to(binfo, 0)) { + free(binfo); + return NULL; + } + + return binfo; +} + +static void build_info_free(struct build_feature_devs_info *binfo) +{ + free(binfo); +} + +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; + + 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]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr: 0x%lx\n", + feature->name, (unsigned long long)feature->addr, + (unsigned long long)feature->addr + feature->size - 1, + feature->phys_addr); + } + + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) { + port = &hw->port[i]; + + if (port->state != IFPGA_PORT_ATTACHED) + continue; + + dev_info(hw, "port device: %d\n", port->port_id); + + for (j = 0; j < PORT_FEATURE_ID_MAX; j++) { + feature = &port->sub_feature[j]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%llx - 0x%llx - paddr:0x%lx\n", + feature->name, + (unsigned long long)feature->addr, + (unsigned long long)feature->addr + + feature->size - 1, + feature->phys_addr); + } + } +} + +int ifpga_bus_enumerate(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + int ret; + + binfo = build_info_alloc_and_init(hw); + if (!binfo) + return -ENOMEM; + + ret = parse_feature_list(binfo, binfo->ioaddr); + if (ret) + goto exit; + + ret = parse_ports_from_fme(binfo); + if (ret) + goto exit; + + ifpga_print_device_feature_list(hw); + +exit: + build_info_free(binfo); + return ret; +} + +int ifpga_bus_init(struct ifpga_hw *hw) +{ + int i; + + fme_hw_init(&hw->fme); + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) + port_hw_init(&hw->port[i]); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h new file mode 100644 index 0000000..14131e3 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_ENUMERATE_H_ +#define _IFPGA_ENUMERATE_H_ + +int ifpga_bus_init(struct ifpga_hw *hw); +int ifpga_bus_enumerate(struct ifpga_hw *hw); + +#endif /* _IFPGA_ENUMERATE_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c new file mode 100644 index 0000000..e3662f0 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -0,0 +1,255 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <sys/ioctl.h> + +#include "ifpga_feature_dev.h" + +/* + * Enable Port by clear the port soft reset bit, which is set by default. + * The AFU is unable to respond to any MMIO access while in reset. + * __fpga_port_enable function should only be used after __fpga_port_disable + * function. + */ +void __fpga_port_enable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + WARN_ON(!port->disable_count); + + if (--port->disable_count != 0) + return; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x0; + writeq(control.csr, &port_hdr->control); +} + +int __fpga_port_disable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + if (port->disable_count++ != 0) + return 0; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + /* Set port soft reset */ + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x1; + writeq(control.csr, &port_hdr->control); + + /* + * HW sets ack bit to 1 when all outstanding requests have been drained + * on this port and minimum soft reset pulse width has elapsed. + * Driver polls port_soft_reset_ack to determine if reset done by HW. + */ + control.port_sftrst_ack = 1; + + if (fpga_wait_register_field(port_sftrst_ack, control, + &port_hdr->control, RST_POLL_TIMEOUT, + RST_POLL_INVL)) { + dev_err(port, "timeout, fail to reset device\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) +{ + struct feature_port_header *port_hdr; + u64 guidl, guidh; + + port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU); + + spinlock_lock(&port->lock); + guidl = readq(&port_hdr->afu_header.guid.b[0]); + guidh = readq(&port_hdr->afu_header.guid.b[8]); + spinlock_unlock(&port->lock); + + printf("%s: guidl=0x%lx, guidh=0x%lx\n", __func__, guidl, guidh); + + memcpy(uuid->b, &guidl, sizeof(u64)); + memcpy(uuid->b + 8, &guidh, sizeof(u64)); + + return 0; +} + +/* Mask / Unmask Port Errors by the Error Mask register. */ +void port_err_mask(struct ifpga_port_hw *port, bool mask) +{ + struct feature_port_error *port_err; + struct feature_port_err_key err_mask; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + if (mask) + err_mask.csr = PORT_ERR_MASK; + else + err_mask.csr = 0; + + writeq(err_mask.csr, &port_err->error_mask); +} + +/* Clear All Port Errors. */ +int port_err_clear(struct ifpga_port_hw *port, u64 err) +{ + struct feature_port_header *port_hdr; + struct feature_port_error *port_err; + struct feature_port_err_key mask; + struct feature_port_first_err_key first; + struct feature_port_status status; + int ret = 0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + /* + * Clear All Port Errors + * + * - Check for AP6 State + * - Halt Port by keeping Port in reset + * - Set PORT Error mask to all 1 to mask errors + * - Clear all errors + * - Set Port mask to all 0 to enable errors + * - All errors start capturing new errors + * - Enable Port by pulling the port out of reset + */ + + /* If device is still in AP6 state, can not clear any error.*/ + status.csr = readq(&port_hdr->status); + if (status.power_state == PORT_POWER_STATE_AP6) { + dev_err(dev, "Could not clear errors, device in AP6 state.\n"); + return -EBUSY; + } + + /* Halt Port by keeping Port in reset */ + ret = __fpga_port_disable(port); + if (ret) + return ret; + + /* Mask all errors */ + port_err_mask(port, true); + + /* Clear errors if err input matches with current port errors.*/ + mask.csr = readq(&port_err->port_error); + + if (mask.csr == err) { + writeq(mask.csr, &port_err->port_error); + + first.csr = readq(&port_err->port_first_error); + writeq(first.csr, &port_err->port_first_error); + } else { + ret = -EBUSY; + } + + /* Clear mask */ + port_err_mask(port, false); + + /* Enable the Port by clear the reset */ + __fpga_port_enable(port); + + return ret; +} + +int port_clear_error(struct ifpga_port_hw *port) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + + dev_info(port, "read port error: 0x%lx\n", error.csr); + + return port_err_clear(port, error.csr); +} + +void fme_hw_uinit(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return; + + 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); + } +} + +int fme_hw_init(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i, ret; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + 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; + } + } + } + + return 0; +} + +void port_hw_uinit(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i; + + 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); + } +} + +int port_hw_init(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i, 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; + } + } + } + + return 0; +} + diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h new file mode 100644 index 0000000..cd114fb --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_FEATURE_DEV_H_ +#define _IFPGA_FEATURE_DEV_H_ + +#include "ifpga_hw.h" + +static inline struct ifpga_port_hw * +get_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return NULL; + + return &hw->port[port_id]; +} + +#define ifpga_for_each_feature(hw, feature) \ + for ((feature) = (hw)->sub_feature; \ + (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++) + +static inline struct feature * +get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(fme, feature) { + if (feature->id == id) + return feature; + } + + return NULL; +} + +static inline struct feature * +get_port_feature_by_id(struct ifpga_port_hw *port, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(port, feature) { + 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; +} + +static inline void * +get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index) +{ + return port->sub_feature[index].addr; +} + +static inline bool +is_fme_feature_present(struct ifpga_fme_hw *fme, int index) +{ + return !!get_fme_feature_ioaddr_by_index(fme, index); +} + +static inline bool +is_port_feature_present(struct ifpga_port_hw *port, int index) +{ + return !!get_port_feature_ioaddr_by_index(port, index); +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid); + +int __fpga_port_disable(struct ifpga_port_hw *port); +void __fpga_port_enable(struct ifpga_port_hw *port); + +static inline int fpga_port_disable(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_disable(port); + spinlock_unlock(&port->lock); + return ret; +} + +static inline int fpga_port_enable(struct ifpga_port_hw *port) +{ + spinlock_lock(&port->lock); + __fpga_port_enable(port); + spinlock_unlock(&port->lock); + + return 0; +} + +static inline int __fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + ret = __fpga_port_disable(port); + if (ret) + return ret; + + __fpga_port_enable(port); + + return 0; +} + +static inline int fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_reset(port); + spinlock_unlock(&port->lock); + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +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); +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set); + +int fme_hw_init(struct ifpga_fme_hw *fme); +void fme_hw_uinit(struct ifpga_fme_hw *fme); +void port_hw_uinit(struct ifpga_port_hw *port); +int port_hw_init(struct ifpga_port_hw *port); +int port_clear_error(struct ifpga_port_hw *port); +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; + +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); + +/* This struct is used when parsing uafu irq_set */ +struct fpga_uafu_irq_set { + u32 start; + u32 count; + s32 *evtfds; +}; + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set); + +extern struct feature_ops port_hdr_ops; +extern struct feature_ops port_error_ops; +extern struct feature_ops port_stp_ops; +extern struct feature_ops port_uint_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 new file mode 100644 index 0000000..4be60c0 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -0,0 +1,734 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PWR_THRESHOLD_MAX 0x7F + +int fme_get_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +/* fme private feature head */ +static int fme_hdr_init(struct feature *feature) +{ + struct feature_fme_header *fme_hdr; + + fme_hdr = (struct feature_fme_header *)feature->addr; + + dev_info(NULL, "FME HDR Init.\n"); + dev_info(NULL, "FME cap %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + return 0; +} + +static void fme_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME HDR UInit.\n"); +} + +static int fme_hdr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&fme_hdr->header); + *revision = header.revision; + + return 0; +} + +static int fme_hdr_get_ports_num(struct ifpga_fme_hw *fme, u64 *ports_num) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *ports_num = fme_capability.num_ports; + + return 0; +} + +static int fme_hdr_get_cache_size(struct ifpga_fme_hw *fme, u64 *cache_size) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *cache_size = fme_capability.cache_size; + + return 0; +} + +static int fme_hdr_get_version(struct ifpga_fme_hw *fme, u64 *version) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *version = fme_capability.fabric_verid; + + return 0; +} + +static int fme_hdr_get_socket_id(struct ifpga_fme_hw *fme, u64 *socket_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *socket_id = fme_capability.socket_id; + + return 0; +} + +static int fme_hdr_get_bitstream_id(struct ifpga_fme_hw *fme, + u64 *bitstream_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_id = readq(&fme_hdr->bitstream_id); + + return 0; +} + +static int fme_hdr_get_bitstream_metadata(struct ifpga_fme_hw *fme, + u64 *bitstream_metadata) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_metadata = readq(&fme_hdr->bitstream_md); + + return 0; +} + +static int +fme_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_HDR_PROP_REVISION: + return fme_hdr_get_revision(fme, &prop->data); + case FME_HDR_PROP_PORTS_NUM: + return fme_hdr_get_ports_num(fme, &prop->data); + case FME_HDR_PROP_CACHE_SIZE: + return fme_hdr_get_cache_size(fme, &prop->data); + case FME_HDR_PROP_VERSION: + return fme_hdr_get_version(fme, &prop->data); + case FME_HDR_PROP_SOCKET_ID: + return fme_hdr_get_socket_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_ID: + return fme_hdr_get_bitstream_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_METADATA: + return fme_hdr_get_bitstream_metadata(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_hdr_ops = { + .init = fme_hdr_init, + .uinit = fme_hdr_uinit, + .get_prop = fme_hdr_get_prop, +}; + +/* thermal management */ +static int fme_thermal_get_threshold1(struct ifpga_fme_hw *fme, u64 *thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1 = temp_threshold.tmp_thshold1; + + return 0; +} + +static int fme_thermal_set_threshold1(struct ifpga_fme_hw *fme, u64 thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres1 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres1 == 0) { + tmp_threshold.tmp_thshold1_enable = 0; + tmp_threshold.tmp_thshold1 = thres1; + } else { + tmp_threshold.tmp_thshold1_enable = 1; + tmp_threshold.tmp_thshold1 = thres1; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold2(struct ifpga_fme_hw *fme, u64 *thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres2 = temp_threshold.tmp_thshold2; + + return 0; +} + +static int fme_thermal_set_threshold2(struct ifpga_fme_hw *fme, u64 thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres2 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres2 == 0) { + tmp_threshold.tmp_thshold2_enable = 0; + tmp_threshold.tmp_thshold2 = thres2; + } else { + tmp_threshold.tmp_thshold2_enable = 1; + tmp_threshold.tmp_thshold2 = thres2; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold_trip(struct ifpga_fme_hw *fme, + u64 *thres_trip) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres_trip = temp_threshold.therm_trip_thshold; + + return 0; +} + +static int fme_thermal_get_threshold1_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold1_status; + + return 0; +} + +static int fme_thermal_get_threshold2_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold2_status; + + return 0; +} + +static int fme_thermal_get_threshold1_policy(struct ifpga_fme_hw *fme, + u64 *thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_policy = temp_threshold.thshold_policy; + + return 0; +} + +static int fme_thermal_set_threshold1_policy(struct ifpga_fme_hw *fme, + u64 thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold tmp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + + if (thres1_policy == 0) { + tmp_threshold.thshold_policy = 0; + } else if (thres1_policy == 1) { + tmp_threshold.thshold_policy = 1; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_temperature(struct ifpga_fme_hw *fme, u64 *temp) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_temp_rdsensor_fmt1 temp_rdsensor_fmt1; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_rdsensor_fmt1.csr = readq(&thermal->rdsensor_fm1); + *temp = temp_rdsensor_fmt1.fpga_temp; + + return 0; +} + +static int fme_thermal_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_thermal *fme_thermal + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + struct feature_header header; + + header.csr = readq(&fme_thermal->header); + *revision = header.revision; + + return 0; +} + +#define FME_THERMAL_CAP_NO_TMP_THRESHOLD 0x1 + +static int fme_thermal_mgmt_init(struct feature *feature) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold_cap thermal_cap; + + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt Init.\n"); + + fme_thermal = (struct feature_fme_thermal *)feature->addr; + thermal_cap.csr = readq(&fme_thermal->threshold_cap); + + dev_info(NULL, "FME thermal cap %llx.\n", + (unsigned long long)fme_thermal->threshold_cap.csr); + + if (thermal_cap.tmp_thshold_disabled) + feature->cap |= FME_THERMAL_CAP_NO_TMP_THRESHOLD; + + return 0; +} + +static void fme_thermal_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt UInit.\n"); +} + +static int +fme_thermal_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_set_threshold1(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_set_threshold2(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_set_threshold1_policy(fme, prop->data); + } + + return -ENOENT; +} + +static int +fme_thermal_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD && + prop->prop_id != FME_THERMAL_PROP_TEMPERATURE && + prop->prop_id != FME_THERMAL_PROP_REVISION) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_get_threshold1(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_get_threshold2(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD_TRIP: + return fme_thermal_get_threshold_trip(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_REACHED: + return fme_thermal_get_threshold1_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2_REACHED: + return fme_thermal_get_threshold2_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_get_threshold1_policy(fme, &prop->data); + case FME_THERMAL_PROP_TEMPERATURE: + return fme_thermal_get_temperature(fme, &prop->data); + case FME_THERMAL_PROP_REVISION: + return fme_thermal_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_thermal_mgmt_ops = { + .init = fme_thermal_mgmt_init, + .uinit = fme_thermal_mgmt_uinit, + .get_prop = fme_thermal_get_prop, + .set_prop = fme_thermal_set_prop, +}; + +static int fme_pwr_get_consumed(struct ifpga_fme_hw *fme, u64 *consumed) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *consumed = pm_status.pwr_consumed; + + return 0; +} + +static int fme_pwr_get_threshold1(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold1; + + return 0; +} + +static int fme_pwr_set_threshold1(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold1 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold2(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold2; + + return 0; +} + +static int fme_pwr_set_threshold2(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold2 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold1_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold1_status; + + return 0; +} + +static int fme_pwr_get_threshold2_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold2_status; + + return 0; +} + +static int fme_pwr_get_rtl(struct ifpga_fme_hw *fme, u64 *rtl) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *rtl = pm_status.fpga_latency_report; + + return 0; +} + +static int fme_pwr_get_xeon_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_xeon_limit xeon_limit; + + xeon_limit.csr = readq(&fme_power->xeon_limit); + + if (!xeon_limit.enable) + xeon_limit.pwr_limit = 0; + + *limit = xeon_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_fpga_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_fpga_limit fpga_limit; + + fpga_limit.csr = readq(&fme_power->fpga_limit); + + if (!fpga_limit.enable) + fpga_limit.pwr_limit = 0; + + *limit = fpga_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_header header; + + header.csr = readq(&fme_power->header); + *revision = header.revision; + + return 0; +} + +static int fme_power_mgmt_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt Init.\n"); + + return 0; +} + +static void fme_power_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt UInit.\n"); +} + +static int fme_power_mgmt_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_CONSUMED: + return fme_pwr_get_consumed(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_get_threshold1(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_get_threshold2(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1_STATUS: + return fme_pwr_get_threshold1_status(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2_STATUS: + return fme_pwr_get_threshold2_status(fme, &prop->data); + case FME_PWR_PROP_RTL: + return fme_pwr_get_rtl(fme, &prop->data); + case FME_PWR_PROP_XEON_LIMIT: + return fme_pwr_get_xeon_limit(fme, &prop->data); + case FME_PWR_PROP_FPGA_LIMIT: + return fme_pwr_get_fpga_limit(fme, &prop->data); + case FME_PWR_PROP_REVISION: + return fme_pwr_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_power_mgmt_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_set_threshold1(fme, prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_set_threshold2(fme, prop->data); + } + + return -ENOENT; +} + +struct 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, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c new file mode 100644 index 0000000..1773b87 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_dperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_clk_ctr clk; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + clk.afu_interf_clock = readq(&dperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_dperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_dperf *dperf; + struct feature_header header; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + header.csr = readq(&dperf->header); + *revision = header.revision; + + return 0; +} + +#define DPERF_TIMEOUT 30 + +static bool fabric_pobj_is_enabled(int port_id, + struct feature_fme_dperf *dperf) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + + ctl.csr = readq(&dperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum dperf_fab_events fab_event) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dfpmon_fab_ctr ctr; + struct feature_fme_dperf *dperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, dperf)) + goto exit; + + ctl.csr = readq(&dperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &dperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &dperf->fab_ctr, DPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&dperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_dperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, DPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, DPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(mmio_read, DPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, DPERF_FAB_MMIO_WR); + +static int fme_dperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_dperf *dperf; + int status; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + status = fabric_pobj_is_enabled(port_id, dperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_dperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dperf *dperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, dperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&dperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_dperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_dperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 + +static int fme_global_dperf_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf Init.\n"); + + return 0; +} + +static void fme_global_dperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf UInit.\n"); +} + +static int fme_dperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_dperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_dperf_get_fab_port_pcie0_read(fme, sub, &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_dperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* MMIO_READ */ + return fme_dperf_get_fab_port_mmio_read(fme, sub, &prop->data); + case 0x5: /* MMIO_WRITE */ + return fme_dperf_get_fab_port_mmio_write(fme, sub, &prop->data); + case 0x6: /* ENABLE */ + return fme_dperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_dperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_dperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_dperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_dperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_dperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE - fab root only prop */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_dperf_set_fab_freeze(fme, prop->data); + case 0x6: /* ENABLE - fab both root and sub */ + return fme_dperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_dperf_ops = { + .init = fme_global_dperf_init, + .uinit = fme_global_dperf_uinit, + .get_prop = fme_global_dperf_get_prop, + .set_prop = fme_global_dperf_set_prop, + +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c new file mode 100644 index 0000000..8c26fb2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c @@ -0,0 +1,381 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static int fme_err_get_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + + fme_error0.csr = readq(&fme_err->fme_err); + *val = fme_error0.csr; + + return 0; +} + +static int fme_err_get_first_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_first_error fme_first_err; + + fme_first_err.csr = readq(&fme_err->fme_first_err); + *val = fme_first_err.err_reg_status; + + return 0; +} + +static int fme_err_get_next_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_next_error fme_next_err; + + fme_next_err.csr = readq(&fme_err->fme_next_err); + *val = fme_next_err.err_reg_status; + + return 0; +} + +static int fme_err_set_clear(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_ERROR0_MASK, &fme_err->fme_err_mask); + + fme_error0.csr = readq(&fme_err->fme_err); + if (val != fme_error0.csr) { + ret = -EBUSY; + goto exit; + } + + fme_first_err.csr = readq(&fme_err->fme_first_err); + fme_next_err.csr = readq(&fme_err->fme_next_err); + + writeq(fme_error0.csr & FME_ERROR0_MASK, &fme_err->fme_err); + writeq(fme_first_err.csr & FME_FIRST_ERROR_MASK, + &fme_err->fme_first_err); + writeq(fme_next_err.csr & FME_NEXT_ERROR_MASK, + &fme_err->fme_next_err); + +exit: + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_revision(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_header header; + + header.csr = readq(&fme_err->header); + *val = header.revision; + + return 0; +} + +static int fme_err_get_pcie0_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + + pcie0_err.csr = readq(&fme_err->pcie0_err); + *val = pcie0_err.csr; + + return 0; +} + +static int fme_err_set_pcie0_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE0_ERROR_MASK, &fme_err->pcie0_err_mask); + + pcie0_err.csr = readq(&fme_err->pcie0_err); + if (val != pcie0_err.csr) + ret = -EBUSY; + else + writeq(pcie0_err.csr & FME_PCIE0_ERROR_MASK, + &fme_err->pcie0_err); + + writeq(0UL, &fme_err->pcie0_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_pcie1_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + + pcie1_err.csr = readq(&fme_err->pcie1_err); + *val = pcie1_err.csr; + + return 0; +} + +static int fme_err_set_pcie1_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE1_ERROR_MASK, &fme_err->pcie1_err_mask); + + pcie1_err.csr = readq(&fme_err->pcie1_err); + if (val != pcie1_err.csr) + ret = -EBUSY; + else + writeq(pcie1_err.csr & FME_PCIE1_ERROR_MASK, + &fme_err->pcie1_err); + + writeq(0UL, &fme_err->pcie1_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_nonfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_nonfaterror ras_nonfaterr; + + ras_nonfaterr.csr = readq(&fme_err->ras_nonfaterr); + *val = ras_nonfaterr.csr; + + return 0; +} + +static int fme_err_get_catfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_catfaterror ras_catfaterr; + + ras_catfaterr.csr = readq(&fme_err->ras_catfaterr); + *val = ras_catfaterr.csr; + + return 0; +} + +static int fme_err_get_inject_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + *val = ras_error_inj.csr & FME_RAS_ERROR_INJ_MASK; + + return 0; +} + +static int fme_err_set_inject_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + spinlock_lock(&fme->lock); + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + + if (val <= FME_RAS_ERROR_INJ_MASK) { + ras_error_inj.csr = val; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(ras_error_inj.csr, &fme_err->ras_error_inj); + spinlock_unlock(&fme->lock); + + return 0; +} + +static void fme_error_enable(struct ifpga_fme_hw *fme) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + writeq(0UL, &fme_err->pcie0_err_mask); + writeq(0UL, &fme_err->pcie1_err_mask); + writeq(0UL, &fme_err->ras_nonfat_mask); + writeq(0UL, &fme_err->ras_catfat_mask); +} + +static int fme_global_error_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = feature->parent; + + fme_error_enable(fme); + + if (feature->ctx_num) + fme->capability |= FPGA_FME_CAP_ERR_IRQ; + + return 0; +} + +static void fme_global_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int fme_err_fme_err_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* ERRORS */ + return fme_err_get_errors(fme, &prop->data); + case 0x2: /* FIRST_ERROR */ + return fme_err_get_first_error(fme, &prop->data); + case 0x3: /* NEXT_ERROR */ + return fme_err_get_next_error(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x5: /* REVISION */ + return fme_err_get_revision(fme, &prop->data); + case 0x6: /* PCIE0_ERRORS */ + return fme_err_get_pcie0_errors(fme, &prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_get_pcie1_errors(fme, &prop->data); + case 0x8: /* NONFATAL_ERRORS */ + return fme_err_get_nonfatal_errors(fme, &prop->data); + case 0x9: /* CATFATAL_ERRORS */ + return fme_err_get_catfatal_errors(fme, &prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_get_inject_errors(fme, &prop->data); + case 0xb: /* REVISION*/ + return fme_err_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_get_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_err_fme_err_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x4: /* CLEAR */ + return fme_err_set_clear(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x6: /* PCIE0_ERRORS */ + return fme_err_set_pcie0_errors(fme, prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_set_pcie1_errors(fme, prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_set_inject_errors(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_set_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_err_ops = { + .init = fme_global_error_init, + .uinit = fme_global_error_uinit, + .get_prop = fme_global_error_get_prop, + .set_prop = fme_global_error_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c new file mode 100644 index 0000000..e6c40a1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c @@ -0,0 +1,715 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_iperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_clk_ctr clk; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + clk.afu_interf_clock = readq(&iperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_iperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_iperf *iperf; + struct feature_header header; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + header.csr = readq(&iperf->header); + *revision = header.revision; + + return 0; +} + +static int fme_iperf_get_cache_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + *freeze = (u64)ctl.freeze; + return 0; +} + +static int fme_iperf_set_cache_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->ch_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define IPERF_TIMEOUT 30 + +static u64 read_cache_counter(struct ifpga_fme_hw *fme, + u8 channel, enum iperf_cache_events event) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + struct feature_fme_ifpmon_ch_ctr ctr0, ctr1; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* set channel access type and cache event code. */ + ctl.csr = readq(&iperf->ch_ctl); + ctl.cci_chsel = channel; + ctl.cache_event = event; + writeq(ctl.csr, &iperf->ch_ctl); + + /* check the event type in the counter registers */ + ctr0.event_code = event; + + if (fpga_wait_register_field(event_code, ctr0, + &iperf->ch_ctr0, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched cache event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr0.csr = readq(&iperf->ch_ctr0); + ctr1.csr = readq(&iperf->ch_ctr1); + counter = ctr0.cache_counter + ctr1.cache_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define CACHE_SHOW(name, type, event) \ +static int fme_iperf_get_cache_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_cache_counter(fme, type, event); \ + return 0; \ +} + +CACHE_SHOW(read_hit, CACHE_CHANNEL_RD, IPERF_CACHE_RD_HIT); +CACHE_SHOW(read_miss, CACHE_CHANNEL_RD, IPERF_CACHE_RD_MISS); +CACHE_SHOW(write_hit, CACHE_CHANNEL_WR, IPERF_CACHE_WR_HIT); +CACHE_SHOW(write_miss, CACHE_CHANNEL_WR, IPERF_CACHE_WR_MISS); +CACHE_SHOW(hold_request, CACHE_CHANNEL_RD, IPERF_CACHE_HOLD_REQ); +CACHE_SHOW(tx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_TX_REQ_STALL); +CACHE_SHOW(rx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_RX_REQ_STALL); +CACHE_SHOW(rx_eviction, CACHE_CHANNEL_RD, IPERF_CACHE_EVICTIONS); +CACHE_SHOW(data_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_DATA_WR_PORT_CONTEN); +CACHE_SHOW(tag_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_TAG_WR_PORT_CONTEN); + +static int fme_iperf_get_vtd_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_vtd_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->vtd_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static u64 read_iommu_sip_counter(struct ifpga_fme_hw *fme, + enum iperf_vtd_sip_events event) +{ + struct feature_fme_ifpmon_vtd_sip_ctl sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr sip_ctr; + struct feature_fme_iperf *iperf; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + sip_ctl.csr = readq(&iperf->vtd_sip_ctl); + sip_ctl.vtd_evtcode = event; + writeq(sip_ctl.csr, &iperf->vtd_sip_ctl); + + sip_ctr.event_code = event; + + if (fpga_wait_register_field(event_code, sip_ctr, + &iperf->vtd_sip_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd SIP event type in counter registers\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + sip_ctr.csr = readq(&iperf->vtd_sip_ctr); + counter = sip_ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_SIP_SHOW(name, event) \ +static int fme_iperf_get_vtd_sip_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_iommu_sip_counter(fme, event); \ + return 0; \ +} + +VTD_SIP_SHOW(iotlb_4k_hit, IPERF_VTD_SIP_IOTLB_4K_HIT); +VTD_SIP_SHOW(iotlb_2m_hit, IPERF_VTD_SIP_IOTLB_2M_HIT); +VTD_SIP_SHOW(iotlb_1g_hit, IPERF_VTD_SIP_IOTLB_1G_HIT); +VTD_SIP_SHOW(slpwc_l3_hit, IPERF_VTD_SIP_SLPWC_L3_HIT); +VTD_SIP_SHOW(slpwc_l4_hit, IPERF_VTD_SIP_SLPWC_L4_HIT); +VTD_SIP_SHOW(rcc_hit, IPERF_VTD_SIP_RCC_HIT); +VTD_SIP_SHOW(iotlb_4k_miss, IPERF_VTD_SIP_IOTLB_4K_MISS); +VTD_SIP_SHOW(iotlb_2m_miss, IPERF_VTD_SIP_IOTLB_2M_MISS); +VTD_SIP_SHOW(iotlb_1g_miss, IPERF_VTD_SIP_IOTLB_1G_MISS); +VTD_SIP_SHOW(slpwc_l3_miss, IPERF_VTD_SIP_SLPWC_L3_MISS); +VTD_SIP_SHOW(slpwc_l4_miss, IPERF_VTD_SIP_SLPWC_L4_MISS); +VTD_SIP_SHOW(rcc_miss, IPERF_VTD_SIP_RCC_MISS); + +static u64 read_iommu_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_vtd_events base_event) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_ifpmon_vtd_ctr ctr; + struct feature_fme_iperf *iperf; + enum iperf_vtd_events event = base_event + port_id; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.vtd_evtcode = event; + writeq(ctl.csr, &iperf->vtd_ctl); + + ctr.event_code = event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->vtd_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->vtd_ctr); + counter = ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_PORT_SHOW(name, base_event) \ +static int fme_iperf_get_vtd_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_iommu_counter(fme, port_id, base_event); \ + return 0; \ +} + +VTD_PORT_SHOW(read_transaction, IPERF_VTD_AFU_MEM_RD_TRANS); +VTD_PORT_SHOW(write_transaction, IPERF_VTD_AFU_MEM_WR_TRANS); +VTD_PORT_SHOW(devtlb_read_hit, IPERF_VTD_AFU_DEVTLB_RD_HIT); +VTD_PORT_SHOW(devtlb_write_hit, IPERF_VTD_AFU_DEVTLB_WR_HIT); +VTD_PORT_SHOW(devtlb_4k_fill, IPERF_VTD_DEVTLB_4K_FILL); +VTD_PORT_SHOW(devtlb_2m_fill, IPERF_VTD_DEVTLB_2M_FILL); +VTD_PORT_SHOW(devtlb_1g_fill, IPERF_VTD_DEVTLB_1G_FILL); + +static bool fabric_pobj_is_enabled(u8 port_id, struct feature_fme_iperf *iperf) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + + ctl.csr = readq(&iperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_fab_events fab_event) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_ifpmon_fab_ctr ctr; + struct feature_fme_iperf *iperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, iperf)) + goto exit; + + ctl.csr = readq(&iperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &iperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->fab_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_iperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, IPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, IPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(pcie1_read, IPERF_FAB_PCIE1_RD); +FAB_PORT_SHOW(pcie1_write, IPERF_FAB_PCIE1_WR); +FAB_PORT_SHOW(upi_read, IPERF_FAB_UPI_RD); +FAB_PORT_SHOW(upi_write, IPERF_FAB_UPI_WR); +FAB_PORT_SHOW(mmio_read, IPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, IPERF_FAB_MMIO_WR); + +static int fme_iperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_iperf *iperf; + int status; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + status = fabric_pobj_is_enabled(port_id, iperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_iperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, iperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&iperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_iperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 +#define FME_IPERF_CAP_IOMMU 0x1 + +static int fme_global_iperf_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme; + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + + dev_info(NULL, "FME global_iperf Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + /* check if iommu is not supported on this device. */ + fme_capability.csr = readq(&fme_hdr->capability); + dev_info(NULL, "FME HEAD fme_capability %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + if (fme_capability.iommu_support) + feature->cap |= FME_IPERF_CAP_IOMMU; + + return 0; +} + +static void fme_global_iperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_iperf UInit.\n"); +} + +static int fme_iperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_iperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_iperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_cache_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_cache_freeze(fme, &prop->data); + case 0x2: /* READ_HIT */ + return fme_iperf_get_cache_read_hit(fme, &prop->data); + case 0x3: /* READ_MISS */ + return fme_iperf_get_cache_read_miss(fme, &prop->data); + case 0x4: /* WRITE_HIT */ + return fme_iperf_get_cache_write_hit(fme, &prop->data); + case 0x5: /* WRITE_MISS */ + return fme_iperf_get_cache_write_miss(fme, &prop->data); + case 0x6: /* HOLD_REQUEST */ + return fme_iperf_get_cache_hold_request(fme, &prop->data); + case 0x7: /* TX_REQ_STALL */ + return fme_iperf_get_cache_tx_req_stall(fme, &prop->data); + case 0x8: /* RX_REQ_STALL */ + return fme_iperf_get_cache_rx_req_stall(fme, &prop->data); + case 0x9: /* RX_EVICTION */ + return fme_iperf_get_cache_rx_eviction(fme, &prop->data); + case 0xa: /* DATA_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_data_write_port_contention(fme, + &prop->data); + case 0xb: /* TAG_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_tag_write_port_contention(fme, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_vtd_freeze(fme, &prop->data); + case 0x2: /* IOTLB_4K_HIT */ + return fme_iperf_get_vtd_sip_iotlb_4k_hit(fme, &prop->data); + case 0x3: /* IOTLB_2M_HIT */ + return fme_iperf_get_vtd_sip_iotlb_2m_hit(fme, &prop->data); + case 0x4: /* IOTLB_1G_HIT */ + return fme_iperf_get_vtd_sip_iotlb_1g_hit(fme, &prop->data); + case 0x5: /* SLPWC_L3_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l3_hit(fme, &prop->data); + case 0x6: /* SLPWC_L4_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l4_hit(fme, &prop->data); + case 0x7: /* RCC_HIT */ + return fme_iperf_get_vtd_sip_rcc_hit(fme, &prop->data); + case 0x8: /* IOTLB_4K_MISS */ + return fme_iperf_get_vtd_sip_iotlb_4k_miss(fme, &prop->data); + case 0x9: /* IOTLB_2M_MISS */ + return fme_iperf_get_vtd_sip_iotlb_2m_miss(fme, &prop->data); + case 0xa: /* IOTLB_1G_MISS */ + return fme_iperf_get_vtd_sip_iotlb_1g_miss(fme, &prop->data); + case 0xb: /* SLPWC_L3_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l3_miss(fme, &prop->data); + case 0xc: /* SLPWC_L4_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l4_miss(fme, &prop->data); + case 0xd: /* RCC_MISS */ + return fme_iperf_get_vtd_sip_rcc_miss(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_sub_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub > PERF_MAX_PORT_NUM) + return -ENOENT; + + switch (id) { + case 0xe: /* READ_TRANSACTION */ + return fme_iperf_get_vtd_port_read_transaction(fme, sub, + &prop->data); + case 0xf: /* WRITE_TRANSACTION */ + return fme_iperf_get_vtd_port_write_transaction(fme, sub, + &prop->data); + case 0x10: /* DEVTLB_READ_HIT */ + return fme_iperf_get_vtd_port_devtlb_read_hit(fme, sub, + &prop->data); + case 0x11: /* DEVTLB_WRITE_HIT */ + return fme_iperf_get_vtd_port_devtlb_write_hit(fme, sub, + &prop->data); + case 0x12: /* DEVTLB_4K_FILL */ + return fme_iperf_get_vtd_port_devtlb_4k_fill(fme, sub, + &prop->data); + case 0x13: /* DEVTLB_2M_FILL */ + return fme_iperf_get_vtd_port_devtlb_2m_fill(fme, sub, + &prop->data); + case 0x14: /* DEVTLB_1G_FILL */ + return fme_iperf_get_vtd_port_devtlb_1g_fill(fme, sub, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED) + return fme_iperf_vtd_root_get_prop(feature, prop); + + return fme_iperf_vtd_sub_get_prop(feature, prop); +} + +static int fme_iperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + /* Other properties are present for both top and sub levels */ + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_iperf_get_fab_port_pcie0_read(fme, sub, + &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_iperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* PCIE1_READ */ + return fme_iperf_get_fab_port_pcie1_read(fme, sub, + &prop->data); + case 0x5: /* PCIE1_WRITE */ + return fme_iperf_get_fab_port_pcie1_write(fme, sub, + &prop->data); + case 0x6: /* UPI_READ */ + return fme_iperf_get_fab_port_upi_read(fme, sub, + &prop->data); + case 0x7: /* UPI_WRITE */ + return fme_iperf_get_fab_port_upi_write(fme, sub, + &prop->data); + case 0x8: /* MMIO_READ */ + return fme_iperf_get_fab_port_mmio_read(fme, sub, + &prop->data); + case 0x9: /* MMIO_WRITE */ + return fme_iperf_get_fab_port_mmio_write(fme, sub, + &prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_get_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_get_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_iperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_iperf_cache_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_cache_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_vtd_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_vtd_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_set_fab_freeze(fme, prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_set_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_set_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_iperf_ops = { + .init = fme_global_iperf_init, + .uinit = fme_global_iperf_uinit, + .get_prop = fme_global_iperf_get_prop, + .set_prop = fme_global_iperf_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c new file mode 100644 index 0000000..49d8cc5 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c @@ -0,0 +1,352 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static u64 +pr_err_handle(struct feature_fme_pr *fme_pr) +{ + struct feature_fme_pr_status fme_pr_status; + unsigned long err_code; + u64 fme_pr_error; + int i; + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + if (!fme_pr_status.pr_status) + return 0; + + err_code = readq(&fme_pr->ccip_fme_pr_err); + fme_pr_error = err_code; + + for (i = 0; i < PR_MAX_ERR_NUM; i++) { + if (err_code & (1 << i)) + dev_info(NULL, "%s\n", pr_err_msg[i]); + } + + writeq(fme_pr_error, &fme_pr->ccip_fme_pr_err); + return fme_pr_error; +} + +static int fme_pr_write_init(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + if (info->flags != FPGA_MGR_PARTIAL_RECONFIG) + return -EINVAL; + + dev_info(fme_dev, "resetting PR before initiated PR\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + fme_pr_ctl.pr_reset_ack = 1; + + if (fpga_wait_register_field(pr_reset_ack, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 0; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "waiting for PR resource in HW to be initialized and ready\n"); + + fme_pr_status.pr_host_status = PR_HOST_STATUS_IDLE; + + if (fpga_wait_register_field(pr_host_status, fme_pr_status, + &fme_pr->ccip_fme_pr_status, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "check if have any previous PR error\n"); + pr_err_handle(fme_pr); + return 0; +} + +static int fme_pr_write(struct ifpga_fme_hw *fme_dev, + int port_id, const char *buf, size_t count, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + struct feature_fme_pr_data fme_pr_data; + int delay, pr_credit; + int ret = 0; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + dev_info(fme_dev, "set PR port ID and start request\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_regionid = port_id; + fme_pr_ctl.pr_start_req = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "pushing data from bitstream to HW\n"); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + + while (count > 0) { + delay = 0; + while (pr_credit <= 1) { + if (delay++ > PR_WAIT_TIMEOUT) { + dev_err(fme_dev, "maximum try\n"); + + info->pr_err = pr_err_handle(fme_pr); + return info->pr_err ? -EIO : -ETIMEDOUT; + } + udelay(1); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + }; + + if (count >= fme_dev->pr_bandwidth) { + switch (fme_dev->pr_bandwidth) { + case 4: + fme_pr_data.rsvd = 0; + fme_pr_data.pr_data_raw = *((const u32 *)buf); + writeq(fme_pr_data.csr, + &fme_pr->ccip_fme_pr_data); + break; + default: + ret = -EFAULT; + goto done; + } + + buf += fme_dev->pr_bandwidth; + count -= fme_dev->pr_bandwidth; + pr_credit--; + } else { + WARN_ON(1); + return -EINVAL; + goto done; + } + } + +done: + return ret; +} + +static int fme_pr_write_complete(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_push_complete = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "green bitstream push complete\n"); + dev_info(fme_dev, "waiting for HW to release PR resource\n"); + + fme_pr_ctl.pr_start_req = 0; + + if (fpga_wait_register_field(pr_start_req, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + printf("maximum try.\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "PR operation complete, checking status\n"); + info->pr_err = pr_err_handle(fme_pr); + if (info->pr_err) + return -EIO; + + dev_info(fme_dev, "PR done successfully\n"); + return 0; +} + +static int fpga_pr_buf_load(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info, const char *buf, + size_t count) +{ + int ret; + + info->state = FPGA_PR_STATE_WRITE_INIT; + ret = fme_pr_write_init(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error preparing FPGA for writing\n"); + info->state = FPGA_PR_STATE_WRITE_INIT_ERR; + return ret; + } + + /* + * Write the FPGA image to the FPGA. + */ + info->state = FPGA_PR_STATE_WRITE; + ret = fme_pr_write(fme_dev, info->port_id, buf, count, info); + if (ret) { + dev_err(fme_dev, "Error while writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_ERR; + return ret; + } + + /* + * After all the FPGA image has been written, do the device specific + * steps to finish and set the FPGA into operating mode. + */ + info->state = FPGA_PR_STATE_WRITE_COMPLETE; + ret = fme_pr_write_complete(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error after writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_COMPLETE_ERR; + return ret; + } + info->state = FPGA_PR_STATE_DONE; + + return 0; +} + +static int fme_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + struct ifpga_fme_hw *fme = &hw->fme; + struct fpga_pr_info info; + struct ifpga_port_hw *port; + int ret = 0; + + if (!buffer || size == 0) + return -EINVAL; + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + /* + * Padding extra zeros to align PR buffer with PR bandwidth, HW will + * ignore these zeros automatically. + */ + size = IFPGA_ALIGN(size, fme->pr_bandwidth); + + /* get fme header region */ + fme_hdr = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_HEADER); + if (!fme_hdr) + return -EINVAL; + + /* check port id */ + fme_capability.csr = readq(&fme_hdr->capability); + if (port_id >= fme_capability.num_ports) { + dev_err(fme, "port number more than maximum\n"); + return -EINVAL; + } + + memset(&info, 0, sizeof(struct fpga_pr_info)); + info.flags = FPGA_MGR_PARTIAL_RECONFIG; + info.port_id = port_id; + + spinlock_lock(&fme->lock); + + /* get port device by port_id */ + port = &hw->port[port_id]; + + /* Disable Port before PR */ + fpga_port_disable(port); + + ret = fpga_pr_buf_load(fme, &info, (void *)buffer, size); + + *status = info.pr_err; + + /* Re-enable Port after PR finished */ + fpga_port_enable(port); + spinlock_unlock(&fme->lock); + + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, u64 *status) +{ + struct bts_header *bts_hdr; + void *buf; + struct ifpga_port_hw *port; + int ret; + + if (!buffer || size == 0) { + dev_err(hw, "invalid parameter\n"); + return -EINVAL; + } + + bts_hdr = (struct bts_header *)buffer; + + if (is_valid_bts(bts_hdr)) { + dev_info(hw, "this is a valid bitsteam..\n"); + size -= (sizeof(struct bts_header) + + bts_hdr->metadata_len); + buf = (u8 *)buffer + sizeof(struct bts_header) + + bts_hdr->metadata_len; + } else { + return -EINVAL; + } + + /* clean port error before do PR */ + port = &hw->port[port_id]; + ret = port_clear_error(port); + if (ret) { + dev_err(hw, "port cannot clear error\n"); + return -EINVAL; + } + + return fme_pr(hw, port_id, buf, size, status); +} + +static int fme_pr_mgmt_init(struct feature *feature) +{ + struct feature_fme_pr *fme_pr; + struct feature_header fme_pr_header; + struct ifpga_fme_hw *fme; + + dev_info(NULL, "FME PR MGMT Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + + fme_pr = (struct feature_fme_pr *)feature->addr; + + fme_pr_header.csr = readq(&fme_pr->header); + if (fme_pr_header.revision == 2) { + dev_info(NULL, "using 512-bit PR\n"); + fme->pr_bandwidth = 64; + } else { + dev_info(NULL, "using 32-bit PR\n"); + fme->pr_bandwidth = 4; + } + + return 0; +} + +static void fme_pr_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME PR MGMT UInit.\n"); +} + +struct 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 new file mode 100644 index 0000000..a20520c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_HW_H_ +#define _IFPGA_HW_H_ + +#include "ifpga_defines.h" +#include "opae_ifpga_hw_api.h" + +enum ifpga_feature_state { + IFPGA_FEATURE_UNUSED = 0, + IFPGA_FEATURE_ATTACHED, +}; + +struct feature_irq_ctx { + int eventfd; + int idx; +}; + +struct feature { + enum ifpga_feature_state state; + const char *name; + u64 id; + u8 *addr; + uint64_t phys_addr; + u32 size; + int revision; + u64 cap; + int vfio_dev_fd; + struct feature_irq_ctx *ctx; + unsigned int ctx_num; + + void *parent; /* to parent hw data structure */ + + struct feature_ops *ops;/* callback to this private feature */ +}; + +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); +}; + +enum ifpga_fme_state { + IFPGA_FME_UNUSED = 0, + IFPGA_FME_IMPLEMENTED, +}; + +struct ifpga_fme_hw { + enum ifpga_fme_state state; + + struct feature sub_feature[FME_FEATURE_ID_MAX]; + spinlock_t lock; /* protect hardware access */ + + void *parent; /* pointer to ifpga_hw */ + + /* provied by HEADER feature */ + u32 port_num; + struct uuid bitstream_id; + u64 bitstream_md; + size_t pr_bandwidth; + u32 socket_id; + u32 fabric_version_id; + u32 cache_size; + + u32 capability; +}; + +enum ifpga_port_state { + IFPGA_PORT_UNUSED = 0, + IFPGA_PORT_ATTACHED, + IFPGA_PORT_DETACHED, +}; + +struct ifpga_port_hw { + enum ifpga_port_state state; + + struct feature sub_feature[PORT_FEATURE_ID_MAX]; + spinlock_t lock; /* protect access to hw */ + + void *parent; /* pointer to ifpga_hw */ + + int port_id; /* provied by HEADER feature */ + struct uuid afu_id; /* provied by User AFU feature */ + + unsigned int disable_count; + + u32 capability; + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ + u8 *stp_addr; + u32 stp_size; +}; + +#define AFU_MAX_REGION 1 + +struct ifpga_afu_info { + struct opae_reg_region region[AFU_MAX_REGION]; + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct ifpga_hw { + struct opae_adapter *adapter; + struct opae_adapter_data_pci *pci_data; + + struct ifpga_fme_hw fme; + struct ifpga_port_hw port[MAX_FPGA_PORT_NUM]; +}; + +static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) +{ + return hw->fme.state != IFPGA_FME_UNUSED; +} + +static inline bool is_valid_port_id(struct ifpga_hw *hw, u32 port_id) +{ + if (port_id >= MAX_FPGA_PORT_NUM || + hw->port[port_id].state != IFPGA_PORT_ATTACHED) + return false; + + return true; +} +#endif /* _IFPGA_HW_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c new file mode 100644 index 0000000..a962f5b --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c @@ -0,0 +1,388 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +static int port_get_revision(struct ifpga_port_hw *port, u64 *revision) +{ + struct feature_port_header *port_hdr + = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&port_hdr->header); + + *revision = header.revision; + + return 0; +} + +static int port_get_portidx(struct ifpga_port_hw *port, u64 *idx) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + capability.csr = readq(&port_hdr->capability); + *idx = capability.port_number; + + return 0; +} + +static int port_get_latency_tolerance(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + control.csr = readq(&port_hdr->control); + *val = control.latency_tolerance; + + return 0; +} + +static int port_get_ap1_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap1_event; + + return 0; +} + +static int port_set_ap1_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap1_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_ap2_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap2_event; + + return 0; +} + +static int port_set_ap2_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap2_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_power_state(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.power_state; + + return 0; +} + +static int port_get_userclk_freqcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_hdr_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port hdr Init.\n"); + + fpga_port_reset(port); + + return 0; +} + +static void port_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port hdr uinit.\n"); +} + +static int port_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_REVISION: + return port_get_revision(port, &prop->data); + case PORT_HDR_PROP_PORTIDX: + return port_get_portidx(port, &prop->data); + case PORT_HDR_PROP_LATENCY_TOLERANCE: + return port_get_latency_tolerance(port, &prop->data); + case PORT_HDR_PROP_AP1_EVENT: + return port_get_ap1_event(port, &prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_get_ap2_event(port, &prop->data); + case PORT_HDR_PROP_POWER_STATE: + return port_get_power_state(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_get_userclk_freqcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_get_userclk_freqcntrcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQSTS: + return port_get_userclk_freqsts(port, &prop->data); + case PORT_HDR_PROP_USERCLK_CNTRSTS: + return port_get_userclk_freqcntrsts(port, &prop->data); + } + + return -ENOENT; +} + +static int port_hdr_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_AP1_EVENT: + return port_set_ap1_event(port, prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_set_ap2_event(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_set_userclk_freqcmd(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_set_userclk_freqcntrcmd(port, prop->data); + } + + return -ENOENT; +} + +struct feature_ops 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) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port stp Init.\n"); + + spinlock_lock(&port->lock); + port->stp_addr = feature->addr; + port->stp_size = feature->size; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_stp_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port stp uinit.\n"); +} + +struct feature_ops port_stp_ops = { + .init = port_stp_init, + .uinit = port_stp_uinit, +}; + +static int port_uint_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "PORT UINT Init.\n"); + + spinlock_lock(&port->lock); + if (feature->ctx_num) { + port->capability |= FPGA_PORT_CAP_UAFU_IRQ; + port->num_uafu_irqs = feature->ctx_num; + } + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_uint_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT UINT UInit.\n"); +} + +struct feature_ops port_uint_ops = { + .init = port_uint_init, + .uinit = port_uint_uinit, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c new file mode 100644 index 0000000..23db562 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static int port_err_get_revision(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_header header; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + header.csr = readq(&port_err->header); + *val = header.revision; + + return 0; +} + +static int port_err_get_errors(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + *val = error.csr; + + return 0; +} + +static int port_err_get_first_error(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_first_err_key first_error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + first_error.csr = readq(&port_err->port_first_error); + *val = first_error.csr; + + return 0; +} + +static int port_err_get_first_malformed_req_lsb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req0 malreq0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq0.header_lsb = readq(&port_err->malreq0); + *val = malreq0.header_lsb; + + return 0; +} + +static int port_err_get_first_malformed_req_msb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req1 malreq1; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq1.header_msb = readq(&port_err->malreq1); + *val = malreq1.header_msb; + + return 0; +} + +static int port_err_set_clear(struct ifpga_port_hw *port, u64 val) +{ + int ret; + + spinlock_lock(&port->lock); + ret = port_err_clear(port, val); + spinlock_unlock(&port->lock); + + return ret; +} + +static int port_error_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port error Init.\n"); + + spinlock_lock(&port->lock); + port_err_mask(port, false); + if (feature->ctx_num) + port->capability |= FPGA_PORT_CAP_ERR_IRQ; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int port_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_ERR_PROP_REVISION: + return port_err_get_revision(port, &prop->data); + case PORT_ERR_PROP_ERRORS: + return port_err_get_errors(port, &prop->data); + case PORT_ERR_PROP_FIRST_ERROR: + return port_err_get_first_error(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB: + return port_err_get_first_malformed_req_lsb(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB: + return port_err_get_first_malformed_req_msb(port, &prop->data); + } + + return -ENOENT; +} + +static int port_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + if (prop->prop_id == PORT_ERR_PROP_CLEAR) + return port_err_set_clear(port, prop->data); + + return -ENOENT; +} + +struct feature_ops port_error_ops = { + .init = port_error_init, + .uinit = port_error_uinit, + .get_prop = port_error_get_prop, + .set_prop = port_error_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/meson.build b/drivers/raw/ifpga_rawdev/base/meson.build new file mode 100644 index 0000000..cb65535 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/meson.build @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +sources = [ + 'ifpga_api.c', + 'ifpga_enumerate.c', + 'ifpga_feature_dev.c', + 'ifpga_fme.c', + 'ifpga_fme_iperf.c', + 'ifpga_fme_dperf.c', + 'ifpga_fme_error.c', + 'ifpga_port.c', + 'ifpga_port_error.c', + 'ifpga_fme_pr.c', + 'opae_hw_api.c', + 'opae_ifpga_hw_api.c', + 'opae_debug.c' +] + +error_cflags = ['-Wno-sign-compare', '-Wno-unused-value', + '-Wno-format', '-Wno-unused-but-set-variable', + '-Wno-strict-aliasing' +] +c_args = cflags +foreach flag: error_cflags + if cc.has_argument(flag) + c_args += flag + endif +endforeach + +base_lib = static_library('ifpga_rawdev_base', sources, + dependencies: static_rte_eal, + c_args: c_args) +base_objs = base_lib.extract_all_objects() diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.c b/drivers/raw/ifpga_rawdev/base/opae_debug.c new file mode 100644 index 0000000..024d7d2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.c @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#define OPAE_HW_DEBUG + +#include "opae_hw_api.h" +#include "opae_debug.h" + +void opae_manager_dump(struct opae_manager *mgr) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Manger %s\n", mgr->name); + opae_log("OPAE Manger OPs = %p\n", mgr->ops); + opae_log("OPAE Manager Private Data = %p\n", mgr->data); + opae_log("OPAE Adapter(parent) = %p\n", mgr->adapter); + opae_log("==========================\n"); +} + +void opae_bridge_dump(struct opae_bridge *br) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Bridge %s\n", br->name); + opae_log("OPAE Bridge ID = %d\n", br->id); + opae_log("OPAE Bridge OPs = %p\n", br->ops); + opae_log("OPAE Bridge Private Data = %p\n", br->data); + opae_log("OPAE Accelerator(under this bridge) = %p\n", br->acc); + opae_log("==========================\n"); +} + +void opae_accelerator_dump(struct opae_accelerator *acc) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Accelerator %s\n", acc->name); + opae_log("OPAE Accelerator Index = %d\n", acc->index); + opae_log("OPAE Accelerator OPs = %p\n", acc->ops); + opae_log("OPAE Accelerator Private Data = %p\n", acc->data); + opae_log("OPAE Bridge (upstream) = %p\n", acc->br); + opae_log("OPAE Manager (upstream) = %p\n", acc->mgr); + opae_log("==========================\n"); + + if (acc->br) + opae_bridge_dump(acc->br); +} + +static void opae_adapter_data_dump(void *data) +{ + struct opae_adapter_data *d = data; + struct opae_adapter_data_pci *d_pci; + struct opae_reg_region *r; + int i; + + opae_log("=====%s=====\n", __func__); + + switch (d->type) { + case OPAE_FPGA_PCI: + d_pci = (struct opae_adapter_data_pci *)d; + + opae_log("OPAE Adapter Type = PCI\n"); + opae_log("PCI Device ID: 0x%04x\n", d_pci->device_id); + opae_log("PCI Vendor ID: 0x%04x\n", d_pci->vendor_id); + + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + r = &d_pci->region[i]; + opae_log("PCI Bar %d: phy(%llx) len(%llx) addr(%p)\n", + i, (unsigned long long)r->phys_addr, + (unsigned long long)r->len, r->addr); + } + break; + case OPAE_FPGA_NET: + break; + } + + opae_log("==========================\n"); +} + +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) { + if (adapter->mgr) + opae_manager_dump(adapter->mgr); + + opae_adapter_for_each_acc(adapter, acc) + opae_accelerator_dump(acc); + + if (adapter->data) + opae_adapter_data_dump(adapter->data); + } + + opae_log("==========================\n"); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.h b/drivers/raw/ifpga_rawdev/base/opae_debug.h new file mode 100644 index 0000000..a03dff9 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_DEBUG_H_ +#define _OPAE_DEBUG_H_ + +#ifdef OPAE_HW_DEBUG +#define opae_log(fmt, args...) printf(fmt, ## args) +#else +#define opae_log(fme, args...) do {} while (0) +#endif + +void opae_manager_dump(struct opae_manager *mgr); +void opae_bridge_dump(struct opae_bridge *br); +void opae_accelerator_dump(struct opae_accelerator *acc); +void opae_adapter_dump(struct opae_adapter *adapter, int verbose); + +#endif /* _OPAE_DEBUG_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c new file mode 100644 index 0000000..a533dfe --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -0,0 +1,381 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_hw_api.h" +#include "opae_debug.h" +#include "ifpga_api.h" + +/* OPAE Bridge Functions */ + +/** + * opae_bridge_alloc - alloc opae_bridge data structure + * @name: bridge name. + * @ops: ops of this bridge. + * @data: private data of this bridge. + * + * Return opae_bridge on success, otherwise NULL. + */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data) +{ + struct opae_bridge *br = opae_zmalloc(sizeof(*br)); + + if (!br) + return NULL; + + br->name = name; + br->ops = ops; + br->data = data; + + opae_log("%s %p\n", __func__, br); + + return br; +} + +/** + * opae_bridge_reset - reset opae_bridge + * @br: bridge to be reset. + * + * Return: 0 on success, otherwise error code. + */ +int opae_bridge_reset(struct opae_bridge *br) +{ + if (!br) + return -EINVAL; + + if (br->ops && br->ops->reset) + return br->ops->reset(br); + + opae_log("%s no ops\n", __func__); + + return -ENOENT; +} + +/* Accelerator Functions */ + +/** + * opae_accelerator_alloc - alloc opae_accelerator data structure + * @name: accelerator name. + * @ops: ops of this accelerator. + * @data: private data of this accelerator. + * + * Return: opae_accelerator on success, otherwise NULL. + */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data) +{ + struct opae_accelerator *acc = opae_zmalloc(sizeof(*acc)); + + if (!acc) + return NULL; + + acc->name = name; + acc->ops = ops; + acc->data = data; + + opae_log("%s %p\n", __func__, acc); + + return acc; +} + +/** + * opae_acc_reg_read - read accelerator's register from its reg region. + * @acc: accelerator to read. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: read operation width, e.g 4 byte = 32bit read. + * @data: data to store the value read from the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->read) + return acc->ops->read(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_reg_write - write to accelerator's register from its reg region. + * @acc: accelerator to write. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: write operation width, e.g 4 byte = 32bit write. + * @data: data stored the value to write to the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->write) + return acc->ops->write(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_get_info - get information of an accelerator. + * @acc: targeted accelerator + * @info: accelerator info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_info) + return acc->ops->get_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_get_region_info - get information of an accelerator register region. + * @acc: targeted accelerator + * @info: accelerator region info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_region_info) + return acc->ops->get_region_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_set_irq - set an accelerator's irq. + * @acc: targeted accelerator + * @start: start vector number + * @count: count of vectors to be set from the start vector + * @evtfds: event fds to be notified when corresponding irqs happens + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + if (!acc || !acc->data) + return -EINVAL; + + if (start + count <= start) + return -EINVAL; + + if (acc->ops && acc->ops->set_irq) + return acc->ops->set_irq(acc, start, count, evtfds); + + return -ENOENT; +} + +/** + * opae_acc_get_uuid - get accelerator's UUID. + * @acc: targeted accelerator + * @uuid: a pointer to UUID + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + if (!acc || !uuid) + return -EINVAL; + + if (acc->ops && acc->ops->get_uuid) + return acc->ops->get_uuid(acc, uuid); + + return -ENOENT; +} + +/* Manager Functions */ + +/** + * opae_manager_alloc - alloc opae_manager data structure + * @name: manager name. + * @ops: ops of this manager. + * @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) +{ + struct opae_manager *mgr = opae_zmalloc(sizeof(*mgr)); + + if (!mgr) + return NULL; + + mgr->name = name; + mgr->ops = ops; + mgr->data = data; + + opae_log("%s %p\n", __func__, mgr); + + return mgr; +} + +/** + * opae_manager_flash - flash a reconfiguration image via opae_manager + * @mgr: opae_manager for flash. + * @id: id of target region (accelerator). + * @buf: image data buffer. + * @size: buffer size. + * @status: status to store flash result. + * + * Return: 0 on success, otherwise error code. + */ +int opae_manager_flash(struct opae_manager *mgr, int id, void *buf, u32 size, + u64 *status) +{ + if (!mgr) + return -EINVAL; + + if (mgr && mgr->ops && mgr->ops->flash) + return mgr->ops->flash(mgr, id, buf, size, status); + + return -ENOENT; +} + +/* Adapter Functions */ + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @type: opae_adapter_type. + * + * Return: opae_adapter_data on success, otherwise NULL. + */ +void *opae_adapter_data_alloc(enum opae_adapter_type type) +{ + struct opae_adapter_data *data; + int size; + + switch (type) { + case OPAE_FPGA_PCI: + size = sizeof(struct opae_adapter_data_pci); + break; + case OPAE_FPGA_NET: + size = sizeof(struct opae_adapter_data_net); + break; + default: + size = sizeof(struct opae_adapter_data); + break; + } + + data = opae_zmalloc(size); + if (!data) + return NULL; + + data->type = type; + + return data; +} + +static struct opae_adapter_ops *match_ops(struct opae_adapter *adapter) +{ + struct opae_adapter_data *data; + + if (!adapter || !adapter->data) + return NULL; + + data = adapter->data; + + if (data->type == OPAE_FPGA_PCI) + return &ifpga_adapter_ops; + + return NULL; +} + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @name: adapter name. + * @data: private data of this adapter. + * + * Return: opae_adapter on success, otherwise NULL. + */ +struct opae_adapter *opae_adapter_alloc(const char *name, void *data) +{ + struct opae_adapter *adapter = opae_zmalloc(sizeof(*adapter)); + + if (!adapter) + return NULL; + + TAILQ_INIT(&adapter->acc_list); + adapter->data = data; + adapter->name = name; + adapter->ops = match_ops(adapter); + + return adapter; +} + +/** + * opae_adapter_enumerate - enumerate this adapter + * @adapter: adapter to enumerate. + * + * Return: 0 on success, otherwise error code. + */ +int opae_adapter_enumerate(struct opae_adapter *adapter) +{ + int ret = -ENOENT; + + if (!adapter) + return -EINVAL; + + if (adapter->ops && adapter->ops->enumerate) + ret = adapter->ops->enumerate(adapter); + + if (!ret) + opae_adapter_dump(adapter, 1); + + return ret; +} + +/** + * opae_adapter_destroy - destroy this adapter + * @adapter: adapter to destroy. + * + * destroy things allocated during adapter enumeration. + */ +void opae_adapter_destroy(struct opae_adapter *adapter) +{ + if (adapter && adapter->ops && adapter->ops->destroy) + adapter->ops->destroy(adapter); +} + +/** + * opae_adapter_get_acc - find and return accelerator with matched id + * @adapter: adapter to find the accelerator. + * @acc_id: id (index) of the accelerator. + * + * destroy things allocated during adapter enumeration. + */ +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id) +{ + struct opae_accelerator *acc = NULL; + + if (!adapter) + return NULL; + + opae_adapter_for_each_acc(adapter, acc) + if (acc->index == acc_id) + return acc; + + return NULL; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h new file mode 100644 index 0000000..4bbc9df --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_HW_API_H_ +#define _OPAE_HW_API_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> + +#include "opae_osdep.h" + +#ifndef PCI_MAX_RESOURCE +#define PCI_MAX_RESOURCE 6 +#endif + +struct opae_adapter; + +enum opae_adapter_type { + OPAE_FPGA_PCI, + OPAE_FPGA_NET, +}; + +/* OPAE Manager Data Structure */ +struct opae_manager_ops; + +/* + * opae_manager has pointer to its parent adapter, as it could be able to manage + * all components on this FPGA device (adapter). If not the case, don't set this + * adapter, which limit opae_manager ops to manager itself. + */ +struct opae_manager { + const char *name; + struct opae_adapter *adapter; + struct opae_manager_ops *ops; + void *data; +}; + +/* FIXME: add more management ops, e.g power/thermal and etc */ +struct opae_manager_ops { + int (*flash)(struct opae_manager *mgr, int id, void *buffer, + u32 size, u64 *status); +}; + +/* OPAE Manager APIs */ +struct opae_manager * +opae_manager_alloc(const char *name, struct opae_manager_ops *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); + +/* OPAE Bridge Data Structure */ +struct opae_bridge_ops; + +/* + * opae_bridge only has pointer to its downstream accelerator. + */ +struct opae_bridge { + const char *name; + int id; + struct opae_accelerator *acc; + struct opae_bridge_ops *ops; + void *data; +}; + +struct opae_bridge_ops { + int (*reset)(struct opae_bridge *br); +}; + +/* OPAE Bridge APIs */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data); +int opae_bridge_reset(struct opae_bridge *br); +#define opae_bridge_free(br) opae_free(br) + +/* OPAE Acceleraotr Data Structure */ +struct opae_accelerator_ops; + +/* + * opae_accelerator has pointer to its upstream bridge(port). + * In some cases, if we allow same user to do PR on its own accelerator, then + * set the manager pointer during the enumeration. But in other cases, the PR + * functions only could be done via manager in another module / thread / service + * / application for better protection. + */ +struct opae_accelerator { + TAILQ_ENTRY(opae_accelerator) node; + const char *name; + int index; + struct opae_bridge *br; + struct opae_manager *mgr; + struct opae_accelerator_ops *ops; + void *data; +}; + +struct opae_acc_info { + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct opae_acc_region_info { + u32 flags; +#define ACC_REGION_READ (1 << 0) +#define ACC_REGION_WRITE (1 << 1) +#define ACC_REGION_MMIO (1 << 2) + u32 index; + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_accelerator_ops { + int (*read)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*write)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*get_info)(struct opae_accelerator *acc, + struct opae_acc_info *info); + int (*get_region_info)(struct opae_accelerator *acc, + struct opae_acc_region_info *info); + int (*set_irq)(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); + int (*get_uuid)(struct opae_accelerator *acc, + struct uuid *uuid); +}; + +/* OPAE accelerator APIs */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data); +#define opae_accelerator_free(acc) opae_free(acc) +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info); +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info); +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid); + +static inline struct opae_bridge * +opae_acc_get_br(struct opae_accelerator *acc) +{ + return acc ? acc->br : NULL; +} + +static inline struct opae_manager * +opae_acc_get_mgr(struct opae_accelerator *acc) +{ + return acc ? acc->mgr : NULL; +} + +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + +#define opae_acc_reg_read64(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 8, data) +#define opae_acc_reg_write64(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 8, data) +#define opae_acc_reg_read32(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 4, data) +#define opae_acc_reg_write32(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 4, data) +#define opae_acc_reg_read16(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 2, data) +#define opae_acc_reg_write16(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 2, data) +#define opae_acc_reg_read8(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 1, data) +#define opae_acc_reg_write8(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 1, data) + +/*for data stream read/write*/ +int opae_acc_data_read(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); +int opae_acc_data_write(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); + +/* OPAE Adapter Data Structure */ +struct opae_adapter_data { + enum opae_adapter_type type; +}; + +struct opae_reg_region { + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_adapter_data_pci { + enum opae_adapter_type type; + u16 device_id; + u16 vendor_id; + struct opae_reg_region region[PCI_MAX_RESOURCE]; + int vfio_dev_fd; /* VFIO device file descriptor */ +}; + +/* FIXME: OPAE_FPGA_NET type */ +struct opae_adapter_data_net { + enum opae_adapter_type type; +}; + +struct opae_adapter_ops { + int (*enumerate)(struct opae_adapter *adapter); + void (*destroy)(struct opae_adapter *adapter); +}; + +TAILQ_HEAD(opae_accelerator_list, opae_accelerator); + +#define opae_adapter_for_each_acc(adatper, acc) \ + TAILQ_FOREACH(acc, &adapter->acc_list, node) + +struct opae_adapter { + const char *name; + struct opae_manager *mgr; + struct opae_accelerator_list acc_list; + struct opae_adapter_ops *ops; + void *data; +}; + +/* OPAE Adapter APIs */ +void *opae_adapter_data_alloc(enum opae_adapter_type type); +#define opae_adapter_data_free(data) opae_free(data) + +struct opae_adapter *opae_adapter_alloc(const char *name, void *data); +#define opae_adapter_free(adapter) opae_free(adapter) + +int opae_adapter_enumerate(struct opae_adapter *adapter); +void opae_adapter_destroy(struct opae_adapter *adapter); +static inline struct opae_manager * +opae_adapter_get_mgr(struct opae_adapter *adapter) +{ + return adapter ? adapter->mgr : NULL; +} + +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id); + +static inline void opae_adapter_add_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_INSERT_TAIL(&adapter->acc_list, acc, node); +} + +static inline void opae_adapter_remove_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_REMOVE(&adapter->acc_list, acc, node); +} +#endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c new file mode 100644 index 0000000..a40c8da --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_ifpga_hw_api.h" +#include "ifpga_api.h" + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data || !fme_info) + return -EINVAL; + + fme = mgr->data; + + spinlock_lock(&fme->lock); + fme_info->capability = fme->capability; + spinlock_unlock(&fme->lock); + + return 0; +} + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_irq(fme->parent, FEATURE_FIU_ID_FME, 0, + IFPGA_FME_FEATURE_ID_GLOBAL_ERR, err_irq_set); +} + +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_get_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !port_info) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + port_info->capability = port->capability; + port_info->num_uafu_irqs = port->num_uafu_irqs; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !info) + return -EINVAL; + + /* Only support STP region now */ + if (info->index != PORT_REGION_INDEX_STP) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + info->addr = (u64)port->stp_addr; + info->size = port->stp_size; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_ERROR, err_irq_set); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h new file mode 100644 index 0000000..65086cf --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_IFPGA_HW_API_H_ +#define _OPAE_IFPGA_HW_API_H_ + +#include "opae_hw_api.h" + +/** + * struct feature_prop - data structure for feature property + * @feature_id: id of this feature. + * @prop_id: id of this property under this feature. + * @data: property value to set/get. + */ +struct feature_prop { + u64 feature_id; + u64 prop_id; + u64 data; +}; + +#define IFPGA_FIU_ID_FME 0x0 +#define IFPGA_FIU_ID_PORT 0x1 + +#define IFPGA_FME_FEATURE_ID_HEADER 0x0 +#define IFPGA_FME_FEATURE_ID_THERMAL_MGMT 0x1 +#define IFPGA_FME_FEATURE_ID_POWER_MGMT 0x2 +#define IFPGA_FME_FEATURE_ID_GLOBAL_IPERF 0x3 +#define IFPGA_FME_FEATURE_ID_GLOBAL_ERR 0x4 +#define IFPGA_FME_FEATURE_ID_PR_MGMT 0x5 +#define IFPGA_FME_FEATURE_ID_HSSI 0x6 +#define IFPGA_FME_FEATURE_ID_GLOBAL_DPERF 0x7 + +#define IFPGA_PORT_FEATURE_ID_HEADER 0x0 +#define IFPGA_PORT_FEATURE_ID_AFU 0xff +#define IFPGA_PORT_FEATURE_ID_ERROR 0x10 +#define IFPGA_PORT_FEATURE_ID_UMSG 0x11 +#define IFPGA_PORT_FEATURE_ID_UINT 0x12 +#define IFPGA_PORT_FEATURE_ID_STP 0x13 + +/* + * PROP format (TOP + SUB + ID) + * + * (~0x0) means this field is unused. + */ +#define PROP_TOP GENMASK(31, 24) +#define PROP_TOP_UNUSED 0xff +#define PROP_SUB GENMASK(23, 16) +#define PROP_SUB_UNUSED 0xff +#define PROP_ID GENMASK(15, 0) + +#define PROP(_top, _sub, _id) \ + (SET_FIELD(PROP_TOP, _top) | SET_FIELD(PROP_SUB, _sub) |\ + SET_FIELD(PROP_ID, _id)) + +/* FME head feature's properties*/ +#define FME_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define FME_HDR_PROP_PORTS_NUM 0x2 /* RDONLY */ +#define FME_HDR_PROP_CACHE_SIZE 0x3 /* RDONLY */ +#define FME_HDR_PROP_VERSION 0x4 /* RDONLY */ +#define FME_HDR_PROP_SOCKET_ID 0x5 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_ID 0x6 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_METADATA 0x7 /* RDONLY */ + +/* FME error reporting feature's properties */ +/* FME error reporting properties format */ +#define ERR_PROP(_top, _id) PROP(_top, 0xff, _id) +#define ERR_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define ERR_PROP_TOP_FME_ERR 0x1 +#define ERR_PROP_ROOT(_id) ERR_PROP(0xff, _id) +#define ERR_PROP_FME_ERR(_id) ERR_PROP(ERR_PROP_TOP_FME_ERR, _id) + +#define FME_ERR_PROP_ERRORS ERR_PROP_FME_ERR(0x1) +#define FME_ERR_PROP_FIRST_ERROR ERR_PROP_FME_ERR(0x2) +#define FME_ERR_PROP_NEXT_ERROR ERR_PROP_FME_ERR(0x3) +#define FME_ERR_PROP_CLEAR ERR_PROP_FME_ERR(0x4) /* WO */ +#define FME_ERR_PROP_REVISION ERR_PROP_ROOT(0x5) +#define FME_ERR_PROP_PCIE0_ERRORS ERR_PROP_ROOT(0x6) /* RW */ +#define FME_ERR_PROP_PCIE1_ERRORS ERR_PROP_ROOT(0x7) /* RW */ +#define FME_ERR_PROP_NONFATAL_ERRORS ERR_PROP_ROOT(0x8) +#define FME_ERR_PROP_CATFATAL_ERRORS ERR_PROP_ROOT(0x9) +#define FME_ERR_PROP_INJECT_ERRORS ERR_PROP_ROOT(0xa) /* RW */ + +/* FME thermal feature's properties */ +#define FME_THERMAL_PROP_THRESHOLD1 0x1 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD2 0x2 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD_TRIP 0x3 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_REACHED 0x4 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD2_REACHED 0x5 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_POLICY 0x6 /* RW */ +#define FME_THERMAL_PROP_TEMPERATURE 0x7 /* RDONLY */ +#define FME_THERMAL_PROP_REVISION 0x8 /* RDONLY */ + +/* FME power feature's properties */ +#define FME_PWR_PROP_CONSUMED 0x1 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD1 0x2 /* RW */ +#define FME_PWR_PROP_THRESHOLD2 0x3 /* RW */ +#define FME_PWR_PROP_THRESHOLD1_STATUS 0x4 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD2_STATUS 0x5 /* RDONLY */ +#define FME_PWR_PROP_RTL 0x6 /* RDONLY */ +#define FME_PWR_PROP_XEON_LIMIT 0x7 /* RDONLY */ +#define FME_PWR_PROP_FPGA_LIMIT 0x8 /* RDONLY */ +#define FME_PWR_PROP_REVISION 0x9 /* RDONLY */ + +/* FME iperf/dperf PROP format */ +#define PERF_PROP_TOP_CACHE 0x1 +#define PERF_PROP_TOP_VTD 0x2 +#define PERF_PROP_TOP_FAB 0x3 +#define PERF_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define PERF_PROP_SUB_UNUSED PROP_SUB_UNUSED + +#define PERF_PROP_ROOT(_id) PROP(0xff, 0xff, _id) +#define PERF_PROP_CACHE(_id) PROP(PERF_PROP_TOP_CACHE, 0xff, _id) +#define PERF_PROP_VTD(_sub, _id) PROP(PERF_PROP_TOP_VTD, _sub, _id) +#define PERF_PROP_VTD_ROOT(_id) PROP(PERF_PROP_TOP_VTD, 0xff, _id) +#define PERF_PROP_FAB(_sub, _id) PROP(PERF_PROP_TOP_FAB, _sub, _id) +#define PERF_PROP_FAB_ROOT(_id) PROP(PERF_PROP_TOP_FAB, 0xff, _id) + +/* FME iperf feature's properties */ +#define FME_IPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_IPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* iperf CACHE properties */ +#define FME_IPERF_PROP_CACHE_FREEZE PERF_PROP_CACHE(0x1) /* RW */ +#define FME_IPERF_PROP_CACHE_READ_HIT PERF_PROP_CACHE(0x2) +#define FME_IPERF_PROP_CACHE_READ_MISS PERF_PROP_CACHE(0x3) +#define FME_IPERF_PROP_CACHE_WRITE_HIT PERF_PROP_CACHE(0x4) +#define FME_IPERF_PROP_CACHE_WRITE_MISS PERF_PROP_CACHE(0x5) +#define FME_IPERF_PROP_CACHE_HOLD_REQUEST PERF_PROP_CACHE(0x6) +#define FME_IPERF_PROP_CACHE_TX_REQ_STALL PERF_PROP_CACHE(0x7) +#define FME_IPERF_PROP_CACHE_RX_REQ_STALL PERF_PROP_CACHE(0x8) +#define FME_IPERF_PROP_CACHE_RX_EVICTION PERF_PROP_CACHE(0x9) +#define FME_IPERF_PROP_CACHE_DATA_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xa) +#define FME_IPERF_PROP_CACHE_TAG_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xb) +/* iperf VTD properties */ +#define FME_IPERF_PROP_VTD_FREEZE PERF_PROP_VTD_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_HIT PERF_PROP_VTD_ROOT(0x2) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_HIT PERF_PROP_VTD_ROOT(0x3) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_HIT PERF_PROP_VTD_ROOT(0x4) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_HIT PERF_PROP_VTD_ROOT(0x5) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_HIT PERF_PROP_VTD_ROOT(0x6) +#define FME_IPERF_PROP_VTD_SIP_RCC_HIT PERF_PROP_VTD_ROOT(0x7) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_MISS PERF_PROP_VTD_ROOT(0x8) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_MISS PERF_PROP_VTD_ROOT(0x9) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_MISS PERF_PROP_VTD_ROOT(0xa) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_MISS PERF_PROP_VTD_ROOT(0xb) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_MISS PERF_PROP_VTD_ROOT(0xc) +#define FME_IPERF_PROP_VTD_SIP_RCC_MISS PERF_PROP_VTD_ROOT(0xd) +#define FME_IPERF_PROP_VTD_PORT_READ_TRANSACTION(n) PERF_PROP_VTD(n, 0xe) +#define FME_IPERF_PROP_VTD_PORT_WRITE_TRANSACTION(n) PERF_PROP_VTD(n, 0xf) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_READ_HIT(n) PERF_PROP_VTD(n, 0x10) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_WRITE_HIT(n) PERF_PROP_VTD(n, 0x11) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_4K_FILL(n) PERF_PROP_VTD(n, 0x12) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_2M_FILL(n) PERF_PROP_VTD(n, 0x13) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_1G_FILL(n) PERF_PROP_VTD(n, 0x14) +/* iperf FAB properties */ +#define FME_IPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_IPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_IPERF_PROP_FAB_PCIE1_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_IPERF_PROP_FAB_PCIE1_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_IPERF_PROP_FAB_UPI_READ PERF_PROP_FAB_ROOT(0x6) +#define FME_IPERF_PROP_FAB_PORT_UPI_READ(n) PERF_PROP_FAB(n, 0x6) +#define FME_IPERF_PROP_FAB_UPI_WRITE PERF_PROP_FAB_ROOT(0x7) +#define FME_IPERF_PROP_FAB_PORT_UPI_WRITE(n) PERF_PROP_FAB(n, 0x7) +#define FME_IPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x8) +#define FME_IPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x8) +#define FME_IPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x9) +#define FME_IPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x9) +#define FME_IPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0xa) /* RW */ +#define FME_IPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0xa) /* RW */ + +/* FME dperf properties */ +#define FME_DPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_DPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* dperf FAB properties */ +#define FME_DPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_DPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_DPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_DPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_DPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_DPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_DPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_DPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0x6) /* RW */ +#define FME_DPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0x6) /* RW */ + +/*PORT hdr feature's properties*/ +#define PORT_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_HDR_PROP_PORTIDX 0x2 /* RDONLY */ +#define PORT_HDR_PROP_LATENCY_TOLERANCE 0x3 /* RDONLY */ +#define PORT_HDR_PROP_AP1_EVENT 0x4 /* RW */ +#define PORT_HDR_PROP_AP2_EVENT 0x5 /* RW */ +#define PORT_HDR_PROP_POWER_STATE 0x6 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_FREQCMD 0x7 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQCNTRCMD 0x8 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQSTS 0x9 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_CNTRSTS 0xa /* RDONLY */ + +/*PORT error feature's properties*/ +#define PORT_ERR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_ERR_PROP_ERRORS 0x2 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_ERROR 0x3 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB 0x4 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB 0x5 /* RDONLY */ +#define PORT_ERR_PROP_CLEAR 0x6 /* WRONLY */ + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop); +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop); + +/* + * Retrieve information about the fpga fme. + * Driver fills the info in provided struct fpga_fme_info. + */ +struct fpga_fme_info { + u32 capability; /* The capability of FME device */ +#define FPGA_FME_CAP_ERR_IRQ (1 << 0) /* Support fme error interrupt */ +}; + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info); + +/* Set eventfd information for ifpga FME error interrupt */ +struct fpga_fme_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set); + +/* + * Retrieve information about the fpga port. + * Driver fills the info in provided struct fpga_port_info. + */ +struct fpga_port_info { + u32 capability; /* The capability of port device */ +#define FPGA_PORT_CAP_ERR_IRQ (1 << 0) /* Support port error interrupt */ +#define FPGA_PORT_CAP_UAFU_IRQ (1 << 1) /* Support uafu error interrupt */ + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ +}; + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info); +/* + * Retrieve region information about the fpga port. + * Driver needs to fill the index of struct fpga_port_region_info. + */ +struct fpga_port_region_info { + u32 index; +#define PORT_REGION_INDEX_STP (1 << 1) /* Signal Tap Region */ + u64 size; /* Region Size */ + u64 addr; /* Base address of the region */ +}; + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info); + +/* Set eventfd information for ifpga port error interrupt */ +struct fpga_port_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set); + +#endif /* _OPAE_IFPGA_HW_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h new file mode 100644 index 0000000..90f54f7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_OSDEP_H +#define _OPAE_OSDEP_H + +#include <string.h> +#include <stdbool.h> + +#ifdef RTE_LIBRTE_EAL +#include "osdep_rte/osdep_generic.h" +#else +#include "osdep_raw/osdep_generic.h" +#endif + +#define __iomem + +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef uint64_t dma_addr_t; + +struct uuid { + u8 b[16]; +}; + +#ifndef LINUX_MACROS +#ifndef BITS_PER_LONG +#define BITS_PER_LONG (__SIZEOF_LONG__ * 8) +#endif +#ifndef BIT +#define BIT(a) (1UL << (a)) +#endif /* BIT */ +#ifndef BIT_ULL +#define BIT_ULL(a) (1ULL << (a)) +#endif /* BIT_ULL */ +#ifndef GENMASK +#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#endif /* GENMASK */ +#ifndef GENMASK_ULL +#define GENMASK_ULL(h, l) (((U64_C(1) << ((h) - (l) + 1)) - 1) << (l)) +#endif /* GENMASK_ULL */ +#endif /* LINUX_MACROS */ + +#define SET_FIELD(m, v) (((v) << (__builtin_ffsll(m) - 1)) & (m)) +#define GET_FIELD(m, v) (((v) & (m)) >> (__builtin_ffsll(m) - 1)) + +#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) +#define pr_info(y, args...) dev_info(0, y, ##args) + +#ifndef WARN_ON +#define WARN_ON(x) do { \ + int ret = !!(x); \ + if (unlikely(ret)) \ + pr_warn("WARN_ON: \"" #x "\" at %s:%d\n", __func__, __LINE__); \ +} while (0) +#endif + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define udelay(x) opae_udelay(x) +#define msleep(x) opae_udelay(1000 * (x)) +#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000)) + +#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 new file mode 100644 index 0000000..895a1d8 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OSDEP_RAW_GENERIC_H +#define _OSDEP_RAW_GENERIC_H + +#define compiler_barrier() (asm volatile ("" : : : "memory")) + +#define io_wmb() compiler_barrier() +#define io_rmb() compiler_barrier() + +static inline uint8_t opae_readb(const volatile void *addr) +{ + uint8_t val; + + val = *(const volatile uint8_t *)addr; + io_rmb(); + return val; +} + +static inline uint16_t opae_readw(const volatile void *addr) +{ + uint16_t val; + + val = *(const volatile uint16_t *)addr; + io_rmb(); + return val; +} + +static inline uint32_t opae_readl(const volatile void *addr) +{ + uint32_t val; + + val = *(const volatile uint32_t *)addr; + io_rmb(); + return val; +} + +static inline uint64_t opae_readq(const volatile void *addr) +{ + uint64_t val; + + val = *(const volatile uint64_t *)addr; + io_rmb(); + return val; +} + +static inline void opae_writeb(uint8_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint8_t *)addr = value; +} + +static inline void opae_writew(uint16_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint16_t *)addr = value; +} + +static inline void opae_writel(uint32_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint32_t *)addr = value; +} + +static inline void opae_writeq(uint64_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint64_t *)addr = value; +} + +#define opae_free(addr) free(addr) + +#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 new file mode 100644 index 0000000..76902e2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OSDEP_RTE_GENERIC_H +#define _OSDEP_RTE_GENERIC_H + +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_spinlock.h> +#include <rte_log.h> +#include <rte_io.h> +#include <rte_malloc.h> + +#define dev_printf(level, fmt, args...) \ + RTE_LOG(level, PMD, "osdep_rte: " fmt, ## args) + +#define osdep_panic(...) rte_panic(...) + +#define opae_udelay(x) rte_delay_us(x) + +#define opae_readb(addr) rte_read8(addr) +#define opae_readw(addr) rte_read16(addr) +#define opae_readl(addr) rte_read32(addr) +#define opae_readq(addr) rte_read64(addr) +#define opae_writeb(value, addr) rte_write8(value, addr) +#define opae_writew(value, addr) rte_write16(value, addr) +#define opae_writel(value, addr) rte_write32(value, addr) +#define opae_writeq(value, addr) rte_write64(value, addr) + +#define opae_malloc(size) rte_malloc(NULL, size, 0) +#define opae_zmalloc(size) rte_zmalloc(NULL, size, 0) +#define opae_free(addr) rte_free(addr) + +#define ARRAY_SIZE(arr) RTE_DIM(arr) + +#define min(a, b) RTE_MIN(a, b) +#define max(a, b) RTE_MAX(a, b) + +#define spinlock_t rte_spinlock_t +#define spinlock_init(x) rte_spinlock_init(x) +#define spinlock_lock(x) rte_spinlock_lock(x) +#define spinlock_unlock(x) rte_spinlock_unlock(x) + +#endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v11 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 0/3] Introduce Intel FPGA BUS Xu, Rosen 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 1/3] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 2/3] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen @ 2018-05-10 14:00 ` Xu, Rosen 2 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-10 14:00 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Yanglong Wu From: Rosen Xu <rosen.xu@intel.com> Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev library. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> --- MAINTAINERS | 3 + config/common_base | 5 + doc/guides/rawdevs/ifpga_rawdev.rst | 112 ++++ doc/guides/rawdevs/index.rst | 1 + doc/guides/rel_notes/release_18_05.rst | 8 + drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 ++ drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 608 +++++++++++++++++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ drivers/raw/ifpga_rawdev/meson.build | 15 + .../ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map | 4 + drivers/raw/meson.build | 2 +- mk/rte.app.mk | 4 +- 13 files changed, 834 insertions(+), 2 deletions(-) create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/meson.build create mode 100644 drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map diff --git a/MAINTAINERS b/MAINTAINERS index e1a1ef9..2576f86 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -851,8 +851,11 @@ Rawdev Drivers -------------- Intel FPGA +M: Rosen Xu <rosen.xu@intel.com> M: Tianfei zhang <tianfei.zhang@intel.com> +F: drivers/raw/ifpga_rawdev/ F: drivers/raw/ifpga_rawdev/base/ +F: doc/guides/rawdevs/ifpga_rawdev.rst NXP DPAA2 QDMA M: Nipun Gupta <nipun.gupta@nxp.com> diff --git a/config/common_base b/config/common_base index 1440316..017a15a 100644 --- a/config/common_base +++ b/config/common_base @@ -633,6 +633,11 @@ CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV=n CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV=n # +# Compile PMD for Intel FPGA raw device +# +CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV=y + +# # Compile librte_ring # CONFIG_RTE_LIBRTE_RING=y diff --git a/doc/guides/rawdevs/ifpga_rawdev.rst b/doc/guides/rawdevs/ifpga_rawdev.rst new file mode 100644 index 0000000..d400db6 --- /dev/null +++ b/doc/guides/rawdevs/ifpga_rawdev.rst @@ -0,0 +1,112 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2018 Intel Corporation. + +IFPGA Rawdev Driver +====================== + +FPGA is used more and more widely in Cloud and NFV, one primary reason is +that FPGA not only provides ASIC performance but also it's more flexible +than ASIC. + +FPGA uses Partial Reconfigure (PR) Parts of Bit Stream to achieve its +flexibility. That means one FPGA Device Bit Stream is divided into many Parts +of Bit Stream(each Part of Bit Stream is defined as AFU-Accelerated Function +Unit), and each AFU is a hardware acceleration unit which can be dynamically +reloaded respectively. + +By PR (Partial Reconfiguration) AFUs, one FPGA resources can be time-shared by +different users. FPGA hot upgrade and fault tolerance can be provided easily. + +The SW IFPGA Rawdev Driver (**ifpga_rawdev**) provides a Rawdev driver +that utilizes Intel FPGA Software Stack OPAE(Open Programmable Acceleration +Engine) for FPGA management. + +Implementation details +---------------------- + +Each instance of IFPGA Rawdev Driver is probed by Intel FpgaDev. In coordination +with OPAE share code IFPGA Rawdev Driver provides common FPGA management ops +for FPGA operation, OPAE provides all following operations: +- FPGA PR (Partial Reconfiguration) management +- FPGA AFUs Identifying +- FPGA Thermal Management +- FPGA Power Management +- FPGA Performance reporting +- FPGA Remote Debug + +All configuration parameters are taken by vdev_ifpga_cfg driver. Besides +configuration, vdev_ifpga_cfg driver also hot plugs in IFPGA Bus. + +All of the AFUs of one FPGA may share same PCI BDF and AFUs scan depend on +IFPGA Rawdev Driver so IFPGA Bus takes AFU device scan and AFU drivers probe. +All AFU device driver bind to AFU device by its UUID (Universally Unique +Identifier). + +To avoid unnecessary code duplication and ensure maximum performance, +handling of AFU devices is left to different PMDs; all the design as +summarized by the following block diagram:: + + +---------------------------------------------------------------+ + | Application(s) | + +----------------------------.----------------------------------+ + | + | + +----------------------------'----------------------------------+ + | DPDK Framework (APIs) | + +----------|------------|--------.---------------------|--------+ + / \ | + / \ | + +-------'-------+ +-------'-------+ +--------'--------+ + | Eth PMD | | Crypto PMD | | | + +-------.-------+ +-------.-------+ | | + | | | | + | | | | + +-------'-------+ +-------'-------+ | IFPGA | + | Eth AFU Dev | |Crypto AFU Dev | | Rawdev Driver | + +-------.-------+ +-------.-------+ |(OPAE Share Code)| + | | | | + | | Rawdev | | + +-------'------------------'-------+ Ops | | + | IFPGA Bus | -------->| | + +-----------------.----------------+ +--------.--------+ + | | + Hot-plugin -->| | + | | + +-----------------'------------------+ +--------'--------+ + | vdev_ifpga_cfg driver | | Intel FpgaDev | + +------------------------------------+ +-----------------+ + +Build options +------------- + +- ``CONFIG_RTE_LIBRTE_IFPGA_BUS`` (default ``y``) + + Toggle compilation of IFPGA Bus library. + +- ``CONFIG_RTE_LIBRTE_IFPGA_RAWDEV`` (default ``y``) + + Toggle compilation of the ``ifpga_rawdev`` driver. + +Run-time parameters +------------------- + +This driver is invoked automatically in systems added with Intel FPGA, +but PR and IFPGA Bus scan is trigged by command line using +``--vdev 'ifpga_rawdev_cfg`` EAL option. + +The following device parameters are supported: + +- ``ifpga`` [string] + + Provide a specific Intel FPGA device PCI BDF. Can be provided multiple + times for additional instances. + +- ``port`` [int] + + Each FPGA can provide many channels to PR AFU by software, each channels + is identified by this parameter. + +- ``afu_bts`` [string] + + If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and + identifies AFU Bit Stream file. diff --git a/doc/guides/rawdevs/index.rst b/doc/guides/rawdevs/index.rst index 7769083..7c3bd95 100644 --- a/doc/guides/rawdevs/index.rst +++ b/doc/guides/rawdevs/index.rst @@ -13,3 +13,4 @@ application through rawdev API. dpaa2_cmdif dpaa2_qdma + ifpga_rawdev diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst index 265950a..f5241a1 100644 --- a/doc/guides/rel_notes/release_18_05.rst +++ b/doc/guides/rel_notes/release_18_05.rst @@ -189,6 +189,14 @@ New Features the DPDK framework. It provides Intel FPGA Partial Bit Stream AFU(Accelerated Function Unit) scan and drivers prove. +* **Added IFPGA(Intel FPGA) Rawdev Driver.** + + Added a new Rawdev driver called IFPGA(Intel FPGA) Rawdev Driver, which cooperates + with OPAE(Open Programmable Acceleration Engine) share code provides common FPGA + management ops for FPGA operation. + + See the :doc:`../rawdevs/ifpga_rawdev` programmer's guide for more details. + API Changes ----------- diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index 2eb2787..8e29b4a 100644 --- a/drivers/raw/Makefile +++ b/drivers/raw/Makefile @@ -9,5 +9,6 @@ ifeq ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += dpaa2_cmdif DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += dpaa2_qdma endif +DIRS-$(CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV) += ifpga_rawdev include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/raw/ifpga_rawdev/Makefile b/drivers/raw/ifpga_rawdev/Makefile new file mode 100644 index 0000000..f3b9d5e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/Makefile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_pmd_ifpga_rawdev.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_bus_vdev +LDLIBS += -lrte_kvargs +LDLIBS += -lrte_bus_pci +LDLIBS += -lrte_bus_ifpga + +EXPORT_MAP := rte_pmd_ifpga_rawdev_version.map + +LIBABIVER := 1 + +VPATH += $(SRCDIR)/base + +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV) += ifpga_rawdev.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c new file mode 100644 index 0000000..f658e32 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c @@ -0,0 +1,608 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <rte_log.h> +#include <rte_bus.h> +#include <rte_eal_memconfig.h> +#include <rte_malloc.h> +#include <rte_devargs.h> +#include <rte_memcpy.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include <rte_errno.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> +#include <rte_bus_vdev.h> + +#include "base/opae_hw_api.h" +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_common.h" +#include "ifpga_logs.h" +#include "ifpga_rawdev.h" + +int ifpga_rawdev_logtype; + +#define PCI_VENDOR_ID_INTEL 0x8086 +/* PCI Device ID */ +#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 +/* 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 RTE_MAX_RAW_DEVICE 10 + +static const struct rte_pci_id pci_ifpga_map[] = { + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_6_X) }, + { 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) }, + { .vendor_id = 0, /* sentinel */ }, +}; + +static int +ifpga_fill_afu_dev(struct opae_accelerator *acc, + struct rte_afu_device *afu_dev) +{ + struct rte_mem_resource *res = afu_dev->mem_resource; + struct opae_acc_region_info region_info; + struct opae_acc_info info; + unsigned long i; + int ret; + + ret = opae_acc_get_info(acc, &info); + if (ret) + return ret; + + if (info.num_regions > PCI_MAX_RESOURCE) + return -EFAULT; + + afu_dev->num_region = info.num_regions; + + for (i = 0; i < info.num_regions; i++) { + region_info.index = i; + ret = opae_acc_get_region_info(acc, ®ion_info); + if (ret) + return ret; + + if ((region_info.flags & ACC_REGION_MMIO) && + (region_info.flags & ACC_REGION_READ) && + (region_info.flags & ACC_REGION_WRITE)) { + res[i].phys_addr = region_info.phys_addr; + res[i].len = region_info.len; + res[i].addr = region_info.addr; + } else + return -EFAULT; + } + + return 0; +} + +static void +ifpga_rawdev_info_get(struct rte_rawdev *dev, + rte_rawdev_obj_t dev_info) +{ + struct opae_adapter *adapter; + struct opae_accelerator *acc; + struct rte_afu_device *afu_dev; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + if (!dev_info) { + IFPGA_RAWDEV_PMD_ERR("Invalid request"); + return; + } + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return; + + afu_dev = dev_info; + afu_dev->rawdev = dev; + + /* find opae_accelerator and fill info into afu_device */ + opae_adapter_for_each_acc(adapter, acc) { + if (acc->index != afu_dev->id.port) + continue; + + if (ifpga_fill_afu_dev(acc, afu_dev)) { + IFPGA_RAWDEV_PMD_ERR("cannot get info\n"); + return; + } + } +} + +static int +ifpga_rawdev_start(struct rte_rawdev *dev) +{ + int ret = 0; + struct opae_adapter *adapter; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + return ret; +} + +static void +ifpga_rawdev_stop(struct rte_rawdev *dev) +{ + dev->started = 0; +} + +static int +ifpga_rawdev_close(struct rte_rawdev *dev) +{ + return dev ? 0:1; +} + +static int +ifpga_rawdev_reset(struct rte_rawdev *dev) +{ + return dev ? 0:1; +} + +static int +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, + u64 *status) +{ + + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_accelerator *acc; + struct opae_bridge *br; + int ret; + + adapter = ifpga_rawdev_get_priv(raw_dev); + if (!adapter) + return -ENODEV; + + mgr = opae_adapter_get_mgr(adapter); + if (!mgr) + return -ENODEV; + + acc = opae_adapter_get_acc(adapter, port_id); + if (!acc) + return -ENODEV; + + br = opae_acc_get_br(acc); + if (!br) + return -ENODEV; + + ret = opae_manager_flash(mgr, port_id, buffer, size, status); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("%s pr error %d\n", __func__, ret); + return ret; + } + + ret = opae_bridge_reset(br); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("%s reset port:%d error %d\n", + __func__, port_id, ret); + return ret; + } + + return ret; +} + +static int +rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, + const char *file_name) +{ + struct stat file_stat; + int file_fd; + int ret = 0; + u32 buffer_size; + void *buffer; + u64 pr_error; + + if (!file_name) + return -EINVAL; + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + IFPGA_RAWDEV_PMD_ERR("%s: open file error: %s\n", + __func__, file_name); + IFPGA_RAWDEV_PMD_ERR("Message : %s\n", strerror(errno)); + return -EINVAL; + } + ret = stat(file_name, &file_stat); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("stat on bitstream file failed: %s\n", + file_name); + return -EINVAL; + } + buffer_size = file_stat.st_size; + IFPGA_RAWDEV_PMD_INFO("bitstream file size: %u\n", buffer_size); + buffer = rte_malloc(NULL, buffer_size, 0); + if (!buffer) { + ret = -ENOMEM; + goto close_fd; + } + + /*read the raw data*/ + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { + ret = -EINVAL; + goto free_buffer; + } + + /*do PR now*/ + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); + IFPGA_RAWDEV_PMD_INFO("downloading to device port %d....%s.\n", port_id, + ret ? "failed" : "success"); + if (ret) { + ret = -EINVAL; + goto free_buffer; + } + +free_buffer: + if (buffer) + rte_free(buffer); +close_fd: + close(file_fd); + file_fd = 0; + return ret; +} + +static int +ifpga_rawdev_pr(struct rte_rawdev *dev, + rte_rawdev_obj_t pr_conf) +{ + struct opae_adapter *adapter; + struct rte_afu_pr_conf *afu_pr_conf; + int ret; + struct uuid uuid; + struct opae_accelerator *acc; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + if (!pr_conf) + return -EINVAL; + + afu_pr_conf = pr_conf; + + if (afu_pr_conf->pr_enable) { + ret = rte_fpga_do_pr(dev, + afu_pr_conf->afu_id.port, + afu_pr_conf->bs_path); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("do pr error %d\n", ret); + return ret; + } + } + + acc = opae_adapter_get_acc(adapter, afu_pr_conf->afu_id.port); + if (!acc) + return -ENODEV; + + ret = opae_acc_get_uuid(acc, &uuid); + if (ret) + return ret; + + memcpy(&afu_pr_conf->afu_id.uuid.uuid_low, uuid.b, sizeof(u64)); + memcpy(&afu_pr_conf->afu_id.uuid.uuid_high, uuid.b + 8, sizeof(u64)); + + IFPGA_RAWDEV_PMD_INFO("%s: uuid_l=0x%lx, uuid_h=0x%lx\n", __func__, + (u64)afu_pr_conf->afu_id.uuid.uuid_low, + (u64)afu_pr_conf->afu_id.uuid.uuid_high); + + return 0; +} + +static const struct rte_rawdev_ops ifpga_rawdev_ops = { + .dev_info_get = ifpga_rawdev_info_get, + .dev_configure = NULL, + .dev_start = ifpga_rawdev_start, + .dev_stop = ifpga_rawdev_stop, + .dev_close = ifpga_rawdev_close, + .dev_reset = ifpga_rawdev_reset, + + .queue_def_conf = NULL, + .queue_setup = NULL, + .queue_release = NULL, + + .attr_get = NULL, + .attr_set = NULL, + + .enqueue_bufs = NULL, + .dequeue_bufs = NULL, + + .dump = NULL, + + .xstats_get = NULL, + .xstats_get_names = NULL, + .xstats_get_by_name = NULL, + .xstats_reset = NULL, + + .firmware_status_get = NULL, + .firmware_version_get = NULL, + .firmware_load = ifpga_rawdev_pr, + .firmware_unload = NULL, + + .dev_selftest = NULL, +}; + +static int +ifpga_rawdev_create(struct rte_pci_device *pci_dev, + int socket_id) +{ + int ret = 0; + struct rte_rawdev *rawdev = NULL; + struct opae_adapter *adapter = NULL; + struct opae_manager *mgr = NULL; + struct opae_adapter_data_pci *data = NULL; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + int i; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + goto cleanup; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id()); + + /* Allocate device structure */ + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct opae_adapter), + socket_id); + if (rawdev == NULL) { + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); + ret = -EINVAL; + goto cleanup; + } + + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API */ + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); + if (!data) { + ret = -ENOMEM; + goto cleanup; + } + + /* init opae_adapter_data_pci for device specific information */ + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + data->region[i].phys_addr = pci_dev->mem_resource[i].phys_addr; + data->region[i].len = pci_dev->mem_resource[i].len; + data->region[i].addr = pci_dev->mem_resource[i].addr; + } + data->device_id = pci_dev->id.device_id; + data->vendor_id = pci_dev->id.vendor_id; + + /* create a opae_adapter based on above device data */ + adapter = opae_adapter_alloc(pci_dev->device.name, data); + if (!adapter) { + ret = -ENOMEM; + goto free_adapter_data; + } + + rawdev->dev_ops = &ifpga_rawdev_ops; + rawdev->device = &pci_dev->device; + rawdev->driver_name = pci_dev->device.driver->name; + + rawdev->dev_private = adapter; + + /* must enumerate the adapter before use it */ + ret = opae_adapter_enumerate(adapter); + if (ret) + goto free_adapter; + + /* get opae_manager to rawdev */ + mgr = opae_adapter_get_mgr(adapter); + if (mgr) { + /* PF function */ + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); + } + + return ret; + +free_adapter: + if (adapter) + opae_adapter_free(adapter); +free_adapter_data: + if (data) + opae_adapter_data_free(data); +cleanup: + if (rawdev) + rte_rawdev_pmd_release(rawdev); + + return ret; +} + +static int +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) +{ + int ret; + struct rte_rawdev *rawdev; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + struct opae_adapter *adapter; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + return ret; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", + name, rte_socket_id()); + + rawdev = rte_rawdev_pmd_get_named_dev(name); + if (!rawdev) { + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name); + return -EINVAL; + } + + adapter = ifpga_rawdev_get_priv(rawdev); + if (!adapter) + return -ENODEV; + + opae_adapter_data_free(adapter->data); + opae_adapter_free(adapter); + + /* rte_rawdev_close is called by pmd_release */ + ret = rte_rawdev_pmd_release(rawdev); + if (ret) + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); + + return ret; +} + +static int +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()); +} + +static int +ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) +{ + return ifpga_rawdev_destroy(pci_dev); +} + +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { + .id_table = pci_ifpga_map, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, + .probe = ifpga_rawdev_pci_probe, + .remove = ifpga_rawdev_pci_remove, +}; + +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | uio_pci_generic | vfio-pci"); + +RTE_INIT(ifpga_rawdev_init_log); +static void +ifpga_rawdev_init_log(void) +{ + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); + if (ifpga_rawdev_logtype >= 0) + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +static int +ifpga_cfg_probe(struct rte_vdev_device *dev) +{ + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + int port; + char *name = NULL; + char dev_name[RTE_RAWDEV_NAME_MAX_LEN]; + + devargs = dev->device.devargs; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &rte_ifpga_get_string_arg, &name) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, + IFPGA_ARG_PORT, + &rte_ifpga_get_integer32_arg, + &port) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + memset(dev_name, 0, sizeof(dev_name)); + snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s", + port, name); + + rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), + dev_name, devargs->args); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +static int +ifpga_cfg_remove(struct rte_vdev_device *vdev) +{ + IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p", + vdev); + + return 0; +} + +static struct rte_vdev_driver ifpga_cfg_driver = { + .probe = ifpga_cfg_probe, + .remove = ifpga_cfg_remove, +}; + +RTE_PMD_REGISTER_VDEV(ifpga_rawdev_cfg, ifpga_cfg_driver); +RTE_PMD_REGISTER_ALIAS(ifpga_rawdev_cfg, ifpga_cfg); +RTE_PMD_REGISTER_PARAM_STRING(ifpga_rawdev_cfg, + "bdf=<string> " + "port=<int> " + "afu_bts=<path>"); + diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h new file mode 100644 index 0000000..c7759b8 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_RAWDEV_H_ +#define _IFPGA_RAWDEV_H_ + +extern int ifpga_rawdev_logtype; + +#define IFPGA_RAWDEV_PMD_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_rawdev_logtype, "ifgpa: " fmt, \ + ##args) + +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") + +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) +#define IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) +#define IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) +#define IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) + +enum ifpga_rawdev_device_state { + IFPGA_IDLE, + IFPGA_READY, + IFPGA_ERROR +}; + +static inline struct opae_adapter * +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) +{ + return rawdev->dev_private; +} + +#endif /* _IFPGA_RAWDEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/meson.build b/drivers/raw/ifpga_rawdev/meson.build new file mode 100644 index 0000000..6725687 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/meson.build @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +version = 1 + +subdir('base') +objs = [base_objs] + +deps += ['rawdev', 'pci', 'bus_pci', 'kvargs', + 'bus_vdev', 'bus_ifpga'] +sources = files('ifpga_rawdev.c') + +includes += include_directories('base') + +allow_experimental_apis = true diff --git a/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map new file mode 100644 index 0000000..9b9ab1a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map @@ -0,0 +1,4 @@ +DPDK_18.05 { + + local: *; +}; diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build index 34dfac4..a61cdcc 100644 --- a/drivers/raw/meson.build +++ b/drivers/raw/meson.build @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright 2018 NXP -drivers = ['skeleton_rawdev', 'dpaa2_cmdif', 'dpaa2_qdma'] +drivers = ['skeleton_rawdev', 'dpaa2_cmdif', 'dpaa2_qdma', 'ifpga_rawdev'] std_deps = ['rawdev'] config_flag_fmt = 'RTE_LIBRTE_PMD_@0@_RAWDEV' driver_name_fmt = 'rte_pmd_@0@' diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 3861e1a..acc0ec3 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -256,9 +256,11 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += -lrte_pmd_dpaa2_cmdif _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += -lrte_pmd_dpaa2_qdma 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 +endif # CONFIG_RTE_LIBRTE_IFPGA_BUS endif # CONFIG_RTE_LIBRTE_RAWDEV - endif # !CONFIG_RTE_BUILD_SHARED_LIBS _LDLIBS-y += --no-whole-archive -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (14 preceding siblings ...) 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 0/3] Introduce Intel FPGA BUS Xu, Rosen @ 2018-05-11 8:31 ` Xu, Rosen 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 1/3] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen ` (3 more replies) 2018-05-14 9:58 ` [dpdk-dev] [PATCH] raw/ifpga/base: fix compile error on ia32 icc compiler Xu, Rosen 2018-05-16 13:48 ` [dpdk-dev] [PATCH] drivers/bus/ifpga/: fix Coverity issue Rosen Xu 17 siblings, 4 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-11 8:31 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: "Xu, Rosen" <rosen.xu@intel.com> Intel FPGA BUS in DPDK ------------------------- This patch set introduces Intel FPGA BUS support in DPDK. v12 updates: =========== - Remove redundancy data struct ifpga_dev So all afu_dev list togeter. - Fix comments from Jingjing Wu and Qi Zhang - Fix compile issue in BSD flatform - Take more test in IA platform v11 updates: =========== - To improve PR speed OPAE Share Code involved AVX-512, but AVX-512 is not available in all IA platforms, besides this, after we have test several times, using AVX-512 only improve 1 ms. So this patch we don't use it. - Fix comments of patch 1 of Jingjing Wu and Qi Zhang. - Updated configurations parameters form net_ifpga_cfg to ifpga_rawdev_cfg v10 updates: =========== - Add prefix rte_ for exported symbols - Fix alphabetical order error - Fix share code title well underlined comments - Squash the release notes parts in relevant patches - Update the MAINTAINERS file in patches 1, 2 and 3 v9 updates: ========== - Rebase ifpga_rawdev on QDMA and CMDIF driver - Split and squash the patch 4(v8 patch) into patch 2 and patch 3 v8 updates: ========== - Fix some comments from Shreyansh Jain - Patch 3 and Patch 5 will continue rebase when qcom patches merging into mainline - add Shreyansh Jain's Acked-by v7 updates: ========== - Fix some comments from DPDK community - Fix the CLANG compile error - Fix the meson build warring. v6 updates: =========== - Add documentation - Add meson build script - Split new patch for OPAE share code v5 updates: =========== - Fixed SHARED LIB Build issue - Changed command name to IFPGA Rawdev name, so remove pci library datastruct and function. - Fixed PATCH v2/v3/v4 comments v4 updates: =========== - Remove all modifications from eal - Create vdev to take IFPGA parameters configuration - AFU Device Driver bind to AFU Device by uuid - Take more test in scenario of Multi-FPGA System v3 updates: =========== - Remove all modifications of bus scan and probe - FPGA BUS Scan is trigged by hotplug of Rawdev - Took Modifications of comments - Move AFU Device to IFPGA - FPGA BUS Scan depend on it's IFPGA Rawdev - Add Build Macros for FPGA BUS and IFPGA Rawdev Questions ========= Why not PCI Bus? All of the AFUs of one FPGA may share same PCI BDF. Why not vdev Bus? Because AFUs depend on Rawdev, and it's hardware specpic. Motivation ========== FPGA is used more and more widely in Cloud and NFV, one primary reason is that FPGA not only provide ASIC performance but also it's more flexible than ASIC. FPGA use Partial Reconfigure(PR) Parts of Bitstream to achieve its flexibility. Another reason is that one FPGA can be shared by different Users, and each User can use some of AFUs of One FPGA. That means One FPGA Device Bitstream is divided into many Parts of Bitstream(each Part of Bitstream is defined as AFU-Accelerated Function Unit), and each AFU is a Hardware Acceleration Unit and it can dynamically Reload respectively. Proposed Solution ================= - Involve Rawdev to take FPGA Partial Configuration(Download/PR) - Defined FPGA-BUS for Acceleration Drivers of AFUs - FPGA PCI Scan(1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver. FPGA-BUS scan is called, but AFU depend on Rawdev, so this scan doesn't trig AFU device create. - AFU Scan(2nd Scan) bind DPDK Driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their dirves are also probed. Scope ===== The Intel FPGA BUS implementation is target towards various FPGA Devices use PR to provide many Acceleration Function. Specific PMDs may also bind to its AFU. And Applications don't care they are using ASIC Acceleration or FPGA AFU Acceleration. Status ===== With integrating Intel PSG FPGA Software Stack OPAE(Open Programmable Acceleration Engine) Share Code, Intel FPGA BUS runs well in Intel PSG FPGA Cards. Rosen Xu (2): bus/ifpga: Add Intel FPGA BUS Library iFPGA: Add Intel FPGA BUS Rawdev Driver Tianfei Zhang (1): iFPGA: Add Intel FPGA OPAE Share Code MAINTAINERS | 11 + config/common_base | 10 + doc/guides/rawdevs/ifpga_rawdev.rst | 112 ++ doc/guides/rawdevs/index.rst | 1 + doc/guides/rel_notes/release_18_05.rst | 13 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 + drivers/bus/ifpga/ifpga_bus.c | 464 ++++++ drivers/bus/ifpga/ifpga_common.c | 88 ++ drivers/bus/ifpga/ifpga_common.h | 18 + drivers/bus/ifpga/ifpga_logs.h | 31 + drivers/bus/ifpga/meson.build | 8 + drivers/bus/ifpga/rte_bus_ifpga.h | 150 ++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/bus/meson.build | 2 +- drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 + drivers/raw/ifpga_rawdev/base/Makefile | 26 + drivers/raw/ifpga_rawdev/base/README | 31 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 294 ++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 28 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 58 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1662 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 821 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 11 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 253 +++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 164 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 734 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 301 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 381 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 715 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 352 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 127 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 388 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 144 ++ drivers/raw/ifpga_rawdev/base/meson.build | 34 + drivers/raw/ifpga_rawdev/base/opae_debug.c | 99 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 19 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 381 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 253 +++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 145 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 279 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 79 + .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 75 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 45 + drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 619 ++++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 + drivers/raw/ifpga_rawdev/meson.build | 15 + .../ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map | 4 + drivers/raw/meson.build | 2 +- mk/rte.app.mk | 5 +- 51 files changed, 9566 insertions(+), 3 deletions(-) create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/meson.build create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/README create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/meson.build create mode 100644 drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v12 1/3] bus/ifpga: Add Intel FPGA BUS Library 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS Xu, Rosen @ 2018-05-11 8:31 ` Xu, Rosen 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 2/3] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen ` (2 subsequent siblings) 3 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-11 8:31 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet From: Rosen Xu <rosen.xu@intel.com> Defined FPGA-BUS for Acceleration Drivers of AFUs 1. FPGA PCI Scan (1st Scan) follows DPDK UIO/VFIO PCI Scan Process, probe Intel FPGA Rawdev Driver, it will be covered in following patches. 2. AFU Scan(2nd Scan) bind DPDK driver to FPGA Partial-Bitstream. This scan is trigged by hotplug of IFPGA Rawdev probe, in this scan the AFUs will be created and their drivers are also probed. This patch will introduce rte_afu_device which describe the AFU device listed in the FPGA-BUS. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> --- MAINTAINERS | 4 + config/common_base | 5 + doc/guides/rel_notes/release_18_05.rst | 5 + drivers/bus/Makefile | 1 + drivers/bus/ifpga/Makefile | 32 ++ drivers/bus/ifpga/ifpga_bus.c | 464 ++++++++++++++++++++++++++++ drivers/bus/ifpga/ifpga_common.c | 88 ++++++ drivers/bus/ifpga/ifpga_common.h | 18 ++ drivers/bus/ifpga/ifpga_logs.h | 31 ++ drivers/bus/ifpga/meson.build | 8 + drivers/bus/ifpga/rte_bus_ifpga.h | 150 +++++++++ drivers/bus/ifpga/rte_bus_ifpga_version.map | 10 + drivers/bus/meson.build | 2 +- mk/rte.app.mk | 1 + 14 files changed, 818 insertions(+), 1 deletion(-) create mode 100644 drivers/bus/ifpga/Makefile create mode 100644 drivers/bus/ifpga/ifpga_bus.c create mode 100644 drivers/bus/ifpga/ifpga_common.c create mode 100644 drivers/bus/ifpga/ifpga_common.h create mode 100644 drivers/bus/ifpga/ifpga_logs.h create mode 100644 drivers/bus/ifpga/meson.build create mode 100644 drivers/bus/ifpga/rte_bus_ifpga.h create mode 100644 drivers/bus/ifpga/rte_bus_ifpga_version.map diff --git a/MAINTAINERS b/MAINTAINERS index 7cc8860..39c3988 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -401,6 +401,10 @@ F: drivers/mempool/bucket/ Bus Drivers ----------- +Intel FPGA bus +M: Rosen Xu <rosen.xu@intel.com> +F: drivers/bus/ifpga/ + NXP buses M: Hemant Agrawal <hemant.agrawal@nxp.com> M: Shreyansh Jain <shreyansh.jain@nxp.com> diff --git a/config/common_base b/config/common_base index 28557ed..49704ad 100644 --- a/config/common_base +++ b/config/common_base @@ -139,6 +139,11 @@ CONFIG_RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS=n CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n # +# Compile the Intel FPGA bus +# +CONFIG_RTE_LIBRTE_IFPGA_BUS=y + +# # Compile PCI bus driver # CONFIG_RTE_LIBRTE_PCI_BUS=y diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst index 458b47f..1053311 100644 --- a/doc/guides/rel_notes/release_18_05.rst +++ b/doc/guides/rel_notes/release_18_05.rst @@ -208,6 +208,11 @@ New Features stats/xstats on shared memory from secondary process, and also pdump packets on those virtual devices. +* **Added Ifpga Bus, a generic Intel FPGA Bus library.** + + The Ifpga Bus library provides support for integrating any Intel FPGA device with + the DPDK framework. It provides Intel FPGA Partial Bit Stream AFU(Accelerated + Function Unit) scan and drivers prove. API Changes ----------- diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index c251b65..ef7f247 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -7,6 +7,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_DPAA_BUS) += dpaa ifeq ($(CONFIG_RTE_EAL_VFIO),y) DIRS-$(CONFIG_RTE_LIBRTE_FSLMC_BUS) += fslmc endif +DIRS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga DIRS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci DIRS-$(CONFIG_RTE_LIBRTE_VDEV_BUS) += vdev diff --git a/drivers/bus/ifpga/Makefile b/drivers/bus/ifpga/Makefile new file mode 100644 index 0000000..3ff3bdb --- /dev/null +++ b/drivers/bus/ifpga/Makefile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_bus_ifpga.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_kvargs + +# versioning export map +EXPORT_MAP := rte_bus_ifpga_version.map + +# library version +LIBABIVER := 1 + +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_bus.c +SRCS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += ifpga_common.c + +# +# Export include files +# +SYMLINK-$(CONFIG_RTE_LIBRTE_IFPGA_BUS)-include += rte_bus_ifpga.h + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c new file mode 100644 index 0000000..16b7e06 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -0,0 +1,464 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int ifpga_bus_logtype; + +/* Forward declaration to access Intel FPGA bus + * on which iFPGA devices are connected + */ +static struct rte_bus rte_ifpga_bus; + +static struct ifpga_afu_dev_list ifpga_afu_dev_list = + TAILQ_HEAD_INITIALIZER(ifpga_afu_dev_list); +static struct ifpga_afu_drv_list ifpga_afu_drv_list = + TAILQ_HEAD_INITIALIZER(ifpga_afu_drv_list); + + +/* register a ifpga bus based driver */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver) +{ + RTE_VERIFY(driver); + + TAILQ_INSERT_TAIL(&ifpga_afu_drv_list, driver, next); +} + +/* un-register a fpga bus based driver */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) +{ + TAILQ_REMOVE(&ifpga_afu_drv_list, driver, next); +} + +static struct rte_afu_device * +ifpga_find_afu_dev(const struct rte_rawdev *rdev, + const struct rte_afu_id *afu_id) +{ + struct rte_afu_device *afu_dev = NULL; + + TAILQ_FOREACH(afu_dev, &ifpga_afu_dev_list, next) { + if (afu_dev && + afu_dev->rawdev == rdev && + !ifpga_afu_id_cmp(&afu_dev->id, afu_id)) + return afu_dev; + } + return NULL; +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static struct rte_afu_device * +ifpga_scan_one(struct rte_rawdev *rawdev, + struct rte_devargs *devargs) +{ + struct rte_kvargs *kvlist = NULL; + struct rte_afu_device *afu_dev = NULL; + struct rte_afu_pr_conf afu_pr_conf; + int ret = 0; + char *path = NULL; + + memset(&afu_pr_conf, 0, sizeof(struct rte_afu_pr_conf)); + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_PORT, + &rte_ifpga_get_integer32_arg, &afu_pr_conf.afu_id.port) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_AFU_BTS) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_AFU_BTS, + &rte_ifpga_get_string_arg, &path) < 0) { + IFPGA_BUS_ERR("Failed to parse %s", + IFPGA_AFU_BTS); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_AFU_BTS); + goto end; + } + + afu_pr_conf.afu_id.uuid.uuid_low = 0; + afu_pr_conf.afu_id.uuid.uuid_high = 0; + afu_pr_conf.pr_enable = path?1:0; + + if (ifpga_find_afu_dev(rawdev, &afu_pr_conf.afu_id)) + goto end; + + afu_dev = calloc(1, sizeof(*afu_dev)); + if (!afu_dev) + goto end; + + afu_dev->device.devargs = devargs; + afu_dev->device.numa_node = SOCKET_ID_ANY; + afu_dev->device.name = devargs->name; + afu_dev->rawdev = rawdev; + afu_dev->id.uuid.uuid_low = 0; + afu_dev->id.uuid.uuid_high = 0; + afu_dev->id.port = afu_pr_conf.afu_id.port; + + if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get) + rawdev->dev_ops->dev_info_get(rawdev, afu_dev); + + if (rawdev->dev_ops && + rawdev->dev_ops->dev_start && + rawdev->dev_ops->dev_start(rawdev)) + goto free_dev; + + strncpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); + if (rawdev->dev_ops->firmware_load && + rawdev->dev_ops->firmware_load(rawdev, + &afu_pr_conf)){ + IFPGA_BUS_ERR("firmware load error %d\n", ret); + goto free_dev; + } + afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; + afu_dev->id.uuid.uuid_high = afu_pr_conf.afu_id.uuid.uuid_high; + + return afu_dev; + +free_dev: + free(afu_dev); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (path) + free(path); + + return NULL; +} + +/* + * Scan the content of the FPGA bus, and the devices in the devices + * list + */ +static int +ifpga_scan(void) +{ + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + struct rte_rawdev *rawdev = NULL; + char *name = NULL; + char name1[RTE_RAWDEV_NAME_MAX_LEN]; + struct rte_afu_device *afu_dev = NULL; + + /* for FPGA devices we scan the devargs_list populated via cmdline */ + RTE_EAL_DEVARGS_FOREACH(IFPGA_ARG_NAME, devargs) { + if (devargs->bus != &rte_ifpga_bus) + continue; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_BUS_ERR("error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &rte_ifpga_get_string_arg, &name) < 0) { + IFPGA_BUS_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_BUS_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + memset(name1, 0, sizeof(name1)); + snprintf(name1, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", name); + + rawdev = rte_rawdev_pmd_get_named_dev(name1); + if (!rawdev) + goto end; + + afu_dev = ifpga_scan_one(rawdev, devargs); + if (afu_dev != NULL) + TAILQ_INSERT_TAIL(&ifpga_afu_dev_list, afu_dev, next); + } + +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +/* + * Match the AFU Driver and AFU Device using the ID Table + */ +static int +rte_afu_match(const struct rte_afu_driver *afu_drv, + const struct rte_afu_device *afu_dev) +{ + const struct rte_afu_uuid *id_table; + + for (id_table = afu_drv->id_table; + ((id_table->uuid_low != 0) && (id_table->uuid_high != 0)); + id_table++) { + /* check if device's identifiers match the driver's ones */ + if ((id_table->uuid_low != afu_dev->id.uuid.uuid_low) || + id_table->uuid_high != + afu_dev->id.uuid.uuid_high) + continue; + + return 1; + } + + return 0; +} + +static int +ifpga_probe_one_driver(struct rte_afu_driver *drv, + struct rte_afu_device *afu_dev) +{ + int ret; + + if (!rte_afu_match(drv, afu_dev)) + /* Match of device and driver failed */ + return 1; + + /* reference driver structure */ + afu_dev->driver = drv; + afu_dev->device.driver = &drv->driver; + + /* call the driver probe() function */ + ret = drv->probe(afu_dev); + if (ret) { + afu_dev->driver = NULL; + afu_dev->device.driver = NULL; + } + + return ret; +} + +static int +ifpga_probe_all_drivers(struct rte_afu_device *afu_dev) +{ + struct rte_afu_driver *drv = NULL; + int ret = 0; + + if (afu_dev == NULL) + return -1; + + /* Check if a driver is already loaded */ + if (afu_dev->driver != NULL) + return 0; + + TAILQ_FOREACH(drv, &ifpga_afu_drv_list, next) { + if (ifpga_probe_one_driver(drv, afu_dev)) { + ret = -1; + break; + } + } + return ret; +} + +/* + * Scan the content of the Intel FPGA bus, and call the probe() function for + * all registered drivers that have a matching entry in its id_table + * for discovered devices. + */ +static int +ifpga_probe(void) +{ + struct rte_afu_device *afu_dev = NULL; + int ret = 0; + + TAILQ_FOREACH(afu_dev, &ifpga_afu_dev_list, next) { + if (afu_dev->device.driver) + continue; + + ret = ifpga_probe_all_drivers(afu_dev); + if (ret < 0) + IFPGA_BUS_ERR("failed to initialize %s device\n", + rte_ifpga_device_name(afu_dev)); + } + + return ret; +} + +static int +ifpga_plug(struct rte_device *dev) +{ + return ifpga_probe_all_drivers(RTE_DEV_TO_AFU(dev)); +} + +static int +ifpga_remove_driver(struct rte_afu_device *afu_dev) +{ + const char *name; + const struct rte_afu_driver *driver; + + name = rte_ifpga_device_name(afu_dev); + if (!afu_dev->device.driver) { + IFPGA_BUS_DEBUG("no driver attach to device %s\n", name); + return 1; + } + + driver = RTE_DRV_TO_AFU_CONST(afu_dev->device.driver); + return driver->remove(afu_dev); +} + +static int +ifpga_unplug(struct rte_device *dev) +{ + struct rte_afu_device *afu_dev = NULL; + struct rte_devargs *devargs = NULL; + int ret; + + if (dev == NULL) + return -EINVAL; + + afu_dev = RTE_DEV_TO_AFU(dev); + if (!dev) + return -ENOENT; + + devargs = dev->devargs; + + ret = ifpga_remove_driver(afu_dev); + if (ret) + return ret; + + TAILQ_REMOVE(&ifpga_afu_dev_list, afu_dev, next); + + rte_devargs_remove(devargs->bus->name, devargs->name); + free(afu_dev); + return 0; + +} + +static struct rte_device * +ifpga_find_device(const struct rte_device *start, + rte_dev_cmp_t cmp, const void *data) +{ + struct rte_afu_device *afu_dev; + + TAILQ_FOREACH(afu_dev, &ifpga_afu_dev_list, next) { + if (start && &afu_dev->device == start) { + start = NULL; + continue; + } + if (cmp(&afu_dev->device, data) == 0) + return &afu_dev->device; + } + + return NULL; +} +static int +ifpga_parse(const char *name, void *addr) +{ + int *out = addr; + struct rte_rawdev *rawdev = NULL; + char rawdev_name[RTE_RAWDEV_NAME_MAX_LEN]; + char *c1 = NULL; + char *c2 = NULL; + int port = IFPGA_BUS_DEV_PORT_MAX; + char str_port[8]; + int str_port_len = 0; + int ret; + + memset(str_port, 0, 8); + c1 = strchr(name, '|'); + if (c1 != NULL) { + str_port_len = c1 - name; + c2 = c1 + 1; + } + + if (str_port_len < 8 && + str_port_len > 0) { + memcpy(str_port, name, str_port_len); + ret = sscanf(str_port, "%d", &port); + if (ret == -1) + return 0; + } + + memset(rawdev_name, 0, sizeof(rawdev_name)); + snprintf(rawdev_name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%s", c2); + rawdev = rte_rawdev_pmd_get_named_dev(rawdev_name); + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev && + (addr != NULL)) + *out = port; + + if ((port < IFPGA_BUS_DEV_PORT_MAX) && + rawdev) + return 0; + else + return 1; +} + +static struct rte_bus rte_ifpga_bus = { + .scan = ifpga_scan, + .probe = ifpga_probe, + .find_device = ifpga_find_device, + .plug = ifpga_plug, + .unplug = ifpga_unplug, + .parse = ifpga_parse, +}; + +RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus); + +RTE_INIT(ifpga_init_log) +{ + ifpga_bus_logtype = rte_log_register("bus.ifpga"); + if (ifpga_bus_logtype >= 0) + rte_log_set_level(ifpga_bus_logtype, RTE_LOG_NOTICE); +} diff --git a/drivers/bus/ifpga/ifpga_common.c b/drivers/bus/ifpga/ifpga_common.c new file mode 100644 index 0000000..78e2eae --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include <rte_errno.h> +#include <rte_bus.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> + +#include <rte_devargs.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include "rte_bus_ifpga.h" +#include "ifpga_logs.h" +#include "ifpga_common.h" + +int rte_ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(char **)extra_args = strdup(value); + + if (!*(char **)extra_args) + return -ENOMEM; + + return 0; +} +int rte_ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(int *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args) +{ + if (!value || !extra_args) + return -EINVAL; + + *(uint64_t *)extra_args = strtoull(value, NULL, 0); + + return 0; +} +int ifpga_get_unsigned_long(const char *str, int base) +{ + unsigned long num; + char *end = NULL; + + errno = 0; + + num = strtoul(str, &end, base); + if ((str[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0)) + return -1; + + return num; +} + +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1) +{ + if ((afu_id0->uuid.uuid_low == afu_id1->uuid.uuid_low) && + (afu_id0->uuid.uuid_high == afu_id1->uuid.uuid_high) && + (afu_id0->port == afu_id1->port)) { + return 0; + } else + return 1; +} diff --git a/drivers/bus/ifpga/ifpga_common.h b/drivers/bus/ifpga/ifpga_common.h new file mode 100644 index 0000000..f9254b9 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_common.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMMON_H_ +#define _IFPGA_COMMON_H_ + +int rte_ifpga_get_string_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int rte_ifpga_get_integer32_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_integer64_arg(const char *key __rte_unused, + const char *value, void *extra_args); +int ifpga_get_unsigned_long(const char *str, int base); +int ifpga_afu_id_cmp(const struct rte_afu_id *afu_id0, + const struct rte_afu_id *afu_id1); + +#endif /* _IFPGA_COMMON_H_ */ diff --git a/drivers/bus/ifpga/ifpga_logs.h b/drivers/bus/ifpga/ifpga_logs.h new file mode 100644 index 0000000..873e0a4 --- /dev/null +++ b/drivers/bus/ifpga/ifpga_logs.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_LOGS_H_ +#define _IFPGA_LOGS_H_ + +#include <rte_log.h> + +extern int ifpga_bus_logtype; + +#define IFPGA_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_bus_logtype, "%s(): " fmt "\n", \ + __func__, ##args) + +#define IFPGA_BUS_FUNC_TRACE() IFPGA_BUS_LOG(DEBUG, ">>") + +#define IFPGA_BUS_DEBUG(fmt, args...) \ + IFPGA_BUS_LOG(DEBUG, fmt, ## args) +#define IFPGA_BUS_INFO(fmt, args...) \ + IFPGA_BUS_LOG(INFO, fmt, ## args) +#define IFPGA_BUS_ERR(fmt, args...) \ + IFPGA_BUS_LOG(ERR, fmt, ## args) +#define IFPGA_BUS_WARN(fmt, args...) \ + IFPGA_BUS_LOG(WARNING, fmt, ## args) + +#endif /* _IFPGA_BUS_LOGS_H_ */ diff --git a/drivers/bus/ifpga/meson.build b/drivers/bus/ifpga/meson.build new file mode 100644 index 0000000..c9b08c8 --- /dev/null +++ b/drivers/bus/ifpga/meson.build @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2018 Intel Corporation + +deps += ['pci', 'kvargs', 'rawdev'] +install_headers('rte_bus_ifpga.h') +sources = files('ifpga_common.c', 'ifpga_bus.c') + +allow_experimental_apis = true diff --git a/drivers/bus/ifpga/rte_bus_ifpga.h b/drivers/bus/ifpga/rte_bus_ifpga.h new file mode 100644 index 0000000..981bc35 --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga.h @@ -0,0 +1,150 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _RTE_BUS_IFPGA_H_ +#define _RTE_BUS_IFPGA_H_ + +/** + * @file + * + * RTE Intel FPGA Bus Interface + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_bus.h> +#include <rte_pci.h> + +/** Name of Intel FPGA Bus */ +#define IFPGA_BUS_NAME ifpga + +/* Forward declarations */ +struct rte_afu_device; +struct rte_afu_driver; + +/** Double linked list of Intel FPGA AFU device. */ +TAILQ_HEAD(ifpga_afu_dev_list, rte_afu_device); +/** Double linked list of Intel FPGA AFU device drivers. */ +TAILQ_HEAD(ifpga_afu_drv_list, rte_afu_driver); + +#define IFPGA_BUS_BITSTREAM_PATH_MAX_LEN 256 + +struct rte_afu_uuid { + uint64_t uuid_low; + uint64_t uuid_high; +} __attribute__ ((packed)); + +#define IFPGA_BUS_DEV_PORT_MAX 4 + +/** + * A structure describing an ID for a AFU driver. Each driver provides a + * table of these IDs for each device that it supports. + */ +struct rte_afu_id { + struct rte_afu_uuid uuid; + int port; /**< port number */ +} __attribute__ ((packed)); + +/** + * A structure PR (Partial Reconfiguration) configuration AFU driver. + */ + +struct rte_afu_pr_conf { + struct rte_afu_id afu_id; + int pr_enable; + char bs_path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +}; + +#define AFU_PRI_STR_SIZE (PCI_PRI_STR_SIZE + 8) + +/** + * A structure describing a AFU device. + */ +struct rte_afu_device { + TAILQ_ENTRY(rte_afu_device) next; /**< Next in device list. */ + struct rte_device device; /**< Inherit core device */ + struct rte_rawdev *rawdev; /**< Point Rawdev */ + struct rte_afu_id id; /**< AFU id within FPGA. */ + uint32_t num_region; /**< number of regions found */ + struct rte_mem_resource mem_resource[PCI_MAX_RESOURCE]; + /**< AFU Memory Resource */ + struct rte_intr_handle intr_handle; /**< Interrupt handle */ + struct rte_afu_driver *driver; /**< Associated driver */ + char path[IFPGA_BUS_BITSTREAM_PATH_MAX_LEN]; +} __attribute__ ((packed)); + +/** + * @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_DRV_TO_AFU_CONST(ptr) \ + container_of(ptr, const struct rte_afu_driver, driver) + +/** + * Initialization function for the driver called during FPGA BUS probing. + */ +typedef int (afu_probe_t)(struct rte_afu_device *); + +/** + * Uninitialization function for the driver called during hotplugging. + */ +typedef int (afu_remove_t)(struct rte_afu_device *); + +/** + * A structure describing a AFU device. + */ +struct rte_afu_driver { + TAILQ_ENTRY(rte_afu_driver) next; /**< Next afu driver. */ + struct rte_driver driver; /**< Inherit core driver. */ + afu_probe_t *probe; /**< Device Probe function. */ + afu_remove_t *remove; /**< Device Remove function. */ + const struct rte_afu_uuid *id_table; /**< AFU uuid within FPGA. */ +}; + +static inline const char * +rte_ifpga_device_name(const struct rte_afu_device *afu) +{ + if (afu && afu->device.name) + return afu->device.name; + return NULL; +} + +/** + * Register a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be registered. + */ +void rte_ifpga_driver_register(struct rte_afu_driver *driver); + +/** + * Unregister a ifpga afu device driver. + * + * @param driver + * A pointer to a rte_afu_driver structure describing the driver + * to be unregistered. + */ +void rte_ifpga_driver_unregister(struct rte_afu_driver *driver); + +#define RTE_PMD_REGISTER_AFU(nm, afudrv)\ +RTE_INIT(afudrvinitfn_ ##afudrv);\ +static const char *afudrvinit_ ## nm ## _alias;\ +static void afudrvinitfn_ ##afudrv(void)\ +{\ + (afudrv).driver.name = RTE_STR(nm);\ + (afudrv).driver.alias = afudrvinit_ ## nm ## _alias;\ + rte_ifpga_driver_register(&afudrv);\ +} \ +RTE_PMD_EXPORT_NAME(nm, __COUNTER__) + +#define RTE_PMD_REGISTER_AFU_ALIAS(nm, alias)\ +static const char *afudrvinit_ ## nm ## _alias = RTE_STR(alias) + +#endif /* _RTE_BUS_IFPGA_H_ */ diff --git a/drivers/bus/ifpga/rte_bus_ifpga_version.map b/drivers/bus/ifpga/rte_bus_ifpga_version.map new file mode 100644 index 0000000..a027979 --- /dev/null +++ b/drivers/bus/ifpga/rte_bus_ifpga_version.map @@ -0,0 +1,10 @@ +DPDK_18.05 { + global: + + rte_ifpga_get_integer32_arg; + rte_ifpga_get_string_arg; + rte_ifpga_driver_register; + rte_ifpga_driver_unregister; + + local: *; +}; diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build index 58dfbe2..52c755d 100644 --- a/drivers/bus/meson.build +++ b/drivers/bus/meson.build @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel Corporation -drivers = ['dpaa', 'fslmc', 'pci', 'vdev'] +drivers = ['dpaa', 'fslmc', 'ifpga', 'pci', 'vdev'] std_deps = ['eal'] config_flag_fmt = 'RTE_LIBRTE_@0@_BUS' driver_name_fmt = 'rte_bus_@0@' diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 6807663..290fdf2 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -261,6 +261,7 @@ ifeq ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += -lrte_pmd_dpaa2_cmdif _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += -lrte_pmd_dpaa2_qdma endif # CONFIG_RTE_LIBRTE_FSLMC_BUS +_LDLIBS-$(CONFIG_RTE_LIBRTE_IFPGA_BUS) += -lrte_bus_ifpga endif # CONFIG_RTE_LIBRTE_RAWDEV -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v12 2/3] iFPGA: Add Intel FPGA OPAE Share Code 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS Xu, Rosen 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 1/3] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen @ 2018-05-11 8:31 ` Xu, Rosen 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2018-05-11 12:11 ` [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS Zhang, Qi Z 3 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-11 8:31 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Xu, Yilun From: Tianfei Zhang <tianfei.zhang@intel.com> This patch adds Intel FPGA Open Programmable Acceleration Engine (OPAE)[1] base driver code, in order to support Intel FPGA devices under DPDK. The base code currently supports Intel FPGA solutions including integrated solution (Intel(R) Xeon(R) CPU with FPGAs) and discrete solution (Intel(R) Programmable Acceleration Card with Intel(R) Arria(R) 10 FPGA) and it could be extended to support more FPGA devices in the future. Please refer to [1][2] for more introduction on OPAE and Intel FPGAs. [1] https://01.org/OPAE [2] https://www.altera.com/solutions/acceleration-hub/overview.html Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> Signed-off-by: Wu, Hao <hao.wu@intel.com> Signed-off-by: Xu, Yilun <yilun.xu@intel.com> --- MAINTAINERS | 4 + drivers/raw/ifpga_rawdev/base/Makefile | 26 + drivers/raw/ifpga_rawdev/base/README | 31 + drivers/raw/ifpga_rawdev/base/ifpga_api.c | 294 ++++ drivers/raw/ifpga_rawdev/base/ifpga_api.h | 28 + drivers/raw/ifpga_rawdev/base/ifpga_compat.h | 58 + drivers/raw/ifpga_rawdev/base/ifpga_defines.h | 1662 ++++++++++++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c | 821 ++++++++++ drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h | 11 + drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c | 253 +++ drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 164 ++ drivers/raw/ifpga_rawdev/base/ifpga_fme.c | 734 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c | 301 ++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c | 381 +++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c | 715 +++++++++ drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c | 352 +++++ drivers/raw/ifpga_rawdev/base/ifpga_hw.h | 127 ++ drivers/raw/ifpga_rawdev/base/ifpga_port.c | 388 +++++ drivers/raw/ifpga_rawdev/base/ifpga_port_error.c | 144 ++ drivers/raw/ifpga_rawdev/base/meson.build | 34 + drivers/raw/ifpga_rawdev/base/opae_debug.c | 99 ++ drivers/raw/ifpga_rawdev/base/opae_debug.h | 19 + drivers/raw/ifpga_rawdev/base/opae_hw_api.c | 381 +++++ drivers/raw/ifpga_rawdev/base/opae_hw_api.h | 253 +++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c | 145 ++ drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h | 279 ++++ drivers/raw/ifpga_rawdev/base/opae_osdep.h | 79 + .../ifpga_rawdev/base/osdep_raw/osdep_generic.h | 75 + .../ifpga_rawdev/base/osdep_rte/osdep_generic.h | 45 + 29 files changed, 7903 insertions(+) create mode 100644 drivers/raw/ifpga_rawdev/base/Makefile create mode 100644 drivers/raw/ifpga_rawdev/base/README create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_compat.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_defines.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_hw.h create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port.c create mode 100644 drivers/raw/ifpga_rawdev/base/ifpga_port_error.c create mode 100644 drivers/raw/ifpga_rawdev/base/meson.build create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_debug.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c create mode 100644 drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h create mode 100644 drivers/raw/ifpga_rawdev/base/opae_osdep.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h create mode 100644 drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h diff --git a/MAINTAINERS b/MAINTAINERS index 39c3988..a872973 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -880,6 +880,10 @@ F: doc/guides/eventdevs/opdl.rst Rawdev Drivers -------------- +Intel FPGA +M: Tianfei zhang <tianfei.zhang@intel.com> +F: drivers/raw/ifpga_rawdev/base/ + NXP DPAA2 QDMA M: Nipun Gupta <nipun.gupta@nxp.com> F: drivers/raw/dpaa2_qdma/ diff --git a/drivers/raw/ifpga_rawdev/base/Makefile b/drivers/raw/ifpga_rawdev/base/Makefile new file mode 100644 index 0000000..d79da72 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/Makefile @@ -0,0 +1,26 @@ +#SPDX-License-Identifier: BSD-3-Clause +#Copyright(c) 2010-2018 Intel Corporation + +ifneq ($(CONFIG_RTE_LIBRTE_EAL),) +OSDEP := osdep_rte +else +OSDEP := osdep_raw +endif + +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev/base/$(OSDEP) + +SRCS-y += ifpga_api.c +SRCS-y += ifpga_enumerate.c +SRCS-y += ifpga_feature_dev.c +SRCS-y += ifpga_fme.c +SRCS-y += ifpga_fme_iperf.c +SRCS-y += ifpga_fme_dperf.c +SRCS-y += ifpga_fme_error.c +SRCS-y += ifpga_port.c +SRCS-y += ifpga_port_error.c +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 += $(wildcard $(SRCDIR)/base/$(OSDEP)/*.c) diff --git a/drivers/raw/ifpga_rawdev/base/README b/drivers/raw/ifpga_rawdev/base/README new file mode 100644 index 0000000..5bc2ed0 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/README @@ -0,0 +1,31 @@ +.. + +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +Intel iFPGA driver +================== + +This directory contains source code of Intel FPGA driver released by +the team which develops Intel FPGA Open Programmable Acceleration Engine (OPAE). +The directory of base/ contains the original source package. The base code +currently supports Intel FPGA solutions including integrated solution (Intel(R) +Xeon(R) CPU with FPGAs) and discrete solution (Intel(R) Programmable Acceleration +Card with Intel(R) Arria(R) 10 FPGA) and it could be extended to support more FPGA +devices in the future. + +Please refer to [1][2] for more introduction on OPAE and Intel FPGAs. + +[1] https://01.org/OPAE +[2] https://www.altera.com/solutions/acceleration-hub/overview.html + + +Updating the driver +=================== + +NOTE: The source code in this directory should not be modified apart from +the following file(s): + + osdep_raw/osdep_generic.h + osdep_rte/osdep_generic.h diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.c b/drivers/raw/ifpga_rawdev/base/ifpga_api.c new file mode 100644 index 0000000..540e171 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.c @@ -0,0 +1,294 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_api.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +#include "opae_hw_api.h" + +/* Accelerator APIs */ +static int ifpga_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return fpga_get_afu_uuid(port, uuid); +} + +static int ifpga_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_bridge *br = acc->br; + struct ifpga_port_hw *port; + struct fpga_uafu_irq_set irq_set; + + if (!br || !br->data) + return -EINVAL; + + if (start >= afu_info->num_irqs || start + count > afu_info->num_irqs) + return -EINVAL; + + port = br->data; + + irq_set.start = start; + irq_set.count = count; + irq_set.evtfds = evtfds; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_UINT, &irq_set); +} + +static int ifpga_acc_get_info(struct opae_accelerator *acc, + struct opae_acc_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -ENODEV; + + info->num_regions = afu_info->num_regions; + info->num_irqs = afu_info->num_irqs; + + return 0; +} + +static int ifpga_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + struct ifpga_afu_info *afu_info = acc->data; + + if (!afu_info) + return -EINVAL; + + if (info->index >= afu_info->num_regions) + return -EINVAL; + + /* always one RW region only for AFU now */ + info->flags = ACC_REGION_READ | ACC_REGION_WRITE | ACC_REGION_MMIO; + info->len = afu_info->region[info->index].len; + info->addr = afu_info->region[info->index].addr; + + return 0; +} + +static int ifpga_acc_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + switch (byte) { + case 8: + *(u64 *)data = opae_readq(region->addr + offset); + break; + case 4: + *(u32 *)data = opae_readl(region->addr + offset); + break; + case 2: + *(u16 *)data = opae_readw(region->addr + offset); + break; + case 1: + *(u8 *)data = opae_readb(region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ifpga_acc_write(struct opae_accelerator *acc, + unsigned int region_idx, u64 offset, + unsigned int byte, void *data) +{ + struct ifpga_afu_info *afu_info = acc->data; + struct opae_reg_region *region; + + if (!afu_info) + return -EINVAL; + + if (offset + byte <= offset) + return -EINVAL; + + if (region_idx >= afu_info->num_regions) + return -EINVAL; + + region = &afu_info->region[region_idx]; + if (offset + byte > region->len) + return -EINVAL; + + /* normal mmio case */ + switch (byte) { + case 8: + opae_writeq(*(u64 *)data, region->addr + offset); + break; + case 4: + opae_writel(*(u32 *)data, region->addr + offset); + break; + case 2: + opae_writew(*(u16 *)data, region->addr + offset); + break; + case 1: + opae_writeb(*(u8 *)data, region->addr + offset); + break; + default: + return -EINVAL; + } + + return 0; +} + +struct opae_accelerator_ops ifpga_acc_ops = { + .read = ifpga_acc_read, + .write = ifpga_acc_write, + .set_irq = ifpga_acc_set_irq, + .get_info = ifpga_acc_get_info, + .get_region_info = ifpga_acc_get_region_info, + .get_uuid = ifpga_acc_get_uuid, +}; + +/* Bridge APIs */ + +static int ifpga_br_reset(struct opae_bridge *br) +{ + struct ifpga_port_hw *port = br->data; + + return fpga_port_reset(port); +} + +struct opae_bridge_ops ifpga_br_ops = { + .reset = ifpga_br_reset, +}; + +/* Manager APIs */ +static int ifpga_mgr_flash(struct opae_manager *mgr, int id, void *buf, + u32 size, u64 *status) +{ + struct ifpga_fme_hw *fme = mgr->data; + struct ifpga_hw *hw = fme->parent; + + return ifpga_pr(hw, id, buf, size, status); +} + +struct opae_manager_ops ifpga_mgr_ops = { + .flash = ifpga_mgr_flash, +}; + +/* Adapter APIs */ +static int ifpga_adapter_enumerate(struct opae_adapter *adapter) +{ + struct ifpga_hw *hw = malloc(sizeof(*hw)); + + if (hw) { + memset(hw, 0, sizeof(*hw)); + hw->pci_data = adapter->data; + hw->adapter = adapter; + if (ifpga_bus_enumerate(hw)) + goto error; + return ifpga_bus_init(hw); + } + +error: + return -ENOMEM; +} + +struct opae_adapter_ops ifpga_adapter_ops = { + .enumerate = ifpga_adapter_enumerate, +}; + +/** + * ifpga_pr - do the partial reconfiguration for a given port device + * @hw: pointer to the HW structure + * @port_id: the port device id + * @buffer: the buffer of the bitstream + * @size: the size of the bitstream + * @status: hardware status including PR error code if return -EIO. + * + * @return + * - 0: Success, partial reconfiguration finished. + * - <0: Error code returned in partial reconfiguration. + **/ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + + return do_pr(hw, port_id, buffer, size, status); +} + +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_get_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_get_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop) +{ + if (!hw || !prop) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_prop(&hw->fme, prop); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_prop(&hw->port[port_id], prop); + } + + return -ENOENT; +} + +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set) +{ + if (!hw || !irq_set) + return -EINVAL; + + switch (fiu_id) { + case FEATURE_FIU_ID_FME: + return fme_set_irq(&hw->fme, feature_id, irq_set); + case FEATURE_FIU_ID_PORT: + if (!is_valid_port_id(hw, port_id)) + return -ENODEV; + return port_set_irq(&hw->port[port_id], feature_id, irq_set); + } + + return -ENOENT; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_api.h b/drivers/raw/ifpga_rawdev/base/ifpga_api.h new file mode 100644 index 0000000..dae7ca1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_api.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_API_H_ +#define _IFPGA_API_H_ + +#include "opae_hw_api.h" +#include "ifpga_hw.h" + +extern struct opae_adapter_ops ifpga_adapter_ops; +extern struct opae_manager_ops ifpga_mgr_ops; +extern struct opae_bridge_ops ifpga_br_ops; +extern struct opae_accelerator_ops ifpga_acc_ops; + +/* common APIs */ +int ifpga_get_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_prop(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + struct feature_prop *prop); +int ifpga_set_irq(struct ifpga_hw *hw, u32 fiu_id, u32 port_id, + u32 feature_id, void *irq_set); + +/* FME APIs */ +int ifpga_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +#endif /* _IFPGA_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_compat.h b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h new file mode 100644 index 0000000..931c893 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_compat.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_COMPAT_H_ +#define _IFPGA_COMPAT_H_ + +#include "opae_osdep.h" + +#undef container_of +#define container_of(ptr, type, member) ({ \ + typeof(((type *)0)->member)(*__mptr) = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +#define IFPGA_PAGE_SHIFT 12 +#define IFPGA_PAGE_SIZE (1 << IFPGA_PAGE_SHIFT) +#define IFPGA_PAGE_MASK (~(IFPGA_PAGE_SIZE - 1)) +#define IFPGA_PAGE_ALIGN(addr) (((addr) + IFPGA_PAGE_SIZE - 1)\ + & IFPGA_PAGE_MASK) +#define IFPGA_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) +#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), IFPGA_PAGE_SIZE) + +#define readl(addr) opae_readl(addr) +#define readq(addr) opae_readq(addr) +#define writel(value, addr) opae_writel(value, addr) +#define writeq(value, addr) opae_writeq(value, addr) + +#define malloc(size) opae_malloc(size) +#define zmalloc(size) opae_zmalloc(size) +#define free(size) opae_free(size) + +/* + * Wait register's _field to be changed to the given value (_expect's _field) + * by polling with given interval and timeout. + */ +#define fpga_wait_register_field(_field, _expect, _reg_addr, _timeout, _invl)\ +({ \ + int wait = 0; \ + int ret = -ETIMEDOUT; \ + typeof(_expect) value; \ + for (; wait <= _timeout; wait += _invl) { \ + value.csr = readq(_reg_addr); \ + if (_expect._field == value._field) { \ + ret = 0; \ + break; \ + } \ + udelay(_invl); \ + } \ + ret; \ +}) + +#define __maybe_unused __attribute__((__unused__)) + +#define UNUSED(x) (void)(x) + +#endif /* _IFPGA_COMPAT_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_defines.h b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h new file mode 100644 index 0000000..0b9622d --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_defines.h @@ -0,0 +1,1662 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_DEFINES_H_ +#define _IFPGA_DEFINES_H_ + +#include "ifpga_compat.h" + +#define MAX_FPGA_PORT_NUM 4 + +#define FME_FEATURE_HEADER "fme_hdr" +#define FME_FEATURE_THERMAL_MGMT "fme_thermal" +#define FME_FEATURE_POWER_MGMT "fme_power" +#define FME_FEATURE_GLOBAL_IPERF "fme_iperf" +#define FME_FEATURE_GLOBAL_ERR "fme_error" +#define FME_FEATURE_PR_MGMT "fme_pr" +#define FME_FEATURE_HSSI_ETH "fme_hssi" +#define FME_FEATURE_GLOBAL_DPERF "fme_dperf" +#define FME_FEATURE_QSPI_FLASH "fme_qspi_flash" + +#define PORT_FEATURE_HEADER "port_hdr" +#define PORT_FEATURE_UAFU "port_uafu" +#define PORT_FEATURE_ERR "port_err" +#define PORT_FEATURE_UMSG "port_umsg" +#define PORT_FEATURE_PR "port_pr" +#define PORT_FEATURE_UINT "port_uint" +#define PORT_FEATURE_STP "port_stp" + +/* + * do not check the revision id as id may be dynamic under + * some cases, e.g, UAFU. + */ +#define SKIP_REVISION_CHECK 0xff + +#define FME_HEADER_REVISION 1 +#define FME_THERMAL_MGMT_REVISION 0 +#define FME_POWER_MGMT_REVISION 1 +#define FME_GLOBAL_IPERF_REVISION 1 +#define FME_GLOBAL_ERR_REVISION 1 +#define FME_PR_MGMT_REVISION 2 +#define FME_HSSI_ETH_REVISION 0 +#define FME_GLOBAL_DPERF_REVISION 0 +#define FME_QSPI_REVISION 0 + +#define PORT_HEADER_REVISION 0 +/* UAFU's header info depends on the downloaded GBS */ +#define PORT_UAFU_REVISION SKIP_REVISION_CHECK +#define PORT_ERR_REVISION 1 +#define PORT_UMSG_REVISION 0 +#define PORT_UINT_REVISION 0 +#define PORT_STP_REVISION 1 + +#define FEATURE_TYPE_AFU 0x1 +#define FEATURE_TYPE_BBB 0x2 +#define FEATURE_TYPE_PRIVATE 0x3 +#define FEATURE_TYPE_FIU 0x4 + +#define FEATURE_FIU_ID_FME 0x0 +#define FEATURE_FIU_ID_PORT 0x1 + +#define FEATURE_ID_HEADER 0x0 +#define FEATURE_ID_AFU 0xff + +enum fpga_id_type { + FME_ID, + PORT_ID, + 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, +}; + +/* + * All headers and structures must be byte-packed to match the spec. + */ +#pragma pack(1) + +struct feature_header { + union { + u64 csr; + struct { + u16 id:12; + u8 revision:4; + u32 next_header_offset:24; + u8 end_of_list:1; + u32 reserved:19; + u8 type:4; + }; + }; +}; + +struct feature_bbb_header { + struct uuid guid; +}; + +struct feature_afu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fiu_header { + struct uuid guid; + union { + u64 csr; + struct { + u64 next_afu:24; + u64 reserved:40; + }; + }; +}; + +struct feature_fme_capability { + union { + u64 csr; + struct { + u8 fabric_verid; /* Fabric version ID */ + u8 socket_id:1; /* Socket id */ + u8 rsvd1:3; /* Reserved */ + /* pci0 link available yes /no */ + u8 pci0_link_avile:1; + /* pci1 link available yes /no */ + u8 pci1_link_avile:1; + /* Coherent (QPI/UPI) link available yes /no */ + u8 qpi_link_avile:1; + u8 rsvd2:1; /* Reserved */ + /* IOMMU or VT-d supported yes/no */ + u8 iommu_support:1; + u8 num_ports:3; /* Number of ports */ + u8 sf_fab_ctl:1; /* Internal validation bit */ + u8 rsvd3:3; /* Reserved */ + /* + * Address width supported in bits + * BXT -0x26 , SKX -0x30 + */ + u8 address_width_bits:6; + u8 rsvd4:2; /* Reserved */ + /* Size of cache supported in kb */ + u16 cache_size:12; + u8 cache_assoc:4; /* Cache Associativity */ + u16 rsvd5:15; /* Reserved */ + u8 lock_bit:1; /* Lock bit */ + }; + }; +}; + +#define FME_AFU_ACCESS_PF 0 +#define FME_AFU_ACCESS_VF 1 + +struct feature_fme_port { + union { + u64 csr; + struct { + u32 port_offset:24; + u8 reserved1; + u8 port_bar:3; + u32 reserved2:20; + u8 afu_access_control:1; + u8 reserved3:4; + u8 port_implemented:1; + u8 reserved4:3; + }; + }; +}; + +struct feature_fme_fab_status { + union { + u64 csr; + struct { + u8 upilink_status:4; /* UPI Link Status */ + u8 rsvd1:4; /* Reserved */ + u8 pci0link_status:1; /* pci0 link status */ + u8 rsvd2:3; /* Reserved */ + u8 pci1link_status:1; /* pci1 link status */ + u64 rsvd3:51; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_base { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Base Address of memory range */ + u8 protected_base_addrss:4; + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +struct feature_fme_genprotrange2_limit { + union { + u64 csr; + struct { + u16 rsvd1; /* Reserved */ + /* Limit Address of memory range */ + u8 protected_limit_addrss:4; + u16 rsvd2:11; /* Reserved */ + u8 enable:1; /* Enable GENPROTRANGE check */ + u32 rsvd3; /* Reserved */ + }; + }; +}; + +struct feature_fme_dxe_lock { + union { + u64 csr; + struct { + /* + * Determines write access to the DXE region CSRs + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_early_lock:1; + /* + * Determines write access to the HSSI CSR + * 1 - CSR region is locked; + * 0 - it is open for write access. + */ + u8 dxe_late_lock:1; + u64 rsvd:62; + }; + }; +}; + +#define HSSI_ID_NO_HASSI 0 +#define HSSI_ID_PCIE_RP 1 +#define HSSI_ID_ETHERNET 2 + +struct feature_fme_bitstream_id { + union { + u64 csr; + struct { + u32 gitrepo_hash:32; /* GIT repository hash */ + /* + * HSSI configuration identifier: + * 0 - No HSSI + * 1 - PCIe-RP + * 2 - Ethernet + */ + u8 hssi_id:4; + u16 rsvd1:12; /* Reserved */ + /* Bitstream version patch number */ + u8 bs_verpatch:4; + /* Bitstream version minor number */ + u8 bs_verminor:4; + /* Bitstream version major number */ + u8 bs_vermajor:4; + /* Bitstream version debug number */ + u8 bs_verdebug:4; + }; + }; +}; + +struct feature_fme_bitstream_md { + union { + u64 csr; + struct { + /* Seed number userd for synthesis flow */ + u8 synth_seed:4; + /* Synthesis date(day number - 2 digits) */ + u8 synth_day:8; + /* Synthesis date(month number - 2 digits) */ + u8 synth_month:8; + /* Synthesis date(year number - 2 digits) */ + u8 synth_year:8; + u64 rsvd:36; /* Reserved */ + }; + }; +}; + +struct feature_fme_iommu_ctrl { + union { + u64 csr; + struct { + /* Disables IOMMU prefetcher for C0 channel */ + u8 prefetch_disableC0:1; + /* Disables IOMMU prefetcher for C1 channel */ + u8 prefetch_disableC1:1; + /* Disables IOMMU partial cache line writes */ + u8 prefetch_wrdisable:1; + u8 rsvd1:1; /* Reserved */ + /* + * Select counter and read value from register + * iommu_stat.dbg_counters + * 0 - Number of 4K page translation response + * 1 - Number of 2M page translation response + * 2 - Number of 1G page translation response + */ + u8 counter_sel:2; + u32 rsvd2:26; /* Reserved */ + /* Connected to IOMMU SIP Capabilities */ + u32 capecap_defeature; + }; + }; +}; + +struct feature_fme_iommu_stat { + union { + u64 csr; + struct { + /* Translation Enable bit from IOMMU SIP */ + u8 translation_enable:1; + /* Drain request in progress */ + u8 drain_req_inprog:1; + /* Invalidation current state */ + u8 inv_state:3; + /* C0 Response Buffer current state */ + u8 respbuffer_stateC0:3; + /* C1 Response Buffer current state */ + u8 respbuffer_stateC1:3; + /* Last request ID to IOMMU SIP */ + u8 last_reqID:4; + /* Last IOMMU SIP response ID value */ + u8 last_respID:4; + /* Last IOMMU SIP response status value */ + u8 last_respstatus:3; + /* C0 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC0:1; + /* C1 Transaction Buffer is not empty */ + u8 transbuf_notEmptyC1:1; + /* C0 Request FIFO is not empty */ + u8 reqFIFO_notemptyC0:1; + /* C1 Request FIFO is not empty */ + u8 reqFIFO_notemptyC1:1; + /* C0 Response FIFO is not empty */ + u8 respFIFO_notemptyC0:1; + /* C1 Response FIFO is not empty */ + u8 respFIFO_notemptyC1:1; + /* C0 Response FIFO overflow detected */ + u8 respFIFO_overflowC0:1; + /* C1 Response FIFO overflow detected */ + u8 respFIFO_overflowC1:1; + /* C0 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC0:1; + /* C1 Transaction Buffer overflow detected */ + u8 tranbuf_overflowC1:1; + /* Request FIFO overflow detected */ + u8 reqFIFO_overflow:1; + /* IOMMU memory read in progress */ + u8 memrd_inprog:1; + /* IOMMU memory write in progress */ + u8 memwr_inprog:1; + u8 rsvd1:1; /* Reserved */ + /* Value of counter selected by iommu_ctl.counter_sel */ + u16 dbg_counters:16; + u16 rsvd2:12; /* Reserved */ + }; + }; +}; + +struct feature_fme_pcie0_ctrl { + union { + u64 csr; + struct { + u64 vtd_bar_lock:1; /* Lock VT-D BAR register */ + u64 rsvd1:3; + u64 rciep:1; /* Configure PCIE0 as RCiEP */ + u64 rsvd2:59; + }; + }; +}; + +struct feature_fme_llpr_smrr_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR rule is valid or not */ + /* + * SMRR memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_base { + union { + u64 csr; + struct { + u64 rsvd1:12; + u64 base:20; /* SMRR2 memory range base address */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_smrr2_mask { + union { + u64 csr; + struct { + u64 rsvd1:11; + u64 valid:1; /* LLPR_SMRR2 rule is valid or not */ + /* + * SMRR2 memory range mask which determines the range + * of region being mapped + */ + u64 phys_mask:20; + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_llpr_meseg_base { + union { + u64 csr; + struct { + /* A[45:19] of base address memory range */ + u64 me_base:27; + u64 rsvd:37; + }; + }; +}; + +struct feature_fme_llpr_meseg_limit { + union { + u64 csr; + struct { + /* A[45:19] of limit address memory range */ + u64 me_limit:27; + u64 rsvd1:4; + u64 enable:1; /* Enable LLPR MESEG rule */ + u64 rsvd2:32; + }; + }; +}; + +struct feature_fme_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 reserved; + u64 scratchpad; + struct feature_fme_capability capability; + struct feature_fme_port port[MAX_FPGA_PORT_NUM]; + struct feature_fme_fab_status fab_status; + struct feature_fme_bitstream_id bitstream_id; + struct feature_fme_bitstream_md bitstream_md; + struct feature_fme_genprotrange2_base genprotrange2_base; + struct feature_fme_genprotrange2_limit genprotrange2_limit; + struct feature_fme_dxe_lock dxe_lock; + struct feature_fme_iommu_ctrl iommu_ctrl; + struct feature_fme_iommu_stat iommu_stat; + struct feature_fme_pcie0_ctrl pcie0_control; + struct feature_fme_llpr_smrr_base smrr_base; + struct feature_fme_llpr_smrr_mask smrr_mask; + struct feature_fme_llpr_smrr2_base smrr2_base; + struct feature_fme_llpr_smrr2_mask smrr2_mask; + struct feature_fme_llpr_meseg_base meseg_base; + struct feature_fme_llpr_meseg_limit meseg_limit; +}; + +struct feature_port_capability { + union { + u64 csr; + struct { + u8 port_number:2; /* Port Number 0-3 */ + u8 rsvd1:6; /* Reserved */ + u16 mmio_size; /* User MMIO size in KB */ + u8 rsvd2; /* Reserved */ + u8 sp_intr_num:4; /* Supported interrupts num */ + u32 rsvd3:28; /* Reserved */ + }; + }; +}; + +struct feature_port_control { + union { + u64 csr; + struct { + u8 port_sftrst:1; /* Port Soft Reset */ + u8 rsvd1:1; /* Reserved */ + u8 latency_tolerance:1;/* '1' >= 40us, '0' < 40us */ + u8 rsvd2:1; /* Reserved */ + u8 port_sftrst_ack:1; /* HW ACK for Soft Reset */ + u64 rsvd3:59; /* Reserved */ + }; + }; +}; + +#define PORT_POWER_STATE_NORMAL 0 +#define PORT_POWER_STATE_AP1 1 +#define PORT_POWER_STATE_AP2 2 +#define PORT_POWER_STATE_AP6 6 + +struct feature_port_status { + union { + u64 csr; + struct { + u8 port_freeze:1; /* '1' - freezed '0' - normal */ + u8 rsvd1:7; /* Reserved */ + u8 power_state:4; /* Power State */ + u8 ap1_event:1; /* AP1 event was detected */ + u8 ap2_event:1; /* AP2 event was detected */ + u64 rsvd2:50; /* Reserved */ + }; + }; +}; + +/* Port Header Register Set */ +struct feature_port_header { + struct feature_header header; + struct feature_afu_header afu_header; + u64 port_mailbox; + u64 scratchpad; + struct feature_port_capability capability; + struct feature_port_control control; + struct feature_port_status status; + u64 rsvd2; + u64 user_clk_freq_cmd0; + u64 user_clk_freq_cmd1; + u64 user_clk_freq_sts0; + u64 user_clk_freq_sts1; +}; + +struct feature_fme_tmp_threshold { + union { + u64 csr; + struct { + u8 tmp_thshold1:7; /* temperature Threshold 1 */ + /* temperature Threshold 1 enable/disable */ + u8 tmp_thshold1_enable:1; + u8 tmp_thshold2:7; /* temperature Threshold 2 */ + /* temperature Threshold 2 enable /disable */ + u8 tmp_thshold2_enable:1; + u8 pro_hot_setpoint:7; /* Proc Hot set point */ + u8 rsvd4:1; /* Reserved */ + u8 therm_trip_thshold:7; /* Thermeal Trip Threshold */ + u8 rsvd3:1; /* Reserved */ + u8 thshold1_status:1; /* Threshold 1 Status */ + u8 thshold2_status:1; /* Threshold 2 Status */ + u8 rsvd5:1; /* Reserved */ + /* Thermeal Trip Threshold status */ + u8 therm_trip_thshold_status:1; + u8 rsvd6:4; /* Reserved */ + /* Validation mode- Force Proc Hot */ + u8 valmodeforce:1; + /* Validation mode - Therm trip Hot */ + u8 valmodetherm:1; + u8 rsvd2:2; /* Reserved */ + u8 thshold_policy:1; /* threshold policy */ + u32 rsvd:19; /* Reserved */ + }; + }; +}; + +/* Temperature Sensor Read values format 1 */ +struct feature_fme_temp_rdsensor_fmt1 { + union { + u64 csr; + struct { + /* Reads out FPGA temperature in celsius */ + u8 fpga_temp:7; + u8 rsvd0:1; /* Reserved */ + /* Temperature reading sequence number */ + u16 tmp_reading_seq_num; + /* Temperature reading is valid */ + u8 tmp_reading_valid:1; + u8 rsvd1:7; /* Reserved */ + u16 dbg_mode:10; /* Debug mode */ + u32 rsvd2:22; /* Reserved */ + }; + }; +}; + +/* Temperature sensor read values format 2 */ +struct feature_fme_temp_rdsensor_fmt2 { + u64 rsvd; /* Reserved */ +}; + +/* Temperature Threshold Capability Register */ +struct feature_fme_tmp_threshold_cap { + union { + u64 csr; + struct { + /* Temperature Threshold Unsupported */ + u8 tmp_thshold_disabled:1; + u64 rsvd:63; /* Reserved */ + }; + }; +}; + +/* FME THERNAL FEATURE */ +struct feature_fme_thermal { + struct feature_header header; + struct feature_fme_tmp_threshold threshold; + struct feature_fme_temp_rdsensor_fmt1 rdsensor_fm1; + struct feature_fme_temp_rdsensor_fmt2 rdsensor_fm2; + struct feature_fme_tmp_threshold_cap threshold_cap; +}; + +/* Power Status register */ +struct feature_fme_pm_status { + union { + u64 csr; + struct { + /* FPGA Power consumed, The format is to be defined */ + u32 pwr_consumed:18; + /* FPGA Latency Tolerance Reporting */ + u8 fpga_latency_report:1; + u64 rsvd:45; /* Reserved */ + }; + }; +}; + +/* AP Thresholds */ +struct feature_fme_pm_ap_threshold { + union { + u64 csr; + struct { + /* + * Number of clocks (5ns period) for assertion + * of FME_data + */ + u8 threshold1:7; + u8 rsvd1:1; + u8 threshold2:7; + u8 rsvd2:1; + u8 threshold1_status:1; + u8 threshold2_status:1; + u64 rsvd3:46; /* Reserved */ + }; + }; +}; + +/* Xeon Power Limit */ +struct feature_fme_pm_xeon_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FPGA Power Limit */ +struct feature_fme_pm_fpga_limit { + union { + u64 csr; + struct { + /* Power limit in Watts in 12.3 format */ + u16 pwr_limit:15; + /* Indicates that power limit has been written */ + u8 enable:1; + /* 0 - Turbe range, 1 - Entire range */ + u8 clamping:1; + /* Time constant in XXYYY format */ + u8 time:7; + u64 rsvd:40; /* Reserved */ + }; + }; +}; + +/* FME POWER FEATURE */ +struct feature_fme_power { + struct feature_header header; + struct feature_fme_pm_status status; + struct feature_fme_pm_ap_threshold threshold; + struct feature_fme_pm_xeon_limit xeon_limit; + struct feature_fme_pm_fpga_limit fpga_limit; +}; + +#define CACHE_CHANNEL_RD 0 +#define CACHE_CHANNEL_WR 1 + +enum iperf_cache_events { + IPERF_CACHE_RD_HIT, + IPERF_CACHE_WR_HIT, + IPERF_CACHE_RD_MISS, + IPERF_CACHE_WR_MISS, + IPERF_CACHE_RSVD, /* reserved */ + IPERF_CACHE_HOLD_REQ, + IPERF_CACHE_DATA_WR_PORT_CONTEN, + IPERF_CACHE_TAG_WR_PORT_CONTEN, + IPERF_CACHE_TX_REQ_STALL, + IPERF_CACHE_RX_REQ_STALL, + IPERF_CACHE_EVICTIONS, +}; + +/* FPMON Cache Control */ +struct feature_fme_ifpmon_ch_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd1:7; /* Reserved */ + u8 freeze:1; /* Freeze if set to 1 */ + u8 rsvd2:7; /* Reserved */ + u8 cache_event:4; /* Select the cache event */ + u8 cci_chsel:1; /* Select the channel */ + u64 rsvd3:43; /* Reserved */ + }; + }; +}; + +/* FPMON Cache Counter */ +struct feature_fme_ifpmon_ch_ctr { + union { + u64 csr; + struct { + /* Cache Counter for even addresse */ + u64 cache_counter:48; + u16 rsvd:12; /* Reserved */ + /* Cache Event being reported */ + u8 event_code:4; + }; + }; +}; + +enum iperf_fab_events { + IPERF_FAB_PCIE0_RD, + IPERF_FAB_PCIE0_WR, + IPERF_FAB_PCIE1_RD, + IPERF_FAB_PCIE1_WR, + IPERF_FAB_UPI_RD, + IPERF_FAB_UPI_WR, + IPERF_FAB_MMIO_RD, + IPERF_FAB_MMIO_WR, +}; + +#define FAB_DISABLE_FILTER 0 +#define FAB_ENABLE_FILTER 1 + +/* FPMON FAB Control */ +struct feature_fme_ifpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_ifpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_ifpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +enum iperf_vtd_events { + IPERF_VTD_AFU_MEM_RD_TRANS, + IPERF_VTD_AFU_MEM_WR_TRANS, + IPERF_VTD_AFU_DEVTLB_RD_HIT, + IPERF_VTD_AFU_DEVTLB_WR_HIT, + IPERF_VTD_DEVTLB_4K_FILL, + IPERF_VTD_DEVTLB_2M_FILL, + IPERF_VTD_DEVTLB_1G_FILL, +}; + +/* VT-d control register */ +struct feature_fme_ifpmon_vtd_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d event counter */ +struct feature_fme_ifpmon_vtd_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +enum iperf_vtd_sip_events { + IPERF_VTD_SIP_IOTLB_4K_HIT, + IPERF_VTD_SIP_IOTLB_2M_HIT, + IPERF_VTD_SIP_IOTLB_1G_HIT, + IPERF_VTD_SIP_SLPWC_L3_HIT, + IPERF_VTD_SIP_SLPWC_L4_HIT, + IPERF_VTD_SIP_RCC_HIT, + IPERF_VTD_SIP_IOTLB_4K_MISS, + IPERF_VTD_SIP_IOTLB_2M_MISS, + IPERF_VTD_SIP_IOTLB_1G_MISS, + IPERF_VTD_SIP_SLPWC_L3_MISS, + IPERF_VTD_SIP_SLPWC_L4_MISS, + IPERF_VTD_SIP_RCC_MISS, +}; + +/* VT-d SIP control register */ +struct feature_fme_ifpmon_vtd_sip_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 vtd_evtcode:4; /* VTd and TLB event code */ + u64 rsvd2:44; /* Reserved */ + }; + }; +}; + +/* VT-d SIP event counter */ +struct feature_fme_ifpmon_vtd_sip_ctr { + union { + u64 csr; + struct { + u64 vtd_counter:48; /* VTd event counter */ + u16 rsvd:12; /* Reserved */ + u8 event_code:4; /* VTd event code */ + }; + }; +}; + +/* FME IPERF FEATURE */ +struct feature_fme_iperf { + struct feature_header header; + struct feature_fme_ifpmon_ch_ctl ch_ctl; + struct feature_fme_ifpmon_ch_ctr ch_ctr0; + struct feature_fme_ifpmon_ch_ctr ch_ctr1; + struct feature_fme_ifpmon_fab_ctl fab_ctl; + struct feature_fme_ifpmon_fab_ctr fab_ctr; + struct feature_fme_ifpmon_clk_ctr clk; + struct feature_fme_ifpmon_vtd_ctl vtd_ctl; + struct feature_fme_ifpmon_vtd_ctr vtd_ctr; + struct feature_fme_ifpmon_vtd_sip_ctl vtd_sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr vtd_sip_ctr; +}; + +enum dperf_fab_events { + DPERF_FAB_PCIE0_RD, + DPERF_FAB_PCIE0_WR, + DPERF_FAB_MMIO_RD = 6, + DPERF_FAB_MMIO_WR, +}; + +/* FPMON FAB Control */ +struct feature_fme_dfpmon_fab_ctl { + union { + u64 csr; + struct { + u8 reset_counters:1; /* Reset Counters */ + u8 rsvd:7; /* Reserved */ + u8 freeze:1; /* Set to 1 frozen counter */ + u8 rsvd1:7; /* Reserved */ + u8 fab_evtcode:4; /* Fabric Event Code */ + u8 port_id:2; /* Port ID */ + u8 rsvd2:1; /* Reserved */ + u8 port_filter:1; /* Port Filter */ + u64 rsvd3:40; /* Reserved */ + }; + }; +}; + +/* FPMON Event Counter */ +struct feature_fme_dfpmon_fab_ctr { + union { + u64 csr; + struct { + u64 fab_cnt:60; /* Fabric event counter */ + /* Fabric event code being reported */ + u8 event_code:4; + }; + }; +}; + +/* FPMON Clock Counter */ +struct feature_fme_dfpmon_clk_ctr { + u64 afu_interf_clock; /* Clk_16UI (AFU clock) counter. */ +}; + +/* FME DPERF FEATURE */ +struct feature_fme_dperf { + struct feature_header header; + u64 rsvd[3]; + struct feature_fme_dfpmon_fab_ctl fab_ctl; + struct feature_fme_dfpmon_fab_ctr fab_ctr; + struct feature_fme_dfpmon_clk_ctr clk; +}; + +struct feature_fme_error0 { +#define FME_ERROR0_MASK 0xFFUL +#define FME_ERROR0_MASK_DEFAULT 0x40UL /* pcode workaround */ + union { + u64 csr; + struct { + u8 fabric_err:1; /* Fabric error */ + u8 fabfifo_overflow:1; /* Fabric fifo overflow */ + u8 kticdc_parity_err:2;/* KTI CDC Parity Error */ + u8 iommu_parity_err:1; /* IOMMU Parity error */ + /* AFU PF/VF access mismatch detected */ + u8 afu_acc_mode_err:1; + u8 mbp_err:1; /* Indicates an MBP event */ + /* PCIE0 CDC Parity Error */ + u8 pcie0cdc_parity_err:5; + /* PCIE1 CDC Parity Error */ + u8 pcie1cdc_parity_err:5; + /* CVL CDC Parity Error */ + u8 cvlcdc_parity_err:3; + u64 rsvd:44; /* Reserved */ + }; + }; +}; + +/* PCIe0 Error Status register */ +struct feature_fme_pcie0_error { +#define FME_PCIE0_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:52; /* Reserved */ + u8 vfnumb_err:1; /* Number of error VF */ + u8 funct_type_err:1; /* Virtual (1) or Physical */ + }; + }; +}; + +/* PCIe1 Error Status register */ +struct feature_fme_pcie1_error { +#define FME_PCIE1_ERROR_MASK 0xFFUL + union { + u64 csr; + struct { + u8 formattype_err:1; /* TLP format/type error */ + u8 MWAddr_err:1; /* TLP MW address error */ + u8 MWAddrLength_err:1; /* TLP MW length error */ + u8 MRAddr_err:1; /* TLP MR address error */ + u8 MRAddrLength_err:1; /* TLP MR length error */ + u8 cpl_tag_err:1; /* TLP CPL tag error */ + u8 cpl_status_err:1; /* TLP CPL status error */ + u8 cpl_timeout_err:1; /* TLP CPL timeout */ + u8 cci_parity_err:1; /* CCI bridge parity error */ + u8 rxpoison_tlp_err:1; /* Received a TLP with EP set */ + u64 rsvd:54; /* Reserved */ + }; + }; +}; + +/* FME First Error register */ +struct feature_fme_first_error { +#define FME_FIRST_ERROR_MASK ((1ULL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered first + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered first + */ + u8 errReg_id:4; + }; + }; +}; + +/* FME Next Error register */ +struct feature_fme_next_error { +#define FME_NEXT_ERROR_MASK ((1ULL << 60) - 1) + union { + u64 csr; + struct { + /* + * Indicates the Error Register that was + * triggered second + */ + u64 err_reg_status:60; + /* + * Holds 60 LSBs from the Error register that was + * triggered second + */ + u8 errReg_id:4; + }; + }; +}; + +/* RAS Non Fatal Error Status register */ +struct feature_fme_ras_nonfaterror { + union { + u64 csr; + struct { + /* thremal threshold AP1 */ + u8 temp_thresh_ap1:1; + /* thremal threshold AP2 */ + u8 temp_thresh_ap2:1; + u8 pcie_error:1; /* pcie Error */ + u8 portfatal_error:1; /* port fatal error */ + u8 proc_hot:1; /* Indicates a ProcHot event */ + /* Indicates an AFU PF/VF access mismatch */ + u8 afu_acc_mode_err:1; + /* Injected nonfata Error */ + u8 injected_nonfata_err:1; + u8 rsvd1:2; + /* Temperature threshold triggered AP6*/ + u8 temp_thresh_AP6:1; + /* Power threshold triggered AP1 */ + u8 power_thresh_AP1:1; + /* Power threshold triggered AP2 */ + u8 power_thresh_AP2:1; + /* Indicates a MBP event */ + u8 mbp_err:1; + u64 rsvd2:51; /* Reserved */ + }; + }; +}; + +/* RAS Catastrophic Fatal Error Status register */ +struct feature_fme_ras_catfaterror { + union { + u64 csr; + struct { + /* KTI Link layer error detected */ + u8 ktilink_fatal_err:1; + /* tag-n-cache error detected */ + u8 tagcch_fatal_err:1; + /* CCI error detected */ + u8 cci_fatal_err:1; + /* KTI Protocol error detected */ + u8 ktiprpto_fatal_err:1; + /* Fatal DRAM error detected */ + u8 dram_fatal_err:1; + /* IOMMU detected */ + u8 iommu_fatal_err:1; + /* Fabric Fatal Error */ + u8 fabric_fatal_err:1; + /* PCIe possion Error */ + u8 pcie_poison_err:1; + /* Injected fatal Error */ + u8 inject_fata_err:1; + /* Catastrophic CRC Error */ + u8 crc_catast_err:1; + /* Catastrophic Thermal Error */ + u8 therm_catast_err:1; + /* Injected Catastrophic Error */ + u8 injected_catast_err:1; + u64 rsvd:52; + }; + }; +}; + +/* RAS Error injection register */ +struct feature_fme_ras_error_inj { +#define FME_RAS_ERROR_INJ_MASK 0x7UL + union { + u64 csr; + struct { + u8 catast_error:1; /* Catastrophic error flag */ + u8 fatal_error:1; /* Fatal error flag */ + u8 nonfatal_error:1; /* NonFatal error flag */ + u64 rsvd:61; /* Reserved */ + }; + }; +}; + +/* FME error capabilities */ +struct feature_fme_error_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* FME ERR FEATURE */ +struct feature_fme_err { + struct feature_header header; + struct feature_fme_error0 fme_err_mask; + struct feature_fme_error0 fme_err; + struct feature_fme_pcie0_error pcie0_err_mask; + struct feature_fme_pcie0_error pcie0_err; + struct feature_fme_pcie1_error pcie1_err_mask; + struct feature_fme_pcie1_error pcie1_err; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + struct feature_fme_ras_nonfaterror ras_nonfat_mask; + struct feature_fme_ras_nonfaterror ras_nonfaterr; + struct feature_fme_ras_catfaterror ras_catfat_mask; + struct feature_fme_ras_catfaterror ras_catfaterr; + struct feature_fme_ras_error_inj ras_error_inj; + struct feature_fme_error_capability fme_err_capability; +}; + +/* FME Partial Reconfiguration Control */ +struct feature_fme_pr_ctl { + union { + u64 csr; + struct { + u8 pr_reset:1; /* Reset PR Engine */ + u8 rsvd3:3; /* Reserved */ + u8 pr_reset_ack:1; /* Reset PR Engine Ack */ + u8 rsvd4:3; /* Reserved */ + u8 pr_regionid:2; /* PR Region ID */ + u8 rsvd1:2; /* Reserved */ + u8 pr_start_req:1; /* PR Start Request */ + u8 pr_push_complete:1; /* PR Data push complete */ + u8 pr_kind:1; /* PR Data push complete */ + u32 rsvd:17; /* Reserved */ + u32 config_data; /* Config data TBD */ + }; + }; +}; + +/* FME Partial Reconfiguration Status */ +struct feature_fme_pr_status { + union { + u64 csr; + struct { + u16 pr_credit:9; /* PR Credits */ + u8 rsvd2:7; /* Reserved */ + u8 pr_status:1; /* PR status */ + u8 rsvd:3; /* Reserved */ + /* Altra PR Controller Block status */ + u8 pr_controller_status:3; + u8 rsvd1:1; /* Reserved */ + u8 pr_host_status:4; /* PR Host status */ + u8 rsvd3:4; /* Reserved */ + /* Security Block Status fields (TBD) */ + u32 security_bstatus; + }; + }; +}; + +/* FME Partial Reconfiguration Data */ +struct feature_fme_pr_data { + union { + u64 csr; /* PR data from the raw-binary file */ + struct { + /* PR data from the raw-binary file */ + u32 pr_data_raw; + u32 rsvd; + }; + }; +}; + +/* FME PR Public Key */ +struct feature_fme_pr_key { + u64 key; /* FME PR Public Hash */ +}; + +/* FME PR FEATURE */ +struct feature_fme_pr { + struct feature_header header; + /*Partial Reconfiguration control */ + struct feature_fme_pr_ctl ccip_fme_pr_control; + + /* Partial Reconfiguration Status */ + struct feature_fme_pr_status ccip_fme_pr_status; + + /* Partial Reconfiguration data */ + struct feature_fme_pr_data ccip_fme_pr_data; + + /* Partial Reconfiguration data */ + u64 ccip_fme_pr_err; + + u64 rsvd1[3]; + + /* Partial Reconfiguration data registers */ + u64 fme_pr_data1; + u64 fme_pr_data2; + u64 fme_pr_data3; + u64 fme_pr_data4; + u64 fme_pr_data5; + u64 fme_pr_data6; + u64 fme_pr_data7; + u64 fme_pr_data8; + + u64 rsvd2[5]; + + /* PR Interface ID */ + u64 fme_pr_intfc_id_l; + u64 fme_pr_intfc_id_h; + + /* MSIX filed to be Added */ +}; + +/* FME HSSI Control */ +struct feature_fme_hssi_eth_ctrl { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u16 address:16; /* HSSI address */ + /* + * HSSI comamnd + * 0x0 - No request + * 0x08 - SW register RD request + * 0x10 - SW register WR request + * 0x40 - Auxiliar bus RD request + * 0x80 - Auxiliar bus WR request + */ + u16 cmd:16; + }; + }; +}; + +/* FME HSSI Status */ +struct feature_fme_hssi_eth_stat { + union { + u64 csr; + struct { + u32 data:32; /* HSSI data */ + u8 acknowledge:1; /* HSSI acknowledge */ + u8 spare:1; /* HSSI spare */ + u32 rsvd:30; /* Reserved */ + }; + }; +}; + +/* FME HSSI FEATURE */ +struct feature_fme_hssi { + struct feature_header header; + struct feature_fme_hssi_eth_ctrl hssi_control; + struct feature_fme_hssi_eth_stat hssi_status; +}; + +#define PORT_ERR_MASK 0xfff0703ff001f +struct feature_port_err_key { + union { + u64 csr; + struct { + /* Tx Channel0: Overflow */ + u8 tx_ch0_overflow:1; + /* Tx Channel0: Invalid request encoding */ + u8 tx_ch0_invaldreq :1; + /* Tx Channel0: Request with cl_len=3 not supported */ + u8 tx_ch0_cl_len3:1; + /* Tx Channel0: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch0_cl_len2:1; + /* Tx Channel0: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch0_cl_len4:1; + + u16 rsvd1:4; /* Reserved */ + + /* AFU MMIO RD received while PORT is in reset */ + u8 mmio_rd_whilerst:1; + /* AFU MMIO WR received while PORT is in reset */ + u8 mmio_wr_whilerst:1; + + u16 rsvd2:5; /* Reserved */ + + /* Tx Channel1: Overflow */ + u8 tx_ch1_overflow:1; + /* Tx Channel1: Invalid request encoding */ + u8 tx_ch1_invaldreq:1; + /* Tx Channel1: Request with cl_len=3 not supported */ + u8 tx_ch1_cl_len3:1; + /* Tx Channel1: Request with cl_len=2 not aligned 2CL */ + u8 tx_ch1_cl_len2:1; + /* Tx Channel1: Request with cl_len=4 not aligned 4CL */ + u8 tx_ch1_cl_len4:1; + + /* Tx Channel1: Insufficient data payload */ + u8 tx_ch1_insuff_data:1; + /* Tx Channel1: Data payload overrun */ + u8 tx_ch1_data_overrun:1; + /* Tx Channel1 : Incorrect address */ + u8 tx_ch1_incorr_addr:1; + /* Tx Channel1 : NON-Zero SOP Detected */ + u8 tx_ch1_nzsop:1; + /* Tx Channel1 : Illegal VC_SEL, atomic request VLO */ + u8 tx_ch1_illegal_vcsel:1; + + u8 rsvd3:6; /* Reserved */ + + /* MMIO Read Timeout in AFU */ + u8 mmioread_timeout:1; + + /* Tx Channel2: FIFO Overflow */ + u8 tx_ch2_fifo_overflow:1; + + /* MMIO read is not matching pending request */ + u8 unexp_mmio_resp:1; + + u8 rsvd4:5; /* Reserved */ + + /* Number of pending Requests: counter overflow */ + u8 tx_req_counter_overflow:1; + /* Req with Address violating SMM Range */ + u8 llpr_smrr_err:1; + /* Req with Address violating second SMM Range */ + u8 llpr_smrr2_err:1; + /* Req with Address violating ME Stolen message */ + u8 llpr_mesg_err:1; + /* Req with Address violating Generic Protected Range */ + u8 genprot_range_err:1; + /* Req with Address violating Legacy Range low */ + u8 legrange_low_err:1; + /* Req with Address violating Legacy Range High */ + u8 legrange_high_err:1; + /* Req with Address violating VGA memory range */ + u8 vgmem_range_err:1; + u8 page_fault_err:1; /* Page fault */ + u8 pmr_err:1; /* PMR Error */ + u8 ap6_event:1; /* AP6 event */ + /* VF FLR detected on Port with PF access control */ + u8 vfflr_access_err:1; + u16 rsvd5:12; /* Reserved */ + }; + }; +}; + +/* Port first error register, not contain all error bits in error register. */ +struct feature_port_first_err_key { + union { + u64 csr; + struct { + u8 tx_ch0_overflow:1; + u8 tx_ch0_invaldreq :1; + u8 tx_ch0_cl_len3:1; + u8 tx_ch0_cl_len2:1; + u8 tx_ch0_cl_len4:1; + u8 rsvd1:4; /* Reserved */ + u8 mmio_rd_whilerst:1; + u8 mmio_wr_whilerst:1; + u8 rsvd2:5; /* Reserved */ + u8 tx_ch1_overflow:1; + u8 tx_ch1_invaldreq:1; + u8 tx_ch1_cl_len3:1; + u8 tx_ch1_cl_len2:1; + u8 tx_ch1_cl_len4:1; + u8 tx_ch1_insuff_data:1; + u8 tx_ch1_data_overrun:1; + u8 tx_ch1_incorr_addr:1; + u8 tx_ch1_nzsop:1; + u8 tx_ch1_illegal_vcsel:1; + u8 rsvd3:6; /* Reserved */ + u8 mmioread_timeout:1; + u8 tx_ch2_fifo_overflow:1; + u8 rsvd4:6; /* Reserved */ + u8 tx_req_counter_overflow:1; + u32 rsvd5:23; /* Reserved */ + }; + }; +}; + +/* Port malformed Req0 */ +struct feature_port_malformed_req0 { + u64 header_lsb; +}; + +/* Port malformed Req1 */ +struct feature_port_malformed_req1 { + u64 header_msb; +}; + +/* Port debug register */ +struct feature_port_debug { + u64 port_debug; +}; + +/* Port error capabilities */ +struct feature_port_err_capability { + union { + u64 csr; + struct { + u8 support_intr:1; + /* MSI-X vector table entry number */ + u16 intr_vector_num:12; + u64 rsvd:51; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE ERROR */ +struct feature_port_error { + struct feature_header header; + struct feature_port_err_key error_mask; + struct feature_port_err_key port_error; + struct feature_port_first_err_key port_first_error; + struct feature_port_malformed_req0 malreq0; + struct feature_port_malformed_req1 malreq1; + struct feature_port_debug port_debug; + struct feature_port_err_capability error_capability; +}; + +/* Port UMSG Capability */ +struct feature_port_umsg_cap { + union { + u64 csr; + struct { + /* Number of umsg allocated to this port */ + u8 umsg_allocated; + /* Enable / Disable UMsg engine for this port */ + u8 umsg_enable:1; + /* Usmg initialization status */ + u8 umsg_init_complete:1; + /* IOMMU can not translate the umsg base address */ + u8 umsg_trans_error:1; + u64 rsvd:53; /* Reserved */ + }; + }; +}; + +/* Port UMSG base address */ +struct feature_port_umsg_baseaddr { + union { + u64 csr; + struct { + u64 base_addr:48; /* 48 bit physical address */ + u16 rsvd; /* Reserved */ + }; + }; +}; + +struct feature_port_umsg_mode { + union { + u64 csr; + struct { + u32 umsg_hint_enable; /* UMSG hint enable/disable */ + u32 rsvd; /* Reserved */ + }; + }; +}; + +/* PORT FEATURE UMSG */ +struct feature_port_umsg { + struct feature_header header; + struct feature_port_umsg_cap capability; + struct feature_port_umsg_baseaddr baseaddr; + struct feature_port_umsg_mode mode; +}; + +#define UMSG_EN_POLL_INVL 10 /* us */ +#define UMSG_EN_POLL_TIMEOUT 1000 /* us */ + +/* Port UINT Capability */ +struct feature_port_uint_cap { + union { + u64 csr; + struct { + u16 intr_num:12; /* Supported interrupts num */ + /* First MSI-X vector table entry number */ + u16 first_vec_num:12; + u64 rsvd:40; + }; + }; +}; + +/* PORT FEATURE UINT */ +struct feature_port_uint { + struct feature_header header; + struct feature_port_uint_cap capability; +}; + +/* STP region supports mmap operation, so use page aligned size. */ +#define PORT_FEATURE_STP_REGION_SIZE \ + IFPGA_PAGE_ALIGN(sizeof(struct feature_port_stp)) + +/* Port STP status register (for debug only)*/ +struct feature_port_stp_status { + union { + u64 csr; + struct { + /* SLD Hub end-point read/write timeout */ + u8 sld_ep_timeout:1; + /* Remote STP in reset/disable */ + u8 rstp_disabled:1; + u8 unsupported_read:1; + /* MMIO timeout detected and faked with a response */ + u8 mmio_timeout:1; + u8 txfifo_count:4; + u8 rxfifo_count:4; + u8 txfifo_overflow:1; + u8 txfifo_underflow:1; + u8 rxfifo_overflow:1; + u8 rxfifo_underflow:1; + /* Number of MMIO write requests */ + u16 write_requests; + /* Number of MMIO read requests */ + u16 read_requests; + /* Number of MMIO read responses */ + u16 read_responses; + }; + }; +}; + +/* + * PORT FEATURE STP + * Most registers in STP region are not touched by driver, but mmapped to user + * space. So they are not defined in below data structure, as its actual size + * is 0x18c per spec. + */ +struct feature_port_stp { + struct feature_header header; + struct feature_port_stp_status stp_status; +}; + +/** + * enum fpga_pr_states - fpga PR states + * @FPGA_PR_STATE_UNKNOWN: can't determine state + * @FPGA_PR_STATE_WRITE_INIT: preparing FPGA for programming + * @FPGA_PR_STATE_WRITE_INIT_ERR: Error during WRITE_INIT stage + * @FPGA_PR_STATE_WRITE: writing image to FPGA + * @FPGA_PR_STATE_WRITE_ERR: Error while writing FPGA + * @FPGA_PR_STATE_WRITE_COMPLETE: Doing post programming steps + * @FPGA_PR_STATE_WRITE_COMPLETE_ERR: Error during WRITE_COMPLETE + * @FPGA_PR_STATE_OPERATING: FPGA PR done + */ +enum fpga_pr_states { + /* canot determine state states */ + FPGA_PR_STATE_UNKNOWN, + + /* write sequence: init, write, complete */ + FPGA_PR_STATE_WRITE_INIT, + FPGA_PR_STATE_WRITE_INIT_ERR, + FPGA_PR_STATE_WRITE, + FPGA_PR_STATE_WRITE_ERR, + FPGA_PR_STATE_WRITE_COMPLETE, + FPGA_PR_STATE_WRITE_COMPLETE_ERR, + + /* FPGA PR done */ + FPGA_PR_STATE_DONE, +}; + +/* + * FPGA Manager flags + * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported + */ +#define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + +/** + * struct fpga_pr_info - specific information to a FPGA PR + * @flags: boolean flags as defined above + * @pr_err: PR error code + * @state: fpga manager state + * @port_id: port id + */ +struct fpga_pr_info { + u32 flags; + u64 pr_err; + enum fpga_pr_states state; + int port_id; +}; + +#define DEFINE_FPGA_PR_ERR_MSG(_name_) \ +static const char * const _name_[] = { \ + "PR operation error detected", \ + "PR CRC error detected", \ + "PR incompatiable bitstream error detected", \ + "PR IP protocol error detected", \ + "PR FIFO overflow error detected", \ + "PR timeout error detected", \ + "PR secure load error detected", \ +} + +#define RST_POLL_INVL 10 /* us */ +#define RST_POLL_TIMEOUT 1000 /* us */ + +#define PR_WAIT_TIMEOUT 15000000 + +#define PR_HOST_STATUS_IDLE 0 +#define PR_MAX_ERR_NUM 7 + +DEFINE_FPGA_PR_ERR_MSG(pr_err_msg); + +/* + * green bitstream header must be byte-packed to match the + * real file format. + */ +struct bts_header { + u64 guid_h; + u64 guid_l; + u32 metadata_len; +}; + +#define GBS_GUID_H 0x414750466e6f6558 +#define GBS_GUID_L 0x31303076534247b7 +#define is_valid_bts(bts_hdr) \ + (((bts_hdr)->guid_h == GBS_GUID_H) && \ + ((bts_hdr)->guid_l == GBS_GUID_L)) + +#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 new file mode 100644 index 0000000..f0939dc --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.c @@ -0,0 +1,821 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_hw_api.h" +#include "ifpga_api.h" + +#include "ifpga_hw.h" +#include "ifpga_enumerate.h" +#include "ifpga_feature_dev.h" + +struct build_feature_devs_info { + struct opae_adapter_data_pci *pci_data; + + struct ifpga_afu_info *acc_info; + + void *fiu; + enum fpga_id_type current_type; + int current_port_id; + + void *ioaddr; + void *ioend; + uint64_t phys_addr; + int current_bar; + + void *pfme_hdr; + + 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; +}; + +/* 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, + } +}; + +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 = &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 = &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 = &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 = &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 + }, +}; + +static u64 feature_id(void __iomem *start) +{ + struct feature_header header; + + header.csr = readq(start); + + switch (header.type) { + case FEATURE_TYPE_FIU: + return FEATURE_ID_HEADER; + case FEATURE_TYPE_PRIVATE: + return header.id; + case FEATURE_TYPE_AFU: + return FEATURE_ID_AFU; + } + + WARN_ON(1); + return 0; +} + +static int +build_info_add_sub_feature(struct build_feature_devs_info *binfo, + struct feature_info *finfo, void __iomem *start) +{ + 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; + } + + 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->phys_addr = binfo->phys_addr + + ((u8 *)start - (u8 *)binfo->ioaddr); + + if (vec_cnt) { + if (vec_start + vec_cnt <= vec_start) + return -EINVAL; + + ctx = zmalloc(sizeof(*ctx) * vec_cnt); + if (!ctx) + return -ENOMEM; + + for (i = 0; i < vec_cnt; i++) { + ctx[i].eventfd = -1; + ctx[i].idx = vec_start + i; + } + } + + feature->ctx = ctx; + feature->ctx_num = vec_cnt; + feature->vfio_dev_fd = binfo->pci_data->vfio_dev_fd; + + return ret; +} + +static int +create_feature_instance(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + 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); +} + +/* + * UAFU GUID is dynamic as it can be changed after FME downloads different + * Green Bitstream to the port, so we treat the unknown GUIDs which are + * attached on port's feature list as UAFU. + */ +static bool feature_is_UAFU(struct build_feature_devs_info *binfo) +{ + if (binfo->current_type != PORT_ID) + return false; + + return true; +} + +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; + struct ifpga_afu_info *info; + void *start = (void *)hdr; + int ret; + + 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; + } + + if (ret) + return ret; + + /* FIXME: need to figure out a better name */ + info = 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->num_regions = 1; + + binfo->acc_info = info; + + return ret; +} + +static int parse_feature_afus(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + int ret; + struct feature_afu_header *afu_hdr, header; + u8 __iomem *start; + u8 __iomem *end = binfo->ioend; + + start = (u8 __iomem *)hdr; + for (; start < end; start += header.next_afu) { + if ((unsigned int)(end - start) < + (unsigned int)(sizeof(*afu_hdr) + sizeof(*hdr))) + return -EINVAL; + + hdr = (struct feature_header *)start; + afu_hdr = (struct feature_afu_header *)(hdr + 1); + header.csr = readq(&afu_hdr->csr); + + if (feature_is_UAFU(binfo)) { + ret = parse_feature_port_uafu(binfo, hdr); + if (ret) + return ret; + } + + if (!header.next_afu) + break; + } + + return 0; +} + +/* create and register proper private data */ +static int build_info_commit_dev(struct build_feature_devs_info *binfo) +{ + struct ifpga_afu_info *info = binfo->acc_info; + struct ifpga_hw *hw = binfo->hw; + struct opae_manager *mgr; + struct opae_bridge *br; + struct opae_accelerator *acc; + + if (!binfo->fiu) + return 0; + + if (binfo->current_type == PORT_ID) { + /* return error if no valid acc info data structure */ + if (!info) + return -EFAULT; + + br = opae_bridge_alloc(hw->adapter->name, &ifpga_br_ops, + binfo->fiu); + if (!br) + return -ENOMEM; + + br->id = binfo->current_port_id; + + /* update irq info */ + info->num_irqs = port_features[PORT_FEATURE_ID_UINT].vec_cnt; + + acc = opae_accelerator_alloc(hw->adapter->name, + &ifpga_acc_ops, info); + if (!acc) { + opae_bridge_free(br); + return -ENOMEM; + } + + acc->br = br; + acc->index = br->id; + + opae_adapter_add_acc(hw->adapter, acc); + + } else if (binfo->current_type == FME_ID) { + mgr = opae_manager_alloc(hw->adapter->name, &ifpga_mgr_ops, + binfo->fiu); + if (!mgr) + return -ENOMEM; + + mgr->adapter = hw->adapter; + hw->adapter->mgr = mgr; + } + + binfo->fiu = NULL; + + return 0; +} + +static int +build_info_create_dev(struct build_feature_devs_info *binfo, + enum fpga_id_type type, unsigned int index) +{ + int ret; + + ret = build_info_commit_dev(binfo); + if (ret) + return ret; + + binfo->current_type = type; + + if (type == FME_ID) { + binfo->fiu = &binfo->hw->fme; + } else if (type == PORT_ID) { + binfo->fiu = &binfo->hw->port[index]; + binfo->current_port_id = index; + } + + return 0; +} + +static int parse_feature_fme(struct build_feature_devs_info *binfo, + struct feature_header *start) +{ + struct ifpga_hw *hw = binfo->hw; + struct ifpga_fme_hw *fme = &hw->fme; + int ret; + + ret = build_info_create_dev(binfo, FME_ID, 0); + if (ret) + return ret; + + /* Update FME states */ + fme->state = IFPGA_FME_IMPLEMENTED; + fme->parent = hw; + spinlock_init(&fme->lock); + + return create_feature_instance(binfo, start, + &fme_features[FME_FEATURE_ID_HEADER]); +} + +static int parse_feature_port(struct build_feature_devs_info *binfo, + void __iomem *start) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + struct ifpga_hw *hw = binfo->hw; + struct ifpga_port_hw *port; + unsigned int port_id; + int ret; + + /* Get current port's id */ + port_hdr = (struct feature_port_header *)start; + capability.csr = readq(&port_hdr->capability); + port_id = capability.port_number; + + ret = build_info_create_dev(binfo, PORT_ID, port_id); + if (ret) + return ret; + + /*found a Port device*/ + port = &hw->port[port_id]; + port->port_id = binfo->current_port_id; + port->parent = hw; + port->state = IFPGA_PORT_ATTACHED; + spinlock_init(&port->lock); + + return create_feature_instance(binfo, start, + &port_features[PORT_FEATURE_ID_HEADER]); +} + +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); +} + +static int parse_feature_fiu(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + struct feature_fiu_header *fiu_hdr, fiu_header; + u8 __iomem *start = (u8 __iomem *)hdr; + int ret; + + header.csr = readq(hdr); + + switch (header.id) { + case FEATURE_FIU_ID_FME: + ret = parse_feature_fme(binfo, hdr); + binfo->pfme_hdr = hdr; + if (ret) + return ret; + break; + case FEATURE_FIU_ID_PORT: + ret = parse_feature_port(binfo, hdr); + enable_port_uafu(binfo, hdr); + if (ret) + return ret; + + /* Check Port FIU's next_afu pointer to User AFU DFH */ + fiu_hdr = (struct feature_fiu_header *)(hdr + 1); + fiu_header.csr = readq(&fiu_hdr->csr); + + if (fiu_header.next_afu) { + start += fiu_header.next_afu; + ret = parse_feature_afus(binfo, + (struct feature_header *)start); + if (ret) + return ret; + } else { + dev_info(binfo, "No AFUs detected on Port\n"); + } + + break; + default: + dev_info(binfo, "FIU TYPE %d is not supported yet.\n", + header.id); + } + + return 0; +} + +static void parse_feature_irqs(struct build_feature_devs_info *binfo, + void __iomem *start, struct feature_info *finfo) +{ + finfo->vec_start = 0; + finfo->vec_cnt = 0; + + UNUSED(binfo); + + if (!strcmp(finfo->name, PORT_FEATURE_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; + } else { + dev_debug(binfo, "UAFU doesn't support interrupt\n"); + } + } else if (!strcmp(finfo->name, PORT_FEATURE_ERR)) { + 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; + } else { + dev_debug(&binfo, "Port error doesn't support interrupt\n"); + } + + } else if (!strcmp(finfo->name, FME_FEATURE_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; + } else { + dev_debug(&binfo, "FME error doesn't support interrupt\n"); + } + } +} + +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; + } + + parse_feature_irqs(binfo, hdr, &fme_features[header.id]); + + return create_feature_instance(binfo, hdr, &fme_features[header.id]); +} + +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; + + 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]); + + return create_feature_instance(binfo, hdr, &port_features[id]); +} + +static int parse_feature_private(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + + header.csr = readq(hdr); + + switch (binfo->current_type) { + case FME_ID: + return parse_feature_fme_private(binfo, hdr); + case PORT_ID: + return parse_feature_port_private(binfo, hdr); + default: + dev_err(binfo, "private feature %x belonging to AFU %d (unknown_type) is not supported yet.\n", + header.id, binfo->current_type); + } + return 0; +} + +static int parse_feature(struct build_feature_devs_info *binfo, + struct feature_header *hdr) +{ + struct feature_header header; + int ret = 0; + + header.csr = readq(hdr); + + switch (header.type) { + case FEATURE_TYPE_AFU: + ret = parse_feature_afus(binfo, hdr); + break; + case FEATURE_TYPE_PRIVATE: + ret = parse_feature_private(binfo, hdr); + break; + case FEATURE_TYPE_FIU: + ret = parse_feature_fiu(binfo, hdr); + break; + default: + dev_err(binfo, "Feature Type %x is not supported.\n", + hdr->type); + }; + + return ret; +} + +static int +parse_feature_list(struct build_feature_devs_info *binfo, u8 __iomem *start) +{ + struct feature_header *hdr, header; + u8 __iomem *end = (u8 __iomem *)binfo->ioend; + int ret = 0; + + for (; start < end; start += header.next_header_offset) { + if ((unsigned int)(end - start) < (unsigned int)sizeof(*hdr)) { + dev_err(binfo, "The region is too small to contain a feature.\n"); + ret = -EINVAL; + break; + } + + hdr = (struct feature_header *)start; + ret = parse_feature(binfo, hdr); + if (ret) + return ret; + + header.csr = readq(hdr); + if (!header.next_header_offset) + break; + } + + return build_info_commit_dev(binfo); +} + +/* switch the memory mapping to BAR# @bar */ +static int parse_switch_to(struct build_feature_devs_info *binfo, int bar) +{ + struct opae_adapter_data_pci *pci_data = binfo->pci_data; + + if (!pci_data->region[bar].addr) + return -ENOMEM; + + binfo->ioaddr = pci_data->region[bar].addr; + binfo->ioend = (u8 __iomem *)binfo->ioaddr + pci_data->region[bar].len; + binfo->phys_addr = pci_data->region[bar].phys_addr; + binfo->current_bar = bar; + + return 0; +} + +static int parse_ports_from_fme(struct build_feature_devs_info *binfo) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_port port; + int i = 0, ret = 0; + + if (!binfo->pfme_hdr) { + dev_info(binfo, "VF is detected.\n"); + return ret; + } + + fme_hdr = binfo->pfme_hdr; + + do { + port.csr = readq(&fme_hdr->port[i]); + if (!port.port_implemented) + break; + + /* skip port which only could be accessed via VF */ + if (port.afu_access_control == FME_AFU_ACCESS_VF) + continue; + + ret = parse_switch_to(binfo, port.port_bar); + if (ret) + break; + + ret = parse_feature_list(binfo, + (u8 __iomem *)binfo->ioaddr + + port.port_offset); + if (ret) + break; + } while (++i < MAX_FPGA_PORT_NUM); + + return ret; +} + +static struct build_feature_devs_info * +build_info_alloc_and_init(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + + binfo = zmalloc(sizeof(*binfo)); + if (!binfo) + return binfo; + + binfo->hw = hw; + binfo->pci_data = hw->pci_data; + + /* fpga feature list starts from BAR 0 */ + if (parse_switch_to(binfo, 0)) { + free(binfo); + return NULL; + } + + return binfo; +} + +static void build_info_free(struct build_feature_devs_info *binfo) +{ + free(binfo); +} + +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; + + 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]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%p - 0x%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++) { + port = &hw->port[i]; + + if (port->state != IFPGA_PORT_ATTACHED) + continue; + + dev_info(hw, "port device: %d\n", port->port_id); + + for (j = 0; j < PORT_FEATURE_ID_MAX; j++) { + feature = &port->sub_feature[j]; + if (feature->state != IFPGA_FEATURE_ATTACHED) + continue; + + dev_info(hw, "%12s: 0x%p - 0x%p - paddr:0x%lx\n", + feature->name, + feature->addr, + feature->addr + + feature->size - 1, + (unsigned long)feature->phys_addr); + } + } +} + +int ifpga_bus_enumerate(struct ifpga_hw *hw) +{ + struct build_feature_devs_info *binfo; + int ret; + + binfo = build_info_alloc_and_init(hw); + if (!binfo) + return -ENOMEM; + + ret = parse_feature_list(binfo, binfo->ioaddr); + if (ret) + goto exit; + + ret = parse_ports_from_fme(binfo); + if (ret) + goto exit; + + ifpga_print_device_feature_list(hw); + +exit: + build_info_free(binfo); + return ret; +} + +int ifpga_bus_init(struct ifpga_hw *hw) +{ + int i; + + fme_hw_init(&hw->fme); + for (i = 0; i < MAX_FPGA_PORT_NUM; i++) + port_hw_init(&hw->port[i]); + + return 0; +} diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h new file mode 100644 index 0000000..14131e3 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_enumerate.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_ENUMERATE_H_ +#define _IFPGA_ENUMERATE_H_ + +int ifpga_bus_init(struct ifpga_hw *hw); +int ifpga_bus_enumerate(struct ifpga_hw *hw); + +#endif /* _IFPGA_ENUMERATE_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c new file mode 100644 index 0000000..be7ac9e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.c @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <sys/ioctl.h> + +#include "ifpga_feature_dev.h" + +/* + * Enable Port by clear the port soft reset bit, which is set by default. + * The AFU is unable to respond to any MMIO access while in reset. + * __fpga_port_enable function should only be used after __fpga_port_disable + * function. + */ +void __fpga_port_enable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + WARN_ON(!port->disable_count); + + if (--port->disable_count != 0) + return; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x0; + writeq(control.csr, &port_hdr->control); +} + +int __fpga_port_disable(struct ifpga_port_hw *port) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + if (port->disable_count++ != 0) + return 0; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + WARN_ON(!port_hdr); + + /* Set port soft reset */ + control.csr = readq(&port_hdr->control); + control.port_sftrst = 0x1; + writeq(control.csr, &port_hdr->control); + + /* + * HW sets ack bit to 1 when all outstanding requests have been drained + * on this port and minimum soft reset pulse width has elapsed. + * Driver polls port_soft_reset_ack to determine if reset done by HW. + */ + control.port_sftrst_ack = 1; + + if (fpga_wait_register_field(port_sftrst_ack, control, + &port_hdr->control, RST_POLL_TIMEOUT, + RST_POLL_INVL)) { + dev_err(port, "timeout, fail to reset device\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) +{ + struct feature_port_header *port_hdr; + u64 guidl, guidh; + + port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU); + + spinlock_lock(&port->lock); + guidl = readq(&port_hdr->afu_header.guid.b[0]); + 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)); + + return 0; +} + +/* Mask / Unmask Port Errors by the Error Mask register. */ +void port_err_mask(struct ifpga_port_hw *port, bool mask) +{ + struct feature_port_error *port_err; + struct feature_port_err_key err_mask; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + if (mask) + err_mask.csr = PORT_ERR_MASK; + else + err_mask.csr = 0; + + writeq(err_mask.csr, &port_err->error_mask); +} + +/* Clear All Port Errors. */ +int port_err_clear(struct ifpga_port_hw *port, u64 err) +{ + struct feature_port_header *port_hdr; + struct feature_port_error *port_err; + struct feature_port_err_key mask; + struct feature_port_first_err_key first; + struct feature_port_status status; + int ret = 0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + /* + * Clear All Port Errors + * + * - Check for AP6 State + * - Halt Port by keeping Port in reset + * - Set PORT Error mask to all 1 to mask errors + * - Clear all errors + * - Set Port mask to all 0 to enable errors + * - All errors start capturing new errors + * - Enable Port by pulling the port out of reset + */ + + /* If device is still in AP6 state, can not clear any error.*/ + status.csr = readq(&port_hdr->status); + if (status.power_state == PORT_POWER_STATE_AP6) { + dev_err(dev, "Could not clear errors, device in AP6 state.\n"); + return -EBUSY; + } + + /* Halt Port by keeping Port in reset */ + ret = __fpga_port_disable(port); + if (ret) + return ret; + + /* Mask all errors */ + port_err_mask(port, true); + + /* Clear errors if err input matches with current port errors.*/ + mask.csr = readq(&port_err->port_error); + + if (mask.csr == err) { + writeq(mask.csr, &port_err->port_error); + + first.csr = readq(&port_err->port_first_error); + writeq(first.csr, &port_err->port_first_error); + } else { + ret = -EBUSY; + } + + /* Clear mask */ + port_err_mask(port, false); + + /* Enable the Port by clear the reset */ + __fpga_port_enable(port); + + return ret; +} + +int port_clear_error(struct ifpga_port_hw *port) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + + dev_info(port, "read port error: 0x%lx\n", (unsigned long)error.csr); + + return port_err_clear(port, error.csr); +} + +void fme_hw_uinit(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return; + + 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); + } +} + +int fme_hw_init(struct ifpga_fme_hw *fme) +{ + struct feature *feature; + int i, ret; + + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + 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; + } + } + } + + return 0; +} + +void port_hw_uinit(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i; + + 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); + } +} + +int port_hw_init(struct ifpga_port_hw *port) +{ + struct feature *feature; + int i, 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; + } + } + } + + return 0; +} + diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h new file mode 100644 index 0000000..cd114fb --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_FEATURE_DEV_H_ +#define _IFPGA_FEATURE_DEV_H_ + +#include "ifpga_hw.h" + +static inline struct ifpga_port_hw * +get_port(struct ifpga_hw *hw, u32 port_id) +{ + if (!is_valid_port_id(hw, port_id)) + return NULL; + + return &hw->port[port_id]; +} + +#define ifpga_for_each_feature(hw, feature) \ + for ((feature) = (hw)->sub_feature; \ + (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++) + +static inline struct feature * +get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(fme, feature) { + if (feature->id == id) + return feature; + } + + return NULL; +} + +static inline struct feature * +get_port_feature_by_id(struct ifpga_port_hw *port, u64 id) +{ + struct feature *feature; + + ifpga_for_each_feature(port, feature) { + 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; +} + +static inline void * +get_port_feature_ioaddr_by_index(struct ifpga_port_hw *port, int index) +{ + return port->sub_feature[index].addr; +} + +static inline bool +is_fme_feature_present(struct ifpga_fme_hw *fme, int index) +{ + return !!get_fme_feature_ioaddr_by_index(fme, index); +} + +static inline bool +is_port_feature_present(struct ifpga_port_hw *port, int index) +{ + return !!get_port_feature_ioaddr_by_index(port, index); +} + +int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid); + +int __fpga_port_disable(struct ifpga_port_hw *port); +void __fpga_port_enable(struct ifpga_port_hw *port); + +static inline int fpga_port_disable(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_disable(port); + spinlock_unlock(&port->lock); + return ret; +} + +static inline int fpga_port_enable(struct ifpga_port_hw *port) +{ + spinlock_lock(&port->lock); + __fpga_port_enable(port); + spinlock_unlock(&port->lock); + + return 0; +} + +static inline int __fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + ret = __fpga_port_disable(port); + if (ret) + return ret; + + __fpga_port_enable(port); + + return 0; +} + +static inline int fpga_port_reset(struct ifpga_port_hw *port) +{ + int ret; + + spinlock_lock(&port->lock); + ret = __fpga_port_reset(port); + spinlock_unlock(&port->lock); + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status); + +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); +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set); + +int fme_hw_init(struct ifpga_fme_hw *fme); +void fme_hw_uinit(struct ifpga_fme_hw *fme); +void port_hw_uinit(struct ifpga_port_hw *port); +int port_hw_init(struct ifpga_port_hw *port); +int port_clear_error(struct ifpga_port_hw *port); +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; + +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); + +/* This struct is used when parsing uafu irq_set */ +struct fpga_uafu_irq_set { + u32 start; + u32 count; + s32 *evtfds; +}; + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set); + +extern struct feature_ops port_hdr_ops; +extern struct feature_ops port_error_ops; +extern struct feature_ops port_stp_ops; +extern struct feature_ops port_uint_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 new file mode 100644 index 0000000..4be60c0 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme.c @@ -0,0 +1,734 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PWR_THRESHOLD_MAX 0x7F + +int fme_get_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_prop(struct ifpga_fme_hw *fme, struct feature_prop *prop) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int fme_set_irq(struct ifpga_fme_hw *fme, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!fme) + return -ENOENT; + + feature = get_fme_feature_by_id(fme, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +/* fme private feature head */ +static int fme_hdr_init(struct feature *feature) +{ + struct feature_fme_header *fme_hdr; + + fme_hdr = (struct feature_fme_header *)feature->addr; + + dev_info(NULL, "FME HDR Init.\n"); + dev_info(NULL, "FME cap %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + return 0; +} + +static void fme_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME HDR UInit.\n"); +} + +static int fme_hdr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&fme_hdr->header); + *revision = header.revision; + + return 0; +} + +static int fme_hdr_get_ports_num(struct ifpga_fme_hw *fme, u64 *ports_num) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *ports_num = fme_capability.num_ports; + + return 0; +} + +static int fme_hdr_get_cache_size(struct ifpga_fme_hw *fme, u64 *cache_size) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *cache_size = fme_capability.cache_size; + + return 0; +} + +static int fme_hdr_get_version(struct ifpga_fme_hw *fme, u64 *version) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *version = fme_capability.fabric_verid; + + return 0; +} + +static int fme_hdr_get_socket_id(struct ifpga_fme_hw *fme, u64 *socket_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + struct feature_fme_capability fme_capability; + + fme_capability.csr = readq(&fme_hdr->capability); + *socket_id = fme_capability.socket_id; + + return 0; +} + +static int fme_hdr_get_bitstream_id(struct ifpga_fme_hw *fme, + u64 *bitstream_id) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_id = readq(&fme_hdr->bitstream_id); + + return 0; +} + +static int fme_hdr_get_bitstream_metadata(struct ifpga_fme_hw *fme, + u64 *bitstream_metadata) +{ + struct feature_fme_header *fme_hdr + = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + *bitstream_metadata = readq(&fme_hdr->bitstream_md); + + return 0; +} + +static int +fme_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_HDR_PROP_REVISION: + return fme_hdr_get_revision(fme, &prop->data); + case FME_HDR_PROP_PORTS_NUM: + return fme_hdr_get_ports_num(fme, &prop->data); + case FME_HDR_PROP_CACHE_SIZE: + return fme_hdr_get_cache_size(fme, &prop->data); + case FME_HDR_PROP_VERSION: + return fme_hdr_get_version(fme, &prop->data); + case FME_HDR_PROP_SOCKET_ID: + return fme_hdr_get_socket_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_ID: + return fme_hdr_get_bitstream_id(fme, &prop->data); + case FME_HDR_PROP_BITSTREAM_METADATA: + return fme_hdr_get_bitstream_metadata(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_hdr_ops = { + .init = fme_hdr_init, + .uinit = fme_hdr_uinit, + .get_prop = fme_hdr_get_prop, +}; + +/* thermal management */ +static int fme_thermal_get_threshold1(struct ifpga_fme_hw *fme, u64 *thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1 = temp_threshold.tmp_thshold1; + + return 0; +} + +static int fme_thermal_set_threshold1(struct ifpga_fme_hw *fme, u64 thres1) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres1 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres1 == 0) { + tmp_threshold.tmp_thshold1_enable = 0; + tmp_threshold.tmp_thshold1 = thres1; + } else { + tmp_threshold.tmp_thshold1_enable = 1; + tmp_threshold.tmp_thshold1 = thres1; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold2(struct ifpga_fme_hw *fme, u64 *thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres2 = temp_threshold.tmp_thshold2; + + return 0; +} + +static int fme_thermal_set_threshold2(struct ifpga_fme_hw *fme, u64 thres2) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_header *fme_hdr; + struct feature_fme_tmp_threshold tmp_threshold; + struct feature_fme_capability fme_capability; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + fme_capability.csr = readq(&fme_hdr->capability); + + if (fme_capability.lock_bit == 1) { + spinlock_unlock(&fme->lock); + return -EBUSY; + } else if (thres2 > 100) { + spinlock_unlock(&fme->lock); + return -EINVAL; + } else if (thres2 == 0) { + tmp_threshold.tmp_thshold2_enable = 0; + tmp_threshold.tmp_thshold2 = thres2; + } else { + tmp_threshold.tmp_thshold2_enable = 1; + tmp_threshold.tmp_thshold2 = thres2; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_threshold_trip(struct ifpga_fme_hw *fme, + u64 *thres_trip) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres_trip = temp_threshold.therm_trip_thshold; + + return 0; +} + +static int fme_thermal_get_threshold1_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold1_status; + + return 0; +} + +static int fme_thermal_get_threshold2_reached(struct ifpga_fme_hw *fme, + u64 *thres1_reached) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_reached = temp_threshold.thshold2_status; + + return 0; +} + +static int fme_thermal_get_threshold1_policy(struct ifpga_fme_hw *fme, + u64 *thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold temp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_threshold.csr = readq(&thermal->threshold); + *thres1_policy = temp_threshold.thshold_policy; + + return 0; +} + +static int fme_thermal_set_threshold1_policy(struct ifpga_fme_hw *fme, + u64 thres1_policy) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_tmp_threshold tmp_threshold; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + spinlock_lock(&fme->lock); + tmp_threshold.csr = readq(&thermal->threshold); + + if (thres1_policy == 0) { + tmp_threshold.thshold_policy = 0; + } else if (thres1_policy == 1) { + tmp_threshold.thshold_policy = 1; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(tmp_threshold.csr, &thermal->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_thermal_get_temperature(struct ifpga_fme_hw *fme, u64 *temp) +{ + struct feature_fme_thermal *thermal; + struct feature_fme_temp_rdsensor_fmt1 temp_rdsensor_fmt1; + + thermal = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + + temp_rdsensor_fmt1.csr = readq(&thermal->rdsensor_fm1); + *temp = temp_rdsensor_fmt1.fpga_temp; + + return 0; +} + +static int fme_thermal_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_thermal *fme_thermal + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_THERMAL_MGMT); + struct feature_header header; + + header.csr = readq(&fme_thermal->header); + *revision = header.revision; + + return 0; +} + +#define FME_THERMAL_CAP_NO_TMP_THRESHOLD 0x1 + +static int fme_thermal_mgmt_init(struct feature *feature) +{ + struct feature_fme_thermal *fme_thermal; + struct feature_fme_tmp_threshold_cap thermal_cap; + + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt Init.\n"); + + fme_thermal = (struct feature_fme_thermal *)feature->addr; + thermal_cap.csr = readq(&fme_thermal->threshold_cap); + + dev_info(NULL, "FME thermal cap %llx.\n", + (unsigned long long)fme_thermal->threshold_cap.csr); + + if (thermal_cap.tmp_thshold_disabled) + feature->cap |= FME_THERMAL_CAP_NO_TMP_THRESHOLD; + + return 0; +} + +static void fme_thermal_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME thermal mgmt UInit.\n"); +} + +static int +fme_thermal_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_set_threshold1(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_set_threshold2(fme, prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_set_threshold1_policy(fme, prop->data); + } + + return -ENOENT; +} + +static int +fme_thermal_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + if (feature->cap & FME_THERMAL_CAP_NO_TMP_THRESHOLD && + prop->prop_id != FME_THERMAL_PROP_TEMPERATURE && + prop->prop_id != FME_THERMAL_PROP_REVISION) + return -ENOENT; + + switch (prop->prop_id) { + case FME_THERMAL_PROP_THRESHOLD1: + return fme_thermal_get_threshold1(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2: + return fme_thermal_get_threshold2(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD_TRIP: + return fme_thermal_get_threshold_trip(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_REACHED: + return fme_thermal_get_threshold1_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD2_REACHED: + return fme_thermal_get_threshold2_reached(fme, &prop->data); + case FME_THERMAL_PROP_THRESHOLD1_POLICY: + return fme_thermal_get_threshold1_policy(fme, &prop->data); + case FME_THERMAL_PROP_TEMPERATURE: + return fme_thermal_get_temperature(fme, &prop->data); + case FME_THERMAL_PROP_REVISION: + return fme_thermal_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +struct feature_ops fme_thermal_mgmt_ops = { + .init = fme_thermal_mgmt_init, + .uinit = fme_thermal_mgmt_uinit, + .get_prop = fme_thermal_get_prop, + .set_prop = fme_thermal_set_prop, +}; + +static int fme_pwr_get_consumed(struct ifpga_fme_hw *fme, u64 *consumed) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *consumed = pm_status.pwr_consumed; + + return 0; +} + +static int fme_pwr_get_threshold1(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold1; + + return 0; +} + +static int fme_pwr_set_threshold1(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold1 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold2(struct ifpga_fme_hw *fme, u64 *threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold = pm_ap_threshold.threshold2; + + return 0; +} + +static int fme_pwr_set_threshold2(struct ifpga_fme_hw *fme, u64 threshold) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + spinlock_lock(&fme->lock); + pm_ap_threshold.csr = readq(&fme_power->threshold); + + if (threshold <= PWR_THRESHOLD_MAX) { + pm_ap_threshold.threshold2 = threshold; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(pm_ap_threshold.csr, &fme_power->threshold); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_pwr_get_threshold1_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold1_status; + + return 0; +} + +static int fme_pwr_get_threshold2_status(struct ifpga_fme_hw *fme, + u64 *threshold_status) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_ap_threshold pm_ap_threshold; + + pm_ap_threshold.csr = readq(&fme_power->threshold); + + *threshold_status = pm_ap_threshold.threshold2_status; + + return 0; +} + +static int fme_pwr_get_rtl(struct ifpga_fme_hw *fme, u64 *rtl) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_status pm_status; + + pm_status.csr = readq(&fme_power->status); + + *rtl = pm_status.fpga_latency_report; + + return 0; +} + +static int fme_pwr_get_xeon_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_xeon_limit xeon_limit; + + xeon_limit.csr = readq(&fme_power->xeon_limit); + + if (!xeon_limit.enable) + xeon_limit.pwr_limit = 0; + + *limit = xeon_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_fpga_limit(struct ifpga_fme_hw *fme, u64 *limit) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_fme_pm_fpga_limit fpga_limit; + + fpga_limit.csr = readq(&fme_power->fpga_limit); + + if (!fpga_limit.enable) + fpga_limit.pwr_limit = 0; + + *limit = fpga_limit.pwr_limit; + + return 0; +} + +static int fme_pwr_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_power *fme_power + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_POWER_MGMT); + struct feature_header header; + + header.csr = readq(&fme_power->header); + *revision = header.revision; + + return 0; +} + +static int fme_power_mgmt_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt Init.\n"); + + return 0; +} + +static void fme_power_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME power mgmt UInit.\n"); +} + +static int fme_power_mgmt_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_CONSUMED: + return fme_pwr_get_consumed(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_get_threshold1(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_get_threshold2(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD1_STATUS: + return fme_pwr_get_threshold1_status(fme, &prop->data); + case FME_PWR_PROP_THRESHOLD2_STATUS: + return fme_pwr_get_threshold2_status(fme, &prop->data); + case FME_PWR_PROP_RTL: + return fme_pwr_get_rtl(fme, &prop->data); + case FME_PWR_PROP_XEON_LIMIT: + return fme_pwr_get_xeon_limit(fme, &prop->data); + case FME_PWR_PROP_FPGA_LIMIT: + return fme_pwr_get_fpga_limit(fme, &prop->data); + case FME_PWR_PROP_REVISION: + return fme_pwr_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_power_mgmt_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + + switch (prop->prop_id) { + case FME_PWR_PROP_THRESHOLD1: + return fme_pwr_set_threshold1(fme, prop->data); + case FME_PWR_PROP_THRESHOLD2: + return fme_pwr_set_threshold2(fme, prop->data); + } + + return -ENOENT; +} + +struct 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, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c new file mode 100644 index 0000000..1773b87 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_dperf.c @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_dperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_clk_ctr clk; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + clk.afu_interf_clock = readq(&dperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_dperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_dperf *dperf; + struct feature_header header; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + header.csr = readq(&dperf->header); + *revision = header.revision; + + return 0; +} + +#define DPERF_TIMEOUT 30 + +static bool fabric_pobj_is_enabled(int port_id, + struct feature_fme_dperf *dperf) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + + ctl.csr = readq(&dperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum dperf_fab_events fab_event) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dfpmon_fab_ctr ctr; + struct feature_fme_dperf *dperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, dperf)) + goto exit; + + ctl.csr = readq(&dperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &dperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &dperf->fab_ctr, DPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&dperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_dperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, DPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, DPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(mmio_read, DPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, DPERF_FAB_MMIO_WR); + +static int fme_dperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_dperf *dperf; + int status; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + status = fabric_pobj_is_enabled(port_id, dperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_dperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_dfpmon_fab_ctl ctl; + struct feature_fme_dperf *dperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, dperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&dperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_dperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_dperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_dperf *dperf; + struct feature_fme_dfpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + dperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_DPERF); + ctl.csr = readq(&dperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &dperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 + +static int fme_global_dperf_init(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf Init.\n"); + + return 0; +} + +static void fme_global_dperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_dperf UInit.\n"); +} + +static int fme_dperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_dperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_dperf_get_fab_port_pcie0_read(fme, sub, &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_dperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* MMIO_READ */ + return fme_dperf_get_fab_port_mmio_read(fme, sub, &prop->data); + case 0x5: /* MMIO_WRITE */ + return fme_dperf_get_fab_port_mmio_write(fme, sub, &prop->data); + case 0x6: /* ENABLE */ + return fme_dperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_dperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_dperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_dperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_dperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_dperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE - fab root only prop */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_dperf_set_fab_freeze(fme, prop->data); + case 0x6: /* ENABLE - fab both root and sub */ + return fme_dperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_dperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_FAB: + return fme_dperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_dperf_ops = { + .init = fme_global_dperf_init, + .uinit = fme_global_dperf_uinit, + .get_prop = fme_global_dperf_get_prop, + .set_prop = fme_global_dperf_set_prop, + +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c new file mode 100644 index 0000000..8c26fb2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_error.c @@ -0,0 +1,381 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static int fme_err_get_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + + fme_error0.csr = readq(&fme_err->fme_err); + *val = fme_error0.csr; + + return 0; +} + +static int fme_err_get_first_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_first_error fme_first_err; + + fme_first_err.csr = readq(&fme_err->fme_first_err); + *val = fme_first_err.err_reg_status; + + return 0; +} + +static int fme_err_get_next_error(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_next_error fme_next_err; + + fme_next_err.csr = readq(&fme_err->fme_next_err); + *val = fme_next_err.err_reg_status; + + return 0; +} + +static int fme_err_set_clear(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_error0 fme_error0; + struct feature_fme_first_error fme_first_err; + struct feature_fme_next_error fme_next_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_ERROR0_MASK, &fme_err->fme_err_mask); + + fme_error0.csr = readq(&fme_err->fme_err); + if (val != fme_error0.csr) { + ret = -EBUSY; + goto exit; + } + + fme_first_err.csr = readq(&fme_err->fme_first_err); + fme_next_err.csr = readq(&fme_err->fme_next_err); + + writeq(fme_error0.csr & FME_ERROR0_MASK, &fme_err->fme_err); + writeq(fme_first_err.csr & FME_FIRST_ERROR_MASK, + &fme_err->fme_first_err); + writeq(fme_next_err.csr & FME_NEXT_ERROR_MASK, + &fme_err->fme_next_err); + +exit: + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_revision(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_header header; + + header.csr = readq(&fme_err->header); + *val = header.revision; + + return 0; +} + +static int fme_err_get_pcie0_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + + pcie0_err.csr = readq(&fme_err->pcie0_err); + *val = pcie0_err.csr; + + return 0; +} + +static int fme_err_set_pcie0_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie0_error pcie0_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE0_ERROR_MASK, &fme_err->pcie0_err_mask); + + pcie0_err.csr = readq(&fme_err->pcie0_err); + if (val != pcie0_err.csr) + ret = -EBUSY; + else + writeq(pcie0_err.csr & FME_PCIE0_ERROR_MASK, + &fme_err->pcie0_err); + + writeq(0UL, &fme_err->pcie0_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_pcie1_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + + pcie1_err.csr = readq(&fme_err->pcie1_err); + *val = pcie1_err.csr; + + return 0; +} + +static int fme_err_set_pcie1_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_pcie1_error pcie1_err; + int ret = 0; + + spinlock_lock(&fme->lock); + writeq(FME_PCIE1_ERROR_MASK, &fme_err->pcie1_err_mask); + + pcie1_err.csr = readq(&fme_err->pcie1_err); + if (val != pcie1_err.csr) + ret = -EBUSY; + else + writeq(pcie1_err.csr & FME_PCIE1_ERROR_MASK, + &fme_err->pcie1_err); + + writeq(0UL, &fme_err->pcie1_err_mask); + spinlock_unlock(&fme->lock); + + return ret; +} + +static int fme_err_get_nonfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_nonfaterror ras_nonfaterr; + + ras_nonfaterr.csr = readq(&fme_err->ras_nonfaterr); + *val = ras_nonfaterr.csr; + + return 0; +} + +static int fme_err_get_catfatal_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_catfaterror ras_catfaterr; + + ras_catfaterr.csr = readq(&fme_err->ras_catfaterr); + *val = ras_catfaterr.csr; + + return 0; +} + +static int fme_err_get_inject_errors(struct ifpga_fme_hw *fme, u64 *val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + *val = ras_error_inj.csr & FME_RAS_ERROR_INJ_MASK; + + return 0; +} + +static int fme_err_set_inject_errors(struct ifpga_fme_hw *fme, u64 val) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + struct feature_fme_ras_error_inj ras_error_inj; + + spinlock_lock(&fme->lock); + ras_error_inj.csr = readq(&fme_err->ras_error_inj); + + if (val <= FME_RAS_ERROR_INJ_MASK) { + ras_error_inj.csr = val; + } else { + spinlock_unlock(&fme->lock); + return -EINVAL; + } + + writeq(ras_error_inj.csr, &fme_err->ras_error_inj); + spinlock_unlock(&fme->lock); + + return 0; +} + +static void fme_error_enable(struct ifpga_fme_hw *fme) +{ + struct feature_fme_err *fme_err + = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_ERR); + + writeq(FME_ERROR0_MASK_DEFAULT, &fme_err->fme_err_mask); + writeq(0UL, &fme_err->pcie0_err_mask); + writeq(0UL, &fme_err->pcie1_err_mask); + writeq(0UL, &fme_err->ras_nonfat_mask); + writeq(0UL, &fme_err->ras_catfat_mask); +} + +static int fme_global_error_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme = feature->parent; + + fme_error_enable(fme); + + if (feature->ctx_num) + fme->capability |= FPGA_FME_CAP_ERR_IRQ; + + return 0; +} + +static void fme_global_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int fme_err_fme_err_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* ERRORS */ + return fme_err_get_errors(fme, &prop->data); + case 0x2: /* FIRST_ERROR */ + return fme_err_get_first_error(fme, &prop->data); + case 0x3: /* NEXT_ERROR */ + return fme_err_get_next_error(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x5: /* REVISION */ + return fme_err_get_revision(fme, &prop->data); + case 0x6: /* PCIE0_ERRORS */ + return fme_err_get_pcie0_errors(fme, &prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_get_pcie1_errors(fme, &prop->data); + case 0x8: /* NONFATAL_ERRORS */ + return fme_err_get_nonfatal_errors(fme, &prop->data); + case 0x9: /* CATFATAL_ERRORS */ + return fme_err_get_catfatal_errors(fme, &prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_get_inject_errors(fme, &prop->data); + case 0xb: /* REVISION*/ + return fme_err_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_get_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_err_fme_err_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x4: /* CLEAR */ + return fme_err_set_clear(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_err_root_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x6: /* PCIE0_ERRORS */ + return fme_err_set_pcie0_errors(fme, prop->data); + case 0x7: /* PCIE1_ERRORS */ + return fme_err_set_pcie1_errors(fme, prop->data); + case 0xa: /* INJECT_ERRORS */ + return fme_err_set_inject_errors(fme, prop->data); + } + + return -ENOENT; +} + +static int fme_global_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + /* PROP_SUB is never used */ + if (sub != PROP_SUB_UNUSED) + return -ENOENT; + + switch (top) { + case ERR_PROP_TOP_FME_ERR: + return fme_err_fme_err_set_prop(feature, prop); + case ERR_PROP_TOP_UNUSED: + return fme_err_root_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_err_ops = { + .init = fme_global_error_init, + .uinit = fme_global_error_uinit, + .get_prop = fme_global_error_get_prop, + .set_prop = fme_global_error_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c new file mode 100644 index 0000000..e6c40a1 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_iperf.c @@ -0,0 +1,715 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +#define PERF_OBJ_ROOT_ID 0xff + +static int fme_iperf_get_clock(struct ifpga_fme_hw *fme, u64 *clock) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_clk_ctr clk; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + clk.afu_interf_clock = readq(&iperf->clk); + + *clock = clk.afu_interf_clock; + return 0; +} + +static int fme_iperf_get_revision(struct ifpga_fme_hw *fme, u64 *revision) +{ + struct feature_fme_iperf *iperf; + struct feature_header header; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + header.csr = readq(&iperf->header); + *revision = header.revision; + + return 0; +} + +static int fme_iperf_get_cache_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + *freeze = (u64)ctl.freeze; + return 0; +} + +static int fme_iperf_set_cache_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->ch_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->ch_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define IPERF_TIMEOUT 30 + +static u64 read_cache_counter(struct ifpga_fme_hw *fme, + u8 channel, enum iperf_cache_events event) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_ch_ctl ctl; + struct feature_fme_ifpmon_ch_ctr ctr0, ctr1; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* set channel access type and cache event code. */ + ctl.csr = readq(&iperf->ch_ctl); + ctl.cci_chsel = channel; + ctl.cache_event = event; + writeq(ctl.csr, &iperf->ch_ctl); + + /* check the event type in the counter registers */ + ctr0.event_code = event; + + if (fpga_wait_register_field(event_code, ctr0, + &iperf->ch_ctr0, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched cache event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr0.csr = readq(&iperf->ch_ctr0); + ctr1.csr = readq(&iperf->ch_ctr1); + counter = ctr0.cache_counter + ctr1.cache_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define CACHE_SHOW(name, type, event) \ +static int fme_iperf_get_cache_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_cache_counter(fme, type, event); \ + return 0; \ +} + +CACHE_SHOW(read_hit, CACHE_CHANNEL_RD, IPERF_CACHE_RD_HIT); +CACHE_SHOW(read_miss, CACHE_CHANNEL_RD, IPERF_CACHE_RD_MISS); +CACHE_SHOW(write_hit, CACHE_CHANNEL_WR, IPERF_CACHE_WR_HIT); +CACHE_SHOW(write_miss, CACHE_CHANNEL_WR, IPERF_CACHE_WR_MISS); +CACHE_SHOW(hold_request, CACHE_CHANNEL_RD, IPERF_CACHE_HOLD_REQ); +CACHE_SHOW(tx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_TX_REQ_STALL); +CACHE_SHOW(rx_req_stall, CACHE_CHANNEL_RD, IPERF_CACHE_RX_REQ_STALL); +CACHE_SHOW(rx_eviction, CACHE_CHANNEL_RD, IPERF_CACHE_EVICTIONS); +CACHE_SHOW(data_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_DATA_WR_PORT_CONTEN); +CACHE_SHOW(tag_write_port_contention, CACHE_CHANNEL_WR, + IPERF_CACHE_TAG_WR_PORT_CONTEN); + +static int fme_iperf_get_vtd_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_vtd_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->vtd_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static u64 read_iommu_sip_counter(struct ifpga_fme_hw *fme, + enum iperf_vtd_sip_events event) +{ + struct feature_fme_ifpmon_vtd_sip_ctl sip_ctl; + struct feature_fme_ifpmon_vtd_sip_ctr sip_ctr; + struct feature_fme_iperf *iperf; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + sip_ctl.csr = readq(&iperf->vtd_sip_ctl); + sip_ctl.vtd_evtcode = event; + writeq(sip_ctl.csr, &iperf->vtd_sip_ctl); + + sip_ctr.event_code = event; + + if (fpga_wait_register_field(event_code, sip_ctr, + &iperf->vtd_sip_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd SIP event type in counter registers\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + sip_ctr.csr = readq(&iperf->vtd_sip_ctr); + counter = sip_ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_SIP_SHOW(name, event) \ +static int fme_iperf_get_vtd_sip_##name(struct ifpga_fme_hw *fme, \ + u64 *counter) \ +{ \ + *counter = read_iommu_sip_counter(fme, event); \ + return 0; \ +} + +VTD_SIP_SHOW(iotlb_4k_hit, IPERF_VTD_SIP_IOTLB_4K_HIT); +VTD_SIP_SHOW(iotlb_2m_hit, IPERF_VTD_SIP_IOTLB_2M_HIT); +VTD_SIP_SHOW(iotlb_1g_hit, IPERF_VTD_SIP_IOTLB_1G_HIT); +VTD_SIP_SHOW(slpwc_l3_hit, IPERF_VTD_SIP_SLPWC_L3_HIT); +VTD_SIP_SHOW(slpwc_l4_hit, IPERF_VTD_SIP_SLPWC_L4_HIT); +VTD_SIP_SHOW(rcc_hit, IPERF_VTD_SIP_RCC_HIT); +VTD_SIP_SHOW(iotlb_4k_miss, IPERF_VTD_SIP_IOTLB_4K_MISS); +VTD_SIP_SHOW(iotlb_2m_miss, IPERF_VTD_SIP_IOTLB_2M_MISS); +VTD_SIP_SHOW(iotlb_1g_miss, IPERF_VTD_SIP_IOTLB_1G_MISS); +VTD_SIP_SHOW(slpwc_l3_miss, IPERF_VTD_SIP_SLPWC_L3_MISS); +VTD_SIP_SHOW(slpwc_l4_miss, IPERF_VTD_SIP_SLPWC_L4_MISS); +VTD_SIP_SHOW(rcc_miss, IPERF_VTD_SIP_RCC_MISS); + +static u64 read_iommu_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_vtd_events base_event) +{ + struct feature_fme_ifpmon_vtd_ctl ctl; + struct feature_fme_ifpmon_vtd_ctr ctr; + struct feature_fme_iperf *iperf; + enum iperf_vtd_events event = base_event + port_id; + u64 counter; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->vtd_ctl); + ctl.vtd_evtcode = event; + writeq(ctl.csr, &iperf->vtd_ctl); + + ctr.event_code = event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->vtd_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->vtd_ctr); + counter = ctr.vtd_counter; + spinlock_unlock(&fme->lock); + + return counter; +} + +#define VTD_PORT_SHOW(name, base_event) \ +static int fme_iperf_get_vtd_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_iommu_counter(fme, port_id, base_event); \ + return 0; \ +} + +VTD_PORT_SHOW(read_transaction, IPERF_VTD_AFU_MEM_RD_TRANS); +VTD_PORT_SHOW(write_transaction, IPERF_VTD_AFU_MEM_WR_TRANS); +VTD_PORT_SHOW(devtlb_read_hit, IPERF_VTD_AFU_DEVTLB_RD_HIT); +VTD_PORT_SHOW(devtlb_write_hit, IPERF_VTD_AFU_DEVTLB_WR_HIT); +VTD_PORT_SHOW(devtlb_4k_fill, IPERF_VTD_DEVTLB_4K_FILL); +VTD_PORT_SHOW(devtlb_2m_fill, IPERF_VTD_DEVTLB_2M_FILL); +VTD_PORT_SHOW(devtlb_1g_fill, IPERF_VTD_DEVTLB_1G_FILL); + +static bool fabric_pobj_is_enabled(u8 port_id, struct feature_fme_iperf *iperf) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + + ctl.csr = readq(&iperf->fab_ctl); + + if (ctl.port_filter == FAB_DISABLE_FILTER) + return port_id == PERF_OBJ_ROOT_ID; + + return port_id == ctl.port_id; +} + +static u64 read_fabric_counter(struct ifpga_fme_hw *fme, u8 port_id, + enum iperf_fab_events fab_event) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_ifpmon_fab_ctr ctr; + struct feature_fme_iperf *iperf; + u64 counter = 0; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is disabled, force the counter to return zero. */ + if (!fabric_pobj_is_enabled(port_id, iperf)) + goto exit; + + ctl.csr = readq(&iperf->fab_ctl); + ctl.fab_evtcode = fab_event; + writeq(ctl.csr, &iperf->fab_ctl); + + ctr.event_code = fab_event; + + if (fpga_wait_register_field(event_code, ctr, + &iperf->fab_ctr, IPERF_TIMEOUT, 1)) { + dev_err(fme, "timeout, unmatched VTd event type in counter registers.\n"); + spinlock_unlock(&fme->lock); + return -ETIMEDOUT; + } + + ctr.csr = readq(&iperf->fab_ctr); + counter = ctr.fab_cnt; +exit: + spinlock_unlock(&fme->lock); + return counter; +} + +#define FAB_PORT_SHOW(name, event) \ +static int fme_iperf_get_fab_port_##name(struct ifpga_fme_hw *fme, \ + u8 port_id, u64 *counter) \ +{ \ + *counter = read_fabric_counter(fme, port_id, event); \ + return 0; \ +} + +FAB_PORT_SHOW(pcie0_read, IPERF_FAB_PCIE0_RD); +FAB_PORT_SHOW(pcie0_write, IPERF_FAB_PCIE0_WR); +FAB_PORT_SHOW(pcie1_read, IPERF_FAB_PCIE1_RD); +FAB_PORT_SHOW(pcie1_write, IPERF_FAB_PCIE1_WR); +FAB_PORT_SHOW(upi_read, IPERF_FAB_UPI_RD); +FAB_PORT_SHOW(upi_write, IPERF_FAB_UPI_WR); +FAB_PORT_SHOW(mmio_read, IPERF_FAB_MMIO_RD); +FAB_PORT_SHOW(mmio_write, IPERF_FAB_MMIO_WR); + +static int fme_iperf_get_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 *enable) +{ + struct feature_fme_iperf *iperf; + int status; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + status = fabric_pobj_is_enabled(port_id, iperf); + *enable = (u64)status; + + return 0; +} + +/* + * If enable one port or all port event counter in fabric, other + * fabric event counter originally enabled will be disable automatically. + */ +static int fme_iperf_set_fab_port_enable(struct ifpga_fme_hw *fme, + u8 port_id, u64 enable) +{ + struct feature_fme_ifpmon_fab_ctl ctl; + struct feature_fme_iperf *iperf; + bool state; + + state = !!enable; + + if (!state) + return -EINVAL; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + + /* if it is already enabled. */ + if (fabric_pobj_is_enabled(port_id, iperf)) + return 0; + + spinlock_lock(&fme->lock); + ctl.csr = readq(&iperf->fab_ctl); + if (port_id == PERF_OBJ_ROOT_ID) { + ctl.port_filter = FAB_DISABLE_FILTER; + } else { + ctl.port_filter = FAB_ENABLE_FILTER; + ctl.port_id = port_id; + } + + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +static int fme_iperf_get_fab_freeze(struct ifpga_fme_hw *fme, u64 *freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + *freeze = (u64)ctl.freeze; + + return 0; +} + +static int fme_iperf_set_fab_freeze(struct ifpga_fme_hw *fme, u64 freeze) +{ + struct feature_fme_iperf *iperf; + struct feature_fme_ifpmon_fab_ctl ctl; + bool state; + + state = !!freeze; + + spinlock_lock(&fme->lock); + iperf = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_GLOBAL_IPERF); + ctl.csr = readq(&iperf->fab_ctl); + ctl.freeze = state; + writeq(ctl.csr, &iperf->fab_ctl); + spinlock_unlock(&fme->lock); + + return 0; +} + +#define PERF_MAX_PORT_NUM 1 +#define FME_IPERF_CAP_IOMMU 0x1 + +static int fme_global_iperf_init(struct feature *feature) +{ + struct ifpga_fme_hw *fme; + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + + dev_info(NULL, "FME global_iperf Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + fme_hdr = get_fme_feature_ioaddr_by_index(fme, FME_FEATURE_ID_HEADER); + + /* check if iommu is not supported on this device. */ + fme_capability.csr = readq(&fme_hdr->capability); + dev_info(NULL, "FME HEAD fme_capability %llx.\n", + (unsigned long long)fme_hdr->capability.csr); + + if (fme_capability.iommu_support) + feature->cap |= FME_IPERF_CAP_IOMMU; + + return 0; +} + +static void fme_global_iperf_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME global_iperf UInit.\n"); +} + +static int fme_iperf_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* CLOCK */ + return fme_iperf_get_clock(fme, &prop->data); + case 0x2: /* REVISION */ + return fme_iperf_get_revision(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_cache_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_cache_freeze(fme, &prop->data); + case 0x2: /* READ_HIT */ + return fme_iperf_get_cache_read_hit(fme, &prop->data); + case 0x3: /* READ_MISS */ + return fme_iperf_get_cache_read_miss(fme, &prop->data); + case 0x4: /* WRITE_HIT */ + return fme_iperf_get_cache_write_hit(fme, &prop->data); + case 0x5: /* WRITE_MISS */ + return fme_iperf_get_cache_write_miss(fme, &prop->data); + case 0x6: /* HOLD_REQUEST */ + return fme_iperf_get_cache_hold_request(fme, &prop->data); + case 0x7: /* TX_REQ_STALL */ + return fme_iperf_get_cache_tx_req_stall(fme, &prop->data); + case 0x8: /* RX_REQ_STALL */ + return fme_iperf_get_cache_rx_req_stall(fme, &prop->data); + case 0x9: /* RX_EVICTION */ + return fme_iperf_get_cache_rx_eviction(fme, &prop->data); + case 0xa: /* DATA_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_data_write_port_contention(fme, + &prop->data); + case 0xb: /* TAG_WRITE_PORT_CONTENTION */ + return fme_iperf_get_cache_tag_write_port_contention(fme, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_root_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + return fme_iperf_get_vtd_freeze(fme, &prop->data); + case 0x2: /* IOTLB_4K_HIT */ + return fme_iperf_get_vtd_sip_iotlb_4k_hit(fme, &prop->data); + case 0x3: /* IOTLB_2M_HIT */ + return fme_iperf_get_vtd_sip_iotlb_2m_hit(fme, &prop->data); + case 0x4: /* IOTLB_1G_HIT */ + return fme_iperf_get_vtd_sip_iotlb_1g_hit(fme, &prop->data); + case 0x5: /* SLPWC_L3_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l3_hit(fme, &prop->data); + case 0x6: /* SLPWC_L4_HIT */ + return fme_iperf_get_vtd_sip_slpwc_l4_hit(fme, &prop->data); + case 0x7: /* RCC_HIT */ + return fme_iperf_get_vtd_sip_rcc_hit(fme, &prop->data); + case 0x8: /* IOTLB_4K_MISS */ + return fme_iperf_get_vtd_sip_iotlb_4k_miss(fme, &prop->data); + case 0x9: /* IOTLB_2M_MISS */ + return fme_iperf_get_vtd_sip_iotlb_2m_miss(fme, &prop->data); + case 0xa: /* IOTLB_1G_MISS */ + return fme_iperf_get_vtd_sip_iotlb_1g_miss(fme, &prop->data); + case 0xb: /* SLPWC_L3_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l3_miss(fme, &prop->data); + case 0xc: /* SLPWC_L4_MISS */ + return fme_iperf_get_vtd_sip_slpwc_l4_miss(fme, &prop->data); + case 0xd: /* RCC_MISS */ + return fme_iperf_get_vtd_sip_rcc_miss(fme, &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_sub_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub > PERF_MAX_PORT_NUM) + return -ENOENT; + + switch (id) { + case 0xe: /* READ_TRANSACTION */ + return fme_iperf_get_vtd_port_read_transaction(fme, sub, + &prop->data); + case 0xf: /* WRITE_TRANSACTION */ + return fme_iperf_get_vtd_port_write_transaction(fme, sub, + &prop->data); + case 0x10: /* DEVTLB_READ_HIT */ + return fme_iperf_get_vtd_port_devtlb_read_hit(fme, sub, + &prop->data); + case 0x11: /* DEVTLB_WRITE_HIT */ + return fme_iperf_get_vtd_port_devtlb_write_hit(fme, sub, + &prop->data); + case 0x12: /* DEVTLB_4K_FILL */ + return fme_iperf_get_vtd_port_devtlb_4k_fill(fme, sub, + &prop->data); + case 0x13: /* DEVTLB_2M_FILL */ + return fme_iperf_get_vtd_port_devtlb_2m_fill(fme, sub, + &prop->data); + case 0x14: /* DEVTLB_1G_FILL */ + return fme_iperf_get_vtd_port_devtlb_1g_fill(fme, sub, + &prop->data); + } + + return -ENOENT; +} + +static int fme_iperf_vtd_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED) + return fme_iperf_vtd_root_get_prop(feature, prop); + + return fme_iperf_vtd_sub_get_prop(feature, prop); +} + +static int fme_iperf_fab_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + /* Other properties are present for both top and sub levels */ + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_get_fab_freeze(fme, &prop->data); + case 0x2: /* PCIE0_READ */ + return fme_iperf_get_fab_port_pcie0_read(fme, sub, + &prop->data); + case 0x3: /* PCIE0_WRITE */ + return fme_iperf_get_fab_port_pcie0_write(fme, sub, + &prop->data); + case 0x4: /* PCIE1_READ */ + return fme_iperf_get_fab_port_pcie1_read(fme, sub, + &prop->data); + case 0x5: /* PCIE1_WRITE */ + return fme_iperf_get_fab_port_pcie1_write(fme, sub, + &prop->data); + case 0x6: /* UPI_READ */ + return fme_iperf_get_fab_port_upi_read(fme, sub, + &prop->data); + case 0x7: /* UPI_WRITE */ + return fme_iperf_get_fab_port_upi_write(fme, sub, + &prop->data); + case 0x8: /* MMIO_READ */ + return fme_iperf_get_fab_port_mmio_read(fme, sub, + &prop->data); + case 0x9: /* MMIO_WRITE */ + return fme_iperf_get_fab_port_mmio_write(fme, sub, + &prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_get_fab_port_enable(fme, sub, &prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_get_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_get_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_get_prop(feature, prop); + case PERF_PROP_TOP_UNUSED: + return fme_iperf_root_get_prop(feature, prop); + } + + return -ENOENT; +} + +static int fme_iperf_cache_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_cache_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_vtd_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + if (sub == PERF_PROP_SUB_UNUSED && id == 0x1) /* FREEZE */ + return fme_iperf_set_vtd_freeze(fme, prop->data); + + return -ENOENT; +} + +static int fme_iperf_fab_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme = feature->parent; + u8 sub = GET_FIELD(PROP_SUB, prop->prop_id); + u16 id = GET_FIELD(PROP_ID, prop->prop_id); + + switch (id) { + case 0x1: /* FREEZE */ + if (sub != PERF_PROP_SUB_UNUSED) + return -ENOENT; + return fme_iperf_set_fab_freeze(fme, prop->data); + case 0xa: /* ENABLE */ + return fme_iperf_set_fab_port_enable(fme, sub, prop->data); + } + + return -ENOENT; +} + +static int fme_global_iperf_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + u8 top = GET_FIELD(PROP_TOP, prop->prop_id); + + switch (top) { + case PERF_PROP_TOP_CACHE: + return fme_iperf_cache_set_prop(feature, prop); + case PERF_PROP_TOP_VTD: + return fme_iperf_vtd_set_prop(feature, prop); + case PERF_PROP_TOP_FAB: + return fme_iperf_fab_set_prop(feature, prop); + } + + return -ENOENT; +} + +struct feature_ops fme_global_iperf_ops = { + .init = fme_global_iperf_init, + .uinit = fme_global_iperf_uinit, + .get_prop = fme_global_iperf_get_prop, + .set_prop = fme_global_iperf_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c new file mode 100644 index 0000000..49d8cc5 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_fme_pr.c @@ -0,0 +1,352 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static u64 +pr_err_handle(struct feature_fme_pr *fme_pr) +{ + struct feature_fme_pr_status fme_pr_status; + unsigned long err_code; + u64 fme_pr_error; + int i; + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + if (!fme_pr_status.pr_status) + return 0; + + err_code = readq(&fme_pr->ccip_fme_pr_err); + fme_pr_error = err_code; + + for (i = 0; i < PR_MAX_ERR_NUM; i++) { + if (err_code & (1 << i)) + dev_info(NULL, "%s\n", pr_err_msg[i]); + } + + writeq(fme_pr_error, &fme_pr->ccip_fme_pr_err); + return fme_pr_error; +} + +static int fme_pr_write_init(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + if (info->flags != FPGA_MGR_PARTIAL_RECONFIG) + return -EINVAL; + + dev_info(fme_dev, "resetting PR before initiated PR\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + fme_pr_ctl.pr_reset_ack = 1; + + if (fpga_wait_register_field(pr_reset_ack, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_reset = 0; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "waiting for PR resource in HW to be initialized and ready\n"); + + fme_pr_status.pr_host_status = PR_HOST_STATUS_IDLE; + + if (fpga_wait_register_field(pr_host_status, fme_pr_status, + &fme_pr->ccip_fme_pr_status, + PR_WAIT_TIMEOUT, 1)) { + dev_err(fme_dev, "maximum PR timeout\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "check if have any previous PR error\n"); + pr_err_handle(fme_pr); + return 0; +} + +static int fme_pr_write(struct ifpga_fme_hw *fme_dev, + int port_id, const char *buf, size_t count, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + struct feature_fme_pr_status fme_pr_status; + struct feature_fme_pr_data fme_pr_data; + int delay, pr_credit; + int ret = 0; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + if (!fme_pr) + return -EINVAL; + + dev_info(fme_dev, "set PR port ID and start request\n"); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_regionid = port_id; + fme_pr_ctl.pr_start_req = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "pushing data from bitstream to HW\n"); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + + while (count > 0) { + delay = 0; + while (pr_credit <= 1) { + if (delay++ > PR_WAIT_TIMEOUT) { + dev_err(fme_dev, "maximum try\n"); + + info->pr_err = pr_err_handle(fme_pr); + return info->pr_err ? -EIO : -ETIMEDOUT; + } + udelay(1); + + fme_pr_status.csr = readq(&fme_pr->ccip_fme_pr_status); + pr_credit = fme_pr_status.pr_credit; + }; + + if (count >= fme_dev->pr_bandwidth) { + switch (fme_dev->pr_bandwidth) { + case 4: + fme_pr_data.rsvd = 0; + fme_pr_data.pr_data_raw = *((const u32 *)buf); + writeq(fme_pr_data.csr, + &fme_pr->ccip_fme_pr_data); + break; + default: + ret = -EFAULT; + goto done; + } + + buf += fme_dev->pr_bandwidth; + count -= fme_dev->pr_bandwidth; + pr_credit--; + } else { + WARN_ON(1); + return -EINVAL; + goto done; + } + } + +done: + return ret; +} + +static int fme_pr_write_complete(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info) +{ + struct feature_fme_pr *fme_pr; + struct feature_fme_pr_ctl fme_pr_ctl; + + fme_pr = get_fme_feature_ioaddr_by_index(fme_dev, + FME_FEATURE_ID_PR_MGMT); + + fme_pr_ctl.csr = readq(&fme_pr->ccip_fme_pr_control); + fme_pr_ctl.pr_push_complete = 1; + writeq(fme_pr_ctl.csr, &fme_pr->ccip_fme_pr_control); + + dev_info(fme_dev, "green bitstream push complete\n"); + dev_info(fme_dev, "waiting for HW to release PR resource\n"); + + fme_pr_ctl.pr_start_req = 0; + + if (fpga_wait_register_field(pr_start_req, fme_pr_ctl, + &fme_pr->ccip_fme_pr_control, + PR_WAIT_TIMEOUT, 1)) { + printf("maximum try.\n"); + return -ETIMEDOUT; + } + + dev_info(fme_dev, "PR operation complete, checking status\n"); + info->pr_err = pr_err_handle(fme_pr); + if (info->pr_err) + return -EIO; + + dev_info(fme_dev, "PR done successfully\n"); + return 0; +} + +static int fpga_pr_buf_load(struct ifpga_fme_hw *fme_dev, + struct fpga_pr_info *info, const char *buf, + size_t count) +{ + int ret; + + info->state = FPGA_PR_STATE_WRITE_INIT; + ret = fme_pr_write_init(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error preparing FPGA for writing\n"); + info->state = FPGA_PR_STATE_WRITE_INIT_ERR; + return ret; + } + + /* + * Write the FPGA image to the FPGA. + */ + info->state = FPGA_PR_STATE_WRITE; + ret = fme_pr_write(fme_dev, info->port_id, buf, count, info); + if (ret) { + dev_err(fme_dev, "Error while writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_ERR; + return ret; + } + + /* + * After all the FPGA image has been written, do the device specific + * steps to finish and set the FPGA into operating mode. + */ + info->state = FPGA_PR_STATE_WRITE_COMPLETE; + ret = fme_pr_write_complete(fme_dev, info); + if (ret) { + dev_err(fme_dev, "Error after writing image data to FPGA\n"); + info->state = FPGA_PR_STATE_WRITE_COMPLETE_ERR; + return ret; + } + info->state = FPGA_PR_STATE_DONE; + + return 0; +} + +static int fme_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, + u64 *status) +{ + struct feature_fme_header *fme_hdr; + struct feature_fme_capability fme_capability; + struct ifpga_fme_hw *fme = &hw->fme; + struct fpga_pr_info info; + struct ifpga_port_hw *port; + int ret = 0; + + if (!buffer || size == 0) + return -EINVAL; + if (fme->state != IFPGA_FME_IMPLEMENTED) + return -EINVAL; + + /* + * Padding extra zeros to align PR buffer with PR bandwidth, HW will + * ignore these zeros automatically. + */ + size = IFPGA_ALIGN(size, fme->pr_bandwidth); + + /* get fme header region */ + fme_hdr = get_fme_feature_ioaddr_by_index(fme, + FME_FEATURE_ID_HEADER); + if (!fme_hdr) + return -EINVAL; + + /* check port id */ + fme_capability.csr = readq(&fme_hdr->capability); + if (port_id >= fme_capability.num_ports) { + dev_err(fme, "port number more than maximum\n"); + return -EINVAL; + } + + memset(&info, 0, sizeof(struct fpga_pr_info)); + info.flags = FPGA_MGR_PARTIAL_RECONFIG; + info.port_id = port_id; + + spinlock_lock(&fme->lock); + + /* get port device by port_id */ + port = &hw->port[port_id]; + + /* Disable Port before PR */ + fpga_port_disable(port); + + ret = fpga_pr_buf_load(fme, &info, (void *)buffer, size); + + *status = info.pr_err; + + /* Re-enable Port after PR finished */ + fpga_port_enable(port); + spinlock_unlock(&fme->lock); + + return ret; +} + +int do_pr(struct ifpga_hw *hw, u32 port_id, void *buffer, u32 size, u64 *status) +{ + struct bts_header *bts_hdr; + void *buf; + struct ifpga_port_hw *port; + int ret; + + if (!buffer || size == 0) { + dev_err(hw, "invalid parameter\n"); + return -EINVAL; + } + + bts_hdr = (struct bts_header *)buffer; + + if (is_valid_bts(bts_hdr)) { + dev_info(hw, "this is a valid bitsteam..\n"); + size -= (sizeof(struct bts_header) + + bts_hdr->metadata_len); + buf = (u8 *)buffer + sizeof(struct bts_header) + + bts_hdr->metadata_len; + } else { + return -EINVAL; + } + + /* clean port error before do PR */ + port = &hw->port[port_id]; + ret = port_clear_error(port); + if (ret) { + dev_err(hw, "port cannot clear error\n"); + return -EINVAL; + } + + return fme_pr(hw, port_id, buf, size, status); +} + +static int fme_pr_mgmt_init(struct feature *feature) +{ + struct feature_fme_pr *fme_pr; + struct feature_header fme_pr_header; + struct ifpga_fme_hw *fme; + + dev_info(NULL, "FME PR MGMT Init.\n"); + + fme = (struct ifpga_fme_hw *)feature->parent; + + fme_pr = (struct feature_fme_pr *)feature->addr; + + fme_pr_header.csr = readq(&fme_pr->header); + if (fme_pr_header.revision == 2) { + dev_info(NULL, "using 512-bit PR\n"); + fme->pr_bandwidth = 64; + } else { + dev_info(NULL, "using 32-bit PR\n"); + fme->pr_bandwidth = 4; + } + + return 0; +} + +static void fme_pr_mgmt_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "FME PR MGMT UInit.\n"); +} + +struct 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 new file mode 100644 index 0000000..a20520c --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_hw.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_HW_H_ +#define _IFPGA_HW_H_ + +#include "ifpga_defines.h" +#include "opae_ifpga_hw_api.h" + +enum ifpga_feature_state { + IFPGA_FEATURE_UNUSED = 0, + IFPGA_FEATURE_ATTACHED, +}; + +struct feature_irq_ctx { + int eventfd; + int idx; +}; + +struct feature { + enum ifpga_feature_state state; + const char *name; + u64 id; + u8 *addr; + uint64_t phys_addr; + u32 size; + int revision; + u64 cap; + int vfio_dev_fd; + struct feature_irq_ctx *ctx; + unsigned int ctx_num; + + void *parent; /* to parent hw data structure */ + + struct feature_ops *ops;/* callback to this private feature */ +}; + +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); +}; + +enum ifpga_fme_state { + IFPGA_FME_UNUSED = 0, + IFPGA_FME_IMPLEMENTED, +}; + +struct ifpga_fme_hw { + enum ifpga_fme_state state; + + struct feature sub_feature[FME_FEATURE_ID_MAX]; + spinlock_t lock; /* protect hardware access */ + + void *parent; /* pointer to ifpga_hw */ + + /* provied by HEADER feature */ + u32 port_num; + struct uuid bitstream_id; + u64 bitstream_md; + size_t pr_bandwidth; + u32 socket_id; + u32 fabric_version_id; + u32 cache_size; + + u32 capability; +}; + +enum ifpga_port_state { + IFPGA_PORT_UNUSED = 0, + IFPGA_PORT_ATTACHED, + IFPGA_PORT_DETACHED, +}; + +struct ifpga_port_hw { + enum ifpga_port_state state; + + struct feature sub_feature[PORT_FEATURE_ID_MAX]; + spinlock_t lock; /* protect access to hw */ + + void *parent; /* pointer to ifpga_hw */ + + int port_id; /* provied by HEADER feature */ + struct uuid afu_id; /* provied by User AFU feature */ + + unsigned int disable_count; + + u32 capability; + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ + u8 *stp_addr; + u32 stp_size; +}; + +#define AFU_MAX_REGION 1 + +struct ifpga_afu_info { + struct opae_reg_region region[AFU_MAX_REGION]; + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct ifpga_hw { + struct opae_adapter *adapter; + struct opae_adapter_data_pci *pci_data; + + struct ifpga_fme_hw fme; + struct ifpga_port_hw port[MAX_FPGA_PORT_NUM]; +}; + +static inline bool is_ifpga_hw_pf(struct ifpga_hw *hw) +{ + return hw->fme.state != IFPGA_FME_UNUSED; +} + +static inline bool is_valid_port_id(struct ifpga_hw *hw, u32 port_id) +{ + if (port_id >= MAX_FPGA_PORT_NUM || + hw->port[port_id].state != IFPGA_PORT_ATTACHED) + return false; + + return true; +} +#endif /* _IFPGA_HW_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port.c b/drivers/raw/ifpga_rawdev/base/ifpga_port.c new file mode 100644 index 0000000..a962f5b --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port.c @@ -0,0 +1,388 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +int port_get_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->get_prop) + return feature->ops->get_prop(feature, prop); + + return -ENOENT; +} + +int port_set_prop(struct ifpga_port_hw *port, struct feature_prop *prop) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, prop->feature_id); + + if (feature && feature->ops && feature->ops->set_prop) + return feature->ops->set_prop(feature, prop); + + return -ENOENT; +} + +int port_set_irq(struct ifpga_port_hw *port, u32 feature_id, void *irq_set) +{ + struct feature *feature; + + if (!port) + return -ENOENT; + + feature = get_port_feature_by_id(port, feature_id); + + if (feature && feature->ops && feature->ops->set_irq) + return feature->ops->set_irq(feature, irq_set); + + return -ENOENT; +} + +static int port_get_revision(struct ifpga_port_hw *port, u64 *revision) +{ + struct feature_port_header *port_hdr + = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + struct feature_header header; + + header.csr = readq(&port_hdr->header); + + *revision = header.revision; + + return 0; +} + +static int port_get_portidx(struct ifpga_port_hw *port, u64 *idx) +{ + struct feature_port_header *port_hdr; + struct feature_port_capability capability; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + capability.csr = readq(&port_hdr->capability); + *idx = capability.port_number; + + return 0; +} + +static int port_get_latency_tolerance(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_control control; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + control.csr = readq(&port_hdr->control); + *val = control.latency_tolerance; + + return 0; +} + +static int port_get_ap1_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap1_event; + + return 0; +} + +static int port_set_ap1_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap1_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_ap2_event(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.ap2_event; + + return 0; +} + +static int port_set_ap2_event(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + status.ap2_event = val; + writeq(status.csr, &port_hdr->status); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_power_state(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + struct feature_port_status status; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + status.csr = readq(&port_hdr->status); + spinlock_unlock(&port->lock); + + *val = status.power_state; + + return 0; +} + +static int port_get_userclk_freqcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_set_userclk_freqcntrcmd(struct ifpga_port_hw *port, u64 val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + writeq(val, &port_hdr->user_clk_freq_cmd1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts0); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_get_userclk_freqcntrsts(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_header *port_hdr; + + port_hdr = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_HEADER); + + spinlock_lock(&port->lock); + *val = readq(&port_hdr->user_clk_freq_sts1); + spinlock_unlock(&port->lock); + + return 0; +} + +static int port_hdr_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port hdr Init.\n"); + + fpga_port_reset(port); + + return 0; +} + +static void port_hdr_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port hdr uinit.\n"); +} + +static int port_hdr_get_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_REVISION: + return port_get_revision(port, &prop->data); + case PORT_HDR_PROP_PORTIDX: + return port_get_portidx(port, &prop->data); + case PORT_HDR_PROP_LATENCY_TOLERANCE: + return port_get_latency_tolerance(port, &prop->data); + case PORT_HDR_PROP_AP1_EVENT: + return port_get_ap1_event(port, &prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_get_ap2_event(port, &prop->data); + case PORT_HDR_PROP_POWER_STATE: + return port_get_power_state(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_get_userclk_freqcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_get_userclk_freqcntrcmd(port, &prop->data); + case PORT_HDR_PROP_USERCLK_FREQSTS: + return port_get_userclk_freqsts(port, &prop->data); + case PORT_HDR_PROP_USERCLK_CNTRSTS: + return port_get_userclk_freqcntrsts(port, &prop->data); + } + + return -ENOENT; +} + +static int port_hdr_set_prop(struct feature *feature, struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_HDR_PROP_AP1_EVENT: + return port_set_ap1_event(port, prop->data); + case PORT_HDR_PROP_AP2_EVENT: + return port_set_ap2_event(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCMD: + return port_set_userclk_freqcmd(port, prop->data); + case PORT_HDR_PROP_USERCLK_FREQCNTRCMD: + return port_set_userclk_freqcntrcmd(port, prop->data); + } + + return -ENOENT; +} + +struct feature_ops 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) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port stp Init.\n"); + + spinlock_lock(&port->lock); + port->stp_addr = feature->addr; + port->stp_size = feature->size; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_stp_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "port stp uinit.\n"); +} + +struct feature_ops port_stp_ops = { + .init = port_stp_init, + .uinit = port_stp_uinit, +}; + +static int port_uint_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "PORT UINT Init.\n"); + + spinlock_lock(&port->lock); + if (feature->ctx_num) { + port->capability |= FPGA_PORT_CAP_UAFU_IRQ; + port->num_uafu_irqs = feature->ctx_num; + } + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_uint_uinit(struct feature *feature) +{ + UNUSED(feature); + + dev_info(NULL, "PORT UINT UInit.\n"); +} + +struct feature_ops port_uint_ops = { + .init = port_uint_init, + .uinit = port_uint_uinit, +}; diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c new file mode 100644 index 0000000..23db562 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/ifpga_port_error.c @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "ifpga_feature_dev.h" + +static int port_err_get_revision(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_header header; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + header.csr = readq(&port_err->header); + *val = header.revision; + + return 0; +} + +static int port_err_get_errors(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_err_key error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + error.csr = readq(&port_err->port_error); + *val = error.csr; + + return 0; +} + +static int port_err_get_first_error(struct ifpga_port_hw *port, u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_first_err_key first_error; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + first_error.csr = readq(&port_err->port_first_error); + *val = first_error.csr; + + return 0; +} + +static int port_err_get_first_malformed_req_lsb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req0 malreq0; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq0.header_lsb = readq(&port_err->malreq0); + *val = malreq0.header_lsb; + + return 0; +} + +static int port_err_get_first_malformed_req_msb(struct ifpga_port_hw *port, + u64 *val) +{ + struct feature_port_error *port_err; + struct feature_port_malformed_req1 malreq1; + + port_err = get_port_feature_ioaddr_by_index(port, + PORT_FEATURE_ID_ERROR); + + malreq1.header_msb = readq(&port_err->malreq1); + *val = malreq1.header_msb; + + return 0; +} + +static int port_err_set_clear(struct ifpga_port_hw *port, u64 val) +{ + int ret; + + spinlock_lock(&port->lock); + ret = port_err_clear(port, val); + spinlock_unlock(&port->lock); + + return ret; +} + +static int port_error_init(struct feature *feature) +{ + struct ifpga_port_hw *port = feature->parent; + + dev_info(NULL, "port error Init.\n"); + + spinlock_lock(&port->lock); + port_err_mask(port, false); + if (feature->ctx_num) + port->capability |= FPGA_PORT_CAP_ERR_IRQ; + spinlock_unlock(&port->lock); + + return 0; +} + +static void port_error_uinit(struct feature *feature) +{ + UNUSED(feature); +} + +static int port_error_get_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + switch (prop->prop_id) { + case PORT_ERR_PROP_REVISION: + return port_err_get_revision(port, &prop->data); + case PORT_ERR_PROP_ERRORS: + return port_err_get_errors(port, &prop->data); + case PORT_ERR_PROP_FIRST_ERROR: + return port_err_get_first_error(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB: + return port_err_get_first_malformed_req_lsb(port, &prop->data); + case PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB: + return port_err_get_first_malformed_req_msb(port, &prop->data); + } + + return -ENOENT; +} + +static int port_error_set_prop(struct feature *feature, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port = feature->parent; + + if (prop->prop_id == PORT_ERR_PROP_CLEAR) + return port_err_set_clear(port, prop->data); + + return -ENOENT; +} + +struct feature_ops port_error_ops = { + .init = port_error_init, + .uinit = port_error_uinit, + .get_prop = port_error_get_prop, + .set_prop = port_error_set_prop, +}; diff --git a/drivers/raw/ifpga_rawdev/base/meson.build b/drivers/raw/ifpga_rawdev/base/meson.build new file mode 100644 index 0000000..cb65535 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/meson.build @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +sources = [ + 'ifpga_api.c', + 'ifpga_enumerate.c', + 'ifpga_feature_dev.c', + 'ifpga_fme.c', + 'ifpga_fme_iperf.c', + 'ifpga_fme_dperf.c', + 'ifpga_fme_error.c', + 'ifpga_port.c', + 'ifpga_port_error.c', + 'ifpga_fme_pr.c', + 'opae_hw_api.c', + 'opae_ifpga_hw_api.c', + 'opae_debug.c' +] + +error_cflags = ['-Wno-sign-compare', '-Wno-unused-value', + '-Wno-format', '-Wno-unused-but-set-variable', + '-Wno-strict-aliasing' +] +c_args = cflags +foreach flag: error_cflags + if cc.has_argument(flag) + c_args += flag + endif +endforeach + +base_lib = static_library('ifpga_rawdev_base', sources, + dependencies: static_rte_eal, + c_args: c_args) +base_objs = base_lib.extract_all_objects() diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.c b/drivers/raw/ifpga_rawdev/base/opae_debug.c new file mode 100644 index 0000000..024d7d2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.c @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#define OPAE_HW_DEBUG + +#include "opae_hw_api.h" +#include "opae_debug.h" + +void opae_manager_dump(struct opae_manager *mgr) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Manger %s\n", mgr->name); + opae_log("OPAE Manger OPs = %p\n", mgr->ops); + opae_log("OPAE Manager Private Data = %p\n", mgr->data); + opae_log("OPAE Adapter(parent) = %p\n", mgr->adapter); + opae_log("==========================\n"); +} + +void opae_bridge_dump(struct opae_bridge *br) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Bridge %s\n", br->name); + opae_log("OPAE Bridge ID = %d\n", br->id); + opae_log("OPAE Bridge OPs = %p\n", br->ops); + opae_log("OPAE Bridge Private Data = %p\n", br->data); + opae_log("OPAE Accelerator(under this bridge) = %p\n", br->acc); + opae_log("==========================\n"); +} + +void opae_accelerator_dump(struct opae_accelerator *acc) +{ + opae_log("=====%s=====\n", __func__); + opae_log("OPAE Accelerator %s\n", acc->name); + opae_log("OPAE Accelerator Index = %d\n", acc->index); + opae_log("OPAE Accelerator OPs = %p\n", acc->ops); + opae_log("OPAE Accelerator Private Data = %p\n", acc->data); + opae_log("OPAE Bridge (upstream) = %p\n", acc->br); + opae_log("OPAE Manager (upstream) = %p\n", acc->mgr); + opae_log("==========================\n"); + + if (acc->br) + opae_bridge_dump(acc->br); +} + +static void opae_adapter_data_dump(void *data) +{ + struct opae_adapter_data *d = data; + struct opae_adapter_data_pci *d_pci; + struct opae_reg_region *r; + int i; + + opae_log("=====%s=====\n", __func__); + + switch (d->type) { + case OPAE_FPGA_PCI: + d_pci = (struct opae_adapter_data_pci *)d; + + opae_log("OPAE Adapter Type = PCI\n"); + opae_log("PCI Device ID: 0x%04x\n", d_pci->device_id); + opae_log("PCI Vendor ID: 0x%04x\n", d_pci->vendor_id); + + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + r = &d_pci->region[i]; + opae_log("PCI Bar %d: phy(%llx) len(%llx) addr(%p)\n", + i, (unsigned long long)r->phys_addr, + (unsigned long long)r->len, r->addr); + } + break; + case OPAE_FPGA_NET: + break; + } + + opae_log("==========================\n"); +} + +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) { + if (adapter->mgr) + opae_manager_dump(adapter->mgr); + + opae_adapter_for_each_acc(adapter, acc) + opae_accelerator_dump(acc); + + if (adapter->data) + opae_adapter_data_dump(adapter->data); + } + + opae_log("==========================\n"); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_debug.h b/drivers/raw/ifpga_rawdev/base/opae_debug.h new file mode 100644 index 0000000..a03dff9 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_debug.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_DEBUG_H_ +#define _OPAE_DEBUG_H_ + +#ifdef OPAE_HW_DEBUG +#define opae_log(fmt, args...) printf(fmt, ## args) +#else +#define opae_log(fme, args...) do {} while (0) +#endif + +void opae_manager_dump(struct opae_manager *mgr); +void opae_bridge_dump(struct opae_bridge *br); +void opae_accelerator_dump(struct opae_accelerator *acc); +void opae_adapter_dump(struct opae_adapter *adapter, int verbose); + +#endif /* _OPAE_DEBUG_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c new file mode 100644 index 0000000..a533dfe --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.c @@ -0,0 +1,381 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_hw_api.h" +#include "opae_debug.h" +#include "ifpga_api.h" + +/* OPAE Bridge Functions */ + +/** + * opae_bridge_alloc - alloc opae_bridge data structure + * @name: bridge name. + * @ops: ops of this bridge. + * @data: private data of this bridge. + * + * Return opae_bridge on success, otherwise NULL. + */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data) +{ + struct opae_bridge *br = opae_zmalloc(sizeof(*br)); + + if (!br) + return NULL; + + br->name = name; + br->ops = ops; + br->data = data; + + opae_log("%s %p\n", __func__, br); + + return br; +} + +/** + * opae_bridge_reset - reset opae_bridge + * @br: bridge to be reset. + * + * Return: 0 on success, otherwise error code. + */ +int opae_bridge_reset(struct opae_bridge *br) +{ + if (!br) + return -EINVAL; + + if (br->ops && br->ops->reset) + return br->ops->reset(br); + + opae_log("%s no ops\n", __func__); + + return -ENOENT; +} + +/* Accelerator Functions */ + +/** + * opae_accelerator_alloc - alloc opae_accelerator data structure + * @name: accelerator name. + * @ops: ops of this accelerator. + * @data: private data of this accelerator. + * + * Return: opae_accelerator on success, otherwise NULL. + */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data) +{ + struct opae_accelerator *acc = opae_zmalloc(sizeof(*acc)); + + if (!acc) + return NULL; + + acc->name = name; + acc->ops = ops; + acc->data = data; + + opae_log("%s %p\n", __func__, acc); + + return acc; +} + +/** + * opae_acc_reg_read - read accelerator's register from its reg region. + * @acc: accelerator to read. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: read operation width, e.g 4 byte = 32bit read. + * @data: data to store the value read from the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->read) + return acc->ops->read(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_reg_write - write to accelerator's register from its reg region. + * @acc: accelerator to write. + * @region_idx: reg region index. + * @offset: reg offset. + * @byte: write operation width, e.g 4 byte = 32bit write. + * @data: data stored the value to write to the register. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data) +{ + if (!acc || !data) + return -EINVAL; + + if (acc->ops && acc->ops->write) + return acc->ops->write(acc, region_idx, offset, byte, data); + + return -ENOENT; +} + +/** + * opae_acc_get_info - get information of an accelerator. + * @acc: targeted accelerator + * @info: accelerator info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_info) + return acc->ops->get_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_get_region_info - get information of an accelerator register region. + * @acc: targeted accelerator + * @info: accelerator region info data structure to be filled. + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info) +{ + if (!acc || !info) + return -EINVAL; + + if (acc->ops && acc->ops->get_region_info) + return acc->ops->get_region_info(acc, info); + + return -ENOENT; +} + +/** + * opae_acc_set_irq - set an accelerator's irq. + * @acc: targeted accelerator + * @start: start vector number + * @count: count of vectors to be set from the start vector + * @evtfds: event fds to be notified when corresponding irqs happens + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]) +{ + if (!acc || !acc->data) + return -EINVAL; + + if (start + count <= start) + return -EINVAL; + + if (acc->ops && acc->ops->set_irq) + return acc->ops->set_irq(acc, start, count, evtfds); + + return -ENOENT; +} + +/** + * opae_acc_get_uuid - get accelerator's UUID. + * @acc: targeted accelerator + * @uuid: a pointer to UUID + * + * Return: 0 on success, otherwise error code. + */ +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid) +{ + if (!acc || !uuid) + return -EINVAL; + + if (acc->ops && acc->ops->get_uuid) + return acc->ops->get_uuid(acc, uuid); + + return -ENOENT; +} + +/* Manager Functions */ + +/** + * opae_manager_alloc - alloc opae_manager data structure + * @name: manager name. + * @ops: ops of this manager. + * @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) +{ + struct opae_manager *mgr = opae_zmalloc(sizeof(*mgr)); + + if (!mgr) + return NULL; + + mgr->name = name; + mgr->ops = ops; + mgr->data = data; + + opae_log("%s %p\n", __func__, mgr); + + return mgr; +} + +/** + * opae_manager_flash - flash a reconfiguration image via opae_manager + * @mgr: opae_manager for flash. + * @id: id of target region (accelerator). + * @buf: image data buffer. + * @size: buffer size. + * @status: status to store flash result. + * + * Return: 0 on success, otherwise error code. + */ +int opae_manager_flash(struct opae_manager *mgr, int id, void *buf, u32 size, + u64 *status) +{ + if (!mgr) + return -EINVAL; + + if (mgr && mgr->ops && mgr->ops->flash) + return mgr->ops->flash(mgr, id, buf, size, status); + + return -ENOENT; +} + +/* Adapter Functions */ + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @type: opae_adapter_type. + * + * Return: opae_adapter_data on success, otherwise NULL. + */ +void *opae_adapter_data_alloc(enum opae_adapter_type type) +{ + struct opae_adapter_data *data; + int size; + + switch (type) { + case OPAE_FPGA_PCI: + size = sizeof(struct opae_adapter_data_pci); + break; + case OPAE_FPGA_NET: + size = sizeof(struct opae_adapter_data_net); + break; + default: + size = sizeof(struct opae_adapter_data); + break; + } + + data = opae_zmalloc(size); + if (!data) + return NULL; + + data->type = type; + + return data; +} + +static struct opae_adapter_ops *match_ops(struct opae_adapter *adapter) +{ + struct opae_adapter_data *data; + + if (!adapter || !adapter->data) + return NULL; + + data = adapter->data; + + if (data->type == OPAE_FPGA_PCI) + return &ifpga_adapter_ops; + + return NULL; +} + +/** + * opae_adapter_data_alloc - alloc opae_adapter_data data structure + * @name: adapter name. + * @data: private data of this adapter. + * + * Return: opae_adapter on success, otherwise NULL. + */ +struct opae_adapter *opae_adapter_alloc(const char *name, void *data) +{ + struct opae_adapter *adapter = opae_zmalloc(sizeof(*adapter)); + + if (!adapter) + return NULL; + + TAILQ_INIT(&adapter->acc_list); + adapter->data = data; + adapter->name = name; + adapter->ops = match_ops(adapter); + + return adapter; +} + +/** + * opae_adapter_enumerate - enumerate this adapter + * @adapter: adapter to enumerate. + * + * Return: 0 on success, otherwise error code. + */ +int opae_adapter_enumerate(struct opae_adapter *adapter) +{ + int ret = -ENOENT; + + if (!adapter) + return -EINVAL; + + if (adapter->ops && adapter->ops->enumerate) + ret = adapter->ops->enumerate(adapter); + + if (!ret) + opae_adapter_dump(adapter, 1); + + return ret; +} + +/** + * opae_adapter_destroy - destroy this adapter + * @adapter: adapter to destroy. + * + * destroy things allocated during adapter enumeration. + */ +void opae_adapter_destroy(struct opae_adapter *adapter) +{ + if (adapter && adapter->ops && adapter->ops->destroy) + adapter->ops->destroy(adapter); +} + +/** + * opae_adapter_get_acc - find and return accelerator with matched id + * @adapter: adapter to find the accelerator. + * @acc_id: id (index) of the accelerator. + * + * destroy things allocated during adapter enumeration. + */ +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id) +{ + struct opae_accelerator *acc = NULL; + + if (!adapter) + return NULL; + + opae_adapter_for_each_acc(adapter, acc) + if (acc->index == acc_id) + return acc; + + return NULL; +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h new file mode 100644 index 0000000..4bbc9df --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_hw_api.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_HW_API_H_ +#define _OPAE_HW_API_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/queue.h> + +#include "opae_osdep.h" + +#ifndef PCI_MAX_RESOURCE +#define PCI_MAX_RESOURCE 6 +#endif + +struct opae_adapter; + +enum opae_adapter_type { + OPAE_FPGA_PCI, + OPAE_FPGA_NET, +}; + +/* OPAE Manager Data Structure */ +struct opae_manager_ops; + +/* + * opae_manager has pointer to its parent adapter, as it could be able to manage + * all components on this FPGA device (adapter). If not the case, don't set this + * adapter, which limit opae_manager ops to manager itself. + */ +struct opae_manager { + const char *name; + struct opae_adapter *adapter; + struct opae_manager_ops *ops; + void *data; +}; + +/* FIXME: add more management ops, e.g power/thermal and etc */ +struct opae_manager_ops { + int (*flash)(struct opae_manager *mgr, int id, void *buffer, + u32 size, u64 *status); +}; + +/* OPAE Manager APIs */ +struct opae_manager * +opae_manager_alloc(const char *name, struct opae_manager_ops *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); + +/* OPAE Bridge Data Structure */ +struct opae_bridge_ops; + +/* + * opae_bridge only has pointer to its downstream accelerator. + */ +struct opae_bridge { + const char *name; + int id; + struct opae_accelerator *acc; + struct opae_bridge_ops *ops; + void *data; +}; + +struct opae_bridge_ops { + int (*reset)(struct opae_bridge *br); +}; + +/* OPAE Bridge APIs */ +struct opae_bridge * +opae_bridge_alloc(const char *name, struct opae_bridge_ops *ops, void *data); +int opae_bridge_reset(struct opae_bridge *br); +#define opae_bridge_free(br) opae_free(br) + +/* OPAE Acceleraotr Data Structure */ +struct opae_accelerator_ops; + +/* + * opae_accelerator has pointer to its upstream bridge(port). + * In some cases, if we allow same user to do PR on its own accelerator, then + * set the manager pointer during the enumeration. But in other cases, the PR + * functions only could be done via manager in another module / thread / service + * / application for better protection. + */ +struct opae_accelerator { + TAILQ_ENTRY(opae_accelerator) node; + const char *name; + int index; + struct opae_bridge *br; + struct opae_manager *mgr; + struct opae_accelerator_ops *ops; + void *data; +}; + +struct opae_acc_info { + unsigned int num_regions; + unsigned int num_irqs; +}; + +struct opae_acc_region_info { + u32 flags; +#define ACC_REGION_READ (1 << 0) +#define ACC_REGION_WRITE (1 << 1) +#define ACC_REGION_MMIO (1 << 2) + u32 index; + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_accelerator_ops { + int (*read)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*write)(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + int (*get_info)(struct opae_accelerator *acc, + struct opae_acc_info *info); + int (*get_region_info)(struct opae_accelerator *acc, + struct opae_acc_region_info *info); + int (*set_irq)(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); + int (*get_uuid)(struct opae_accelerator *acc, + struct uuid *uuid); +}; + +/* OPAE accelerator APIs */ +struct opae_accelerator * +opae_accelerator_alloc(const char *name, struct opae_accelerator_ops *ops, + void *data); +#define opae_accelerator_free(acc) opae_free(acc) +int opae_acc_get_info(struct opae_accelerator *acc, struct opae_acc_info *info); +int opae_acc_get_region_info(struct opae_accelerator *acc, + struct opae_acc_region_info *info); +int opae_acc_set_irq(struct opae_accelerator *acc, + u32 start, u32 count, s32 evtfds[]); +int opae_acc_get_uuid(struct opae_accelerator *acc, + struct uuid *uuid); + +static inline struct opae_bridge * +opae_acc_get_br(struct opae_accelerator *acc) +{ + return acc ? acc->br : NULL; +} + +static inline struct opae_manager * +opae_acc_get_mgr(struct opae_accelerator *acc) +{ + return acc ? acc->mgr : NULL; +} + +int opae_acc_reg_read(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); +int opae_acc_reg_write(struct opae_accelerator *acc, unsigned int region_idx, + u64 offset, unsigned int byte, void *data); + +#define opae_acc_reg_read64(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 8, data) +#define opae_acc_reg_write64(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 8, data) +#define opae_acc_reg_read32(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 4, data) +#define opae_acc_reg_write32(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 4, data) +#define opae_acc_reg_read16(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 2, data) +#define opae_acc_reg_write16(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 2, data) +#define opae_acc_reg_read8(acc, region, offset, data) \ + opae_acc_reg_read(acc, region, offset, 1, data) +#define opae_acc_reg_write8(acc, region, offset, data) \ + opae_acc_reg_write(acc, region, offset, 1, data) + +/*for data stream read/write*/ +int opae_acc_data_read(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); +int opae_acc_data_write(struct opae_accelerator *acc, unsigned int flags, + u64 offset, unsigned int byte, void *data); + +/* OPAE Adapter Data Structure */ +struct opae_adapter_data { + enum opae_adapter_type type; +}; + +struct opae_reg_region { + u64 phys_addr; + u64 len; + u8 *addr; +}; + +struct opae_adapter_data_pci { + enum opae_adapter_type type; + u16 device_id; + u16 vendor_id; + struct opae_reg_region region[PCI_MAX_RESOURCE]; + int vfio_dev_fd; /* VFIO device file descriptor */ +}; + +/* FIXME: OPAE_FPGA_NET type */ +struct opae_adapter_data_net { + enum opae_adapter_type type; +}; + +struct opae_adapter_ops { + int (*enumerate)(struct opae_adapter *adapter); + void (*destroy)(struct opae_adapter *adapter); +}; + +TAILQ_HEAD(opae_accelerator_list, opae_accelerator); + +#define opae_adapter_for_each_acc(adatper, acc) \ + TAILQ_FOREACH(acc, &adapter->acc_list, node) + +struct opae_adapter { + const char *name; + struct opae_manager *mgr; + struct opae_accelerator_list acc_list; + struct opae_adapter_ops *ops; + void *data; +}; + +/* OPAE Adapter APIs */ +void *opae_adapter_data_alloc(enum opae_adapter_type type); +#define opae_adapter_data_free(data) opae_free(data) + +struct opae_adapter *opae_adapter_alloc(const char *name, void *data); +#define opae_adapter_free(adapter) opae_free(adapter) + +int opae_adapter_enumerate(struct opae_adapter *adapter); +void opae_adapter_destroy(struct opae_adapter *adapter); +static inline struct opae_manager * +opae_adapter_get_mgr(struct opae_adapter *adapter) +{ + return adapter ? adapter->mgr : NULL; +} + +struct opae_accelerator * +opae_adapter_get_acc(struct opae_adapter *adapter, int acc_id); + +static inline void opae_adapter_add_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_INSERT_TAIL(&adapter->acc_list, acc, node); +} + +static inline void opae_adapter_remove_acc(struct opae_adapter *adapter, + struct opae_accelerator *acc) +{ + TAILQ_REMOVE(&adapter->acc_list, acc, node); +} +#endif /* _OPAE_HW_API_H_*/ diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c new file mode 100644 index 0000000..89c7b49 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.c @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include "opae_ifpga_hw_api.h" +#include "ifpga_api.h" + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_get_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_prop(fme->parent, FEATURE_FIU_ID_FME, 0, prop); +} + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data || !fme_info) + return -EINVAL; + + fme = mgr->data; + + spinlock_lock(&fme->lock); + fme_info->capability = fme->capability; + spinlock_unlock(&fme->lock); + + return 0; +} + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set) +{ + struct ifpga_fme_hw *fme; + + if (!mgr || !mgr->data) + return -EINVAL; + + fme = mgr->data; + + return ifpga_set_irq(fme->parent, FEATURE_FIU_ID_FME, 0, + IFPGA_FME_FEATURE_ID_GLOBAL_ERR, err_irq_set); +} + +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_get_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_prop(port->parent, FEATURE_FIU_ID_PORT, + port->port_id, prop); +} + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !port_info) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + port_info->capability = port->capability; + port_info->num_uafu_irqs = port->num_uafu_irqs; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data || !info) + return -EINVAL; + + /* Only support STP region now */ + if (info->index != PORT_REGION_INDEX_STP) + return -EINVAL; + + port = br->data; + + spinlock_lock(&port->lock); + info->addr = port->stp_addr; + info->size = port->stp_size; + spinlock_unlock(&port->lock); + + return 0; +} + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set) +{ + struct ifpga_port_hw *port; + + if (!br || !br->data) + return -EINVAL; + + port = br->data; + + return ifpga_set_irq(port->parent, FEATURE_FIU_ID_PORT, port->port_id, + IFPGA_PORT_FEATURE_ID_ERROR, err_irq_set); +} diff --git a/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h new file mode 100644 index 0000000..4c2c990 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_ifpga_hw_api.h @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_IFPGA_HW_API_H_ +#define _OPAE_IFPGA_HW_API_H_ + +#include "opae_hw_api.h" + +/** + * struct feature_prop - data structure for feature property + * @feature_id: id of this feature. + * @prop_id: id of this property under this feature. + * @data: property value to set/get. + */ +struct feature_prop { + u64 feature_id; + u64 prop_id; + u64 data; +}; + +#define IFPGA_FIU_ID_FME 0x0 +#define IFPGA_FIU_ID_PORT 0x1 + +#define IFPGA_FME_FEATURE_ID_HEADER 0x0 +#define IFPGA_FME_FEATURE_ID_THERMAL_MGMT 0x1 +#define IFPGA_FME_FEATURE_ID_POWER_MGMT 0x2 +#define IFPGA_FME_FEATURE_ID_GLOBAL_IPERF 0x3 +#define IFPGA_FME_FEATURE_ID_GLOBAL_ERR 0x4 +#define IFPGA_FME_FEATURE_ID_PR_MGMT 0x5 +#define IFPGA_FME_FEATURE_ID_HSSI 0x6 +#define IFPGA_FME_FEATURE_ID_GLOBAL_DPERF 0x7 + +#define IFPGA_PORT_FEATURE_ID_HEADER 0x0 +#define IFPGA_PORT_FEATURE_ID_AFU 0xff +#define IFPGA_PORT_FEATURE_ID_ERROR 0x10 +#define IFPGA_PORT_FEATURE_ID_UMSG 0x11 +#define IFPGA_PORT_FEATURE_ID_UINT 0x12 +#define IFPGA_PORT_FEATURE_ID_STP 0x13 + +/* + * PROP format (TOP + SUB + ID) + * + * (~0x0) means this field is unused. + */ +#define PROP_TOP GENMASK(31, 24) +#define PROP_TOP_UNUSED 0xff +#define PROP_SUB GENMASK(23, 16) +#define PROP_SUB_UNUSED 0xff +#define PROP_ID GENMASK(15, 0) + +#define PROP(_top, _sub, _id) \ + (SET_FIELD(PROP_TOP, _top) | SET_FIELD(PROP_SUB, _sub) |\ + SET_FIELD(PROP_ID, _id)) + +/* FME head feature's properties*/ +#define FME_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define FME_HDR_PROP_PORTS_NUM 0x2 /* RDONLY */ +#define FME_HDR_PROP_CACHE_SIZE 0x3 /* RDONLY */ +#define FME_HDR_PROP_VERSION 0x4 /* RDONLY */ +#define FME_HDR_PROP_SOCKET_ID 0x5 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_ID 0x6 /* RDONLY */ +#define FME_HDR_PROP_BITSTREAM_METADATA 0x7 /* RDONLY */ + +/* FME error reporting feature's properties */ +/* FME error reporting properties format */ +#define ERR_PROP(_top, _id) PROP(_top, 0xff, _id) +#define ERR_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define ERR_PROP_TOP_FME_ERR 0x1 +#define ERR_PROP_ROOT(_id) ERR_PROP(0xff, _id) +#define ERR_PROP_FME_ERR(_id) ERR_PROP(ERR_PROP_TOP_FME_ERR, _id) + +#define FME_ERR_PROP_ERRORS ERR_PROP_FME_ERR(0x1) +#define FME_ERR_PROP_FIRST_ERROR ERR_PROP_FME_ERR(0x2) +#define FME_ERR_PROP_NEXT_ERROR ERR_PROP_FME_ERR(0x3) +#define FME_ERR_PROP_CLEAR ERR_PROP_FME_ERR(0x4) /* WO */ +#define FME_ERR_PROP_REVISION ERR_PROP_ROOT(0x5) +#define FME_ERR_PROP_PCIE0_ERRORS ERR_PROP_ROOT(0x6) /* RW */ +#define FME_ERR_PROP_PCIE1_ERRORS ERR_PROP_ROOT(0x7) /* RW */ +#define FME_ERR_PROP_NONFATAL_ERRORS ERR_PROP_ROOT(0x8) +#define FME_ERR_PROP_CATFATAL_ERRORS ERR_PROP_ROOT(0x9) +#define FME_ERR_PROP_INJECT_ERRORS ERR_PROP_ROOT(0xa) /* RW */ + +/* FME thermal feature's properties */ +#define FME_THERMAL_PROP_THRESHOLD1 0x1 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD2 0x2 /* RW */ +#define FME_THERMAL_PROP_THRESHOLD_TRIP 0x3 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_REACHED 0x4 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD2_REACHED 0x5 /* RDONLY */ +#define FME_THERMAL_PROP_THRESHOLD1_POLICY 0x6 /* RW */ +#define FME_THERMAL_PROP_TEMPERATURE 0x7 /* RDONLY */ +#define FME_THERMAL_PROP_REVISION 0x8 /* RDONLY */ + +/* FME power feature's properties */ +#define FME_PWR_PROP_CONSUMED 0x1 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD1 0x2 /* RW */ +#define FME_PWR_PROP_THRESHOLD2 0x3 /* RW */ +#define FME_PWR_PROP_THRESHOLD1_STATUS 0x4 /* RDONLY */ +#define FME_PWR_PROP_THRESHOLD2_STATUS 0x5 /* RDONLY */ +#define FME_PWR_PROP_RTL 0x6 /* RDONLY */ +#define FME_PWR_PROP_XEON_LIMIT 0x7 /* RDONLY */ +#define FME_PWR_PROP_FPGA_LIMIT 0x8 /* RDONLY */ +#define FME_PWR_PROP_REVISION 0x9 /* RDONLY */ + +/* FME iperf/dperf PROP format */ +#define PERF_PROP_TOP_CACHE 0x1 +#define PERF_PROP_TOP_VTD 0x2 +#define PERF_PROP_TOP_FAB 0x3 +#define PERF_PROP_TOP_UNUSED PROP_TOP_UNUSED +#define PERF_PROP_SUB_UNUSED PROP_SUB_UNUSED + +#define PERF_PROP_ROOT(_id) PROP(0xff, 0xff, _id) +#define PERF_PROP_CACHE(_id) PROP(PERF_PROP_TOP_CACHE, 0xff, _id) +#define PERF_PROP_VTD(_sub, _id) PROP(PERF_PROP_TOP_VTD, _sub, _id) +#define PERF_PROP_VTD_ROOT(_id) PROP(PERF_PROP_TOP_VTD, 0xff, _id) +#define PERF_PROP_FAB(_sub, _id) PROP(PERF_PROP_TOP_FAB, _sub, _id) +#define PERF_PROP_FAB_ROOT(_id) PROP(PERF_PROP_TOP_FAB, 0xff, _id) + +/* FME iperf feature's properties */ +#define FME_IPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_IPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* iperf CACHE properties */ +#define FME_IPERF_PROP_CACHE_FREEZE PERF_PROP_CACHE(0x1) /* RW */ +#define FME_IPERF_PROP_CACHE_READ_HIT PERF_PROP_CACHE(0x2) +#define FME_IPERF_PROP_CACHE_READ_MISS PERF_PROP_CACHE(0x3) +#define FME_IPERF_PROP_CACHE_WRITE_HIT PERF_PROP_CACHE(0x4) +#define FME_IPERF_PROP_CACHE_WRITE_MISS PERF_PROP_CACHE(0x5) +#define FME_IPERF_PROP_CACHE_HOLD_REQUEST PERF_PROP_CACHE(0x6) +#define FME_IPERF_PROP_CACHE_TX_REQ_STALL PERF_PROP_CACHE(0x7) +#define FME_IPERF_PROP_CACHE_RX_REQ_STALL PERF_PROP_CACHE(0x8) +#define FME_IPERF_PROP_CACHE_RX_EVICTION PERF_PROP_CACHE(0x9) +#define FME_IPERF_PROP_CACHE_DATA_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xa) +#define FME_IPERF_PROP_CACHE_TAG_WRITE_PORT_CONTENTION PERF_PROP_CACHE(0xb) +/* iperf VTD properties */ +#define FME_IPERF_PROP_VTD_FREEZE PERF_PROP_VTD_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_HIT PERF_PROP_VTD_ROOT(0x2) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_HIT PERF_PROP_VTD_ROOT(0x3) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_HIT PERF_PROP_VTD_ROOT(0x4) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_HIT PERF_PROP_VTD_ROOT(0x5) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_HIT PERF_PROP_VTD_ROOT(0x6) +#define FME_IPERF_PROP_VTD_SIP_RCC_HIT PERF_PROP_VTD_ROOT(0x7) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_4K_MISS PERF_PROP_VTD_ROOT(0x8) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_2M_MISS PERF_PROP_VTD_ROOT(0x9) +#define FME_IPERF_PROP_VTD_SIP_IOTLB_1G_MISS PERF_PROP_VTD_ROOT(0xa) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L3_MISS PERF_PROP_VTD_ROOT(0xb) +#define FME_IPERF_PROP_VTD_SIP_SLPWC_L4_MISS PERF_PROP_VTD_ROOT(0xc) +#define FME_IPERF_PROP_VTD_SIP_RCC_MISS PERF_PROP_VTD_ROOT(0xd) +#define FME_IPERF_PROP_VTD_PORT_READ_TRANSACTION(n) PERF_PROP_VTD(n, 0xe) +#define FME_IPERF_PROP_VTD_PORT_WRITE_TRANSACTION(n) PERF_PROP_VTD(n, 0xf) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_READ_HIT(n) PERF_PROP_VTD(n, 0x10) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_WRITE_HIT(n) PERF_PROP_VTD(n, 0x11) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_4K_FILL(n) PERF_PROP_VTD(n, 0x12) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_2M_FILL(n) PERF_PROP_VTD(n, 0x13) +#define FME_IPERF_PROP_VTD_PORT_DEVTLB_1G_FILL(n) PERF_PROP_VTD(n, 0x14) +/* iperf FAB properties */ +#define FME_IPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_IPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_IPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_IPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_IPERF_PROP_FAB_PCIE1_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_IPERF_PROP_FAB_PCIE1_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_IPERF_PROP_FAB_PORT_PCIE1_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_IPERF_PROP_FAB_UPI_READ PERF_PROP_FAB_ROOT(0x6) +#define FME_IPERF_PROP_FAB_PORT_UPI_READ(n) PERF_PROP_FAB(n, 0x6) +#define FME_IPERF_PROP_FAB_UPI_WRITE PERF_PROP_FAB_ROOT(0x7) +#define FME_IPERF_PROP_FAB_PORT_UPI_WRITE(n) PERF_PROP_FAB(n, 0x7) +#define FME_IPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x8) +#define FME_IPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x8) +#define FME_IPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x9) +#define FME_IPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x9) +#define FME_IPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0xa) /* RW */ +#define FME_IPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0xa) /* RW */ + +/* FME dperf properties */ +#define FME_DPERF_PROP_CLOCK PERF_PROP_ROOT(0x1) +#define FME_DPERF_PROP_REVISION PERF_PROP_ROOT(0x2) + +/* dperf FAB properties */ +#define FME_DPERF_PROP_FAB_FREEZE PERF_PROP_FAB_ROOT(0x1) /* RW */ +#define FME_DPERF_PROP_FAB_PCIE0_READ PERF_PROP_FAB_ROOT(0x2) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_READ(n) PERF_PROP_FAB(n, 0x2) +#define FME_DPERF_PROP_FAB_PCIE0_WRITE PERF_PROP_FAB_ROOT(0x3) +#define FME_DPERF_PROP_FAB_PORT_PCIE0_WRITE(n) PERF_PROP_FAB(n, 0x3) +#define FME_DPERF_PROP_FAB_MMIO_READ PERF_PROP_FAB_ROOT(0x4) +#define FME_DPERF_PROP_FAB_PORT_MMIO_READ(n) PERF_PROP_FAB(n, 0x4) +#define FME_DPERF_PROP_FAB_MMIO_WRITE PERF_PROP_FAB_ROOT(0x5) +#define FME_DPERF_PROP_FAB_PORT_MMIO_WRITE(n) PERF_PROP_FAB(n, 0x5) +#define FME_DPERF_PROP_FAB_ENABLE PERF_PROP_FAB_ROOT(0x6) /* RW */ +#define FME_DPERF_PROP_FAB_PORT_ENABLE(n) PERF_PROP_FAB(n, 0x6) /* RW */ + +/*PORT hdr feature's properties*/ +#define PORT_HDR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_HDR_PROP_PORTIDX 0x2 /* RDONLY */ +#define PORT_HDR_PROP_LATENCY_TOLERANCE 0x3 /* RDONLY */ +#define PORT_HDR_PROP_AP1_EVENT 0x4 /* RW */ +#define PORT_HDR_PROP_AP2_EVENT 0x5 /* RW */ +#define PORT_HDR_PROP_POWER_STATE 0x6 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_FREQCMD 0x7 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQCNTRCMD 0x8 /* RW */ +#define PORT_HDR_PROP_USERCLK_FREQSTS 0x9 /* RDONLY */ +#define PORT_HDR_PROP_USERCLK_CNTRSTS 0xa /* RDONLY */ + +/*PORT error feature's properties*/ +#define PORT_ERR_PROP_REVISION 0x1 /* RDONLY */ +#define PORT_ERR_PROP_ERRORS 0x2 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_ERROR 0x3 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_LSB 0x4 /* RDONLY */ +#define PORT_ERR_PROP_FIRST_MALFORMED_REQ_MSB 0x5 /* RDONLY */ +#define PORT_ERR_PROP_CLEAR 0x6 /* WRONLY */ + +int opae_manager_ifpga_get_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_manager_ifpga_set_prop(struct opae_manager *mgr, + struct feature_prop *prop); +int opae_bridge_ifpga_get_prop(struct opae_bridge *br, + struct feature_prop *prop); +int opae_bridge_ifpga_set_prop(struct opae_bridge *br, + struct feature_prop *prop); + +/* + * Retrieve information about the fpga fme. + * Driver fills the info in provided struct fpga_fme_info. + */ +struct fpga_fme_info { + u32 capability; /* The capability of FME device */ +#define FPGA_FME_CAP_ERR_IRQ (1 << 0) /* Support fme error interrupt */ +}; + +int opae_manager_ifpga_get_info(struct opae_manager *mgr, + struct fpga_fme_info *fme_info); + +/* Set eventfd information for ifpga FME error interrupt */ +struct fpga_fme_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_manager_ifpga_set_err_irq(struct opae_manager *mgr, + struct fpga_fme_err_irq_set *err_irq_set); + +/* + * Retrieve information about the fpga port. + * Driver fills the info in provided struct fpga_port_info. + */ +struct fpga_port_info { + u32 capability; /* The capability of port device */ +#define FPGA_PORT_CAP_ERR_IRQ (1 << 0) /* Support port error interrupt */ +#define FPGA_PORT_CAP_UAFU_IRQ (1 << 1) /* Support uafu error interrupt */ + u32 num_umsgs; /* The number of allocated umsgs */ + u32 num_uafu_irqs; /* The number of uafu interrupts */ +}; + +int opae_bridge_ifpga_get_info(struct opae_bridge *br, + struct fpga_port_info *port_info); +/* + * Retrieve region information about the fpga port. + * Driver needs to fill the index of struct fpga_port_region_info. + */ +struct fpga_port_region_info { + u32 index; +#define PORT_REGION_INDEX_STP (1 << 1) /* Signal Tap Region */ + u64 size; /* Region Size */ + u8 *addr; /* Base address of the region */ +}; + +int opae_bridge_ifpga_get_region_info(struct opae_bridge *br, + struct fpga_port_region_info *info); + +/* Set eventfd information for ifpga port error interrupt */ +struct fpga_port_err_irq_set { + s32 evtfd; /* Eventfd handler */ +}; + +int opae_bridge_ifpga_set_err_irq(struct opae_bridge *br, + struct fpga_port_err_irq_set *err_irq_set); + +#endif /* _OPAE_IFPGA_HW_API_H_ */ diff --git a/drivers/raw/ifpga_rawdev/base/opae_osdep.h b/drivers/raw/ifpga_rawdev/base/opae_osdep.h new file mode 100644 index 0000000..90f54f7 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/opae_osdep.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OPAE_OSDEP_H +#define _OPAE_OSDEP_H + +#include <string.h> +#include <stdbool.h> + +#ifdef RTE_LIBRTE_EAL +#include "osdep_rte/osdep_generic.h" +#else +#include "osdep_raw/osdep_generic.h" +#endif + +#define __iomem + +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef uint64_t dma_addr_t; + +struct uuid { + u8 b[16]; +}; + +#ifndef LINUX_MACROS +#ifndef BITS_PER_LONG +#define BITS_PER_LONG (__SIZEOF_LONG__ * 8) +#endif +#ifndef BIT +#define BIT(a) (1UL << (a)) +#endif /* BIT */ +#ifndef BIT_ULL +#define BIT_ULL(a) (1ULL << (a)) +#endif /* BIT_ULL */ +#ifndef GENMASK +#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#endif /* GENMASK */ +#ifndef GENMASK_ULL +#define GENMASK_ULL(h, l) (((U64_C(1) << ((h) - (l) + 1)) - 1) << (l)) +#endif /* GENMASK_ULL */ +#endif /* LINUX_MACROS */ + +#define SET_FIELD(m, v) (((v) << (__builtin_ffsll(m) - 1)) & (m)) +#define GET_FIELD(m, v) (((v) & (m)) >> (__builtin_ffsll(m) - 1)) + +#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) +#define pr_info(y, args...) dev_info(0, y, ##args) + +#ifndef WARN_ON +#define WARN_ON(x) do { \ + int ret = !!(x); \ + if (unlikely(ret)) \ + pr_warn("WARN_ON: \"" #x "\" at %s:%d\n", __func__, __LINE__); \ +} while (0) +#endif + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define udelay(x) opae_udelay(x) +#define msleep(x) opae_udelay(1000 * (x)) +#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000)) + +#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 new file mode 100644 index 0000000..895a1d8 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_raw/osdep_generic.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OSDEP_RAW_GENERIC_H +#define _OSDEP_RAW_GENERIC_H + +#define compiler_barrier() (asm volatile ("" : : : "memory")) + +#define io_wmb() compiler_barrier() +#define io_rmb() compiler_barrier() + +static inline uint8_t opae_readb(const volatile void *addr) +{ + uint8_t val; + + val = *(const volatile uint8_t *)addr; + io_rmb(); + return val; +} + +static inline uint16_t opae_readw(const volatile void *addr) +{ + uint16_t val; + + val = *(const volatile uint16_t *)addr; + io_rmb(); + return val; +} + +static inline uint32_t opae_readl(const volatile void *addr) +{ + uint32_t val; + + val = *(const volatile uint32_t *)addr; + io_rmb(); + return val; +} + +static inline uint64_t opae_readq(const volatile void *addr) +{ + uint64_t val; + + val = *(const volatile uint64_t *)addr; + io_rmb(); + return val; +} + +static inline void opae_writeb(uint8_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint8_t *)addr = value; +} + +static inline void opae_writew(uint16_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint16_t *)addr = value; +} + +static inline void opae_writel(uint32_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint32_t *)addr = value; +} + +static inline void opae_writeq(uint64_t value, volatile void *addr) +{ + io_wmb(); + *(volatile uint64_t *)addr = value; +} + +#define opae_free(addr) free(addr) + +#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 new file mode 100644 index 0000000..76902e2 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/base/osdep_rte/osdep_generic.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _OSDEP_RTE_GENERIC_H +#define _OSDEP_RTE_GENERIC_H + +#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_spinlock.h> +#include <rte_log.h> +#include <rte_io.h> +#include <rte_malloc.h> + +#define dev_printf(level, fmt, args...) \ + RTE_LOG(level, PMD, "osdep_rte: " fmt, ## args) + +#define osdep_panic(...) rte_panic(...) + +#define opae_udelay(x) rte_delay_us(x) + +#define opae_readb(addr) rte_read8(addr) +#define opae_readw(addr) rte_read16(addr) +#define opae_readl(addr) rte_read32(addr) +#define opae_readq(addr) rte_read64(addr) +#define opae_writeb(value, addr) rte_write8(value, addr) +#define opae_writew(value, addr) rte_write16(value, addr) +#define opae_writel(value, addr) rte_write32(value, addr) +#define opae_writeq(value, addr) rte_write64(value, addr) + +#define opae_malloc(size) rte_malloc(NULL, size, 0) +#define opae_zmalloc(size) rte_zmalloc(NULL, size, 0) +#define opae_free(addr) rte_free(addr) + +#define ARRAY_SIZE(arr) RTE_DIM(arr) + +#define min(a, b) RTE_MIN(a, b) +#define max(a, b) RTE_MAX(a, b) + +#define spinlock_t rte_spinlock_t +#define spinlock_init(x) rte_spinlock_init(x) +#define spinlock_lock(x) rte_spinlock_lock(x) +#define spinlock_unlock(x) rte_spinlock_unlock(x) + +#endif -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v12 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS Xu, Rosen 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 1/3] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 2/3] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen @ 2018-05-11 8:31 ` Xu, Rosen 2018-05-11 12:11 ` [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS Zhang, Qi Z 3 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-11 8:31 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, Yanglong Wu From: Rosen Xu <rosen.xu@intel.com> Add Intel FPGA BUS Rawdev Driver which is based on librte_rawdev library. Signed-off-by: Rosen Xu <rosen.xu@intel.com> Signed-off-by: Yanglong Wu <yanglong.wu@intel.com> Signed-off-by: Tianfei Zhang <tianfei.zhang@intel.com> Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com> --- MAINTAINERS | 3 + config/common_base | 5 + doc/guides/rawdevs/ifpga_rawdev.rst | 112 ++++ doc/guides/rawdevs/index.rst | 1 + doc/guides/rel_notes/release_18_05.rst | 8 + drivers/raw/Makefile | 1 + drivers/raw/ifpga_rawdev/Makefile | 36 ++ drivers/raw/ifpga_rawdev/ifpga_rawdev.c | 619 +++++++++++++++++++++ drivers/raw/ifpga_rawdev/ifpga_rawdev.h | 37 ++ drivers/raw/ifpga_rawdev/meson.build | 15 + .../ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map | 4 + drivers/raw/meson.build | 2 +- mk/rte.app.mk | 4 +- 13 files changed, 845 insertions(+), 2 deletions(-) create mode 100644 doc/guides/rawdevs/ifpga_rawdev.rst create mode 100644 drivers/raw/ifpga_rawdev/Makefile create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.c create mode 100644 drivers/raw/ifpga_rawdev/ifpga_rawdev.h create mode 100644 drivers/raw/ifpga_rawdev/meson.build create mode 100644 drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map diff --git a/MAINTAINERS b/MAINTAINERS index a872973..61b7a35 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -881,8 +881,11 @@ Rawdev Drivers -------------- Intel FPGA +M: Rosen Xu <rosen.xu@intel.com> M: Tianfei zhang <tianfei.zhang@intel.com> +F: drivers/raw/ifpga_rawdev/ F: drivers/raw/ifpga_rawdev/base/ +F: doc/guides/rawdevs/ifpga_rawdev.rst NXP DPAA2 QDMA M: Nipun Gupta <nipun.gupta@nxp.com> diff --git a/config/common_base b/config/common_base index 49704ad..452e800 100644 --- a/config/common_base +++ b/config/common_base @@ -650,6 +650,11 @@ CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV=n CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV=n # +# Compile PMD for Intel FPGA raw device +# +CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV=y + +# # Compile librte_ring # CONFIG_RTE_LIBRTE_RING=y diff --git a/doc/guides/rawdevs/ifpga_rawdev.rst b/doc/guides/rawdevs/ifpga_rawdev.rst new file mode 100644 index 0000000..d400db6 --- /dev/null +++ b/doc/guides/rawdevs/ifpga_rawdev.rst @@ -0,0 +1,112 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2018 Intel Corporation. + +IFPGA Rawdev Driver +====================== + +FPGA is used more and more widely in Cloud and NFV, one primary reason is +that FPGA not only provides ASIC performance but also it's more flexible +than ASIC. + +FPGA uses Partial Reconfigure (PR) Parts of Bit Stream to achieve its +flexibility. That means one FPGA Device Bit Stream is divided into many Parts +of Bit Stream(each Part of Bit Stream is defined as AFU-Accelerated Function +Unit), and each AFU is a hardware acceleration unit which can be dynamically +reloaded respectively. + +By PR (Partial Reconfiguration) AFUs, one FPGA resources can be time-shared by +different users. FPGA hot upgrade and fault tolerance can be provided easily. + +The SW IFPGA Rawdev Driver (**ifpga_rawdev**) provides a Rawdev driver +that utilizes Intel FPGA Software Stack OPAE(Open Programmable Acceleration +Engine) for FPGA management. + +Implementation details +---------------------- + +Each instance of IFPGA Rawdev Driver is probed by Intel FpgaDev. In coordination +with OPAE share code IFPGA Rawdev Driver provides common FPGA management ops +for FPGA operation, OPAE provides all following operations: +- FPGA PR (Partial Reconfiguration) management +- FPGA AFUs Identifying +- FPGA Thermal Management +- FPGA Power Management +- FPGA Performance reporting +- FPGA Remote Debug + +All configuration parameters are taken by vdev_ifpga_cfg driver. Besides +configuration, vdev_ifpga_cfg driver also hot plugs in IFPGA Bus. + +All of the AFUs of one FPGA may share same PCI BDF and AFUs scan depend on +IFPGA Rawdev Driver so IFPGA Bus takes AFU device scan and AFU drivers probe. +All AFU device driver bind to AFU device by its UUID (Universally Unique +Identifier). + +To avoid unnecessary code duplication and ensure maximum performance, +handling of AFU devices is left to different PMDs; all the design as +summarized by the following block diagram:: + + +---------------------------------------------------------------+ + | Application(s) | + +----------------------------.----------------------------------+ + | + | + +----------------------------'----------------------------------+ + | DPDK Framework (APIs) | + +----------|------------|--------.---------------------|--------+ + / \ | + / \ | + +-------'-------+ +-------'-------+ +--------'--------+ + | Eth PMD | | Crypto PMD | | | + +-------.-------+ +-------.-------+ | | + | | | | + | | | | + +-------'-------+ +-------'-------+ | IFPGA | + | Eth AFU Dev | |Crypto AFU Dev | | Rawdev Driver | + +-------.-------+ +-------.-------+ |(OPAE Share Code)| + | | | | + | | Rawdev | | + +-------'------------------'-------+ Ops | | + | IFPGA Bus | -------->| | + +-----------------.----------------+ +--------.--------+ + | | + Hot-plugin -->| | + | | + +-----------------'------------------+ +--------'--------+ + | vdev_ifpga_cfg driver | | Intel FpgaDev | + +------------------------------------+ +-----------------+ + +Build options +------------- + +- ``CONFIG_RTE_LIBRTE_IFPGA_BUS`` (default ``y``) + + Toggle compilation of IFPGA Bus library. + +- ``CONFIG_RTE_LIBRTE_IFPGA_RAWDEV`` (default ``y``) + + Toggle compilation of the ``ifpga_rawdev`` driver. + +Run-time parameters +------------------- + +This driver is invoked automatically in systems added with Intel FPGA, +but PR and IFPGA Bus scan is trigged by command line using +``--vdev 'ifpga_rawdev_cfg`` EAL option. + +The following device parameters are supported: + +- ``ifpga`` [string] + + Provide a specific Intel FPGA device PCI BDF. Can be provided multiple + times for additional instances. + +- ``port`` [int] + + Each FPGA can provide many channels to PR AFU by software, each channels + is identified by this parameter. + +- ``afu_bts`` [string] + + If null, the AFU Bit Stream has been PR in FPGA, if not forces PR and + identifies AFU Bit Stream file. diff --git a/doc/guides/rawdevs/index.rst b/doc/guides/rawdevs/index.rst index 7769083..7c3bd95 100644 --- a/doc/guides/rawdevs/index.rst +++ b/doc/guides/rawdevs/index.rst @@ -13,3 +13,4 @@ application through rawdev API. dpaa2_cmdif dpaa2_qdma + ifpga_rawdev diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst index 1053311..1257f17 100644 --- a/doc/guides/rel_notes/release_18_05.rst +++ b/doc/guides/rel_notes/release_18_05.rst @@ -214,6 +214,14 @@ New Features the DPDK framework. It provides Intel FPGA Partial Bit Stream AFU(Accelerated Function Unit) scan and drivers prove. +* **Added IFPGA(Intel FPGA) Rawdev Driver.** + + Added a new Rawdev driver called IFPGA(Intel FPGA) Rawdev Driver, which cooperates + with OPAE(Open Programmable Acceleration Engine) share code provides common FPGA + management ops for FPGA operation. + + See the :doc:`../rawdevs/ifpga_rawdev` programmer's guide for more details. + API Changes ----------- diff --git a/drivers/raw/Makefile b/drivers/raw/Makefile index 2eb2787..8e29b4a 100644 --- a/drivers/raw/Makefile +++ b/drivers/raw/Makefile @@ -9,5 +9,6 @@ ifeq ($(CONFIG_RTE_EAL_VFIO)$(CONFIG_RTE_LIBRTE_FSLMC_BUS),yy) DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += dpaa2_cmdif DIRS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += dpaa2_qdma endif +DIRS-$(CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV) += ifpga_rawdev include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/drivers/raw/ifpga_rawdev/Makefile b/drivers/raw/ifpga_rawdev/Makefile new file mode 100644 index 0000000..f3b9d5e --- /dev/null +++ b/drivers/raw/ifpga_rawdev/Makefile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_pmd_ifpga_rawdev.a + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(RTE_SDK)/drivers/bus/ifpga +CFLAGS += -I$(RTE_SDK)/drivers/raw/ifpga_rawdev +LDLIBS += -lrte_eal +LDLIBS += -lrte_rawdev +LDLIBS += -lrte_bus_vdev +LDLIBS += -lrte_kvargs +LDLIBS += -lrte_bus_pci +LDLIBS += -lrte_bus_ifpga + +EXPORT_MAP := rte_pmd_ifpga_rawdev_version.map + +LIBABIVER := 1 + +VPATH += $(SRCDIR)/base + +include $(RTE_SDK)/drivers/raw/ifpga_rawdev/base/Makefile + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV) += ifpga_rawdev.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.c b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c new file mode 100644 index 0000000..030ed1b --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.c @@ -0,0 +1,619 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include <string.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <rte_log.h> +#include <rte_bus.h> +#include <rte_eal_memconfig.h> +#include <rte_malloc.h> +#include <rte_devargs.h> +#include <rte_memcpy.h> +#include <rte_pci.h> +#include <rte_bus_pci.h> +#include <rte_kvargs.h> +#include <rte_alarm.h> + +#include <rte_errno.h> +#include <rte_per_lcore.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_eal.h> +#include <rte_common.h> +#include <rte_bus_vdev.h> + +#include "base/opae_hw_api.h" +#include "rte_rawdev.h" +#include "rte_rawdev_pmd.h" +#include "rte_bus_ifpga.h" +#include "ifpga_common.h" +#include "ifpga_logs.h" +#include "ifpga_rawdev.h" + +int ifpga_rawdev_logtype; + +#define PCI_VENDOR_ID_INTEL 0x8086 +/* PCI Device ID */ +#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 +/* 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 RTE_MAX_RAW_DEVICE 10 + +static const struct rte_pci_id pci_ifpga_map[] = { + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_5_X) }, + { RTE_PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_6_X) }, + { 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) }, + { .vendor_id = 0, /* sentinel */ }, +}; + +static int +ifpga_fill_afu_dev(struct opae_accelerator *acc, + struct rte_afu_device *afu_dev) +{ + struct rte_mem_resource *res = afu_dev->mem_resource; + struct opae_acc_region_info region_info; + struct opae_acc_info info; + unsigned long i; + int ret; + + ret = opae_acc_get_info(acc, &info); + if (ret) + return ret; + + if (info.num_regions > PCI_MAX_RESOURCE) + return -EFAULT; + + afu_dev->num_region = info.num_regions; + + for (i = 0; i < info.num_regions; i++) { + region_info.index = i; + ret = opae_acc_get_region_info(acc, ®ion_info); + if (ret) + return ret; + + if ((region_info.flags & ACC_REGION_MMIO) && + (region_info.flags & ACC_REGION_READ) && + (region_info.flags & ACC_REGION_WRITE)) { + res[i].phys_addr = region_info.phys_addr; + res[i].len = region_info.len; + res[i].addr = region_info.addr; + } else + return -EFAULT; + } + + return 0; +} + +static void +ifpga_rawdev_info_get(struct rte_rawdev *dev, + rte_rawdev_obj_t dev_info) +{ + struct opae_adapter *adapter; + struct opae_accelerator *acc; + struct rte_afu_device *afu_dev; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + if (!dev_info) { + IFPGA_RAWDEV_PMD_ERR("Invalid request"); + return; + } + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return; + + afu_dev = dev_info; + afu_dev->rawdev = dev; + + /* find opae_accelerator and fill info into afu_device */ + opae_adapter_for_each_acc(adapter, acc) { + if (acc->index != afu_dev->id.port) + continue; + + if (ifpga_fill_afu_dev(acc, afu_dev)) { + IFPGA_RAWDEV_PMD_ERR("cannot get info\n"); + return; + } + } +} + +static int +ifpga_rawdev_configure(const struct rte_rawdev *dev, + rte_rawdev_obj_t config) +{ + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + return config ? 0 : 1; +} + +static int +ifpga_rawdev_start(struct rte_rawdev *dev) +{ + int ret = 0; + struct opae_adapter *adapter; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + return ret; +} + +static void +ifpga_rawdev_stop(struct rte_rawdev *dev) +{ + dev->started = 0; +} + +static int +ifpga_rawdev_close(struct rte_rawdev *dev) +{ + return dev ? 0:1; +} + +static int +ifpga_rawdev_reset(struct rte_rawdev *dev) +{ + return dev ? 0:1; +} + +static int +fpga_pr(struct rte_rawdev *raw_dev, u32 port_id, u64 *buffer, u32 size, + u64 *status) +{ + + struct opae_adapter *adapter; + struct opae_manager *mgr; + struct opae_accelerator *acc; + struct opae_bridge *br; + int ret; + + adapter = ifpga_rawdev_get_priv(raw_dev); + if (!adapter) + return -ENODEV; + + mgr = opae_adapter_get_mgr(adapter); + if (!mgr) + return -ENODEV; + + acc = opae_adapter_get_acc(adapter, port_id); + if (!acc) + return -ENODEV; + + br = opae_acc_get_br(acc); + if (!br) + return -ENODEV; + + ret = opae_manager_flash(mgr, port_id, buffer, size, status); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("%s pr error %d\n", __func__, ret); + return ret; + } + + ret = opae_bridge_reset(br); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("%s reset port:%d error %d\n", + __func__, port_id, ret); + return ret; + } + + return ret; +} + +static int +rte_fpga_do_pr(struct rte_rawdev *rawdev, int port_id, + const char *file_name) +{ + struct stat file_stat; + int file_fd; + int ret = 0; + ssize_t buffer_size; + void *buffer; + u64 pr_error; + + if (!file_name) + return -EINVAL; + + file_fd = open(file_name, O_RDONLY); + if (file_fd < 0) { + IFPGA_RAWDEV_PMD_ERR("%s: open file error: %s\n", + __func__, file_name); + IFPGA_RAWDEV_PMD_ERR("Message : %s\n", strerror(errno)); + return -EINVAL; + } + ret = stat(file_name, &file_stat); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("stat on bitstream file failed: %s\n", + file_name); + return -EINVAL; + } + buffer_size = file_stat.st_size; + IFPGA_RAWDEV_PMD_INFO("bitstream file size: %zu\n", buffer_size); + buffer = rte_malloc(NULL, buffer_size, 0); + if (!buffer) { + ret = -ENOMEM; + goto close_fd; + } + + /*read the raw data*/ + if (buffer_size != read(file_fd, (void *)buffer, buffer_size)) { + ret = -EINVAL; + goto free_buffer; + } + + /*do PR now*/ + ret = fpga_pr(rawdev, port_id, buffer, buffer_size, &pr_error); + IFPGA_RAWDEV_PMD_INFO("downloading to device port %d....%s.\n", port_id, + ret ? "failed" : "success"); + if (ret) { + ret = -EINVAL; + goto free_buffer; + } + +free_buffer: + if (buffer) + rte_free(buffer); +close_fd: + close(file_fd); + file_fd = 0; + return ret; +} + +static int +ifpga_rawdev_pr(struct rte_rawdev *dev, + rte_rawdev_obj_t pr_conf) +{ + struct opae_adapter *adapter; + struct rte_afu_pr_conf *afu_pr_conf; + int ret; + struct uuid uuid; + struct opae_accelerator *acc; + + IFPGA_RAWDEV_PMD_FUNC_TRACE(); + + adapter = ifpga_rawdev_get_priv(dev); + if (!adapter) + return -ENODEV; + + if (!pr_conf) + return -EINVAL; + + afu_pr_conf = pr_conf; + + if (afu_pr_conf->pr_enable) { + ret = rte_fpga_do_pr(dev, + afu_pr_conf->afu_id.port, + afu_pr_conf->bs_path); + if (ret) { + IFPGA_RAWDEV_PMD_ERR("do pr error %d\n", ret); + return ret; + } + } + + acc = opae_adapter_get_acc(adapter, afu_pr_conf->afu_id.port); + if (!acc) + return -ENODEV; + + ret = opae_acc_get_uuid(acc, &uuid); + if (ret) + return ret; + + memcpy(&afu_pr_conf->afu_id.uuid.uuid_low, uuid.b, sizeof(u64)); + memcpy(&afu_pr_conf->afu_id.uuid.uuid_high, uuid.b + 8, sizeof(u64)); + + IFPGA_RAWDEV_PMD_INFO("%s: uuid_l=0x%lx, uuid_h=0x%lx\n", __func__, + (unsigned long)afu_pr_conf->afu_id.uuid.uuid_low, + (unsigned long)afu_pr_conf->afu_id.uuid.uuid_high); + + return 0; +} + +static const struct rte_rawdev_ops ifpga_rawdev_ops = { + .dev_info_get = ifpga_rawdev_info_get, + .dev_configure = ifpga_rawdev_configure, + .dev_start = ifpga_rawdev_start, + .dev_stop = ifpga_rawdev_stop, + .dev_close = ifpga_rawdev_close, + .dev_reset = ifpga_rawdev_reset, + + .queue_def_conf = NULL, + .queue_setup = NULL, + .queue_release = NULL, + + .attr_get = NULL, + .attr_set = NULL, + + .enqueue_bufs = NULL, + .dequeue_bufs = NULL, + + .dump = NULL, + + .xstats_get = NULL, + .xstats_get_names = NULL, + .xstats_get_by_name = NULL, + .xstats_reset = NULL, + + .firmware_status_get = NULL, + .firmware_version_get = NULL, + .firmware_load = ifpga_rawdev_pr, + .firmware_unload = NULL, + + .dev_selftest = NULL, +}; + +static int +ifpga_rawdev_create(struct rte_pci_device *pci_dev, + int socket_id) +{ + int ret = 0; + struct rte_rawdev *rawdev = NULL; + struct opae_adapter *adapter = NULL; + struct opae_manager *mgr = NULL; + struct opae_adapter_data_pci *data = NULL; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + int i; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + goto cleanup; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id()); + + /* Allocate device structure */ + rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct opae_adapter), + socket_id); + if (rawdev == NULL) { + IFPGA_RAWDEV_PMD_ERR("Unable to allocate rawdevice"); + ret = -EINVAL; + goto cleanup; + } + + /* alloc OPAE_FPGA_PCI data to register to OPAE hardware level API */ + data = opae_adapter_data_alloc(OPAE_FPGA_PCI); + if (!data) { + ret = -ENOMEM; + goto cleanup; + } + + /* init opae_adapter_data_pci for device specific information */ + for (i = 0; i < PCI_MAX_RESOURCE; i++) { + data->region[i].phys_addr = pci_dev->mem_resource[i].phys_addr; + data->region[i].len = pci_dev->mem_resource[i].len; + data->region[i].addr = pci_dev->mem_resource[i].addr; + } + data->device_id = pci_dev->id.device_id; + data->vendor_id = pci_dev->id.vendor_id; + + /* create a opae_adapter based on above device data */ + adapter = opae_adapter_alloc(pci_dev->device.name, data); + if (!adapter) { + ret = -ENOMEM; + goto free_adapter_data; + } + + rawdev->dev_ops = &ifpga_rawdev_ops; + rawdev->device = &pci_dev->device; + rawdev->driver_name = pci_dev->device.driver->name; + + rawdev->dev_private = adapter; + + /* must enumerate the adapter before use it */ + ret = opae_adapter_enumerate(adapter); + if (ret) + goto free_adapter; + + /* get opae_manager to rawdev */ + mgr = opae_adapter_get_mgr(adapter); + if (mgr) { + /* PF function */ + IFPGA_RAWDEV_PMD_INFO("this is a PF function"); + } + + return ret; + +free_adapter: + if (adapter) + opae_adapter_free(adapter); +free_adapter_data: + if (data) + opae_adapter_data_free(data); +cleanup: + if (rawdev) + rte_rawdev_pmd_release(rawdev); + + return ret; +} + +static int +ifpga_rawdev_destroy(struct rte_pci_device *pci_dev) +{ + int ret; + struct rte_rawdev *rawdev; + char name[RTE_RAWDEV_NAME_MAX_LEN]; + struct opae_adapter *adapter; + + if (!pci_dev) { + IFPGA_RAWDEV_PMD_ERR("Invalid pci_dev of the device!"); + ret = -EINVAL; + return ret; + } + + memset(name, 0, sizeof(name)); + snprintf(name, RTE_RAWDEV_NAME_MAX_LEN, "IFPGA:%x:%02x.%x", + pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function); + + IFPGA_RAWDEV_PMD_INFO("Closing %s on NUMA node %d", + name, rte_socket_id()); + + rawdev = rte_rawdev_pmd_get_named_dev(name); + if (!rawdev) { + IFPGA_RAWDEV_PMD_ERR("Invalid device name (%s)", name); + return -EINVAL; + } + + adapter = ifpga_rawdev_get_priv(rawdev); + if (!adapter) + return -ENODEV; + + opae_adapter_data_free(adapter->data); + opae_adapter_free(adapter); + + /* rte_rawdev_close is called by pmd_release */ + ret = rte_rawdev_pmd_release(rawdev); + if (ret) + IFPGA_RAWDEV_PMD_DEBUG("Device cleanup failed"); + + return ret; +} + +static int +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()); +} + +static int +ifpga_rawdev_pci_remove(struct rte_pci_device *pci_dev) +{ + return ifpga_rawdev_destroy(pci_dev); +} + +static struct rte_pci_driver rte_ifpga_rawdev_pmd = { + .id_table = pci_ifpga_map, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING, + .probe = ifpga_rawdev_pci_probe, + .remove = ifpga_rawdev_pci_remove, +}; + +RTE_PMD_REGISTER_PCI(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_PCI_TABLE(ifpga_rawdev_pci_driver, rte_ifpga_rawdev_pmd); +RTE_PMD_REGISTER_KMOD_DEP(ifpga_rawdev_pci_driver, "* igb_uio | uio_pci_generic | vfio-pci"); + +RTE_INIT(ifpga_rawdev_init_log); +static void +ifpga_rawdev_init_log(void) +{ + ifpga_rawdev_logtype = rte_log_register("driver.raw.init"); + if (ifpga_rawdev_logtype >= 0) + rte_log_set_level(ifpga_rawdev_logtype, RTE_LOG_NOTICE); +} + +static const char * const valid_args[] = { +#define IFPGA_ARG_NAME "ifpga" + IFPGA_ARG_NAME, +#define IFPGA_ARG_PORT "port" + IFPGA_ARG_PORT, +#define IFPGA_AFU_BTS "afu_bts" + IFPGA_AFU_BTS, + NULL +}; + +static int +ifpga_cfg_probe(struct rte_vdev_device *dev) +{ + struct rte_devargs *devargs; + struct rte_kvargs *kvlist = NULL; + int port; + char *name = NULL; + char dev_name[RTE_RAWDEV_NAME_MAX_LEN]; + + devargs = dev->device.devargs; + + kvlist = rte_kvargs_parse(devargs->args, valid_args); + if (!kvlist) { + IFPGA_RAWDEV_PMD_LOG(ERR, "error when parsing param"); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_NAME) == 1) { + if (rte_kvargs_process(kvlist, IFPGA_ARG_NAME, + &rte_ifpga_get_string_arg, &name) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_NAME); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_NAME); + goto end; + } + + if (rte_kvargs_count(kvlist, IFPGA_ARG_PORT) == 1) { + if (rte_kvargs_process(kvlist, + IFPGA_ARG_PORT, + &rte_ifpga_get_integer32_arg, + &port) < 0) { + IFPGA_RAWDEV_PMD_ERR("error to parse %s", + IFPGA_ARG_PORT); + goto end; + } + } else { + IFPGA_RAWDEV_PMD_ERR("arg %s is mandatory for ifpga bus", + IFPGA_ARG_PORT); + goto end; + } + + memset(dev_name, 0, sizeof(dev_name)); + snprintf(dev_name, RTE_RAWDEV_NAME_MAX_LEN, "%d|%s", + port, name); + + rte_eal_hotplug_add(RTE_STR(IFPGA_BUS_NAME), + dev_name, devargs->args); +end: + if (kvlist) + rte_kvargs_free(kvlist); + if (name) + free(name); + + return 0; +} + +static int +ifpga_cfg_remove(struct rte_vdev_device *vdev) +{ + IFPGA_RAWDEV_PMD_INFO("Remove ifpga_cfg %p", + vdev); + + return 0; +} + +static struct rte_vdev_driver ifpga_cfg_driver = { + .probe = ifpga_cfg_probe, + .remove = ifpga_cfg_remove, +}; + +RTE_PMD_REGISTER_VDEV(ifpga_rawdev_cfg, ifpga_cfg_driver); +RTE_PMD_REGISTER_ALIAS(ifpga_rawdev_cfg, ifpga_cfg); +RTE_PMD_REGISTER_PARAM_STRING(ifpga_rawdev_cfg, + "ifpga=<string> " + "port=<int> " + "afu_bts=<path>"); + diff --git a/drivers/raw/ifpga_rawdev/ifpga_rawdev.h b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h new file mode 100644 index 0000000..c7759b8 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/ifpga_rawdev.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _IFPGA_RAWDEV_H_ +#define _IFPGA_RAWDEV_H_ + +extern int ifpga_rawdev_logtype; + +#define IFPGA_RAWDEV_PMD_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, ifpga_rawdev_logtype, "ifgpa: " fmt, \ + ##args) + +#define IFPGA_RAWDEV_PMD_FUNC_TRACE() IFPGA_RAWDEV_PMD_LOG(DEBUG, ">>") + +#define IFPGA_RAWDEV_PMD_DEBUG(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(DEBUG, fmt, ## args) +#define IFPGA_RAWDEV_PMD_INFO(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(INFO, fmt, ## args) +#define IFPGA_RAWDEV_PMD_ERR(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(ERR, fmt, ## args) +#define IFPGA_RAWDEV_PMD_WARN(fmt, args...) \ + IFPGA_RAWDEV_PMD_LOG(WARNING, fmt, ## args) + +enum ifpga_rawdev_device_state { + IFPGA_IDLE, + IFPGA_READY, + IFPGA_ERROR +}; + +static inline struct opae_adapter * +ifpga_rawdev_get_priv(const struct rte_rawdev *rawdev) +{ + return rawdev->dev_private; +} + +#endif /* _IFPGA_RAWDEV_H_ */ diff --git a/drivers/raw/ifpga_rawdev/meson.build b/drivers/raw/ifpga_rawdev/meson.build new file mode 100644 index 0000000..6725687 --- /dev/null +++ b/drivers/raw/ifpga_rawdev/meson.build @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2018 Intel Corporation + +version = 1 + +subdir('base') +objs = [base_objs] + +deps += ['rawdev', 'pci', 'bus_pci', 'kvargs', + 'bus_vdev', 'bus_ifpga'] +sources = files('ifpga_rawdev.c') + +includes += include_directories('base') + +allow_experimental_apis = true diff --git a/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map new file mode 100644 index 0000000..9b9ab1a --- /dev/null +++ b/drivers/raw/ifpga_rawdev/rte_pmd_ifpga_rawdev_version.map @@ -0,0 +1,4 @@ +DPDK_18.05 { + + local: *; +}; diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build index 34dfac4..a61cdcc 100644 --- a/drivers/raw/meson.build +++ b/drivers/raw/meson.build @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright 2018 NXP -drivers = ['skeleton_rawdev', 'dpaa2_cmdif', 'dpaa2_qdma'] +drivers = ['skeleton_rawdev', 'dpaa2_cmdif', 'dpaa2_qdma', 'ifpga_rawdev'] std_deps = ['rawdev'] config_flag_fmt = 'RTE_LIBRTE_PMD_@0@_RAWDEV' driver_name_fmt = 'rte_pmd_@0@' diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 290fdf2..9511f20 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -262,9 +262,11 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV) += -lrte_pmd_dpaa2_cmdif _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV) += -lrte_pmd_dpaa2_qdma 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 +endif # CONFIG_RTE_LIBRTE_IFPGA_BUS endif # CONFIG_RTE_LIBRTE_RAWDEV - endif # !CONFIG_RTE_BUILD_SHARED_LIBS _LDLIBS-y += --no-whole-archive -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS Xu, Rosen ` (2 preceding siblings ...) 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen @ 2018-05-11 12:11 ` Zhang, Qi Z 2018-05-11 13:45 ` Xu, Rosen 2018-05-11 15:12 ` Thomas Monjalon 3 siblings, 2 replies; 149+ messages in thread From: Zhang, Qi Z @ 2018-05-11 12:11 UTC (permalink / raw) To: Xu, Rosen, dev, thomas Cc: Xu, Rosen, Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet > -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > Sent: Friday, May 11, 2018 4:31 PM > To: dev@dpdk.org; thomas@monjalon.net > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS > > From: "Xu, Rosen" <rosen.xu@intel.com> > > Intel FPGA BUS in DPDK > ------------------------- > > This patch set introduces Intel FPGA BUS support in DPDK. > Though opens remains, overall is OK, no objection for merge. Reviewed-by: Qi Zhang <qi.z.zhang@intel.com> ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS 2018-05-11 12:11 ` [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS Zhang, Qi Z @ 2018-05-11 13:45 ` Xu, Rosen 2018-05-11 15:12 ` Thomas Monjalon 1 sibling, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-11 13:45 UTC (permalink / raw) To: Zhang, Qi Z, dev, thomas Cc: Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet Thanks Qi. > -----Original Message----- > From: Zhang, Qi Z > Sent: Friday, May 11, 2018 20:12 > To: Xu, Rosen <rosen.xu@intel.com>; dev@dpdk.org; > thomas@monjalon.net > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: RE: [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS > > > > > -----Original Message----- > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > > Sent: Friday, May 11, 2018 4:31 PM > > To: dev@dpdk.org; thomas@monjalon.net > > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > > Richardson, Bruce <bruce.richardson@intel.com>; > > shreyansh.jain@nxp.com; Yigit, Ferruh <ferruh.yigit@intel.com>; > > Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Tianfei > > <tianfei.zhang@intel.com>; Liu, Song <song.liu@intel.com>; Wu, Hao > > <hao.wu@intel.com>; gaetan.rivet@6wind.com > > Subject: [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS > > > > From: "Xu, Rosen" <rosen.xu@intel.com> > > > > Intel FPGA BUS in DPDK > > ------------------------- > > > > This patch set introduces Intel FPGA BUS support in DPDK. > > > Though opens remains, overall is OK, no objection for merge. > > Reviewed-by: Qi Zhang <qi.z.zhang@intel.com> > > ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS 2018-05-11 12:11 ` [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS Zhang, Qi Z 2018-05-11 13:45 ` Xu, Rosen @ 2018-05-11 15:12 ` Thomas Monjalon 1 sibling, 0 replies; 149+ messages in thread From: Thomas Monjalon @ 2018-05-11 15:12 UTC (permalink / raw) To: Xu, Rosen Cc: dev, Zhang, Qi Z, Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet 11/05/2018 14:11, Zhang, Qi Z: > > From: "Xu, Rosen" <rosen.xu@intel.com> > > > > Intel FPGA BUS in DPDK > > ------------------------- > > > > This patch set introduces Intel FPGA BUS support in DPDK. > > > Though opens remains, overall is OK, no objection for merge. > > Reviewed-by: Qi Zhang <qi.z.zhang@intel.com> Applied, thanks ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH] raw/ifpga/base: fix compile error on ia32 icc compiler 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (15 preceding siblings ...) 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS Xu, Rosen @ 2018-05-14 9:58 ` Xu, Rosen 2018-05-14 10:20 ` De Lara Guarch, Pablo 2018-05-16 13:48 ` [dpdk-dev] [PATCH] drivers/bus/ifpga/: fix Coverity issue Rosen Xu 17 siblings, 1 reply; 149+ messages in thread From: Xu, Rosen @ 2018-05-14 9:58 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, stable From: "Zhang, Tianfei" <tianfei.zhang@intel.com> fix compile error on ia32 icc compiler Fixes: 56bb54ea1bdf ("raw/ifpga: add Intel FPGA bus rawdev driver") Cc: stable@dpdk.org Signed-off-by: Zhang, Tianfei <tianfei.zhang@intel.com> --- drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h index cd114fb..7a39a58 100644 --- a/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h +++ b/drivers/raw/ifpga_rawdev/base/ifpga_feature_dev.h @@ -16,16 +16,20 @@ return &hw->port[port_id]; } -#define ifpga_for_each_feature(hw, feature) \ +#define ifpga_for_each_fme_feature(hw, feature) \ for ((feature) = (hw)->sub_feature; \ (feature) < (hw)->sub_feature + (FME_FEATURE_ID_MAX); (feature)++) +#define ifpga_for_each_port_feature(hw, feature) \ + for ((feature) = (hw)->sub_feature; \ + (feature) < (hw)->sub_feature + (PORT_FEATURE_ID_MAX); (feature)++) + static inline struct feature * get_fme_feature_by_id(struct ifpga_fme_hw *fme, u64 id) { struct feature *feature; - ifpga_for_each_feature(fme, feature) { + ifpga_for_each_fme_feature(fme, feature) { if (feature->id == id) return feature; } @@ -38,7 +42,7 @@ { struct feature *feature; - ifpga_for_each_feature(port, feature) { + ifpga_for_each_port_feature(port, feature) { if (feature->id == id) return feature; } -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH] raw/ifpga/base: fix compile error on ia32 icc compiler 2018-05-14 9:58 ` [dpdk-dev] [PATCH] raw/ifpga/base: fix compile error on ia32 icc compiler Xu, Rosen @ 2018-05-14 10:20 ` De Lara Guarch, Pablo 2018-05-14 10:32 ` Thomas Monjalon 0 siblings, 1 reply; 149+ messages in thread From: De Lara Guarch, Pablo @ 2018-05-14 10:20 UTC (permalink / raw) To: Xu, Rosen, dev, thomas Cc: Xu, Rosen, Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet, stable > -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Xu, Rosen > Sent: Monday, May 14, 2018 10:59 AM > To: dev@dpdk.org; thomas@monjalon.net > Cc: Xu, Rosen <rosen.xu@intel.com>; Zhang, Roy Fan > <roy.fan.zhang@intel.com>; Doherty, Declan <declan.doherty@intel.com>; > Richardson, Bruce <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; > Yigit, Ferruh <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com; stable@dpdk.org > Subject: [dpdk-dev] [PATCH] raw/ifpga/base: fix compile error on ia32 icc > compiler > > From: "Zhang, Tianfei" <tianfei.zhang@intel.com> > > fix compile error on ia32 icc compiler This is also applicable for 64-bit icc compilation. > > Fixes: 56bb54ea1bdf ("raw/ifpga: add Intel FPGA bus rawdev driver") > Cc: stable@dpdk.org No need to cc stable, as this is fixing code from this release. > > Signed-off-by: Zhang, Tianfei <tianfei.zhang@intel.com> Tested-by: Pablo de Lara <oablo.de.lara.guarch@intel.com> ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH] raw/ifpga/base: fix compile error on ia32 icc compiler 2018-05-14 10:20 ` De Lara Guarch, Pablo @ 2018-05-14 10:32 ` Thomas Monjalon 0 siblings, 0 replies; 149+ messages in thread From: Thomas Monjalon @ 2018-05-14 10:32 UTC (permalink / raw) To: Xu, Rosen, Zhang, Tianfei Cc: dev, De Lara Guarch, Pablo, Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Liu, Song, Wu, Hao, gaetan.rivet, stable > > From: "Zhang, Tianfei" <tianfei.zhang@intel.com> > > > > fix compile error on ia32 icc compiler > > This is also applicable for 64-bit icc compilation. > > > > > Fixes: 56bb54ea1bdf ("raw/ifpga: add Intel FPGA bus rawdev driver") > > Cc: stable@dpdk.org > > No need to cc stable, as this is fixing code from this release. > > > > > Signed-off-by: Zhang, Tianfei <tianfei.zhang@intel.com> > > Tested-by: Pablo de Lara <oablo.de.lara.guarch@intel.com> Applied, thanks ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH] drivers/bus/ifpga/: fix Coverity issue 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu ` (16 preceding siblings ...) 2018-05-14 9:58 ` [dpdk-dev] [PATCH] raw/ifpga/base: fix compile error on ia32 icc compiler Xu, Rosen @ 2018-05-16 13:48 ` Rosen Xu 2018-05-21 14:00 ` [dpdk-dev] [dpdk-stable] " Thomas Monjalon 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, 279459 and 279454 Rosen Xu 17 siblings, 2 replies; 149+ messages in thread From: Rosen Xu @ 2018-05-16 13:48 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, stable Fix Coverity issue: 279455, 279459 and 279454 Signed-off-by: Rosen Xu <rosen.xu@intel.com> Fixes: 05fa3d4a6539 ("bus/ifpga: add Intel FPGA bus library") Coverity issue: 279455, 279459 and 279454 Cc: stable@dpdk.org --- drivers/bus/ifpga/ifpga_bus.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c index 45597a1..b324872 100644 --- a/drivers/bus/ifpga/ifpga_bus.c +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -156,27 +156,30 @@ void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) if (rawdev->dev_ops && rawdev->dev_ops->dev_start && rawdev->dev_ops->dev_start(rawdev)) - goto free_dev; + goto end; strlcpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); - if (rawdev->dev_ops->firmware_load && + if (rawdev->dev_ops && + rawdev->dev_ops->firmware_load && rawdev->dev_ops->firmware_load(rawdev, &afu_pr_conf)){ IFPGA_BUS_ERR("firmware load error %d\n", ret); - goto free_dev; + goto end; } afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; afu_dev->id.uuid.uuid_high = afu_pr_conf.afu_id.uuid.uuid_high; + rte_kvargs_free(kvlist); + free(path); return afu_dev; -free_dev: - free(afu_dev); end: if (kvlist) rte_kvargs_free(kvlist); if (path) free(path); + if (afu_dev) + free(afu_dev); return NULL; } @@ -367,7 +370,7 @@ void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) return -EINVAL; afu_dev = RTE_DEV_TO_AFU(dev); - if (!dev) + if (!afu_dev) return -ENOENT; devargs = dev->devargs; -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [dpdk-stable] [PATCH] drivers/bus/ifpga/: fix Coverity issue 2018-05-16 13:48 ` [dpdk-dev] [PATCH] drivers/bus/ifpga/: fix Coverity issue Rosen Xu @ 2018-05-21 14:00 ` Thomas Monjalon 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, 279459 and 279454 Rosen Xu 1 sibling, 0 replies; 149+ messages in thread From: Thomas Monjalon @ 2018-05-21 14:00 UTC (permalink / raw) To: Rosen Xu Cc: stable, dev, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet 16/05/2018 15:48, Rosen Xu: > Fix Coverity issue: 279455, 279459 and 279454 > > Signed-off-by: Rosen Xu <rosen.xu@intel.com> > > Fixes: 05fa3d4a6539 ("bus/ifpga: add Intel FPGA bus library") > Coverity issue: 279455, 279459 and 279454 > Cc: stable@dpdk.org The commit message should explain what was the issue. FYI, it should look like this: " bus/ifpga: fix <scope of the change> <explanation of the issue> Coverity issue: 279455, 279459, 279454 Fixes: 05fa3d4a6539 ("bus/ifpga: add Intel FPGA bus library") Cc: stable@dpdk.org Signed-off-by: Rosen Xu <rosen.xu@intel.com> " ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, 279459 and 279454 2018-05-16 13:48 ` [dpdk-dev] [PATCH] drivers/bus/ifpga/: fix Coverity issue Rosen Xu 2018-05-21 14:00 ` [dpdk-dev] [dpdk-stable] " Thomas Monjalon @ 2018-05-22 10:26 ` Rosen Xu 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 1/3] bus/ifpga: fix error control flow issue Rosen Xu ` (3 more replies) 1 sibling, 4 replies; 149+ messages in thread From: Rosen Xu @ 2018-05-22 10:26 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet This patch set fix bus/ifpga coverity issue: 279455, 279459 and 279454 v2 updates: =========== - Add more description, devide to 3 patches v1 updates: =========== - Fix Coverity issue: 279455, 279459 and 279454 Rosen Xu (3): bus/ifpga: fix error control flow issue bus/ifpga: fix resource leaks issue bus/ifpga: fix null pointer dereferences issue drivers/bus/ifpga/ifpga_bus.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v2 1/3] bus/ifpga: fix error control flow issue 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, 279459 and 279454 Rosen Xu @ 2018-05-22 10:26 ` Rosen Xu 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 2/3] bus/ifpga: fix resource leaks issue Rosen Xu ` (2 subsequent siblings) 3 siblings, 0 replies; 149+ messages in thread From: Rosen Xu @ 2018-05-22 10:26 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, stable The control variable should be afu_dev not dev. Coverity issue: 279455 Fixes: 05fa3d4a6539 ("bus/ifpga: add Intel FPGA bus library") Cc: stable@dpdk.org Signed-off-by: Rosen Xu <rosen.xu@intel.com> --- drivers/bus/ifpga/ifpga_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c index 45597a1..675b9a3 100644 --- a/drivers/bus/ifpga/ifpga_bus.c +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -367,7 +367,7 @@ void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) return -EINVAL; afu_dev = RTE_DEV_TO_AFU(dev); - if (!dev) + if (!afu_dev) return -ENOENT; devargs = dev->devargs; -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v2 2/3] bus/ifpga: fix resource leaks issue 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, 279459 and 279454 Rosen Xu 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 1/3] bus/ifpga: fix error control flow issue Rosen Xu @ 2018-05-22 10:26 ` Rosen Xu 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 3/3] bus/ifpga: fix null pointer dereferences issue Rosen Xu 2018-05-22 15:15 ` [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, 279459 and 279454 Thomas Monjalon 3 siblings, 0 replies; 149+ messages in thread From: Rosen Xu @ 2018-05-22 10:26 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, stable There are some resource leaks in ifpga_scan_one. This patch fixes it. Coverity issue: 279459 Fixes: 05fa3d4a6539 ("bus/ifpga: add Intel FPGA bus library") Cc: stable@dpdk.org Signed-off-by: Rosen Xu <rosen.xu@intel.com> --- drivers/bus/ifpga/ifpga_bus.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c index 675b9a3..db16173 100644 --- a/drivers/bus/ifpga/ifpga_bus.c +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -156,27 +156,29 @@ void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) if (rawdev->dev_ops && rawdev->dev_ops->dev_start && rawdev->dev_ops->dev_start(rawdev)) - goto free_dev; + goto end; strlcpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); if (rawdev->dev_ops->firmware_load && rawdev->dev_ops->firmware_load(rawdev, &afu_pr_conf)){ IFPGA_BUS_ERR("firmware load error %d\n", ret); - goto free_dev; + goto end; } afu_dev->id.uuid.uuid_low = afu_pr_conf.afu_id.uuid.uuid_low; afu_dev->id.uuid.uuid_high = afu_pr_conf.afu_id.uuid.uuid_high; + rte_kvargs_free(kvlist); + free(path); return afu_dev; -free_dev: - free(afu_dev); end: if (kvlist) rte_kvargs_free(kvlist); if (path) free(path); + if (afu_dev) + free(afu_dev); return NULL; } -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* [dpdk-dev] [PATCH v2 3/3] bus/ifpga: fix null pointer dereferences issue 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, 279459 and 279454 Rosen Xu 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 1/3] bus/ifpga: fix error control flow issue Rosen Xu 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 2/3] bus/ifpga: fix resource leaks issue Rosen Xu @ 2018-05-22 10:26 ` Rosen Xu 2018-05-22 15:15 ` [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, 279459 and 279454 Thomas Monjalon 3 siblings, 0 replies; 149+ messages in thread From: Rosen Xu @ 2018-05-22 10:26 UTC (permalink / raw) To: dev, thomas Cc: rosen.xu, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet, stable Fix ifpga_scan_one() null pointer dereferences issue. Coverity issue: 279454 Fixes: 05fa3d4a6539 ("bus/ifpga: add Intel FPGA bus library") Cc: stable@dpdk.org Signed-off-by: Rosen Xu <rosen.xu@intel.com> --- drivers/bus/ifpga/ifpga_bus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c index db16173..b324872 100644 --- a/drivers/bus/ifpga/ifpga_bus.c +++ b/drivers/bus/ifpga/ifpga_bus.c @@ -159,7 +159,8 @@ void rte_ifpga_driver_unregister(struct rte_afu_driver *driver) goto end; strlcpy(afu_pr_conf.bs_path, path, sizeof(afu_pr_conf.bs_path)); - if (rawdev->dev_ops->firmware_load && + if (rawdev->dev_ops && + rawdev->dev_ops->firmware_load && rawdev->dev_ops->firmware_load(rawdev, &afu_pr_conf)){ IFPGA_BUS_ERR("firmware load error %d\n", ret); -- 1.8.3.1 ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, 279459 and 279454 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, 279459 and 279454 Rosen Xu ` (2 preceding siblings ...) 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 3/3] bus/ifpga: fix null pointer dereferences issue Rosen Xu @ 2018-05-22 15:15 ` Thomas Monjalon 2018-05-23 0:26 ` Xu, Rosen 3 siblings, 1 reply; 149+ messages in thread From: Thomas Monjalon @ 2018-05-22 15:15 UTC (permalink / raw) To: Rosen Xu Cc: dev, roy.fan.zhang, declan.doherty, bruce.richardson, shreyansh.jain, ferruh.yigit, konstantin.ananyev, tianfei.zhang, song.liu, hao.wu, gaetan.rivet > Rosen Xu (3): > bus/ifpga: fix error control flow issue > bus/ifpga: fix resource leaks issue > bus/ifpga: fix null pointer dereferences issue Applied, thanks ^ permalink raw reply [flat|nested] 149+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, 279459 and 279454 2018-05-22 15:15 ` [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, 279459 and 279454 Thomas Monjalon @ 2018-05-23 0:26 ` Xu, Rosen 0 siblings, 0 replies; 149+ messages in thread From: Xu, Rosen @ 2018-05-23 0:26 UTC (permalink / raw) To: Thomas Monjalon Cc: dev, Zhang, Roy Fan, Doherty, Declan, Richardson, Bruce, shreyansh.jain, Yigit, Ferruh, Ananyev, Konstantin, Zhang, Tianfei, Liu, Song, Wu, Hao, gaetan.rivet Thanks a lot Thomas. > -----Original Message----- > From: Thomas Monjalon [mailto:thomas@monjalon.net] > Sent: Tuesday, May 22, 2018 23:16 > To: Xu, Rosen <rosen.xu@intel.com> > Cc: dev@dpdk.org; Zhang, Roy Fan <roy.fan.zhang@intel.com>; Doherty, > Declan <declan.doherty@intel.com>; Richardson, Bruce > <bruce.richardson@intel.com>; shreyansh.jain@nxp.com; Yigit, Ferruh > <ferruh.yigit@intel.com>; Ananyev, Konstantin > <konstantin.ananyev@intel.com>; Zhang, Tianfei <tianfei.zhang@intel.com>; > Liu, Song <song.liu@intel.com>; Wu, Hao <hao.wu@intel.com>; > gaetan.rivet@6wind.com > Subject: Re: [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, > 279459 and 279454 > > > Rosen Xu (3): > > bus/ifpga: fix error control flow issue > > bus/ifpga: fix resource leaks issue > > bus/ifpga: fix null pointer dereferences issue > > Applied, thanks > > ^ permalink raw reply [flat|nested] 149+ messages in thread
end of thread, other threads:[~2018-05-23 0:26 UTC | newest] Thread overview: 149+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2018-03-20 13:45 [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Rosen Xu 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 1/5] Add Intel FPGA BUS Command Parse Code Rosen Xu 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 2/5] Add Intel FPGA BUS Probe Code Rosen Xu 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 3/5] Add Intel FPGA BUS Lib Code Rosen Xu 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 4/5] Add Intel FPGA BUS Rawdev Code Rosen Xu 2018-03-20 13:45 ` [dpdk-dev] [PATCH V1 5/5] Add Intel OPAE Share Code Rosen Xu 2018-03-20 14:58 ` [dpdk-dev] [PATCH V1 0/5] Introduce Intel FPGA BUS Gaëtan Rivet 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 0/6] " Rosen Xu 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 1/6] Add Intel FPGA BUS Command Parse Code Rosen Xu 2018-03-28 13:26 ` Gaëtan Rivet 2018-03-31 16:25 ` Xu, Rosen 2018-04-04 1:58 ` Xu, Rosen 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 2/6] config/common_base: Add Intel FPGA Build Configuration Macro Rosen Xu 2018-03-28 13:27 ` Gaëtan Rivet 2018-03-31 16:26 ` Xu, Rosen 2018-04-04 2:01 ` Xu, Rosen 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 3/6] mk/rte.app.mk: Add Intel FPGA Bus Build Configuration Macro To App Script Rosen Xu 2018-03-28 13:28 ` Gaëtan Rivet 2018-03-31 16:27 ` Xu, Rosen 2018-04-04 2:02 ` Xu, Rosen 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 4/6] drivers/bus: Add Intel FPGA Bus Lib Code Rosen Xu 2018-03-28 13:52 ` Gaëtan Rivet 2018-03-31 16:31 ` Xu, Rosen 2018-04-02 4:25 ` Xu, Rosen 2018-04-02 4:31 ` Xu, Rosen 2018-04-04 4:01 ` Xu, Rosen 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 5/6] drivers/raw/ifpga_rawdev: Add Intel FPGA Rawdev Driver Code Rosen Xu 2018-03-28 9:29 ` [dpdk-dev] [PATCH v3 6/6] drivers/raw/ifpga_rawdev: Add Intel FPGA OPAE Share Code Rosen Xu 2018-03-28 9:37 ` [dpdk-dev] [PATCH v3 0/6] Introduce Intel FPGA BUS Bruce Richardson 2018-03-28 13:17 ` Gaëtan Rivet 2018-03-28 16:15 ` Zhang, Tianfei 2018-04-04 1:57 ` Xu, Rosen 2018-03-31 16:02 ` [dpdk-dev] [PATCH v4 0/3] " Rosen Xu 2018-03-31 16:03 ` [dpdk-dev] [PATCH v4 1/3] Add Intel FPGA BUS Lib Code Rosen Xu 2018-04-03 9:25 ` Shreyansh Jain 2018-04-04 1:44 ` Xu, Rosen 2018-03-31 16:03 ` [dpdk-dev] [PATCH v4 2/3] Add Intel FPGA BUS Rawdev Driver Rosen Xu 2018-04-03 9:34 ` Shreyansh Jain 2018-04-04 1:49 ` Xu, Rosen 2018-04-04 11:31 ` Shreyansh Jain 2018-04-26 10:47 ` Xu, Rosen 2018-03-31 16:03 ` [dpdk-dev] [PATCH v4 3/3] Add Intel FPGA OPAE Share Code Rosen Xu 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS Rosen Xu 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 1/3] Add Intel FPGA BUS Library Rosen Xu 2018-04-04 9:55 ` Bruce Richardson 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 2/3] Add Intel FPGA BUS Rawdev Driver Rosen Xu 2018-04-04 6:51 ` [dpdk-dev] [PATCH v5 3/3] Add Intel FPGA OPAE Share Code Rosen Xu 2018-04-04 11:59 ` Hemant Agrawal 2018-04-26 10:45 ` Xu, Rosen 2018-04-04 10:14 ` [dpdk-dev] [PATCH v5 0/3] Introduce Intel FPGA BUS Shreyansh Jain 2018-04-04 10:38 ` Richardson, Bruce 2018-04-04 11:11 ` Shreyansh Jain 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 0/5] " Xu, Rosen 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 1/5] iFPGA: Add Intel FPGA BUS Library Xu, Rosen 2018-05-02 13:14 ` Shreyansh Jain 2018-05-02 13:33 ` Zhang, Tianfei 2018-05-03 3:58 ` Tan, Jianfeng 2018-05-03 8:12 ` Tan, Jianfeng 2018-05-03 8:35 ` Zhang, Tianfei 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 2/5] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2018-05-04 9:14 ` Shreyansh Jain 2018-05-04 9:04 ` Zhang, Tianfei 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 4/5] iFPGA: add meson build Xu, Rosen 2018-05-02 9:46 ` Shreyansh Jain 2018-05-02 13:36 ` Zhang, Tianfei 2018-05-03 9:13 ` Shreyansh Jain 2018-05-03 15:12 ` Zhang, Tianfei 2018-04-26 9:43 ` [dpdk-dev] [PATCH v6 5/5] iFPGA: add document for iFPGA driver Xu, Rosen 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 0/5] Introduce Intel FPGA BUS Xu, Rosen 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 1/5] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen 2018-05-04 14:10 ` [dpdk-dev] [PATCH v7 2/5] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen 2018-05-04 14:11 ` [dpdk-dev] [PATCH v7 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2018-05-05 18:42 ` Shreyansh Jain 2018-05-06 0:28 ` Zhang, Tianfei 2018-05-05 19:09 ` Shreyansh Jain 2018-05-06 0:52 ` Zhang, Tianfei 2018-05-04 14:11 ` [dpdk-dev] [PATCH v7 4/5] iFPGA: add meson build Xu, Rosen 2018-05-05 18:21 ` Shreyansh Jain 2018-05-06 0:27 ` Zhang, Tianfei 2018-05-04 14:11 ` [dpdk-dev] [PATCH v7 5/5] iFPGA: add document for iFPGA driver Xu, Rosen 2018-05-05 19:19 ` Shreyansh Jain 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 0/5] Introduce Intel FPGA BUS Xu, Rosen 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 1/5] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 2/5] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 3/5] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 4/5] iFPGA: add meson build Xu, Rosen 2018-05-06 8:40 ` [dpdk-dev] [PATCH v8 5/5] iFPGA: add document for iFPGA driver Xu, Rosen 2018-05-06 11:54 ` Shreyansh Jain 2018-05-06 14:24 ` Zhang, Tianfei 2018-05-08 14:18 ` [dpdk-dev] [PATCH v9 0/4] Introduce Intel FPGA BUS Xu, Rosen 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 1/4] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen 2018-05-08 14:42 ` Thomas Monjalon 2018-05-09 1:25 ` Xu, Rosen 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 2/4] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen 2018-05-08 14:45 ` Thomas Monjalon 2018-05-09 1:24 ` Xu, Rosen 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 3/4] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2018-05-08 14:19 ` [dpdk-dev] [PATCH v9 4/4] iFPGA: add document for iFPGA driver Xu, Rosen 2018-05-08 14:49 ` Thomas Monjalon 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 0/3] Introduce Intel FPGA BUS Xu, Rosen 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 1/3] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen 2018-05-10 8:43 ` Wu, Jingjing 2018-05-10 12:20 ` Xu, Rosen 2018-05-10 22:39 ` Wu, Jingjing 2018-05-11 3:18 ` Xu, Rosen 2018-05-10 12:26 ` Zhang, Qi Z 2018-05-10 13:29 ` Xu, Rosen 2018-05-10 13:48 ` Zhang, Qi Z 2018-05-10 13:58 ` Xu, Rosen 2018-05-10 14:11 ` Zhang, Qi Z 2018-05-10 13:51 ` Xu, Rosen 2018-05-10 13:58 ` Zhang, Qi Z 2018-05-10 14:49 ` Thomas Monjalon 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 2/3] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen 2018-05-09 7:43 ` [dpdk-dev] [PATCH v10 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2018-05-09 14:47 ` Thomas Monjalon 2018-05-09 15:33 ` Zhang, Tianfei 2018-05-09 15:37 ` Bruce Richardson 2018-05-09 15:57 ` Zhang, Tianfei 2018-05-10 13:31 ` Xu, Rosen 2018-05-10 9:21 ` Wu, Jingjing 2018-05-10 13:16 ` Xu, Rosen 2018-05-11 3:21 ` Xu, Rosen 2018-05-10 14:24 ` Zhang, Qi Z 2018-05-11 3:16 ` Xu, Rosen 2018-05-11 5:36 ` Zhang, Qi Z 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 0/3] Introduce Intel FPGA BUS Xu, Rosen 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 1/3] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 2/3] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen 2018-05-10 14:00 ` [dpdk-dev] [PATCH v11 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS Xu, Rosen 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 1/3] bus/ifpga: Add Intel FPGA BUS Library Xu, Rosen 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 2/3] iFPGA: Add Intel FPGA OPAE Share Code Xu, Rosen 2018-05-11 8:31 ` [dpdk-dev] [PATCH v12 3/3] iFPGA: Add Intel FPGA BUS Rawdev Driver Xu, Rosen 2018-05-11 12:11 ` [dpdk-dev] [PATCH v12 0/3] Introduce Intel FPGA BUS Zhang, Qi Z 2018-05-11 13:45 ` Xu, Rosen 2018-05-11 15:12 ` Thomas Monjalon 2018-05-14 9:58 ` [dpdk-dev] [PATCH] raw/ifpga/base: fix compile error on ia32 icc compiler Xu, Rosen 2018-05-14 10:20 ` De Lara Guarch, Pablo 2018-05-14 10:32 ` Thomas Monjalon 2018-05-16 13:48 ` [dpdk-dev] [PATCH] drivers/bus/ifpga/: fix Coverity issue Rosen Xu 2018-05-21 14:00 ` [dpdk-dev] [dpdk-stable] " Thomas Monjalon 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, 279459 and 279454 Rosen Xu 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 1/3] bus/ifpga: fix error control flow issue Rosen Xu 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 2/3] bus/ifpga: fix resource leaks issue Rosen Xu 2018-05-22 10:26 ` [dpdk-dev] [PATCH v2 3/3] bus/ifpga: fix null pointer dereferences issue Rosen Xu 2018-05-22 15:15 ` [dpdk-dev] [PATCH v2 0/3] Fix bus/ifpga coverity issue: 279455, 279459 and 279454 Thomas Monjalon 2018-05-23 0:26 ` Xu, Rosen
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).