From patchwork Fri Jul 10 22:26:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chautru, Nicolas" X-Patchwork-Id: 73785 X-Patchwork-Delegate: gakhil@marvell.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 92E66A052A; Sat, 11 Jul 2020 00:28:11 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 7C5551DA18; Sat, 11 Jul 2020 00:28:04 +0200 (CEST) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by dpdk.org (Postfix) with ESMTP id 05BAD1D9B7 for ; Sat, 11 Jul 2020 00:28:01 +0200 (CEST) IronPort-SDR: UXnz6irJdsRuP3FRssbzQFiFhLCio4ALmIScWTnWr23y2f3CC/rDu2+S2rV1HVg5qPXgxUj6Ew DPEclKz/Df4Q== X-IronPort-AV: E=McAfee;i="6000,8403,9678"; a="145806450" X-IronPort-AV: E=Sophos;i="5.75,336,1589266800"; d="scan'208";a="145806450" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Jul 2020 15:28:00 -0700 IronPort-SDR: WUGTQX/olX4+WcXgQLmh7/z6SZpTnOKCJBqE50XsNcMX/XxLO1Ii+OKiSmUdLO/SLQTf7Zg87w Zjpcy4ERn4MQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.75,336,1589266800"; d="scan'208";a="298562033" Received: from skx-5gnr-sc12-4.sc.intel.com ([172.25.69.210]) by orsmga002.jf.intel.com with ESMTP; 10 Jul 2020 15:27:59 -0700 From: Nicolas Chautru To: dev@dpdk.org, akhil.goyal@nxp.com, thomas@monjalon.net Cc: Nicolas Chautru Date: Fri, 10 Jul 2020 15:26:06 -0700 Message-Id: <1594419966-230753-2-git-send-email-nicolas.chautru@intel.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1594419966-230753-1-git-send-email-nicolas.chautru@intel.com> References: <1594419966-230753-1-git-send-email-nicolas.chautru@intel.com> Subject: [dpdk-dev] [PATCH v1] baseband/fpga_5gnr_fec: add companion PF config App X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Adding companion application to configure HW Device from the PF. Then the device can be accessed through BBDEV from VF (or PF). Signed-off-by: Nicolas Chautru --- doc/guides/bbdevs/fpga_5gnr_fec.rst | 81 +++-- .../baseband/fpga_5gnr_fec/pf_config_app/Makefile | 36 ++ .../fpga_5gnr_fec/pf_config_app/config_app.c | 382 +++++++++++++++++++++ .../pf_config_app/fpga_5gnr_cfg_app.c | 351 +++++++++++++++++++ .../pf_config_app/fpga_5gnr_cfg_app.h | 102 ++++++ .../pf_config_app/fpga_5gnr_cfg_parser.c | 187 ++++++++++ .../pf_config_app/fpga_5gnr_config.cfg | 18 + 7 files changed, 1137 insertions(+), 20 deletions(-) create mode 100644 drivers/baseband/fpga_5gnr_fec/pf_config_app/Makefile create mode 100644 drivers/baseband/fpga_5gnr_fec/pf_config_app/config_app.c create mode 100644 drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_cfg_app.c create mode 100644 drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_cfg_app.h create mode 100644 drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_cfg_parser.c create mode 100644 drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_config.cfg diff --git a/doc/guides/bbdevs/fpga_5gnr_fec.rst b/doc/guides/bbdevs/fpga_5gnr_fec.rst index 19bba36..b9333e3 100644 --- a/doc/guides/bbdevs/fpga_5gnr_fec.rst +++ b/doc/guides/bbdevs/fpga_5gnr_fec.rst @@ -218,33 +218,74 @@ parameters defined in ``fpga_5gnr_fec_conf`` structure: time_out = flr_time_out x 16.384us. For instance, if you want to set 10ms for the FLR time out then set this setting to 0x262=610. +A companion application pf_config_app is provided as a standalone application +described in next section. -An example configuration code calling the function ``fpga_5gnr_fec_configure()`` is shown -below: +PF Config App +------------- -.. code-block:: c +The PF Configuration Application ``pf_config_app`` provides a means to +configure the baseband device at the host-level. The program sets the various +parameters through memory-mapped IO read/writes. Then the BBDEV driver can be +used to run the workload. + +The parameters are parsed from a given configuration file (with .cfg extentions) +that is specific to particular BBDEV device, although they follow same format. + +External Dependencies +~~~~~~~~~~~~~~~~~~~~~ + +The third party .INI parser is a pre-requisite for building the application. +It can be downloaded from [github]: + +.. code-block:: console - struct fpga_5gnr_fec_conf conf; - unsigned int i; + git clone https://github.com/benhoyt/inih - memset(&conf, 0, sizeof(struct fpga_5gnr_fec_conf)); - conf.pf_mode_en = 1; +Use the version release 44 tracked by tag 'r44': + +.. code-block:: console + + git checkout r44 + +The application features a makefile in the `extra/` directory which generates +the library, `libinih.a`. To compile the inih library, run make as: + +.. code-block:: console + + make -f Makefile.static + +Building PF Config App +~~~~~~~~~~~~~~~~~~~~~~ + +Before building the application, set the following environment variables with +the location where the INI library is located: + +.. code-block:: console + + export INIH_PATH= + +If not set, makefile will look into current folder. + +Next, build the program by typing ``make`` from the pf_Config_app subdirectory +to produce the binary ``pf_config_app_fpga_5gnr``. + +Usage +~~~~~ + +The application executes as the following: + +.. code-block:: console - for (i = 0; i < FPGA_5GNR_FEC_NUM_VFS; ++i) { - conf.vf_ul_queues_number[i] = 4; - conf.vf_dl_queues_number[i] = 4; - } - conf.ul_bandwidth = 12; - conf.dl_bandwidth = 5; - conf.dl_load_balance = 64; - conf.ul_load_balance = 64; + ./pf_config_app_fpga_5gnr [-h] [-a] [-c CFG_FILE] [-f NUM_VFS] [-p PCI_ID] - /* setup FPGA PF */ - ret = fpga_5gnr_fec_configure(info->dev_name, &conf); - TEST_ASSERT_SUCCESS(ret, - "Failed to configure 4G FPGA PF for bbdev %s", - info->dev_name); +* ``-c CFG_FILE``: Specifies configuration file to use +* ``-f NUM_VFS``: Specifies number of Virtual Functions to enable through SRIOV +* ``-p PCI_ID``: Specifies PCI ID of device to configure +* ``-a``: Configures all PCI devices +* ``-h``: Prints help +Default configure file is provided: ``fpga_5gnr_config.cfg``. Test Application ---------------- diff --git a/drivers/baseband/fpga_5gnr_fec/pf_config_app/Makefile b/drivers/baseband/fpga_5gnr_fec/pf_config_app/Makefile new file mode 100644 index 0000000..dfd0b6d --- /dev/null +++ b/drivers/baseband/fpga_5gnr_fec/pf_config_app/Makefile @@ -0,0 +1,36 @@ + +CC=gcc +CFLAGS=-O0 -g -Wall +ODIR=build +DEPS= + +ifeq ($(INIH_PATH),) +INCLUDE=-I. +LDFLAGS=-L. +else +INCLUDE=-I. -I$(INIH_PATH) +LDFLAGS=-L. -L$(INIH_PATH) +endif + +LDLIBS=-linih + +SRC = config_app.c fpga_5gnr_cfg_app.c fpga_5gnr_cfg_parser.c +OBJ = $(patsubst %.c,$(ODIR)/%.o,$(SRC)) + +.PHONY: clean + +all: pf_config_app + +$(ODIR): + mkdir -p $(ODIR) + +$(OBJ): $(ODIR)/%.o: ./%.c | $(DEPS) $(ODIR) + @mkdir -p $(@D) + $(CC) -c -o $@ $< $(CFLAGS) $(INCLUDE) + +pf_config_app: $(OBJ) + $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) $(LDLIBS) + +clean: + rm -rf $(ODIR) + rm -rf pf_config_app diff --git a/drivers/baseband/fpga_5gnr_fec/pf_config_app/config_app.c b/drivers/baseband/fpga_5gnr_fec/pf_config_app/config_app.c new file mode 100644 index 0000000..61036fc --- /dev/null +++ b/drivers/baseband/fpga_5gnr_fec/pf_config_app/config_app.c @@ -0,0 +1,382 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fpga_5gnr_cfg_app.h" + +#define SYS_DIR "/sys/bus/pci/devices" +#define CUR_DIR "." +#define PREV_DIR ".." + +#define DRIVER_LINK "driver" +#define DEVICE_FILE "device" +#define VENDOR_FILE "vendor" +#define BAR0_FILE "resource0" +#define MAX_VFS_FILE "max_vfs" + +#define PCI_STR_SIZE 15 +#define DEV_STR_SIZE 10 +#define NULL_PAD 2 + +/* Function Pointer for device specific configuration file */ +typedef int (*configuration)(void *bar0addr, const char *arg_cfg_filename); + +typedef struct hw_device { + const char *device_name; + char *config_file; + int vendor_id; + int device_id; + char pci_address[PCI_STR_SIZE]; + bool driver_found; + configuration conf; + char *num_vfs; + int config_all; +} hw_device; + +static int +enable_vfs(const char *pci_addr, char *num_vfs) +{ + char maxvfspath[PATH_MAX]; + char fs_num_vfs[4] = {0, 0, 0, 0}; + int maxvfsfd; + + snprintf(maxvfspath, sizeof(maxvfspath), + "%s/%s/%s", SYS_DIR, pci_addr, MAX_VFS_FILE); + maxvfsfd = open(maxvfspath, O_RDWR | O_SYNC); + + if (maxvfsfd < 0) { + printf("Unable to enable VFs. Was device bound under igb_uio?\n"); + return -1; + } + + /* read current num of VFs */ + read(maxvfsfd, (void *)fs_num_vfs, 3); + strtok(fs_num_vfs, "\n"); + + if (!strncmp(fs_num_vfs, num_vfs, 3)) { + /* value is same */ + close(maxvfsfd); + return 0; + } + + /* update num of VFs */ + write(maxvfsfd, "0", 1); + write(maxvfsfd, num_vfs, strlen(num_vfs)); + close(maxvfsfd); + + return 0; +} + +static void * +get_bar0_mapping(const char *pci_addr, unsigned int bar_size) +{ + char bar0path[PATH_MAX]; + int bar0addrfd; + void *map; + + snprintf(bar0path, sizeof(bar0path), + "%s/%s/%s", SYS_DIR, pci_addr, BAR0_FILE); + bar0addrfd = open(bar0path, O_RDWR | O_SYNC); + if (bar0addrfd < 0) { + printf("\nFailed to open BAR %s\n", bar0path); + exit(1); + } + map = mmap(0, bar_size, PROT_READ | PROT_WRITE, MAP_SHARED, + bar0addrfd, 0); + close(bar0addrfd); + return map; +} + +static unsigned long +get_file_val(const char *file_path) +{ + char content[BUFSIZ]; + FILE *f; + + f = fopen(file_path, "r"); + if (f == NULL) { + printf("\nFailed to open %s\n", file_path); + exit(1); + } + if (fgets(content, sizeof(content), f) == NULL) { + fclose(f); + return false; + } + fclose(f); + const unsigned long content_val = strtoul(content, NULL, 16); + + return content_val; +} + +static bool +get_device_id(hw_device *device, const char *location) +{ + unsigned long vendor_id = -1, device_id = -1; + struct dirent *dirent; + DIR *dir; + char pci_path[PATH_MAX]; + + snprintf(pci_path, sizeof(pci_path), "%s/%s", SYS_DIR, location); + dir = opendir(pci_path); + if (dir == NULL) { + printf("Failed to open %s (%s)\n", pci_path, strerror(errno)); + return false; + } + + while ((dirent = readdir(dir)) != NULL) { + char file_path[PATH_MAX]; + + /* Omit Current Directory & Previous Directory Lookup */ + if (strncmp(dirent->d_name, CUR_DIR, + strlen(dirent->d_name)) == 0 || + strncmp(dirent->d_name, PREV_DIR, + strlen(dirent->d_name)) == 0) + continue; + + /* Set filepath as next PCI folder (xxxx:xx:xx.x) */ + snprintf(file_path, sizeof(file_path), "%s/%s", + pci_path, dirent->d_name); + + /* Get Device ID */ + if (strncmp(dirent->d_name, DEVICE_FILE, + strlen(dirent->d_name)) == 0 && + dirent->d_type == DT_REG) + device_id = get_file_val(file_path); + + /* Get Vendor ID */ + if (strncmp(dirent->d_name, VENDOR_FILE, + strlen(dirent->d_name)) == 0 && + dirent->d_type == DT_REG) + vendor_id = get_file_val(file_path); + } + + closedir(dir); + /* Check if device is found */ + return (vendor_id == device->vendor_id && + device_id == device->device_id); +} + +static int +probe_pci_bus(hw_device *device, char **found_devices) +{ + struct dirent *dirent; + DIR *dir; + int num_devices = 0; + + /* Locate PCI Devices */ + dir = opendir(SYS_DIR); + if (dir == NULL) + return -1; + + /* Iterate Through Directories */ + while ((dirent = readdir(dir)) != NULL) { + + /* Omit Current Directory and Previous Directory Lookup */ + if (strncmp(dirent->d_name, CUR_DIR, + strlen(dirent->d_name)) == 0 || + strncmp(dirent->d_name, PREV_DIR, + strlen(dirent->d_name)) == 0) + continue; + /* Check if current device matches requested device */ + if (get_device_id(device, dirent->d_name)) { + found_devices[num_devices] = + (char *) malloc(PCI_STR_SIZE); + /* Copy PCI slot of device */ + strncpy(found_devices[num_devices], dirent->d_name, + sizeof(device->pci_address) - NULL_PAD); + num_devices++; + } + } + + return num_devices; +} + +static int +match_device(char *pci_address, char **found_devices, int num_devices) +{ + int i; + for (i = 0; i < num_devices; i++) { + if (!strncmp(pci_address, found_devices[i], + sizeof(pci_address) - NULL_PAD)) + return 0; + } + + printf("Given PCI ID is not available\n"); + return -1; +} + +static int +select_device(hw_device *device, char **found_devices, int num_devices) +{ + int i, selected; + /* If more than one device found, get user input on which to use */ + if (num_devices >= 2) { + printf("More than one device found. Please select which device you would like to use from the list:\n"); + + /*Print PCI Slots */ + for (i = 0; i < num_devices; i++) + printf("[%i]: %s\n", i+1, found_devices[i]); + + printf("> "); + scanf("%d", &selected); + if (selected >= 1 && selected <= num_devices) { + strncpy(device->pci_address, found_devices[selected-1], + sizeof(device->pci_address) - NULL_PAD); + return 0; + } + + printf("Invalid Option, please try again..\n"); + return -1; + } + + strncpy(device->pci_address, found_devices[0], + sizeof(device->pci_address) - NULL_PAD); + return 0; +} + +void set_device(hw_device *device) +{ + device->vendor_id = FPGA_5GNR_FEC_VENDOR_ID; + device->device_id = FPGA_5GNR_FEC_DEVICE_ID; + device->conf = fpga_5gnr_configure; + if (device->config_file == NULL) { + device->config_file = getenv("FPGA_5GNR_CONFIG_FILE"); + if (device->config_file == NULL) + device->config_file = "fpga_5gnr_config.cfg"; + } +} + +static void +print_helper(const char *prgname) +{ + printf("Usage: %s [-h] [-a] [-c CFG_FILE] [-f NUM_VFS] [-p PCI_ID]\n\n" + " -c CFG_FILE \t specifies configuration file to use\n" + " -f NUM_VFS \t specifies number of Virtual Functions to enable through SRIOV\n" + " -p PCI_ID \t specifies PCI ID of device to configure\n" + " -a \t\t configures all PCI devices matching the given DEVICE_NAME\n" + " -h \t\t prints this helper\n\n", prgname); +} + +static int +parse_args(int argc, char **argv, + struct hw_device *device) +{ + int opt; + char *prgname = argv[0]; + device->device_name = FPGA_5GNR_FEC_DEV_NAME; + + while ((opt = getopt(argc, argv, "c:f:p:ah")) != -1) { + switch (opt) { + case 'c': + device->config_file = optarg; + break; + case 'f': + device->num_vfs = optarg; + break; + case 'p': + strncpy(device->pci_address, optarg, + sizeof(device->pci_address) + - NULL_PAD); + break; + case 'a': + device->config_all = 1; + break; + case 'h': + default: + print_helper(prgname); + return 1; + } + } + return 0; +} + +static int +configure_device(hw_device *device) +{ + /* Get BAR0 Mapping for device */ + void *bar0addr = get_bar0_mapping(device->pci_address, + FPGA_5GNR_FEC_BAR_SIZE); + + if (device->num_vfs != 0) + if (enable_vfs(device->pci_address, device->num_vfs) < 0) + return -1; + + /* Call device specific configuration function */ + if (device->conf(bar0addr, device->config_file) == 0) { + + if (device->num_vfs != 0) + printf("Enabled %s %s VFs\n", + device->num_vfs, device->device_name); + + printf("%s PF [%s] configuration complete!\n\n", + device->device_name, device->pci_address + - NULL_PAD); + return 0; + } + printf("Configuration error!!\n"); + return -1; +} + +int +main(int argc, char *argv[]) +{ + int i, num_devices; + hw_device device; + char *found_devices[DEV_STR_SIZE]; + + memset(&device, 0, sizeof(device)); + + if (parse_args(argc, argv, &device) > 0) + return 0; + + /* Set Device Info */ + set_device(&device); + /* Check if device is installed */ + num_devices = probe_pci_bus(&device, found_devices); + if (num_devices == 0) { + printf("No devices found!!\n"); + return -1; + } else if (num_devices < 0) { + return num_devices; + } + + if (device.pci_address[0] != 0) { + if (match_device(device.pci_address, found_devices, + num_devices) < 0) + return -1; + } + + if (device.config_all) { + for (i = 0; i < num_devices; i++) { + strncpy(device.pci_address, found_devices[i], + sizeof(device.pci_address) - NULL_PAD); + configure_device(&device); + } + } else { + select_device(&device, found_devices, num_devices); + configure_device(&device); + } + + /* Free memory for stored PCI slots */ + for (i = 0; i < num_devices; i++) + free(found_devices[i]); + + return 0; +} diff --git a/drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_cfg_app.c b/drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_cfg_app.c new file mode 100644 index 0000000..ac01722 --- /dev/null +++ b/drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_cfg_app.c @@ -0,0 +1,351 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "fpga_5gnr_cfg_app.h" + +extern int +fpga_5gnr_parse_conf_file(const char *file_name, + struct fpga_5gnr_fec_conf *fpga_conf); + +/* Read 8-bit register of FPGA 5GNR FEC device */ +static uint8_t +fpga_reg_read_8(void *mmio_base, uint32_t offset) +{ + void *reg_addr = mmio_base + offset; + return *((volatile uint8_t *)(reg_addr)); +} + +/* Read 16-bit register of FPGA 5GNR FEC device */ +static uint16_t +fpga_reg_read_16(void *mmio_base, uint32_t offset) +{ + void *reg_addr = mmio_base + offset; + uint16_t ret = *((volatile uint16_t *)(reg_addr)); +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return __bswap_16(ret); +#else + return ret; +#endif +} + +/* Read 32-bit register of FPGA 5GNR FEC device */ +static uint32_t +fpga_reg_read_32(void *mmio_base, uint32_t offset) +{ + void *reg_addr = mmio_base + offset; + uint32_t ret = *((volatile uint32_t *)(reg_addr)); +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return __bswap_32(ret); +#else + return ret; +#endif +} + +static inline void +fpga_reg_write_16(void *mmio_base, uint32_t offset, + uint16_t payload) { + void *reg_addr = mmio_base + offset; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + payload = __bswap_16(payload); +#endif + *((volatile uint16_t *) (reg_addr)) = payload; +} + +static inline void +fpga_reg_write_32(void *mmio_base, uint32_t offset, + uint32_t payload) +{ + void *reg_addr = mmio_base + offset; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + payload = __bswap_32(payload); +#endif + *((volatile uint32_t *) (reg_addr)) = payload; +} + +static inline void +set_default_fpga_conf(struct fpga_5gnr_fec_conf *def_conf) +{ + /* Set pf mode to true */ + def_conf->pf_mode_en = true; + + /* Set ratio between UL and DL to 1:1 (unit of weight is 3 CBs) */ + def_conf->ul_bandwidth = 3; + def_conf->dl_bandwidth = 3; + + /* Set Load Balance Factor to 64 */ + def_conf->dl_load_balance = 64; + def_conf->ul_load_balance = 64; +} + +static int +fpga_read_config_file(const char *arg_cfg_filename, + struct fpga_5gnr_fec_conf *fpga_5gnr_fec_conf) +{ + const char *cfg_filename; + + if (arg_cfg_filename == NULL) { + cfg_filename = getenv(FPGA_5GNR_FEC_CONFIG_FILE_ENV); + if (cfg_filename == NULL) { + cfg_filename = FPGA_5GNR_FEC_CONFIG_FILE_NAME; + printf("'%s' was not set. %s will be used\n", + FPGA_5GNR_FEC_CONFIG_FILE_NAME, + cfg_filename); + } else + printf("'%s=%s' config file will be used\n", + FPGA_5GNR_FEC_CONFIG_FILE_ENV, + cfg_filename); + } else + cfg_filename = arg_cfg_filename; + + return fpga_5gnr_parse_conf_file(cfg_filename, fpga_5gnr_fec_conf); +} + +/* Read Static Register of FPGA 5GNR FEC device */ +static inline void +print_static_reg_debug_info(void *mmio_base) +{ + uint8_t i, q_id; + uint32_t fid; + uint32_t version_id = fpga_reg_read_32(mmio_base, + FPGA_5GNR_FEC_VERSION_ID); + uint16_t config = fpga_reg_read_16(mmio_base, + FPGA_5GNR_FEC_CONFIGURATION); + uint8_t qmap_done = fpga_reg_read_8(mmio_base, + FPGA_5GNR_FEC_QUEUE_PF_VF_MAP_DONE); + uint16_t lb_factor = fpga_reg_read_16(mmio_base, + FPGA_5GNR_FEC_LOAD_BALANCE_FACTOR); + uint16_t ring_desc_len = fpga_reg_read_16(mmio_base, + FPGA_5GNR_FEC_RING_DESC_LEN); + uint16_t flr_time_out = fpga_reg_read_16(mmio_base, + FPGA_5GNR_FEC_FLR_TIME_OUT); + + printf("FEC FPGA RTL v%u.%u\n", + ((uint16_t)(version_id >> 16)), ((uint16_t)version_id)); + printf("UL.DL Weights = %u.%u\n", + ((uint8_t)config), ((uint8_t)(config >> 8))); + printf("UL.DL Load Balance = %u.%u\n", + ((uint8_t)lb_factor), ((uint8_t)(lb_factor >> 8))); + printf("Queue-PF/VF Mapping Table = %s\n", + (qmap_done > 0) ? "READY" : "NOT-READY"); + printf("Ring Descriptor Size = %u bytes\n", + ring_desc_len*FPGA_RING_DESC_LEN_UNIT_BYTES); + printf("FLR Timeout = %f usec\n", + (float)flr_time_out*FPGA_FLR_TIMEOUT_UNIT); + + printf("\n--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+\n"); + printf(" | PF | VF0 | VF1 | VF2 | VF3 | VF4 | VF5 | VF6 | VF7 |\n"); + printf("--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+\n"); + + for (q_id = 0; q_id < FPGA_TOTAL_NUM_QUEUES; q_id++) { + + printf("%s-Q'%02u |", + (q_id < FPGA_NUM_UL_QUEUES) ? "UL" : "DL", q_id); + + fid = fpga_reg_read_32(mmio_base, + FPGA_5GNR_FEC_QUEUE_MAP + (q_id << 2)); + + for (i = 0; i < 9; ++i) { + + if (!((fid >> 16) & (0x80)) && i == 0) { + printf(" X |"); + continue; + } + + if (((((fid >> 16) & (0x7f)) + 1) == i) && + ((fid >> 16) & (0x80))) + printf(" X |"); + else + printf(" |"); + } + printf("\n"); + } + printf("--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+\n\n"); +} + +static int +fpga_write_config(void *mapaddr, struct fpga_5gnr_fec_conf *conf) +{ + + uint32_t payload_32, address; + uint16_t payload_16; + uint16_t q_id, vf_id, total_q_id, total_ul_q_id, total_dl_q_id; + + uint32_t *bar0addr = mapaddr; + + /* + * Configure UL:DL ratio. + * [7:0]: UL weight + * [15:8]: DL weight + */ + payload_16 = (conf->dl_bandwidth << 8) | conf->ul_bandwidth; + address = FPGA_5GNR_FEC_CONFIGURATION; + fpga_reg_write_16(bar0addr, address, payload_16); + + /* Clear all queues registers */ + payload_32 = FPGA_INVALID_HW_QUEUE_ID; + for (q_id = 0; q_id < FPGA_TOTAL_NUM_QUEUES; ++q_id) { + address = (q_id << 2) + FPGA_5GNR_FEC_QUEUE_MAP; + fpga_reg_write_32(bar0addr, address, payload_32); + } + + /* + * If PF mode is enabled allocate all queues for PF only. + * + * For VF mode each VF can have different number of UL and DL queues. + * Total number of queues to configure cannot exceed FPGA + * capabilities - 64 queues - 32 queues for UL and 32 queues for DL. + * Queues mapping is done according to configuration: + * + * UL queues: + * | Q_ID | VF_ID | + * | 0 | 0 | + * | ... | 0 | + * | conf->vf_dl_queues_number[0] - 1 | 0 | + * | conf->vf_dl_queues_number[0] | 1 | + * | ... | 1 | + * | conf->vf_dl_queues_number[1] - 1 | 1 | + * | ... | ... | + * | conf->vf_dl_queues_number[7] - 1 | 7 | + * + * DL queues: + * | Q_ID | VF_ID | + * | 32 | 0 | + * | ... | 0 | + * | conf->vf_ul_queues_number[0] - 1 | 0 | + * | conf->vf_ul_queues_number[0] | 1 | + * | ... | 1 | + * | conf->vf_ul_queues_number[1] - 1 | 1 | + * | ... | ... | + * | conf->vf_ul_queues_number[7] - 1 | 7 | + * + * Example of configuration: + * conf->vf_ul_queues_number[0] = 4; -> 4 UL queues for VF0 + * conf->vf_dl_queues_number[0] = 4; -> 4 DL queues for VF0 + * conf->vf_ul_queues_number[1] = 2; -> 2 UL queues for VF1 + * conf->vf_dl_queues_number[1] = 2; -> 2 DL queues for VF1 + * + * UL: + * | Q_ID | VF_ID | + * | 0 | 0 | + * | 1 | 0 | + * | 2 | 0 | + * | 3 | 0 | + * | 4 | 1 | + * | 5 | 1 | + * + * DL: + * | Q_ID | VF_ID | + * | 32 | 0 | + * | 33 | 0 | + * | 34 | 0 | + * | 35 | 0 | + * | 36 | 1 | + * | 37 | 1 | + */ + if (conf->pf_mode_en) { + payload_32 = 0x1; + for (q_id = 0; q_id < FPGA_TOTAL_NUM_QUEUES; ++q_id) { + address = (q_id << 2) + FPGA_5GNR_FEC_QUEUE_MAP; + fpga_reg_write_32(bar0addr, address, payload_32); + } + } else { + /* Calculate total number of UL and DL queues to configure */ + total_ul_q_id = total_dl_q_id = 0; + for (vf_id = 0; vf_id < FPGA_5GNR_FEC_NUM_VFS; ++vf_id) { + total_ul_q_id += conf->vf_ul_queues_number[vf_id]; + total_dl_q_id += conf->vf_dl_queues_number[vf_id]; + } + total_q_id = total_dl_q_id + total_ul_q_id; + /* + * Check if total number of queues to configure does not exceed + * FPGA capabilities (64 queues - 32 UL and 32 DL queues) + */ + if ((total_ul_q_id > FPGA_NUM_UL_QUEUES) || + (total_dl_q_id > FPGA_NUM_DL_QUEUES) || + (total_q_id > FPGA_TOTAL_NUM_QUEUES)) { + printf( + "FPGA Configuration failed. Too many queues to configure: UL_Q %u, DL_Q %u, FPGA_Q %u", + total_ul_q_id, total_dl_q_id, + FPGA_TOTAL_NUM_QUEUES); + return -EINVAL; + } + total_ul_q_id = 0; + for (vf_id = 0; vf_id < FPGA_5GNR_FEC_NUM_VFS; ++vf_id) { + for (q_id = 0; q_id < conf->vf_ul_queues_number[vf_id]; + ++q_id, ++total_ul_q_id) { + address = (total_ul_q_id << 2) + + FPGA_5GNR_FEC_QUEUE_MAP; + payload_32 = ((0x80 + vf_id) << 16) | 0x1; + fpga_reg_write_32(bar0addr, address, + payload_32); + } + } + total_dl_q_id = 0; + for (vf_id = 0; vf_id < FPGA_5GNR_FEC_NUM_VFS; ++vf_id) { + for (q_id = 0; q_id < conf->vf_dl_queues_number[vf_id]; + ++q_id, ++total_dl_q_id) { + address = ((total_dl_q_id + FPGA_NUM_UL_QUEUES) + << 2) + FPGA_5GNR_FEC_QUEUE_MAP; + payload_32 = ((0x80 + vf_id) << 16) | 0x1; + fpga_reg_write_32(bar0addr, address, + payload_32); + } + } + } + + /* Setting Load Balance Factor */ + payload_16 = (conf->dl_load_balance << 8) | (conf->ul_load_balance); + address = FPGA_5GNR_FEC_LOAD_BALANCE_FACTOR; + fpga_reg_write_16(bar0addr, address, payload_16); + + /* Setting length of ring descriptor entry */ + payload_16 = FPGA_RING_DESC_ENTRY_LENGTH; + address = FPGA_5GNR_FEC_RING_DESC_LEN; + fpga_reg_write_16(bar0addr, address, payload_16); + + /* Setting FLR timeout value */ + payload_16 = conf->flr_time_out; + address = FPGA_5GNR_FEC_FLR_TIME_OUT; + fpga_reg_write_16(bar0addr, address, payload_16); + + /* Queue PF/VF mapping table is ready */ + payload_16 = 0x1; + address = FPGA_5GNR_FEC_QUEUE_PF_VF_MAP_DONE; + fpga_reg_write_16(bar0addr, address, payload_16); + + print_static_reg_debug_info(bar0addr); + printf("Mode of operation = %s-mode\n", + conf->pf_mode_en ? "PF" : "VF"); + + return 0; +} + +int +fpga_5gnr_configure(void *bar0addr, const char *cfg_filename) +{ + struct fpga_5gnr_fec_conf fpga_conf; + int ret; + + ret = fpga_read_config_file(cfg_filename, &fpga_conf); + if (ret != 0) { + printf("Error reading config file.\n"); + return -1; + } + + ret = fpga_write_config(bar0addr, &fpga_conf); + if (ret != 0) { + printf("Error writing configuration for FPGA.\n"); + return -1; + } + + return 0; +} diff --git a/drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_cfg_app.h b/drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_cfg_app.h new file mode 100644 index 0000000..f7ab8e1 --- /dev/null +++ b/drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_cfg_app.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#ifndef _FPGA_5GNR_CFG_APP_H_ +#define _FPGA_5GNR_CFG_APP_H_ + +#include +#include +#include +#include +#include +#include +#include + +/**< Number of Virtual Functions FGPA 5GNR FEC supports */ +#define FPGA_5GNR_FEC_NUM_VFS 8 +#define FPGA_5GNR_FEC_VENDOR_ID 0x8086 +#define FPGA_5GNR_FEC_DEVICE_ID 0x0D8F +#define FPGA_5GNR_FEC_BAR_SIZE 0x1000 +#define FPGA_5GNR_FEC_DEV_NAME "FPGA_5GNR_FEC" +#define FPGA_5GNR_FEC_CONFIG_FILE_ENV "FPGA_5GNR_FEC_CONFIG_FILE" +#define FPGA_5GNR_FEC_CONFIG_FILE_NAME "fpga_5gnr_fec_config.cfg" + +/* Multiplier of 256 bits (32 bytes) */ +#define FPGA_RING_DESC_ENTRY_LENGTH (8) +#define FPGA_RING_DESC_LEN_UNIT_BYTES (32) +/* Maximum size of queue */ +#define FPGA_RING_MAX_SIZE (1024) +#define FPGA_FLR_TIMEOUT_UNIT (16.384) + +#define FPGA_NUM_UL_QUEUES (32) +#define FPGA_NUM_DL_QUEUES (32) +#define FPGA_TOTAL_NUM_QUEUES (FPGA_NUM_UL_QUEUES + FPGA_NUM_DL_QUEUES) + +#define FPGA_INVALID_HW_QUEUE_ID (0xFFFFFFFF) + +/* FPGA 5GNR FEC Register mapping on BAR0 */ +enum { + FPGA_5GNR_FEC_VERSION_ID = 0x00000000, /* len: 4B */ + FPGA_5GNR_FEC_CONFIGURATION = 0x00000004, /* len: 2B */ + FPGA_5GNR_FEC_QUEUE_PF_VF_MAP_DONE = 0x00000008, /* len: 1B */ + FPGA_5GNR_FEC_LOAD_BALANCE_FACTOR = 0x0000000a, /* len: 2B */ + FPGA_5GNR_FEC_RING_DESC_LEN = 0x0000000c, /* len: 2B */ + FPGA_5GNR_FEC_FLR_TIME_OUT = 0x0000000e, /* len: 2B */ + FPGA_5GNR_FEC_VFQ_FLUSH_STATUS_LW = 0x00000018, /* len: 4B */ + FPGA_5GNR_FEC_VFQ_FLUSH_STATUS_HI = 0x0000001c, /* len: 4B */ + FPGA_5GNR_FEC_QUEUE_MAP = 0x00000040, /* len: 256B */ + FPGA_5GNR_FEC_RING_CTRL_REGS = 0x00000200, /* len: 2048B */ + FPGA_5GNR_FEC_DDR4_WR_ADDR_REGS = 0x00000A00, /* len: 4B */ + FPGA_5GNR_FEC_DDR4_WR_DATA_REGS = 0x00000A08, /* len: 8B */ + FPGA_5GNR_FEC_DDR4_WR_DONE_REGS = 0x00000A10, /* len: 1B */ + FPGA_5GNR_FEC_DDR4_RD_ADDR_REGS = 0x00000A18, /* len: 4B */ + FPGA_5GNR_FEC_DDR4_RD_DONE_REGS = 0x00000A20, /* len: 1B */ + FPGA_5GNR_FEC_DDR4_RD_RDY_REGS = 0x00000A28, /* len: 1B */ + FPGA_5GNR_FEC_DDR4_RD_DATA_REGS = 0x00000A30, /* len: 8B */ + FPGA_5GNR_FEC_DDR4_ADDR_RDY_REGS = 0x00000A38, /* len: 1B */ + FPGA_5GNR_FEC_HARQ_BUF_SIZE_RDY_REGS = 0x00000A40, /* len: 1B */ + FPGA_5GNR_FEC_HARQ_BUF_SIZE_REGS = 0x00000A48, /* len: 4B */ + FPGA_5GNR_FEC_MUTEX = 0x00000A60, /* len: 4B */ + FPGA_5GNR_FEC_MUTEX_RESET = 0x00000A68 /* len: 4B */ +}; + +/* FIXME Add HARQ/DDR Registers */ + +/* FPGA 5GNR FEC Ring Control Registers */ +enum { + FPGA_5GNR_FEC_RING_HEAD_ADDR = 0x00000008, + FPGA_5GNR_FEC_RING_SIZE = 0x00000010, + FPGA_5GNR_FEC_RING_MISC = 0x00000014, + FPGA_5GNR_FEC_RING_ENABLE = 0x00000015, + FPGA_5GNR_FEC_RING_FLUSH_QUEUE_EN = 0x00000016, + FPGA_5GNR_FEC_RING_SHADOW_TAIL = 0x00000018, + FPGA_5GNR_FEC_RING_HEAD_POINT = 0x0000001C +}; + +struct +fpga_5gnr_fec_conf { + /**< 1 if PF is used for dataplane, 0 for VFs */ + bool pf_mode_en; + /**< Number of UL queues per VF */ + uint8_t vf_ul_queues_number[FPGA_5GNR_FEC_NUM_VFS]; + /**< Number of DL queues per VF */ + uint8_t vf_dl_queues_number[FPGA_5GNR_FEC_NUM_VFS]; + /**< UL bandwidth. Needed for schedule algorithm */ + uint8_t ul_bandwidth; + /**< DL bandwidth. Needed for schedule algorithm */ + uint8_t dl_bandwidth; + /**< UL Load Balance */ + uint8_t ul_load_balance; + /**< DL Load Balance */ + uint8_t dl_load_balance; + /**< FLR timeout value */ + uint16_t flr_time_out; +}; + +/** + * Configure FPGA + */ +int fpga_5gnr_configure(void *bar0addr, const char *arg_cfg_filename); + +#endif /* _FPGA_5GNR_CFG_APP_H_ */ diff --git a/drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_cfg_parser.c b/drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_cfg_parser.c new file mode 100644 index 0000000..271b213 --- /dev/null +++ b/drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_cfg_parser.c @@ -0,0 +1,187 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include + +#include +#include "fpga_5gnr_cfg_app.h" + +/* Names of sections used in the configuration file */ +#define MODE "MODE" +#define UL "UL" +#define DL "DL" +#define FLR "FLR" + +/* Names of entries in sections used in the configuration file */ +#define PFMODE "pf_mode_en" +#define BANDWIDTH "bandwidth" +#define LOAD_BALANCE "load_balance" +#define QUEUE_MAP "vfqmap" +#define FLR_TIME_OUT "flr_time_out" + +/* Default values for FPGA device configuration variables */ +#define DEFAULT_PF_MODE_EN 1 +#define DEFAULT_UL_BANDWIDTH 3 +#define DEFAULT_DL_BANDWIDTH 3 +#define DEFAULT_UL_LOAD_BALANCE 64 +#define DEFAULT_DL_LOAD_BALANCE 64 +#define DEFAULT_NUM_VF_QUEUE 8 + +/* Possible values for MODE and LLR_SIGN */ +#define ZERO "0" +#define ONE "1" + +static int +parse_number8(const char *str, uint8_t *value) +{ + uint64_t val = 0; + char *end; + + if (str == NULL) + return -EINVAL; + + val = strtoul(str, &end, 0); + if (val > UINT8_MAX || str == end) { + printf("ERROR: Invalid value %" PRIu64 "\n", val); + return -ERANGE; + } + + *value = (uint8_t) val; + return 1; +} + +static int +parse_number16(const char *str, uint16_t *value) +{ + uint64_t val = 0; + char *end; + + if (str == NULL) + return -EINVAL; + + val = strtoul(str, &end, 0); + if (val > UINT16_MAX || str == end) { + printf("ERROR: Invalid value %" PRIu64 "\n", val); + return -ERANGE; + } + + *value = (uint16_t) val; + return 1; +} + +static int +parse_array8(const char *str, uint8_t *array) +{ + int i; + uint64_t val = 0; + char *end; + + if (str == NULL) + return -EINVAL; + + char *val_ch = strtok((char *)str, ","); + for (i = 0; i < 8 && NULL != val_ch; i++) { + + val = strtoul(val_ch, &end, 0); + if (val > UINT8_MAX || val_ch == end) { + printf("ERROR: Invalid value %" PRIu64 "\n", val); + return -ERANGE; + } + array[i] = (uint8_t) val; + + val_ch = strtok(NULL, ","); + } + return 1; +} + +static void +set_default_config(struct fpga_5gnr_fec_conf *fpga_conf) +{ + int i; + + /* Set pf mode to true */ + fpga_conf->pf_mode_en = DEFAULT_PF_MODE_EN; + + /* Set ratio between UL and DL to 1:1 (unit of weight is 3 CBs) */ + fpga_conf->ul_bandwidth = DEFAULT_UL_BANDWIDTH; + fpga_conf->dl_bandwidth = DEFAULT_DL_BANDWIDTH; + + /* Set Load Balance Factor to 64 */ + fpga_conf->ul_load_balance = DEFAULT_UL_LOAD_BALANCE; + fpga_conf->dl_load_balance = DEFAULT_DL_LOAD_BALANCE; + + for (i = 0; i < FPGA_5GNR_FEC_NUM_VFS; i++) { + fpga_conf->vf_ul_queues_number[i] = DEFAULT_NUM_VF_QUEUE / 2; + fpga_conf->vf_dl_queues_number[i] = DEFAULT_NUM_VF_QUEUE / 2; + } +} + +static int +fpga_handler(void *user, const char *section, + const char *name, const char *value) +{ + struct fpga_5gnr_fec_conf *fpga_conf = + (struct fpga_5gnr_fec_conf *) user; + int ret = 1; + + if (!strcmp(section, MODE) && !strcmp(name, PFMODE)) { + if (!strcmp(value, ZERO)) + fpga_conf->pf_mode_en = false; + else if (!strcmp(value, ONE)) + fpga_conf->pf_mode_en = true; + else + ret = 0; + } else if (!strcmp(section, UL) && !strcmp(name, BANDWIDTH)) { + ret = parse_number8(value, &fpga_conf->ul_bandwidth); + } else if (!strcmp(section, DL) && !strcmp(name, BANDWIDTH)) { + ret = parse_number8(value, &fpga_conf->dl_bandwidth); + } else if (!strcmp(section, UL) && !strcmp(name, LOAD_BALANCE)) { + ret = parse_number8(value, &fpga_conf->ul_load_balance); + } else if (!strcmp(section, DL) && !strcmp(name, LOAD_BALANCE)) { + ret = parse_number8(value, &fpga_conf->dl_load_balance); + } else if (!strcmp(section, UL) && !strcmp(name, QUEUE_MAP)) { + ret = parse_array8(value, fpga_conf->vf_ul_queues_number); + } else if (!strcmp(section, DL) && !strcmp(name, QUEUE_MAP)) { + ret = parse_array8(value, fpga_conf->vf_dl_queues_number); + } else if (!strcmp(section, FLR) && !strcmp(name, FLR_TIME_OUT)) { + ret = parse_number16(value, &fpga_conf->flr_time_out); + } else { + printf("ERROR: Section (%s) or name (%s) is not valid.\n", + section, name); + return 0; + } + if (ret != 1) + printf("Error: Conversion of value (%s) failed.\n", value); + + return ret; +} + +int +fpga_5gnr_parse_conf_file(const char *file_name, + struct fpga_5gnr_fec_conf *fpga_conf) +{ + int ret; + + set_default_config(fpga_conf); + + ret = ini_parse(file_name, fpga_handler, fpga_conf); + + if (ret == -1) { + printf("ERROR: Error loading configuration file %s\n", + file_name); + set_default_config(fpga_conf); + return -ENOENT; + } else if (ret == -2) { + printf("ERROR: Memory allocation error\n"); + set_default_config(fpga_conf); + return -ENOMEM; + } + + return 0; +} diff --git a/drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_config.cfg b/drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_config.cfg new file mode 100644 index 0000000..0854672 --- /dev/null +++ b/drivers/baseband/fpga_5gnr_fec/pf_config_app/fpga_5gnr_config.cfg @@ -0,0 +1,18 @@ +; SPDX-License-Identifier: BSD-3-Clause +; Copyright(c) 2020 Intel Corporation + +[MODE] +pf_mode_en = 1 + +[UL] +bandwidth = 3 +load_balance = 128 +vfqmap = 4,4,4,4,4,4,4,4 + +[DL] +bandwidth = 3 +load_balance = 128 +vfqmap = 4,4,4,4,4,4,4,4 + +[FLR] +flr_time_out = 610