@@ -89,6 +89,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_spico_code.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_ext_port.c
+SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_config.c
+SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_ffu.c
+SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_stats.c
endif
SRCS-$(CONFIG_RTE_LIBRTE_FM10K_INC_VECTOR) += fm10k_rxtx_vec.c
new file mode 100644
@@ -0,0 +1,863 @@
+/* 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
+
+/* used for store the key strings */
+struct fm10k_cfg_key_item {
+ const char *key_str[FM10K_CONFIG_WORD_MAX];
+ uint8_t type;
+};
+
+/* configuration file path */
+static const char *fm10k_config_dpdk_conf_file = "/etc/dpdk_fm10k.conf";
+/* configuration structure */
+static struct fm10k_dpdk_cfg fm10k_config_dpdk_cfg;
+
+/* configuration key strings */
+static struct fm10k_cfg_key_item fm10k_config_key_items[] = {
+ /* enable debug print */
+ { {"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;
+
+ FM10K_SW_INFO(" FLOWSET ENABLE: %s\n",
+ fm10k_config_dpdk_cfg.current->name);
+
+ flowset = fm10k_config_dpdk_cfg.flowset_head.next;
+ while (flowset) {
+ FM10K_SW_INFO("\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) {
+ FM10K_SW_INFO(" 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 {
+ FM10K_SW_INFO(" 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;
+
+ FM10K_SW_INFO("--- FM10K STATIC CONFIG ---\n");
+ FM10K_SW_INFO(" Card Type: %s\n", info->desc);
+ FM10K_SW_INFO(" PF Max : %d\n", fm10k_config_dpdk_cfg.pf_max);
+ FM10K_SW_INFO(" PF Bind : %d\n", fm10k_config_dpdk_cfg.pf_num);
+ FM10K_SW_INFO(" DEBUG : %#x\n", fm10k_config_dpdk_cfg.debug_cfg);
+ FM10K_SW_INFO(" STATS GAP: %d sec\n",
+ fm10k_config_dpdk_cfg.stats_interval);
+ FM10K_SW_INFO(" EXT PORT speed: %d Gbps\n",
+ fm10k_config_dpdk_cfg.ext_port_speed);
+ FM10K_SW_INFO(" 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)
+ FM10K_SW_INFO(" EXT PORT[%d] MAP: PF%d\n", i + 1,
+ fm10k_config_dpdk_cfg.ext_port_map[i].map_no[0]);
+ else
+ FM10K_SW_INFO(" 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)
+ FM10K_SW_INFO(" DPDK PORT[%d] MAP: PF%d\n", i,
+ fm10k_config_dpdk_cfg.dpdk_port_map[i].map_no[0]);
+ else
+ FM10K_SW_INFO(" 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) {
+ FM10K_SW_INFO("\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) {
+ FM10K_SW_INFO(" 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 {
+ FM10K_SW_INFO(" 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;
+ }
+ FM10K_SW_INFO("\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;
+}
new file mode 100644
@@ -0,0 +1,178 @@
+/* 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 */
new file mode 100644
@@ -0,0 +1,1253 @@
+/* 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)) \
+ FM10K_SW_INFO(__VA_ARGS__); \
+} while (0)
+
+#define FM10K_FFU_RULE_PRINT(cfg, ...) \
+do { \
+ if (fm10k_config_check_debug(cfg, FM10K_CONFIG_DEBUG_FFU_RULE)) \
+ FM10K_SW_INFO(__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 struct fm10k_multi_glort {
+ uint8_t lport1;
+ uint8_t lport2;
+ uint16_t vlan1;
+ uint16_t vlan2;
+} fm10k_multi_glorts[FM10K_SW_FFU_RULE_MAX];
+
+static uint32_t
+fm10k_ffu_multi_glort_get(uint8_t lport1, uint8_t lport2,
+ uint16_t vlan1, uint16_t vlan2, bool *p_new)
+{
+ int i;
+
+ for (i = 0; i < FM10K_SW_FFU_RULE_MAX; i++) {
+ if (lport1 == fm10k_multi_glorts[i].lport1 &&
+ lport2 == fm10k_multi_glorts[i].lport2 &&
+ vlan1 == fm10k_multi_glorts[i].vlan1 &&
+ vlan2 == fm10k_multi_glorts[i].vlan2) {
+ if (p_new != NULL)
+ *p_new = false;
+ return FM10K_SW_MULTI_GLORT_START + i;
+ }
+ }
+
+ for (i = 0; i < FM10K_SW_FFU_RULE_MAX; i++) {
+ if (fm10k_multi_glorts[i].lport1 == 0 &&
+ fm10k_multi_glorts[i].lport2 == 0 &&
+ fm10k_multi_glorts[i].vlan1 == 0 &&
+ fm10k_multi_glorts[i].vlan2 == 0) {
+ fm10k_multi_glorts[i].lport1 = lport1;
+ fm10k_multi_glorts[i].lport2 = lport2;
+ fm10k_multi_glorts[i].vlan1 = vlan1;
+ fm10k_multi_glorts[i].vlan2 = vlan2;
+ if (p_new != NULL)
+ *p_new = true;
+ return FM10K_SW_MULTI_GLORT_START + i;
+ }
+ }
+
+ return 0;
+}
+
+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 = false;
+ uint32_t idx;
+ uint64_t temp64;
+
+ dglort =
+ fm10k_ffu_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;
+
+ FM10K_SW_INFO("----- GLORT -----\n");
+
+ for (i = 0; i < sw->glort_cam_ram_idx; i++) {
+ data32 = fm10k_read_switch_reg(sw, FM10K_SW_GLORT_CAM(i));
+ FM10K_SW_INFO("[%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));
+ FM10K_SW_INFO(" 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));
+ FM10K_SW_INFO(" 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));
+ FM10K_SW_INFO(" 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));
+ FM10K_SW_INFO(" 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));
+ FM10K_SW_INFO(" 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));
+ FM10K_SW_INFO(" 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;
+
+ FM10K_SW_INFO("--------------- FFU REGISTERS DUMP -----------------\n");
+
+ fm10k_read_switch_array(sw, FM10K_SW_FFU_MASTER_VALID, data, 2);
+ FM10K_SW_INFO("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;
+
+ FM10K_SW_INFO("------ SLICE%d ------\n", i);
+ fm10k_read_switch_array(sw,
+ FM10K_SW_FFU_SLICE_VALID(i), data, 2);
+ if (data[0] != 0 || data[1] != 0)
+ FM10K_SW_INFO("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)
+ FM10K_SW_INFO("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)
+ FM10K_SW_INFO("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))
+ FM10K_SW_INFO("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)
+ FM10K_SW_INFO("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;
+}
new file mode 100644
@@ -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 */
new file mode 100644
@@ -0,0 +1,1114 @@
+/* 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);
+ FM10K_SW_INFO(" 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);
+ FM10K_SW_INFO(" 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);
+ FM10K_SW_INFO("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;
+ FM10K_SW_INFO("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);
+ }
+}
+
+
+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) {
+ FM10K_SW_INFO("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) {
+ FM10K_SW_INFO("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 (sw->detaching == 0) {
+ if (fm10k_config_check_debug(sw->dpdk_cfg,
+ FM10K_CONFIG_DEBUG_STATS_PORT)) {
+ FM10K_SW_INFO("--- port statistic ---\n");
+ fm10k_stats_epl_port_print(sw);
+ }
+ if (fm10k_config_check_debug(sw->dpdk_cfg,
+ FM10K_CONFIG_DEBUG_STATS_FFU)) {
+ FM10K_SW_INFO("--- ffu statistic ---\n");
+ fm10k_stats_ffu_count_print(sw);
+ }
+ if (fm10k_config_check_debug(sw->dpdk_cfg,
+ FM10K_CONFIG_DEBUG_STATS_MORE)) {
+ FM10K_SW_INFO("--- detail statistic ---\n");
+ fm10k_stats_port_bank_print(sw);
+ }
+ usec_delay(1000000 * sw->dpdk_cfg->stats_interval);
+ }
+ return NULL;
+}
+
new file mode 100644
@@ -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 */
@@ -76,6 +76,37 @@
#define FM10K_SW_MEM_POOL_SEGS_MAX 24576
#define FM10K_SW_MEM_POOL_SEGS_RSVD 256
+/*
+ * GLORT MAP
+ */
+#define FM10K_SW_EPLA_GLORT 0x10
+#define FM10K_SW_EPLB_GLORT 0x20
+#define FM10K_SW_PEP01_GLORT 0x30
+#define FM10K_SW_PEP23_GLORT 0x40
+#define FM10K_SW_PEP45_GLORT 0x50
+#define FM10K_SW_PEP67_GLORT 0x60
+
+/*
+ * logical port number
+ */
+#define FM10K_SW_EPLA_LOGICAL_PORT 1
+#define FM10K_SW_EPLB_LOGICAL_PORT 2
+
+#define FM10K_SW_PEP01_LOGICAL_PORT 3
+#define FM10K_SW_PEP23_LOGICAL_PORT 4
+#define FM10K_SW_PEP45_LOGICAL_PORT 5
+#define FM10K_SW_PEP67_LOGICAL_PORT 6
+
+/*
+ * physical port number
+ */
+#define FM10K_SW_EPLA_PHYSICAL_PORT 0
+#define FM10K_SW_EPLB_PHYSICAL_PORT 4
+
+#define FM10K_SW_PEP01_PHYSICAL_PORT 36
+#define FM10K_SW_PEP23_PHYSICAL_PORT 40
+#define FM10K_SW_PEP45_PHYSICAL_PORT 44
+#define FM10K_SW_PEP67_PHYSICAL_PORT 48
#define FM10K_SW_CARD_ID(v_, d_) (((v_) << 16) | (d_))
@@ -111,6 +142,7 @@
#define FM10K_SW_DEV_ID_PE3100G2DQIRM_QXSL4 0x01C2
#define FM10K_SW_DEV_ID_PE325G2DSIR 0x01C8
+
/*
* SWITCH
*/
@@ -125,6 +157,15 @@ struct fm10k_device_info {
uint8_t num_peps;
};
+static struct fm10k_device_info fm10k_device_table[] = {
+ { FM10K_SW_VENDOR_ID_SILICOM, FM10K_SW_DEV_ID_PE3100G2DQIR_QXSL4,
+ "Silicom PE3100G2DQiR-QX4/QS4/QL4", 2, 100, 2, 2 },
+ { FM10K_SW_VENDOR_ID_SILICOM, FM10K_SW_DEV_ID_PE3100G2DQIRL_QXSL4,
+ "Silicom PE3100G2DQiRL-QX4/QS4/QL4", 2, 100, 2, 2 },
+ { FM10K_SW_VENDOR_ID_SILICOM, FM10K_SW_DEV_ID_PE3100G2DQIRM_QXSL4,
+ "Silicom PE3100G2DQiRM-QX4/QS4/QL4", 2, 100, 2, 4 },
+};
+
struct fm10k_i2c;
struct fm10k_sbus;
@@ -287,6 +328,114 @@ struct fm10k_switch {
fm10k_write_switch_reg(sw, FM10K_SW_GPIO_DATA, data);
}
+
+static struct fm10k_sw_port_map fm10k_pep_port_map[FM10K_SW_PEPS_SUPPORTED] = {
+ {
+ FM10K_SW_PEP01_GLORT,
+ FM10K_SW_PEP01_LOGICAL_PORT,
+ FM10K_SW_PEP01_PHYSICAL_PORT
+ },
+ {
+ FM10K_SW_PEP23_GLORT,
+ FM10K_SW_PEP23_LOGICAL_PORT,
+ FM10K_SW_PEP23_PHYSICAL_PORT
+ },
+ {
+ FM10K_SW_PEP45_GLORT,
+ FM10K_SW_PEP45_LOGICAL_PORT,
+ FM10K_SW_PEP45_PHYSICAL_PORT
+ },
+ {
+ FM10K_SW_PEP67_GLORT,
+ FM10K_SW_PEP67_LOGICAL_PORT,
+ FM10K_SW_PEP67_PHYSICAL_PORT
+ },
+};
+
+static struct fm10k_sw_port_map fm10k_epl_port_map[FM10K_SW_EPLS_SUPPORTED] = {
+ {
+ FM10K_SW_EPLA_GLORT,
+ FM10K_SW_EPLA_LOGICAL_PORT,
+ FM10K_SW_EPLA_PHYSICAL_PORT
+ },
+ {
+ FM10K_SW_EPLB_GLORT,
+ FM10K_SW_EPLB_LOGICAL_PORT,
+ FM10K_SW_EPLB_PHYSICAL_PORT
+ },
+};
+
+static inline uint32_t
+fm10k_switch_pf_logical_get(uint8_t pf_no)
+{
+ return fm10k_pep_port_map[pf_no].logical_port;
+}
+
+static inline uint32_t
+fm10k_switch_epl_logical_get(uint8_t epl_no)
+{
+ return fm10k_epl_port_map[epl_no].logical_port;
+}
+
+static inline uint32_t
+fm10k_switch_vf_glort_get(uint8_t vf_no)
+{
+ return FM10K_SW_VF_GLORT_START + vf_no;
+}
+
+static inline uint32_t
+fm10k_switch_pf_glort_get(uint8_t pf_no)
+{
+ return fm10k_pep_port_map[pf_no].glort;
+}
+
+static inline uint32_t
+fm10k_switch_epl_glort_get(uint8_t epl_no)
+{
+ return fm10k_epl_port_map[epl_no].glort;
+}
+
+static inline uint32_t
+fm10k_switch_pfs_glort_get(uint8_t pf1, uint8_t pf2)
+{
+ uint8_t idx;
+ if (pf1 > pf2)
+ idx = (pf2 & 0xf) | (pf1 << 4 & 0xf0);
+ else
+ idx = (pf1 & 0xf) | (pf2 << 4 & 0xf0);
+ return FM10K_SW_PFS_GLORT_START + idx;
+}
+
+
+static inline struct fm10k_device_info*
+fm10k_get_device_info(struct fm10k_hw *hw)
+{
+ unsigned int i;
+ struct fm10k_device_info *info;
+ uint16_t pci_vendor = hw->vendor_id;
+ uint16_t pci_device = hw->device_id;
+ uint16_t pci_subvendor = hw->subsystem_vendor_id;
+ uint16_t pci_subdevice = hw->subsystem_device_id;
+
+ if (pci_vendor != FM10K_SW_VENDOR_ID_INTEL ||
+ pci_device != FM10K_SW_DEV_ID_FM10K)
+ return (NULL);
+
+ for (i = 0;
+ i < sizeof(fm10k_device_table) /
+ sizeof(fm10k_device_table[0]);
+ i++) {
+ info = &fm10k_device_table[i];
+ if (pci_subvendor == info->subvendor &&
+ pci_subdevice == info->subdevice) {
+ return info;
+ }
+ }
+
+ return NULL;
+}
+
+
#define fm10k_udelay usec_delay
typedef int eth_fm10k_dev_init_half_func(struct fm10k_hw *hw);
@@ -312,15 +461,6 @@ struct fm10k_flow_list *
void fm10k_switch_dpdk_tx_queue_num_set(struct fm10k_hw *hw, uint8_t num);
void fm10k_switch_dpdk_rx_queue_num_set(struct fm10k_hw *hw, uint8_t num);
-uint32_t fm10k_switch_pf_logical_get(uint8_t pf_no);
-uint32_t fm10k_switch_epl_logical_get(uint8_t epl_no);
-uint32_t fm10k_switch_vf_glort_get(uint8_t vf_no);
-uint32_t fm10k_switch_pf_glort_get(uint8_t pf_no);
-uint32_t fm10k_switch_pfs_glort_get(uint8_t pf1, uint8_t pf2);
-uint32_t fm10k_switch_epl_glort_get(uint8_t epl_no);
-uint32_t fm10k_switch_multi_glort_get(uint8_t pf1, uint8_t pf2,
- uint16_t vlan1, uint16_t vlan2, bool *p_new);
-
int fm10k_switch_mirror_set(struct fm10k_hw *hw, u16 dest_port, u16 vlan);
int fm10k_switch_mirror_reset(struct fm10k_hw *hw);