Commit 8fdf6659 authored by Paolo Abeni's avatar Paolo Abeni

Merge branch 'adding-sparx5-es0-vcap-support'

Steen Hegelund says:

====================
Adding Sparx5 ES0 VCAP support

This provides the Egress Stage 0 (ES0) VCAP (Versatile Content-Aware
Processor) support for the Sparx5 platform.

The ES0 VCAP is an Egress Access Control VCAP that uses frame keyfields and
previously classified keyfields to add, rewrite or remove VLAN tags on the
egress frames, and is therefore often referred to as the rewriter.

The ES0 VCAP also supports trapping frames to the host.

The ES0 VCAP has 1 lookup accessible with this chain id:

- chain 10000000: ES0 Lookup 0

The ES0 VCAP does not do traffic classification to select a keyset, but it
does have two keysets that can be used on all traffic.  For now only the
ISDX keyset is used.

The ES0 VCAP can match on an ISDX key (Ingress Service Index) as one of the
frame metadata keyfields, similar to the ES2 VCAP.

The ES0 VCAP uses external counters in the XQS (statistics) group.
====================

Link: https://lore.kernel.org/r/20230214104049.1553059-1-steen.hegelund@microchip.comSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 72bc7f16 ebf44ded
......@@ -199,6 +199,7 @@ static const struct sparx5_main_io_resource sparx5_main_iomap[] = {
{ TARGET_QFWD, 0x110b0000, 2 }, /* 0x6110b0000 */
{ TARGET_XQS, 0x110c0000, 2 }, /* 0x6110c0000 */
{ TARGET_VCAP_ES2, 0x110d0000, 2 }, /* 0x6110d0000 */
{ TARGET_VCAP_ES0, 0x110e0000, 2 }, /* 0x6110e0000 */
{ TARGET_CLKGEN, 0x11100000, 2 }, /* 0x611100000 */
{ TARGET_ANA_AC_POL, 0x11200000, 2 }, /* 0x611200000 */
{ TARGET_QRES, 0x11280000, 2 }, /* 0x611280000 */
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -1071,6 +1071,11 @@ int sparx5_port_init(struct sparx5 *sparx5,
/* Discard pause frame 01-80-C2-00-00-01 */
spx5_wr(PAUSE_DISCARD, sparx5, ANA_CL_CAPTURE_BPDU_CFG(port->portno));
/* Discard SMAC multicast */
spx5_rmw(ANA_CL_FILTER_CTRL_FILTER_SMAC_MC_DIS_SET(0),
ANA_CL_FILTER_CTRL_FILTER_SMAC_MC_DIS,
sparx5, ANA_CL_FILTER_CTRL(port->portno));
if (conf->portmode == PHY_INTERFACE_MODE_QSGMII ||
conf->portmode == PHY_INTERFACE_MODE_SGMII) {
err = sparx5_serdes_set(sparx5, port, conf);
......
......@@ -21,6 +21,80 @@ enum SPX5_PORT_MASK_MODE {
SPX5_PMM_OR_PGID_MASK,
};
/* Controls ES0 forwarding */
enum SPX5_FORWARDING_SEL {
SPX5_FWSEL_NO_ACTION,
SPX5_FWSEL_COPY_TO_LOOPBACK,
SPX5_FWSEL_REDIRECT_TO_LOOPBACK,
SPX5_FWSEL_DISCARD,
};
/* Controls tag A (outer tagging) */
enum SPX5_OUTER_TAG_SEL {
SPX5_OTAG_PORT,
SPX5_OTAG_TAG_A,
SPX5_OTAG_FORCED_PORT,
SPX5_OTAG_UNTAG,
};
/* Selects TPID for ES0 tag A */
enum SPX5_TPID_A_SEL {
SPX5_TPID_A_8100,
SPX5_TPID_A_88A8,
SPX5_TPID_A_CUST1,
SPX5_TPID_A_CUST2,
SPX5_TPID_A_CUST3,
SPX5_TPID_A_CLASSIFIED,
};
/* Selects VID for ES0 tag A */
enum SPX5_VID_A_SEL {
SPX5_VID_A_CLASSIFIED,
SPX5_VID_A_VAL,
SPX5_VID_A_IFH,
SPX5_VID_A_RESERVED,
};
/* Select PCP source for ES0 tag A */
enum SPX5_PCP_A_SEL {
SPX5_PCP_A_CLASSIFIED,
SPX5_PCP_A_VAL,
SPX5_PCP_A_RESERVED,
SPX5_PCP_A_POPPED,
SPX5_PCP_A_MAPPED_0,
SPX5_PCP_A_MAPPED_1,
SPX5_PCP_A_MAPPED_2,
SPX5_PCP_A_MAPPED_3,
};
/* Select DEI source for ES0 tag A */
enum SPX5_DEI_A_SEL {
SPX5_DEI_A_CLASSIFIED,
SPX5_DEI_A_VAL,
SPX5_DEI_A_REW,
SPX5_DEI_A_POPPED,
SPX5_DEI_A_MAPPED_0,
SPX5_DEI_A_MAPPED_1,
SPX5_DEI_A_MAPPED_2,
SPX5_DEI_A_MAPPED_3,
};
/* Controls tag B (inner tagging) */
enum SPX5_INNER_TAG_SEL {
SPX5_ITAG_NO_PUSH,
SPX5_ITAG_PUSH_B_TAG,
};
/* Selects TPID for ES0 tag B. */
enum SPX5_TPID_B_SEL {
SPX5_TPID_B_8100,
SPX5_TPID_B_88A8,
SPX5_TPID_B_CUST1,
SPX5_TPID_B_CUST2,
SPX5_TPID_B_CUST3,
SPX5_TPID_B_CLASSIFIED,
};
int sparx5_port_setup_tc(struct net_device *ndev, enum tc_setup_type type,
void *type_data);
......
......@@ -284,6 +284,44 @@ static void sparx5_vcap_is2_port_stickies(struct sparx5 *sparx5,
out->prf(out->dst, "\n");
}
static void sparx5_vcap_es0_port_keys(struct sparx5 *sparx5,
struct vcap_admin *admin,
struct sparx5_port *port,
struct vcap_output_print *out)
{
u32 value;
out->prf(out->dst, " port[%02d] (%s): ", port->portno,
netdev_name(port->ndev));
out->prf(out->dst, "\n Lookup 0: ");
/* Get lookup state */
value = spx5_rd(sparx5, REW_ES0_CTRL);
out->prf(out->dst, "\n state: ");
if (REW_ES0_CTRL_ES0_LU_ENA_GET(value))
out->prf(out->dst, "on");
else
out->prf(out->dst, "off");
out->prf(out->dst, "\n keyset: ");
value = spx5_rd(sparx5, REW_RTAG_ETAG_CTRL(port->portno));
switch (REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA_GET(value)) {
case VCAP_ES0_PS_NORMAL_SELECTION:
out->prf(out->dst, "normal");
break;
case VCAP_ES0_PS_FORCE_ISDX_LOOKUPS:
out->prf(out->dst, "isdx");
break;
case VCAP_ES0_PS_FORCE_VID_LOOKUPS:
out->prf(out->dst, "vid");
break;
case VCAP_ES0_PS_RESERVED:
out->prf(out->dst, "reserved");
break;
}
out->prf(out->dst, "\n");
}
static void sparx5_vcap_es2_port_keys(struct sparx5 *sparx5,
struct vcap_admin *admin,
struct sparx5_port *port,
......@@ -418,6 +456,9 @@ int sparx5_port_info(struct net_device *ndev,
sparx5_vcap_is2_port_keys(sparx5, admin, port, out);
sparx5_vcap_is2_port_stickies(sparx5, admin, out);
break;
case VCAP_TYPE_ES0:
sparx5_vcap_es0_port_keys(sparx5, admin, port, out);
break;
case VCAP_TYPE_ES2:
sparx5_vcap_es2_port_keys(sparx5, admin, port, out);
sparx5_vcap_es2_port_stickies(sparx5, admin, out);
......
......@@ -32,6 +32,9 @@
#define SPARX5_VCAP_CID_IS2_MAX \
(VCAP_CID_INGRESS_STAGE2_L3 + VCAP_CID_LOOKUP_SIZE - 1) /* IS2 Max */
#define SPARX5_VCAP_CID_ES0_L0 VCAP_CID_EGRESS_L0 /* ES0 lookup 0 */
#define SPARX5_VCAP_CID_ES0_MAX (VCAP_CID_EGRESS_L1 - 1) /* ES0 Max */
#define SPARX5_VCAP_CID_ES2_L0 VCAP_CID_EGRESS_STAGE2_L0 /* ES2 lookup 0 */
#define SPARX5_VCAP_CID_ES2_L1 VCAP_CID_EGRESS_STAGE2_L1 /* ES2 lookup 1 */
#define SPARX5_VCAP_CID_ES2_MAX \
......@@ -134,6 +137,16 @@ enum vcap_is2_port_sel_arp {
VCAP_IS2_PS_ARP_ARP,
};
/* ES0 port keyset selection control */
/* ES0 Egress port traffic type classification */
enum vcap_es0_port_sel {
VCAP_ES0_PS_NORMAL_SELECTION,
VCAP_ES0_PS_FORCE_ISDX_LOOKUPS,
VCAP_ES0_PS_FORCE_VID_LOOKUPS,
VCAP_ES0_PS_RESERVED,
};
/* ES2 port keyset selection control */
/* ES2 IPv4 traffic type keyset generation */
......@@ -163,6 +176,18 @@ enum vcap_es2_port_sel_arp {
VCAP_ES2_PS_ARP_ARP,
};
/* Selects TPID for ES0 matching */
enum SPX5_TPID_SEL {
SPX5_TPID_SEL_UNTAGGED,
SPX5_TPID_SEL_8100,
SPX5_TPID_SEL_UNUSED_0,
SPX5_TPID_SEL_UNUSED_1,
SPX5_TPID_SEL_88A8,
SPX5_TPID_SEL_TPIDCFG_1,
SPX5_TPID_SEL_TPIDCFG_2,
SPX5_TPID_SEL_TPIDCFG_3,
};
/* Get the port keyset for the vcap lookup */
int sparx5_vcap_get_port_keyset(struct net_device *ndev,
struct vcap_admin *admin,
......
......@@ -219,8 +219,8 @@ void sparx5_vlan_port_apply(struct sparx5 *sparx5,
spx5_wr(val, sparx5,
ANA_CL_VLAN_FILTER_CTRL(port->portno, 0));
/* Egress configuration (REW_TAG_CFG): VLAN tag type to 8021Q */
val = REW_TAG_CTRL_TAG_TPID_CFG_SET(0);
/* Egress configuration (REW_TAG_CFG): VLAN tag selected via IFH */
val = REW_TAG_CTRL_TAG_TPID_CFG_SET(5);
if (port->vlan_aware) {
if (port->vid)
/* Tag all frames except when VID == DEFAULT_VLAN */
......
......@@ -1649,10 +1649,8 @@ bool vcap_is_next_lookup(struct vcap_control *vctrl, int src_cid, int dst_cid)
if (vcap_api_check(vctrl))
return false;
/* The offset must be at least one lookup, round up */
next_cid = src_cid + VCAP_CID_LOOKUP_SIZE;
next_cid /= VCAP_CID_LOOKUP_SIZE;
next_cid *= VCAP_CID_LOOKUP_SIZE;
/* The offset must be at least one lookup so round up one chain */
next_cid = roundup(src_cid + 1, VCAP_CID_LOOKUP_SIZE);
if (dst_cid < next_cid)
return false;
......@@ -2177,12 +2175,13 @@ static int vcap_get_next_chain(struct vcap_control *vctrl,
static bool vcap_path_exist(struct vcap_control *vctrl, struct net_device *ndev,
int dst_cid)
{
int cid = rounddown(dst_cid, VCAP_CID_LOOKUP_SIZE);
struct vcap_enabled_port *eport = NULL;
struct vcap_enabled_port *elem;
struct vcap_admin *admin;
int tmp;
if (dst_cid == 0) /* Chain zero is always available */
if (cid == 0) /* Chain zero is always available */
return true;
/* Find first entry that starts from chain 0*/
......@@ -2201,7 +2200,7 @@ static bool vcap_path_exist(struct vcap_control *vctrl, struct net_device *ndev,
return false;
tmp = eport->dst_cid;
while (tmp != dst_cid && tmp != 0)
while (tmp != cid && tmp != 0)
tmp = vcap_get_next_chain(vctrl, ndev, tmp);
return !!tmp;
......@@ -2246,6 +2245,11 @@ int vcap_add_rule(struct vcap_rule *rule)
if (move.count > 0)
vcap_move_rules(ri, &move);
/* Set the counter to zero */
ret = vcap_write_counter(ri, &ctr);
if (ret)
goto out;
if (ri->state == VCAP_RS_DISABLED) {
/* Erase the rule area */
ri->vctrl->ops->init(ri->ndev, ri->admin, ri->addr, ri->size);
......@@ -2264,8 +2268,6 @@ int vcap_add_rule(struct vcap_rule *rule)
pr_err("%s:%d: rule write error: %d\n", __func__, __LINE__, ret);
goto out;
}
/* Set the counter to zero */
ret = vcap_write_counter(ri, &ctr);
out:
mutex_unlock(&ri->admin->lock);
return ret;
......
......@@ -387,7 +387,7 @@ static const char * const test_admin_info_expect[] = {
"default_cnt: 73\n",
"require_cnt_dis: 0\n",
"version: 1\n",
"vtype: 2\n",
"vtype: 3\n",
"vinst: 0\n",
"ingress: 1\n",
"first_cid: 10000\n",
......@@ -435,7 +435,7 @@ static const char * const test_admin_expect[] = {
"default_cnt: 73\n",
"require_cnt_dis: 0\n",
"version: 1\n",
"vtype: 2\n",
"vtype: 3\n",
"vinst: 0\n",
"ingress: 1\n",
"first_cid: 8000000\n",
......
......@@ -1337,8 +1337,8 @@ static void vcap_api_encode_rule_test(struct kunit *test)
u32 port_mask_rng_mask = 0x0f;
u32 igr_port_mask_value = 0xffabcd01;
u32 igr_port_mask_mask = ~0;
/* counter is written as the last operation */
u32 expwriteaddr[] = {792, 793, 794, 795, 796, 797, 792};
/* counter is written as the first operation */
u32 expwriteaddr[] = {792, 792, 793, 794, 795, 796, 797};
int idx;
vcap_test_api_init(&is2_admin);
......
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries.
/* Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP test model interface for kunit testing
*/
/* This file is autogenerated by cml-utils 2023-02-10 11:16:00 +0100.
* Commit ID: c30fb4bf0281cd4a7133bdab6682f9e43c872ada
*/
#ifndef __VCAP_MODEL_KUNIT_H__
#define __VCAP_MODEL_KUNIT_H__
/* VCAPs */
extern const struct vcap_info kunit_test_vcaps[];
extern const struct vcap_statistics kunit_test_vcap_stats;
#endif /* __VCAP_MODEL_KUNIT_H__ */
......@@ -235,6 +235,9 @@ int vcap_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st,
goto out;
}
if (mt.mask->vlan_tpid)
st->tpid = be16_to_cpu(mt.key->vlan_tpid);
st->used_keys |= BIT(FLOW_DISSECTOR_KEY_VLAN);
return 0;
......
......@@ -13,6 +13,7 @@ struct vcap_tc_flower_parse_usage {
struct vcap_admin *admin;
u16 l3_proto;
u8 l4_proto;
u16 tpid;
unsigned int used_keys;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment