[PATCH v1 net-next 4/6] net: mscc: ocelot: VCAP IS1 support
From: Xiaoliang Yang
Date: Wed May 06 2020 - 03:54:09 EST
VCAP IS1 is a VCAP module which can filter MAC, IP, VLAN, protocol, and
TCP/UDP ports keys, and do Qos and VLAN retag actions.
This patch added VCAP IS1 support in ocelot ace driver, which can supports
vlan modify action of tc filter.
Usage:
tc qdisc add dev swp0 ingress
tc filter add dev swp0 protocol 802.1Q parent ffff: flower \
skip_sw vlan_id 1 vlan_prio 1 action vlan modify id 2 priority 2
Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@xxxxxxx>
---
drivers/net/dsa/ocelot/felix_vsc9959.c | 102 +++++++++++
drivers/net/ethernet/mscc/ocelot.c | 7 +
drivers/net/ethernet/mscc/ocelot_ace.c | 198 +++++++++++++++++++++-
drivers/net/ethernet/mscc/ocelot_ace.h | 9 +
drivers/net/ethernet/mscc/ocelot_flower.c | 6 +
drivers/net/ethernet/mscc/ocelot_regs.c | 1 +
include/soc/mscc/ocelot.h | 1 +
include/soc/mscc/ocelot_vcap.h | 93 +++++++++-
8 files changed, 415 insertions(+), 2 deletions(-)
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index 3b37c5f41fca..1f5edabf5fd2 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -13,6 +13,8 @@
#define VSC9959_VCAP_IS2_CNT 1024
#define VSC9959_VCAP_IS2_ENTRY_WIDTH 376
#define VSC9959_VCAP_PORT_CNT 6
+#define VSC9959_VCAP_IS1_CNT 256
+#define VSC9959_VCAP_IS1_ENTRY_WIDTH 376
/* TODO: should find a better place for these */
#define USXGMII_BMCR_RESET BIT(15)
@@ -332,6 +334,7 @@ static const u32 *vsc9959_regmap[] = {
[QSYS] = vsc9959_qsys_regmap,
[REW] = vsc9959_rew_regmap,
[SYS] = vsc9959_sys_regmap,
+ [S1] = vsc9959_vcap_regmap,
[S2] = vsc9959_vcap_regmap,
[PTP] = vsc9959_ptp_regmap,
[GCB] = vsc9959_gcb_regmap,
@@ -366,6 +369,11 @@ static struct resource vsc9959_target_io_res[] = {
.end = 0x001ffff,
.name = "sys",
},
+ [S1] = {
+ .start = 0x0050000,
+ .end = 0x00503ff,
+ .name = "s1",
+ },
[S2] = {
.start = 0x0060000,
.end = 0x00603ff,
@@ -556,6 +564,80 @@ static const struct ocelot_stat_layout vsc9959_stats_layout[] = {
{ .offset = 0x111, .name = "drop_green_prio_7", },
};
+struct vcap_field vsc9959_vcap_is1_keys[] = {
+ [VCAP_IS1_HK_TYPE] = { 0, 1},
+ [VCAP_IS1_HK_LOOKUP] = { 1, 2},
+ [VCAP_IS1_HK_IGR_PORT_MASK] = { 3, 7},
+ [VCAP_IS1_HK_RSV] = { 10, 9},
+ [VCAP_IS1_HK_OAM_Y1731] = { 19, 1},
+ [VCAP_IS1_HK_L2_MC] = { 20, 1},
+ [VCAP_IS1_HK_L2_BC] = { 21, 1},
+ [VCAP_IS1_HK_IP_MC] = { 22, 1},
+ [VCAP_IS1_HK_VLAN_TAGGED] = { 23, 1},
+ [VCAP_IS1_HK_VLAN_DBL_TAGGED] = { 24, 1},
+ [VCAP_IS1_HK_TPID] = { 25, 1},
+ [VCAP_IS1_HK_VID] = { 26, 12},
+ [VCAP_IS1_HK_DEI] = { 38, 1},
+ [VCAP_IS1_HK_PCP] = { 39, 3},
+ /* Specific Fields for IS1 Half Key S1_NORMAL */
+ [VCAP_IS1_HK_L2_SMAC] = { 42, 48},
+ [VCAP_IS1_HK_ETYPE_LEN] = { 90, 1},
+ [VCAP_IS1_HK_ETYPE] = { 91, 16},
+ [VCAP_IS1_HK_IP_SNAP] = {107, 1},
+ [VCAP_IS1_HK_IP4] = {108, 1},
+ /* Layer-3 Information */
+ [VCAP_IS1_HK_L3_FRAGMENT] = {109, 1},
+ [VCAP_IS1_HK_L3_FRAG_OFS_GT0] = {110, 1},
+ [VCAP_IS1_HK_L3_OPTIONS] = {111, 1},
+ [VCAP_IS1_HK_L3_DSCP] = {112, 6},
+ [VCAP_IS1_HK_L3_IP4_SIP] = {118, 32},
+ /* Layer-4 Information */
+ [VCAP_IS1_HK_TCP_UDP] = {150, 1},
+ [VCAP_IS1_HK_TCP] = {151, 1},
+ [VCAP_IS1_HK_L4_SPORT] = {152, 16},
+ [VCAP_IS1_HK_L4_RNG] = {168, 8},
+ /* Specific Fields for IS1 Half Key S1_5TUPLE_IP4 */
+ [VCAP_IS1_HK_IP4_INNER_TPID] = { 42, 1},
+ [VCAP_IS1_HK_IP4_INNER_VID] = { 43, 12},
+ [VCAP_IS1_HK_IP4_INNER_DEI] = { 55, 1},
+ [VCAP_IS1_HK_IP4_INNER_PCP] = { 56, 3},
+ [VCAP_IS1_HK_IP4_IP4] = { 59, 1},
+ [VCAP_IS1_HK_IP4_L3_FRAGMENT] = { 60, 1},
+ [VCAP_IS1_HK_IP4_L3_FRAG_OFS_GT0] = { 61, 1},
+ [VCAP_IS1_HK_IP4_L3_OPTIONS] = { 62, 1},
+ [VCAP_IS1_HK_IP4_L3_DSCP] = { 63, 6},
+ [VCAP_IS1_HK_IP4_L3_IP4_DIP] = { 69, 32},
+ [VCAP_IS1_HK_IP4_L3_IP4_SIP] = {101, 32},
+ [VCAP_IS1_HK_IP4_L3_PROTO] = {133, 8},
+ [VCAP_IS1_HK_IP4_TCP_UDP] = {141, 1},
+ [VCAP_IS1_HK_IP4_TCP] = {142, 1},
+ [VCAP_IS1_HK_IP4_L4_RNG] = {143, 8},
+ [VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE] = {151, 32},
+};
+
+struct vcap_field vsc9959_vcap_is1_actions[] = {
+ [VCAP_IS1_ACT_DSCP_ENA] = { 0, 1},
+ [VCAP_IS1_ACT_DSCP_VAL] = { 1, 6},
+ [VCAP_IS1_ACT_QOS_ENA] = { 7, 1},
+ [VCAP_IS1_ACT_QOS_VAL] = { 8, 3},
+ [VCAP_IS1_ACT_DP_ENA] = { 11, 1},
+ [VCAP_IS1_ACT_DP_VAL] = { 12, 1},
+ [VCAP_IS1_ACT_PAG_OVERRIDE_MASK] = { 13, 8},
+ [VCAP_IS1_ACT_PAG_VAL] = { 21, 8},
+ [VCAP_IS1_ACT_RSV] = { 29, 9},
+ [VCAP_IS1_ACT_VID_REPLACE_ENA] = { 38, 1},
+ [VCAP_IS1_ACT_VID_ADD_VAL] = { 39, 12},
+ [VCAP_IS1_ACT_FID_SEL] = { 51, 2},
+ [VCAP_IS1_ACT_FID_VAL] = { 53, 13},
+ [VCAP_IS1_ACT_PCP_DEI_ENA] = { 66, 1},
+ [VCAP_IS1_ACT_PCP_VAL] = { 67, 3},
+ [VCAP_IS1_ACT_DEI_VAL] = { 70, 1},
+ [VCAP_IS1_ACT_VLAN_POP_CNT_ENA] = { 71, 1},
+ [VCAP_IS1_ACT_VLAN_POP_CNT] = { 72, 2},
+ [VCAP_IS1_ACT_CUSTOM_ACE_TYPE_ENA] = { 74, 4},
+ [VCAP_IS1_ACT_HIT_STICKY] = { 78, 1},
+};
+
struct vcap_field vsc9959_vcap_is2_keys[] = {
/* Common: 41 bits */
[VCAP_IS2_TYPE] = { 0, 4},
@@ -655,6 +737,26 @@ struct vcap_field vsc9959_vcap_is2_actions[] = {
};
static const struct vcap_props vsc9959_vcap_props[] = {
+ [VCAP_IS1] = {
+ .tg_width = 2,
+ .sw_count = 4,
+ .entry_count = VSC9959_VCAP_IS1_CNT,
+ .entry_width = VSC9959_VCAP_IS1_ENTRY_WIDTH,
+ .action_count = VSC9959_VCAP_IS1_CNT + 1,
+ .action_width = 312,
+ .action_type_width = 0,
+ .action_table = {
+ [IS1_ACTION_TYPE_NORMAL] = {
+ .width = 78,
+ .count = 4
+ },
+ },
+ .counter_words = 1,
+ .counter_width = 4,
+ .target = S1,
+ .keys = vsc9959_vcap_is1_keys,
+ .actions = vsc9959_vcap_is1_actions,
+ },
[VCAP_IS2] = {
.tg_width = 2,
.sw_count = 4,
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index a2b9b85612a4..2fa22801bc67 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -136,6 +136,13 @@ static void ocelot_vcap_enable(struct ocelot *ocelot, int port)
ocelot_write_gix(ocelot, ANA_PORT_VCAP_S2_CFG_S2_ENA |
ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG(0xa),
ANA_PORT_VCAP_S2_CFG, port);
+
+ ocelot_write_gix(ocelot, ANA_PORT_VCAP_CFG_S1_ENA,
+ ANA_PORT_VCAP_CFG, port);
+ ocelot_write_gix(ocelot,
+ ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP6_CFG(2) |
+ ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP4_CFG(2),
+ ANA_PORT_VCAP_S1_KEY_CFG, port);
}
static inline u32 ocelot_vlant_read_vlanaccess(struct ocelot *ocelot)
diff --git a/drivers/net/ethernet/mscc/ocelot_ace.c b/drivers/net/ethernet/mscc/ocelot_ace.c
index 29d61b89b73a..0f0fc709113b 100644
--- a/drivers/net/ethernet/mscc/ocelot_ace.c
+++ b/drivers/net/ethernet/mscc/ocelot_ace.c
@@ -341,6 +341,8 @@ static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data,
vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_COPY_ENA, 0);
break;
+ default:
+ break;
}
}
@@ -643,6 +645,195 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
}
+static void is1_action_set(struct ocelot *ocelot, struct vcap_data *data,
+ struct ocelot_ace_rule *ace)
+{
+ const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS1];
+
+ switch (ace->action) {
+ case OCELOT_ACL_ACTION_VLAN_MODIFY:
+ vcap_action_set(vcap, data, VCAP_IS1_ACT_QOS_ENA, 1);
+ vcap_action_set(vcap, data, VCAP_IS1_ACT_QOS_VAL,
+ ace->vlan_modify.pcp);
+ vcap_action_set(vcap, data, VCAP_IS1_ACT_VID_REPLACE_ENA, 1);
+ vcap_action_set(vcap, data, VCAP_IS1_ACT_VID_ADD_VAL,
+ ace->vlan_modify.vid);
+ vcap_action_set(vcap, data, VCAP_IS1_ACT_PCP_DEI_ENA, 1);
+ vcap_action_set(vcap, data, VCAP_IS1_ACT_PCP_VAL,
+ ace->vlan_modify.pcp);
+ vcap_action_set(vcap, data, VCAP_IS1_ACT_DEI_VAL,
+ ace->vlan_modify.dei);
+ break;
+ default:
+ break;
+ }
+}
+
+static void is1_entry_set(struct ocelot *ocelot, int ix,
+ struct ocelot_ace_rule *ace)
+{
+ const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS1];
+ u32 val, msk, type, i;
+ struct ocelot_ace_vlan *tag = &ace->vlan;
+ struct ocelot_vcap_u64 payload;
+ struct vcap_data data;
+ int row = ix / 2;
+
+ memset(&payload, 0, sizeof(payload));
+ memset(&data, 0, sizeof(data));
+
+ /* Read row */
+ vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_READ, VCAP_SEL_ALL);
+ vcap_cache2entry(ocelot, vcap, &data);
+ vcap_cache2action(ocelot, vcap, &data);
+
+ data.tg_sw = VCAP_TG_HALF;
+ data.type = IS1_ACTION_TYPE_NORMAL;
+ vcap_data_offset_get(vcap, &data, ix);
+ data.tg = (data.tg & ~data.tg_mask);
+ if (ace->prio != 0)
+ data.tg |= data.tg_value;
+
+ vcap_key_set(vcap, &data, VCAP_IS1_HK_IGR_PORT_MASK, 0,
+ ~ace->ingress_port_mask);
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_L2_MC, ace->dmac_mc);
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_L2_BC, ace->dmac_bc);
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_VLAN_TAGGED, tag->tagged);
+ vcap_key_set(vcap, &data, VCAP_IS1_HK_VID,
+ tag->vid.value, tag->vid.mask);
+ vcap_key_set(vcap, &data, VCAP_IS1_HK_PCP,
+ tag->pcp.value[0], tag->pcp.mask[0]);
+ type = IS1_TYPE_S1_NORMAL;
+
+ switch (ace->type) {
+ case OCELOT_ACE_TYPE_ETYPE: {
+ struct ocelot_ace_frame_etype *etype = &ace->frame.etype;
+
+ type = IS1_TYPE_S1_NORMAL;
+ vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_L2_SMAC,
+ etype->smac.value, etype->smac.mask);
+ vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_ETYPE,
+ etype->etype.value, etype->etype.mask);
+ break;
+ }
+ case OCELOT_ACE_TYPE_IPV4:
+ case OCELOT_ACE_TYPE_IPV6: {
+ enum ocelot_vcap_bit sip_eq_dip, sport_eq_dport;
+ enum ocelot_vcap_bit seq_zero, tcp;
+ enum ocelot_vcap_bit ttl, fragment, options;
+ enum ocelot_vcap_bit tcp_ack, tcp_urg;
+ enum ocelot_vcap_bit tcp_fin, tcp_syn, tcp_rst, tcp_psh;
+ struct ocelot_ace_frame_ipv4 *ipv4 = NULL;
+ struct ocelot_ace_frame_ipv6 *ipv6 = NULL;
+ struct ocelot_vcap_udp_tcp *sport, *dport;
+ struct ocelot_vcap_ipv4 sip, dip;
+ struct ocelot_vcap_u8 proto, ds;
+ struct ocelot_vcap_u48 *ip_data;
+ struct ocelot_vcap_u32 port;
+
+ type = IS1_TYPE_S1_5TUPLE_IP4;
+ if (ace->type == OCELOT_ACE_TYPE_IPV4) {
+ ipv4 = &ace->frame.ipv4;
+ ttl = ipv4->ttl;
+ fragment = ipv4->fragment;
+ options = ipv4->options;
+ proto = ipv4->proto;
+ ds = ipv4->ds;
+ ip_data = &ipv4->data;
+ sip = ipv4->sip;
+ dip = ipv4->dip;
+ sport = &ipv4->sport;
+ dport = &ipv4->dport;
+ tcp_fin = ipv4->tcp_fin;
+ tcp_syn = ipv4->tcp_syn;
+ tcp_rst = ipv4->tcp_rst;
+ tcp_psh = ipv4->tcp_psh;
+ tcp_ack = ipv4->tcp_ack;
+ tcp_urg = ipv4->tcp_urg;
+ sip_eq_dip = ipv4->sip_eq_dip;
+ sport_eq_dport = ipv4->sport_eq_dport;
+ seq_zero = ipv4->seq_zero;
+ } else {
+ ipv6 = &ace->frame.ipv6;
+ ttl = ipv6->ttl;
+ fragment = OCELOT_VCAP_BIT_ANY;
+ options = OCELOT_VCAP_BIT_ANY;
+ proto = ipv6->proto;
+ ds = ipv6->ds;
+ ip_data = &ipv6->data;
+ for (i = 0; i < 4; i++) {
+ dip.value.addr[i] = ipv6->dip.value[i];
+ dip.mask.addr[i] = ipv6->dip.mask[i];
+ sip.value.addr[i] = ipv6->sip.value[i];
+ sip.mask.addr[i] = ipv6->sip.mask[i];
+ }
+ sport = &ipv6->sport;
+ dport = &ipv6->dport;
+ tcp_fin = ipv6->tcp_fin;
+ tcp_syn = ipv6->tcp_syn;
+ tcp_rst = ipv6->tcp_rst;
+ tcp_psh = ipv6->tcp_psh;
+ tcp_ack = ipv6->tcp_ack;
+ tcp_urg = ipv6->tcp_urg;
+ sip_eq_dip = ipv6->sip_eq_dip;
+ sport_eq_dport = ipv6->sport_eq_dport;
+ seq_zero = ipv6->seq_zero;
+ }
+
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP4_IP4,
+ ipv4 ? OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP4_L3_FRAGMENT,
+ fragment);
+ vcap_key_set(vcap, &data, VCAP_IS1_HK_IP4_L3_FRAG_OFS_GT0,
+ 0, 0);
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP4_L3_OPTIONS,
+ options);
+ vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_IP4_L3_IP4_DIP,
+ dip.value.addr, dip.mask.addr);
+ vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_IP4_L3_IP4_SIP,
+ sip.value.addr, sip.mask.addr);
+ val = proto.value[0];
+ msk = proto.mask[0];
+ if (msk == 0xff && (val == 6 || val == 17)) {
+ /* UDP/TCP protocol match */
+ tcp = (val == 6 ?
+ OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP4_TCP,
+ tcp);
+ vcap_key_l4_port_set(vcap, &data,
+ VCAP_IS1_HK_L4_SPORT, sport);
+ vcap_key_set(vcap, &data, VCAP_IS1_HK_IP4_L4_RNG,
+ 0, 0);
+ port.value[0] = sport->value & 0xFF;
+ port.value[1] = sport->value >> 8;
+ port.value[2] = dport->value & 0xFF;
+ port.value[3] = dport->value >> 8;
+ port.mask[0] = sport->mask & 0xFF;
+ port.mask[1] = sport->mask >> 8;
+ port.mask[2] = dport->mask & 0xFF;
+ port.mask[3] = dport->mask >> 8;
+ vcap_key_bytes_set(vcap, &data,
+ VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE,
+ port.value, port.mask);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TYPE,
+ type ? OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
+
+ is1_action_set(ocelot, &data, ace);
+ vcap_data_set(data.counter, data.counter_offset,
+ vcap->counter_width, ace->stats.pkts);
+
+ /* Write row */
+ vcap_entry2cache(ocelot, vcap, &data);
+ vcap_action2cache(ocelot, vcap, &data);
+ vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
+}
+
static void vcap_entry_get(struct ocelot *ocelot, struct ocelot_ace_rule *rule,
int ix)
{
@@ -667,6 +858,9 @@ static void vcap_entry_set(struct ocelot *ocelot, int ix,
struct ocelot_ace_rule *ace)
{
switch (ace->vcap_id) {
+ case VCAP_IS1:
+ is1_entry_set(ocelot, ix, ace);
+ break;
case VCAP_IS2:
is2_entry_set(ocelot, ix, ace);
break;
@@ -1007,6 +1201,7 @@ int ocelot_ace_init(struct ocelot *ocelot)
{
struct ocelot_acl_block *block;
+ vcap_init(ocelot, &ocelot->vcap[VCAP_IS1]);
vcap_init(ocelot, &ocelot->vcap[VCAP_IS2]);
/* Create a policer that will drop the frames for the cpu.
@@ -1026,7 +1221,8 @@ int ocelot_ace_init(struct ocelot *ocelot)
block = &ocelot->acl_block[VCAP_IS2];
block->pol_lpr = OCELOT_POLICER_DISCARD - 1;
- INIT_LIST_HEAD(&block->rules);
+ INIT_LIST_HEAD(&ocelot->acl_block[VCAP_IS1].rules);
+ INIT_LIST_HEAD(&ocelot->acl_block[VCAP_IS2].rules);
return 0;
}
diff --git a/drivers/net/ethernet/mscc/ocelot_ace.h b/drivers/net/ethernet/mscc/ocelot_ace.h
index badc883c14be..5d9c495a28f7 100644
--- a/drivers/net/ethernet/mscc/ocelot_ace.h
+++ b/drivers/net/ethernet/mscc/ocelot_ace.h
@@ -93,6 +93,12 @@ struct ocelot_ace_vlan {
enum ocelot_vcap_bit tagged; /* Tagged/untagged frame */
};
+struct ocelot_ace_action_vlan {
+ u16 vid;
+ u8 pcp;
+ u8 dei;
+};
+
struct ocelot_ace_frame_etype {
struct ocelot_vcap_u48 dmac;
struct ocelot_vcap_u48 smac;
@@ -158,6 +164,7 @@ struct ocelot_ace_frame_ipv4 {
struct ocelot_ace_frame_ipv6 {
struct ocelot_vcap_u8 proto; /* IPv6 protocol */
struct ocelot_vcap_u128 sip; /* IPv6 source (byte 0-7 ignored) */
+ struct ocelot_vcap_u128 dip; /* IPv6 destination (byte 0-7 ignored) */
enum ocelot_vcap_bit ttl; /* TTL zero */
struct ocelot_vcap_u8 ds;
struct ocelot_vcap_u48 data; /* Not UDP/TCP: IP data */
@@ -178,6 +185,7 @@ enum ocelot_ace_action {
OCELOT_ACL_ACTION_DROP,
OCELOT_ACL_ACTION_TRAP,
OCELOT_ACL_ACTION_POLICE,
+ OCELOT_ACL_ACTION_VLAN_MODIFY,
};
struct ocelot_ace_stats {
@@ -200,6 +208,7 @@ struct ocelot_ace_rule {
enum ocelot_vcap_bit dmac_mc;
enum ocelot_vcap_bit dmac_bc;
struct ocelot_ace_vlan vlan;
+ struct ocelot_ace_action_vlan vlan_modify;
enum ocelot_ace_type type;
union {
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index 1963279cc062..f770448d7c7e 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -42,6 +42,12 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
burst = rate * PSCHED_NS2TICKS(a->police.burst);
ace->pol.burst = div_u64(burst, PSCHED_TICKS_PER_SEC);
break;
+ case FLOW_ACTION_VLAN_MANGLE:
+ ace->vcap_id = VCAP_IS1;
+ ace->action = OCELOT_ACL_ACTION_VLAN_MODIFY;
+ ace->vlan_modify.vid = a->vlan.vid;
+ ace->vlan_modify.pcp = a->vlan.prio;
+ break;
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c
index 8cc0e0082a76..69d97cbe25d6 100644
--- a/drivers/net/ethernet/mscc/ocelot_regs.c
+++ b/drivers/net/ethernet/mscc/ocelot_regs.c
@@ -254,6 +254,7 @@ static const u32 *ocelot_regmap[] = {
[QSYS] = ocelot_qsys_regmap,
[REW] = ocelot_rew_regmap,
[SYS] = ocelot_sys_regmap,
+ [S1] = ocelot_vcap_regmap,
[S2] = ocelot_vcap_regmap,
[PTP] = ocelot_ptp_regmap,
};
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index a704b5c69453..6b131cab1500 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -107,6 +107,7 @@ enum ocelot_target {
QSYS,
REW,
SYS,
+ S1,
S2,
HSIO,
PTP,
diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h
index da1e6b2c3ee4..6d3ed5260ad8 100644
--- a/include/soc/mscc/ocelot_vcap.h
+++ b/include/soc/mscc/ocelot_vcap.h
@@ -14,7 +14,7 @@
*/
enum {
- /* VCAP_IS1, */
+ VCAP_IS1,
VCAP_IS2,
/* VCAP_ES0, */
VCAP_CORE_MAX,
@@ -265,4 +265,95 @@ enum vcap_is2_action_field {
VCAP_IS2_ACT_HIT_CNT,
};
+/* =================================================================
+ * VCAP IS1
+ * =================================================================
+ */
+
+/* IS1 half key types */
+#define IS1_TYPE_S1_NORMAL 0
+#define IS1_TYPE_S1_5TUPLE_IP4 1
+
+/* IS1 full key types */
+#define IS1_TYPE_S1_NORMAL_IP6 0
+#define IS1_TYPE_S1_7TUPLE 1
+#define IS2_TYPE_S1_5TUPLE_IP6 2
+
+enum {
+ IS1_ACTION_TYPE_NORMAL,
+ IS1_ACTION_TYPE_MAX,
+};
+
+enum vcap_is1_half_key_field {
+ VCAP_IS1_HK_TYPE,
+ VCAP_IS1_HK_LOOKUP,
+ VCAP_IS1_HK_IGR_PORT_MASK,
+ VCAP_IS1_HK_RSV,
+ VCAP_IS1_HK_OAM_Y1731,
+ VCAP_IS1_HK_L2_MC,
+ VCAP_IS1_HK_L2_BC,
+ VCAP_IS1_HK_IP_MC,
+ VCAP_IS1_HK_VLAN_TAGGED,
+ VCAP_IS1_HK_VLAN_DBL_TAGGED,
+ VCAP_IS1_HK_TPID,
+ VCAP_IS1_HK_VID,
+ VCAP_IS1_HK_DEI,
+ VCAP_IS1_HK_PCP,
+ /* Specific Fields for IS1 Half Key S1_NORMAL */
+ VCAP_IS1_HK_L2_SMAC,
+ VCAP_IS1_HK_ETYPE_LEN,
+ VCAP_IS1_HK_ETYPE,
+ VCAP_IS1_HK_IP_SNAP,
+ VCAP_IS1_HK_IP4,
+ VCAP_IS1_HK_L3_FRAGMENT,
+ VCAP_IS1_HK_L3_FRAG_OFS_GT0,
+ VCAP_IS1_HK_L3_OPTIONS,
+ VCAP_IS1_HK_L3_DSCP,
+ VCAP_IS1_HK_L3_IP4_SIP,
+ VCAP_IS1_HK_TCP_UDP,
+ VCAP_IS1_HK_TCP,
+ VCAP_IS1_HK_L4_SPORT,
+ VCAP_IS1_HK_L4_RNG,
+ /* Specific Fields for IS1 Half Key S1_5TUPLE_IP4 */
+ VCAP_IS1_HK_IP4_INNER_TPID,
+ VCAP_IS1_HK_IP4_INNER_VID,
+ VCAP_IS1_HK_IP4_INNER_DEI,
+ VCAP_IS1_HK_IP4_INNER_PCP,
+ VCAP_IS1_HK_IP4_IP4,
+ VCAP_IS1_HK_IP4_L3_FRAGMENT,
+ VCAP_IS1_HK_IP4_L3_FRAG_OFS_GT0,
+ VCAP_IS1_HK_IP4_L3_OPTIONS,
+ VCAP_IS1_HK_IP4_L3_DSCP,
+ VCAP_IS1_HK_IP4_L3_IP4_DIP,
+ VCAP_IS1_HK_IP4_L3_IP4_SIP,
+ VCAP_IS1_HK_IP4_L3_PROTO,
+ VCAP_IS1_HK_IP4_TCP_UDP,
+ VCAP_IS1_HK_IP4_TCP,
+ VCAP_IS1_HK_IP4_L4_RNG,
+ VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE,
+};
+
+enum vcap_is1_action_field {
+ VCAP_IS1_ACT_DSCP_ENA,
+ VCAP_IS1_ACT_DSCP_VAL,
+ VCAP_IS1_ACT_QOS_ENA,
+ VCAP_IS1_ACT_QOS_VAL,
+ VCAP_IS1_ACT_DP_ENA,
+ VCAP_IS1_ACT_DP_VAL,
+ VCAP_IS1_ACT_PAG_OVERRIDE_MASK,
+ VCAP_IS1_ACT_PAG_VAL,
+ VCAP_IS1_ACT_RSV,
+ VCAP_IS1_ACT_VID_REPLACE_ENA,
+ VCAP_IS1_ACT_VID_ADD_VAL,
+ VCAP_IS1_ACT_FID_SEL,
+ VCAP_IS1_ACT_FID_VAL,
+ VCAP_IS1_ACT_PCP_DEI_ENA,
+ VCAP_IS1_ACT_PCP_VAL,
+ VCAP_IS1_ACT_DEI_VAL,
+ VCAP_IS1_ACT_VLAN_POP_CNT_ENA,
+ VCAP_IS1_ACT_VLAN_POP_CNT,
+ VCAP_IS1_ACT_CUSTOM_ACE_TYPE_ENA,
+ VCAP_IS1_ACT_HIT_STICKY,
+};
+
#endif /* _OCELOT_VCAP_H_ */
--
2.17.1