[PATCH 17/52] mips: octeon: Add cvmx-helper-pki.c
Stefan Roese
sr at denx.de
Wed Mar 30 12:06:53 CEST 2022
From: Aaron Williams <awilliams at marvell.com>
Import cvmx-helper-pki.c from 2013 U-Boot. It will be used by the later
added drivers to support networking on the MIPS Octeon II / III
platforms.
Signed-off-by: Aaron Williams <awilliams at marvell.com>
Signed-off-by: Stefan Roese <sr at denx.de>
---
arch/mips/mach-octeon/cvmx-helper-pki.c | 2156 +++++++++++++++++++++++
1 file changed, 2156 insertions(+)
create mode 100644 arch/mips/mach-octeon/cvmx-helper-pki.c
diff --git a/arch/mips/mach-octeon/cvmx-helper-pki.c b/arch/mips/mach-octeon/cvmx-helper-pki.c
new file mode 100644
index 000000000000..d68c7dac0087
--- /dev/null
+++ b/arch/mips/mach-octeon/cvmx-helper-pki.c
@@ -0,0 +1,2156 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018-2022 Marvell International Ltd.
+ *
+ * PKI helper functions.
+ */
+
+#include <time.h>
+#include <log.h>
+#include <linux/delay.h>
+
+#include <mach/cvmx-regs.h>
+#include <mach/cvmx-csr.h>
+#include <mach/cvmx-bootmem.h>
+#include <mach/octeon-model.h>
+#include <mach/cvmx-fuse.h>
+#include <mach/octeon-feature.h>
+#include <mach/cvmx-qlm.h>
+#include <mach/octeon_qlm.h>
+#include <mach/cvmx-pcie.h>
+#include <mach/cvmx-coremask.h>
+
+#include <mach/cvmx-agl-defs.h>
+#include <mach/cvmx-bgxx-defs.h>
+#include <mach/cvmx-ciu-defs.h>
+#include <mach/cvmx-gmxx-defs.h>
+#include <mach/cvmx-gserx-defs.h>
+#include <mach/cvmx-ilk-defs.h>
+#include <mach/cvmx-ipd-defs.h>
+#include <mach/cvmx-pexp-defs.h>
+#include <mach/cvmx-pcsx-defs.h>
+#include <mach/cvmx-pcsxx-defs.h>
+#include <mach/cvmx-pki-defs.h>
+#include <mach/cvmx-pko-defs.h>
+#include <mach/cvmx-sli-defs.h>
+#include <mach/cvmx-xcv-defs.h>
+
+#include <mach/cvmx-hwpko.h>
+#include <mach/cvmx-ilk.h>
+#include <mach/cvmx-pki.h>
+
+#include <mach/cvmx-helper.h>
+#include <mach/cvmx-helper-board.h>
+#include <mach/cvmx-helper-cfg.h>
+#include <mach/cvmx-helper-pki.h>
+
+#include <mach/cvmx-global-resources.h>
+#include <mach/cvmx-pko-internal-ports-range.h>
+#include <mach/cvmx-ilk.h>
+#include <mach/cvmx-pip.h>
+
+static int pki_helper_debug;
+
+bool cvmx_pki_dflt_init[CVMX_MAX_NODES] = { [0 ... CVMX_MAX_NODES - 1] = 1 };
+
+static bool cvmx_pki_dflt_bp_en[CVMX_MAX_NODES] = { [0 ... CVMX_MAX_NODES - 1] =
+ true };
+static struct cvmx_pki_cluster_grp_config pki_dflt_clgrp[CVMX_MAX_NODES] = {
+ { 0, 0xf },
+ { 0, 0xf }
+};
+
+struct cvmx_pki_pool_config pki_dflt_pool[CVMX_MAX_NODES] = {
+ [0 ... CVMX_MAX_NODES -
+ 1] = { .pool_num = -1, .buffer_size = 2048, .buffer_count = 0 }
+};
+
+struct cvmx_pki_aura_config pki_dflt_aura[CVMX_MAX_NODES] = {
+ [0 ... CVMX_MAX_NODES -
+ 1] = { .aura_num = 0, .pool_num = -1, .buffer_count = 0 }
+};
+
+struct cvmx_pki_style_config pki_dflt_style[CVMX_MAX_NODES] = {
+ [0 ... CVMX_MAX_NODES - 1] = { .parm_cfg = { .lenerr_en = 1,
+ .maxerr_en = 1,
+ .minerr_en = 1,
+ .fcs_strip = 1,
+ .fcs_chk = 1,
+ .first_skip = 40,
+ .mbuff_size = 2048 } }
+};
+
+struct cvmx_pki_sso_grp_config pki_dflt_sso_grp[CVMX_MAX_NODES];
+struct cvmx_pki_qpg_config pki_dflt_qpg[CVMX_MAX_NODES];
+struct cvmx_pki_pkind_config pki_dflt_pkind[CVMX_MAX_NODES];
+u64 pkind_style_map[CVMX_MAX_NODES][CVMX_PKI_NUM_PKIND] = {
+ [0 ... CVMX_MAX_NODES -
+ 1] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 }
+};
+
+/* To store the qos watcher values before they are written to pcam when watcher is enabled
+There is no cvmx-pip.c file exist so it ended up here */
+struct cvmx_pki_legacy_qos_watcher qos_watcher[8];
+u64 pcam_dmach[CVMX_PKI_NUM_PCAM_ENTRY] = { -1 };
+u64 pcam_dmacl[CVMX_PKI_NUM_PCAM_ENTRY] = { -1 };
+
+/** @INTERNAL
+ * This function setsup default ltype map
+ * @param node node number
+ */
+void __cvmx_helper_pki_set_dflt_ltype_map(int node)
+{
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_NONE,
+ CVMX_PKI_BELTYPE_NONE);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_ENET,
+ CVMX_PKI_BELTYPE_MISC);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_VLAN,
+ CVMX_PKI_BELTYPE_MISC);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_SNAP_PAYLD,
+ CVMX_PKI_BELTYPE_MISC);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_ARP,
+ CVMX_PKI_BELTYPE_MISC);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_RARP,
+ CVMX_PKI_BELTYPE_MISC);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_IP4,
+ CVMX_PKI_BELTYPE_IP4);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_IP4_OPT,
+ CVMX_PKI_BELTYPE_IP4);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_IP6,
+ CVMX_PKI_BELTYPE_IP6);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_IP6_OPT,
+ CVMX_PKI_BELTYPE_IP6);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_IPSEC_ESP,
+ CVMX_PKI_BELTYPE_MISC);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_IPFRAG,
+ CVMX_PKI_BELTYPE_MISC);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_IPCOMP,
+ CVMX_PKI_BELTYPE_MISC);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_TCP,
+ CVMX_PKI_BELTYPE_TCP);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_UDP,
+ CVMX_PKI_BELTYPE_UDP);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_SCTP,
+ CVMX_PKI_BELTYPE_SCTP);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_UDP_VXLAN,
+ CVMX_PKI_BELTYPE_UDP);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_GRE,
+ CVMX_PKI_BELTYPE_MISC);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_NVGRE,
+ CVMX_PKI_BELTYPE_MISC);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_GTP,
+ CVMX_PKI_BELTYPE_MISC);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_SW28,
+ CVMX_PKI_BELTYPE_MISC);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_SW29,
+ CVMX_PKI_BELTYPE_MISC);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_SW30,
+ CVMX_PKI_BELTYPE_MISC);
+ cvmx_pki_write_ltype_map(node, CVMX_PKI_LTYPE_E_SW31,
+ CVMX_PKI_BELTYPE_MISC);
+}
+
+/** @INTERNAL
+ * This function installs the default VLAN entries to identify
+ * the VLAN and set WQE[vv], WQE[vs] if VLAN is found. In 78XX
+ * hardware (PKI) is not hardwired to recognize any 802.1Q VLAN
+ * Ethertypes
+ *
+ * @param node node number
+ */
+int __cvmx_helper_pki_install_dflt_vlan(int node)
+{
+ struct cvmx_pki_pcam_input pcam_input;
+ struct cvmx_pki_pcam_action pcam_action;
+ enum cvmx_pki_term field;
+ int index;
+ int bank;
+ u64 cl_mask = CVMX_PKI_CLUSTER_ALL;
+
+ memset(&pcam_input, 0, sizeof(pcam_input));
+ memset(&pcam_action, 0, sizeof(pcam_action));
+
+ if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X)) {
+ /* PKI-20858 */
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ union cvmx_pki_clx_ecc_ctl ecc_ctl;
+
+ ecc_ctl.u64 =
+ csr_rd_node(node, CVMX_PKI_CLX_ECC_CTL(i));
+ ecc_ctl.s.pcam_en = 0;
+ ecc_ctl.s.pcam0_cdis = 1;
+ ecc_ctl.s.pcam1_cdis = 1;
+ csr_wr_node(node, CVMX_PKI_CLX_ECC_CTL(i), ecc_ctl.u64);
+ }
+ }
+
+ for (field = CVMX_PKI_PCAM_TERM_ETHTYPE0;
+ field < CVMX_PKI_PCAM_TERM_ETHTYPE2; field++) {
+ bank = field & 0x01;
+
+ index = cvmx_pki_pcam_entry_alloc(
+ node, CVMX_PKI_FIND_AVAL_ENTRY, bank, cl_mask);
+ if (index < 0) {
+ debug("ERROR: Allocating pcam entry node=%d bank=%d\n",
+ node, bank);
+ return -1;
+ }
+ pcam_input.style = 0;
+ pcam_input.style_mask = 0;
+ pcam_input.field = field;
+ pcam_input.field_mask = 0xfd;
+ pcam_input.data = 0x81000000;
+ pcam_input.data_mask = 0xffff0000;
+ pcam_action.parse_mode_chg = CVMX_PKI_PARSE_NO_CHG;
+ pcam_action.layer_type_set = CVMX_PKI_LTYPE_E_VLAN;
+ pcam_action.style_add = 0;
+ pcam_action.pointer_advance = 4;
+ cvmx_pki_pcam_write_entry(
+ node, index, cl_mask, pcam_input,
+ pcam_action); /*cluster_mask in pass2*/
+
+ index = cvmx_pki_pcam_entry_alloc(
+ node, CVMX_PKI_FIND_AVAL_ENTRY, bank, cl_mask);
+ if (index < 0) {
+ debug("ERROR: Allocating pcam entry node=%d bank=%d\n",
+ node, bank);
+ return -1;
+ }
+ pcam_input.data = 0x88a80000;
+ cvmx_pki_pcam_write_entry(node, index, cl_mask, pcam_input,
+ pcam_action);
+
+ index = cvmx_pki_pcam_entry_alloc(
+ node, CVMX_PKI_FIND_AVAL_ENTRY, bank, cl_mask);
+ if (index < 0) {
+ debug("ERROR: Allocating pcam entry node=%d bank=%d\n",
+ node, bank);
+ return -1;
+ }
+ pcam_input.data = 0x92000000;
+ cvmx_pki_pcam_write_entry(
+ node, index, cl_mask, pcam_input,
+ pcam_action); /* cluster_mask in pass2*/
+
+ index = cvmx_pki_pcam_entry_alloc(
+ node, CVMX_PKI_FIND_AVAL_ENTRY, bank, cl_mask);
+ if (index < 0) {
+ debug("ERROR: Allocating pcam entry node=%d bank=%d\n",
+ node, bank);
+ return -1;
+ }
+ pcam_input.data = 0x91000000;
+ cvmx_pki_pcam_write_entry(node, index, cl_mask, pcam_input,
+ pcam_action);
+ }
+ return 0;
+}
+
+static int __cvmx_helper_setup_pki_cluster_groups(int node)
+{
+ u64 cl_mask;
+ int cl_group;
+
+ cl_group =
+ cvmx_pki_cluster_grp_alloc(node, pki_dflt_clgrp[node].grp_num);
+ if (cl_group == CVMX_RESOURCE_ALLOC_FAILED)
+ return -1;
+ else if (cl_group == CVMX_RESOURCE_ALREADY_RESERVED) {
+ if (pki_dflt_clgrp[node].grp_num == -1)
+ return -1;
+ else
+ return 0; /* cluster already configured, share it */
+ }
+ cl_mask = pki_dflt_clgrp[node].cluster_mask;
+ if (pki_helper_debug)
+ debug("pki-helper: setup pki cluster grp %d with cl_mask 0x%llx\n",
+ (int)cl_group, (unsigned long long)cl_mask);
+ cvmx_pki_attach_cluster_to_group(node, cl_group, cl_mask);
+ return 0;
+}
+
+/**
+ * This function sets up pools/auras to be used by PKI
+ * @param node node number
+ */
+int __cvmx_helper_pki_setup_sso_groups(int node)
+{
+ struct cvmx_coremask core_mask = CVMX_COREMASK_EMPTY;
+ cvmx_xgrp_t xgrp;
+ int grp;
+ int priority;
+ int weight;
+ int affinity;
+ u64 modify_mask;
+ u8 core_mask_set;
+
+ /* try to reserve sso groups and configure them if they are not configured */
+ grp = cvmx_sso_reserve_group_range(node, &pki_dflt_sso_grp[node].group,
+ 1);
+ if (grp == CVMX_RESOURCE_ALLOC_FAILED)
+ return -1;
+ else if (grp == CVMX_RESOURCE_ALREADY_RESERVED)
+ return 0; /* sso group already configured, share it */
+
+ xgrp.xgrp = grp;
+ priority = pki_dflt_sso_grp[node].priority;
+ weight = pki_dflt_sso_grp[node].weight;
+ affinity = pki_dflt_sso_grp[node].affinity;
+ core_mask_set = pki_dflt_sso_grp[node].core_mask_set;
+ cvmx_coremask_set64_node(&core_mask, node,
+ pki_dflt_sso_grp[node].core_mask);
+ modify_mask = CVMX_SSO_MODIFY_GROUP_PRIORITY |
+ CVMX_SSO_MODIFY_GROUP_WEIGHT |
+ CVMX_SSO_MODIFY_GROUP_AFFINITY;
+ if (pki_helper_debug)
+ debug("pki-helper: set sso grp %d with priority %d weight %d core_mask 0x%llx\n",
+ grp, priority, weight,
+ (unsigned long long)pki_dflt_sso_grp[node].core_mask);
+ cvmx_sso_set_group_priority(node, xgrp, priority, weight, affinity,
+ modify_mask);
+ cvmx_sso_set_group_core_affinity(xgrp, &core_mask, core_mask_set);
+ return 0;
+}
+
+/**
+ * This function sets up pools/auras to be used by PKI
+ * @param node node number
+ */
+static int __cvmx_helper_pki_setup_fpa_pools(int node)
+{
+ u64 buffer_count;
+ u64 buffer_size;
+
+ if (__cvmx_fpa3_aura_valid(pki_dflt_aura[node].aura))
+ return 0; /* aura already configured, share it */
+
+ buffer_count = pki_dflt_pool[node].buffer_count;
+ buffer_size = pki_dflt_pool[node].buffer_size;
+
+ if (buffer_count != 0) {
+ pki_dflt_pool[node].pool = cvmx_fpa3_setup_fill_pool(
+ node, pki_dflt_pool[node].pool_num, "PKI POOL DFLT",
+ buffer_size, buffer_count, NULL);
+ if (!__cvmx_fpa3_pool_valid(pki_dflt_pool[node].pool)) {
+ cvmx_printf("ERROR: %s: Failed to allocate pool %d\n",
+ __func__, pki_dflt_pool[node].pool_num);
+ return -1;
+ }
+ pki_dflt_pool[node].pool_num = pki_dflt_pool[node].pool.lpool;
+
+ if (pki_helper_debug)
+ debug("%s pool %d with buffer size %d cnt %d\n",
+ __func__, pki_dflt_pool[node].pool_num,
+ (int)buffer_size, (int)buffer_count);
+
+ pki_dflt_aura[node].pool_num = pki_dflt_pool[node].pool_num;
+ pki_dflt_aura[node].pool = pki_dflt_pool[node].pool;
+ }
+
+ buffer_count = pki_dflt_aura[node].buffer_count;
+
+ if (buffer_count != 0) {
+ pki_dflt_aura[node].aura = cvmx_fpa3_set_aura_for_pool(
+ pki_dflt_aura[node].pool, pki_dflt_aura[node].aura_num,
+ "PKI DFLT AURA", buffer_size, buffer_count);
+
+ if (!__cvmx_fpa3_aura_valid(pki_dflt_aura[node].aura)) {
+ debug("ERROR: %sL Failed to allocate aura %d\n",
+ __func__, pki_dflt_aura[node].aura_num);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int __cvmx_helper_setup_pki_qpg_table(int node)
+{
+ int offset;
+
+ offset = cvmx_pki_qpg_entry_alloc(node, pki_dflt_qpg[node].qpg_base, 1);
+ if (offset == CVMX_RESOURCE_ALLOC_FAILED)
+ return -1;
+ else if (offset == CVMX_RESOURCE_ALREADY_RESERVED)
+ return 0; /* share the qpg table entry */
+ if (pki_helper_debug)
+ debug("pki-helper: set qpg entry at offset %d with port add %d aura %d grp_ok %d grp_bad %d\n",
+ offset, pki_dflt_qpg[node].port_add,
+ pki_dflt_qpg[node].aura_num, pki_dflt_qpg[node].grp_ok,
+ pki_dflt_qpg[node].grp_bad);
+ cvmx_pki_write_qpg_entry(node, offset, &pki_dflt_qpg[node]);
+ return 0;
+}
+
+int __cvmx_helper_pki_port_setup(int node, int ipd_port)
+{
+ int xiface, index;
+ int pknd, style_num;
+ int rs;
+ struct cvmx_pki_pkind_config pkind_cfg;
+
+ if (!cvmx_pki_dflt_init[node])
+ return 0;
+ xiface = cvmx_helper_get_interface_num(ipd_port);
+ index = cvmx_helper_get_interface_index_num(ipd_port);
+
+ pknd = cvmx_helper_get_pknd(xiface, index);
+ style_num = pkind_style_map[node][pknd];
+
+ /* try to reserve the style, if it is not configured already, reserve
+ and configure it */
+ rs = cvmx_pki_style_alloc(node, style_num);
+ if (rs < 0) {
+ if (rs == CVMX_RESOURCE_ALLOC_FAILED)
+ return -1;
+ } else {
+ if (pki_helper_debug)
+ debug("pki-helper: set style %d with default parameters\n",
+ style_num);
+ pkind_style_map[node][pknd] = style_num;
+ /* configure style with default parameters */
+ cvmx_pki_write_style_config(node, style_num,
+ CVMX_PKI_CLUSTER_ALL,
+ &pki_dflt_style[node]);
+ }
+ if (pki_helper_debug)
+ debug("pki-helper: set pkind %d with initial style %d\n", pknd,
+ style_num);
+ /* write pkind configuration */
+ pkind_cfg = pki_dflt_pkind[node];
+ pkind_cfg.initial_style = style_num;
+ cvmx_pki_write_pkind_config(node, pknd, &pkind_cfg);
+ return 0;
+}
+
+int __cvmx_helper_pki_global_setup(int node)
+{
+ __cvmx_helper_pki_set_dflt_ltype_map(node);
+ if (!cvmx_pki_dflt_init[node])
+ return 0;
+ /* Setup the packet pools*/
+ __cvmx_helper_pki_setup_fpa_pools(node);
+ /*set up default cluster*/
+ __cvmx_helper_setup_pki_cluster_groups(node);
+ //__cvmx_helper_pki_setup_sso_groups(node);
+ __cvmx_helper_setup_pki_qpg_table(node);
+ /*
+ * errata PKI-19103 backward compat has only 1 aura
+ * no head line blocking
+ */
+ if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X)) {
+ cvmx_pki_buf_ctl_t buf_ctl;
+
+ buf_ctl.u64 = csr_rd_node(node, CVMX_PKI_BUF_CTL);
+ buf_ctl.s.fpa_wait = 1;
+ csr_wr_node(node, CVMX_PKI_BUF_CTL, buf_ctl.u64);
+ }
+ return 0;
+}
+
+void cvmx_helper_pki_set_dflt_pool(int node, int pool, int buffer_size,
+ int buffer_count)
+{
+ if (pool == 0)
+ pool = -1;
+ pki_dflt_pool[node].pool_num = pool;
+ pki_dflt_pool[node].buffer_size = buffer_size;
+ pki_dflt_pool[node].buffer_count = buffer_count;
+}
+
+void cvmx_helper_pki_set_dflt_aura(int node, int aura, int pool,
+ int buffer_count)
+{
+ pki_dflt_aura[node].aura_num = aura;
+ pki_dflt_aura[node].pool_num = pool;
+ pki_dflt_aura[node].buffer_count = buffer_count;
+}
+
+void cvmx_helper_pki_set_dflt_pool_buffer(int node, int buffer_count)
+{
+ pki_dflt_pool[node].buffer_count = buffer_count;
+}
+
+void cvmx_helper_pki_set_dflt_aura_buffer(int node, int buffer_count)
+{
+ pki_dflt_aura[node].buffer_count = buffer_count;
+}
+
+void cvmx_helper_pki_set_dflt_style(int node,
+ struct cvmx_pki_style_config *style_cfg)
+{
+ pki_dflt_style[node] = *style_cfg;
+}
+
+void cvmx_helper_pki_get_dflt_style(int node,
+ struct cvmx_pki_style_config *style_cfg)
+{
+ *style_cfg = pki_dflt_style[node];
+}
+
+void cvmx_helper_pki_set_dflt_qpg(int node, struct cvmx_pki_qpg_config *qpg_cfg)
+{
+ pki_dflt_qpg[node] = *qpg_cfg;
+}
+
+void cvmx_helper_pki_get_dflt_qpg(int node, struct cvmx_pki_qpg_config *qpg_cfg)
+{
+ *qpg_cfg = pki_dflt_qpg[node];
+}
+
+void cvmx_helper_pki_set_dflt_pkind_map(int node, int pkind, int style)
+{
+ pkind_style_map[node][pkind] = style;
+}
+
+void cvmx_helper_pki_no_dflt_init(int node)
+{
+ cvmx_pki_dflt_init[node] = 0;
+}
+
+void cvmx_helper_pki_set_dflt_bp_en(int node, bool bp_en)
+{
+ cvmx_pki_dflt_bp_en[node] = bp_en;
+}
+
+/**
+ * This function Enabled the PKI hardware to
+ * start accepting/processing packets.
+ *
+ * @param node node number
+ */
+void cvmx_helper_pki_enable(int node)
+{
+ if (pki_helper_debug)
+ debug("enable PKI on node %d\n", node);
+ __cvmx_helper_pki_install_dflt_vlan(node);
+ cvmx_pki_setup_clusters(node);
+ if (cvmx_pki_dflt_bp_en[node])
+ cvmx_pki_enable_backpressure(node);
+ cvmx_pki_parse_enable(node, 0);
+ cvmx_pki_enable(node);
+}
+
+/**
+ * This function frees up PKI resources consumed by that port.
+ * This function should only be called if port resources
+ * (fpa pools aura, style qpg entry pcam entry etc.) are not shared
+ * @param ipd_port ipd port number for which resources need to
+ * be freed.
+ */
+int cvmx_helper_pki_port_shutdown(int ipd_port)
+{
+ /* remove pcam entries */
+ /* implemet if needed */
+ /* __cvmx_pki_port_rsrc_free(node); */
+ return 0;
+}
+
+/**
+ * This function shuts down complete PKI hardware
+ * and software resources.
+ * @param node node number where PKI needs to shutdown.
+ */
+void cvmx_helper_pki_shutdown(int node)
+{
+ int i, k;
+ /* remove pcam entries */
+ /* Disable PKI */
+ cvmx_pki_disable(node);
+ /* Free all prefetched buffers */
+ __cvmx_pki_free_ptr(node);
+ /* Reset PKI */
+ cvmx_pki_reset(node);
+ /* Free all the allocated PKI resources
+ except fpa pools & aura which will be done in fpa block */
+ __cvmx_pki_global_rsrc_free(node);
+ /* Setup some configuration registers to the reset state.*/
+ for (i = 0; i < CVMX_PKI_NUM_PKIND; i++) {
+ for (k = 0; k < (int)CVMX_PKI_NUM_CLUSTER; k++) {
+ csr_wr_node(node, CVMX_PKI_CLX_PKINDX_CFG(i, k), 0);
+ csr_wr_node(node, CVMX_PKI_CLX_PKINDX_STYLE(i, k), 0);
+ csr_wr_node(node, CVMX_PKI_CLX_PKINDX_SKIP(i, k), 0);
+ csr_wr_node(node, CVMX_PKI_CLX_PKINDX_L2_CUSTOM(i, k),
+ 0);
+ csr_wr_node(node, CVMX_PKI_CLX_PKINDX_LG_CUSTOM(i, k),
+ 0);
+ }
+ csr_wr_node(node, CVMX_PKI_PKINDX_ICGSEL(k), 0);
+ }
+ for (i = 0; i < CVMX_PKI_NUM_FINAL_STYLE; i++) {
+ for (k = 0; k < (int)CVMX_PKI_NUM_CLUSTER; k++) {
+ csr_wr_node(node, CVMX_PKI_CLX_STYLEX_CFG(i, k), 0);
+ csr_wr_node(node, CVMX_PKI_CLX_STYLEX_CFG2(i, k), 0);
+ csr_wr_node(node, CVMX_PKI_CLX_STYLEX_ALG(i, k), 0);
+ }
+ csr_wr_node(node, CVMX_PKI_STYLEX_BUF(k), (0x5 << 22) | 0x20);
+ }
+}
+
+/**
+ * This function calculates how mant qpf entries will be needed for
+ * a particular QOS.
+ * @param qpg_qos qos value for which entries need to be calculated.
+ */
+int cvmx_helper_pki_get_num_qpg_entry(enum cvmx_pki_qpg_qos qpg_qos)
+{
+ if (qpg_qos == CVMX_PKI_QPG_QOS_NONE)
+ return 1;
+ else if (qpg_qos == CVMX_PKI_QPG_QOS_VLAN ||
+ qpg_qos == CVMX_PKI_QPG_QOS_MPLS)
+ return 8;
+ else if (qpg_qos == CVMX_PKI_QPG_QOS_DSA_SRC)
+ return 32;
+ else if (qpg_qos == CVMX_PKI_QPG_QOS_DIFFSERV ||
+ qpg_qos == CVMX_PKI_QPG_QOS_HIGIG)
+ return 64;
+ else {
+ debug("ERROR: unrecognized qpg_qos = %d", qpg_qos);
+ return 0;
+ }
+}
+
+/**
+ * This function setups the qos table by allocating qpg entry and writing
+ * the provided parameters to that entry (offset).
+ * @param node node number.
+ * @param qpg_cfg pointer to struct containing qpg configuration
+ */
+int cvmx_helper_pki_set_qpg_entry(int node, struct cvmx_pki_qpg_config *qpg_cfg)
+{
+ int offset;
+
+ offset = cvmx_pki_qpg_entry_alloc(node, qpg_cfg->qpg_base, 1);
+ if (pki_helper_debug)
+ debug("pki-helper:set qpg entry at offset %d\n", offset);
+ if (offset == CVMX_RESOURCE_ALREADY_RESERVED) {
+ debug("INFO:setup_qpg_table: offset %d already reserved\n",
+ qpg_cfg->qpg_base);
+ return CVMX_RESOURCE_ALREADY_RESERVED;
+ } else if (offset == CVMX_RESOURCE_ALLOC_FAILED) {
+ debug("ERROR:setup_qpg_table: no more entries available\n");
+ return CVMX_RESOURCE_ALLOC_FAILED;
+ }
+ qpg_cfg->qpg_base = offset;
+ cvmx_pki_write_qpg_entry(node, offset, qpg_cfg);
+ return offset;
+}
+
+/**
+ * This function sets up aura QOS for RED, backpressure and tail-drop.
+ *
+ * @param node node number.
+ * @param aura aura to configure.
+ * @param ena_red enable RED based on [DROP] and [PASS] levels
+ * 1: enable 0:disable
+ * @param pass_thresh pass threshold for RED.
+ * @param drop_thresh drop threshold for RED
+ * @param ena_bp enable backpressure based on [BP] level.
+ * 1:enable 0:disable
+ * @param bp_thresh backpressure threshold.
+ * @param ena_drop enable tail drop.
+ * 1:enable 0:disable
+ * @return Zero on success. Negative on failure
+ * @note the 'node' and 'aura' arguments may be combined in the future
+ * to use a compaund cvmx_fpa3_gaura_t structure argument.
+ */
+int cvmx_helper_setup_aura_qos(int node, int aura, bool ena_red, bool ena_drop,
+ u64 pass_thresh, u64 drop_thresh, bool ena_bp,
+ u64 bp_thresh)
+{
+ cvmx_fpa3_gaura_t gaura;
+
+ gaura = __cvmx_fpa3_gaura(node, aura);
+
+ ena_red = ena_red | ena_drop;
+ cvmx_fpa3_setup_aura_qos(gaura, ena_red, pass_thresh, drop_thresh,
+ ena_bp, bp_thresh);
+ cvmx_pki_enable_aura_qos(node, aura, ena_red, ena_drop, ena_bp);
+ return 0;
+}
+
+/**
+ * This function maps specified bpid to all the auras from which it can receive bp and
+ * then maps that bpid to all the channels, that bpid can asserrt bp on.
+ *
+ * @param node node number.
+ * @param aura aura number which will back pressure specified bpid.
+ * @param bpid bpid to map.
+ * @param chl_map array of channels to map to that bpid.
+ * @param chl_cnt number of channel/ports to map to that bpid.
+ * @return Zero on success. Negative on failure
+ */
+int cvmx_helper_pki_map_aura_chl_bpid(int node, uint16_t aura, uint16_t bpid,
+ u16 chl_map[], uint16_t chl_cnt)
+{
+ u16 channel;
+
+ if (aura >= CVMX_PKI_NUM_AURA) {
+ debug("ERROR: aura %d is > supported in hw\n", aura);
+ return -1;
+ }
+ if (bpid >= CVMX_PKI_NUM_BPID) {
+ debug("ERROR: bpid %d is > supported in hw\n", bpid);
+ return -1;
+ }
+ cvmx_pki_write_aura_bpid(node, aura, bpid);
+ while (chl_cnt--) {
+ channel = chl_map[chl_cnt];
+ if (channel >= CVMX_PKI_NUM_CHANNEL) {
+ debug("ERROR: channel %d is > supported in hw\n",
+ channel);
+ return -1;
+ }
+ cvmx_pki_write_channel_bpid(node, channel, bpid);
+ }
+ return 0;
+}
+
+/** @INTERNAL
+ * This function returns the value of port shift required
+ * if all the ports on that interface are using same style and
+ * configuring qpg_qos != NONE
+ */
+int __cvmx_helper_pki_port_shift(int xiface, enum cvmx_pki_qpg_qos qpg_qos)
+{
+ u8 num_qos;
+ cvmx_helper_interface_mode_t mode =
+ cvmx_helper_interface_get_mode(xiface);
+
+ num_qos = cvmx_helper_pki_get_num_qpg_entry(qpg_qos);
+ if ((mode != CVMX_HELPER_INTERFACE_MODE_SGMII) &&
+ (mode != CVMX_HELPER_INTERFACE_MODE_NPI) &&
+ (mode != CVMX_HELPER_INTERFACE_MODE_LOOP)) {
+ return ffs(num_qos) - 1;
+ } else if (num_qos <= 16)
+ return 0;
+ else if (num_qos <= 32)
+ return 1;
+ else
+ return 2;
+}
+
+int __cvmx_helper_pki_qos_rsrcs(int node, struct cvmx_pki_qos_schd *qossch)
+{
+ int rs;
+
+ /* Reserve pool resources */
+ if (qossch->pool_per_qos && qossch->pool_num < 0) {
+ if (pki_helper_debug)
+ debug("pki-helper:qos-rsrc: setup pool %d buff_size %d blocks %d\n",
+ qossch->pool_num, (int)qossch->pool_buff_size,
+ (int)qossch->pool_max_buff);
+
+ qossch->_pool = cvmx_fpa3_setup_fill_pool(
+ node, qossch->pool_num, qossch->pool_name,
+ qossch->pool_buff_size, qossch->pool_max_buff, NULL);
+
+ if (!__cvmx_fpa3_pool_valid(qossch->_pool)) {
+ cvmx_printf("ERROR: %s POOL %d init failed\n", __func__,
+ qossch->pool_num);
+ return -1;
+ }
+
+ qossch->pool_num = qossch->_pool.lpool;
+ if (pki_helper_debug)
+ debug("pool alloced is %d\n", qossch->pool_num);
+ }
+ /* Reserve aura resources */
+ if (qossch->aura_per_qos && qossch->aura_num < 0) {
+ if (pki_helper_debug)
+ debug("pki-helper:qos-rsrc: setup aura %d pool %d blocks %d\n",
+ qossch->aura_num, qossch->pool_num,
+ (int)qossch->aura_buff_cnt);
+
+ qossch->_aura = cvmx_fpa3_set_aura_for_pool(
+ qossch->_pool, qossch->aura_num, qossch->aura_name,
+ qossch->pool_buff_size, qossch->aura_buff_cnt);
+
+ if (!__cvmx_fpa3_aura_valid(qossch->_aura)) {
+ cvmx_printf("ERROR: %s AURA %d init failed\n", __func__,
+ qossch->aura_num);
+ return -1;
+ }
+
+ qossch->aura_num = qossch->_aura.laura;
+ if (pki_helper_debug)
+ debug("aura alloced is %d\n", qossch->aura_num);
+ }
+ /* Reserve sso group resources */
+ /* Find which node work needs to be schedules vinita_to_do to extract node*/
+ if (qossch->sso_grp_per_qos && qossch->sso_grp < 0) {
+ //unsigned grp_node;
+ //grp_node = (abs)(qossch->sso_grp + CVMX_PKI_FIND_AVAILABLE_RSRC);
+ rs = cvmx_sso_reserve_group(node);
+ if (rs < 0) {
+ debug("pki-helper:qos-rsrc: ERROR: sso grp not available\n");
+ return rs;
+ }
+ qossch->sso_grp = rs | (node << 8);
+ if (pki_helper_debug)
+ debug("pki-helper:qos-rsrc: sso grp alloced is %d\n",
+ qossch->sso_grp);
+ }
+ return 0;
+}
+
+int __cvmx_helper_pki_port_rsrcs(int node, struct cvmx_pki_prt_schd *prtsch)
+{
+ int rs;
+
+ /* Erratum 22557: Disable per-port allocation for CN78XX pass 1.X */
+ if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X)) {
+ static bool warned;
+
+ prtsch->pool_per_prt = 0;
+ if (!warned)
+ cvmx_printf(
+ "WARNING: %s: Ports configured in single-pool mode per erratum 22557.\n",
+ __func__);
+ warned = true;
+ }
+ /* Reserve pool resources */
+ if (prtsch->pool_per_prt && prtsch->pool_num < 0) {
+ if (pki_helper_debug)
+ debug("pki-helper:port-rsrc: setup pool %d buff_size %d blocks %d\n",
+ prtsch->pool_num, (int)prtsch->pool_buff_size,
+ (int)prtsch->pool_max_buff);
+
+ prtsch->_pool = cvmx_fpa3_setup_fill_pool(
+ node, prtsch->pool_num, prtsch->pool_name,
+ prtsch->pool_buff_size, prtsch->pool_max_buff, NULL);
+
+ if (!__cvmx_fpa3_pool_valid(prtsch->_pool)) {
+ cvmx_printf("ERROR: %s: POOL %d init failed\n",
+ __func__, prtsch->pool_num);
+ return -1;
+ }
+ prtsch->pool_num = prtsch->_pool.lpool;
+ if (pki_helper_debug)
+ debug("pool alloced is %d\n", prtsch->pool_num);
+ }
+ /* Reserve aura resources */
+ if (prtsch->aura_per_prt && prtsch->aura_num < 0) {
+ if (pki_helper_debug)
+ debug("pki-helper:port-rsrc; setup aura %d pool %d blocks %d\n",
+ prtsch->aura_num, prtsch->pool_num,
+ (int)prtsch->aura_buff_cnt);
+ prtsch->_aura = cvmx_fpa3_set_aura_for_pool(
+ prtsch->_pool, prtsch->aura_num, prtsch->aura_name,
+ prtsch->pool_buff_size, prtsch->aura_buff_cnt);
+
+ if (!__cvmx_fpa3_aura_valid(prtsch->_aura)) {
+ cvmx_printf("ERROR: %s: AURA %d init failed\n",
+ __func__, prtsch->aura_num);
+ return -1;
+ }
+ prtsch->aura_num = prtsch->_aura.laura;
+
+ if (pki_helper_debug)
+ debug("aura alloced is %d\n", prtsch->aura_num);
+ }
+ /* Reserve sso group resources , vinita_to_do to extract node*/
+ if (prtsch->sso_grp_per_prt && prtsch->sso_grp < 0) {
+ //unsigned grp_node;
+ //grp_node = (abs)(prtsch->sso_grp + CVMX_PKI_FIND_AVAILABLE_RSRC);
+ rs = cvmx_sso_reserve_group(node);
+ if (rs < 0) {
+ cvmx_printf("ERROR: %s: sso grp not available\n",
+ __func__);
+ return rs;
+ }
+ prtsch->sso_grp = rs | (node << 8);
+ if (pki_helper_debug)
+ debug("pki-helper:port-rsrc: sso grp alloced is %d\n",
+ prtsch->sso_grp);
+ }
+ return 0;
+}
+
+int __cvmx_helper_pki_intf_rsrcs(int node, struct cvmx_pki_intf_schd *intf)
+{
+ int rs;
+
+ if (intf->pool_per_intf && intf->pool_num < 0) {
+ if (pki_helper_debug)
+ debug("pki-helper:intf-rsrc: setup pool %d buff_size %d blocks %d\n",
+ intf->pool_num, (int)intf->pool_buff_size,
+ (int)intf->pool_max_buff);
+ intf->_pool = cvmx_fpa3_setup_fill_pool(
+ node, intf->pool_num, intf->pool_name,
+ intf->pool_buff_size, intf->pool_max_buff, NULL);
+
+ if (!__cvmx_fpa3_pool_valid(intf->_pool)) {
+ cvmx_printf("ERROR: %s: POOL %d init failed\n",
+ __func__, intf->pool_num);
+ return -1;
+ }
+ intf->pool_num = intf->_pool.lpool;
+
+ if (pki_helper_debug)
+ debug("pool alloced is %d\n", intf->pool_num);
+ }
+ if (intf->aura_per_intf && intf->aura_num < 0) {
+ if (pki_helper_debug)
+ debug("pki-helper:intf-rsrc: setup aura %d pool %d blocks %d\n",
+ intf->aura_num, intf->pool_num,
+ (int)intf->aura_buff_cnt);
+ intf->_aura = cvmx_fpa3_set_aura_for_pool(
+ intf->_pool, intf->aura_num, intf->aura_name,
+ intf->pool_buff_size, intf->aura_buff_cnt);
+
+ if (!__cvmx_fpa3_aura_valid(intf->_aura)) {
+ cvmx_printf("ERROR: %s: AURA %d init failed\n",
+ __func__, intf->aura_num);
+
+ return -1;
+ }
+
+ intf->aura_num = intf->_aura.laura;
+
+ if (pki_helper_debug)
+ debug("aura alloced is %d\n", intf->aura_num);
+ }
+ /* vinita_to_do to extract node */
+ if (intf->sso_grp_per_intf && intf->sso_grp < 0) {
+ //unsigned grp_node;
+ //grp_node = (abs)(intf->sso_grp + CVMX_PKI_FIND_AVAILABLE_RSRC);
+ rs = cvmx_sso_reserve_group(node);
+ if (rs < 0) {
+ cvmx_printf("ERROR: %s: sso grp not available\n",
+ __func__);
+ return rs;
+ }
+ intf->sso_grp = rs | (node << 8);
+ if (pki_helper_debug)
+ debug("pki-helper:intf-rsrc: sso grp alloced is %d\n",
+ intf->sso_grp);
+ }
+ return 0;
+}
+
+int __cvmx_helper_pki_set_intf_qpg(int node, int port, int qpg_base,
+ int num_entry,
+ struct cvmx_pki_intf_schd *intfsch)
+{
+ int offset;
+ int entry;
+ struct cvmx_pki_qpg_config qpg_cfg;
+
+ memset(&qpg_cfg, 0, sizeof(qpg_cfg));
+ if (pki_helper_debug)
+ debug("pki-helper:intf_qpg port %d qpg_base %d num_entry %d",
+ port, qpg_base, num_entry);
+ offset = cvmx_pki_qpg_entry_alloc(node, qpg_base, num_entry);
+ if (offset == CVMX_RESOURCE_ALREADY_RESERVED) {
+ debug("pki-helper: INFO: qpg entries will be shared\n");
+ return offset;
+ } else if (offset == CVMX_RESOURCE_ALLOC_FAILED) {
+ debug("pki-helper: ERROR: qpg entries not available\n");
+ return offset;
+ } else if (intfsch->qpg_base < 0) {
+ intfsch->qpg_base = offset;
+ }
+ if (pki_helper_debug)
+ debug("qpg_base allocated is %d\n", offset);
+ for (entry = 0; entry < num_entry; entry++) {
+ qpg_cfg.port_add = intfsch->prt_s[port].qos_s[entry].port_add;
+ qpg_cfg.aura_num = intfsch->prt_s[port].qos_s[entry].aura_num;
+ qpg_cfg.grp_ok = intfsch->prt_s[port].qos_s[entry].sso_grp;
+ qpg_cfg.grp_bad = intfsch->prt_s[port].qos_s[entry].sso_grp;
+ cvmx_pki_write_qpg_entry(node, (offset + entry), &qpg_cfg);
+ }
+ return offset;
+}
+
+/**
+ * This function sets up the global pool, aura and sso group
+ * resources which application can use between any interfaces
+ * and ports.
+ * @param node node number
+ * @param gblsch pointer to struct containing global
+ * scheduling parameters.
+ */
+int cvmx_helper_pki_set_gbl_schd(int node, struct cvmx_pki_global_schd *gblsch)
+{
+ int rs;
+
+ if (gblsch->setup_pool && gblsch->pool_num < 0) {
+ if (pki_helper_debug)
+ debug("%s: gbl setup global pool %d buff_size %d blocks %d\n",
+ __func__, gblsch->pool_num,
+ (int)gblsch->pool_buff_size,
+ (int)gblsch->pool_max_buff);
+
+ gblsch->_pool = cvmx_fpa3_setup_fill_pool(
+ node, gblsch->pool_num, gblsch->pool_name,
+ gblsch->pool_buff_size, gblsch->pool_max_buff, NULL);
+
+ if (!__cvmx_fpa3_pool_valid(gblsch->_pool)) {
+ cvmx_printf("ERROR: %s: POOL %u:%d unavailable\n",
+ __func__, node, gblsch->pool_num);
+ return -1;
+ }
+
+ gblsch->pool_num = gblsch->_pool.lpool;
+
+ if (pki_helper_debug)
+ debug("pool alloced is %d\n", gblsch->pool_num);
+ }
+ if (gblsch->setup_aura && gblsch->aura_num < 0) {
+ if (pki_helper_debug)
+ debug("%s: gbl setup global aura %d pool %d blocks %d\n",
+ __func__, gblsch->aura_num, gblsch->pool_num,
+ (int)gblsch->aura_buff_cnt);
+
+ gblsch->_aura = cvmx_fpa3_set_aura_for_pool(
+ gblsch->_pool, gblsch->aura_num, gblsch->aura_name,
+ gblsch->pool_buff_size, gblsch->aura_buff_cnt);
+
+ if (!__cvmx_fpa3_aura_valid(gblsch->_aura)) {
+ cvmx_printf("ERROR: %s: AURA %u:%d unavailable\n",
+ __func__, node, gblsch->aura_num);
+ return -1;
+ }
+
+ gblsch->aura_num = gblsch->_aura.laura;
+
+ if (pki_helper_debug)
+ debug("aura alloced is %d\n", gblsch->aura_num);
+ }
+ if (gblsch->setup_sso_grp && gblsch->sso_grp < 0) {
+ rs = cvmx_sso_reserve_group(node);
+ if (rs < 0) {
+ debug("pki-helper:gbl: ERROR: sso grp not available\n");
+ return rs;
+ }
+ gblsch->sso_grp = rs | (node << 8);
+ if (pki_helper_debug)
+ debug("pki-helper:gbl: sso grp alloced is %d\n",
+ gblsch->sso_grp);
+ }
+ return 0;
+}
+
+/**
+ * This function sets up scheduling parameters (pool, aura, sso group etc)
+ * of an ipd port.
+ * @param ipd_port ipd port number
+ * @param prtsch pointer to struct containing port's
+ * scheduling parameters.
+ */
+int cvmx_helper_pki_init_port(int ipd_port, struct cvmx_pki_prt_schd *prtsch)
+{
+ int num_qos;
+ int qos;
+ struct cvmx_pki_qpg_config qpg_cfg;
+ struct cvmx_pki_qos_schd *qossch;
+ struct cvmx_pki_style_config style_cfg;
+ struct cvmx_pki_pkind_config pknd_cfg;
+ int xiface = cvmx_helper_get_interface_num(ipd_port);
+ int pknd;
+ u16 mbuff_size;
+ int rs;
+
+ struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
+
+ num_qos = cvmx_helper_pki_get_num_qpg_entry(prtsch->qpg_qos);
+ mbuff_size = prtsch->pool_buff_size;
+ memset(&qpg_cfg, 0, sizeof(qpg_cfg));
+
+ /* Reserve port resources */
+ rs = __cvmx_helper_pki_port_rsrcs(xp.node, prtsch);
+ if (rs)
+ return rs;
+ /* Reserve qpg resources */
+ if (prtsch->qpg_base < 0) {
+ rs = cvmx_pki_qpg_entry_alloc(xp.node, prtsch->qpg_base,
+ num_qos);
+ if (rs < 0) {
+ debug("pki-helper:port%d:ERROR: qpg entries not available\n",
+ ipd_port);
+ return CVMX_RESOURCE_ALLOC_FAILED;
+ }
+ prtsch->qpg_base = rs;
+ if (pki_helper_debug)
+ debug("pki-helper:port-init: to port %d, qpg_base %d allocated\n",
+ ipd_port, prtsch->qpg_base);
+ }
+
+ if (prtsch->qpg_qos) {
+ for (qos = 0; qos < num_qos; qos++) {
+ qossch = &prtsch->qos_s[qos];
+ if (!qossch->pool_per_qos)
+ qossch->pool_num = prtsch->pool_num;
+ else if (qossch->pool_buff_size < mbuff_size)
+ mbuff_size = qossch->pool_buff_size;
+ if (!qossch->aura_per_qos)
+ qossch->aura_num = prtsch->aura_num;
+ if (!qossch->sso_grp_per_qos)
+ qossch->sso_grp = prtsch->sso_grp;
+
+ /* Reserve qos resources */
+ rs = __cvmx_helper_pki_qos_rsrcs(xp.node, qossch);
+ if (rs)
+ return rs;
+ qpg_cfg.port_add = qossch->port_add;
+ qpg_cfg.aura_num = qossch->aura_num;
+ qpg_cfg.grp_ok = qossch->sso_grp;
+ qpg_cfg.grp_bad = qossch->sso_grp;
+ cvmx_pki_write_qpg_entry(
+ xp.node, prtsch->qpg_base + qos, &qpg_cfg);
+ if (pki_helper_debug)
+ debug("%s: port %d qos %d has port_add %d aura %d grp %d\n",
+ __func__, ipd_port, qos, qossch->port_add,
+ qossch->aura_num, qossch->sso_grp);
+ } /* for qos 0 ... num_qos */
+ } else {
+ qpg_cfg.port_add = 0;
+ qpg_cfg.aura_num = prtsch->aura_num;
+ qpg_cfg.grp_ok = prtsch->sso_grp;
+ qpg_cfg.grp_bad = prtsch->sso_grp;
+ cvmx_pki_write_qpg_entry(xp.node, prtsch->qpg_base, &qpg_cfg);
+
+ if (pki_helper_debug)
+ debug("%s: non-qos port %d has aura %d grp %d\n",
+ __func__, ipd_port, prtsch->aura_num,
+ prtsch->sso_grp);
+ }
+
+ /* LR: The rest of code is common for qos and non-qos ports */
+
+ /* Allocate style here and map it to the port */
+ rs = cvmx_pki_style_alloc(xp.node, prtsch->style);
+ if (rs == CVMX_RESOURCE_ALREADY_RESERVED) {
+ debug("%s INFO: style will be shared\n", __func__);
+ } else if (rs == CVMX_RESOURCE_ALLOC_FAILED) {
+ debug("%s ERROR: style not available\n", __func__);
+ return CVMX_RESOURCE_ALLOC_FAILED;
+ }
+ prtsch->style = rs;
+
+ if (pki_helper_debug)
+ debug("%s: port %d has style %d\n", __func__, ipd_port,
+ prtsch->style);
+
+ /* Config STYLE to above QPG table base entry */
+ style_cfg = pki_dflt_style[xp.node];
+ style_cfg.parm_cfg.qpg_qos = prtsch->qpg_qos;
+ style_cfg.parm_cfg.qpg_base = prtsch->qpg_base;
+ style_cfg.parm_cfg.qpg_port_msb = 0;
+ style_cfg.parm_cfg.qpg_port_sh = 0;
+ style_cfg.parm_cfg.mbuff_size = mbuff_size;
+ cvmx_pki_write_style_config(xp.node, prtsch->style,
+ CVMX_PKI_CLUSTER_ALL, &style_cfg);
+
+ /* Update PKND with initial STYLE */
+ pknd = cvmx_helper_get_pknd(
+ xiface, cvmx_helper_get_interface_index_num(ipd_port));
+ cvmx_pki_read_pkind_config(xp.node, pknd, &pknd_cfg);
+ pknd_cfg.initial_style = prtsch->style;
+ pknd_cfg.fcs_pres = __cvmx_helper_get_has_fcs(xiface);
+ cvmx_pki_write_pkind_config(xp.node, pknd, &pknd_cfg);
+
+ return 0;
+}
+
+/**
+ * This function sets up scheduling parameters (pool, aura, sso group etc)
+ * of an interface (all ports/channels on that interface).
+ * @param xiface interface number with node.
+ * @param intfsch pointer to struct containing interface
+ * scheduling parameters.
+ * @param gblsch pointer to struct containing global scheduling parameters
+ * (can be NULL if not used)
+ */
+int cvmx_helper_pki_init_interface(const int xiface,
+ struct cvmx_pki_intf_schd *intfsch,
+ struct cvmx_pki_global_schd *gblsch)
+{
+ const u16 num_ports = cvmx_helper_ports_on_interface(xiface);
+ u8 qos;
+ u16 port = num_ports;
+ u8 port_msb = 0;
+ u8 port_shift = 0;
+ u16 num_entry = 0;
+ u8 num_qos;
+ int pknd;
+ int rs;
+ int has_fcs;
+ int ipd_port;
+ int qpg_base;
+ u64 mbuff_size = 0;
+ struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
+ enum cvmx_pki_qpg_qos qpg_qos = CVMX_PKI_QPG_QOS_NONE;
+ struct cvmx_pki_qpg_config qpg_cfg;
+ struct cvmx_pki_prt_schd *prtsch;
+ struct cvmx_pki_qos_schd *qossch;
+ struct cvmx_pki_style_config style_cfg;
+ struct cvmx_pki_pkind_config pknd_cfg;
+
+ has_fcs = __cvmx_helper_get_has_fcs(xiface);
+ memset(&qpg_cfg, 0, sizeof(qpg_cfg));
+
+ if (pki_helper_debug)
+ debug("pki-helper:intf-init:intf0x%x initialize--------------------------------\n",
+ xiface);
+
+ if (!intfsch->pool_per_intf) {
+ if (gblsch) {
+ intfsch->_pool = gblsch->_pool;
+ intfsch->pool_num = gblsch->pool_num;
+ } else {
+ debug("ERROR:pki-helper:intf-init:intf0x%x: global scheduling is in use but is NULL\n",
+ xiface);
+ return -1;
+ }
+ } else {
+ if (!intfsch) {
+ debug("ERROR:pki-helper:intf-init:intf0x%x: interface scheduling pointer is NULL\n",
+ xiface);
+ return -1;
+ }
+ mbuff_size = intfsch->pool_buff_size;
+ }
+ if (!intfsch->aura_per_intf) {
+ intfsch->_aura = gblsch->_aura;
+ intfsch->aura_num = gblsch->aura_num;
+ }
+ if (!intfsch->sso_grp_per_intf)
+ intfsch->sso_grp = gblsch->sso_grp;
+
+ /* Allocate interface resources */
+ rs = __cvmx_helper_pki_intf_rsrcs(xi.node, intfsch);
+ if (rs)
+ return rs;
+
+ for (port = 0; port < num_ports; port++) {
+ prtsch = &intfsch->prt_s[port];
+
+ /* Skip invalid/disabled ports */
+ if (!cvmx_helper_is_port_valid(xiface, port) ||
+ prtsch->cfg_port)
+ continue;
+
+ if (!prtsch->pool_per_prt) {
+ prtsch->pool_num = intfsch->pool_num;
+ prtsch->_pool = intfsch->_pool;
+ prtsch->pool_buff_size = intfsch->pool_buff_size;
+ } else if (prtsch->pool_buff_size < mbuff_size || !mbuff_size) {
+ mbuff_size = prtsch->pool_buff_size;
+ }
+ if (!prtsch->aura_per_prt) {
+ prtsch->aura_num = intfsch->aura_num;
+ prtsch->_aura = intfsch->_aura;
+ }
+ if (!prtsch->sso_grp_per_prt)
+ prtsch->sso_grp = intfsch->sso_grp;
+
+ rs = __cvmx_helper_pki_port_rsrcs(xi.node, prtsch);
+ if (rs)
+ return rs;
+
+ /* Port is using qpg qos to schedule packets to differnet aura or sso group */
+ num_qos = cvmx_helper_pki_get_num_qpg_entry(prtsch->qpg_qos);
+ if (pki_helper_debug)
+ debug("pki-helper:intf-init:intf%d: port %d used qpg_qos=%d\n",
+ xiface, port, prtsch->qpg_qos);
+
+ /* All ports will share the aura from port 0 for the respective qos */
+ /* Port 0 should never have this set to TRUE **/
+ if (intfsch->qos_share_aura && (port != 0)) {
+ if (pki_helper_debug)
+ debug("pki-helper:intf-init:intf0x%x All ports will share same aura for all qos\n",
+ xiface);
+ for (qos = 0; qos < num_qos; qos++) {
+ qossch = &prtsch->qos_s[qos];
+ prtsch->qpg_qos = intfsch->prt_s[0].qpg_qos;
+ qossch->pool_per_qos = intfsch->prt_s[0]
+ .qos_s[qos]
+ .pool_per_qos;
+ qossch->aura_per_qos = intfsch->prt_s[0]
+ .qos_s[qos]
+ .aura_per_qos;
+ qossch->pool_num =
+ intfsch->prt_s[0].qos_s[qos].pool_num;
+ qossch->_pool =
+ intfsch->prt_s[0].qos_s[qos]._pool;
+ qossch->aura_num =
+ intfsch->prt_s[0].qos_s[qos].aura_num;
+ qossch->_aura =
+ intfsch->prt_s[0].qos_s[qos]._aura;
+ }
+ }
+ if (intfsch->qos_share_grp && port != 0) {
+ if (pki_helper_debug)
+ debug("pki-helper:intf-init:intf0x%x: All ports will share same sso group for all qos\n",
+ xiface);
+ for (qos = 0; qos < num_qos; qos++) {
+ qossch = &prtsch->qos_s[qos];
+ qossch->sso_grp_per_qos =
+ intfsch->prt_s[0]
+ .qos_s[qos]
+ .sso_grp_per_qos;
+ qossch->sso_grp =
+ intfsch->prt_s[0].qos_s[qos].sso_grp;
+ }
+ }
+ for (qos = 0; qos < num_qos; qos++) {
+ qossch = &prtsch->qos_s[qos];
+ if (!qossch->pool_per_qos) {
+ qossch->pool_num = prtsch->pool_num;
+ qossch->_pool = prtsch->_pool;
+ if (pki_helper_debug)
+ debug("pki-helper:intf-init:intf0x%x: qos %d has pool %d\n",
+ xiface, qos, prtsch->pool_num);
+ } else if (qossch->pool_buff_size < mbuff_size ||
+ !mbuff_size)
+ mbuff_size = qossch->pool_buff_size;
+ if (!qossch->aura_per_qos) {
+ qossch->aura_num = prtsch->aura_num;
+ qossch->_aura = prtsch->_aura;
+ }
+ if (!qossch->sso_grp_per_qos)
+ qossch->sso_grp = prtsch->sso_grp;
+ rs = __cvmx_helper_pki_qos_rsrcs(xi.node, qossch);
+ if (rs)
+ return rs;
+ }
+ }
+ /* Using port shift and port msb to schedule packets from differnt
+ * port to differnt auras and different sso group
+ */
+ /* Using QPG_QOS to schedule packets to different aura and sso group */
+ /* If ports needs to send packets to different aura and sso group
+ * depending on packet qos
+ */
+ /* We will need to set up aura and sso group for each port and each qos
+ */
+ /* If all ports are using same style, they will be using same qpg_qos
+ * so check only for port 0
+ */
+ if (intfsch->style_per_intf) {
+ if (intfsch->prt_s[0].qpg_qos) {
+ /* all ports using same style will use same qos
+ * defined in port 0 config
+ */
+ qpg_qos = intfsch->prt_s[0].qpg_qos;
+ num_qos = cvmx_helper_pki_get_num_qpg_entry(
+ intfsch->prt_s[0].qpg_qos);
+ if (intfsch->qos_share_aura && intfsch->qos_share_grp) {
+ /* All ports will use same qpg offset so no
+ * need for port_msb or port shift
+ */
+ port_msb = 0;
+ port_shift = 0;
+ num_entry = num_qos;
+ qpg_base = intfsch->qpg_base;
+ rs = __cvmx_helper_pki_set_intf_qpg(xi.node, 0,
+ qpg_base,
+ num_entry,
+ intfsch);
+ if (rs == -1)
+ return rs;
+ intfsch->qpg_base = rs;
+ } else {
+ port_msb = 8;
+ port_shift = __cvmx_helper_pki_port_shift(
+ xiface, intfsch->prt_s[0].qpg_qos);
+ if (pki_helper_debug) {
+ debug("pki-helper: num qpg entry needed %d\n",
+ (int)num_entry);
+ debug("pki-helper:port_msb=%d port_shift=%d\n",
+ port_msb, port_shift);
+ }
+ num_entry = num_qos;
+ for (port = 0; port < num_ports; port++) {
+ /* Skip invalid/disabled ports */
+ prtsch = &intfsch->prt_s[port];
+ if (!cvmx_helper_is_port_valid(xiface,
+ port) ||
+ prtsch->cfg_port)
+ continue;
+ ipd_port = cvmx_helper_get_ipd_port(
+ xiface, port);
+ qpg_base = intfsch->qpg_base +
+ ((ipd_port & 0xff)
+ << port_shift);
+ rs = __cvmx_helper_pki_set_intf_qpg(
+ xi.node, port, qpg_base,
+ num_entry, intfsch);
+ if (rs == -1)
+ return rs;
+ prtsch->qpg_base = rs;
+ }
+ intfsch->qpg_base = intfsch->prt_s[0].qpg_base;
+ }
+ } else if (intfsch->prt_s[0].aura_per_prt ||
+ intfsch->prt_s[0].sso_grp_per_prt) {
+ /* Every port is using their own aura or group but no qos */
+ port_msb = 8;
+ port_shift = 0;
+ num_entry = 1;
+ if (pki_helper_debug)
+ debug("pki-helper: aura/grp_per_prt: num qpg entry needed %d\n",
+ (int)num_entry);
+ for (port = 0; port < num_ports; port++) {
+ prtsch = &intfsch->prt_s[port];
+ /* Skip invalid/disabled ports */
+ if (!cvmx_helper_is_port_valid(xiface, port) ||
+ prtsch->cfg_port)
+ continue;
+ ipd_port =
+ cvmx_helper_get_ipd_port(xiface, port);
+ qpg_base = intfsch->qpg_base +
+ ((ipd_port & 0xff) << port_shift);
+ if (pki_helper_debug)
+ debug("port %d intf_q_base=%d q_base= %d\n",
+ port, intfsch->qpg_base,
+ qpg_base);
+ qpg_base = cvmx_pki_qpg_entry_alloc(
+ xi.node, qpg_base, num_entry);
+ if (qpg_base ==
+ CVMX_RESOURCE_ALREADY_RESERVED) {
+ debug("pki-helper: INFO: qpg entries will be shared\n");
+ } else if (qpg_base ==
+ CVMX_RESOURCE_ALLOC_FAILED) {
+ debug("pki-helper: ERROR: qpg entries not available\n");
+ return qpg_base;
+ }
+
+ if (intfsch->qpg_base < 0)
+ intfsch->qpg_base = qpg_base;
+ prtsch->qpg_base = qpg_base;
+
+ qpg_cfg.port_add = 0;
+ qpg_cfg.aura_num = prtsch->aura_num;
+ qpg_cfg.grp_ok = prtsch->sso_grp;
+ qpg_cfg.grp_bad = prtsch->sso_grp;
+ cvmx_pki_write_qpg_entry(xi.node, qpg_base,
+ &qpg_cfg);
+ }
+ intfsch->qpg_base = intfsch->prt_s[0].qpg_base;
+ } else {
+ /* All ports on that intf use same port_add,
+ * aura & sso grps
+ */
+ /* All ports will use same qpg offset so no need for
+ * port_msb or port shift
+ */
+ port_msb = 0;
+ port_shift = 0;
+ num_entry = 1;
+ qpg_base = intfsch->qpg_base;
+ qpg_base = cvmx_pki_qpg_entry_alloc(xi.node, qpg_base,
+ num_entry);
+ if (qpg_base == CVMX_RESOURCE_ALREADY_RESERVED) {
+ debug("pki-helper: INFO: qpg entries will be shared\n");
+ } else if (qpg_base == CVMX_RESOURCE_ALLOC_FAILED) {
+ debug("pki-helper: ERROR: qpg entries not available\n");
+ return qpg_base;
+ }
+ intfsch->qpg_base = qpg_base;
+
+ qpg_cfg.port_add = 0;
+ qpg_cfg.aura_num = intfsch->aura_num;
+ qpg_cfg.grp_ok = intfsch->sso_grp;
+ qpg_cfg.grp_bad = intfsch->sso_grp;
+ cvmx_pki_write_qpg_entry(xi.node, qpg_base, &qpg_cfg);
+ }
+ if (!mbuff_size) {
+ if (!gblsch->setup_pool) {
+ debug("No pool has setup for intf 0x%x\n",
+ xiface);
+ return -1;
+ }
+ mbuff_size = gblsch->pool_buff_size;
+ debug("interface %d on node %d is using global pool\n",
+ xi.interface, xi.node);
+ }
+ /* Allocate style here and map it to all ports on interface */
+ rs = cvmx_pki_style_alloc(xi.node, intfsch->style);
+ if (rs == CVMX_RESOURCE_ALREADY_RESERVED) {
+ debug("passthrough: INFO: style will be shared\n");
+ } else if (rs == CVMX_RESOURCE_ALLOC_FAILED) {
+ debug("passthrough: ERROR: style not available\n");
+ return CVMX_RESOURCE_ALLOC_FAILED;
+ }
+
+ intfsch->style = rs;
+ if (pki_helper_debug)
+ debug("style %d allocated intf 0x%x qpg_base %d\n",
+ intfsch->style, xiface, intfsch->qpg_base);
+ style_cfg = pki_dflt_style[xi.node];
+ style_cfg.parm_cfg.qpg_qos = qpg_qos;
+ style_cfg.parm_cfg.qpg_base = intfsch->qpg_base;
+ style_cfg.parm_cfg.qpg_port_msb = port_msb;
+ style_cfg.parm_cfg.qpg_port_sh = port_shift;
+ style_cfg.parm_cfg.mbuff_size = mbuff_size;
+ cvmx_pki_write_style_config(xi.node, intfsch->style,
+ CVMX_PKI_CLUSTER_ALL, &style_cfg);
+
+ for (port = 0; port < num_ports; port++) {
+ prtsch = &intfsch->prt_s[port];
+ /* Skip invalid/disabled ports */
+ if (!cvmx_helper_is_port_valid(xiface, port) ||
+ prtsch->cfg_port)
+ continue;
+ prtsch->style = intfsch->style;
+ pknd = cvmx_helper_get_pknd(xiface, port);
+ cvmx_pki_read_pkind_config(xi.node, pknd, &pknd_cfg);
+ pknd_cfg.initial_style = intfsch->style;
+ pknd_cfg.fcs_pres = has_fcs;
+ cvmx_pki_write_pkind_config(xi.node, pknd, &pknd_cfg);
+ }
+ } else {
+ port_msb = 0;
+ port_shift = 0;
+ for (port = 0; port < num_ports; port++) {
+ prtsch = &intfsch->prt_s[port];
+ /* Skip invalid/disabled ports */
+ if (!cvmx_helper_is_port_valid(xiface, port) ||
+ prtsch->cfg_port)
+ continue;
+ if (prtsch->qpg_qos && intfsch->qos_share_aura &&
+ intfsch->qos_share_grp && port != 0) {
+ if (pki_helper_debug)
+ debug("intf 0x%x has all ports share qos aura n grps\n",
+ xiface);
+ /* Ports have differnet styles but want
+ * to share same qpg entries.
+ * this might never be the case
+ */
+ prtsch->qpg_base = intfsch->prt_s[0].qpg_base;
+ }
+ ipd_port = cvmx_helper_get_ipd_port(xiface, port);
+ cvmx_helper_pki_init_port(ipd_port, prtsch);
+ }
+ }
+ return 0;
+}
+
+/**
+ * This function gets all the PKI parameters related to that
+ * particular port from hardware.
+ * @param xipd_port xipd_port port number with node to get parameter of
+ * @param port_cfg pointer to structure where to store read parameters
+ */
+void cvmx_pki_get_port_config(int xipd_port,
+ struct cvmx_pki_port_config *port_cfg)
+{
+ int xiface, index, pknd;
+ int style, cl_mask;
+ cvmx_pki_icgx_cfg_t pki_cl_msk;
+ struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(xipd_port);
+
+ /* get the pkind used by this ipd port */
+ xiface = cvmx_helper_get_interface_num(xipd_port);
+ index = cvmx_helper_get_interface_index_num(xipd_port);
+ pknd = cvmx_helper_get_pknd(xiface, index);
+
+ cvmx_pki_read_pkind_config(xp.node, pknd, &port_cfg->pkind_cfg);
+ style = port_cfg->pkind_cfg.initial_style;
+ pki_cl_msk.u64 = csr_rd_node(
+ xp.node, CVMX_PKI_ICGX_CFG(port_cfg->pkind_cfg.cluster_grp));
+ cl_mask = pki_cl_msk.s.clusters;
+ cvmx_pki_read_style_config(xp.node, style, cl_mask,
+ &port_cfg->style_cfg);
+}
+
+/**
+ * This function sets all the PKI parameters related to that
+ * particular port in hardware.
+ * @param xipd_port ipd port number with node to get parameter of
+ * @param port_cfg pointer to structure containing port parameters
+ */
+void cvmx_pki_set_port_config(int xipd_port,
+ struct cvmx_pki_port_config *port_cfg)
+{
+ int xiface, index, pknd;
+ int style, cl_mask;
+ cvmx_pki_icgx_cfg_t pki_cl_msk;
+ struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(xipd_port);
+
+ /* get the pkind used by this ipd port */
+ xiface = cvmx_helper_get_interface_num(xipd_port);
+ index = cvmx_helper_get_interface_index_num(xipd_port);
+ pknd = cvmx_helper_get_pknd(xiface, index);
+
+ if (cvmx_pki_write_pkind_config(xp.node, pknd, &port_cfg->pkind_cfg))
+ return;
+ style = port_cfg->pkind_cfg.initial_style;
+ pki_cl_msk.u64 = csr_rd_node(
+ xp.node, CVMX_PKI_ICGX_CFG(port_cfg->pkind_cfg.cluster_grp));
+ cl_mask = pki_cl_msk.s.clusters;
+ cvmx_pki_write_style_config(xp.node, style, cl_mask,
+ &port_cfg->style_cfg);
+}
+
+/**
+ * This function displays all the PKI parameters related to that
+ * particular port.
+ * @param xipd_port ipd port number to display parameter of
+ */
+void cvmx_helper_pki_show_port_config(int xipd_port)
+{
+ int xiface, index, pknd;
+ struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(xipd_port);
+
+ xiface = cvmx_helper_get_interface_num(xipd_port);
+ index = cvmx_helper_get_interface_index_num(xipd_port);
+ pknd = cvmx_helper_get_pknd(xiface, index);
+ debug("Showing stats for intf 0x%x port %d------------------\n", xiface,
+ index);
+ cvmx_pki_show_pkind_attributes(xp.node, pknd);
+ debug("END STAUS------------------------\n\n");
+}
+
+void cvmx_helper_pki_errata(int node)
+{
+ struct cvmx_pki_global_config gbl_cfg;
+
+ if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X)) {
+ cvmx_pki_read_global_config(node, &gbl_cfg);
+ gbl_cfg.fpa_wait = CVMX_PKI_WAIT_PKT;
+ cvmx_pki_write_global_config(node, &gbl_cfg);
+ }
+}
+
+static const char *pki_ltype_sprint(int ltype)
+{
+ switch (ltype) {
+ case CVMX_PKI_LTYPE_E_ENET:
+ return "(ENET)";
+ case CVMX_PKI_LTYPE_E_VLAN:
+ return "(VLAN)";
+ case CVMX_PKI_LTYPE_E_SNAP_PAYLD:
+ return "(SNAP_PAYLD)";
+ case CVMX_PKI_LTYPE_E_ARP:
+ return "(ARP)";
+ case CVMX_PKI_LTYPE_E_RARP:
+ return "(RARP)";
+ case CVMX_PKI_LTYPE_E_IP4:
+ return "(IP4)";
+ case CVMX_PKI_LTYPE_E_IP4_OPT:
+ return "(IP4_OPT)";
+ case CVMX_PKI_LTYPE_E_IP6:
+ return "(IP6)";
+ case CVMX_PKI_LTYPE_E_IP6_OPT:
+ return "(IP6_OPT)";
+ case CVMX_PKI_LTYPE_E_IPSEC_ESP:
+ return "(IPSEC_ESP)";
+ case CVMX_PKI_LTYPE_E_IPFRAG:
+ return "(IPFRAG)";
+ case CVMX_PKI_LTYPE_E_IPCOMP:
+ return "(IPCOMP)";
+ case CVMX_PKI_LTYPE_E_TCP:
+ return "(TCP)";
+ case CVMX_PKI_LTYPE_E_UDP:
+ return "(UDP)";
+ case CVMX_PKI_LTYPE_E_SCTP:
+ return "(SCTP)";
+ case CVMX_PKI_LTYPE_E_UDP_VXLAN:
+ return "(UDP_VXLAN)";
+ case CVMX_PKI_LTYPE_E_GRE:
+ return "(GRE)";
+ case CVMX_PKI_LTYPE_E_NVGRE:
+ return "(NVGRE)";
+ case CVMX_PKI_LTYPE_E_GTP:
+ return "(GTP)";
+ default:
+ return "";
+ }
+}
+
+void cvmx_pki_dump_wqe(const cvmx_wqe_78xx_t *wqp)
+{
+ int i;
+ /* it is not cvmx_shared so per core only */
+ static u64 count;
+
+ debug("Wqe entry for packet %lld\n", (unsigned long long)count++);
+ debug(" WORD%02d: %016llx", 0, (unsigned long long)wqp->word0.u64);
+ debug(" aura=0x%x", wqp->word0.aura);
+ debug(" apad=%d", wqp->word0.apad);
+ debug(" chan=0x%x", wqp->word0.channel);
+ debug(" bufs=%d", wqp->word0.bufs);
+ debug(" style=0x%x", wqp->word0.style);
+ debug(" pknd=0x%x", wqp->word0.pknd);
+ debug("\n");
+ debug(" WORD%02d: %016llx", 1, (unsigned long long)wqp->word1.u64);
+ debug(" len=%d", wqp->word1.len);
+ debug(" grp=0x%x", wqp->word1.grp);
+ debug(" tt=%s", OCT_TAG_TYPE_STRING(wqp->word1.tag_type));
+ debug(" tag=0x%08x", wqp->word1.tag);
+ debug("\n");
+ if (wqp->word2.u64) {
+ debug(" WORD%02d: %016llx", 2,
+ (unsigned long long)wqp->word2.u64);
+ if (wqp->word2.le_hdr_type)
+ debug(" [LAE]");
+ if (wqp->word2.lb_hdr_type)
+ debug(" lbty=%d%s", wqp->word2.lb_hdr_type,
+ pki_ltype_sprint(wqp->word2.lb_hdr_type));
+ if (wqp->word2.lc_hdr_type)
+ debug(" lcty=%d%s", wqp->word2.lc_hdr_type,
+ pki_ltype_sprint(wqp->word2.lc_hdr_type));
+ if (wqp->word2.ld_hdr_type)
+ debug(" ldty=%d%s", wqp->word2.ld_hdr_type,
+ pki_ltype_sprint(wqp->word2.ld_hdr_type));
+ if (wqp->word2.le_hdr_type)
+ debug(" lety=%d%s", wqp->word2.le_hdr_type,
+ pki_ltype_sprint(wqp->word2.le_hdr_type));
+ if (wqp->word2.lf_hdr_type)
+ debug(" lfty=%d%s", wqp->word2.lf_hdr_type,
+ pki_ltype_sprint(wqp->word2.lf_hdr_type));
+ if (wqp->word2.lg_hdr_type)
+ debug(" lgty=%d%s", wqp->word2.lg_hdr_type,
+ pki_ltype_sprint(wqp->word2.lg_hdr_type));
+ if (wqp->word2.pcam_flag1)
+ debug(" PF1");
+ if (wqp->word2.pcam_flag2)
+ debug(" PF2");
+ if (wqp->word2.pcam_flag3)
+ debug(" PF3");
+ if (wqp->word2.pcam_flag4)
+ debug(" PF4");
+ if (wqp->word2.vlan_valid || wqp->word2.vlan_stacked) {
+ if (wqp->word2.vlan_valid)
+ debug(" vlan valid");
+ if (wqp->word2.vlan_stacked)
+ debug(" vlan stacked");
+ debug(" ");
+ }
+ if (wqp->word2.stat_inc)
+ debug(" stat_inc");
+ if (wqp->word2.is_frag)
+ debug(" L3 Fragment");
+ if (wqp->word2.is_l3_bcast)
+ debug(" L3 Broadcast");
+ if (wqp->word2.is_l3_mcast)
+ debug(" L3 Multicast");
+ if (wqp->word2.is_l2_bcast)
+ debug(" L2 Broadcast");
+ if (wqp->word2.is_l2_mcast)
+ debug(" L2 Multicast");
+ if (wqp->word2.is_raw)
+ debug(" RAW");
+ if (wqp->word2.err_level || wqp->word2.err_code) {
+ debug(" errlev=%d", wqp->word2.err_level);
+ debug(" opcode=0x%x", wqp->word2.err_code);
+ }
+ debug("\n");
+ }
+ debug(" WORD%02d: %016llx", 3,
+ (unsigned long long)wqp->packet_ptr.u64);
+
+ debug(" size=%d", wqp->packet_ptr.size);
+ debug(" addr=0x%llx", (unsigned long long)wqp->packet_ptr.addr);
+
+ debug("\n");
+ if (wqp->word4.u64) {
+ debug(" WORD%02d: %016llx", 4,
+ (unsigned long long)wqp->word4.u64);
+ if (wqp->word4.ptr_layer_a)
+ debug(" laptr=%d", wqp->word4.ptr_layer_a);
+ if (wqp->word4.ptr_layer_b)
+ debug(" lbptr=%d", wqp->word4.ptr_layer_b);
+ if (wqp->word4.ptr_layer_c)
+ debug(" lcptr=%d", wqp->word4.ptr_layer_c);
+ if (wqp->word4.ptr_layer_d)
+ debug(" ldptr=%d", wqp->word4.ptr_layer_d);
+ if (wqp->word4.ptr_layer_e)
+ debug(" leptr=%d", wqp->word4.ptr_layer_e);
+ if (wqp->word4.ptr_layer_f)
+ debug(" lfptr=%d", wqp->word4.ptr_layer_f);
+ if (wqp->word4.ptr_layer_g)
+ debug(" lgptr=%d", wqp->word4.ptr_layer_g);
+ if (wqp->word4.ptr_vlan)
+ debug(" vlptr=%d", wqp->word4.ptr_vlan);
+ debug("\n");
+ }
+ for (i = 0; i < 10; ++i) {
+ if (wqp->wqe_data[i])
+ debug(" WORD%02d: %016llx\n", i + 5,
+ (unsigned long long)wqp->wqe_data[i]);
+ }
+}
+
+/**
+ * Modifies maximum frame length to check.
+ * It modifies the global frame length set used by this port, any other
+ * port using the same set will get affected too.
+ * @param xipd_port ipd port for which to modify max len.
+ * @param max_size maximum frame length
+ */
+void cvmx_pki_set_max_frm_len(int ipd_port, uint32_t max_size)
+{
+ /* On CN78XX frame check is enabled for a style n and
+ * PKI_CLX_STYLE_CFG[minmax_sel] selects which set of
+ * MAXLEN/MINLEN to use.
+ */
+ int xiface, index, pknd;
+ cvmx_pki_clx_stylex_cfg_t style_cfg;
+ cvmx_pki_frm_len_chkx_t frame_len;
+ struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
+ int cluster = 0;
+ int style;
+ int sel;
+
+ /* get the pkind used by this ipd port */
+ xiface = cvmx_helper_get_interface_num(ipd_port);
+ index = cvmx_helper_get_interface_index_num(ipd_port);
+ pknd = cvmx_helper_get_pknd(xiface, index);
+
+ style = cvmx_pki_get_pkind_style(xp.node, pknd);
+ style_cfg.u64 =
+ csr_rd_node(xp.node, CVMX_PKI_CLX_STYLEX_CFG(style, cluster));
+ sel = style_cfg.s.minmax_sel;
+ frame_len.u64 = csr_rd_node(xp.node, CVMX_PKI_FRM_LEN_CHKX(sel));
+ frame_len.s.maxlen = max_size;
+ csr_wr_node(xp.node, CVMX_PKI_FRM_LEN_CHKX(sel), frame_len.u64);
+}
+
+/**
+ * This function sets up all th eports of particular interface
+ * for chosen fcs mode. (only use for backward compatibility).
+ * New application can control it via init_interface calls.
+ * @param node node number.
+ * @param interface interface number.
+ * @param nports number of ports
+ * @param has_fcs 1 -- enable fcs check and fcs strip.
+ * 0 -- disable fcs check.
+ */
+void cvmx_helper_pki_set_fcs_op(int node, int interface, int nports,
+ int has_fcs)
+{
+ int xiface, index;
+ int pknd;
+ unsigned int cluster = 0;
+ cvmx_pki_clx_pkindx_cfg_t pkind_cfg;
+
+ xiface = cvmx_helper_node_interface_to_xiface(node, interface);
+ for (index = 0; index < nports; index++) {
+ pknd = cvmx_helper_get_pknd(xiface, index);
+ while (cluster < CVMX_PKI_NUM_CLUSTER) {
+ /*find the cluster in use pass2*/
+ pkind_cfg.u64 = csr_rd_node(
+ node, CVMX_PKI_CLX_PKINDX_CFG(pknd, cluster));
+ pkind_cfg.s.fcs_pres = has_fcs;
+ csr_wr_node(node,
+ CVMX_PKI_CLX_PKINDX_CFG(pknd, cluster),
+ pkind_cfg.u64);
+ cluster++;
+ }
+ /* make sure fcs_strip and fcs_check is also enable/disable
+ * for the style used by that port
+ */
+ cvmx_pki_endis_fcs_check(node, pknd, has_fcs, has_fcs);
+ cluster = 0;
+ }
+}
+
+/**
+ * This function sets the wqe buffer mode of all ports. First packet data buffer can reside
+ * either in same buffer as wqe OR it can go in separate buffer. If used the later mode,
+ * make sure software allocate enough buffers to now have wqe separate from packet data.
+ * @param node node number.
+ * @param pkt_outside_wqe 0 = The packet link pointer will be at word [FIRST_SKIP]
+ * immediately followed by packet data, in the same buffer
+ * as the work queue entry.
+ * 1 = The packet link pointer will be at word [FIRST_SKIP] in a new
+ * buffer separate from the work queue entry. Words following the
+ * WQE in the same cache line will be zeroed, other lines in the
+ * buffer will not be modified and will retain stale data (from the
+ * buffer’s previous use). This setting may decrease the peak PKI
+ * performance by up to half on small packets.
+ */
+void cvmx_helper_pki_set_wqe_mode(int node, bool pkt_outside_wqe)
+{
+ int interface, xiface, port, pknd;
+ int num_intf, num_ports;
+ u64 style;
+
+ /* get the pkind used by this ipd port */
+ num_intf = cvmx_helper_get_number_of_interfaces();
+ for (interface = 0; interface < num_intf; interface++) {
+ num_ports = cvmx_helper_ports_on_interface(interface);
+ /*Skip invalid/disabled interfaces */
+ if (num_ports <= 0)
+ continue;
+ xiface = cvmx_helper_node_interface_to_xiface(node, interface);
+ for (port = 0; port < num_ports; port++) {
+ pknd = cvmx_helper_get_pknd(xiface, port);
+ style = cvmx_pki_get_pkind_style(node, pknd);
+ cvmx_pki_set_wqe_mode(node, style, pkt_outside_wqe);
+ }
+ }
+}
+
+/**
+ * This function sets the Packet mode of all ports and styles to little-endian.
+ * It Changes write operations of packet data to L2C to
+ * be in little-endian. Does not change the WQE header format, which is
+ * properly endian neutral.
+ * @param node node number.
+ */
+void cvmx_helper_pki_set_little_endian(int node)
+{
+ int interface, xiface, port, pknd;
+ int num_intf, num_ports;
+ u64 style;
+
+ /* get the pkind used by this ipd port */
+ num_intf = cvmx_helper_get_number_of_interfaces();
+ for (interface = 0; interface < num_intf; interface++) {
+ num_ports = cvmx_helper_ports_on_interface(interface);
+ /*Skip invalid/disabled interfaces */
+ if (num_ports <= 0)
+ continue;
+ xiface = cvmx_helper_node_interface_to_xiface(node, interface);
+ for (port = 0; port < num_ports; port++) {
+ pknd = cvmx_helper_get_pknd(xiface, port);
+ style = cvmx_pki_get_pkind_style(node, pknd);
+ cvmx_pki_set_little_endian(node, style);
+ }
+ }
+}
+
+/**
+ * This function modifies the sso group where packets from specified port needs to be routed
+ * @param ipd_port pki port number.
+ * @param grp_ok sso group where good packets are routed
+ * @param grp_bad sso group where errored packets are routed
+ * NOTE: This function assumes that each port has its own style/profile and is not using qpg qos
+ */
+void cvmx_helper_pki_modify_prtgrp(int xipd_port, int grp_ok, int grp_bad)
+{
+ struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(xipd_port);
+ struct cvmx_pki_port_config port_cfg;
+ struct cvmx_pki_qpg_config qpg_cfg;
+ int index;
+
+ cvmx_pki_get_port_config(xipd_port, &port_cfg);
+ /* TODO: expand it to calculate index in other cases hrm:10.5.3*/
+ index = port_cfg.style_cfg.parm_cfg.qpg_base;
+ cvmx_pki_read_qpg_entry(xp.node, index, &qpg_cfg);
+ qpg_cfg.grp_ok = grp_ok;
+ qpg_cfg.grp_bad = grp_bad;
+ cvmx_pki_write_qpg_entry(xp.node, index, &qpg_cfg);
+}
+
+int cvmx_pki_clone_style(int node, int style, u64 cluster_mask)
+{
+ int new_style;
+ struct cvmx_pki_style_config style_cfg;
+
+ cvmx_pki_read_style_config(node, style, cluster_mask, &style_cfg);
+ new_style = cvmx_pki_style_alloc(node, CVMX_PKI_FIND_AVAL_ENTRY);
+ if (new_style < 0)
+ return -1;
+ cvmx_pki_write_style_config(node, new_style, cluster_mask, &style_cfg);
+ return new_style;
+}
+
+/* Optimize if use at runtime */
+int cvmx_pki_add_entry(u64 *array, u64 match, int index, int num_entries)
+{
+ if (index >= num_entries)
+ return -1;
+ array[index] = match;
+ return 0;
+}
+
+/* Optimize if use at runtime */
+int cvmx_pki_find_entry(u64 *array, u64 match, int num_entries)
+{
+ int i;
+
+ for (i = 0; i < num_entries; i++) {
+ if ((array[i] & 0xffffffffff) == match)
+ return i;
+ }
+ return -1;
+}
+
+/**
+ * This function send the packets to specified style/profile if
+ * specified mac address and specified input style/profile matches.
+ * @param node node number.
+ * @param style style/profile to match against
+ * @param mac_addr mac address to match
+ * @param mac_addr_mask mask of mac address bits
+ * 1: exact match
+ * 0: don't care
+ * ex: to exactly match mac address 0x0a0203040506
+ * mask = 0xffffffffffff
+ * to match only first 2 bytes 0x0a02xxxxxxxx
+ * mask = 0xffff00000000
+ * @param final_style final style (contains aura/sso_grp etc) to
+ * route matched packet to.
+ */
+int cvmx_helper_pki_route_dmac(int node, int style, u64 mac_addr,
+ u64 mac_addr_mask, int final_style)
+{
+ struct cvmx_pki_pcam_input pcam_input;
+ struct cvmx_pki_pcam_action pcam_action;
+ int bank;
+ int index;
+ int interim_style = style;
+ u64 cl_mask = CVMX_PKI_CLUSTER_ALL;
+ u32 data_to_match;
+ u32 data_to_mask;
+ u64 match_h;
+ u64 match_l;
+
+ memset(&pcam_input, 0, sizeof(pcam_input));
+ memset(&pcam_action, 0, sizeof(pcam_action));
+ data_to_match =
+ (mac_addr >> CVMX_PKI_DMACH_SHIFT) & CVMX_PKI_DMACH_MASK;
+ data_to_mask =
+ (mac_addr_mask >> CVMX_PKI_DMACH_SHIFT) & CVMX_PKI_DMACH_MASK;
+ match_h = (u64)(data_to_match & data_to_mask) | (u64)(style << 16);
+ if (!data_to_mask)
+ goto pcam_dmacl;
+ index = cvmx_pki_find_entry(pcam_dmach, match_h,
+ CVMX_PKI_NUM_PCAM_ENTRY);
+
+ if (index >= 0) {
+ interim_style = (pcam_dmach[index] >> 40) & 0xffffffffff;
+ goto pcam_dmacl;
+ }
+ bank = 0;
+ index = cvmx_pki_pcam_entry_alloc(node, CVMX_PKI_FIND_AVAL_ENTRY, bank,
+ cl_mask);
+ if (index < 0) {
+ debug("ERROR: Allocating pcam entry node=%d bank=%d\n", node,
+ bank);
+ return -1;
+ }
+ pcam_input.style = style;
+ pcam_input.style_mask = 0xffffffffffffffff;
+ pcam_input.field = CVMX_PKI_PCAM_TERM_DMACH;
+ pcam_input.field_mask = 0xff;
+ pcam_input.data = data_to_match;
+ pcam_input.data_mask = data_to_mask;
+ pcam_action.parse_mode_chg = CVMX_PKI_PARSE_NO_CHG;
+ pcam_action.parse_flag_set = 0;
+ pcam_action.layer_type_set = CVMX_PKI_LTYPE_E_NONE;
+ interim_style = cvmx_pki_clone_style(node, style, cl_mask);
+ if (interim_style < 0) {
+ debug("ERROR: Failed to allocate interim style\n");
+ return -1;
+ }
+ pcam_action.style_add = interim_style - style;
+ pcam_action.pointer_advance = 0;
+ cvmx_pki_pcam_write_entry(node, index, cl_mask, pcam_input,
+ pcam_action); /*cluster_mask in pass2*/
+ match_h |= (u64)(((u64)interim_style << 40) & 0xff0000000000);
+ cvmx_pki_add_entry(pcam_dmach, match_h, index, CVMX_PKI_NUM_PCAM_ENTRY);
+pcam_dmacl:
+ bank = 1;
+ data_to_match = (mac_addr & CVMX_PKI_DMACL_MASK);
+ data_to_mask = (mac_addr_mask & CVMX_PKI_DMACL_MASK);
+ if (!data_to_mask)
+ return 0;
+ match_l = (u64)(data_to_match & data_to_mask) |
+ ((u64)interim_style << 32);
+ if (cvmx_pki_find_entry(pcam_dmacl, match_l, CVMX_PKI_NUM_PCAM_ENTRY) >=
+ 0)
+ return 0;
+ index = cvmx_pki_pcam_entry_alloc(node, CVMX_PKI_FIND_AVAL_ENTRY, bank,
+ cl_mask);
+ if (index < 0) {
+ debug("ERROR: Allocating pcam entry node=%d bank=%d\n", node,
+ bank);
+ return -1;
+ }
+ cvmx_pki_add_entry(pcam_dmacl, match_l, index, CVMX_PKI_NUM_PCAM_ENTRY);
+ pcam_input.style = interim_style;
+ pcam_input.style_mask = 0xffffffffffffffff;
+ pcam_input.field = CVMX_PKI_PCAM_TERM_DMACL;
+ pcam_input.field_mask = 0xff;
+ pcam_input.data = data_to_match;
+ pcam_input.data_mask = data_to_mask;
+ /* customer need to decide if they want to resume parsing or terminate
+ * it, if further match found in pcam it will take precedence
+ */
+ pcam_action.parse_mode_chg = CVMX_PKI_PARSE_NO_CHG;
+ pcam_action.parse_flag_set = 0;
+ pcam_action.layer_type_set = CVMX_PKI_LTYPE_E_NONE;
+ pcam_action.style_add = final_style - interim_style;
+ pcam_action.pointer_advance = 0;
+ cvmx_pki_pcam_write_entry(node, index, cl_mask, pcam_input,
+ pcam_action); /*cluster_mask in pass2*/
+
+ return 0;
+}
+
+/**
+ * This function send the packets to specified sso group if
+ * specified mac address and specified input port matches.
+ * NOTE: This function will always create a new style/profile for the specified
+ * sso group even if style/profile already exist and if the style used by this ipd port is
+ * shared all the ports using that style will get affected.
+ * similar function to use: cvmx_helper_pki_route_dmac()
+ * @param node node number.
+ * @param ipd_port ipd port on which mac address match needs to be performed.
+ * @param mac_addr mac address to match
+ * @param mac_addr_mask mask of mac address bits
+ * 1: exact match
+ * 0: don't care
+ * ex: to exactly match mac address 0x0a0203040506
+ * mask = 0xffffffffffff
+ * to match only first 2 bytes 0x0a02xxxxxxxx
+ * mask = 0xffff00000000
+ * @param grp sso group to route matched packet to.
+ * @return success: final style containing routed sso group
+ * fail: -1
+ */
+int cvmx_helper_pki_route_prt_dmac(int xipd_port, u64 mac_addr,
+ u64 mac_addr_mask, int grp)
+{
+ int style;
+ int new_style;
+ int offset, index;
+ struct cvmx_pki_style_config st_cfg;
+ struct cvmx_pki_port_config port_cfg;
+ struct cvmx_pki_qpg_config qpg_cfg;
+ struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(xipd_port);
+ int node = xp.node;
+
+ /* 1. Get the current/initial style config used by this port */
+ cvmx_pki_get_port_config(xipd_port, &port_cfg);
+ style = port_cfg.pkind_cfg.initial_style;
+ st_cfg = port_cfg.style_cfg;
+
+ /* 2. Create new style/profile from current and modify it to steer
+ * traffic to specified grp
+ */
+ new_style = cvmx_pki_style_alloc(node, CVMX_PKI_FIND_AVAL_ENTRY);
+ if (new_style < 0) {
+ cvmx_printf("ERROR: %s: new style not available\n", __func__);
+ return -1;
+ }
+ offset = st_cfg.parm_cfg.qpg_base;
+ cvmx_pki_read_qpg_entry(node, offset, &qpg_cfg);
+ qpg_cfg.qpg_base = CVMX_PKI_FIND_AVAL_ENTRY;
+ qpg_cfg.grp_ok = grp;
+ qpg_cfg.grp_bad = grp;
+ index = cvmx_helper_pki_set_qpg_entry(node, &qpg_cfg);
+ if (index < 0) {
+ cvmx_printf("ERROR: %s: new qpg entry not available\n",
+ __func__);
+ return -1;
+ }
+ st_cfg.parm_cfg.qpg_base = index;
+ cvmx_pki_write_style_config(node, new_style, CVMX_PKI_CLUSTER_ALL,
+ &st_cfg);
+ cvmx_helper_pki_route_dmac(node, style, mac_addr, mac_addr_mask,
+ new_style);
+ return new_style;
+}
--
2.35.1
More information about the U-Boot
mailing list