To support switch management, add the following new files:
Add fm10k/switch/fm10k_config.h.
Add fm10k/switch/fm10k_config.c(support switch configuration)
Add fm10k/switch/fm10k_ffu.h
Add fm10k/switch/fm10k_ffu.c(support switch ffu rule)
Add fm10k/switch/fm10k_stats.h
Add fm10k/switch/fm10k_stats.c(support switch statistics)
and modify fm10k/Makefile(add fm10k_config.c,
fm10k_ffu.c, and fm10k_stats.c).

To avoid configuration for both kernel driver
and userspace SDK outside DPDK, we add switch
management in FM10K DPDK PMD driver.
To enable switch management, you need add
CONFIG_RTE_FM10K_MANAGEMENT=y in
config/common_linux when building.

Signed-off-by: Xiaojun Liu <xiaojun....@silicom.co.il>
---
 drivers/net/fm10k/Makefile              |    3 +
 drivers/net/fm10k/switch/fm10k_config.c |  855 +++++++++++++++++++++
 drivers/net/fm10k/switch/fm10k_config.h |  171 +++++
 drivers/net/fm10k/switch/fm10k_ffu.c    | 1209 ++++++++++++++++++++++++++++++
 drivers/net/fm10k/switch/fm10k_ffu.h    |   31 +
 drivers/net/fm10k/switch/fm10k_stats.c  | 1242 +++++++++++++++++++++++++++++++
 drivers/net/fm10k/switch/fm10k_stats.h  |  257 +++++++
 7 files changed, 3768 insertions(+)
 create mode 100644 drivers/net/fm10k/switch/fm10k_config.c
 create mode 100644 drivers/net/fm10k/switch/fm10k_config.h
 create mode 100644 drivers/net/fm10k/switch/fm10k_ffu.c
 create mode 100644 drivers/net/fm10k/switch/fm10k_ffu.h
 create mode 100644 drivers/net/fm10k/switch/fm10k_stats.c
 create mode 100644 drivers/net/fm10k/switch/fm10k_stats.h

diff --git a/drivers/net/fm10k/Makefile b/drivers/net/fm10k/Makefile
index 4ec2a80..ed73251 100644
--- a/drivers/net/fm10k/Makefile
+++ b/drivers/net/fm10k/Makefile
@@ -90,6 +90,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_sbus.c
 SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_serdes.c
 SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_sm.c
 SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_spico_code.c
+SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_stats.c
+SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_ffu.c
+SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_config.c
 endif
 
 SRCS-$(CONFIG_RTE_LIBRTE_FM10K_INC_VECTOR) += fm10k_rxtx_vec.c
diff --git a/drivers/net/fm10k/switch/fm10k_config.c 
b/drivers/net/fm10k/switch/fm10k_config.c
new file mode 100644
index 0000000..46c3fae
--- /dev/null
+++ b/drivers/net/fm10k/switch/fm10k_config.c
@@ -0,0 +1,855 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2019   Silicom Ltd. Connectivity Solutions
+ */
+
+#include <unistd.h>
+
+#include <rte_time.h>
+#include <rte_kvargs.h>
+#include <rte_hash.h>
+#include <rte_flow.h>
+#include <rte_flow_driver.h>
+#include <rte_tm_driver.h>
+
+#include "../base/fm10k_type.h"
+#include "../base/fm10k_osdep.h"
+
+#include "../fm10k.h"
+#include "../fm10k_logs.h"
+#include "fm10k_debug.h"
+#include "fm10k_regs.h"
+#include "fm10k_switch.h"
+#include "fm10k_config.h"
+
+#define FM10K_CONFIG_WORD_MAX                  10
+#define FM10K_CONFIG_WORD_LEN                  20
+#define FM10K_CONFIG_STR_MAX                   100
+
+struct fm10k_cfg_key_item {
+       const char *key_str[FM10K_CONFIG_WORD_MAX];
+       uint8_t type;
+};
+
+static const char *fm10k_config_dpdk_conf_file = "/etc/dpdk_fm10k.conf";
+static struct fm10k_dpdk_cfg fm10k_config_dpdk_cfg;
+
+static struct fm10k_cfg_key_item fm10k_config_key_items[] = {
+               /* debug configuration */
+               { {"debug", "print", "enable"},
+                       FM10K_CONFIG_DEBUG_ENABLE},
+               { {"debug", "print", "config"},
+                       FM10K_CONFIG_DEBUG_CONFIG},
+               { {"debug", "print", "ffu", "init"},
+                       FM10K_CONFIG_DEBUG_FFU_INIT},
+               { {"debug", "print", "ffu", "register"},
+                       FM10K_CONFIG_DEBUG_FFU_REG},
+               { {"debug", "print", "ffu", "rule"},
+                       FM10K_CONFIG_DEBUG_FFU_RULE},
+               { {"debug", "print", "stats", "port"},
+                       FM10K_CONFIG_DEBUG_STATS_PORT},
+               { {"debug", "print", "stats", "queue"},
+                       FM10K_CONFIG_DEBUG_STATS_QUEUE},
+               { {"debug", "print", "stats", "rule"},
+                       FM10K_CONFIG_DEBUG_STATS_FFU},
+               { {"debug", "print", "stats", "detail"},
+                       FM10K_CONFIG_DEBUG_STATS_MORE},
+               { {"debug", "print", "stats", "interval"},
+                       FM10K_CONFIG_DEBUG_STATS_INTERVAL},
+               /* general configuration */
+               { {"dpdk", "bind", "pf", "number"},
+                       FM10K_CONFIG_BIND_PF_NUMBER},
+               { {"extern", "port", "speed"},
+                       FM10K_CONFIG_EXT_PORT_SPEED},
+               /* internal redirect configuration */
+               { {"dpdk", "port", "*", "map", "pf"},
+                       FM10K_CONFIG_DPDK_PORT_MAP_PF},
+               { {"extern", "port", "*", "map", "pf"},
+                       FM10K_CONFIG_EXT_PORT_MAP_PF},
+               /* external redirect configuration */
+               { {"flowset", "start"},
+                       FM10K_CONFIG_FLOWSET_START},
+               { {"flowset", "stop"},
+                       FM10K_CONFIG_FLOWSET_STOP},
+               { {"flowset", "enable"},
+                       FM10K_CONFIG_FLOWSET_ENABLE},
+               { {"flow", "*", "condition", "source", "extern", "port"},
+                       FM10K_CONFIG_FLOW_COND_SRC_EXT_PORT},
+               { {"flow", "*", "condition", "source", "dpdk", "port"},
+                       FM10K_CONFIG_FLOW_COND_SRC_DPDK_PORT},
+               { {"flow", "*", "condition", "vlan"},
+                       FM10K_CONFIG_FLOW_COND_VLAN},
+               { {"flow", "*", "action", "forward", "extern", "port"},
+                       FM10K_CONFIG_FLOW_ACT_FW_EXT_PORT},
+               { {"flow", "*", "action", "forward", "dpdk", "port"},
+                       FM10K_CONFIG_FLOW_ACT_FW_DPDK_PORT},
+               { {"flow", "*", "action", "forward", "vlan"},
+                       FM10K_CONFIG_FLOW_ACT_FW_VALN},
+};
+
+static char default_flowset[10] = "default";
+
+static struct fm10k_cfg_config_item fm10k_silc_nic_2ext_2pep[] = {
+       {   FM10K_CONFIG_BIND_PF_NUMBER, FM10K_CONFIG_VALUE_INT, 0,
+               "# Tell how many PF ports are bound in DPDK.\n"
+               "# Driver will check the number when initializes.",
+               .val.int64 = 2
+       },
+       {   FM10K_CONFIG_EXT_PORT_SPEED, FM10K_CONFIG_VALUE_INT, 0,
+               "# Set external port speed, 40 means 40G, 100 means 100G.",
+               .val.int64 = 100
+       },
+       {   FM10K_CONFIG_DPDK_PORT_MAP_PF, FM10K_CONFIG_VALUE_INT, 0,
+               "# Map 1 or 2 PF ports to one DPDK port.\n"
+               "# If mapped PF number is 2, traffic will be\n"
+               "# load balance between the 2 PF.\n"
+               "# And the DPDK port queue number will be configured\n"
+               "# more than 2(each PF need at least 1 DPDK port queue).",
+               .val.int64 = 0
+       },
+       {   FM10K_CONFIG_DPDK_PORT_MAP_PF, FM10K_CONFIG_VALUE_INT, 1,
+               "",
+               .val.int64 = 1
+       },
+       {   FM10K_CONFIG_EXT_PORT_MAP_PF, FM10K_CONFIG_VALUE_INT, 1,
+               "# Map 1 or 2 PF to one external port. If mapped PF number is 
2,\n"
+               "# traffic will be load balance between the 2 PF. ",
+               .val.int64 = 0
+       },
+       {   FM10K_CONFIG_EXT_PORT_MAP_PF, FM10K_CONFIG_VALUE_INT, 2,
+               "",
+               .val.int64 = 1
+       },
+       {   FM10K_CONFIG_FLOWSET_START, FM10K_CONFIG_VALUE_STR, 0,
+               "# Define flow rule",
+               .val.str = default_flowset
+       },
+       {   FM10K_CONFIG_FLOWSET_STOP, FM10K_CONFIG_VALUE_STR, 0,
+               "",
+               .val.str = default_flowset
+       },
+       {   FM10K_CONFIG_FLOWSET_ENABLE, FM10K_CONFIG_VALUE_STR, 0,
+               "",
+               .val.str = default_flowset
+       },
+       {   FM10K_CONFIG_TYPE_NULL, 0, 0,
+               "",
+               .val.int64 = 0
+       },
+};
+
+static struct fm10k_cfg_config_item fm10k_silc_nic_2ext_4pep[] = {
+       {   FM10K_CONFIG_BIND_PF_NUMBER, FM10K_CONFIG_VALUE_INT, 0,
+               "# Tell how many PF ports are bound in DPDK.\n"
+               "# Driver will check the  number when initializes.",
+               .val.int64 = 4
+       },
+
+       {   FM10K_CONFIG_EXT_PORT_SPEED, FM10K_CONFIG_VALUE_INT, 0,
+               "# Set external port speed, 40 means 40G, 100 means 100G.",
+               .val.int64 = 100
+       },
+       {   FM10K_CONFIG_DPDK_PORT_MAP_PF, FM10K_CONFIG_VALUE_INT, 0,
+               "# Map 1 or 2 PF ports to one DPDK port.\n"
+               "# If mapped PF number is 2, traffic will be\n"
+               "# load balance between the 2 PFs.\n"
+               "# And the DPDK port queue number will be configured\n"
+               "# more than 2(each PF need at least 1 DPDK port queue).",
+               .val.int64 = 0
+       },
+       {   FM10K_CONFIG_DPDK_PORT_MAP_PF, FM10K_CONFIG_VALUE_INT, 0,
+               "",
+               .val.int64 = 2
+       },
+       {   FM10K_CONFIG_DPDK_PORT_MAP_PF, FM10K_CONFIG_VALUE_INT, 1,
+               "",
+               .val.int64 = 1
+       },
+       {   FM10K_CONFIG_DPDK_PORT_MAP_PF, FM10K_CONFIG_VALUE_INT, 1,
+               "",
+               .val.int64 = 3
+       },
+       {   FM10K_CONFIG_EXT_PORT_MAP_PF, FM10K_CONFIG_VALUE_INT, 1,
+               "# Map 1 or 2 PF to one external port. If mapped PF number is 
2,\n"
+               "# traffic will be load balance between the 2 PF.",
+               .val.int64 = 0
+       },
+       {   FM10K_CONFIG_EXT_PORT_MAP_PF, FM10K_CONFIG_VALUE_INT, 1,
+               "",
+               .val.int64 = 2
+       },
+       {   FM10K_CONFIG_EXT_PORT_MAP_PF, FM10K_CONFIG_VALUE_INT, 2,
+               "",
+               .val.int64 = 1
+       },
+       {   FM10K_CONFIG_EXT_PORT_MAP_PF, FM10K_CONFIG_VALUE_INT, 2,
+               "",
+               .val.int64 = 3
+       },
+       {   FM10K_CONFIG_FLOWSET_START, FM10K_CONFIG_VALUE_STR, 0,
+               "# Define flow rule",
+               .val.str = default_flowset
+       },
+       {   FM10K_CONFIG_FLOWSET_STOP, FM10K_CONFIG_VALUE_STR, 0,
+               "",
+               .val.str = default_flowset
+       },
+       {   FM10K_CONFIG_FLOWSET_ENABLE, FM10K_CONFIG_VALUE_STR, 0,
+               "",
+               .val.str = default_flowset
+       },
+       {   FM10K_CONFIG_TYPE_NULL, 0, 0,
+               "",
+               .val.int64 = 0
+       },
+};
+
+
+static int
+fm10k_config_conf_line_parser(char *buff, struct fm10k_cfg_config_item *item)
+{
+       char *p;
+       char *endptr;
+       const char *cfg_delims = { " " };
+       const char *key_delims = { "." };
+       struct fm10k_cfg_key_item *key;
+       char cfgs[3][FM10K_CONFIG_STR_MAX];
+       char cmp_keys[FM10K_CONFIG_WORD_MAX][FM10K_CONFIG_WORD_LEN];
+       long key_param = 0;
+       uint16_t i, j;
+       uint8_t val_type = FM10K_CONFIG_VALUE_NULL;
+
+       for (i = 0; i < 3; i++) {
+               if (i == 0)
+                       p = strtok(buff, cfg_delims);
+               else
+                       p = strtok(NULL, cfg_delims);
+               if (p == NULL)
+                       return -1;
+               strncpy(cfgs[i], p, FM10K_CONFIG_STR_MAX);
+       }
+
+       p = strtok(NULL, cfg_delims);
+       if (p)
+               return -1;
+
+       memset(cmp_keys, 0, sizeof(cmp_keys));
+       for (i = 0; i < FM10K_CONFIG_WORD_MAX; i++)     {
+               if (i == 0)
+                       p = strtok(cfgs[0], key_delims);
+               else
+                       p = strtok(NULL, key_delims);
+               if (p == NULL)
+                       break;
+               strncpy(cmp_keys[i], p, FM10K_CONFIG_WORD_LEN);
+       }
+
+       if (strcmp(cfgs[1], "int") == 0)
+               val_type = FM10K_CONFIG_VALUE_INT;
+       else if (strcmp(cfgs[1], "string") == 0)
+               val_type = FM10K_CONFIG_VALUE_STR;
+       else
+               return -1;
+
+       for (i = 0;
+                       i < sizeof(fm10k_config_key_items) /
+                               sizeof(fm10k_config_key_items[0]);
+                       i++) {
+               key = &fm10k_config_key_items[i];
+               for (j = 0; j < FM10K_CONFIG_WORD_MAX; j++)     {
+                       if (key->key_str[j] &&
+                                       strlen(cmp_keys[j]) > 0) {
+                               if (strcmp(key->key_str[j], "*") == 0) {
+                                       key_param =
+                                       strtol(cmp_keys[j], &endptr, 10);
+                                       if ((key_param == 0 &&
+                                               endptr == cmp_keys[j]) ||
+                                               (endptr != cmp_keys[j] &&
+                                               strlen(endptr) != 0))
+                                               break;
+                               } else if (strcmp(key->key_str[j],
+                                                       cmp_keys[j]) != 0) {
+                                       break;
+                               }
+                       } else if (key->key_str[j] == 0 &&
+                                       strlen(cmp_keys[j]) == 0) {
+                               if (val_type == FM10K_CONFIG_VALUE_STR) {
+                                       item->val.str =
+                                       malloc(strlen(cfgs[2]) + 1);
+                                       if (item->val.str == NULL)
+                                               return -1;
+                                       strcpy(item->val.str, cfgs[2]);
+                               } else {
+                                       item->val.int64 =
+                                       strtol(cfgs[2], NULL, 10);
+                               }
+                               item->type = key->type;
+                               item->key_param = key_param;
+                               item->val_type = val_type;
+                               return 0;
+                       }
+               }
+       }
+       return -1;
+}
+
+static bool
+fm10k_config_blank_line_check(char *line)
+{
+       uint16_t i;
+
+       for (i = 0; i < strlen(line); i++) {
+               if (line[i] == ' ' ||
+                               line[i] == '\n' ||
+                               line[i] == '\t' || line[i] == 0x0d) /* 0d: CR */
+                       continue;
+               else
+                       return false;
+       }
+       return true;
+}
+
+static int
+fm10k_config_conf_file_load(void)
+{
+       int i = 0;
+       FILE *fp;
+       char buff[255];
+       struct fm10k_cfg_config_item *item;
+
+       fp = fopen(fm10k_config_dpdk_conf_file, "r");
+       if (fp == NULL)
+               return -1;
+
+       fm10k_config_dpdk_cfg.config_list =     malloc
+               (sizeof(struct fm10k_cfg_config_item) * FM10K_SW_CONFIG_MAX);
+       if (fm10k_config_dpdk_cfg.config_list == NULL)
+               return -1;
+       memset(fm10k_config_dpdk_cfg.config_list, 0,
+               sizeof(struct fm10k_cfg_config_item) * FM10K_SW_CONFIG_MAX);
+
+       while (fgets(buff, sizeof(buff), fp)) {
+               if (buff[0] == '#' || buff[0] == 0)
+                       continue;
+
+               if (fm10k_config_blank_line_check(buff))
+                       continue;
+
+               item = &fm10k_config_dpdk_cfg.config_list[i++];
+               if (fm10k_config_conf_line_parser(buff, item) < 0) {
+                       FM10K_SW_ERR("Unknown configuration: %s", buff);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+struct fm10k_hw*
+fm10k_config_hw_get(int port_no)
+{
+       int hw_port;
+
+       hw_port = fm10k_config_dpdk_cfg.dpdk_port_map[port_no].map_no[0];
+       return fm10k_config_dpdk_cfg.pf_hw[hw_port];
+}
+
+struct fm10k_cfg_flowset *
+fm10k_config_flowset_current_get(void)
+{
+       return fm10k_config_dpdk_cfg.current;
+}
+
+void
+fm10k_config_flowset_current_set(struct fm10k_cfg_flowset *new)
+{
+       fm10k_config_dpdk_cfg.current = new;
+}
+
+bool
+fm10k_config_flow_list_end(struct fm10k_cfg_flow *list,
+               struct fm10k_cfg_flow *flow)
+{
+       return (list == flow);
+}
+
+static void
+fm10k_config_flow_list_init(struct fm10k_cfg_flow *list)
+{
+       list->next = list;
+       list->prev = list;
+}
+
+static void
+fm10k_config_flow_list_add(struct fm10k_cfg_flow *new,
+               struct fm10k_cfg_flow *list)
+{
+       struct fm10k_cfg_flow *next = list->next;
+       next->prev = new;
+       new->next = next;
+       new->prev = list;
+       list->next = new;
+}
+
+void
+fm10k_config_flow_list_add_tail(struct fm10k_cfg_flowset *flowset,
+               struct fm10k_cfg_flow *flow)
+{
+       fm10k_config_flow_list_add(flow, flowset->flow_head.prev);
+}
+
+void
+fm10k_config_flow_list_delete(struct fm10k_cfg_flow *flow)
+{
+       flow->prev->next = flow->next;
+       flow->next->prev = flow->prev;
+       flow->prev = NULL;
+       flow->next = NULL;
+}
+
+struct fm10k_cfg_flowset *
+fm10k_config_flowset_get(const char *name)
+{
+       struct fm10k_cfg_flowset *flowset;
+
+       flowset = fm10k_config_dpdk_cfg.flowset_head.next;
+       while (flowset) {
+               if (strcmp(flowset->name, name) == 0)
+                       break;
+               flowset = flowset->next;
+       }
+
+       if (flowset == NULL) {
+               flowset = malloc(sizeof(struct fm10k_cfg_flowset));
+               if (flowset == NULL)
+                       return NULL;
+               strcpy(flowset->name, name);
+               fm10k_config_flow_list_init(&flowset->flow_head);
+               flowset->next = fm10k_config_dpdk_cfg.flowset_head.next;
+               fm10k_config_dpdk_cfg.flowset_head.next = flowset;
+       }
+       return flowset;
+}
+
+
+static int
+fm10k_cfg_flow_item_set(struct fm10k_cfg_flowset *flowset,
+               uint8_t flow_no, uint8_t type, int64_t val)
+{
+       struct fm10k_cfg_flow *tmp;
+       struct fm10k_cfg_flow *flow = NULL;
+
+       if (flowset == NULL)
+               return -1;
+
+       tmp = flowset->flow_head.next;
+       while (!fm10k_config_flow_list_end(&flowset->flow_head, tmp)) {
+               if (tmp->flow_no == flow_no) {
+                       flow = tmp;
+                       break;
+               }
+               tmp = tmp->next;
+       }
+       if (flow == NULL) {
+               flow = malloc(sizeof(struct fm10k_cfg_flow));
+               memset(flow, 0, sizeof(struct fm10k_cfg_flow));
+               flow->flow_no = flow_no;
+               fm10k_config_flow_list_add_tail(flowset, flow);
+       }
+       if (flow == NULL)
+               return -1;
+
+       switch (type) {
+       case FM10K_CONFIG_FLOW_COND_SRC_EXT_PORT:
+               flow->src_port.port_type = FM10K_CONFIG_FLOW_EXT_PORT;
+               flow->src_port.port_no = val;
+               break;
+       case FM10K_CONFIG_FLOW_COND_SRC_DPDK_PORT:
+               flow->src_port.port_type = FM10K_CONFIG_FLOW_DPDK_PORT;
+               flow->src_port.port_no = val;
+               break;
+       case FM10K_CONFIG_FLOW_COND_VLAN:
+               flow->src_port.vlan_id = val;
+               break;
+       case FM10K_CONFIG_FLOW_ACT_FW_EXT_PORT:
+               if (flow->fw_port[0].port_type == FM10K_CONFIG_FLOW_NONE_PORT) {
+                       flow->fw_port[0].port_type = FM10K_CONFIG_FLOW_EXT_PORT;
+                       flow->fw_port[0].port_no = val;
+               } else {
+                       flow->fw_port[1].port_type = FM10K_CONFIG_FLOW_EXT_PORT;
+                       flow->fw_port[1].port_no = val;
+               }
+               break;
+       case FM10K_CONFIG_FLOW_ACT_FW_DPDK_PORT:
+               if (flow->fw_port[0].port_type == FM10K_CONFIG_FLOW_NONE_PORT) {
+                       flow->fw_port[0].port_type =
+                                       FM10K_CONFIG_FLOW_DPDK_PORT;
+                       flow->fw_port[0].port_no = val;
+               } else {
+                       flow->fw_port[1].port_type =
+                                       FM10K_CONFIG_FLOW_DPDK_PORT;
+                       flow->fw_port[1].port_no = val;
+               }
+               break;
+       case FM10K_CONFIG_FLOW_ACT_FW_VALN:
+               if (flow->fw_port[0].vlan_id == 0)
+                       flow->fw_port[0].vlan_id = val;
+               else
+                       flow->fw_port[1].vlan_id = val;
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+fm10k_config_conf_file_transfer(void)
+{
+       int i;
+       int offset;
+       uint32_t tmp, data;
+       struct fm10k_cfg_config_item *item;
+       struct fm10k_cfg_flowset *flowset = NULL;
+       struct fm10k_cfg_port_pf_map *map;
+
+       for (i = 0; i < FM10K_SW_CONFIG_MAX; i++) {
+               item = &fm10k_config_dpdk_cfg.config_list[i];
+               if (item->type == FM10K_CONFIG_TYPE_NULL)
+                       break;
+
+               switch (item->type)     {
+               case FM10K_CONFIG_BIND_PF_NUMBER:
+                       fm10k_config_dpdk_cfg.pf_num = item->val.int64;
+                       break;
+               case FM10K_CONFIG_EXT_PORT_SPEED:
+                       fm10k_config_dpdk_cfg.ext_port_speed = item->val.int64;
+                       break;
+               case FM10K_CONFIG_DPDK_PORT_MAP_PF:
+                       map =
+                       &fm10k_config_dpdk_cfg.dpdk_port_map[item->key_param];
+                       if (map->type == FM10K_CONFIG_PORT_MAP_PF) {
+                               map->type = FM10K_CONFIG_PORT_MAP_PFS;
+                               map->map_no[1] = item->val.int64;
+                       } else {
+                               map->type = FM10K_CONFIG_PORT_MAP_PF;
+                               map->map_no[0] = item->val.int64;
+                       }
+                       break;
+               case FM10K_CONFIG_EXT_PORT_MAP_PF:
+                       map =
+                               &fm10k_config_dpdk_cfg.ext_port_map
+                               [item->key_param - 1];
+                       if (map->type == FM10K_CONFIG_PORT_MAP_PF) {
+                               map->type = FM10K_CONFIG_PORT_MAP_PFS;
+                               map->map_no[1] = item->val.int64;
+                       } else {
+                               map->type = FM10K_CONFIG_PORT_MAP_PF;
+                               map->map_no[0] = item->val.int64;
+                       }
+                       break;
+
+               case FM10K_CONFIG_DEBUG_ENABLE:
+               case FM10K_CONFIG_DEBUG_CONFIG:
+               case FM10K_CONFIG_DEBUG_FFU_INIT:
+               case FM10K_CONFIG_DEBUG_FFU_REG:
+               case FM10K_CONFIG_DEBUG_FFU_RULE:
+               case FM10K_CONFIG_DEBUG_STATS_PORT:
+               case FM10K_CONFIG_DEBUG_STATS_QUEUE:
+               case FM10K_CONFIG_DEBUG_STATS_FFU:
+               case FM10K_CONFIG_DEBUG_STATS_MORE:
+                       offset = item->type - FM10K_CONFIG_DEBUG_START;
+                       tmp = fm10k_config_dpdk_cfg.debug_cfg;
+                       data = 1;
+                       if (item->val.int64 != 1)
+                               fm10k_config_dpdk_cfg.debug_cfg =
+                                               tmp & ~(data << offset);
+                       else
+                               fm10k_config_dpdk_cfg.debug_cfg |=
+                                               (data << offset);
+                       break;
+               case FM10K_CONFIG_DEBUG_STATS_INTERVAL:
+                       fm10k_config_dpdk_cfg.stats_interval = item->val.int64;
+                       break;
+
+               case FM10K_CONFIG_FLOWSET_START:
+                       /* skip /n */
+                       item->val.str[strlen(item->val.str) - 1] = 0;
+                       flowset = fm10k_config_flowset_get(item->val.str);
+                       if (flowset == NULL)
+                               return -1;
+                       break;
+               case FM10K_CONFIG_FLOWSET_STOP:
+                       flowset = NULL;
+                       break;
+               case FM10K_CONFIG_FLOWSET_ENABLE:
+                       /* skip /n */
+                       item->val.str[strlen(item->val.str) - 1] = 0;
+                       fm10k_config_dpdk_cfg.current =
+                                       fm10k_config_flowset_get(item->val.str);
+                       break;
+               case FM10K_CONFIG_FLOW_COND_SRC_EXT_PORT:
+               case FM10K_CONFIG_FLOW_COND_SRC_DPDK_PORT:
+               case FM10K_CONFIG_FLOW_COND_VLAN:
+               case FM10K_CONFIG_FLOW_ACT_FW_EXT_PORT:
+               case FM10K_CONFIG_FLOW_ACT_FW_DPDK_PORT:
+               case FM10K_CONFIG_FLOW_ACT_FW_VALN:
+                       if (flowset == NULL ||
+                                       fm10k_cfg_flow_item_set(flowset,
+                                       item->key_param, item->type,
+                                       item->val.int64) != 0)
+                               return -1;
+                       break;
+               default:
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+static bool
+fm10k_config_conf_file_exist(void)
+{
+       if (access(fm10k_config_dpdk_conf_file, 0) == 0)
+               return true;
+       return false;
+}
+
+static int
+fm10k_config_conf_file_item_create(FILE *fp, char *buff,
+               struct fm10k_cfg_key_item *key,
+               struct fm10k_cfg_config_item *item)
+{
+       int i;
+
+       if (item->type != key->type)
+               return 0;
+
+       for (i = 0; i < FM10K_CONFIG_WORD_MAX; i++) {
+               if (key->key_str[i] == 0)
+                       break;
+               if (i == 0) {
+                       sprintf(buff + strlen(buff),
+                               "%s", key->key_str[i]);
+               } else {
+                       if (strcmp(key->key_str[i], "*") == 0)
+                               sprintf(buff + strlen(buff),
+                                               ".%u", item->key_param);
+                       else
+                               sprintf(buff + strlen(buff),
+                                               ".%s", key->key_str[i]);
+               }
+       }
+       if (item->val_type == FM10K_CONFIG_VALUE_INT)
+               sprintf(buff + strlen(buff),
+                               " int %lld\n", (long long)item->val.int64);
+       else if (item->val_type == FM10K_CONFIG_VALUE_STR)
+               sprintf(buff + strlen(buff), " string %s\n", item->val.str);
+       else
+               return -1;
+       fwrite(buff, strlen(buff), 1, fp);
+       FM10K_SW_TRACE("[write] %s", buff);
+
+       return 0;
+}
+
+static int
+fm10k_config_conf_file_create(void)
+{
+       uint16_t i, j;
+       struct fm10k_cfg_key_item *key;
+       struct fm10k_cfg_config_item *item;
+       FILE *fp;
+       char buff[255] = "";
+
+       fp = fopen(fm10k_config_dpdk_conf_file, "w");
+       if (fp == NULL)
+               return -1;
+
+       for (i = 0; i < FM10K_SW_CONFIG_MAX; i++) {
+               item = &fm10k_config_dpdk_cfg.config_list[i];
+               if (item->type == FM10K_CONFIG_TYPE_NULL)
+                       break;
+               buff[0] = 0;
+               if (strlen(item->describe) > 0)
+                       sprintf(buff, "\n\n%s\n", item->describe);
+               for (j = 0;
+                               j < sizeof(fm10k_config_key_items) /
+                                       sizeof(fm10k_config_key_items[0]);
+                               j++) {
+                       key = &fm10k_config_key_items[j];
+                       if (fm10k_config_conf_file_item_create
+                                       (fp, buff, key, item) != 0) {
+                               fclose(fp);
+                               return -1;
+                       }
+               }
+       }
+       fclose(fp);
+       return 0;
+}
+
+void
+fm10k_config_cfg_flowset_show(void)
+{
+       struct fm10k_cfg_flowset *flowset;
+
+       printf("  FLOWSET ENABLE: %s\n", fm10k_config_dpdk_cfg.current->name);
+
+       flowset = fm10k_config_dpdk_cfg.flowset_head.next;
+       while (flowset) {
+               printf("\n  FLOWSET  : %s\n", flowset->name);
+               struct fm10k_cfg_flow *flow = flowset->flow_head.next;
+               while (!fm10k_config_flow_list_end(&flowset->flow_head, flow)) {
+                       const char *port_type[3] = { "NON", "EXT", "DPDK" };
+                       if (flow->fw_port[1].port_type !=
+                                       FM10K_CONFIG_FLOW_NONE_PORT) {
+                               printf("  FLOW %d : %4s PORT %d VLAN %4d --> "
+                                       "%4s PORT %d VLAN %4d & %4s PORT %d 
VLAN %4d\n",
+                                       flow->flow_no,
+                                       port_type[flow->src_port.port_type],
+                                       flow->src_port.port_no,
+                                       flow->src_port.vlan_id,
+                                       port_type[flow->fw_port[0].port_type],
+                                       flow->fw_port[0].port_no,
+                                       flow->fw_port[0].vlan_id,
+                                       port_type[flow->fw_port[1].port_type],
+                                       flow->fw_port[1].port_no,
+                                       flow->fw_port[1].vlan_id);
+                       } else {
+                               printf("  FLOW %d : %4s PORT %d VLAN %4d --> "
+                                       "%4s PORT %d VLAN %4d\n",
+                                       flow->flow_no,
+                                       port_type[flow->src_port.port_type],
+                                       flow->src_port.port_no,
+                                       flow->src_port.vlan_id,
+                                       port_type[flow->fw_port[0].port_type],
+                                       flow->fw_port[0].port_no,
+                                       flow->fw_port[0].vlan_id);
+                       }
+                       flow = flow->next;
+               }
+               flowset = flowset->next;
+       }
+}
+
+static void
+fm10k_config_cfg_describe(struct fm10k_switch *sw,
+               struct fm10k_device_info *info)
+{
+       uint16_t i;
+       struct fm10k_cfg_flowset *flowset;
+
+       if (!fm10k_config_check_debug(sw->dpdk_cfg, FM10K_CONFIG_DEBUG_CONFIG))
+               return;
+
+       printf("--- FM10K STATIC CONFIG ---\n");
+       printf("  Card Type: %s\n", info->desc);
+       printf("  PF Max   : %d\n", fm10k_config_dpdk_cfg.pf_max);
+       printf("  PF Bind  : %d\n", fm10k_config_dpdk_cfg.pf_num);
+       printf("  DEBUG    : %#x\n", fm10k_config_dpdk_cfg.debug_cfg);
+       printf("  STATS GAP: %d sec\n", fm10k_config_dpdk_cfg.stats_interval);
+       printf("  EXT PORT speed: %d Gbps\n",
+                       fm10k_config_dpdk_cfg.ext_port_speed);
+       printf("  FLOWSET ENABLE: %s\n", fm10k_config_dpdk_cfg.current->name);
+
+       for (i = 0; i < fm10k_config_dpdk_cfg.ext_port_num; i++) {
+               if (fm10k_config_dpdk_cfg.ext_port_map[i].type ==
+                               FM10K_CONFIG_PORT_MAP_NULL)
+                       continue;
+               if (fm10k_config_dpdk_cfg.ext_port_map[i].type ==
+                               FM10K_CONFIG_PORT_MAP_PF)
+                       printf("  EXT PORT[%d] MAP: PF%d\n", i + 1,
+                       fm10k_config_dpdk_cfg.ext_port_map[i].map_no[0]);
+               else
+                       printf("  EXT PORT[%d] MAP: PF%d PF%d\n", i + 1,
+                       fm10k_config_dpdk_cfg.ext_port_map[i].map_no[0],
+                       fm10k_config_dpdk_cfg.ext_port_map[i].map_no[1]);
+       }
+
+       for (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++) {
+               if (fm10k_config_dpdk_cfg.dpdk_port_map[i].type ==
+                               FM10K_CONFIG_PORT_MAP_NULL)
+                       continue;
+               if (fm10k_config_dpdk_cfg.ext_port_map[i].type ==
+                               FM10K_CONFIG_PORT_MAP_PF)
+                       printf("  DPDK PORT[%d] MAP: PF%d\n", i,
+                       fm10k_config_dpdk_cfg.dpdk_port_map[i].map_no[0]);
+               else
+                       printf("  DPDK PORT[%d] MAP: PF%d PF%d\n", i,
+                       fm10k_config_dpdk_cfg.dpdk_port_map[i].map_no[0],
+                       fm10k_config_dpdk_cfg.dpdk_port_map[i].map_no[1]);
+       }
+
+       flowset = fm10k_config_dpdk_cfg.flowset_head.next;
+       while (flowset) {
+               printf("\n  FLOWSET  : %s\n", flowset->name);
+               struct fm10k_cfg_flow *flow = flowset->flow_head.next;
+               while (!fm10k_config_flow_list_end(&flowset->flow_head, flow)) {
+                       const char *port_type[3] = { "NON", "EXT", "DPDK" };
+                       if (flow->fw_port[1].port_type !=
+                                       FM10K_CONFIG_FLOW_NONE_PORT) {
+                               printf("  FLOW %d : %4s PORT %d VLAN %4d --> "
+                                       "%4s PORT %d VLAN %4d & %4s PORT %d "
+                                       "VLAN %4d\n",
+                                       flow->flow_no,
+                                       port_type[flow->src_port.port_type],
+                                       flow->src_port.port_no,
+                                       flow->src_port.vlan_id,
+                                       port_type[flow->fw_port[0].port_type],
+                                       flow->fw_port[0].port_no,
+                                       flow->fw_port[0].vlan_id,
+                                       port_type[flow->fw_port[1].port_type],
+                                       flow->fw_port[1].port_no,
+                                       flow->fw_port[1].vlan_id);
+                       } else {
+                               printf("  FLOW %d : %4s PORT %d VLAN %4d --> "
+                                       "%4s PORT %d VLAN %4d\n",
+                                       flow->flow_no,
+                                       port_type[flow->src_port.port_type],
+                                       flow->src_port.port_no,
+                                       flow->src_port.vlan_id,
+                                       port_type[flow->fw_port[0].port_type],
+                                       flow->fw_port[0].port_no,
+                                       flow->fw_port[0].vlan_id);
+                       }
+                       flow = flow->next;
+               }
+               flowset = flowset->next;
+       }
+       printf("\n");
+}
+
+int
+fm10k_config_init(struct fm10k_switch *sw, struct fm10k_hw *hw)
+{
+       struct fm10k_device_info *info = fm10k_get_device_info(hw);
+
+       fm10k_config_dpdk_cfg.stats_interval = 2;
+       fm10k_config_dpdk_cfg.pf_max = info->num_peps;
+       fm10k_config_dpdk_cfg.ext_port_num = info->num_ext_ports;
+
+       if (!fm10k_config_conf_file_exist()) {
+               if (info->num_epls == 2 && info->num_peps == 2)
+                       fm10k_config_dpdk_cfg.config_list =
+                                       fm10k_silc_nic_2ext_2pep;
+               else if (info->num_epls == 2 && info->num_peps == 4)
+                       fm10k_config_dpdk_cfg.config_list =
+                                       fm10k_silc_nic_2ext_4pep;
+               else
+                       return -1;
+
+               fm10k_config_conf_file_create();
+       } else {
+               if (fm10k_config_conf_file_load() < 0)
+                       return -1;
+       }
+
+       if (fm10k_config_conf_file_transfer() < 0)
+               return -1;
+       sw->dpdk_cfg = &fm10k_config_dpdk_cfg;
+
+       fm10k_config_cfg_describe(sw, info);
+
+       return 0;
+}
diff --git a/drivers/net/fm10k/switch/fm10k_config.h 
b/drivers/net/fm10k/switch/fm10k_config.h
new file mode 100644
index 0000000..f79df01
--- /dev/null
+++ b/drivers/net/fm10k/switch/fm10k_config.h
@@ -0,0 +1,171 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2019   Silicom Ltd. Connectivity Solutions
+ */
+
+#ifndef _FM10K_CONFIG_H_
+#define _FM10K_CONFIG_H_
+
+
+#include <stdint.h>
+#include "fm10k_switch.h"
+
+/* General configuration */
+#define FM10K_CONFIG_TYPE_NULL                         0
+#define FM10K_CONFIG_BIND_PF_NUMBER                    1
+#define FM10K_CONFIG_EXT_PORT_SPEED                    2
+
+/* Internal redirect configuration */
+#define FM10K_CONFIG_DPDK_PORT_MAP_PF          10
+#define FM10K_CONFIG_EXT_PORT_MAP_PF           11
+
+/* Debug configuration */
+#define FM10K_CONFIG_DEBUG_START          50
+#define FM10K_CONFIG_DEBUG_ENABLE         (FM10K_CONFIG_DEBUG_START + 0)
+#define FM10K_CONFIG_DEBUG_CONFIG         (FM10K_CONFIG_DEBUG_START + 1)
+#define FM10K_CONFIG_DEBUG_FFU_INIT       (FM10K_CONFIG_DEBUG_START + 2)
+#define FM10K_CONFIG_DEBUG_FFU_REG        (FM10K_CONFIG_DEBUG_START + 3)
+#define FM10K_CONFIG_DEBUG_FFU_RULE       (FM10K_CONFIG_DEBUG_START + 4)
+#define FM10K_CONFIG_DEBUG_STATS_PORT     (FM10K_CONFIG_DEBUG_START + 5)
+#define FM10K_CONFIG_DEBUG_STATS_QUEUE    (FM10K_CONFIG_DEBUG_START + 6)
+#define FM10K_CONFIG_DEBUG_STATS_FFU      (FM10K_CONFIG_DEBUG_START + 7)
+#define FM10K_CONFIG_DEBUG_STATS_MORE     (FM10K_CONFIG_DEBUG_START + 8)
+#define FM10K_CONFIG_DEBUG_STATS_INTERVAL (FM10K_CONFIG_DEBUG_START + 9)
+
+/* external redirect configuration */
+#define FM10K_CONFIG_FLOWSET_START           80
+#define FM10K_CONFIG_FLOWSET_STOP            81
+#define FM10K_CONFIG_FLOWSET_ENABLE          82
+
+#define FM10K_CONFIG_FLOW_COND_START         100
+#define FM10K_CONFIG_FLOW_COND_SRC_EXT_PORT  (FM10K_CONFIG_FLOW_COND_START + 0)
+#define FM10K_CONFIG_FLOW_COND_SRC_DPDK_PORT (FM10K_CONFIG_FLOW_COND_START + 1)
+#define FM10K_CONFIG_FLOW_COND_VLAN          (FM10K_CONFIG_FLOW_COND_START + 2)
+#define FM10K_CONFIG_FLOW_COND_END           (FM10K_CONFIG_FLOW_COND_START + 2)
+
+#define FM10K_CONFIG_FLOW_ACT_START          200
+#define FM10K_CONFIG_FLOW_ACT_FW_EXT_PORT    (FM10K_CONFIG_FLOW_ACT_START + 0)
+#define FM10K_CONFIG_FLOW_ACT_FW_DPDK_PORT   (FM10K_CONFIG_FLOW_ACT_START + 1)
+#define FM10K_CONFIG_FLOW_ACT_FW_VALN        (FM10K_CONFIG_FLOW_ACT_START + 2)
+#define FM10K_CONFIG_FLOW_ACT_END            (FM10K_CONFIG_FLOW_ACT_START + 2)
+
+#define FM10K_CONFIG_FLOW_NONE_PORT            0
+#define FM10K_CONFIG_FLOW_EXT_PORT             1
+#define FM10K_CONFIG_FLOW_DPDK_PORT            2
+
+#define FM10K_CONFIG_VALUE_NULL                        0
+#define FM10K_CONFIG_VALUE_INT                 1
+#define FM10K_CONFIG_VALUE_STR                 2
+
+/* SWITCH config */
+#define FM10K_CONFIG_PORT_MAP_NULL             0
+#define FM10K_CONFIG_PORT_MAP_PF               1
+#define FM10K_CONFIG_PORT_MAP_PFS              2
+#define FM10K_CONFIG_PORT_MAP_PFSS             3
+
+/* DPDK port */
+#define        FM10K_CONFIG_DPDK_NULL                  0
+#define FM10K_CONFIG_DPDK_PF                   1
+#define FM10K_CONFIG_DPDK_VF                   2
+#define FM10K_CONFIG_DPDK_MAX                  3
+
+struct fm10k_cfg_port_pf_map {
+       uint8_t type;
+       uint8_t map_no[2];
+};
+
+/* Configuration read from file */
+struct fm10k_cfg_config_item {
+       uint8_t  type;
+       uint8_t  val_type;
+       uint16_t key_param;
+       const char *describe;
+       union {
+               int64_t int64;
+               char *str;
+       } val;
+};
+
+struct fm10k_hw;
+
+struct fm10k_dpdk_port {
+       uint8_t type;
+       struct fm10k_hw *hw;
+       void *rte_dev;
+       void *flow_list;
+       uint16_t pf_no;
+       uint8_t tx_queue_num;
+       uint8_t rx_queue_num;
+};
+
+
+/* Flow configuration */
+struct fm10k_cfg_port {
+       uint8_t port_type;
+       uint8_t port_no;
+       uint16_t vlan_id;
+};
+
+struct fm10k_cfg_flow {
+       /* set by configuration */
+       struct fm10k_cfg_flow *prev;
+       struct fm10k_cfg_flow *next;
+       uint8_t flow_no; /* only configured flow has this NO. */
+       struct fm10k_cfg_port src_port;
+       struct fm10k_cfg_port fw_port[2];
+       /* set by ffu rule add */
+       uint16_t rule_id;
+};
+
+#define FM10K_CONFIG_FLOWSET_NAME_MAX  256
+struct fm10k_cfg_flowset {
+       char name[FM10K_CONFIG_FLOWSET_NAME_MAX];
+       struct fm10k_cfg_flow flow_head;
+       struct fm10k_cfg_flowset *next;
+};
+
+/* Configuration */
+struct fm10k_dpdk_cfg {
+       uint8_t pf_num;                 /* configure by conf */
+       uint8_t pf_bind;                /* initialize by dpdk */
+       uint8_t pf_max;                 /* set by card type */
+       uint8_t ext_port_num;   /* configure by conf */
+       uint8_t ext_port_speed; /* configure by conf */
+       uint32_t debug_cfg;             /* configure by conf */
+       uint32_t stats_interval;/* configure by conf */
+
+       struct fm10k_hw *master_hw; /* initialize by dpdk */
+       struct fm10k_hw *pf_hw[FM10K_SW_PEP_PORTS_MAX]; /* initialize by dpdk */
+
+       /* initialize by dpdk */
+       struct fm10k_dpdk_port ports[FM10K_SW_LOGICAL_PORTS_MAX];
+       /* configure by conf or default*/
+       struct fm10k_cfg_port_pf_map dpdk_port_map
+                                       [FM10K_SW_LOGICAL_PORTS_MAX];
+       /* configure by conf */
+       struct fm10k_cfg_port_pf_map ext_port_map[FM10K_SW_EXT_PORTS_MAX];
+       struct fm10k_cfg_config_item *config_list; /* configure by conf */
+       struct fm10k_cfg_flowset flowset_head; /* transfer from conf file */
+       struct fm10k_cfg_flowset *current;
+};
+
+static inline bool
+fm10k_config_check_debug(struct fm10k_dpdk_cfg *cfg, uint16_t dbg)
+{
+       return cfg->debug_cfg & 1 << (dbg - FM10K_CONFIG_DEBUG_START) &&
+                  cfg->debug_cfg & 1;
+}
+
+struct fm10k_cfg_flowset *fm10k_config_flowset_get(const char *name);
+struct fm10k_cfg_flowset *fm10k_config_flowset_current_get(void);
+void fm10k_config_flowset_current_set(struct fm10k_cfg_flowset *new);
+void fm10k_config_flow_list_add_tail(struct fm10k_cfg_flowset *flowset,
+                               struct fm10k_cfg_flow *flow);
+void fm10k_config_flow_list_delete(struct fm10k_cfg_flow *flow);
+bool fm10k_config_flow_list_end(struct fm10k_cfg_flow *list,
+                               struct fm10k_cfg_flow *flow);
+
+void fm10k_config_cfg_flowset_show(void);
+struct fm10k_hw *fm10k_config_hw_get(int port_no);
+int fm10k_config_init(struct fm10k_switch *sw, struct fm10k_hw *hw);
+
+#endif /* _FM10K_CONFIG_H */
diff --git a/drivers/net/fm10k/switch/fm10k_ffu.c 
b/drivers/net/fm10k/switch/fm10k_ffu.c
new file mode 100644
index 0000000..c2e8491
--- /dev/null
+++ b/drivers/net/fm10k/switch/fm10k_ffu.c
@@ -0,0 +1,1209 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2019   Silicom Ltd. Connectivity Solutions
+ */
+
+#include <rte_time.h>
+#include <rte_kvargs.h>
+#include <rte_hash.h>
+#include <rte_flow.h>
+#include <rte_flow_driver.h>
+#include <rte_tm_driver.h>
+
+#include "../base/fm10k_type.h"
+#include "../base/fm10k_osdep.h"
+
+#include "../fm10k.h"
+#include "../fm10k_logs.h"
+#include "fm10k_debug.h"
+#include "fm10k_regs.h"
+#include "fm10k_switch.h"
+#include "fm10k_config.h"
+#include "fm10k_ffu.h"
+#include "fm10k_stats.h"
+
+/*
+ * one SLICE for 40bits SEL
+ * SLICE 28   FOR SEL SGLORT(16bits) and VLAN(16bits)
+ *            FOR ACT ROUTE
+ * SLICE 29   FOR SEL ETHER_TYPE(16bits)
+ *                       FOR ACT MIRROR | SET_VLAN
+ * SLICE 30   FOR SEL MPLS_LABEL0(32bits)
+ * SLICE 31   FOR SEL MPLS_LABEL1(32bits)
+ */
+#define FM10K_FFU_SLICE_START                  28
+#define FM10K_FFU_SLICE_SGLORT_VID             28
+#define FM10K_FFU_SLICE_ETYPE_VID2             29
+#define FM10K_FFU_SLICE_MPLS_LABEL0            30
+#define FM10K_FFU_SLICE_MPLS_LABEL1            31
+
+#define FM10K_FFU_SLICE_SGLORT_VLAN_CFG            \
+               (FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_0, \
+                               FM10K_SW_FFU_MUX_SEL_SGLORT) | \
+               FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_1, \
+                               FM10K_SW_FFU_MUX_SEL_SGLORT) | \
+               FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_2, \
+                               FM10K_SW_FFU_MUX_SEL_VPRI_VID) | \
+               FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_3, \
+                               FM10K_SW_FFU_MUX_SEL_VPRI_VID) | \
+               FM10K_SW_FFU_SLICE_CFG_START_ACTION | \
+               FM10K_SW_FFU_SLICE_CFG_START_COMPARE | \
+               FM10K_SW_FFU_SLICE_CFG_VALID_LOW)
+
+#define FM10K_FFU_SLICE_ETHER_TYPE_CFG     \
+               (FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_0, \
+                               FM10K_SW_FFU_MUX_SEL_L2_TYPE) | \
+               FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_1, \
+                               FM10K_SW_FFU_MUX_SEL_L2_TYPE) | \
+               FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_2, \
+                               FM10K_SW_FFU_MUX_SEL_VPRI2_VID2) | \
+               FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_3, \
+                               FM10K_SW_FFU_MUX_SEL_VPRI2_VID2) | \
+               FM10K_SW_FFU_SLICE_CFG_VALID_LOW)
+
+#define FM10K_FFU_SLICE_MPLS_LABEL0_CFG            \
+               (FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_0, \
+                               FM10K_SW_FFU_MUX_SEL_L3_SIP_127_96) | \
+               FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_1, \
+                               FM10K_SW_FFU_MUX_SEL_L3_SIP_127_96) | \
+               FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_2, \
+                               FM10K_SW_FFU_MUX_SEL_L3_SIP_127_96) | \
+               FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_3, \
+                               FM10K_SW_FFU_MUX_SEL_L3_SIP_127_96) | \
+               FM10K_SW_FFU_SLICE_CFG_START_COMPARE | \
+               FM10K_SW_FFU_SLICE_CFG_VALID_LOW)
+
+#define FM10K_FFU_SLICE_MPLS_LABEL1_CFG            \
+               (FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_0, \
+                               FM10K_SW_FFU_MUX_SEL_L3_SIP_95_64) | \
+               FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_1, \
+                               FM10K_SW_FFU_MUX_SEL_L3_SIP_95_64) | \
+               FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_2, \
+                               FM10K_SW_FFU_MUX_SEL_L3_SIP_95_64) | \
+               FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_CFG_SELECT_3, \
+                               FM10K_SW_FFU_MUX_SEL_L3_SIP_95_64) | \
+               FM10K_SW_FFU_SLICE_CFG_START_COMPARE | \
+               FM10K_SW_FFU_SLICE_CFG_VALID_LOW)
+
+static uint64_t fm10k_ffu_slice_cfgs[4] = {
+               FM10K_FFU_SLICE_SGLORT_VLAN_CFG,
+               FM10K_FFU_SLICE_ETHER_TYPE_CFG,
+               FM10K_FFU_SLICE_MPLS_LABEL0_CFG,
+               FM10K_FFU_SLICE_MPLS_LABEL1_CFG
+};
+
+#define FM10K_FFU_INIT_PRINT(cfg, ...)         do { \
+       if (fm10k_config_check_debug(cfg, FM10K_CONFIG_DEBUG_FFU_INIT)) \
+               printf(__VA_ARGS__); \
+} while (0)
+
+#define FM10K_FFU_RULE_PRINT(cfg, ...)         do { \
+       if (fm10k_config_check_debug(cfg, FM10K_CONFIG_DEBUG_FFU_RULE)) \
+               printf(__VA_ARGS__); \
+} while (0)
+
+#define FM10K_FFU_CNT_INDEX(x)         (FM10K_SW_FFU_CNT_START + (x))
+
+#define FM10K_FFU_FLOW_START           10
+#define FM10K_FFU_MIRROR_PROFILE       1
+
+#define FM10K_FFU_SGLORT_TYPE_NULL     0
+#define FM10K_FFU_SGLORT_TYPE_EPL      1
+#define FM10K_FFU_SGLORT_TYPE_PF       2
+#define FM10K_FFU_SGLORT_TYPE_PFS      3
+#define FM10K_FFU_SGLORT_TYPE_DPDK     4
+
+struct fm10k_ffu_rule_data {
+       uint16_t sglort_type;
+       uint16_t cond_sglort;
+       uint16_t cond_vlan;
+       uint16_t act_dglort;
+       uint16_t act_vlan;
+       uint16_t bypass_dglort;
+       uint16_t bypass_vlan;
+};
+
+
+static uint8_t fm10k_ffu_bitmap[FM10K_FFU_RULE_MAX / 8];
+static uint8_t
+fm10k_ffu_rule_get_bit(int id)
+{
+       int num = id / 8;
+       int offset = id % 8;
+
+       return (fm10k_ffu_bitmap[num] >> offset) & 0x1;
+}
+
+static void
+fm10k_ffu_rule_set_bit(int id, uint8_t bit)
+{
+       int num = id / 8;
+       int offset = id % 8;
+       uint8_t tmp = fm10k_ffu_bitmap[num];
+       uint8_t data = 1;
+
+       if (bit == 0)
+               fm10k_ffu_bitmap[num] = tmp & ~(data << offset);
+       else
+               fm10k_ffu_bitmap[num] |= (data << offset);
+}
+
+static int
+fm10k_ffu_rule_alloc(void)
+{
+       int i;
+
+       for (i = FM10K_FFU_FLOW_START; i < FM10K_FFU_RULE_MAX; i++)     {
+               if (fm10k_ffu_rule_get_bit(i) != 0)
+                       continue;
+               fm10k_ffu_rule_set_bit(i, 1);
+               return i;
+       }
+       return -1;
+}
+
+static void
+fm10k_ffu_rule_free(int id)
+{
+       fm10k_ffu_rule_set_bit(id, 0);
+}
+
+static void
+fm10k_ffu_always_mismatch(struct fm10k_switch *sw,
+               unsigned int slice, unsigned int idx)
+{
+       uint64_t temp64;
+
+       temp64 =
+           FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_TCAM_KEY, ~0ULL) |
+           FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_TCAM_KEY_TOP, ~0ULL);
+       fm10k_write_switch_reg128(sw, FM10K_SW_FFU_SLICE_TCAM(slice, idx),
+           temp64, temp64);
+}
+
+static void
+fm10k_ffu_route_dglort(struct fm10k_switch *sw, unsigned int slice,
+                       unsigned int idx, uint16_t sglort, uint16_t dglort)
+{
+       uint64_t temp64, temp64_2;
+
+       /*
+        * Set the key to exact match on the 16 SGLORT bits and
+        * always match everywhere else.
+        */
+       temp64 = FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_TCAM_KEY, sglort);
+       temp64_2 =
+               FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_TCAM_KEY, ~sglort & 0xffff);
+       fm10k_write_switch_reg128(sw,
+                       FM10K_SW_FFU_SLICE_TCAM(slice, idx),
+                       temp64_2, temp64);
+
+       /*
+        * Set the corresponding SRAM entry to ROUTE_GLORT to the
+        * corresponding DGLORT.
+        */
+       temp64 = 0x40;
+       temp64 = temp64 << 32 |
+           FM10K_SW_MAKE_REG_FIELD(FFU_SLICE_SRAM_ROUTE_GLORT_DGLORT, dglort);
+       temp64 |=
+               FM10K_SW_MAKE_REG_FIELD64(FFU_SLICE_SRAM_COMMAND,
+           FM10K_SW_FFU_SLICE_SRAM_COMMAND_ROUTE_GLORT);
+       /*
+        * 11.5.4.2 FFU_SLICE_SRAM[0..31][0..1023]
+        */
+       temp64_2 =
+               FM10K_SW_FFU_CNT_BANK << (35 - 23) |
+               (FM10K_SW_FFU_CNT_START + idx);
+       temp64 |= temp64_2 << 23;
+       fm10k_write_switch_reg64(sw,
+                       FM10K_SW_FFU_SLICE_SRAM(slice, idx), temp64);
+}
+
+
+static void
+fm10k_ffu_set_dest_glort_mask(struct fm10k_switch *sw,
+               unsigned int idx, uint16_t dglort, uint64_t dport_mask)
+{
+       uint64_t temp64;
+       unsigned int multiple_dports;
+       unsigned int num_dports;
+       unsigned int amplification_factor;
+       unsigned int hashed_entries;
+       unsigned int i, j;
+
+       multiple_dports = (dport_mask & (dport_mask - 1));
+
+       FM10K_FFU_INIT_PRINT(sw->dpdk_cfg,
+                       "%s set glort %#x to port ", __func__, dglort);
+       /*
+        * Create an exact-match key for the given DGLORT in the DGLORT CAM.
+        */
+       fm10k_write_switch_reg(sw, FM10K_SW_GLORT_CAM(idx),
+           FM10K_SW_MAKE_REG_FIELD(GLORT_CAM_KEY, dglort) |
+           FM10K_SW_MAKE_REG_FIELD(GLORT_CAM_KEY_INVERT, ~dglort));
+
+       if (multiple_dports) {
+               /*
+                * Create a pair of entries and use the hash value to select
+                * among them.
+                */
+               num_dports = 0;
+               for (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++)
+                       if (dport_mask & (1ULL << i)) {
+                               num_dports++;
+                               FM10K_FFU_INIT_PRINT(sw->dpdk_cfg, " %d", i);
+                       }
+               FM10K_FFU_INIT_PRINT(sw->dpdk_cfg, "\n");
+
+               /*
+                * Create multiple entries for each dport to increase the
+                * hash modulus and capture more hash entropy.  The maximum
+                * number of hashed entries is 16.
+                */
+               amplification_factor = 16 / num_dports;
+               hashed_entries = num_dports * amplification_factor;
+               temp64 =
+                       FM10K_SW_MAKE_REG_FIELD64(GLORT_RAM_STRICT,
+                   FM10K_SW_GLORT_RAM_STRICT_HASHED);
+               temp64 |=
+                       FM10K_SW_MAKE_REG_FIELD64(GLORT_RAM_DEST_INDEX,
+                       sw->glort_dest_table_idx);
+               temp64 |=
+                       FM10K_SW_MAKE_REG_FIELD64(GLORT_RAM_DEST_COUNT,
+                       hashed_entries);
+               fm10k_write_switch_reg64(sw, FM10K_SW_GLORT_RAM(idx), temp64);
+
+               for (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++)
+                       if (dport_mask & (1ULL << i))
+                               for (j = 0; j < amplification_factor; j++) {
+                                       fm10k_write_switch_reg64(sw,
+                                           FM10K_SW_GLORT_DEST_TABLE
+                                               (sw->glort_dest_table_idx),
+                                           FM10K_SW_MAKE_REG_FIELD64
+                                               (GLORT_DEST_TABLE_MASK,
+                                               (1ULL << i)));
+                                       sw->glort_dest_table_idx++;
+                               }
+       } else {
+               /*
+                * Set the corresponding entry in the DGLORT map RAM to use
+                * strict indexing straight into the DEST_TABLE, then write
+                * the corresponding destination port in the DEST_TABLE.
+                */
+
+               temp64 =
+                       FM10K_SW_MAKE_REG_FIELD64(GLORT_RAM_STRICT,
+                   FM10K_SW_GLORT_RAM_STRICT_STRICT);
+               temp64 |=
+                       FM10K_SW_MAKE_REG_FIELD64(GLORT_RAM_DEST_INDEX,
+                       sw->glort_dest_table_idx);
+               fm10k_write_switch_reg64(sw,
+                       FM10K_SW_GLORT_RAM(idx), temp64);
+
+               fm10k_write_switch_reg64(sw,
+                       FM10K_SW_GLORT_DEST_TABLE(sw->glort_dest_table_idx),
+                   FM10K_SW_MAKE_REG_FIELD64
+                       (GLORT_DEST_TABLE_MASK,
+                       dport_mask));
+               sw->glort_dest_table_idx++;
+               for (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++)
+                       if (dport_mask & (1ULL << i))
+                               FM10K_FFU_INIT_PRINT(sw->dpdk_cfg, " %d\n", i);
+       }
+}
+
+
+static uint32_t
+fm10k_ffu_set_dest_glort_multi_cast(struct fm10k_switch *sw,
+               uint8_t lport1, uint8_t lport2,
+               uint16_t vlan1, uint16_t vlan2)
+{
+       uint32_t dglort;
+       bool is_new;
+       uint32_t idx;
+       uint64_t temp64;
+
+       dglort =
+               fm10k_switch_multi_glort_get(lport1, lport2,
+                               vlan1, vlan2, &is_new);
+
+       if (!is_new)
+               return dglort;
+
+       FM10K_FFU_INIT_PRINT(sw->dpdk_cfg,
+                       "%s set glort %#x to (%d:%d) (%d:%d)\n",
+                       __func__, dglort, lport1, vlan1, lport2, vlan2);
+       /*
+        * Create an exact-match key for the given DGLORT in the DGLORT CAM.
+        */
+       idx = sw->glort_cam_ram_idx++;
+       fm10k_write_switch_reg(sw, FM10K_SW_GLORT_CAM(idx),
+           FM10K_SW_MAKE_REG_FIELD(GLORT_CAM_KEY, dglort) |
+           FM10K_SW_MAKE_REG_FIELD(GLORT_CAM_KEY_INVERT, ~dglort));
+
+       /*
+        * Create multiple entries for each dport to increase the
+        * hash modulus and capture more hash entropy.  The maximum
+        * number of hashed entries is 16.
+        */
+       temp64 =
+               FM10K_SW_MAKE_REG_FIELD64(GLORT_RAM_STRICT,
+           FM10K_SW_GLORT_RAM_STRICT_STRICT);
+       temp64 |=
+               FM10K_SW_MAKE_REG_FIELD64(GLORT_RAM_DEST_INDEX,
+               sw->glort_dest_table_idx);
+       fm10k_write_switch_reg64(sw,
+                       FM10K_SW_GLORT_RAM(idx), temp64);
+
+       /* GLORT_DEST_TABLE
+        * Field Name           Bit(s)  Type    Default
+        * DestMask                     47:0    RW              0x0
+        * IP_MulticastIndex59:48       RW              0x0
+        * Reserved                     63:60   RSV             0x0
+        */
+       temp64 = sw->mcast_dest_table_idx;
+       temp64 = temp64 << 48 | 1 << lport1 | 1 << lport2;
+       fm10k_write_switch_reg64(sw,
+                       FM10K_SW_GLORT_DEST_TABLE
+                       (sw->glort_dest_table_idx), temp64);
+       sw->glort_dest_table_idx++;
+
+       /* MCAST_DEST_TABLE
+        * Field Name           Bit(s)  Type    Default
+        * PortMask                     47:0    RW              0x0
+        * LenTableIdx          61:48   RW              0x0
+        * Reserved                     63:62   RSV             00b
+        */
+       temp64 = sw->mcast_len_table_idx;
+       temp64 = 1 << lport1 | 1 << lport2 | temp64 << 48;
+       fm10k_write_switch_reg64(sw,
+                       FM10K_SW_SCHED_MCAST_DEST_TABLE
+                       (sw->mcast_dest_table_idx++), temp64);
+
+       /* MCAST_LEN_TABLE
+        * Field Name           Bit(s)  Type    Default
+        * L3_McastIdx          14:0    RW              0x0
+        * L3_Repcnt            26:15   RW              0x0
+        * Reserved                     31:27   RSV             0x0
+        */
+       temp64 =
+               sw->mcast_vlan_table_idx | 1 << 15;
+       fm10k_write_switch_reg64(sw,
+                       FM10K_SW_SCHED_MCAST_LEN_TABLE
+                       (sw->mcast_len_table_idx++), temp64);
+
+       /* MCAST_VLAN_TABLE
+        * Field Name           Bit(s)  Type    Default
+        * VID                          11:0    RW              0x0
+        * DGLORT                       27:12   RW              0x0
+        * ReplaceVID           28              RW              0b
+        * ReplaceDGLORT        29              RW              0b
+        * Reserved                     31:30   RSV             00b
+        */
+       temp64 = vlan1 |
+                       fm10k_switch_pf_glort_get
+                       (lport1) << 12 | 1 << 28 | 1 << 29;
+       fm10k_write_switch_reg64(sw,
+                       FM10K_SW_MOD_MCAST_VLAN_TABLE
+                       (sw->mcast_vlan_table_idx++), temp64);
+       temp64 = vlan2 |
+                       fm10k_switch_pf_glort_get
+                       (lport2) << 12 | 1 << 28 | 1 << 29;
+       fm10k_write_switch_reg64(sw,
+                       FM10K_SW_MOD_MCAST_VLAN_TABLE
+                       (sw->mcast_vlan_table_idx++), temp64);
+
+       return dglort;
+}
+
+static uint64_t
+fm10k_data64_field64_get(uint64_t data, int start, int end)
+{
+       uint64_t tmp64 = data;
+
+       if (start == end) {
+               tmp64 = (data >> start) & 1;
+       } else {
+               tmp64 = tmp64 << (64 - end);
+               tmp64 = tmp64 >> (64 - end + start);
+       }
+       return tmp64;
+}
+
+static uint32_t
+fm10k_data64_field32_get(uint64_t data, int start, int end)
+{
+       uint64_t tmp64 = data;
+       uint32_t tmp32;
+
+       if (start == end) {
+               tmp32 = (data >> start) & 1;
+       } else {
+               tmp64 = tmp64 << (64 - end);
+               tmp32 = tmp64 >> (64 - end + start);
+       }
+       return tmp32;
+}
+
+static uint32_t
+fm10k_data32_field_get(uint32_t data, int start, int end)
+{
+       uint32_t tmp32 = data;
+
+       if (start == end) {
+               tmp32 = (data >> start) & 1;
+       } else {
+               tmp32 = tmp32 << (64 - end);
+               tmp32 = tmp32 >> (64 - end + start);
+       }
+       return tmp32;
+}
+
+
+static void
+fm10k_glort_register_dump(struct fm10k_switch *sw)
+{
+       uint32_t i;
+       uint64_t data64;
+       uint32_t data32;
+       uint32_t tmp32;
+
+       if (!fm10k_config_check_debug
+               (sw->dpdk_cfg, FM10K_CONFIG_DEBUG_FFU_REG))
+               return;
+
+       printf("----- GLORT -----\n");
+
+       for (i = 0; i < sw->glort_cam_ram_idx; i++)     {
+               data32 = fm10k_read_switch_reg(sw, FM10K_SW_GLORT_CAM(i));
+               printf("[%02u]GLORT_CAM %#x Key %#x\n", i, data32,
+                               fm10k_data32_field_get(data32, 0, 15));
+               data64 = fm10k_read_switch_reg64(sw, FM10K_SW_GLORT_RAM(i));
+               printf("    GLORT_RAM %#llx Strict %u DestIndex %u\n",
+                               (unsigned long long)data64,
+                               fm10k_data64_field32_get(data64, 0, 1),
+                               fm10k_data64_field32_get(data64, 2, 13));
+               tmp32 = fm10k_data64_field32_get(data64, 2, 13);
+               data64 =
+                       fm10k_read_switch_reg64(sw,
+                               FM10K_SW_GLORT_DEST_TABLE(tmp32));
+               printf("    GLORT_DEST_TABLE[%u] %#llx IP_MulticastIndex %u\n",
+                               tmp32, (unsigned long long)data64,
+                               fm10k_data64_field32_get(data64, 48, 59));
+               tmp32 = fm10k_data64_field32_get(data64, 48, 59);
+               if (tmp32 == 0)
+                       continue;
+               data64 = fm10k_read_switch_reg64(sw,
+                               FM10K_SW_SCHED_MCAST_DEST_TABLE(tmp32));
+               printf("    SCHED_MCAST_DEST_TABLE[%u] %#llx PortMask %#llx"
+                               " LenTableIdx %u\n", tmp32,
+                               (unsigned long long)data64,
+                               (unsigned long long)
+                               fm10k_data64_field64_get(data64, 0, 47),
+                               fm10k_data64_field32_get(data64, 48, 61));
+               tmp32 = fm10k_data64_field32_get(data64, 48, 61);
+               data32 = fm10k_read_switch_reg(sw,
+                               FM10K_SW_SCHED_MCAST_LEN_TABLE(tmp32));
+               printf("    SCHED_MCAST_LEN_TABLE[%u] %#x "
+                               "L3_McastIdx %u L3_Repcnt %u\n",
+                               tmp32, data32,
+                               fm10k_data32_field_get(data32, 0, 14),
+                               fm10k_data32_field_get(data32, 15, 26));
+               tmp32 = fm10k_data32_field_get(data32, 0, 14);
+               data32 = fm10k_read_switch_reg(sw,
+                               FM10K_SW_MOD_MCAST_VLAN_TABLE(tmp32));
+               printf("    MOD_MCAST_VLAN_TABLE[%u] %#x VID %u "
+                               "DGLORT %#x ReplaceVID %u ReplaceDGLORT %u\n",
+                               tmp32, data32,
+                               fm10k_data32_field_get(data32, 0, 11),
+                               fm10k_data32_field_get(data32, 12, 27),
+                               fm10k_data32_field_get(data32, 28, 28),
+                               fm10k_data32_field_get(data32, 29, 29));
+               data32 = fm10k_read_switch_reg(sw,
+                               FM10K_SW_MOD_MCAST_VLAN_TABLE(tmp32 + 1));
+               printf("    MOD_MCAST_VLAN_TABLE[%u] %#x VID %u "
+                               "DGLORT %#x ReplaceVID %u ReplaceDGLORT %u\n",
+                               tmp32 + 1, data32,
+                               fm10k_data32_field_get(data32, 0, 11),
+                               fm10k_data32_field_get(data32, 12, 27),
+                               fm10k_data32_field_get(data32, 28, 28),
+                               fm10k_data32_field_get(data32, 29, 29));
+       }
+}
+
+static void
+fm10k_ffu_register_dump(struct fm10k_switch *sw)
+{
+       int i, j;
+       uint32_t data[8];
+       uint32_t ffu_valid;
+
+       if (!fm10k_config_check_debug(sw->dpdk_cfg, FM10K_CONFIG_DEBUG_FFU_REG))
+               return;
+
+       printf("--------------- FFU REGISTERS DUMP ------------------\n");
+
+       fm10k_read_switch_array(sw, FM10K_SW_FFU_MASTER_VALID, data, 2);
+       printf("FFU_MASTER_VALID: %#x %#x\n", data[0], data[1]);
+       ffu_valid = data[0];
+
+       for (i = 0; i < 32; i++) {
+               if ((ffu_valid & (1 << i)) == 0)
+                       continue;
+
+               printf("------ SLICE%d ------\n", i);
+               fm10k_read_switch_array(sw,
+                               FM10K_SW_FFU_SLICE_VALID(i), data, 2);
+               if (data[0] != 0 || data[1] != 0)
+                       printf("FFU_SLICE_VALID[%d]: %#x %#x\n",
+                               i, data[0], data[1]);
+
+               fm10k_read_switch_array(sw,
+                               FM10K_SW_FFU_SLICE_CASCADE_ACTION(i), data, 2);
+               if (data[0] != 0 || data[1] != 0)
+                       printf("FFU_SLICE_CASCADE_ACTION[%d]: %#x %#x\n",
+                               i, data[0], data[1]);
+
+               for (j = 0; j < 1; j++) {
+                       fm10k_read_switch_array(sw,
+                                       FM10K_SW_FFU_SLICE_CFG(i, j), data, 2);
+                       if (data[0] != 0 || data[1] != 0)
+                               printf("FFU_SLICE_CFG[%d][%d]: %#x %#x\n",
+                                               i, j, data[0], data[1]);
+               }
+               for (j = 0; j < 32; j++) {
+                       fm10k_read_switch_array(sw,
+                                       FM10K_SW_FFU_SLICE_TCAM(i, j), data, 4);
+                       if ((data[0] != 0 || data[1] != 0 ||
+                                       data[2] != 0 || data[3] != 0))
+                               printf("FFU_SLICE_TCAM[%d][%d]: %#x %#x %#x 
%#x\n",
+                                       i, j, data[0], data[1],
+                                       data[2], data[3]);
+
+                       fm10k_read_switch_array(sw,
+                                       FM10K_SW_FFU_SLICE_SRAM(i, j), data, 2);
+                       if (data[0] != 0 || data[1] != 0)
+                               printf("FFU_SLICE_SRAM[%d][%d]: %#x %#x\n",
+                                       i, j, data[0], data[1]);
+               }
+       }
+}
+
+
+static void
+fm10k_ffu_mirror_set_action(struct fm10k_switch *sw,
+               uint16_t ffu_slice,     uint16_t table_idx)
+{
+       uint64_t data64;
+
+       /* blank the next ffu slice */
+       fm10k_write_switch_reg128(sw,
+               FM10K_SW_FFU_SLICE_TCAM
+               (ffu_slice, table_idx), 0xffffffffff, 0x1);
+       /* SET FFU RX_MIRROR */
+       data64 = 0x60; /* higher than route, not necessary */
+       data64 = data64 << 32 | 0x2 << 21 | 1 << (8 + 4) | 1 << 4;
+       fm10k_write_switch_reg64(sw,
+                       FM10K_SW_FFU_SLICE_SRAM(ffu_slice, table_idx), data64);
+}
+
+static void
+fm10k_ffu_mirror_set_forward(struct fm10k_switch *sw,
+               int profile,
+               uint16_t vlan,
+               uint16_t dest_lport,
+               uint32_t dest_sglort)
+{
+       uint64_t data64;
+
+       /* RX_MIRROR_CFG */
+       fm10k_write_switch_reg(sw, 0xd50000 + 0xd, profile);
+
+       /* FH_MIRROR_PROFILE_TABLE */
+       fm10k_write_switch_reg(sw,
+                       0xd50000 + 0x1 * profile + 0x40, dest_lport);
+
+       /* MOD_MIRROR_PROFILE_TABLE don't work */
+       data64 = vlan;
+       data64 = (dest_sglort & 0xffff) | data64 << 17;
+       fm10k_write_switch_reg64(sw,
+                       0xe80000 + 0x2 * profile + 0x24000, data64);
+}
+
+
+int
+fm10k_ffu_mirror_set(struct fm10k_switch *sw,
+               uint16_t src_ext_port,
+               uint16_t dest_ext_port,
+               uint16_t vlan)
+{
+       uint16_t table_idx;
+       uint16_t ffu_slice = FM10K_FFU_SLICE_SGLORT_VID + 1;
+       uint16_t mirror_profile = FM10K_FFU_MIRROR_PROFILE;
+
+       table_idx = FM10K_FFU_EXT_PORT_RULE_INGRESS(src_ext_port - 1);
+       fm10k_ffu_mirror_set_action(sw, ffu_slice, table_idx);
+
+       fm10k_ffu_mirror_set_forward(sw, mirror_profile,
+                       vlan, sw->epl_map[dest_ext_port - 1].logical_port,
+                       sw->epl_map[dest_ext_port - 1].glort);
+       return 0;
+}
+
+int
+fm10k_ffu_mirror_reset(struct fm10k_switch *sw, int src_ext_port)
+{
+       uint16_t table_idx;
+       uint16_t ffu_slice = FM10K_FFU_SLICE_SGLORT_VID + 1;
+
+       table_idx = FM10K_FFU_EXT_PORT_RULE_INGRESS(src_ext_port - 1);
+       fm10k_write_switch_reg64(sw,
+                       FM10K_SW_FFU_SLICE_SRAM(ffu_slice, table_idx), 0);
+       return 0;
+}
+
+static void
+fm10k_ffu_logical_port_vlan_set(struct fm10k_switch *sw,
+               uint16_t lport, uint16_t vlan_id)
+{
+       uint64_t data;
+
+       /* 11.21.3.9 INGRESS_VID_TABLE[0..4095] */
+       data = fm10k_read_switch_reg64(sw,
+                       0xE80000 + 0x2 * vlan_id + 0x20000);
+       data |= 1 << lport;
+       fm10k_write_switch_reg64(sw,
+                       0xE80000 + 0x2 * vlan_id + 0x20000, data);
+
+       FM10K_FFU_RULE_PRINT(sw->dpdk_cfg,
+                       "%s lport:%d, vlan_id:%d, reg:%#llx\n",
+                       __func__, lport, vlan_id, (unsigned long long)data);
+}
+
+static void
+fm10k_ffu_glort_port_vlan_set(struct fm10k_switch *sw,
+               uint16_t glort, uint16_t vlan_id)
+{
+       int i;
+
+       for (i = 0; i < FM10K_SW_PEPS_SUPPORTED; i++) {
+               if (sw->pep_map[i].glort == glort) {
+                       fm10k_ffu_logical_port_vlan_set(sw,
+                                       sw->pep_map[i].logical_port, vlan_id);
+                       break;
+               }
+       }
+       for (i = 0; i < FM10K_SW_EPLS_SUPPORTED; i++) {
+               if (sw->epl_map[i].glort == glort) {
+                       fm10k_ffu_logical_port_vlan_set(sw,
+                                       sw->epl_map[i].logical_port, vlan_id);
+                       break;
+               }
+       }
+}
+
+
+static uint16_t
+fm10k_ffu_dpdk_port_glort_get(struct fm10k_switch *sw, int port)
+{
+       int pf;
+       uint16_t glort = 0;
+
+       if (sw->dpdk_cfg->dpdk_port_map[port].type ==
+                       FM10K_CONFIG_PORT_MAP_PFS ||
+               sw->dpdk_cfg->dpdk_port_map[port].type ==
+                       FM10K_CONFIG_PORT_MAP_PFSS) {
+               glort = fm10k_switch_pfs_glort_get
+                               (sw->dpdk_cfg->dpdk_port_map[port].map_no[0],
+                               sw->dpdk_cfg->dpdk_port_map[port].map_no[1]);
+       } else if (sw->dpdk_cfg->dpdk_port_map[port].type ==
+                       FM10K_CONFIG_PORT_MAP_PF) {
+               pf = sw->dpdk_cfg->dpdk_port_map[port].map_no[0];
+               glort = fm10k_switch_pf_glort_get(pf);
+       }
+       return glort;
+}
+
+static void
+fm10k_ffu_rule_enable_single_cast(struct fm10k_switch *sw,
+               int rule_id,
+               uint16_t sglort,
+               uint16_t svlan,
+               uint16_t dglort,
+               uint16_t dvlan)
+{
+       uint64_t temp64;
+       uint64_t sglort_vid_tcam = 0, sglort_vid_tcam_mask = 0;
+       uint64_t sram[4] = { 0, 0, 0, 0 };
+       uint16_t sram_idx = 0, tcam_slice, sram_slice, i;
+
+       sglort_vid_tcam |= sglort;
+       sglort_vid_tcam_mask |= 0xffff;
+       if (svlan) {
+               temp64 = svlan;
+               sglort_vid_tcam |= temp64 << 16;
+               sglort_vid_tcam_mask |= 0xfff0000;
+               fm10k_ffu_glort_port_vlan_set(sw, sglort, svlan);
+       }
+
+       /* set counter */
+       sram[sram_idx] |=
+                       FM10K_SW_MAKE_REG_FIELD64
+                       (FFU_SLICE_SRAM_COUNTER_BANK,
+                       FM10K_SW_FFU_CNT_BANK) |
+                       FM10K_SW_MAKE_REG_FIELD64
+                       (FFU_SLICE_SRAM_COUNTER_INDEX,
+                       FM10K_FFU_CNT_INDEX(rule_id));
+
+       sram[sram_idx] |=
+                       FM10K_SW_MAKE_REG_FIELD64
+                       (FFU_SLICE_SRAM_PRECEDENCE, 3) |
+                   FM10K_SW_MAKE_REG_FIELD
+                       (FFU_SLICE_SRAM_ROUTE_GLORT_DGLORT, dglort) |
+                       FM10K_SW_MAKE_REG_FIELD64
+                       (FFU_SLICE_SRAM_COMMAND,
+                       FM10K_SW_FFU_SLICE_SRAM_COMMAND_ROUTE_GLORT);
+       sram_idx++;
+
+       if (dvlan) {
+               /* Force updating VLAN tag if present.
+                * Add if absent. 11.5.3.4
+                */
+               temp64 = 3;
+               sram[sram_idx] =
+                       temp64 << 16 | dvlan |
+                       FM10K_SW_MAKE_REG_FIELD64
+                       (FFU_SLICE_SRAM_PRECEDENCE, 2) |
+                       FM10K_SW_MAKE_REG_FIELD64
+                       (FFU_SLICE_SRAM_COMMAND,
+                       FM10K_SW_FFU_SLICE_SRAM_COMMAND_FIELD_SET);
+               fm10k_ffu_glort_port_vlan_set(sw, dglort, dvlan);
+               sram_idx++;
+       }
+
+       if (sglort_vid_tcam) {
+               tcam_slice = FM10K_FFU_SLICE_SGLORT_VID;
+               temp64 =
+                       FM10K_SW_MAKE_REG_FIELD64
+                       (FFU_SLICE_TCAM_KEY,
+                       ~sglort_vid_tcam & sglort_vid_tcam_mask);
+               fm10k_write_switch_reg128(sw,
+                       FM10K_SW_FFU_SLICE_TCAM(tcam_slice, rule_id),
+                       temp64, sglort_vid_tcam);
+               FM10K_FFU_RULE_PRINT(sw->dpdk_cfg,
+                       "TCAM slice:%d, rule:%d, data0:%#llx, data1:%#llx\n",
+                       tcam_slice, rule_id,
+                       (unsigned long long)sglort_vid_tcam,
+                       (unsigned long long)temp64);
+       }
+
+       /* blank the next SLICE TCAM */
+       fm10k_ffu_always_mismatch(sw, tcam_slice + 1, rule_id);
+
+       for (i = 0; i < sram_idx; i++) {
+               sram_slice = FM10K_FFU_SLICE_START + i;
+               fm10k_write_switch_reg64(sw,
+                       FM10K_SW_FFU_SLICE_SRAM(sram_slice, rule_id), sram[i]);
+               FM10K_FFU_RULE_PRINT(sw->dpdk_cfg,
+                       "SRAM slice:%d, rule:%d, data:%#llx\n",
+                       sram_slice, rule_id, (unsigned long long)sram[i]);
+       }
+       /* disable the next SLICE SRAM */
+       fm10k_write_switch_reg64(sw,
+                       FM10K_SW_FFU_SLICE_SRAM(sram_slice + 1, rule_id), 0);
+
+       fm10k_stats_rule_count_reg(rule_id);
+}
+
+static void
+fm10k_ffu_rule_enable_multi_cast(struct fm10k_switch *sw,
+               int rule_id,
+               uint16_t sglort,
+               uint16_t svlan,
+               uint8_t lport1,
+               uint8_t lport2,
+               uint16_t vlan1,
+               uint16_t vlan2)
+{
+       uint64_t temp64;
+       uint32_t dglort;
+       uint64_t sglort_vid_tcam = 0, sglort_vid_tcam_mask = 0;
+       uint64_t sram[4] = { 0, 0, 0, 0 };
+       uint16_t sram_idx = 0, tcam_slice, sram_slice, i;
+
+       dglort =
+               fm10k_ffu_set_dest_glort_multi_cast(sw,
+                               lport1, lport2, vlan1, vlan2);
+
+       sglort_vid_tcam |= sglort;
+       sglort_vid_tcam_mask |= 0xffff;
+       if (svlan) {
+               temp64 = svlan;
+               sglort_vid_tcam |= temp64 << 16;
+               sglort_vid_tcam_mask |= 0xfff0000;
+               fm10k_ffu_glort_port_vlan_set(sw, sglort, svlan);
+       }
+
+       fm10k_ffu_logical_port_vlan_set(sw, lport1, vlan1);
+       fm10k_ffu_logical_port_vlan_set(sw, lport2, vlan2);
+
+       /* set counter */
+       sram[sram_idx] |=
+                       FM10K_SW_MAKE_REG_FIELD64
+                       (FFU_SLICE_SRAM_COUNTER_BANK,
+                       FM10K_SW_FFU_CNT_BANK) |
+                       FM10K_SW_MAKE_REG_FIELD64
+                       (FFU_SLICE_SRAM_COUNTER_INDEX,
+                       FM10K_FFU_CNT_INDEX(rule_id));
+
+       sram[sram_idx] |=
+                       FM10K_SW_MAKE_REG_FIELD64
+                       (FFU_SLICE_SRAM_PRECEDENCE, 3) |
+                   FM10K_SW_MAKE_REG_FIELD
+                       (FFU_SLICE_SRAM_ROUTE_GLORT_DGLORT, dglort) |
+                       FM10K_SW_MAKE_REG_FIELD64
+                       (FFU_SLICE_SRAM_COMMAND,
+                       FM10K_SW_FFU_SLICE_SRAM_COMMAND_ROUTE_GLORT);
+       sram_idx++;
+
+       if (sglort_vid_tcam) {
+               tcam_slice = FM10K_FFU_SLICE_SGLORT_VID;
+               temp64 =
+                       FM10K_SW_MAKE_REG_FIELD64
+                       (FFU_SLICE_TCAM_KEY,
+                       ~sglort_vid_tcam & sglort_vid_tcam_mask);
+               fm10k_write_switch_reg128(sw,
+                       FM10K_SW_FFU_SLICE_TCAM(tcam_slice, rule_id),
+                       temp64, sglort_vid_tcam);
+               FM10K_FFU_RULE_PRINT(sw->dpdk_cfg,
+                       "TCAM slice:%d, rule:%d, data0:%#llx, data1:%#llx\n",
+                       tcam_slice, rule_id,
+                       (unsigned long long)sglort_vid_tcam,
+                       (unsigned long long)temp64);
+       }
+
+       /* blank the next SLICE TCAM */
+       fm10k_ffu_always_mismatch(sw, tcam_slice + 1, rule_id);
+
+       for (i = 0; i < sram_idx; i++) {
+               sram_slice = FM10K_FFU_SLICE_START + i;
+               fm10k_write_switch_reg64(sw,
+                       FM10K_SW_FFU_SLICE_SRAM(sram_slice, rule_id), sram[i]);
+               FM10K_FFU_RULE_PRINT(sw->dpdk_cfg,
+                       "SRAM slice:%d, rule:%d, data:%#llx\n",
+                       sram_slice, rule_id, (unsigned long long)sram[i]);
+       }
+       /* disable the next SLICE SRAM */
+       fm10k_write_switch_reg64(sw,
+                       FM10K_SW_FFU_SLICE_SRAM(sram_slice + 1, rule_id), 0);
+
+       fm10k_stats_rule_count_reg(rule_id);
+}
+
+
+void
+fm10k_ffu_flow_enable(struct fm10k_switch *sw, struct fm10k_cfg_flow *flow)
+{
+       uint16_t sglort = 0;
+       uint16_t svlan = 0;
+       uint16_t dglort = 0;
+       uint16_t dvlan = 0;
+       uint16_t lport1 = 0, lport2 = 0;
+       uint16_t dvlan2 = 0;
+
+       switch (flow->src_port.port_type) {
+       case FM10K_CONFIG_FLOW_EXT_PORT:
+               sglort = fm10k_switch_epl_glort_get(flow->src_port.port_no - 1);
+               break;
+       case FM10K_CONFIG_FLOW_DPDK_PORT:
+               sglort =
+                       fm10k_ffu_dpdk_port_glort_get(sw,
+                       flow->src_port.port_no);
+               break;
+       }
+       switch (flow->fw_port[0].port_type) {
+       case FM10K_CONFIG_FLOW_EXT_PORT:
+               dglort =
+                       fm10k_switch_epl_glort_get
+                       (flow->fw_port[0].port_no - 1);
+               lport1 =
+                       fm10k_switch_epl_logical_get
+                       (flow->fw_port[0].port_no - 1);
+               break;
+       case FM10K_CONFIG_FLOW_DPDK_PORT:
+               dglort =
+                       fm10k_ffu_dpdk_port_glort_get
+                       (sw, flow->fw_port[0].port_no);
+               lport1 =
+                       fm10k_switch_pf_logical_get
+                       (flow->fw_port[0].port_no);
+               break;
+       }
+       svlan = flow->src_port.vlan_id;
+       dvlan = flow->fw_port[0].vlan_id;
+
+       flow->rule_id = fm10k_ffu_rule_alloc();
+
+       FM10K_FFU_RULE_PRINT(sw->dpdk_cfg,
+               "Set rule cond sglort:%#x, vlan:%d ==> "
+               "act dglort:%#x, vlan:%d",
+               sglort, svlan, dglort, dvlan);
+
+       if (flow->fw_port[1].port_type) {
+               switch (flow->fw_port[1].port_type)     {
+               case FM10K_CONFIG_FLOW_EXT_PORT:
+                       dglort =
+                               fm10k_switch_epl_glort_get
+                               (flow->fw_port[1].port_no - 1);
+                       lport2 =
+                               fm10k_switch_epl_logical_get
+                               (flow->fw_port[1].port_no - 1);
+                       break;
+               case FM10K_CONFIG_FLOW_DPDK_PORT:
+                       dglort =
+                               fm10k_ffu_dpdk_port_glort_get
+                               (sw, flow->fw_port[1].port_no);
+                       lport2 =
+                               fm10k_switch_pf_logical_get
+                               (flow->fw_port[1].port_no);
+                       break;
+               }
+               dvlan2 = flow->fw_port[1].vlan_id;
+               FM10K_FFU_RULE_PRINT(sw->dpdk_cfg,
+                       " (bypass glort:%#x, vlan:%d)\n",
+                       dglort, dvlan2);
+
+               fm10k_ffu_rule_enable_multi_cast(sw,
+                       flow->rule_id, sglort, svlan,
+                       lport1, lport2, dvlan, dvlan2);
+       } else {
+               FM10K_FFU_RULE_PRINT(sw->dpdk_cfg, "\n");
+               fm10k_ffu_rule_enable_single_cast(sw,
+                       flow->rule_id, sglort, svlan, dglort, dvlan);
+       }
+}
+
+
+void
+fm10k_ffu_flow_disable(struct fm10k_switch *sw, struct fm10k_cfg_flow *flow)
+{
+       int i;
+
+       if (flow->rule_id == 0)
+               return;
+
+       FM10K_FFU_RULE_PRINT(sw->dpdk_cfg,
+                       "Remove flow %d rule %d\n",
+                       flow->flow_no, flow->rule_id);
+
+       for (i = FM10K_FFU_SLICE_START; i < FM10K_SW_FFU_NUM_SLICES; i++) {
+               fm10k_ffu_always_mismatch(sw, i, flow->rule_id);
+               fm10k_write_switch_reg64(sw,
+                               FM10K_SW_FFU_SLICE_SRAM(i, flow->rule_id), 0);
+       }
+       fm10k_ffu_rule_free(flow->rule_id);
+}
+
+
+static int
+fm10k_ffu_configured_flowset_enable(struct fm10k_switch *sw)
+{
+       struct fm10k_cfg_flowset *flowset;
+       struct fm10k_cfg_flow *flow;
+
+       flowset = fm10k_config_flowset_current_get();
+       flow = flowset->flow_head.next;
+       while (!fm10k_config_flow_list_end(&flowset->flow_head, flow)) {
+               fm10k_ffu_flow_enable(sw, flow);
+               flow = flow->next;
+       }
+
+       return 0;
+}
+
+
+void
+fm10k_ffu_flowset_switch(struct fm10k_switch *sw, const char *new_name)
+{
+       struct fm10k_cfg_flowset *flowset;
+       struct fm10k_cfg_flowset *cur_fs;
+       struct fm10k_cfg_flow *flow;
+
+       cur_fs = fm10k_config_flowset_current_get();
+       if (strcmp(cur_fs->name, new_name) == 0)
+               return;
+
+       flowset = fm10k_config_flowset_get(new_name);
+       if (flowset == NULL) {
+               FM10K_SW_ERR("Can not find flowset %s!!\n", new_name);
+               return;
+       }
+
+       /* disable current flowset */
+       flow = cur_fs->flow_head.next;
+       while (!fm10k_config_flow_list_end(&cur_fs->flow_head, flow)) {
+               fm10k_ffu_flow_disable(sw, flow);
+               flow = flow->next;
+       }
+
+       /* enable new flowset */
+       fm10k_config_flowset_current_set(flowset);
+       flow = flowset->flow_head.next;
+       while (!fm10k_config_flow_list_end(&flowset->flow_head, flow)) {
+               fm10k_ffu_flow_enable(sw, flow);
+               flow = flow->next;
+       }
+}
+
+
+int
+fm10k_ffu_init(struct fm10k_switch *sw, struct fm10k_dpdk_cfg *cfg)
+{
+       int ret = 0;
+       uint64_t data64;
+       uint16_t i, j;
+       uint32_t sglort = 0, dglort = 0;
+       uint16_t table_idx = 0;
+       uint16_t ffu_slice = FM10K_FFU_SLICE_START;
+
+       sw->mcast_dest_table_idx = 1;
+       sw->mcast_len_table_idx = 1;
+       sw->mcast_vlan_table_idx = 1;
+
+       for (i = 0;
+                i < sizeof(fm10k_ffu_slice_cfgs) / sizeof(uint64_t);
+                i++) {
+               for (j = 0; j < FM10K_SW_FFU_NUM_SCENARIOS; j++) {
+                       data64 = fm10k_ffu_slice_cfgs[i];
+                       fm10k_write_switch_reg64(sw,
+                                       FM10K_SW_FFU_SLICE_CFG
+                                       (FM10K_FFU_SLICE_START + i, j),
+                                       data64);
+               }
+               FM10K_FFU_INIT_PRINT(cfg, "SET slice %d cfg = %#llx\n",
+                               FM10K_FFU_SLICE_START + i,
+                               (unsigned long long)data64);
+       }
+
+       for (table_idx = 0;
+                table_idx < FM10K_SW_FFU_SLICE_TCAM_ENTRIES / 2;
+                table_idx++)
+               for (i = ffu_slice; i < FM10K_SW_FFU_NUM_SLICES; i++)
+                       fm10k_ffu_always_mismatch(sw, i, table_idx);
+
+       /*
+        * Create a TCAM entry to match each SGLORT that might be used, and
+        * set the corresponding SRAM action entries to ROUTE_GLORT to the
+        * corresponding DGLORT (see above table).
+        * SGLORT ROUTE is always the first slice
+        */
+       for (i = 0; i < FM10K_SW_EXT_PORTS_MAX; i++) {
+               if (cfg->ext_port_map[i].type == FM10K_CONFIG_PORT_MAP_NULL)
+                       continue;
+
+               if (cfg->ext_port_map[i].type == FM10K_CONFIG_PORT_MAP_PF) {
+                       sglort = fm10k_switch_epl_glort_get(i);
+                       dglort =
+                               fm10k_switch_pf_glort_get
+                               (cfg->ext_port_map[i].map_no[0]);
+               } else if (cfg->ext_port_map[i].type ==
+                                  FM10K_CONFIG_PORT_MAP_PFS) {
+                       sglort = fm10k_switch_epl_glort_get(i);
+                       dglort =
+                               fm10k_switch_pfs_glort_get
+                               (cfg->ext_port_map[i].map_no[0],
+                               cfg->ext_port_map[i].map_no[1]);
+               }
+
+               table_idx = FM10K_FFU_EXT_PORT_RULE_INGRESS(i);
+               fm10k_ffu_route_dglort(sw,
+                               ffu_slice, table_idx, sglort, dglort);
+
+               /* blank the next ffu slice */
+               fm10k_write_switch_reg128(sw,
+                               FM10K_SW_FFU_SLICE_TCAM
+                               (ffu_slice + 1, table_idx),
+                           0xffffffffff, 0x1);
+               table_idx = FM10K_FFU_EXT_PORT_RULE_EGRESS(i);
+               fm10k_ffu_route_dglort(sw,
+                               ffu_slice, table_idx, dglort, sglort);
+
+               /* blank the next ffu slice */
+               fm10k_write_switch_reg128(sw,
+                               FM10K_SW_FFU_SLICE_TCAM
+                               (ffu_slice + 1, table_idx),
+                           0xffffffffff, 0x1);
+       }
+
+       for (i = ffu_slice; i < FM10K_SW_FFU_NUM_SLICES; i++) {
+               fm10k_write_switch_reg64(sw,
+                               FM10K_SW_FFU_SLICE_CASCADE_ACTION(i),
+                               0xf0f000f);
+               /* Set slice 0 to valid for all scenarios */
+               fm10k_write_switch_reg64(sw,
+                               FM10K_SW_FFU_SLICE_VALID(i),
+                               FM10K_SW_FFU_SLICE_VALID_ALL_SCENARIOS);
+       }
+
+       /* Mark slice 0 as valid and all chunks as invalid */
+       data64 = 0;
+       for (i = ffu_slice; i < FM10K_SW_FFU_NUM_SLICES; i++)
+               data64 |= FM10K_SW_FFU_MASTER_VALID_SLICE_VALID(i);
+       fm10k_write_switch_reg64(sw, FM10K_SW_FFU_MASTER_VALID, data64);
+
+       /*
+        * Set up the DGLORT map according to the desired
+        * SGLORT -> { DGLORT, logical_port } map.
+        */
+       for (i = 0; i < sw->info->num_peps; i++) {
+               if (sw->pep_map[i].glort == 0)
+                       continue;
+               fm10k_ffu_set_dest_glort_mask(sw,
+                               sw->glort_cam_ram_idx++,
+                               sw->pep_map[i].glort,
+                               FM10K_SW_DPORT_MASK
+                               (sw->pep_map[i].logical_port));
+       }
+
+       for (i = 0; i < FM10K_SW_EPLS_SUPPORTED; i++) {
+               if (sw->epl_map[i].glort == 0)
+                       continue;
+               fm10k_ffu_set_dest_glort_mask(sw,
+                               sw->glort_cam_ram_idx++,
+                               sw->epl_map[i].glort,
+                               FM10K_SW_DPORT_MASK
+                               (sw->epl_map[i].logical_port));
+       }
+
+       for (i = 0; i < FM10K_SW_EXT_PORTS_MAX; i++) {
+               uint64_t dport_mask = 0;
+
+               if (cfg->ext_port_map[i].type ==
+                               FM10K_CONFIG_PORT_MAP_PFS) {
+                       dglort =
+                               fm10k_switch_pfs_glort_get
+                               (cfg->ext_port_map[i].map_no[0],
+                                               cfg->ext_port_map[i].map_no[1]);
+                       dport_mask =
+                               FM10K_SW_DPORT_MASK
+               (sw->pep_map[cfg->ext_port_map[i].map_no[0]].logical_port) |
+                               FM10K_SW_DPORT_MASK
+               (sw->pep_map[cfg->ext_port_map[i].map_no[1]].logical_port);
+                       fm10k_ffu_set_dest_glort_mask(sw,
+                               sw->glort_cam_ram_idx++, dglort, dport_mask);
+               }
+       }
+
+       /* Ensure the rest of the DGLORT TCAM won't match */
+       for (table_idx = sw->glort_cam_ram_idx;
+                table_idx < FM10K_SW_GLORT_CAM_ENTRIES;
+                table_idx++)
+               fm10k_write_switch_reg(sw,
+                               FM10K_SW_GLORT_CAM(table_idx),
+                               FM10K_SW_GLORT_CAM_MATCH_NONE);
+
+       ret = fm10k_ffu_configured_flowset_enable(sw);
+
+       fm10k_ffu_register_dump(sw);
+       fm10k_glort_register_dump(sw);
+       return ret;
+}
diff --git a/drivers/net/fm10k/switch/fm10k_ffu.h 
b/drivers/net/fm10k/switch/fm10k_ffu.h
new file mode 100644
index 0000000..9d46007
--- /dev/null
+++ b/drivers/net/fm10k/switch/fm10k_ffu.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2019   Silicom Ltd. Connectivity Solutions
+ */
+
+#ifndef _FM10K_FFU_H_
+#define _FM10K_FFU_H_
+
+
+#include <stdint.h>
+
+#define FM10K_FFU_EXT_PORT_RULE_INGRESS(i)     ((i) * 2)
+#define FM10K_FFU_EXT_PORT_RULE_EGRESS(i)      ((i) * 2 + 1)
+#define FM10K_FFU_RULE_MAX             FM10K_SW_FFU_RULE_MAX
+
+struct fm10k_switch;
+struct fm10k_dpdk_cfg;
+struct fm10k_cfg_flow;
+
+int fm10k_ffu_init(struct fm10k_switch *sw, struct fm10k_dpdk_cfg *cfg);
+
+int fm10k_ffu_mirror_set(struct fm10k_switch *sw,
+               uint16_t src_dpdk_port, u16 dest_dpdk_port, uint16_t vlan);
+int fm10k_ffu_mirror_reset(struct fm10k_switch *sw, int src_dpdk_port);
+
+void fm10k_ffu_flow_enable(struct fm10k_switch *sw,
+               struct fm10k_cfg_flow *flow);
+void fm10k_ffu_flow_disable(struct fm10k_switch *sw,
+               struct fm10k_cfg_flow *flow);
+void fm10k_ffu_flowset_switch(struct fm10k_switch *sw, const char *new_name);
+
+#endif /* _FM10K_FFU_H */
diff --git a/drivers/net/fm10k/switch/fm10k_stats.c 
b/drivers/net/fm10k/switch/fm10k_stats.c
new file mode 100644
index 0000000..4172b22
--- /dev/null
+++ b/drivers/net/fm10k/switch/fm10k_stats.c
@@ -0,0 +1,1242 @@
+/* spdx-license-identifier: bsd-3-clause
+ * copyright 2019   silicom ltd. connectivity solutions
+ */
+
+#include <rte_time.h>
+#include <rte_kvargs.h>
+#include <rte_hash.h>
+#include <rte_flow.h>
+#include <rte_flow_driver.h>
+#include <rte_tm_driver.h>
+
+#include "../base/fm10k_type.h"
+#include "../base/fm10k_osdep.h"
+
+#include "../fm10k.h"
+#include "../fm10k_logs.h"
+#include "fm10k_debug.h"
+#include "fm10k_regs.h"
+#include "fm10k_ext_port.h"
+#include "fm10k_stats.h"
+#include "fm10k_switch.h"
+#include "fm10k_config.h"
+#include "fm10k_ffu.h"
+
+
+#define FM10K_MAX_VLAN_COUNTER                         63
+#define FM10K_NB_RX_STATS_BANKS                                6
+#define FM10K_BINS_PER_RX_STATS_BANK           16
+#define FM10K_WORDS_PER_RX_STATS_COUNTER       4
+
+/* Max expected entries in read stats scatter gather list */
+#define MAX_STATS_SGLIST 128
+#define FM10K_RX_STATS_BASE                                    (0xE00000)
+#define FM10K_MOD_BASE                                         (0xE80000)
+#define FM10K_CM_APPLY_BASE                                    (0xD40000)
+#define FM10K_EPL_BASE                                         (0x0E0000)
+
+#define FM10K_RX_STATS_BANK(index1, index0, word)                      \
+                       ((0x001000) * ((index1) - 0) + \
+                       (0x000004) * ((index0) - 0) + \
+                       (word) + (0x000000) + \
+                       (FM10K_RX_STATS_BASE))
+#define FM10K_MOD_STATS_BANK_FRAME(index1, index0, word)       \
+                       ((0x000800) * ((index1) - 0) + \
+                       (0x000002) * ((index0) - 0) + \
+                       (word) + (0x025000) + \
+                       (FM10K_MOD_BASE))
+#define FM10K_MOD_STATS_BANK_BYTE(index1, index0, word)                \
+                       ((0x000800) * ((index1) - 0) + \
+                       (0x000002) * ((index0) - 0) + \
+                       (word) + (0x026000) + \
+                       (FM10K_MOD_BASE))
+#define FM10K_CM_APPLY_DROP_COUNT(index, word)                         \
+                       ((0x000002) * ((index) - 0) + \
+                       (word) + (0x000880) + \
+                       (FM10K_CM_APPLY_BASE))
+#define FM10K_MAC_OVERSIZE_COUNTER(index1, index0)                     \
+                       ((0x000400) * ((index1) - 0) + \
+                       (0x000080) * ((index0) - 0) + \
+                       (0x000021) + \
+                       (FM10K_EPL_BASE))
+#define FM10K_MAC_JABBER_COUNTER(index1, index0)                       \
+                       ((0x000400) * ((index1) - 0) + \
+                       (0x000080) * ((index0) - 0) + \
+                       (0x000022) + \
+                       (FM10K_EPL_BASE))
+#define FM10K_MAC_UNDERSIZE_COUNTER(index1, index0)                    \
+                       ((0x000400) * ((index1) - 0) + \
+                       (0x000080) * ((index0) - 0) + \
+                       (0x000023) + \
+                       (FM10K_EPL_BASE))
+#define FM10K_MAC_RUNT_COUNTER(index1, index0)                         \
+                       ((0x000400) * ((index1) - 0) + \
+                       (0x000080) * ((index0) - 0) + \
+                       (0x000024) + \
+                       (FM10K_EPL_BASE))
+#define FM10K_MAC_OVERRUN_COUNTER(index1, index0)                      \
+                       ((0x000400) * ((index1) - 0) + \
+                       (0x000080) * ((index0) - 0) + \
+                       (0x000025) + \
+                       (FM10K_EPL_BASE))
+#define FM10K_MAC_UNDERRUN_COUNTER(index1, index0)                     \
+                       ((0x000400) * ((index1) - 0) + \
+                       (0x000080) * ((index0) - 0) + \
+                       (0x000026) + \
+                       (FM10K_EPL_BASE))
+#define FM10K_MAC_CODE_ERROR_COUNTER(index1, index0)           \
+                       ((0x000400) * ((index1) - 0) + \
+                       (0x000080) * ((index0) - 0) + \
+                       (0x000027) + \
+                       (FM10K_EPL_BASE))
+
+/* Rx Bank Definitions */
+#define FM10K_RX_STAT_BANK_TYPE                       0
+#define FM10K_RX_STAT_BANK_SIZE                       1
+#define FM10K_RX_STAT_BANK_PRI                        2
+#define FM10K_RX_STAT_BANK_FWD_1                      3
+#define FM10K_RX_STAT_BANK_FWD_2                      4
+#define FM10K_RX_STAT_BANK_VLAN                       5
+
+/* FM10K_RX_STAT_BANK_TYPE Bin Definitions */
+#define FM10K_RX_STAT_NONIP_L2UCAST                   0
+#define FM10K_RX_STAT_NONIP_L2MCAST                   1
+#define FM10K_RX_STAT_NONIP_L2BCAST                   2
+#define FM10K_RX_STAT_IPV4_L2UCAST                    3
+#define FM10K_RX_STAT_IPV4_L2MCAST                    4
+#define FM10K_RX_STAT_IPV4_L2BCAST                    5
+#define FM10K_RX_STAT_IPV6_L2UCAST                    6
+#define FM10K_RX_STAT_IPV6_L2MCAST                    7
+#define FM10K_RX_STAT_IPV6_L2BCAST                    8
+#define FM10K_RX_STAT_IEEE802_3_PAUSE                 9
+#define FM10K_RX_STAT_CLASS_BASED_PAUSE               10
+#define FM10K_RX_STAT_FRAMING_ERR                     11
+#define FM10K_RX_STAT_FCS_ERR                         12
+
+/* FM10K_RX_STAT_BANK_SIZE Bin Definitions */
+#define FM10K_RX_STAT_LEN_LT_64                       0
+#define FM10K_RX_STAT_LEN_EQ_64                       1
+#define FM10K_RX_STAT_LEN_65_127                      2
+#define FM10K_RX_STAT_LEN_128_255                     3
+#define FM10K_RX_STAT_LEN_256_511                     4
+#define FM10K_RX_STAT_LEN_512_1023                    5
+#define FM10K_RX_STAT_LEN_1024_1522                   6
+#define FM10K_RX_STAT_LEN_1523_2047                   7
+#define FM10K_RX_STAT_LEN_2048_4095                   8
+#define FM10K_RX_STAT_LEN_4096_8191                   9
+#define FM10K_RX_STAT_LEN_8192_10239                  10
+#define FM10K_RX_STAT_LEN_GE_10240                    11
+
+/* FM10K_RX_STAT_BANK_PRI Bin Definitions */
+#define FM10K_RX_STAT_PRI_0                           0
+#define FM10K_RX_STAT_PRI_1                           1
+#define FM10K_RX_STAT_PRI_2                           2
+#define FM10K_RX_STAT_PRI_3                           3
+#define FM10K_RX_STAT_PRI_4                           4
+#define FM10K_RX_STAT_PRI_5                           5
+#define FM10K_RX_STAT_PRI_6                           6
+#define FM10K_RX_STAT_PRI_7                           7
+#define FM10K_RX_STAT_PRI_8                           8
+#define FM10K_RX_STAT_PRI_9                           9
+#define FM10K_RX_STAT_PRI_10                          10
+#define FM10K_RX_STAT_PRI_11                          11
+#define FM10K_RX_STAT_PRI_12                          12
+#define FM10K_RX_STAT_PRI_13                          13
+#define FM10K_RX_STAT_PRI_14                          14
+#define FM10K_RX_STAT_PRI_15                          15
+
+/* FM10K_RX_STAT_BANK_FWD_1 Bin Definitions */
+#define FM10K_RX_STAT_FID_FORWARDED                   0
+#define FM10K_RX_STAT_FLOOD_FORWARDED                 1
+#define FM10K_RX_STAT_SPECIALLY_HANDLED               2
+#define FM10K_RX_STAT_PARSER_ERROR_DROP               3
+#define FM10K_RX_STAT_ECC_ERROR_DROP                  4
+#define FM10K_RX_STAT_TRAPPED                         5
+#define FM10K_RX_STAT_PAUSE_DROPS                     6
+#define FM10K_RX_STAT_STP_DROPS                       7
+#define FM10K_RX_STAT_SECURITY_VIOLATIONS             8
+#define FM10K_RX_STAT_VLAN_TAG_DROPS                  9
+#define FM10K_RX_STAT_VLAN_INGRESS_DROPS              10
+#define FM10K_RX_STAT_VLAN_EGRESS_DROPS               11
+#define FM10K_RX_STAT_GLORT_MISS_DROPS                12
+#define FM10K_RX_STAT_FFU_DROPS                       13
+#define FM10K_RX_STAT_TRIGGER_DROPS                   14
+#define FM10K_RX_STAT_OVERFLOW4                       15
+
+/* FM10K_RX_STAT_BANK_FWD_2 Bin Definitions */
+#define FM10K_RX_STAT_POLICER_DROPS                   0
+#define FM10K_RX_STAT_TTL_DROPS                       1
+#define FM10K_RX_STAT_CM_PRIV_DROPS                   2
+#define FM10K_RX_STAT_CM_SMP0_DROPS                   3
+#define FM10K_RX_STAT_CM_SMP1_DROPS                   4
+#define FM10K_RX_STAT_CM_RX_HOG_0_DROPS               5
+#define FM10K_RX_STAT_CM_RX_HOG_1_DROPS               6
+#define FM10K_RX_STAT_CM_TX_HOG_0_DROPS               7
+#define FM10K_RX_STAT_CM_TX_HOG_1_DROPS               8
+/* Bin 9 reserved */
+#define FM10K_RX_STAT_TRIGGER_REDIRECTS               10
+#define FM10K_RX_STAT_FLOOD_CONTROL_DROPS             11
+#define FM10K_RX_STAT_GLORT_FORWARDED                 12
+#define FM10K_RX_STAT_LOOPBACK_SUPPRESS               13
+#define FM10K_RX_STAT_OTHERS                          14
+#define FM10K_RX_STAT_OVERFLOW5                       15
+
+/* FM10K_RX_STAT_BANK_VLAN Bin definitions */
+#define FM10K_RX_STAT_VLAN_UCAST                      0
+#define FM10K_RX_STAT_VLAN_MCAST                      1
+#define FM10K_RX_STAT_VLAN_BCAST                      2
+
+/* Tx Bank Definitions */
+#define FM10K_TX_STAT_BANK_TYPE                       0
+#define FM10K_TX_STAT_BANK_SIZE                       1
+
+/* FM10K_TX_STAT_BANK_TYPE Bin Definitions */
+#define FM10K_TX_STAT_L2UCAST                         0
+#define FM10K_TX_STAT_L2MCAST                         1
+#define FM10K_TX_STAT_L2BCAST                         2
+#define FM10K_TX_STAT_ERR_SENT                        3
+#define FM10K_TX_STAT_TIMEOUT_DROP                    4
+#define FM10K_TX_STAT_ERR_DROP                        5
+#define FM10K_TX_STAT_ECC_DROP                        6
+#define FM10K_TX_STAT_LOOPBACK_DROP                   7
+#define FM10K_TX_STAT_TTL1_DROP                       8
+#define FM10K_TX_STAT_IEEE802_3_PAUSE                 9
+#define FM10K_TX_STAT_CLASS_BASED_PAUSE               10
+
+/* FM10K_TX_STAT_BANK_SIZE Bin Definitions */
+#define FM10K_TX_STAT_LEN_LT_64                       0
+#define FM10K_TX_STAT_LEN_EQ_64                       1
+#define FM10K_TX_STAT_LEN_65_127                      2
+#define FM10K_TX_STAT_LEN_128_255                     3
+#define FM10K_TX_STAT_LEN_256_511                     4
+#define FM10K_TX_STAT_LEN_512_1023                    5
+#define FM10K_TX_STAT_LEN_1024_1522                   6
+#define FM10K_TX_STAT_LEN_1523_2047                   7
+#define FM10K_TX_STAT_LEN_2048_4095                   8
+#define FM10K_TX_STAT_LEN_4096_8191                   9
+#define FM10K_TX_STAT_LEN_8192_10239                  10
+#define FM10K_TX_STAT_LEN_GE_10240                    11
+
+
+/* This structure is used to build a table of all rx / tx counters */
+struct fm10k_port_count_mapping {
+       /* Bank in which the counter is located */
+       uint32_t bank;
+
+       /* Bin  in which the counter is located */
+       uint32_t bin;
+
+       /*
+        * Offset (in bytes) of a the frame counter in
+        * the fm10k_counters structure
+        */
+       uint32_t frame_offset;
+
+       /*
+        * Offset (in bytes) of a the byte counter in
+        * the fm10k_counters structure
+        */
+       uint32_t byte_offset;
+};
+
+
+/*
+ * Table of all RX port counters in the RX banks
+ * This table is used for retrieving counters as
+ * well as resetting them
+ */
+static struct fm10k_port_count_mapping rx_port_cnt_map_table[] = {
+    /* Bank                        Bin
+     * --------------------------  ------------------------------
+     * frame_offset
+     * ---------------------------------------------
+     * byte_offset
+     * ---------------------------------------------------
+     */
+    /* Type Bank */
+{      FM10K_RX_STAT_BANK_TYPE,  FM10K_RX_STAT_NONIP_L2UCAST,
+       offsetof(struct fm10k_port_counters, cnt_rx_ucst_pkts_nonip),
+       offsetof(struct fm10k_port_counters, cnt_rx_ucst_octets_nonip)},
+{      FM10K_RX_STAT_BANK_TYPE,  FM10K_RX_STAT_NONIP_L2MCAST,
+       offsetof(struct fm10k_port_counters, cnt_rx_mcst_pkts_nonip),
+       offsetof(struct fm10k_port_counters, cnt_rx_mcst_octets_nonip)},
+{      FM10K_RX_STAT_BANK_TYPE,  FM10K_RX_STAT_NONIP_L2BCAST,
+       offsetof(struct fm10k_port_counters, cnt_rx_bcst_pkts_nonip),
+       offsetof(struct fm10k_port_counters, cnt_rx_bcst_octets_nonip)},
+{      FM10K_RX_STAT_BANK_TYPE,  FM10K_RX_STAT_IPV4_L2UCAST,
+       offsetof(struct fm10k_port_counters, cnt_rx_ucst_pkts_ipv4),
+       offsetof(struct fm10k_port_counters, cnt_rx_ucst_octets_ipv4)},
+{      FM10K_RX_STAT_BANK_TYPE,  FM10K_RX_STAT_IPV4_L2MCAST,
+       offsetof(struct fm10k_port_counters, cnt_rx_mcst_pkts_ipv4),
+       offsetof(struct fm10k_port_counters, cnt_rx_mcst_octets_ipv4)},
+{      FM10K_RX_STAT_BANK_TYPE,  FM10K_RX_STAT_IPV4_L2BCAST,
+       offsetof(struct fm10k_port_counters, cnt_rx_bcst_pkts_ipv4),
+       offsetof(struct fm10k_port_counters, cnt_rx_bcst_octets_ipv4)},
+{      FM10K_RX_STAT_BANK_TYPE,  FM10K_RX_STAT_IPV6_L2UCAST,
+       offsetof(struct fm10k_port_counters, cnt_rx_ucst_pkts_ipv6),
+       offsetof(struct fm10k_port_counters, cnt_rx_ucst_octets_ipv6)},
+{      FM10K_RX_STAT_BANK_TYPE,  FM10K_RX_STAT_IPV6_L2MCAST,
+       offsetof(struct fm10k_port_counters, cnt_rx_mcst_pkts_ipv6),
+       offsetof(struct fm10k_port_counters, cnt_rx_mcst_octets_ipv6)},
+{      FM10K_RX_STAT_BANK_TYPE,  FM10K_RX_STAT_IPV6_L2BCAST,
+       offsetof(struct fm10k_port_counters, cnt_rx_bcst_pkts_ipv6),
+       offsetof(struct fm10k_port_counters, cnt_rx_bcst_octets_ipv6)},
+{      FM10K_RX_STAT_BANK_TYPE,  FM10K_RX_STAT_IEEE802_3_PAUSE,
+       offsetof(struct fm10k_port_counters, cnt_rx_pause_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_pause_octets)},
+{      FM10K_RX_STAT_BANK_TYPE,  FM10K_RX_STAT_CLASS_BASED_PAUSE,
+       offsetof(struct fm10k_port_counters, cnt_rx_cbpause_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_cbpause_octets)},
+{      FM10K_RX_STAT_BANK_TYPE,  FM10K_RX_STAT_FRAMING_ERR,
+       offsetof(struct fm10k_port_counters, cnt_rx_framing_error_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_framing_error_octets)},
+{      FM10K_RX_STAT_BANK_TYPE,  FM10K_RX_STAT_FCS_ERR,
+       offsetof(struct fm10k_port_counters, cnt_rx_fcs_errors),
+       offsetof(struct fm10k_port_counters, cnt_rx_fcs_errors_octets)},
+
+    /* Size Bank */
+{      FM10K_RX_STAT_BANK_SIZE,  FM10K_RX_STAT_LEN_LT_64,
+       offsetof(struct fm10k_port_counters, cnt_rx_minto63_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_minto63_octets)},
+{      FM10K_RX_STAT_BANK_SIZE,  FM10K_RX_STAT_LEN_EQ_64,
+       offsetof(struct fm10k_port_counters, cnt_rx_64_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_64_octets)},
+{      FM10K_RX_STAT_BANK_SIZE,  FM10K_RX_STAT_LEN_65_127,
+       offsetof(struct fm10k_port_counters, cnt_rx_65to127_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_65to127_octets)},
+{      FM10K_RX_STAT_BANK_SIZE,  FM10K_RX_STAT_LEN_128_255,
+       offsetof(struct fm10k_port_counters, cnt_rx_128to255_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_128to255_octets)},
+{      FM10K_RX_STAT_BANK_SIZE,  FM10K_RX_STAT_LEN_256_511,
+       offsetof(struct fm10k_port_counters, cnt_rx_256to511_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_256to511_octets)},
+{      FM10K_RX_STAT_BANK_SIZE,  FM10K_RX_STAT_LEN_512_1023,
+       offsetof(struct fm10k_port_counters, cnt_rx_512to1023_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_512to1023_octets)},
+{      FM10K_RX_STAT_BANK_SIZE,  FM10K_RX_STAT_LEN_1024_1522,
+       offsetof(struct fm10k_port_counters, cnt_rx_1024to1522_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_1024to1522_octets)},
+{      FM10K_RX_STAT_BANK_SIZE,  FM10K_RX_STAT_LEN_1523_2047,
+       offsetof(struct fm10k_port_counters, cnt_rx_1523to2047_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_1523to2047_octets)},
+{      FM10K_RX_STAT_BANK_SIZE,  FM10K_RX_STAT_LEN_2048_4095,
+       offsetof(struct fm10k_port_counters, cnt_rx_2048to4095_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_2048to4095_octets)},
+{      FM10K_RX_STAT_BANK_SIZE,  FM10K_RX_STAT_LEN_4096_8191,
+       offsetof(struct fm10k_port_counters, cnt_rx_4096to8191_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_4096to8191_octets)},
+{      FM10K_RX_STAT_BANK_SIZE,  FM10K_RX_STAT_LEN_8192_10239,
+       offsetof(struct fm10k_port_counters, cnt_rx_8192to10239_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_8192to10239_octets)},
+{      FM10K_RX_STAT_BANK_SIZE,  FM10K_RX_STAT_LEN_GE_10240,
+       offsetof(struct fm10k_port_counters, cnt_rx_10240tomax_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_10240tomax_octets)},
+
+    /* priority Bank */
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_0,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[0]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[0])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_1,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[1]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[1])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_2,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[2]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[2])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_3,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[3]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[3])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_4,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[4]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[4])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_5,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[5]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[5])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_6,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[6]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[6])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_7,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[7]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[7])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_8,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[8]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[8])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_9,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[9]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[9])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_10,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[10]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[10])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_11,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[11]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[11])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_12,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[12]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[12])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_13,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[13]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[13])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_14,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[14]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[14])},
+{      FM10K_RX_STAT_BANK_PRI,   FM10K_RX_STAT_PRI_15,
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_pkts[15]),
+       offsetof(struct fm10k_port_counters, cnt_rx_priority_octets[15])},
+
+    /* Forwarding Bank */
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_FID_FORWARDED,
+       offsetof(struct fm10k_port_counters, cnt_fid_forwarded_pkts),
+       offsetof(struct fm10k_port_counters, cnt_fid_forwarded_octets)},
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_FLOOD_FORWARDED,
+       offsetof(struct fm10k_port_counters, cnt_flood_forwarded_pkts),
+       offsetof(struct fm10k_port_counters, cnt_flood_forwarded_octets)},
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_SPECIALLY_HANDLED,
+       offsetof(struct fm10k_port_counters, cnt_specially_handled_pkts),
+       offsetof(struct fm10k_port_counters, cnt_specially_handled_octets)},
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_PARSER_ERROR_DROP,
+       offsetof(struct fm10k_port_counters, cnt_parse_err_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_parse_err_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_ECC_ERROR_DROP,
+       offsetof(struct fm10k_port_counters, cnt_parity_error_pkts),
+       offsetof(struct fm10k_port_counters, cnt_parity_error_octets)},
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_TRAPPED,
+       offsetof(struct fm10k_port_counters, cnt_trapped_pkts),
+       offsetof(struct fm10k_port_counters, cnt_trapped_octets)},
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_PAUSE_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_pause_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_pause_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_STP_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_stp_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_stp_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_SECURITY_VIOLATIONS,
+       offsetof(struct fm10k_port_counters, cnt_security_violation_pkts),
+       offsetof(struct fm10k_port_counters, cnt_security_violation_octets)},
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_VLAN_TAG_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_vlan_tag_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_vlan_tag_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_VLAN_INGRESS_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_vlan_ingressbv_pkts),
+       offsetof(struct fm10k_port_counters, cnt_vlan_ingressbv_octets)},
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_VLAN_EGRESS_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_vlan_egressbv_pkts),
+       offsetof(struct fm10k_port_counters, cnt_vlan_egressbv_octets)},
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_GLORT_MISS_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_glort_miss_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_glort_miss_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_FFU_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_ffu_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_ffu_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_1, FM10K_RX_STAT_TRIGGER_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_trigger_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_trigger_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_2, FM10K_RX_STAT_POLICER_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_policer_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_policer_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_2, FM10K_RX_STAT_TTL_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_ttl_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_ttl_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_2, FM10K_RX_STAT_CM_PRIV_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_cmpriv_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_cmpriv_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_2, FM10K_RX_STAT_CM_SMP0_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_smp0_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_smp0_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_2, FM10K_RX_STAT_CM_SMP1_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_smp1_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_smp1_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_2, FM10K_RX_STAT_CM_RX_HOG_0_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_rx_hog0_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_hog0_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_2, FM10K_RX_STAT_CM_RX_HOG_1_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_rx_hog1_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_rx_hog1_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_2, FM10K_RX_STAT_CM_TX_HOG_0_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_tx_hog0_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_hog0_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_2, FM10K_RX_STAT_CM_TX_HOG_1_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_tx_hog1_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_hog1_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_2, FM10K_RX_STAT_TRIGGER_REDIRECTS,
+       offsetof(struct fm10k_port_counters, cnt_trigger_redir_pkts),
+       offsetof(struct fm10k_port_counters, cnt_trigger_redir_octets)},
+{      FM10K_RX_STAT_BANK_FWD_2, FM10K_RX_STAT_FLOOD_CONTROL_DROPS,
+       offsetof(struct fm10k_port_counters, cnt_flood_control_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_flood_control_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_2, FM10K_RX_STAT_GLORT_FORWARDED,
+       offsetof(struct fm10k_port_counters, cnt_glort_forwarded_pkts),
+       offsetof(struct fm10k_port_counters, cnt_glort_forwarded_octets)},
+{      FM10K_RX_STAT_BANK_FWD_2, FM10K_RX_STAT_LOOPBACK_SUPPRESS,
+       offsetof(struct fm10k_port_counters, cnt_loopback_drops_pkts),
+       offsetof(struct fm10k_port_counters, cnt_loopback_drop_octets)},
+{      FM10K_RX_STAT_BANK_FWD_2, FM10K_RX_STAT_OTHERS,
+       offsetof(struct fm10k_port_counters, cnt_other_pkts),
+       offsetof(struct fm10k_port_counters, cnt_other_octets)},
+
+}; /* end rxPortCntMapTable */
+
+
+/*
+ * Table of all TX port counters in the TX banks
+ * This table is used for retrieving counters as
+ * well as resetting them
+ */
+static struct fm10k_port_count_mapping tx_port_cnt_map_table[] = {
+    /* Bank                        Bin
+     * --------------------------  ------------------------------
+     * frame_offset
+     * ---------------------------------------------
+     * byte_offset
+     * ---------------------------------------------------
+     */
+    /* Type Bank */
+{      FM10K_TX_STAT_BANK_TYPE, FM10K_TX_STAT_L2UCAST,
+       offsetof(struct fm10k_port_counters, cnt_tx_ucst_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_ucst_octets)},
+{      FM10K_TX_STAT_BANK_TYPE, FM10K_TX_STAT_L2MCAST,
+       offsetof(struct fm10k_port_counters, cnt_tx_mcst_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_mcst_octets)},
+{      FM10K_TX_STAT_BANK_TYPE, FM10K_TX_STAT_L2BCAST,
+       offsetof(struct fm10k_port_counters, cnt_tx_bcst_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_bcst_octets)},
+{      FM10K_TX_STAT_BANK_TYPE, FM10K_TX_STAT_ERR_SENT,
+       offsetof(struct fm10k_port_counters, cnt_tx_error_sent_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_error_sent_octets)},
+{      FM10K_TX_STAT_BANK_TYPE, FM10K_TX_STAT_TIMEOUT_DROP,
+       offsetof(struct fm10k_port_counters, cnt_tx_timeout_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_timeout_octets)},
+{      FM10K_TX_STAT_BANK_TYPE, FM10K_TX_STAT_ERR_DROP,
+       offsetof(struct fm10k_port_counters, cnt_tx_error_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_error_octets)},
+{      FM10K_TX_STAT_BANK_TYPE, FM10K_TX_STAT_ECC_DROP,
+       offsetof(struct fm10k_port_counters, cnt_tx_unrepair_ecc_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_unrepair_ecc_octets)},
+{      FM10K_TX_STAT_BANK_TYPE, FM10K_TX_STAT_LOOPBACK_DROP,
+       offsetof(struct fm10k_port_counters, cnt_tx_loopback_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_loopback_octets)},
+{      FM10K_TX_STAT_BANK_TYPE, FM10K_TX_STAT_TTL1_DROP,
+       offsetof(struct fm10k_port_counters, cnt_tx_ttl_drop_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_ttl_drop_octets)},
+{      FM10K_TX_STAT_BANK_TYPE, FM10K_TX_STAT_IEEE802_3_PAUSE,
+       offsetof(struct fm10k_port_counters, cnt_tx_pause_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_pause_octets)},
+{      FM10K_TX_STAT_BANK_TYPE, FM10K_TX_STAT_CLASS_BASED_PAUSE,
+       offsetof(struct fm10k_port_counters, cnt_tx_cbpause_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_cbpause_octets)},
+
+    /* Size Bank */
+{      FM10K_TX_STAT_BANK_SIZE, FM10K_TX_STAT_LEN_LT_64,
+       offsetof(struct fm10k_port_counters, cnt_tx_minto63_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_minto63_octets)},
+{      FM10K_TX_STAT_BANK_SIZE, FM10K_TX_STAT_LEN_EQ_64,
+       offsetof(struct fm10k_port_counters, cnt_tx_64_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_64_octets)},
+{      FM10K_TX_STAT_BANK_SIZE, FM10K_TX_STAT_LEN_65_127,
+       offsetof(struct fm10k_port_counters, cnt_tx_65to127_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_65to127_octets)},
+{      FM10K_TX_STAT_BANK_SIZE, FM10K_TX_STAT_LEN_128_255,
+       offsetof(struct fm10k_port_counters, cnt_tx_128to255_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_128to255_octets)},
+{      FM10K_TX_STAT_BANK_SIZE, FM10K_TX_STAT_LEN_256_511,
+       offsetof(struct fm10k_port_counters, cnt_tx_256to511_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_256to511_octets)},
+{      FM10K_TX_STAT_BANK_SIZE, FM10K_TX_STAT_LEN_512_1023,
+       offsetof(struct fm10k_port_counters, cnt_tx_512to1023_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_512to1023_octets)},
+{      FM10K_TX_STAT_BANK_SIZE, FM10K_TX_STAT_LEN_1024_1522,
+       offsetof(struct fm10k_port_counters, cnt_tx_1024to1522_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_1024to1522_octets)},
+{      FM10K_TX_STAT_BANK_SIZE, FM10K_TX_STAT_LEN_1523_2047,
+       offsetof(struct fm10k_port_counters, cnt_tx_1523to2047_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_1523to2047_octets)},
+{      FM10K_TX_STAT_BANK_SIZE, FM10K_TX_STAT_LEN_2048_4095,
+       offsetof(struct fm10k_port_counters, cnt_tx_2048to4095_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_2048to4095_octets)},
+{      FM10K_TX_STAT_BANK_SIZE, FM10K_TX_STAT_LEN_4096_8191,
+       offsetof(struct fm10k_port_counters, cnt_tx_4096to8191_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_4096to8191_octets)},
+{      FM10K_TX_STAT_BANK_SIZE, FM10K_TX_STAT_LEN_8192_10239,
+       offsetof(struct fm10k_port_counters, cnt_tx_8192to10239_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_8192to10239_octets)},
+{      FM10K_TX_STAT_BANK_SIZE, FM10K_TX_STAT_LEN_GE_10240,
+       offsetof(struct fm10k_port_counters, cnt_tx_10240tomax_pkts),
+       offsetof(struct fm10k_port_counters, cnt_tx_10240tomax_octets)},
+
+};  /* end tx_port_cnt_map_table */
+
+
+/*
+ * Get a 32bit EPL counter by adding it to the scatter gather
+ * list.
+ * Depends on the existence of the variables:
+ * sgList [out] - scatter gather array to hold the reads
+ * sgListCnt [out] - number of entry in the sgList
+ */
+static inline void
+fm10k_get_epl_port_stat32(struct fm10k_scatter_gather_entry *sg_list,
+               struct fm10k_port_counters *counters,
+               int *sg_list_cnt, int epl, int lane)
+{
+       sg_list[*sg_list_cnt].addr = FM10K_MAC_OVERSIZE_COUNTER(epl, lane);
+       sg_list[*sg_list_cnt].data =
+                       (uint32_t *)&counters->cnt_rx_oversized_pkts;
+       sg_list[*sg_list_cnt].count = 1;
+       (*sg_list_cnt)++;
+
+       sg_list[*sg_list_cnt].addr = FM10K_MAC_JABBER_COUNTER(epl, lane);
+       sg_list[*sg_list_cnt].data =
+                       (uint32_t *)&counters->cnt_rx_jabber_pkts;
+       sg_list[*sg_list_cnt].count = 1;
+       (*sg_list_cnt)++;
+
+       sg_list[*sg_list_cnt].addr = FM10K_MAC_UNDERSIZE_COUNTER(epl, lane);
+       sg_list[*sg_list_cnt].data =
+                       (uint32_t *)&counters->cnt_rx_undersized_pkts;
+       sg_list[*sg_list_cnt].count = 1;
+       (*sg_list_cnt)++;
+
+       sg_list[*sg_list_cnt].addr = FM10K_MAC_RUNT_COUNTER(epl, lane);
+       sg_list[*sg_list_cnt].data =
+                       (uint32_t *)&counters->cnt_rx_fragment_pkts;
+       sg_list[*sg_list_cnt].count = 1;
+       (*sg_list_cnt)++;
+
+       sg_list[*sg_list_cnt].addr = FM10K_MAC_OVERRUN_COUNTER(epl, lane);
+       sg_list[*sg_list_cnt].data =
+                       (uint32_t *)&counters->cnt_over_run_pkts;
+       sg_list[*sg_list_cnt].count = 1;
+       (*sg_list_cnt)++;
+
+       sg_list[*sg_list_cnt].addr = FM10K_MAC_CODE_ERROR_COUNTER(epl, lane);
+       sg_list[*sg_list_cnt].data =
+                       (uint32_t *)&counters->cnt_code_errors;
+       sg_list[*sg_list_cnt].count = 1;
+       (*sg_list_cnt)++;
+}
+
+
+static void
+fm10k_read_scatter_gather(struct fm10k_switch *sw,
+               int n_entries,
+               struct fm10k_scatter_gather_entry *sg_list)
+{
+       int i;
+
+       for (i = 0; i < n_entries; i++) {
+               uint32_t addr  = sg_list[i].addr;
+               uint32_t count = sg_list[i].count;
+               uint32_t *data = sg_list[i].data;
+
+               fm10k_read_switch_array(sw, addr, data, count);
+       }
+}
+
+
+static int
+fm10k_get_port_counters(struct fm10k_switch *sw,
+               struct fm10k_ext_port *ext_port,
+               struct fm10k_port_counters *counters)
+{
+       int phys_port;
+       int epl;
+       int lane;
+       struct timeval ts;
+       bool valid_ip_stats = true;
+       uint32_t i;
+       struct fm10k_scatter_gather_entry sg_list[MAX_STATS_SGLIST];
+       int sg_list_cnt = 0;
+       /* Temporary bin array to retrieve 128bit
+        * port counters (frame + bytes).
+        */
+       uint32_t cnt_rx_port_stats_bank
+                                       [FM10K_NB_RX_STATS_BANKS]
+                                       [FM10K_BINS_PER_RX_STATS_BANK]
+                                       [FM10K_WORDS_PER_RX_STATS_COUNTER];
+       /*
+        * Fill the counters structure with 0 to assure
+        * all fields not explicitly set below, which will
+        * be the fields not supported by the FM10000,
+        * will be 0 on return.
+        */
+       memset(counters, 0, sizeof(*counters));
+
+       phys_port = ext_port->portno;
+       epl = ext_port->eplno;
+       lane = ext_port->first_lane;
+
+       counters->cnt_version = FM10K_STATS_VERSION;
+
+       /*
+        * Reading counters for each RX bank
+        *
+        * Because the RX_STATS_BANK register contains
+        * both, frame count and byte count in a 128bit
+        * register, we first store the data in a temporary
+        * array.
+        * 1. Fill Scatter Gather to retrieve each bin
+        *    counter from the rx bank and store in a temp
+        *    array.
+        */
+       for (i = 0;
+                       i < sizeof(rx_port_cnt_map_table) /
+                               sizeof(rx_port_cnt_map_table[0]);
+                       i++) {
+               /*
+                * Add a 128bit read of an rx counter to the scatter gather
+                * list.
+                * NOTE: Read values will be stored in the temporary
+                *       array switchExt->cnt_rx_port_stats_bank;
+                * Depends on the existence of the variables:
+                * switchExt->cnt_rx_PortStatsBank [out] - Array to store the
+                * 128bit values sgList
+                * [out] - scatter gather array to hold the reads sgListCnt
+                * [out] - number of entry in the sgList
+                */
+               uint32_t bank = rx_port_cnt_map_table[i].bank;
+               uint32_t bin = rx_port_cnt_map_table[i].bin;
+
+               sg_list[sg_list_cnt].addr =
+                       FM10K_RX_STATS_BANK(bank, (phys_port << 4 | (bin)), 0);
+               sg_list[sg_list_cnt].data = cnt_rx_port_stats_bank[bank][bin];
+               sg_list[sg_list_cnt].count = 4;
+               sg_list_cnt++;
+}
+
+       /*
+        * 2. Fill in the scatter gather for tx bank
+        *    counters. They will directly be stored
+        *    in the fm10k_counters structure upon
+        *    scatter gather read.
+        */
+       for (i = 0;
+                       i < sizeof(tx_port_cnt_map_table) /
+                               sizeof(tx_port_cnt_map_table[0]);
+                       i++) {
+               /*
+                * Add a 64bit read of a tx counter to the scatter gather list.
+                * Depends on the existence of the variables:
+                * sgList [out] - scatter gather array to hold the reads
+                * sgListCnt [out] - number of entry in the sgList
+                */
+               uint32_t bank = tx_port_cnt_map_table[i].bank;
+               uint32_t bin = tx_port_cnt_map_table[i].bin;
+               uint32_t frame_offset = tx_port_cnt_map_table[i].frame_offset;
+
+               sg_list[sg_list_cnt].addr =
+                       FM10K_MOD_STATS_BANK_FRAME(bank,
+                                       (phys_port << 4 | (bin)), 0);
+               sg_list[sg_list_cnt].data =
+                       (uint32_t *)(((uint8_t *)counters) + (frame_offset));
+               sg_list[sg_list_cnt].count = 2;
+               sg_list_cnt++;
+       }
+
+       /*
+        * 3. Fill in the scatter gather for TX CM DROP
+        *    and for EPL counters. They will directly be
+        *    stored in the fm10k_counters structure upon
+        *    scatter gather read.
+        */
+       sg_list[sg_list_cnt].addr =
+                       FM10K_CM_APPLY_DROP_COUNT(phys_port, 0);
+       sg_list[sg_list_cnt].data =
+                       (uint32_t *)&counters->cnt_rx_cm_drop_pkts;
+       sg_list[sg_list_cnt].count = 2;
+       sg_list_cnt++;
+       /* EPL Counters */
+       fm10k_get_epl_port_stat32(sg_list, counters, &sg_list_cnt, epl, lane);
+
+       /*
+        * 4. Execute scatter gather read.
+        */
+       if (sg_list_cnt >= MAX_STATS_SGLIST) {
+               /*
+                * Pretty static. Mainly to warn if something new added,
+                * but the array size is not adjust accordingly
+                */
+               FM10K_SW_ERR("Scatter list array %d for port %d overflow.\n",
+                               sg_list_cnt, phys_port);
+               return -1;
+       }
+
+       /*
+        * Taking lock to protect temporary structures used to
+        * store 128b counters
+        */
+       FM10K_SW_SWITCH_LOCK(sw);
+
+       /* now get the stats in one shot, optimized for fibm */
+       fm10k_read_scatter_gather(sw, sg_list_cnt, sg_list);
+       FM10K_SW_SWITCH_UNLOCK(sw);
+
+       counters->timestamp = ts.tv_sec * 1000000 + ts.tv_usec;
+
+       /*
+        * 5. Retrieve the frame/byte counts from 128bit
+        *    registers stored in temporary array and set
+        *    the proper fm_portCounter structure members.
+        */
+       for (i = 0;
+                       i < sizeof(rx_port_cnt_map_table) /
+                               sizeof(rx_port_cnt_map_table[0]);
+                       i++) {
+               /*
+                * Update the counter variable related to a 128bit HW counter
+                * NOTE: Read values will be retrieved from the temporary
+                *       array switchExt->cnt_rx_PortStatsBank;
+                * Depends on the existence of the variables:
+                * switchExt->cnt_rx_PortStatsBank [in] - Array to read the
+                * 128bit values from
+                */
+               uint32_t bank = rx_port_cnt_map_table[i].bank;
+               uint32_t bin = rx_port_cnt_map_table[i].bin;
+               uint32_t frame_offset = rx_port_cnt_map_table[i].frame_offset;
+               uint32_t byte_offset = rx_port_cnt_map_table[i].byte_offset;
+
+               *((uint64_t *)(((uint8_t *)counters) + frame_offset)) =
+               (((uint64_t)(cnt_rx_port_stats_bank[bank][bin][1]) << 32) |
+               ((uint64_t)(cnt_rx_port_stats_bank[bank][bin][0])));
+
+               *((uint64_t *)(((uint8_t *)counters) + byte_offset)) =
+               (((uint64_t)(cnt_rx_port_stats_bank[bank][bin][3]) << 32) |
+               ((uint64_t)(cnt_rx_port_stats_bank[bank][bin][2])));
+       }
+
+       /*
+        * 6. Set some counters that are not available
+        *    in HW but can be computed from two or more
+        *    HW counters.
+        */
+       /*
+        * If IP parsing is enabled then the IP stats will be read and will be
+        * valid. Else all traffic, whether IP or not, is counted as _nonip.
+        */
+       if (valid_ip_stats) {
+               /*
+                * RX counters.
+                */
+               counters->cnt_rx_ucst_pkts =
+                               counters->cnt_rx_ucst_pkts_nonip +
+                               counters->cnt_rx_ucst_pkts_ipv4 +
+                               counters->cnt_rx_ucst_pkts_ipv6;
+
+               counters->cnt_rx_mcst_pkts =
+                               counters->cnt_rx_mcst_pkts_nonip +
+                               counters->cnt_rx_mcst_pkts_ipv4 +
+                               counters->cnt_rx_mcst_pkts_ipv6;
+
+               counters->cnt_rx_bcst_pkts =
+                               counters->cnt_rx_bcst_pkts_nonip +
+                               counters->cnt_rx_bcst_pkts_ipv4 +
+                               counters->cnt_rx_bcst_pkts_ipv6;
+
+               /*
+                * Misc. counters.
+                */
+               counters->cnt_rx_octets_nonip  =
+                               counters->cnt_rx_ucst_octets_nonip +
+                               counters->cnt_rx_mcst_octets_nonip +
+                               counters->cnt_rx_bcst_octets_nonip;
+
+               counters->cnt_rx_octets_ipv4  =
+                               counters->cnt_rx_ucst_octets_ipv4 +
+                               counters->cnt_rx_mcst_octets_ipv4 +
+                               counters->cnt_rx_bcst_octets_ipv4;
+
+               counters->cnt_rx_octets_ipv6  =
+                               counters->cnt_rx_ucst_octets_ipv6 +
+                               counters->cnt_rx_mcst_octets_ipv6 +
+                               counters->cnt_rx_bcst_octets_ipv6;
+
+               counters->cnt_rx_good_octets =
+                               counters->cnt_rx_octets_nonip +
+                               counters->cnt_rx_octets_ipv4 +
+                               counters->cnt_rx_octets_ipv6;
+       } else {
+               /*
+                * RX counters.
+                */
+               counters->cnt_rx_ucst_pkts =
+                               counters->cnt_rx_ucst_pkts_nonip;
+               counters->cnt_rx_mcst_pkts =
+                               counters->cnt_rx_mcst_pkts_nonip;
+               counters->cnt_rx_bcst_pkts =
+                               counters->cnt_rx_bcst_pkts_nonip;
+
+               /*
+                * Misc. counters.
+                */
+               counters->cnt_rx_octets_nonip  =
+                               counters->cnt_rx_ucst_octets_nonip +
+                               counters->cnt_rx_mcst_octets_nonip +
+                               counters->cnt_rx_bcst_octets_nonip;
+
+               counters->cnt_rx_good_octets =
+                               counters->cnt_rx_octets_nonip;
+       }
+
+       counters->cnt_trigger_drop_redir_pkts =
+                       counters->cnt_trigger_redir_pkts +
+                       counters->cnt_trigger_drop_pkts;
+
+       /* Emulate Tx _octets counter using the sum of all size bins. */
+       counters->cnt_tx_octets += counters->cnt_tx_minto63_octets;
+       counters->cnt_tx_octets += counters->cnt_tx_64_octets;
+       counters->cnt_tx_octets += counters->cnt_tx_65to127_octets;
+       counters->cnt_tx_octets += counters->cnt_tx_128to255_octets;
+       counters->cnt_tx_octets += counters->cnt_tx_256to511_octets;
+       counters->cnt_tx_octets += counters->cnt_tx_512to1023_octets;
+       counters->cnt_tx_octets += counters->cnt_tx_1024to1522_octets;
+       counters->cnt_tx_octets += counters->cnt_tx_1523to2047_octets;
+       counters->cnt_tx_octets += counters->cnt_tx_2048to4095_octets;
+       counters->cnt_tx_octets += counters->cnt_tx_4096to8191_octets;
+       counters->cnt_tx_octets += counters->cnt_tx_8192to10239_octets;
+       counters->cnt_tx_octets += counters->cnt_tx_10240tomax_octets;
+
+       return 0;
+}   /* end fm10k_get_port_counters */
+
+
+struct fm10k_stats_data {
+       uint64_t rx_pkts;
+       uint64_t tx_pkts;
+       uint64_t rx_drop;
+};
+
+
+static uint64_t
+fm10k_stats_ffu_count_get(struct fm10k_switch *sw, int table_id)
+{
+       uint64_t data;
+
+       if (FM10K_SW_FFU_CNT_BANK < 2) {
+               data = fm10k_read_switch_reg64(sw,
+                               0xE40000 + 0x4000 * FM10K_SW_FFU_CNT_BANK +
+                               0x4 * (table_id + FM10K_SW_FFU_CNT_START) +
+                               0x8000);
+       } else {
+               data = fm10k_read_switch_reg64(sw,
+                               0xE40000 + 0x800 * (FM10K_SW_FFU_CNT_BANK - 2) +
+                               0x4 * (table_id + FM10K_SW_FFU_CNT_START) +
+                               0x10000);
+       }
+       return data;
+}
+
+static void
+fm10k_stats_epl_ffu_print(struct fm10k_switch *sw, int epl)
+{
+       int table_id;
+       uint64_t data;
+
+       table_id = FM10K_FFU_EXT_PORT_RULE_INGRESS(epl);
+       data = fm10k_stats_ffu_count_get(sw, table_id);
+       printf("             FFU[%d] ingress        %-12llu\n",
+                       table_id, (unsigned long long)(data));
+
+       table_id = FM10K_FFU_EXT_PORT_RULE_EGRESS(epl);
+       data = fm10k_stats_ffu_count_get(sw, table_id);
+       printf("             FFU[%d]  egress        %-12llu\n",
+                       table_id, (unsigned long long)(data));
+}
+
+#define FM10K_STATS_RULE_NUM_MAX       100
+static uint16_t fm10k_stats_rule_list[FM10K_STATS_RULE_NUM_MAX];
+void
+fm10k_stats_rule_count_reg(uint16_t rule_id)
+{
+       int i;
+
+       for (i = 0; i < FM10K_STATS_RULE_NUM_MAX; i++) {
+               if (fm10k_stats_rule_list[i] == 0) {
+                       fm10k_stats_rule_list[i] = rule_id;
+                       break;
+               }
+       }
+}
+
+void
+fm10k_stats_ffu_count_print(struct fm10k_switch *sw)
+{
+       int i, rule_id;
+       uint64_t data;
+       static uint64_t ffu_count[FM10K_STATS_RULE_NUM_MAX];
+
+       for (i = 0; i < FM10K_STATS_RULE_NUM_MAX; i++) {
+               if (fm10k_stats_rule_list[i] == 0)
+                       continue;
+
+               rule_id = fm10k_stats_rule_list[i];
+               data = fm10k_stats_ffu_count_get(sw, rule_id);
+               printf("FFU[%d] count         %-12llu\n",
+                               rule_id,
+                               (unsigned long long)
+                               (data - ffu_count[rule_id]));
+               ffu_count[rule_id] = data;
+       }
+}
+
+void
+fm10k_stats_epl_port_print(struct fm10k_switch *sw)
+{
+       int i, lport;
+       struct fm10k_port_counters counters;
+       struct fm10k_ext_port ext_port;
+       static struct fm10k_stats_data last_data[FM10K_SW_EXT_PORTS_MAX];
+       struct fm10k_stats_data data;
+
+       for (i = 0; i < FM10K_SW_EPLS_SUPPORTED; i++) {
+               lport = sw->epl_map[i].logical_port;
+               ext_port.portno = lport;
+               fm10k_get_port_counters(sw, &ext_port, &counters);
+
+               data.rx_pkts =
+                       counters.cnt_rx_bcst_pkts +
+                       counters.cnt_rx_ucst_pkts;
+               data.tx_pkts =
+                       counters.cnt_tx_bcst_pkts +
+                       counters.cnt_tx_ucst_pkts;
+               data.rx_drop = counters.cnt_cmpriv_drop_pkts;
+               printf("EPL  port %-2d lport %-5d tx_pkt %-12llu rx_pkt %-12llu 
drop_pkt %-12llu\n",
+                               i, lport,
+                               (unsigned long long)
+                               (data.tx_pkts - last_data[i].tx_pkts),
+                               (unsigned long long)
+                               (data.rx_pkts - last_data[i].rx_pkts),
+                               (unsigned long long)
+                               (data.rx_drop - last_data[i].rx_drop));
+               last_data[i] = data;
+
+               if (fm10k_config_check_debug(sw->dpdk_cfg,
+                               FM10K_CONFIG_DEBUG_STATS_FFU))
+                       fm10k_stats_epl_ffu_print(sw, i);
+       }
+}
+
+
+void
+fm10k_stats_dpdk_port_print(struct fm10k_switch *sw)
+{
+       int i, j, lport, pf_no;
+       struct fm10k_port_counters counters;
+       struct fm10k_ext_port ext_port;
+       static struct fm10k_stats_data last_data[FM10K_SW_PEPS_MAX];
+       static struct fm10k_stats_data last_queue_data[FM10K_SW_PEPS_MAX][4];
+       struct fm10k_stats_data data, mydata;
+       char pf_ports[10];
+
+       for (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++) {
+               if (sw->dpdk_cfg->ports[i].hw == NULL)
+                       continue;
+               if (sw->dpdk_cfg->ports[i].type != FM10K_CONFIG_DPDK_PF)
+                       continue;
+               if (sw->dpdk_cfg->dpdk_port_map[i].type ==
+                               FM10K_CONFIG_PORT_MAP_NULL)
+                       continue;
+
+               memset(&mydata, 0, sizeof(mydata));
+               if (sw->dpdk_cfg->dpdk_port_map[i].type ==
+                               FM10K_CONFIG_PORT_MAP_PFS) {
+                       for (j = 0; j < 2; j++) {
+                               pf_no =
+                               sw->dpdk_cfg->dpdk_port_map[i].map_no[j];
+                               lport = sw->pep_map[pf_no].logical_port;
+                               memset(&ext_port, 0, sizeof(ext_port));
+                               ext_port.portno = lport;
+                               fm10k_get_port_counters
+                               (sw, &ext_port, &counters);
+                               data.rx_pkts = counters.cnt_rx_bcst_pkts +
+                                               counters.cnt_rx_ucst_pkts;
+                               data.tx_pkts = counters.cnt_tx_bcst_pkts +
+                                               counters.cnt_tx_ucst_pkts;
+                               data.rx_drop = counters.cnt_cmpriv_drop_pkts;
+                               mydata.rx_pkts += data.rx_pkts -
+                                               last_data[pf_no].rx_pkts;
+                               mydata.tx_pkts += data.tx_pkts -
+                                               last_data[pf_no].tx_pkts;
+                               mydata.rx_drop += data.rx_drop -
+                                               last_data[pf_no].rx_drop;
+                               last_data[pf_no] = data;
+                       }
+               } else if (sw->dpdk_cfg->dpdk_port_map[i].type ==
+                               FM10K_CONFIG_PORT_MAP_PF) {
+                       pf_no = sw->dpdk_cfg->dpdk_port_map[i].map_no[0];
+                       lport = sw->pep_map[pf_no].logical_port;
+                       memset(&ext_port, 0, sizeof(ext_port));
+                       ext_port.portno = lport;
+                       fm10k_get_port_counters(sw, &ext_port, &counters);
+                       data.rx_pkts = counters.cnt_rx_bcst_pkts +
+                                       counters.cnt_rx_ucst_pkts;
+                       data.tx_pkts = counters.cnt_tx_bcst_pkts +
+                                       counters.cnt_tx_ucst_pkts;
+                       data.rx_drop = counters.cnt_cmpriv_drop_pkts;
+                       mydata.rx_pkts += data.rx_pkts -
+                                       last_data[pf_no].rx_pkts;
+                       mydata.tx_pkts += data.tx_pkts -
+                                       last_data[pf_no].tx_pkts;
+                       mydata.rx_drop += data.rx_drop -
+                                       last_data[pf_no].rx_drop;
+                       last_data[pf_no] = data;
+               } else {
+                       continue;
+               }
+
+               if (sw->dpdk_cfg->dpdk_port_map[i].type ==
+                               FM10K_CONFIG_PORT_MAP_PF)
+                       sprintf(pf_ports, "%d",
+                               sw->dpdk_cfg->dpdk_port_map[i].map_no[0]);
+               else
+                       sprintf(pf_ports, "%d/%d",
+                               sw->dpdk_cfg->dpdk_port_map[i].map_no[0],
+                               sw->dpdk_cfg->dpdk_port_map[i].map_no[1]);
+
+               printf("DPDK port %-2d  pf %-5s   tx_pkt %-12llu "
+                               "rx_pkt %-12llu drop_pkt %-12llu\n",
+                               i, pf_ports,
+                               (unsigned long long)mydata.tx_pkts,
+                               (unsigned long long)mydata.rx_pkts,
+                               (unsigned long long)mydata.rx_drop);
+
+               if (!fm10k_config_check_debug(sw->dpdk_cfg,
+                               FM10K_CONFIG_DEBUG_STATS_QUEUE))
+                       continue;
+               memset(&mydata, 0, sizeof(mydata));
+               for (j = 0;
+                        j < sw->dpdk_cfg->ports[i].tx_queue_num;
+                        j++) {
+                       struct fm10k_hw *hw = sw->dpdk_cfg->ports[i].hw;
+                       uint16_t queue_id = j, pf_no;
+
+                       fm10k_switch_dpdk_hw_queue_map(hw, queue_id,
+                                       sw->dpdk_cfg->ports[i].tx_queue_num,
+                                       &hw, &queue_id);
+                       pf_no = fm10k_switch_dpdk_pf_no_get(hw);
+                       data.tx_pkts =
+                               FM10K_READ_REG(hw, FM10K_QPTC(queue_id));
+                       data.rx_pkts =
+                               FM10K_READ_REG(hw, FM10K_QPRC(queue_id));
+                       data.rx_drop =
+                               FM10K_READ_REG(hw, FM10K_QPRDC(queue_id));
+                       mydata.tx_pkts += data.tx_pkts -
+                               last_queue_data[pf_no][queue_id].tx_pkts;
+                       mydata.rx_pkts += data.rx_pkts -
+                               last_queue_data[pf_no][queue_id].rx_pkts;
+                       mydata.rx_drop += data.rx_drop -
+                               last_queue_data[pf_no][queue_id].rx_drop;
+                       printf("            queue %d(%d:%d) tx_pkt %-12llu "
+                               "rx_pkt %-12llu drop_pkt %-12llu\n", j,
+                               pf_no, queue_id,
+                               (unsigned long long)(data.tx_pkts -
+                               last_queue_data[pf_no][queue_id].tx_pkts),
+                               (unsigned long long)(data.rx_pkts -
+                               last_queue_data[pf_no][queue_id].rx_pkts),
+                               (unsigned long long)(data.rx_drop -
+                               last_queue_data[pf_no][queue_id].rx_drop));
+                       last_queue_data[pf_no][queue_id] = data;
+               }
+               printf("                   total tx_pkt %-12llu "
+                               "rx_pkt %-12llu drop_pkt %-12llu\n",
+                               (unsigned long long)mydata.tx_pkts,
+                               (unsigned long long)mydata.rx_pkts,
+                               (unsigned long long)mydata.rx_drop);
+       }
+}
+
+
+static void
+fm10k_stats_port_counter_print(struct fm10k_switch *sw, int lport)
+{
+       unsigned int i;
+       struct fm10k_port_counters counters;
+       struct fm10k_ext_port ext_port;
+       uint64_t *pdata;
+
+       memset(&ext_port, 0, sizeof(ext_port));
+       ext_port.portno = lport;
+       fm10k_get_port_counters(sw, &ext_port, &counters);
+
+       for (i = 0;
+                       i < sizeof(rx_port_cnt_map_table) /
+                               sizeof(rx_port_cnt_map_table[0]);
+                       i++) {
+               pdata =
+                       (uint64_t *)((uint8_t *)(&counters) +
+                       rx_port_cnt_map_table[i].frame_offset);
+               if (*pdata != 0) {
+                       printf("port %d rx bank %d idx %d pkt %llu\n", lport,
+                                       rx_port_cnt_map_table[i].bank,
+                                       rx_port_cnt_map_table[i].bin,
+                                       (unsigned long long)*pdata);
+               }
+       }
+       for (i = 0;
+                       i < sizeof(tx_port_cnt_map_table) /
+                               sizeof(tx_port_cnt_map_table[0]);
+                       i++) {
+               pdata =
+                       (uint64_t *)((uint8_t *)(&counters) +
+                       tx_port_cnt_map_table[i].frame_offset);
+               if (*pdata != 0) {
+                       printf("port %d tx bank %d idx %d pkt %llu\n",
+                                       lport,
+                                       tx_port_cnt_map_table[i].bank,
+                                       tx_port_cnt_map_table[i].bin,
+                                       (unsigned long long)*pdata);
+               }
+       }
+}
+
+void
+fm10k_stats_port_bank_print(struct fm10k_switch *sw)
+{
+       int i;
+
+       for (i = 0;
+                i < FM10K_SW_EPLS_SUPPORTED;
+                i++) {
+               fm10k_stats_port_counter_print(sw,
+                               sw->epl_map[i].logical_port);
+       }
+       for (i = 0;
+                i < FM10K_SW_PEPS_SUPPORTED;
+                i++) {
+               fm10k_stats_port_counter_print(sw,
+                               sw->pep_map[i].logical_port);
+       }
+}
+
+
+void *
+fm10k_switch_process_stats(void *ctx)
+{
+       struct fm10k_switch *sw = ctx;
+
+       usec_delay(5000000);
+
+       if (!fm10k_config_check_debug(sw->dpdk_cfg,
+                       FM10K_CONFIG_DEBUG_ENABLE))
+               return NULL;
+
+       if (!sw->dpdk_cfg->stats_interval)
+               return NULL;
+
+       while (1) {
+               if (fm10k_config_check_debug(sw->dpdk_cfg,
+                               FM10K_CONFIG_DEBUG_STATS_PORT)) {
+                       printf("--- port statistic ---\n");
+                       fm10k_stats_epl_port_print(sw);
+                       fm10k_stats_dpdk_port_print(sw);
+               }
+               if (fm10k_config_check_debug(sw->dpdk_cfg,
+                               FM10K_CONFIG_DEBUG_STATS_FFU)) {
+                       printf("--- ffu statistic ---\n");
+                       fm10k_stats_ffu_count_print(sw);
+               }
+               if (fm10k_config_check_debug(sw->dpdk_cfg,
+                               FM10K_CONFIG_DEBUG_STATS_MORE)) {
+                       printf("--- detail statistic ---\n");
+                       fm10k_stats_port_bank_print(sw);
+               }
+               usec_delay(1000000 * sw->dpdk_cfg->stats_interval);
+       }
+       return NULL;
+}
+
diff --git a/drivers/net/fm10k/switch/fm10k_stats.h 
b/drivers/net/fm10k/switch/fm10k_stats.h
new file mode 100644
index 0000000..5180312
--- /dev/null
+++ b/drivers/net/fm10k/switch/fm10k_stats.h
@@ -0,0 +1,257 @@
+/* spdx-license-identifier: bsd-3-clause
+ * copyright 2019   silicom ltd. connectivity solutions
+ */
+
+#ifndef _fm10k_stats_h_
+#define _fm10k_stats_h_
+
+
+#include <stdint.h>
+
+
+#define FM10K_STATS_VERSION      (1 << 4)
+
+
+struct fm10k_scatter_gather_entry {
+       uint32_t  addr;
+       uint32_t  count;
+       uint32_t *data;
+
+};
+
+
+struct fm10k_port_counters {
+       uint64_t cnt_version;
+       uint64_t cnt_rx_ucst_pkts;
+       uint64_t cnt_rx_ucst_pkts_nonip;
+       uint64_t cnt_rx_ucst_pkts_ipv4;
+       uint64_t cnt_rx_ucst_pkts_ipv6;
+       uint64_t cnt_rx_bcst_pkts;
+       uint64_t cnt_rx_bcst_pkts_nonip;
+       uint64_t cnt_rx_bcst_pkts_ipv4;
+       uint64_t cnt_rx_bcst_pkts_ipv6;
+       uint64_t cnt_rx_mcst_pkts;
+       uint64_t cnt_rx_mcst_pkts_nonip;
+       uint64_t cnt_rx_mcst_pkts_ipv4;
+       uint64_t cnt_rx_mcst_pkts_ipv6;
+       uint64_t cnt_rx_pause_pkts;
+       uint64_t cnt_rx_cbpause_pkts;
+       uint64_t cnt_rx_fcs_errors;
+       uint64_t cnt_rx_symbol_errors;
+       uint64_t cnt_rx_framesize_errors;
+       uint64_t cnt_rx_framing_error_pkts;
+       uint64_t cnt_rx_minto63_pkts;
+       uint64_t cnt_rx_64_pkts;
+       uint64_t cnt_rx_65to127_pkts;
+       uint64_t cnt_rx_128to255_pkts;
+       uint64_t cnt_rx_256to511_pkts;
+       uint64_t cnt_rx_512to1023_pkts;
+       uint64_t cnt_rx_1024to1522_pkts;
+       uint64_t cnt_rx_1523to2047_pkts;
+       uint64_t cnt_rx_2048to4095_pkts;
+       uint64_t cnt_rx_4096to8191_pkts;
+       uint64_t cnt_rx_8192to10239_pkts;
+       uint64_t cnt_rx_10240tomax_pkts;
+       uint64_t cnt_rx_minto63_octets;
+       uint64_t cnt_rx_64_octets;
+       uint64_t cnt_rx_65to127_octets;
+       uint64_t cnt_rx_128to255_octets;
+       uint64_t cnt_rx_256to511_octets;
+       uint64_t cnt_rx_512to1023_octets;
+       uint64_t cnt_rx_1024to1522_octets;
+       uint64_t cnt_rx_1523to2047_octets;
+       uint64_t cnt_rx_2048to4095_octets;
+       uint64_t cnt_rx_4096to8191_octets;
+       uint64_t cnt_rx_8192to10239_octets;
+       uint64_t cnt_rx_10240tomax_octets;
+       uint64_t cnt_rx_octets_nonip;
+       uint64_t cnt_rx_octets_ipv4;
+       uint64_t cnt_rx_octets_ipv6;
+       uint64_t cnt_rx_ucst_octets_nonip;
+       uint64_t cnt_rx_ucst_octets_ipv4;
+       uint64_t cnt_rx_ucst_octets_ipv6;
+       uint64_t cnt_rx_bcst_octets_nonip;
+       uint64_t cnt_rx_bcst_octets_ipv4;
+       uint64_t cnt_rx_bcst_octets_ipv6;
+       uint64_t cnt_rx_mcst_octets_nonip;
+       uint64_t cnt_rx_mcst_octets_ipv4;
+       uint64_t cnt_rx_mcst_octets_ipv6;
+       uint64_t cnt_rx_pause_octets;
+       uint64_t cnt_rx_cbpause_octets;
+       uint64_t cnt_rx_fcs_errors_octets;
+       uint64_t cnt_rx_framing_error_octets;
+       uint64_t cnt_rx_good_octets;
+       uint64_t cnt_rx_bad_octets;
+       uint64_t cnt_rx_priority_pkts[16];
+       uint64_t cnt_rx_invalid_priority_pkts;
+       uint64_t cnt_rx_priority_octets[16];
+       uint64_t cnt_rx_invalid_priority_octets;
+       uint64_t cnt_fid_forwarded_pkts;
+       uint64_t cnt_flood_forwarded_pkts;
+       uint64_t cnt_glort_switched_pkts;
+       uint64_t cnt_glort_routed_pkts;
+       uint64_t cnt_specially_handled_pkts;
+       uint64_t cnt_parse_err_drop_pkts;
+       uint64_t cnt_parity_error_pkts;
+       uint64_t cnt_trapped_pkts;
+       uint64_t cnt_pause_drop_pkts;
+       uint64_t cnt_stp_drop_pkts;
+       uint64_t cnt_stp_ingress_drops_pkts;
+       uint64_t cnt_stp_egress_drops_pkts;
+       uint64_t cnt_reserved_trap_pkts;
+       uint64_t cnt_security_violation_pkts;
+       uint64_t cnt_vlan_tag_drop_pkts;
+       uint64_t cnt_vlan_ingressbv_pkts;
+       uint64_t cnt_vlan_egressbv_pkts;
+       uint64_t cnt_loopback_drops_pkts;
+       uint64_t cnt_glort_miss_drop_pkts;
+       uint64_t cnt_ffu_drop_pkts;
+       uint64_t cnt_invalid_drop_pkts;
+       uint64_t cnt_policer_drop_pkts;
+       uint64_t cnt_ttl_drop_pkts;
+       uint64_t cnt_global_wmdrop_pkts;
+       uint64_t cnt_rx_mpdrop_pkts;
+       uint64_t cnt_rx_hogdrop_pkts;
+       uint64_t cnt_tx_hogdrop_pkts;
+       uint64_t cnt_other_pkts;
+       uint64_t cnt_flood_control_drop_pkts;
+       uint64_t cnt_cmpriv_drop_pkts;
+       uint64_t cnt_smp0_drop_pkts;
+       uint64_t cnt_smp1_drop_pkts;
+       uint64_t cnt_rx_hog0_drop_pkts;
+       uint64_t cnt_rx_hog1_drop_pkts;
+       uint64_t cnt_tx_hog0_drop_pkts;
+       uint64_t cnt_tx_hog1_drop_pkts;
+       uint64_t cnt_rate_limit0_drop_pkts;
+       uint64_t cnt_rate_limit1_drop_pkts;
+       uint64_t cnt_bad_smp_drop_pkts;
+       uint64_t cnt_trigger_drop_redir_pkts;
+       uint64_t cnt_trigger_drop_pkts;
+       uint64_t cnt_trigger_redir_pkts;
+       uint64_t cnt_glort_forwarded_pkts;
+       uint64_t cnt_trigger_mirrored_pkts;
+       uint64_t cnt_broadcast_drop_pkts;
+       uint64_t cnt_dlf_drop_pkts;
+       uint64_t cnt_rx_cm_drop_pkts;
+       uint64_t cnt_fid_forwarded_octets;
+       uint64_t cnt_flood_forwarded_octets;
+       uint64_t cnt_specially_handled_octets;
+       uint64_t cnt_parse_err_drop_octets;
+       uint64_t cnt_parity_error_octets;
+       uint64_t cnt_trapped_octets;
+       uint64_t cnt_pause_drop_octets;
+       uint64_t cnt_stp_drop_octets;
+       uint64_t cnt_security_violation_octets;
+       uint64_t cnt_vlan_tag_drop_octets;
+       uint64_t cnt_vlan_ingressbv_octets;
+       uint64_t cnt_vlan_egressbv_octets;
+       uint64_t cnt_loopback_drop_octets;
+       uint64_t cnt_glort_miss_drop_octets;
+       uint64_t cnt_ffu_drop_octets;
+       uint64_t cnt_policer_drop_octets;
+       uint64_t cnt_ttl_drop_octets;
+       uint64_t cnt_other_octets;
+       uint64_t cnt_flood_control_drop_octets;
+       uint64_t cnt_cmpriv_drop_octets;
+       uint64_t cnt_smp0_drop_octets;
+       uint64_t cnt_smp1_drop_octets;
+       uint64_t cnt_rx_hog0_drop_octets;
+       uint64_t cnt_rx_hog1_drop_octets;
+       uint64_t cnt_tx_hog0_drop_octets;
+       uint64_t cnt_tx_hog1_drop_octets;
+       uint64_t cnt_trigger_drop_octets;
+       uint64_t cnt_trigger_redir_octets;
+       uint64_t cnt_glort_forwarded_octets;
+       uint64_t cnt_tx_ucst_pkts;
+       uint64_t cnt_tx_bcst_pkts;
+       uint64_t cnt_tx_mcst_pkts;
+       uint64_t cnt_tx_ucst_pkts_nonip;
+       uint64_t cnt_tx_bcst_pkts_nonip;
+       uint64_t cnt_tx_mcst_pkts_nonip;
+       uint64_t cnt_tx_ucst_pkts_ip;
+       uint64_t cnt_tx_bcst_pkts_ip;
+       uint64_t cnt_tx_mcst_pkts_ip;
+       uint64_t cnt_tx_pause_pkts;
+       uint64_t cnt_tx_cbpause_pkts;
+       uint64_t cnt_tx_fcs_err_drop_pkts;
+       uint64_t cnt_tx_framing_error_pkts;
+       uint64_t cnt_tx_error_sent_pkts;
+       uint64_t cnt_tx_error_drop_pkts;
+       uint64_t cnt_tx_timeout_pkts;
+       uint64_t cnt_tx_outofmem_err_pkts;
+       uint64_t cnt_tx_unrepair_ecc_pkts;
+       uint64_t cnt_tx_loopback_pkts;
+       uint64_t cnt_tx_ttl_drop_pkts;
+       uint64_t cnt_tx_minto63_pkts;
+       uint64_t cnt_tx_64_pkts;
+       uint64_t cnt_tx_65to127_pkts;
+       uint64_t cnt_tx_128to255_pkts;
+       uint64_t cnt_tx_256to511_pkts;
+       uint64_t cnt_tx_512to1023_pkts;
+       uint64_t cnt_tx_1024to1522_pkts;
+       uint64_t cnt_tx_1523to2047_pkts;
+       uint64_t cnt_tx_2048to4095_pkts;
+       uint64_t cnt_tx_4096to8191_pkts;
+       uint64_t cnt_tx_8192to10239_pkts;
+       uint64_t cnt_tx_10240tomax_pkts;
+       uint64_t cnt_tx_minto63_octets;
+       uint64_t cnt_tx_64_octets;
+       uint64_t cnt_tx_65to127_octets;
+       uint64_t cnt_tx_128to255_octets;
+       uint64_t cnt_tx_256to511_octets;
+       uint64_t cnt_tx_512to1023_octets;
+       uint64_t cnt_tx_1024to1522_octets;
+       uint64_t cnt_tx_1523to2047_octets;
+       uint64_t cnt_tx_2048to4095_octets;
+       uint64_t cnt_tx_4096to8191_octets;
+       uint64_t cnt_tx_8192to10239_octets;
+       uint64_t cnt_tx_10240tomax_octets;
+       uint64_t cnt_tx_ucst_octets_nonip;
+       uint64_t cnt_tx_bcst_octets_nonip;
+       uint64_t cnt_tx_mcst_octets_nonip;
+       uint64_t cnt_tx_ucst_octets_ip;
+       uint64_t cnt_tx_bcst_octets_ip;
+       uint64_t cnt_tx_mcst_octets_ip;
+       uint64_t cnt_tx_ucst_octets;
+       uint64_t cnt_tx_mcst_octets;
+       uint64_t cnt_tx_bcst_octets;
+       uint64_t cnt_tx_fcs_err_drop_octets;
+       uint64_t cnt_tx_octets;
+       uint64_t cnt_tx_error_octets;
+       uint64_t cnt_tx_framing_error_octets;
+       uint64_t cnt_tx_pause_octets;
+       uint64_t cnt_tx_cbpause_octets;
+       uint64_t cnt_tx_fcs_errored_octets;
+       uint64_t cnt_tx_error_sent_octets;
+       uint64_t cnt_tx_timeout_octets;
+       uint64_t cnt_tx_outofmem_err_octets;
+       uint64_t cnt_tx_unrepair_ecc_octets;
+       uint64_t cnt_tx_loopback_octets;
+       uint64_t cnt_tx_ttl_drop_octets;
+       uint64_t cnt_tx_priority_octets[16];
+       uint64_t cnt_under_run_pkts;
+       uint64_t cnt_over_run_pkts;
+       uint64_t cnt_rx_fragment_pkts;
+       uint64_t cnt_rx_undersized_pkts;
+       uint64_t cnt_rx_jabber_pkts;
+       uint64_t cnt_corrupted_pkts;
+       uint64_t cnt_code_errors;
+       uint64_t cnt_rx_oversized_pkts;
+       uint64_t cnt_tx_fcs_errored_pkts;
+       uint64_t cnt_stats_drop_count_tx;
+       uint64_t cnt_stats_drop_count_rx;
+       uint64_t cnt_tx_mirror_pkts;
+       uint64_t cnt_tx_mirror_octets;
+       uint64_t cnt_tx_cmdrop_pkts;
+       uint64_t timestamp;
+};
+
+void fm10k_stats_rule_count_reg(uint16_t rule_id);
+void *fm10k_switch_process_stats(void *ctx_);
+
+void fm10k_stats_epl_port_print(struct fm10k_switch *sw);
+void fm10k_stats_dpdk_port_print(struct fm10k_switch *sw);
+void fm10k_stats_ffu_count_print(struct fm10k_switch *sw);
+void fm10k_stats_port_bank_print(struct fm10k_switch *sw);
+
+#endif /* _fm10k_stats_h */
-- 
1.8.3.1

Reply via email to