Commit 65718c4d authored by David S. Miller's avatar David S. Miller

Merge branch 'lan966x-es0-vcap'

Horatiu Vultur says:

====================
net: lan966x: Add support for ES0 VCAP

Provide the Egress Stage 0 (ES0) VCAP (Versatile Content-Aware
Processor) support for the lan966x platform.

The ES0 VCAP has only 1 lookup which is accessible with a TC chain
id 10000000.

Currently only one action is support which is vlan pop. Also it is
possible to link the IS1 to ES0 using 'goto chain 10000000'.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 81ac2722 85f05000
...@@ -101,6 +101,9 @@ ...@@ -101,6 +101,9 @@
#define LAN966X_VCAP_CID_IS2_L1 VCAP_CID_INGRESS_STAGE2_L1 /* IS2 lookup 1 */ #define LAN966X_VCAP_CID_IS2_L1 VCAP_CID_INGRESS_STAGE2_L1 /* IS2 lookup 1 */
#define LAN966X_VCAP_CID_IS2_MAX (VCAP_CID_INGRESS_STAGE2_L2 - 1) /* IS2 Max */ #define LAN966X_VCAP_CID_IS2_MAX (VCAP_CID_INGRESS_STAGE2_L2 - 1) /* IS2 Max */
#define LAN966X_VCAP_CID_ES0_L0 VCAP_CID_EGRESS_L0 /* ES0 lookup 0 */
#define LAN966X_VCAP_CID_ES0_MAX (VCAP_CID_EGRESS_L1 - 1) /* ES0 Max */
/* MAC table entry types. /* MAC table entry types.
* ENTRYTYPE_NORMAL is subject to aging. * ENTRYTYPE_NORMAL is subject to aging.
* ENTRYTYPE_LOCKED is not subject to aging. * ENTRYTYPE_LOCKED is not subject to aging.
......
...@@ -1471,12 +1471,27 @@ enum lan966x_target { ...@@ -1471,12 +1471,27 @@ enum lan966x_target {
/* REW:PORT:PORT_CFG */ /* REW:PORT:PORT_CFG */
#define REW_PORT_CFG(g) __REG(TARGET_REW, 0, 1, 0, g, 10, 128, 8, 0, 1, 4) #define REW_PORT_CFG(g) __REG(TARGET_REW, 0, 1, 0, g, 10, 128, 8, 0, 1, 4)
#define REW_PORT_CFG_ES0_EN BIT(4)
#define REW_PORT_CFG_ES0_EN_SET(x)\
FIELD_PREP(REW_PORT_CFG_ES0_EN, x)
#define REW_PORT_CFG_ES0_EN_GET(x)\
FIELD_GET(REW_PORT_CFG_ES0_EN, x)
#define REW_PORT_CFG_NO_REWRITE BIT(0) #define REW_PORT_CFG_NO_REWRITE BIT(0)
#define REW_PORT_CFG_NO_REWRITE_SET(x)\ #define REW_PORT_CFG_NO_REWRITE_SET(x)\
FIELD_PREP(REW_PORT_CFG_NO_REWRITE, x) FIELD_PREP(REW_PORT_CFG_NO_REWRITE, x)
#define REW_PORT_CFG_NO_REWRITE_GET(x)\ #define REW_PORT_CFG_NO_REWRITE_GET(x)\
FIELD_GET(REW_PORT_CFG_NO_REWRITE, x) FIELD_GET(REW_PORT_CFG_NO_REWRITE, x)
/* REW:COMMON:STAT_CFG */
#define REW_STAT_CFG __REG(TARGET_REW, 0, 1, 3072, 0, 1, 528, 520, 0, 1, 4)
#define REW_STAT_CFG_STAT_MODE GENMASK(1, 0)
#define REW_STAT_CFG_STAT_MODE_SET(x)\
FIELD_PREP(REW_STAT_CFG_STAT_MODE, x)
#define REW_STAT_CFG_STAT_MODE_GET(x)\
FIELD_GET(REW_STAT_CFG_STAT_MODE, x)
/* SYS:SYSTEM:RESET_CFG */ /* SYS:SYSTEM:RESET_CFG */
#define SYS_RESET_CFG __REG(TARGET_SYS, 0, 1, 4128, 0, 1, 168, 0, 0, 1, 4) #define SYS_RESET_CFG __REG(TARGET_SYS, 0, 1, 4128, 0, 1, 168, 0, 0, 1, 4)
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "vcap_api_client.h" #include "vcap_api_client.h"
#include "vcap_tc.h" #include "vcap_tc.h"
#define LAN966X_FORCE_UNTAGED 3
static bool lan966x_tc_is_known_etype(struct vcap_tc_flower_parse_usage *st, static bool lan966x_tc_is_known_etype(struct vcap_tc_flower_parse_usage *st,
u16 etype) u16 etype)
{ {
...@@ -29,6 +31,8 @@ static bool lan966x_tc_is_known_etype(struct vcap_tc_flower_parse_usage *st, ...@@ -29,6 +31,8 @@ static bool lan966x_tc_is_known_etype(struct vcap_tc_flower_parse_usage *st,
return true; return true;
} }
break; break;
case VCAP_TYPE_ES0:
return true;
default: default:
NL_SET_ERR_MSG_MOD(st->fco->common.extack, NL_SET_ERR_MSG_MOD(st->fco->common.extack,
"VCAP type not supported"); "VCAP type not supported");
...@@ -318,6 +322,9 @@ static int lan966x_tc_set_actionset(struct vcap_admin *admin, ...@@ -318,6 +322,9 @@ static int lan966x_tc_set_actionset(struct vcap_admin *admin,
case VCAP_TYPE_IS2: case VCAP_TYPE_IS2:
aset = VCAP_AFS_BASE_TYPE; aset = VCAP_AFS_BASE_TYPE;
break; break;
case VCAP_TYPE_ES0:
aset = VCAP_AFS_VID;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -353,6 +360,10 @@ static int lan966x_tc_add_rule_link_target(struct vcap_admin *admin, ...@@ -353,6 +360,10 @@ static int lan966x_tc_add_rule_link_target(struct vcap_admin *admin,
/* Add IS2 specific PAG key (for chaining rules from IS1) */ /* Add IS2 specific PAG key (for chaining rules from IS1) */
return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG, return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG,
link_val, ~0); link_val, ~0);
case VCAP_TYPE_ES0:
/* Add ES0 specific ISDX key (for chaining rules from IS1) */
return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS,
link_val, ~0);
default: default:
break; break;
} }
...@@ -389,6 +400,18 @@ static int lan966x_tc_add_rule_link(struct vcap_control *vctrl, ...@@ -389,6 +400,18 @@ static int lan966x_tc_add_rule_link(struct vcap_control *vctrl,
0xff); 0xff);
if (err) if (err)
return err; return err;
} else if (admin->vtype == VCAP_TYPE_IS1 &&
to_admin->vtype == VCAP_TYPE_ES0) {
/* This works for IS1->ES0 */
err = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_ADD_VAL,
diff);
if (err)
return err;
err = vcap_rule_add_action_bit(vrule, VCAP_AF_ISDX_REPLACE_ENA,
VCAP_BIT_1);
if (err)
return err;
} else { } else {
NL_SET_ERR_MSG_MOD(f->common.extack, NL_SET_ERR_MSG_MOD(f->common.extack,
"Unsupported chain destination"); "Unsupported chain destination");
...@@ -398,6 +421,23 @@ static int lan966x_tc_add_rule_link(struct vcap_control *vctrl, ...@@ -398,6 +421,23 @@ static int lan966x_tc_add_rule_link(struct vcap_control *vctrl,
return err; return err;
} }
static int lan966x_tc_add_rule_counter(struct vcap_admin *admin,
struct vcap_rule *vrule)
{
int err = 0;
switch (admin->vtype) {
case VCAP_TYPE_ES0:
err = vcap_rule_mod_action_u32(vrule, VCAP_AF_ESDX,
vrule->id);
break;
default:
break;
}
return err;
}
static int lan966x_tc_flower_add(struct lan966x_port *port, static int lan966x_tc_flower_add(struct lan966x_port *port,
struct flow_cls_offload *f, struct flow_cls_offload *f,
struct vcap_admin *admin, struct vcap_admin *admin,
...@@ -465,6 +505,21 @@ static int lan966x_tc_flower_add(struct lan966x_port *port, ...@@ -465,6 +505,21 @@ static int lan966x_tc_flower_add(struct lan966x_port *port,
if (err) if (err)
goto out; goto out;
break;
case FLOW_ACTION_VLAN_POP:
if (admin->vtype != VCAP_TYPE_ES0) {
NL_SET_ERR_MSG_MOD(f->common.extack,
"Cannot use vlan pop on non es0");
err = -EOPNOTSUPP;
goto out;
}
/* Force untag */
err = vcap_rule_add_action_u32(vrule, VCAP_AF_PUSH_OUTER_TAG,
LAN966X_FORCE_UNTAGED);
if (err)
goto out;
break; break;
default: default:
NL_SET_ERR_MSG_MOD(f->common.extack, NL_SET_ERR_MSG_MOD(f->common.extack,
...@@ -474,6 +529,12 @@ static int lan966x_tc_flower_add(struct lan966x_port *port, ...@@ -474,6 +529,12 @@ static int lan966x_tc_flower_add(struct lan966x_port *port,
} }
} }
err = lan966x_tc_add_rule_counter(admin, vrule);
if (err) {
vcap_set_tc_exterr(f, vrule);
goto out;
}
err = vcap_val_rule(vrule, l3_proto); err = vcap_val_rule(vrule, l3_proto);
if (err) { if (err) {
vcap_set_tc_exterr(f, vrule); vcap_set_tc_exterr(f, vrule);
......
...@@ -190,6 +190,26 @@ static void lan966x_vcap_is2_port_keys(struct lan966x_port *port, ...@@ -190,6 +190,26 @@ static void lan966x_vcap_is2_port_keys(struct lan966x_port *port,
out->prf(out->dst, "\n"); out->prf(out->dst, "\n");
} }
static void lan966x_vcap_es0_port_keys(struct lan966x_port *port,
struct vcap_admin *admin,
struct vcap_output_print *out)
{
struct lan966x *lan966x = port->lan966x;
u32 val;
out->prf(out->dst, " port[%d] (%s): ", port->chip_port,
netdev_name(port->dev));
val = lan_rd(lan966x, REW_PORT_CFG(port->chip_port));
out->prf(out->dst, "\n state: ");
if (REW_PORT_CFG_ES0_EN_GET(val))
out->prf(out->dst, "on");
else
out->prf(out->dst, "off");
out->prf(out->dst, "\n");
}
int lan966x_vcap_port_info(struct net_device *dev, int lan966x_vcap_port_info(struct net_device *dev,
struct vcap_admin *admin, struct vcap_admin *admin,
struct vcap_output_print *out) struct vcap_output_print *out)
...@@ -210,6 +230,9 @@ int lan966x_vcap_port_info(struct net_device *dev, ...@@ -210,6 +230,9 @@ int lan966x_vcap_port_info(struct net_device *dev,
case VCAP_TYPE_IS1: case VCAP_TYPE_IS1:
lan966x_vcap_is1_port_keys(port, admin, out); lan966x_vcap_is1_port_keys(port, admin, out);
break; break;
case VCAP_TYPE_ES0:
lan966x_vcap_es0_port_keys(port, admin, out);
break;
default: default:
out->prf(out->dst, " no info\n"); out->prf(out->dst, " no info\n");
break; break;
......
...@@ -10,6 +10,12 @@ ...@@ -10,6 +10,12 @@
#define LAN966X_IS1_LOOKUPS 3 #define LAN966X_IS1_LOOKUPS 3
#define LAN966X_IS2_LOOKUPS 2 #define LAN966X_IS2_LOOKUPS 2
#define LAN966X_ES0_LOOKUPS 1
#define LAN966X_STAT_ESDX_GRN_BYTES 0x300
#define LAN966X_STAT_ESDX_GRN_PKTS 0x301
#define LAN966X_STAT_ESDX_YEL_BYTES 0x302
#define LAN966X_STAT_ESDX_YEL_PKTS 0x303
static struct lan966x_vcap_inst { static struct lan966x_vcap_inst {
enum vcap_type vtype; /* type of vcap */ enum vcap_type vtype; /* type of vcap */
...@@ -20,6 +26,14 @@ static struct lan966x_vcap_inst { ...@@ -20,6 +26,14 @@ static struct lan966x_vcap_inst {
int count; /* number of available addresses */ int count; /* number of available addresses */
bool ingress; /* is vcap in the ingress path */ bool ingress; /* is vcap in the ingress path */
} lan966x_vcap_inst_cfg[] = { } lan966x_vcap_inst_cfg[] = {
{
.vtype = VCAP_TYPE_ES0,
.tgt_inst = 0,
.lookups = LAN966X_ES0_LOOKUPS,
.first_cid = LAN966X_VCAP_CID_ES0_L0,
.last_cid = LAN966X_VCAP_CID_ES0_MAX,
.count = 64,
},
{ {
.vtype = VCAP_TYPE_IS1, /* IS1-0 */ .vtype = VCAP_TYPE_IS1, /* IS1-0 */
.tgt_inst = 1, .tgt_inst = 1,
...@@ -279,6 +293,8 @@ lan966x_vcap_validate_keyset(struct net_device *dev, ...@@ -279,6 +293,8 @@ lan966x_vcap_validate_keyset(struct net_device *dev,
err = lan966x_vcap_is2_get_port_keysets(dev, lookup, &keysetlist, err = lan966x_vcap_is2_get_port_keysets(dev, lookup, &keysetlist,
l3_proto); l3_proto);
break; break;
case VCAP_TYPE_ES0:
return kslist->keysets[0];
default: default:
pr_err("vcap type: %s not supported\n", pr_err("vcap type: %s not supported\n",
lan966x_vcaps[admin->vtype].name); lan966x_vcaps[admin->vtype].name);
...@@ -338,6 +354,14 @@ static void lan966x_vcap_is2_add_default_fields(struct lan966x_port *port, ...@@ -338,6 +354,14 @@ static void lan966x_vcap_is2_add_default_fields(struct lan966x_port *port,
VCAP_BIT_0); VCAP_BIT_0);
} }
static void lan966x_vcap_es0_add_default_fields(struct lan966x_port *port,
struct vcap_admin *admin,
struct vcap_rule *rule)
{
vcap_rule_add_key_u32(rule, VCAP_KF_IF_EGR_PORT_NO,
port->chip_port, GENMASK(4, 0));
}
static void lan966x_vcap_add_default_fields(struct net_device *dev, static void lan966x_vcap_add_default_fields(struct net_device *dev,
struct vcap_admin *admin, struct vcap_admin *admin,
struct vcap_rule *rule) struct vcap_rule *rule)
...@@ -351,6 +375,9 @@ static void lan966x_vcap_add_default_fields(struct net_device *dev, ...@@ -351,6 +375,9 @@ static void lan966x_vcap_add_default_fields(struct net_device *dev,
case VCAP_TYPE_IS2: case VCAP_TYPE_IS2:
lan966x_vcap_is2_add_default_fields(port, admin, rule); lan966x_vcap_is2_add_default_fields(port, admin, rule);
break; break;
case VCAP_TYPE_ES0:
lan966x_vcap_es0_add_default_fields(port, admin, rule);
break;
default: default:
pr_err("vcap type: %s not supported\n", pr_err("vcap type: %s not supported\n",
lan966x_vcaps[admin->vtype].name); lan966x_vcaps[admin->vtype].name);
...@@ -366,6 +393,40 @@ static void lan966x_vcap_cache_erase(struct vcap_admin *admin) ...@@ -366,6 +393,40 @@ static void lan966x_vcap_cache_erase(struct vcap_admin *admin)
memset(&admin->cache.counter, 0, sizeof(admin->cache.counter)); memset(&admin->cache.counter, 0, sizeof(admin->cache.counter));
} }
/* The ESDX counter is only used/incremented if the frame has been classified
* with an ISDX > 0 (e.g by a rule in IS0). This is not mentioned in the
* datasheet.
*/
static void lan966x_es0_read_esdx_counter(struct lan966x *lan966x,
struct vcap_admin *admin, u32 id)
{
u32 counter;
id = id & 0xff; /* counter limit */
mutex_lock(&lan966x->stats_lock);
lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(id), lan966x, SYS_STAT_CFG);
counter = lan_rd(lan966x, SYS_CNT(LAN966X_STAT_ESDX_GRN_PKTS)) +
lan_rd(lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_PKTS));
mutex_unlock(&lan966x->stats_lock);
if (counter)
admin->cache.counter = counter;
}
static void lan966x_es0_write_esdx_counter(struct lan966x *lan966x,
struct vcap_admin *admin, u32 id)
{
id = id & 0xff; /* counter limit */
mutex_lock(&lan966x->stats_lock);
lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(id), lan966x, SYS_STAT_CFG);
lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_GRN_BYTES));
lan_wr(admin->cache.counter, lan966x,
SYS_CNT(LAN966X_STAT_ESDX_GRN_PKTS));
lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_BYTES));
lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_PKTS));
mutex_unlock(&lan966x->stats_lock);
}
static void lan966x_vcap_cache_write(struct net_device *dev, static void lan966x_vcap_cache_write(struct net_device *dev,
struct vcap_admin *admin, struct vcap_admin *admin,
enum vcap_selection sel, enum vcap_selection sel,
...@@ -398,6 +459,9 @@ static void lan966x_vcap_cache_write(struct net_device *dev, ...@@ -398,6 +459,9 @@ static void lan966x_vcap_cache_write(struct net_device *dev,
admin->cache.sticky = admin->cache.counter > 0; admin->cache.sticky = admin->cache.counter > 0;
lan_wr(admin->cache.counter, lan966x, lan_wr(admin->cache.counter, lan966x,
VCAP_CNT_DAT(admin->tgt_inst, 0)); VCAP_CNT_DAT(admin->tgt_inst, 0));
if (admin->vtype == VCAP_TYPE_ES0)
lan966x_es0_write_esdx_counter(lan966x, admin, start);
break; break;
default: default:
break; break;
...@@ -437,6 +501,9 @@ static void lan966x_vcap_cache_read(struct net_device *dev, ...@@ -437,6 +501,9 @@ static void lan966x_vcap_cache_read(struct net_device *dev,
admin->cache.counter = admin->cache.counter =
lan_rd(lan966x, VCAP_CNT_DAT(instance, 0)); lan_rd(lan966x, VCAP_CNT_DAT(instance, 0));
admin->cache.sticky = admin->cache.counter > 0; admin->cache.sticky = admin->cache.counter > 0;
if (admin->vtype == VCAP_TYPE_ES0)
lan966x_es0_read_esdx_counter(lan966x, admin, start);
} }
} }
...@@ -625,6 +692,12 @@ static void lan966x_vcap_port_key_deselection(struct lan966x *lan966x, ...@@ -625,6 +692,12 @@ static void lan966x_vcap_port_key_deselection(struct lan966x *lan966x,
lan_wr(0, lan966x, ANA_VCAP_S2_CFG(p)); lan_wr(0, lan966x, ANA_VCAP_S2_CFG(p));
break; break;
case VCAP_TYPE_ES0:
for (int p = 0; p < lan966x->num_phys_ports; ++p)
lan_rmw(REW_PORT_CFG_ES0_EN_SET(false),
REW_PORT_CFG_ES0_EN, lan966x,
REW_PORT_CFG(p));
break;
default: default:
pr_err("vcap type: %s not supported\n", pr_err("vcap type: %s not supported\n",
lan966x_vcaps[admin->vtype].name); lan966x_vcaps[admin->vtype].name);
...@@ -674,9 +747,18 @@ int lan966x_vcap_init(struct lan966x *lan966x) ...@@ -674,9 +747,18 @@ int lan966x_vcap_init(struct lan966x *lan966x)
lan_rmw(ANA_VCAP_CFG_S1_ENA_SET(true), lan_rmw(ANA_VCAP_CFG_S1_ENA_SET(true),
ANA_VCAP_CFG_S1_ENA, lan966x, ANA_VCAP_CFG_S1_ENA, lan966x,
ANA_VCAP_CFG(lan966x->ports[p]->chip_port)); ANA_VCAP_CFG(lan966x->ports[p]->chip_port));
lan_rmw(REW_PORT_CFG_ES0_EN_SET(true),
REW_PORT_CFG_ES0_EN, lan966x,
REW_PORT_CFG(lan966x->ports[p]->chip_port));
} }
} }
/* Statistics: Use ESDX from ES0 if hit, otherwise no counting */
lan_rmw(REW_STAT_CFG_STAT_MODE_SET(1),
REW_STAT_CFG_STAT_MODE, lan966x,
REW_STAT_CFG);
lan966x->vcap_ctrl = ctrl; lan966x->vcap_ctrl = ctrl;
return 0; return 0;
......
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