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 <nicolas.chau...@intel.com>
---
 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=<path-to-inih-lib>
+
+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 <stdlib.h>
+#include <stdint.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <linux/vfio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#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 <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <errno.h>
+
+#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 <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <errno.h>
+
+/**< 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 <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <errno.h>
+
+#include <ini.h>
+#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
-- 
1.8.3.1

Reply via email to