提交 8fdf6659 编写于 作者: P 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: NPaolo Abeni <pabeni@redhat.com>
......@@ -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 */
......
......@@ -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);
......
......@@ -28,6 +28,31 @@ struct sparx5_multiple_rules {
struct sparx5_wildcard_rule rule[SPX5_MAX_RULE_SIZE];
};
static int
sparx5_tc_flower_es0_tpid(struct vcap_tc_flower_parse_usage *st)
{
int err = 0;
switch (st->tpid) {
case ETH_P_8021Q:
err = vcap_rule_add_key_u32(st->vrule,
VCAP_KF_8021Q_TPID,
SPX5_TPID_SEL_8100, ~0);
break;
case ETH_P_8021AD:
err = vcap_rule_add_key_u32(st->vrule,
VCAP_KF_8021Q_TPID,
SPX5_TPID_SEL_88A8, ~0);
break;
default:
NL_SET_ERR_MSG_MOD(st->fco->common.extack,
"Invalid vlan proto");
err = -EINVAL;
break;
}
return err;
}
static int
sparx5_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st)
{
......@@ -168,13 +193,21 @@ sparx5_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st)
{
enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS;
enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS;
int err;
if (st->admin->vtype == VCAP_TYPE_IS0) {
vid_key = VCAP_KF_8021Q_VID0;
pcp_key = VCAP_KF_8021Q_PCP0;
}
return vcap_tc_flower_handler_vlan_usage(st, vid_key, pcp_key);
err = vcap_tc_flower_handler_vlan_usage(st, vid_key, pcp_key);
if (err)
return err;
if (st->admin->vtype == VCAP_TYPE_ES0 && st->tpid)
err = sparx5_tc_flower_es0_tpid(st);
return err;
}
static int (*sparx5_tc_flower_usage_handlers[])(struct vcap_tc_flower_parse_usage *st) = {
......@@ -191,38 +224,28 @@ static int (*sparx5_tc_flower_usage_handlers[])(struct vcap_tc_flower_parse_usag
[FLOW_DISSECTOR_KEY_IP] = vcap_tc_flower_handler_ip_usage,
};
static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco,
static int sparx5_tc_use_dissectors(struct vcap_tc_flower_parse_usage *st,
struct vcap_admin *admin,
struct vcap_rule *vrule,
u16 *l3_proto)
struct vcap_rule *vrule)
{
struct vcap_tc_flower_parse_usage state = {
.fco = fco,
.vrule = vrule,
.l3_proto = ETH_P_ALL,
.admin = admin,
};
int idx, err = 0;
state.frule = flow_cls_offload_flow_rule(fco);
for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) {
if (!flow_rule_match_key(state.frule, idx))
if (!flow_rule_match_key(st->frule, idx))
continue;
if (!sparx5_tc_flower_usage_handlers[idx])
continue;
err = sparx5_tc_flower_usage_handlers[idx](&state);
err = sparx5_tc_flower_usage_handlers[idx](st);
if (err)
return err;
}
if (state.frule->match.dissector->used_keys ^ state.used_keys) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
if (st->frule->match.dissector->used_keys ^ st->used_keys) {
NL_SET_ERR_MSG_MOD(st->fco->common.extack,
"Unsupported match item");
return -ENOENT;
}
if (l3_proto)
*l3_proto = state.l3_proto;
return err;
}
......@@ -281,6 +304,27 @@ static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
return -EOPNOTSUPP;
}
if (action_mask & BIT(FLOW_ACTION_VLAN_PUSH) &&
action_mask & BIT(FLOW_ACTION_VLAN_POP)) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Cannot combine vlan push and pop action");
return -EOPNOTSUPP;
}
if (action_mask & BIT(FLOW_ACTION_VLAN_PUSH) &&
action_mask & BIT(FLOW_ACTION_VLAN_MANGLE)) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Cannot combine vlan push and modify action");
return -EOPNOTSUPP;
}
if (action_mask & BIT(FLOW_ACTION_VLAN_POP) &&
action_mask & BIT(FLOW_ACTION_VLAN_MANGLE)) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Cannot combine vlan pop and modify action");
return -EOPNOTSUPP;
}
return 0;
}
......@@ -290,14 +334,29 @@ static int sparx5_tc_add_rule_counter(struct vcap_admin *admin,
{
int err;
if (admin->vtype == VCAP_TYPE_IS2 || admin->vtype == VCAP_TYPE_ES2) {
switch (admin->vtype) {
case VCAP_TYPE_IS0:
break;
case VCAP_TYPE_ES0:
err = vcap_rule_mod_action_u32(vrule, VCAP_AF_ESDX,
vrule->id);
if (err)
return err;
vcap_rule_set_counter_id(vrule, vrule->id);
break;
case VCAP_TYPE_IS2:
case VCAP_TYPE_ES2:
err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID,
vrule->id);
if (err)
return err;
vcap_rule_set_counter_id(vrule, vrule->id);
break;
default:
pr_err("%s:%d: vcap type: %d not supported\n",
__func__, __LINE__, admin->vtype);
break;
}
return 0;
}
......@@ -493,10 +552,14 @@ static int sparx5_tc_set_actionset(struct vcap_admin *admin,
case VCAP_TYPE_IS2:
aset = VCAP_AFS_BASE_TYPE;
break;
case VCAP_TYPE_ES0:
aset = VCAP_AFS_ES0;
break;
case VCAP_TYPE_ES2:
aset = VCAP_AFS_BASE_TYPE;
break;
default:
pr_err("%s:%d: %s\n", __func__, __LINE__, "Invalid VCAP type");
return -EINVAL;
}
/* Do not overwrite any current actionset */
......@@ -532,6 +595,7 @@ static int sparx5_tc_add_rule_link_target(struct vcap_admin *admin,
return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG,
link_val, /* target */
~0);
case VCAP_TYPE_ES0:
case VCAP_TYPE_ES2:
/* Add ISDX key for chaining rules from IS0 */
return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS, link_val,
......@@ -551,12 +615,16 @@ static int sparx5_tc_add_rule_link(struct vcap_control *vctrl,
struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid);
int diff, err = 0;
diff = vcap_chain_offset(vctrl, from_cid, to_cid);
if (!(to_admin && diff > 0)) {
if (!to_admin) {
pr_err("%s:%d: unsupported chain direction: %d\n",
__func__, __LINE__, to_cid);
return -EINVAL;
}
diff = vcap_chain_offset(vctrl, from_cid, to_cid);
if (!diff)
return 0;
if (admin->vtype == VCAP_TYPE_IS0 &&
to_admin->vtype == VCAP_TYPE_IS0) {
/* Between IS0 instances the G_IDX value is used */
......@@ -579,8 +647,9 @@ static int sparx5_tc_add_rule_link(struct vcap_control *vctrl,
if (err)
goto out;
} else if (admin->vtype == VCAP_TYPE_IS0 &&
to_admin->vtype == VCAP_TYPE_ES2) {
/* Between IS0 and ES2 the ISDX value is used */
(to_admin->vtype == VCAP_TYPE_ES0 ||
to_admin->vtype == VCAP_TYPE_ES2)) {
/* Between IS0 and ES0/ES2 the ISDX value is used */
err = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL,
diff);
if (err)
......@@ -731,6 +800,202 @@ static int sparx5_tc_flower_psfp_setup(struct sparx5 *sparx5,
return 0;
}
/* Handle the action trap for a VCAP rule */
static int sparx5_tc_action_trap(struct vcap_admin *admin,
struct vcap_rule *vrule,
struct flow_cls_offload *fco)
{
int err = 0;
switch (admin->vtype) {
case VCAP_TYPE_IS2:
err = vcap_rule_add_action_bit(vrule,
VCAP_AF_CPU_COPY_ENA,
VCAP_BIT_1);
if (err)
break;
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_CPU_QUEUE_NUM, 0);
if (err)
break;
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_MASK_MODE,
SPX5_PMM_REPLACE_ALL);
break;
case VCAP_TYPE_ES0:
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_FWD_SEL,
SPX5_FWSEL_REDIRECT_TO_LOOPBACK);
break;
case VCAP_TYPE_ES2:
err = vcap_rule_add_action_bit(vrule,
VCAP_AF_CPU_COPY_ENA,
VCAP_BIT_1);
if (err)
break;
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_CPU_QUEUE_NUM, 0);
break;
default:
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Trap action not supported in this VCAP");
err = -EOPNOTSUPP;
break;
}
return err;
}
static int sparx5_tc_action_vlan_pop(struct vcap_admin *admin,
struct vcap_rule *vrule,
struct flow_cls_offload *fco,
u16 tpid)
{
int err = 0;
switch (admin->vtype) {
case VCAP_TYPE_ES0:
break;
default:
NL_SET_ERR_MSG_MOD(fco->common.extack,
"VLAN pop action not supported in this VCAP");
return -EOPNOTSUPP;
}
switch (tpid) {
case ETH_P_8021Q:
case ETH_P_8021AD:
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_PUSH_OUTER_TAG,
SPX5_OTAG_UNTAG);
break;
default:
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Invalid vlan proto");
err = -EINVAL;
}
return err;
}
static int sparx5_tc_action_vlan_modify(struct vcap_admin *admin,
struct vcap_rule *vrule,
struct flow_cls_offload *fco,
struct flow_action_entry *act,
u16 tpid)
{
int err = 0;
switch (admin->vtype) {
case VCAP_TYPE_ES0:
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_PUSH_OUTER_TAG,
SPX5_OTAG_TAG_A);
if (err)
return err;
break;
default:
NL_SET_ERR_MSG_MOD(fco->common.extack,
"VLAN modify action not supported in this VCAP");
return -EOPNOTSUPP;
}
switch (tpid) {
case ETH_P_8021Q:
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_TAG_A_TPID_SEL,
SPX5_TPID_A_8100);
break;
case ETH_P_8021AD:
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_TAG_A_TPID_SEL,
SPX5_TPID_A_88A8);
break;
default:
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Invalid vlan proto");
err = -EINVAL;
}
if (err)
return err;
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_TAG_A_VID_SEL,
SPX5_VID_A_VAL);
if (err)
return err;
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_VID_A_VAL,
act->vlan.vid);
if (err)
return err;
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_TAG_A_PCP_SEL,
SPX5_PCP_A_VAL);
if (err)
return err;
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_PCP_A_VAL,
act->vlan.prio);
if (err)
return err;
return vcap_rule_add_action_u32(vrule,
VCAP_AF_TAG_A_DEI_SEL,
SPX5_DEI_A_CLASSIFIED);
}
static int sparx5_tc_action_vlan_push(struct vcap_admin *admin,
struct vcap_rule *vrule,
struct flow_cls_offload *fco,
struct flow_action_entry *act,
u16 tpid)
{
u16 act_tpid = be16_to_cpu(act->vlan.proto);
int err = 0;
switch (admin->vtype) {
case VCAP_TYPE_ES0:
break;
default:
NL_SET_ERR_MSG_MOD(fco->common.extack,
"VLAN push action not supported in this VCAP");
return -EOPNOTSUPP;
}
if (tpid == ETH_P_8021AD) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Cannot push on double tagged frames");
return -EOPNOTSUPP;
}
err = sparx5_tc_action_vlan_modify(admin, vrule, fco, act, act_tpid);
if (err)
return err;
switch (act_tpid) {
case ETH_P_8021Q:
break;
case ETH_P_8021AD:
/* Push classified tag as inner tag */
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_PUSH_INNER_TAG,
SPX5_ITAG_PUSH_B_TAG);
if (err)
break;
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_TAG_B_TPID_SEL,
SPX5_TPID_B_CLASSIFIED);
break;
default:
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Invalid vlan proto");
err = -EINVAL;
}
return err;
}
static int sparx5_tc_flower_replace(struct net_device *ndev,
struct flow_cls_offload *fco,
struct vcap_admin *admin,
......@@ -739,6 +1004,11 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
struct sparx5_psfp_sf sf = { .max_sdu = SPX5_PSFP_SF_MAX_SDU };
struct netlink_ext_ack *extack = fco->common.extack;
int err, idx, tc_sg_idx = -1, tc_pol_idx = -1;
struct vcap_tc_flower_parse_usage state = {
.fco = fco,
.l3_proto = ETH_P_ALL,
.admin = admin,
};
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5_multiple_rules multi = {};
struct sparx5 *sparx5 = port->sparx5;
......@@ -748,7 +1018,6 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
struct vcap_control *vctrl;
struct flow_rule *frule;
struct vcap_rule *vrule;
u16 l3_proto;
vctrl = port->sparx5->vcap_ctrl;
......@@ -763,8 +1032,9 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
vrule->cookie = fco->cookie;
l3_proto = ETH_P_ALL;
err = sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto);
state.vrule = vrule;
state.frule = flow_cls_offload_flow_rule(fco);
err = sparx5_tc_use_dissectors(&state, admin, vrule);
if (err)
goto out;
......@@ -801,27 +1071,7 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
break;
}
case FLOW_ACTION_TRAP:
if (admin->vtype != VCAP_TYPE_IS2 &&
admin->vtype != VCAP_TYPE_ES2) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Trap action not supported in this VCAP");
err = -EOPNOTSUPP;
goto out;
}
err = vcap_rule_add_action_bit(vrule,
VCAP_AF_CPU_COPY_ENA,
VCAP_BIT_1);
if (err)
goto out;
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_CPU_QUEUE_NUM, 0);
if (err)
goto out;
if (admin->vtype != VCAP_TYPE_IS2)
break;
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_MASK_MODE,
SPX5_PMM_REPLACE_ALL);
err = sparx5_tc_action_trap(admin, vrule, fco);
if (err)
goto out;
break;
......@@ -838,6 +1088,24 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
fco->common.chain_index,
act->chain_index);
break;
case FLOW_ACTION_VLAN_POP:
err = sparx5_tc_action_vlan_pop(admin, vrule, fco,
state.tpid);
if (err)
goto out;
break;
case FLOW_ACTION_VLAN_PUSH:
err = sparx5_tc_action_vlan_push(admin, vrule, fco,
act, state.tpid);
if (err)
goto out;
break;
case FLOW_ACTION_VLAN_MANGLE:
err = sparx5_tc_action_vlan_modify(admin, vrule, fco,
act, state.tpid);
if (err)
goto out;
break;
default:
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Unsupported TC action");
......@@ -854,8 +1122,8 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
goto out;
}
err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin, l3_proto,
&multi);
err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin,
state.l3_proto, &multi);
if (err) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
"No matching port keyset for filter protocol and keys");
......@@ -863,7 +1131,7 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
}
/* provide the l3 protocol to guide the keyset selection */
err = vcap_val_rule(vrule, l3_proto);
err = vcap_val_rule(vrule, state.l3_proto);
if (err) {
vcap_set_tc_exterr(fco, vrule);
goto out;
......@@ -873,7 +1141,7 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Could not add the filter");
if (l3_proto == ETH_P_ALL)
if (state.l3_proto == ETH_P_ALL)
err = sparx5_tc_add_remaining_rules(vctrl, fco, vrule, admin,
&multi);
......
......@@ -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);
......
......@@ -37,6 +37,11 @@
ANA_CL_ADV_CL_CFG_MPLS_MC_CLM_KEY_SEL_SET(_mpls_mc) | \
ANA_CL_ADV_CL_CFG_MLBS_CLM_KEY_SEL_SET(_mlbs))
#define SPARX5_ES0_LOOKUPS 1
#define VCAP_ES0_KEYSEL(_key) (REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA_SET(_key))
#define SPARX5_STAT_ESDX_GRN_PKTS 0x300
#define SPARX5_STAT_ESDX_YEL_PKTS 0x301
#define SPARX5_ES2_LOOKUPS 2
#define VCAP_ES2_KEYSEL(_ena, _arp, _ipv4, _ipv6) \
(EACL_VCAP_ES2_KEY_SEL_KEY_ENA_SET(_ena) | \
......@@ -117,6 +122,15 @@ static struct sparx5_vcap_inst {
.blocks = 2,
.ingress = true,
},
{
.vtype = VCAP_TYPE_ES0,
.lookups = SPARX5_ES0_LOOKUPS,
.lookups_per_instance = SPARX5_ES0_LOOKUPS,
.first_cid = SPARX5_VCAP_CID_ES0_L0,
.last_cid = SPARX5_VCAP_CID_ES0_MAX,
.count = 4096, /* Addresses according to datasheet */
.ingress = false,
},
{
.vtype = VCAP_TYPE_ES2,
.lookups = SPARX5_ES2_LOOKUPS,
......@@ -169,6 +183,16 @@ static void sparx5_vcap_wait_super_update(struct sparx5 *sparx5)
false, sparx5, VCAP_SUPER_CTRL);
}
/* Await the ES0 VCAP completion of the current operation */
static void sparx5_vcap_wait_es0_update(struct sparx5 *sparx5)
{
u32 value;
read_poll_timeout(spx5_rd, value,
!VCAP_ES0_CTRL_UPDATE_SHOT_GET(value), 500, 10000,
false, sparx5, VCAP_ES0_CTRL);
}
/* Await the ES2 VCAP completion of the current operation */
static void sparx5_vcap_wait_es2_update(struct sparx5 *sparx5)
{
......@@ -202,6 +226,20 @@ static void _sparx5_vcap_range_init(struct sparx5 *sparx5,
sparx5, VCAP_SUPER_CTRL);
sparx5_vcap_wait_super_update(sparx5);
break;
case VCAP_TYPE_ES0:
spx5_wr(VCAP_ES0_CFG_MV_NUM_POS_SET(0) |
VCAP_ES0_CFG_MV_SIZE_SET(size),
sparx5, VCAP_ES0_CFG);
spx5_wr(VCAP_ES0_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) |
VCAP_ES0_CTRL_UPDATE_ENTRY_DIS_SET(0) |
VCAP_ES0_CTRL_UPDATE_ACTION_DIS_SET(0) |
VCAP_ES0_CTRL_UPDATE_CNT_DIS_SET(0) |
VCAP_ES0_CTRL_UPDATE_ADDR_SET(addr) |
VCAP_ES0_CTRL_CLEAR_CACHE_SET(true) |
VCAP_ES0_CTRL_UPDATE_SHOT_SET(true),
sparx5, VCAP_ES0_CTRL);
sparx5_vcap_wait_es0_update(sparx5);
break;
case VCAP_TYPE_ES2:
spx5_wr(VCAP_ES2_CFG_MV_NUM_POS_SET(0) |
VCAP_ES2_CFG_MV_SIZE_SET(size),
......@@ -563,6 +601,30 @@ sparx5_vcap_es2_get_port_ipv4_keysets(struct vcap_keyset_list *keysetlist,
}
}
/* Return the list of keysets for the vcap port configuration */
static int sparx5_vcap_es0_get_port_keysets(struct net_device *ndev,
struct vcap_keyset_list *keysetlist,
u16 l3_proto)
{
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5 *sparx5 = port->sparx5;
int portno = port->portno;
u32 value;
value = spx5_rd(sparx5, REW_RTAG_ETAG_CTRL(portno));
/* Collect all keysets for the port in a list */
switch (REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA_GET(value)) {
case VCAP_ES0_PS_NORMAL_SELECTION:
case VCAP_ES0_PS_FORCE_ISDX_LOOKUPS:
vcap_keyset_list_add(keysetlist, VCAP_KFS_ISDX);
break;
default:
break;
}
return 0;
}
/* Return the list of keysets for the vcap port configuration */
static int sparx5_vcap_es2_get_port_keysets(struct net_device *ndev,
int lookup,
......@@ -647,6 +709,9 @@ int sparx5_vcap_get_port_keyset(struct net_device *ndev,
err = sparx5_vcap_is2_get_port_keysets(ndev, lookup, kslist,
l3_proto);
break;
case VCAP_TYPE_ES0:
err = sparx5_vcap_es0_get_port_keysets(ndev, kslist, l3_proto);
break;
case VCAP_TYPE_ES2:
lookup = sparx5_vcap_es2_cid_to_lookup(cid);
err = sparx5_vcap_es2_get_port_keysets(ndev, lookup, kslist,
......@@ -675,6 +740,8 @@ bool sparx5_vcap_is_known_etype(struct vcap_admin *admin, u16 etype)
known_etypes = sparx5_vcap_is2_known_etypes;
size = ARRAY_SIZE(sparx5_vcap_is2_known_etypes);
break;
case VCAP_TYPE_ES0:
return true;
case VCAP_TYPE_ES2:
known_etypes = sparx5_vcap_es2_known_etypes;
size = ARRAY_SIZE(sparx5_vcap_es2_known_etypes);
......@@ -719,6 +786,9 @@ sparx5_vcap_validate_keyset(struct net_device *ndev,
sparx5_vcap_is2_get_port_keysets(ndev, lookup, &keysetlist,
l3_proto);
break;
case VCAP_TYPE_ES0:
sparx5_vcap_es0_get_port_keysets(ndev, &keysetlist, l3_proto);
break;
case VCAP_TYPE_ES2:
lookup = sparx5_vcap_es2_cid_to_lookup(rule->vcap_chain_id);
sparx5_vcap_es2_get_port_keysets(ndev, lookup, &keysetlist,
......@@ -775,6 +845,18 @@ static void sparx5_vcap_ingress_add_default_fields(struct net_device *ndev,
VCAP_BIT_0);
}
static void sparx5_vcap_es0_add_default_fields(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_rule *rule)
{
struct sparx5_port *port = netdev_priv(ndev);
vcap_rule_add_key_u32(rule, VCAP_KF_IF_EGR_PORT_NO, port->portno, ~0);
/* Match untagged frames if there was no VLAN key */
vcap_rule_add_key_u32(rule, VCAP_KF_8021Q_TPID, SPX5_TPID_SEL_UNTAGGED,
~0);
}
static void sparx5_vcap_es2_add_default_fields(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_rule *rule)
......@@ -811,6 +893,9 @@ static void sparx5_vcap_add_default_fields(struct net_device *ndev,
case VCAP_TYPE_IS2:
sparx5_vcap_ingress_add_default_fields(ndev, admin, rule);
break;
case VCAP_TYPE_ES0:
sparx5_vcap_es0_add_default_fields(ndev, admin, rule);
break;
case VCAP_TYPE_ES2:
sparx5_vcap_es2_add_default_fields(ndev, admin, rule);
break;
......@@ -919,6 +1004,59 @@ static void sparx5_vcap_is2_cache_write(struct sparx5 *sparx5,
}
}
/* Use ESDX counters located in the XQS */
static void sparx5_es0_write_esdx_counter(struct sparx5 *sparx5,
struct vcap_admin *admin, u32 id)
{
mutex_lock(&sparx5->queue_stats_lock);
spx5_wr(XQS_STAT_CFG_STAT_VIEW_SET(id), sparx5, XQS_STAT_CFG);
spx5_wr(admin->cache.counter, sparx5,
XQS_CNT(SPARX5_STAT_ESDX_GRN_PKTS));
spx5_wr(0, sparx5, XQS_CNT(SPARX5_STAT_ESDX_YEL_PKTS));
mutex_unlock(&sparx5->queue_stats_lock);
}
static void sparx5_vcap_es0_cache_write(struct sparx5 *sparx5,
struct vcap_admin *admin,
enum vcap_selection sel,
u32 start,
u32 count)
{
u32 *keystr, *mskstr, *actstr;
int idx;
keystr = &admin->cache.keystream[start];
mskstr = &admin->cache.maskstream[start];
actstr = &admin->cache.actionstream[start];
switch (sel) {
case VCAP_SEL_ENTRY:
for (idx = 0; idx < count; ++idx) {
/* Avoid 'match-off' by setting value & mask */
spx5_wr(keystr[idx] & mskstr[idx], sparx5,
VCAP_ES0_VCAP_ENTRY_DAT(idx));
spx5_wr(~mskstr[idx], sparx5,
VCAP_ES0_VCAP_MASK_DAT(idx));
}
break;
case VCAP_SEL_ACTION:
for (idx = 0; idx < count; ++idx)
spx5_wr(actstr[idx], sparx5,
VCAP_ES0_VCAP_ACTION_DAT(idx));
break;
case VCAP_SEL_ALL:
pr_err("%s:%d: cannot write all streams at once\n",
__func__, __LINE__);
break;
default:
break;
}
if (sel & VCAP_SEL_COUNTER) {
spx5_wr(admin->cache.counter, sparx5, VCAP_ES0_VCAP_CNT_DAT(0));
sparx5_es0_write_esdx_counter(sparx5, admin, start);
}
}
static void sparx5_vcap_es2_cache_write(struct sparx5 *sparx5,
struct vcap_admin *admin,
enum vcap_selection sel,
......@@ -978,6 +1116,9 @@ static void sparx5_vcap_cache_write(struct net_device *ndev,
case VCAP_TYPE_IS2:
sparx5_vcap_is2_cache_write(sparx5, admin, sel, start, count);
break;
case VCAP_TYPE_ES0:
sparx5_vcap_es0_cache_write(sparx5, admin, sel, start, count);
break;
case VCAP_TYPE_ES2:
sparx5_vcap_es2_cache_write(sparx5, admin, sel, start, count);
break;
......@@ -1062,6 +1203,56 @@ static void sparx5_vcap_is2_cache_read(struct sparx5 *sparx5,
}
}
/* Use ESDX counters located in the XQS */
static void sparx5_es0_read_esdx_counter(struct sparx5 *sparx5,
struct vcap_admin *admin, u32 id)
{
u32 counter;
mutex_lock(&sparx5->queue_stats_lock);
spx5_wr(XQS_STAT_CFG_STAT_VIEW_SET(id), sparx5, XQS_STAT_CFG);
counter = spx5_rd(sparx5, XQS_CNT(SPARX5_STAT_ESDX_GRN_PKTS)) +
spx5_rd(sparx5, XQS_CNT(SPARX5_STAT_ESDX_YEL_PKTS));
mutex_unlock(&sparx5->queue_stats_lock);
if (counter)
admin->cache.counter = counter;
}
static void sparx5_vcap_es0_cache_read(struct sparx5 *sparx5,
struct vcap_admin *admin,
enum vcap_selection sel,
u32 start,
u32 count)
{
u32 *keystr, *mskstr, *actstr;
int idx;
keystr = &admin->cache.keystream[start];
mskstr = &admin->cache.maskstream[start];
actstr = &admin->cache.actionstream[start];
if (sel & VCAP_SEL_ENTRY) {
for (idx = 0; idx < count; ++idx) {
keystr[idx] =
spx5_rd(sparx5, VCAP_ES0_VCAP_ENTRY_DAT(idx));
mskstr[idx] =
~spx5_rd(sparx5, VCAP_ES0_VCAP_MASK_DAT(idx));
}
}
if (sel & VCAP_SEL_ACTION)
for (idx = 0; idx < count; ++idx)
actstr[idx] =
spx5_rd(sparx5, VCAP_ES0_VCAP_ACTION_DAT(idx));
if (sel & VCAP_SEL_COUNTER) {
admin->cache.counter =
spx5_rd(sparx5, VCAP_ES0_VCAP_CNT_DAT(0));
admin->cache.sticky = admin->cache.counter;
sparx5_es0_read_esdx_counter(sparx5, admin, start);
}
}
static void sparx5_vcap_es2_cache_read(struct sparx5 *sparx5,
struct vcap_admin *admin,
enum vcap_selection sel,
......@@ -1115,6 +1306,9 @@ static void sparx5_vcap_cache_read(struct net_device *ndev,
case VCAP_TYPE_IS2:
sparx5_vcap_is2_cache_read(sparx5, admin, sel, start, count);
break;
case VCAP_TYPE_ES0:
sparx5_vcap_es0_cache_read(sparx5, admin, sel, start, count);
break;
case VCAP_TYPE_ES2:
sparx5_vcap_es2_cache_read(sparx5, admin, sel, start, count);
break;
......@@ -1154,6 +1348,25 @@ static void sparx5_vcap_super_update(struct sparx5 *sparx5,
sparx5_vcap_wait_super_update(sparx5);
}
static void sparx5_vcap_es0_update(struct sparx5 *sparx5,
enum vcap_command cmd,
enum vcap_selection sel, u32 addr)
{
bool clear = (cmd == VCAP_CMD_INITIALIZE);
spx5_wr(VCAP_ES0_CFG_MV_NUM_POS_SET(0) |
VCAP_ES0_CFG_MV_SIZE_SET(0), sparx5, VCAP_ES0_CFG);
spx5_wr(VCAP_ES0_CTRL_UPDATE_CMD_SET(cmd) |
VCAP_ES0_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) |
VCAP_ES0_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) |
VCAP_ES0_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) |
VCAP_ES0_CTRL_UPDATE_ADDR_SET(addr) |
VCAP_ES0_CTRL_CLEAR_CACHE_SET(clear) |
VCAP_ES0_CTRL_UPDATE_SHOT_SET(true),
sparx5, VCAP_ES0_CTRL);
sparx5_vcap_wait_es0_update(sparx5);
}
static void sparx5_vcap_es2_update(struct sparx5 *sparx5,
enum vcap_command cmd,
enum vcap_selection sel, u32 addr)
......@@ -1186,6 +1399,9 @@ static void sparx5_vcap_update(struct net_device *ndev,
case VCAP_TYPE_IS2:
sparx5_vcap_super_update(sparx5, cmd, sel, addr);
break;
case VCAP_TYPE_ES0:
sparx5_vcap_es0_update(sparx5, cmd, sel, addr);
break;
case VCAP_TYPE_ES2:
sparx5_vcap_es2_update(sparx5, cmd, sel, addr);
break;
......@@ -1215,6 +1431,26 @@ static void sparx5_vcap_super_move(struct sparx5 *sparx5,
sparx5_vcap_wait_super_update(sparx5);
}
static void sparx5_vcap_es0_move(struct sparx5 *sparx5,
u32 addr,
enum vcap_command cmd,
u16 mv_num_pos,
u16 mv_size)
{
spx5_wr(VCAP_ES0_CFG_MV_NUM_POS_SET(mv_num_pos) |
VCAP_ES0_CFG_MV_SIZE_SET(mv_size),
sparx5, VCAP_ES0_CFG);
spx5_wr(VCAP_ES0_CTRL_UPDATE_CMD_SET(cmd) |
VCAP_ES0_CTRL_UPDATE_ENTRY_DIS_SET(0) |
VCAP_ES0_CTRL_UPDATE_ACTION_DIS_SET(0) |
VCAP_ES0_CTRL_UPDATE_CNT_DIS_SET(0) |
VCAP_ES0_CTRL_UPDATE_ADDR_SET(addr) |
VCAP_ES0_CTRL_CLEAR_CACHE_SET(false) |
VCAP_ES0_CTRL_UPDATE_SHOT_SET(true),
sparx5, VCAP_ES0_CTRL);
sparx5_vcap_wait_es0_update(sparx5);
}
static void sparx5_vcap_es2_move(struct sparx5 *sparx5,
u32 addr,
enum vcap_command cmd,
......@@ -1259,6 +1495,9 @@ static void sparx5_vcap_move(struct net_device *ndev, struct vcap_admin *admin,
case VCAP_TYPE_IS2:
sparx5_vcap_super_move(sparx5, addr, cmd, mv_num_pos, mv_size);
break;
case VCAP_TYPE_ES0:
sparx5_vcap_es0_move(sparx5, addr, cmd, mv_num_pos, mv_size);
break;
case VCAP_TYPE_ES2:
sparx5_vcap_es2_move(sparx5, addr, cmd, mv_num_pos, mv_size);
break;
......@@ -1333,6 +1572,22 @@ static void sparx5_vcap_is2_port_key_selection(struct sparx5 *sparx5,
ANA_ACL_VCAP_S2_CFG(portno));
}
/* Enable ES0 lookups per port and set the keyset generation */
static void sparx5_vcap_es0_port_key_selection(struct sparx5 *sparx5,
struct vcap_admin *admin)
{
int portno;
u32 keysel;
keysel = VCAP_ES0_KEYSEL(VCAP_ES0_PS_FORCE_ISDX_LOOKUPS);
for (portno = 0; portno < SPX5_PORTS; ++portno)
spx5_rmw(keysel, REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA,
sparx5, REW_RTAG_ETAG_CTRL(portno));
spx5_rmw(REW_ES0_CTRL_ES0_LU_ENA_SET(1), REW_ES0_CTRL_ES0_LU_ENA,
sparx5, REW_ES0_CTRL);
}
/* Enable ES2 lookups per port and set the keyset generation */
static void sparx5_vcap_es2_port_key_selection(struct sparx5 *sparx5,
struct vcap_admin *admin)
......@@ -1360,6 +1615,9 @@ static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5,
case VCAP_TYPE_IS2:
sparx5_vcap_is2_port_key_selection(sparx5, admin);
break;
case VCAP_TYPE_ES0:
sparx5_vcap_es0_port_key_selection(sparx5, admin);
break;
case VCAP_TYPE_ES2:
sparx5_vcap_es2_port_key_selection(sparx5, admin);
break;
......@@ -1391,6 +1649,10 @@ static void sparx5_vcap_port_key_deselection(struct sparx5 *sparx5,
sparx5,
ANA_ACL_VCAP_S2_CFG(portno));
break;
case VCAP_TYPE_ES0:
spx5_rmw(REW_ES0_CTRL_ES0_LU_ENA_SET(0),
REW_ES0_CTRL_ES0_LU_ENA, sparx5, REW_ES0_CTRL);
break;
case VCAP_TYPE_ES2:
for (lookup = 0; lookup < admin->lookups; ++lookup)
for (portno = 0; portno < SPX5_PORTS; ++portno)
......@@ -1477,6 +1739,18 @@ static void sparx5_vcap_block_alloc(struct sparx5 *sparx5,
cfg->blocks * SUPER_VCAP_BLK_SIZE;
admin->last_valid_addr = admin->last_used_addr - 1;
break;
case VCAP_TYPE_ES0:
admin->first_valid_addr = 0;
admin->last_used_addr = cfg->count;
admin->last_valid_addr = cfg->count - 1;
cores = spx5_rd(sparx5, VCAP_ES0_CORE_CNT);
for (idx = 0; idx < cores; ++idx) {
spx5_wr(VCAP_ES0_IDX_CORE_IDX_SET(idx), sparx5,
VCAP_ES0_IDX);
spx5_wr(VCAP_ES0_MAP_CORE_MAP_SET(1), sparx5,
VCAP_ES0_MAP);
}
break;
case VCAP_TYPE_ES2:
admin->first_valid_addr = 0;
admin->last_used_addr = cfg->count;
......
......@@ -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 */
......
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册