net: lan966x: Add IS1 VCAP keyset configuration for lan966x

Add IS1 VCAP port keyset configuration for lan966x and also update debug
fs support to show the keyset configuration.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Horatiu Vultur 2023-03-07 23:09:26 +01:00 committed by Jakub Kicinski
parent 99ce286d2d
commit a4d9b3ec63
4 changed files with 383 additions and 16 deletions

View File

@ -92,6 +92,11 @@
#define SE_IDX_QUEUE 0 /* 0-79 : Queue scheduler elements */
#define SE_IDX_PORT 80 /* 80-89 : Port schedular elements */
#define LAN966X_VCAP_CID_IS1_L0 VCAP_CID_INGRESS_L0 /* IS1 lookup 0 */
#define LAN966X_VCAP_CID_IS1_L1 VCAP_CID_INGRESS_L1 /* IS1 lookup 1 */
#define LAN966X_VCAP_CID_IS1_L2 VCAP_CID_INGRESS_L2 /* IS1 lookup 2 */
#define LAN966X_VCAP_CID_IS1_MAX (VCAP_CID_INGRESS_L3 - 1) /* IS1 Max */
#define LAN966X_VCAP_CID_IS2_L0 VCAP_CID_INGRESS_STAGE2_L0 /* IS2 lookup 0 */
#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 */
@ -139,6 +144,39 @@ enum vcap_is2_port_sel_ipv6 {
VCAP_IS2_PS_IPV6_MAC_ETYPE,
};
enum vcap_is1_port_sel_other {
VCAP_IS1_PS_OTHER_NORMAL,
VCAP_IS1_PS_OTHER_7TUPLE,
VCAP_IS1_PS_OTHER_DBL_VID,
VCAP_IS1_PS_OTHER_DMAC_VID,
};
enum vcap_is1_port_sel_ipv4 {
VCAP_IS1_PS_IPV4_NORMAL,
VCAP_IS1_PS_IPV4_7TUPLE,
VCAP_IS1_PS_IPV4_5TUPLE_IP4,
VCAP_IS1_PS_IPV4_DBL_VID,
VCAP_IS1_PS_IPV4_DMAC_VID,
};
enum vcap_is1_port_sel_ipv6 {
VCAP_IS1_PS_IPV6_NORMAL,
VCAP_IS1_PS_IPV6_7TUPLE,
VCAP_IS1_PS_IPV6_5TUPLE_IP4,
VCAP_IS1_PS_IPV6_NORMAL_IP6,
VCAP_IS1_PS_IPV6_5TUPLE_IP6,
VCAP_IS1_PS_IPV6_DBL_VID,
VCAP_IS1_PS_IPV6_DMAC_VID,
};
enum vcap_is1_port_sel_rt {
VCAP_IS1_PS_RT_NORMAL,
VCAP_IS1_PS_RT_7TUPLE,
VCAP_IS1_PS_RT_DBL_VID,
VCAP_IS1_PS_RT_DMAC_VID,
VCAP_IS1_PS_RT_FOLLOW_OTHER = 7,
};
struct lan966x_port;
struct lan966x_db {

View File

@ -316,6 +316,42 @@ enum lan966x_target {
#define ANA_DROP_CFG_DROP_MC_SMAC_ENA_GET(x)\
FIELD_GET(ANA_DROP_CFG_DROP_MC_SMAC_ENA, x)
/* ANA:PORT:VCAP_CFG */
#define ANA_VCAP_CFG(g) __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 12, 0, 1, 4)
#define ANA_VCAP_CFG_S1_ENA BIT(14)
#define ANA_VCAP_CFG_S1_ENA_SET(x)\
FIELD_PREP(ANA_VCAP_CFG_S1_ENA, x)
#define ANA_VCAP_CFG_S1_ENA_GET(x)\
FIELD_GET(ANA_VCAP_CFG_S1_ENA, x)
/* ANA:PORT:VCAP_S1_KEY_CFG */
#define ANA_VCAP_S1_CFG(g, r) __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 16, r, 3, 4)
#define ANA_VCAP_S1_CFG_KEY_RT_CFG GENMASK(11, 9)
#define ANA_VCAP_S1_CFG_KEY_RT_CFG_SET(x)\
FIELD_PREP(ANA_VCAP_S1_CFG_KEY_RT_CFG, x)
#define ANA_VCAP_S1_CFG_KEY_RT_CFG_GET(x)\
FIELD_GET(ANA_VCAP_S1_CFG_KEY_RT_CFG, x)
#define ANA_VCAP_S1_CFG_KEY_IP6_CFG GENMASK(8, 6)
#define ANA_VCAP_S1_CFG_KEY_IP6_CFG_SET(x)\
FIELD_PREP(ANA_VCAP_S1_CFG_KEY_IP6_CFG, x)
#define ANA_VCAP_S1_CFG_KEY_IP6_CFG_GET(x)\
FIELD_GET(ANA_VCAP_S1_CFG_KEY_IP6_CFG, x)
#define ANA_VCAP_S1_CFG_KEY_IP4_CFG GENMASK(5, 3)
#define ANA_VCAP_S1_CFG_KEY_IP4_CFG_SET(x)\
FIELD_PREP(ANA_VCAP_S1_CFG_KEY_IP4_CFG, x)
#define ANA_VCAP_S1_CFG_KEY_IP4_CFG_GET(x)\
FIELD_GET(ANA_VCAP_S1_CFG_KEY_IP4_CFG, x)
#define ANA_VCAP_S1_CFG_KEY_OTHER_CFG GENMASK(2, 0)
#define ANA_VCAP_S1_CFG_KEY_OTHER_CFG_SET(x)\
FIELD_PREP(ANA_VCAP_S1_CFG_KEY_OTHER_CFG, x)
#define ANA_VCAP_S1_CFG_KEY_OTHER_CFG_GET(x)\
FIELD_GET(ANA_VCAP_S1_CFG_KEY_OTHER_CFG, x)
/* ANA:PORT:VCAP_S2_CFG */
#define ANA_VCAP_S2_CFG(g) __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 28, 0, 1, 4)

View File

@ -5,9 +5,124 @@
#include "vcap_api.h"
#include "vcap_api_client.h"
static void lan966x_vcap_port_keys(struct lan966x_port *port,
struct vcap_admin *admin,
struct vcap_output_print *out)
static void lan966x_vcap_is1_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, ANA_VCAP_CFG(port->chip_port));
out->prf(out->dst, "\n state: ");
if (ANA_VCAP_CFG_S1_ENA_GET(val))
out->prf(out->dst, "on");
else
out->prf(out->dst, "off");
for (int l = 0; l < admin->lookups; ++l) {
out->prf(out->dst, "\n Lookup %d: ", l);
out->prf(out->dst, "\n other: ");
switch (ANA_VCAP_S1_CFG_KEY_OTHER_CFG_GET(val)) {
case VCAP_IS1_PS_OTHER_NORMAL:
out->prf(out->dst, "normal");
break;
case VCAP_IS1_PS_OTHER_7TUPLE:
out->prf(out->dst, "7tuple");
break;
case VCAP_IS1_PS_OTHER_DBL_VID:
out->prf(out->dst, "dbl_vid");
break;
case VCAP_IS1_PS_OTHER_DMAC_VID:
out->prf(out->dst, "dmac_vid");
break;
default:
out->prf(out->dst, "-");
break;
}
out->prf(out->dst, "\n ipv4: ");
switch (ANA_VCAP_S1_CFG_KEY_IP4_CFG_GET(val)) {
case VCAP_IS1_PS_IPV4_NORMAL:
out->prf(out->dst, "normal");
break;
case VCAP_IS1_PS_IPV4_7TUPLE:
out->prf(out->dst, "7tuple");
break;
case VCAP_IS1_PS_IPV4_5TUPLE_IP4:
out->prf(out->dst, "5tuple_ipv4");
break;
case VCAP_IS1_PS_IPV4_DBL_VID:
out->prf(out->dst, "dbl_vid");
break;
case VCAP_IS1_PS_IPV4_DMAC_VID:
out->prf(out->dst, "dmac_vid");
break;
default:
out->prf(out->dst, "-");
break;
}
out->prf(out->dst, "\n ipv6: ");
switch (ANA_VCAP_S1_CFG_KEY_IP6_CFG_GET(val)) {
case VCAP_IS1_PS_IPV6_NORMAL:
out->prf(out->dst, "normal");
break;
case VCAP_IS1_PS_IPV6_7TUPLE:
out->prf(out->dst, "7tuple");
break;
case VCAP_IS1_PS_IPV6_5TUPLE_IP4:
out->prf(out->dst, "5tuple_ip4");
break;
case VCAP_IS1_PS_IPV6_NORMAL_IP6:
out->prf(out->dst, "normal_ip6");
break;
case VCAP_IS1_PS_IPV6_5TUPLE_IP6:
out->prf(out->dst, "5tuple_ip6");
break;
case VCAP_IS1_PS_IPV6_DBL_VID:
out->prf(out->dst, "dbl_vid");
break;
case VCAP_IS1_PS_IPV6_DMAC_VID:
out->prf(out->dst, "dmac_vid");
break;
default:
out->prf(out->dst, "-");
break;
}
out->prf(out->dst, "\n rt: ");
switch (ANA_VCAP_S1_CFG_KEY_RT_CFG_GET(val)) {
case VCAP_IS1_PS_RT_NORMAL:
out->prf(out->dst, "normal");
break;
case VCAP_IS1_PS_RT_7TUPLE:
out->prf(out->dst, "7tuple");
break;
case VCAP_IS1_PS_RT_DBL_VID:
out->prf(out->dst, "dbl_vid");
break;
case VCAP_IS1_PS_RT_DMAC_VID:
out->prf(out->dst, "dmac_vid");
break;
case VCAP_IS1_PS_RT_FOLLOW_OTHER:
out->prf(out->dst, "follow_other");
break;
default:
out->prf(out->dst, "-");
break;
}
}
out->prf(out->dst, "\n");
}
static void lan966x_vcap_is2_port_keys(struct lan966x_port *port,
struct vcap_admin *admin,
struct vcap_output_print *out)
{
struct lan966x *lan966x = port->lan966x;
u32 val;
@ -88,7 +203,17 @@ int lan966x_vcap_port_info(struct net_device *dev,
vcap = &vctrl->vcaps[admin->vtype];
out->prf(out->dst, "%s:\n", vcap->name);
lan966x_vcap_port_keys(port, admin, out);
switch (admin->vtype) {
case VCAP_TYPE_IS2:
lan966x_vcap_is2_port_keys(port, admin, out);
break;
case VCAP_TYPE_IS1:
lan966x_vcap_is1_port_keys(port, admin, out);
break;
default:
out->prf(out->dst, " no info\n");
break;
}
return 0;
}

View File

@ -8,6 +8,7 @@
#define STREAMSIZE (64 * 4)
#define LAN966X_IS1_LOOKUPS 3
#define LAN966X_IS2_LOOKUPS 2
static struct lan966x_vcap_inst {
@ -19,6 +20,15 @@ static struct lan966x_vcap_inst {
int count; /* number of available addresses */
bool ingress; /* is vcap in the ingress path */
} lan966x_vcap_inst_cfg[] = {
{
.vtype = VCAP_TYPE_IS1, /* IS1-0 */
.tgt_inst = 1,
.lookups = LAN966X_IS1_LOOKUPS,
.first_cid = LAN966X_VCAP_CID_IS1_L0,
.last_cid = LAN966X_VCAP_CID_IS1_MAX,
.count = 768,
.ingress = true,
},
{
.vtype = VCAP_TYPE_IS2, /* IS2-0 */
.tgt_inst = 2,
@ -72,7 +82,21 @@ static void __lan966x_vcap_range_init(struct lan966x *lan966x,
lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
}
static int lan966x_vcap_cid_to_lookup(int cid)
static int lan966x_vcap_is1_cid_to_lookup(int cid)
{
int lookup = 0;
if (cid >= LAN966X_VCAP_CID_IS1_L1 &&
cid < LAN966X_VCAP_CID_IS1_L2)
lookup = 1;
else if (cid >= LAN966X_VCAP_CID_IS1_L2 &&
cid < LAN966X_VCAP_CID_IS1_MAX)
lookup = 2;
return lookup;
}
static int lan966x_vcap_is2_cid_to_lookup(int cid)
{
if (cid >= LAN966X_VCAP_CID_IS2_L1 &&
cid < LAN966X_VCAP_CID_IS2_MAX)
@ -81,6 +105,67 @@ static int lan966x_vcap_cid_to_lookup(int cid)
return 0;
}
/* Return the list of keysets for the vcap port configuration */
static int
lan966x_vcap_is1_get_port_keysets(struct net_device *ndev, int lookup,
struct vcap_keyset_list *keysetlist,
u16 l3_proto)
{
struct lan966x_port *port = netdev_priv(ndev);
struct lan966x *lan966x = port->lan966x;
u32 val;
val = lan_rd(lan966x, ANA_VCAP_S1_CFG(port->chip_port, lookup));
/* Collect all keysets for the port in a list */
if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) {
switch (ANA_VCAP_S1_CFG_KEY_IP4_CFG_GET(val)) {
case VCAP_IS1_PS_IPV4_7TUPLE:
vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);
break;
case VCAP_IS1_PS_IPV4_5TUPLE_IP4:
vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP4);
break;
case VCAP_IS1_PS_IPV4_NORMAL:
vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);
break;
}
}
if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {
switch (ANA_VCAP_S1_CFG_KEY_IP6_CFG_GET(val)) {
case VCAP_IS1_PS_IPV6_NORMAL:
case VCAP_IS1_PS_IPV6_NORMAL_IP6:
vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);
vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL_IP6);
break;
case VCAP_IS1_PS_IPV6_5TUPLE_IP6:
vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP6);
break;
case VCAP_IS1_PS_IPV6_7TUPLE:
vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);
break;
case VCAP_IS1_PS_IPV6_5TUPLE_IP4:
vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP4);
break;
case VCAP_IS1_PS_IPV6_DMAC_VID:
vcap_keyset_list_add(keysetlist, VCAP_KFS_DMAC_VID);
break;
}
}
switch (ANA_VCAP_S1_CFG_KEY_OTHER_CFG_GET(val)) {
case VCAP_IS1_PS_OTHER_7TUPLE:
vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);
break;
case VCAP_IS1_PS_OTHER_NORMAL:
vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);
break;
}
return 0;
}
static int
lan966x_vcap_is2_get_port_keysets(struct net_device *dev, int lookup,
struct vcap_keyset_list *keysetlist,
@ -180,11 +265,26 @@ lan966x_vcap_validate_keyset(struct net_device *dev,
if (!kslist || kslist->cnt == 0)
return VCAP_KFS_NO_VALUE;
lookup = lan966x_vcap_cid_to_lookup(rule->vcap_chain_id);
keysetlist.max = ARRAY_SIZE(keysets);
keysetlist.keysets = keysets;
err = lan966x_vcap_is2_get_port_keysets(dev, lookup, &keysetlist,
l3_proto);
switch (admin->vtype) {
case VCAP_TYPE_IS1:
lookup = lan966x_vcap_is1_cid_to_lookup(rule->vcap_chain_id);
err = lan966x_vcap_is1_get_port_keysets(dev, lookup, &keysetlist,
l3_proto);
break;
case VCAP_TYPE_IS2:
lookup = lan966x_vcap_is2_cid_to_lookup(rule->vcap_chain_id);
err = lan966x_vcap_is2_get_port_keysets(dev, lookup, &keysetlist,
l3_proto);
break;
default:
pr_err("vcap type: %s not supported\n",
lan966x_vcaps[admin->vtype].name);
return VCAP_KFS_NO_VALUE;
}
if (err)
return VCAP_KFS_NO_VALUE;
@ -197,17 +297,32 @@ lan966x_vcap_validate_keyset(struct net_device *dev,
return VCAP_KFS_NO_VALUE;
}
static bool lan966x_vcap_is_first_chain(struct vcap_rule *rule)
static bool lan966x_vcap_is2_is_first_chain(struct vcap_rule *rule)
{
return (rule->vcap_chain_id >= LAN966X_VCAP_CID_IS2_L0 &&
rule->vcap_chain_id < LAN966X_VCAP_CID_IS2_L1);
}
static void lan966x_vcap_add_default_fields(struct net_device *dev,
struct vcap_admin *admin,
struct vcap_rule *rule)
static void lan966x_vcap_is1_add_default_fields(struct lan966x_port *port,
struct vcap_admin *admin,
struct vcap_rule *rule)
{
u32 value, mask;
u32 lookup;
if (vcap_rule_get_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK,
&value, &mask))
vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0,
~BIT(port->chip_port));
lookup = lan966x_vcap_is1_cid_to_lookup(rule->vcap_chain_id);
vcap_rule_add_key_u32(rule, VCAP_KF_LOOKUP_INDEX, lookup, 0x3);
}
static void lan966x_vcap_is2_add_default_fields(struct lan966x_port *port,
struct vcap_admin *admin,
struct vcap_rule *rule)
{
struct lan966x_port *port = netdev_priv(dev);
u32 value, mask;
if (vcap_rule_get_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK,
@ -215,7 +330,7 @@ static void lan966x_vcap_add_default_fields(struct net_device *dev,
vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0,
~BIT(port->chip_port));
if (lan966x_vcap_is_first_chain(rule))
if (lan966x_vcap_is2_is_first_chain(rule))
vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
VCAP_BIT_1);
else
@ -223,6 +338,26 @@ static void lan966x_vcap_add_default_fields(struct net_device *dev,
VCAP_BIT_0);
}
static void lan966x_vcap_add_default_fields(struct net_device *dev,
struct vcap_admin *admin,
struct vcap_rule *rule)
{
struct lan966x_port *port = netdev_priv(dev);
switch (admin->vtype) {
case VCAP_TYPE_IS1:
lan966x_vcap_is1_add_default_fields(port, admin, rule);
break;
case VCAP_TYPE_IS2:
lan966x_vcap_is2_add_default_fields(port, admin, rule);
break;
default:
pr_err("vcap type: %s not supported\n",
lan966x_vcaps[admin->vtype].name);
break;
}
}
static void lan966x_vcap_cache_erase(struct vcap_admin *admin)
{
memset(admin->cache.keystream, 0, STREAMSIZE);
@ -464,8 +599,37 @@ static void lan966x_vcap_block_init(struct lan966x *lan966x,
static void lan966x_vcap_port_key_deselection(struct lan966x *lan966x,
struct vcap_admin *admin)
{
for (int p = 0; p < lan966x->num_phys_ports; ++p)
lan_wr(0, lan966x, ANA_VCAP_S2_CFG(p));
u32 val;
switch (admin->vtype) {
case VCAP_TYPE_IS1:
val = ANA_VCAP_S1_CFG_KEY_IP6_CFG_SET(VCAP_IS1_PS_IPV6_5TUPLE_IP6) |
ANA_VCAP_S1_CFG_KEY_IP4_CFG_SET(VCAP_IS1_PS_IPV4_5TUPLE_IP4) |
ANA_VCAP_S1_CFG_KEY_OTHER_CFG_SET(VCAP_IS1_PS_OTHER_NORMAL);
for (int p = 0; p < lan966x->num_phys_ports; ++p) {
if (!lan966x->ports[p])
continue;
for (int l = 0; l < LAN966X_IS1_LOOKUPS; ++l)
lan_wr(val, lan966x, ANA_VCAP_S1_CFG(p, l));
lan_rmw(ANA_VCAP_CFG_S1_ENA_SET(true),
ANA_VCAP_CFG_S1_ENA, lan966x,
ANA_VCAP_CFG(p));
}
break;
case VCAP_TYPE_IS2:
for (int p = 0; p < lan966x->num_phys_ports; ++p)
lan_wr(0, lan966x, ANA_VCAP_S2_CFG(p));
break;
default:
pr_err("vcap type: %s not supported\n",
lan966x_vcaps[admin->vtype].name);
break;
}
}
int lan966x_vcap_init(struct lan966x *lan966x)
@ -506,6 +670,10 @@ int lan966x_vcap_init(struct lan966x *lan966x)
lan_rmw(ANA_VCAP_S2_CFG_ENA_SET(true),
ANA_VCAP_S2_CFG_ENA, lan966x,
ANA_VCAP_S2_CFG(lan966x->ports[p]->chip_port));
lan_rmw(ANA_VCAP_CFG_S1_ENA_SET(true),
ANA_VCAP_CFG_S1_ENA, lan966x,
ANA_VCAP_CFG(lan966x->ports[p]->chip_port));
}
}