linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support
@ 2020-06-02  5:18 Xiaoliang Yang
  2020-06-02  5:18 ` [PATCH v2 net-next 01/10] net: mscc: ocelot: introduce a new ocelot_target_{read,write} API Xiaoliang Yang
                   ` (10 more replies)
  0 siblings, 11 replies; 29+ messages in thread
From: Xiaoliang Yang @ 2020-06-02  5:18 UTC (permalink / raw)
  To: xiaoliang.yang_1, po.liu, claudiu.manoil, alexandru.marginean,
	vladimir.oltean, leoyang.li, mingkai.hu, andrew, f.fainelli,
	vivien.didelot, davem, jiri, idosch, kuba, vinicius.gomes,
	nikolay, roopa, netdev, linux-kernel, horatiu.vultur,
	alexandre.belloni, allan.nielsen, joergen.andreasen,
	UNGLinuxDriver, linux-devel

This series patches adds support for VCAP IS1 and ES0 module, each VCAP
correspond to a flow chain to offload.

VCAP IS1 supports FLOW_ACTION_VLAN_MANGLE action to filter MAC, IP,
VLAN, protocol, and TCP/UDP ports keys and retag vlian tag,
FLOW_ACTION_PRIORITY action to classify packages to different Qos in hw.

VCAP ES0 supports FLOW_ACTION_VLAN_PUSH action to filter vlan keys
and push a specific vlan tag to frames.

Changes since v1->v2:
 - Use different chain to assign rules to different hardware VCAP, and
   use action goto chain to express flow order.
 - Add FLOW_ACTION_PRIORITY to add Qos classification on VCAP IS1.
 - Multiple actions support.
 - Fix some code issues.

Vladimir Oltean (3):
  net: mscc: ocelot: introduce a new ocelot_target_{read,write} API
  net: mscc: ocelot: generalize existing code for VCAP
  net: dsa: tag_ocelot: use VLAN information from tagging header when
    available

Xiaoliang Yang (7):
  net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by
    chain index
  net: mscc: ocelot: change vcap to be compatible with full and quad
    entry
  net: mscc: ocelot: VCAP IS1 support
  net: mscc: ocelot: VCAP ES0 support
  net: mscc: ocelot: multiple actions support
  net: ocelot: return error if rule is not found
  net: dsa: felix: correct VCAP IS2 keys offset

 drivers/net/dsa/ocelot/felix.c            |   2 -
 drivers/net/dsa/ocelot/felix.h            |   2 -
 drivers/net/dsa/ocelot/felix_vsc9959.c    | 202 +++++-
 drivers/net/ethernet/mscc/ocelot.c        |  11 +
 drivers/net/ethernet/mscc/ocelot_ace.c    | 729 ++++++++++++++++------
 drivers/net/ethernet/mscc/ocelot_ace.h    |  26 +-
 drivers/net/ethernet/mscc/ocelot_board.c  |   5 +-
 drivers/net/ethernet/mscc/ocelot_flower.c |  95 ++-
 drivers/net/ethernet/mscc/ocelot_io.c     |  17 +
 drivers/net/ethernet/mscc/ocelot_regs.c   |  21 +-
 drivers/net/ethernet/mscc/ocelot_s2.h     |  64 --
 include/soc/mscc/ocelot.h                 |  39 +-
 include/soc/mscc/ocelot_vcap.h            | 199 +++++-
 net/dsa/tag_ocelot.c                      |  29 +
 14 files changed, 1105 insertions(+), 336 deletions(-)
 delete mode 100644 drivers/net/ethernet/mscc/ocelot_s2.h

-- 
2.17.1


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 net-next 01/10] net: mscc: ocelot: introduce a new ocelot_target_{read,write} API
  2020-06-02  5:18 [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Xiaoliang Yang
@ 2020-06-02  5:18 ` Xiaoliang Yang
  2020-06-02  5:18 ` [PATCH v2 net-next 02/10] net: mscc: ocelot: generalize existing code for VCAP Xiaoliang Yang
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 29+ messages in thread
From: Xiaoliang Yang @ 2020-06-02  5:18 UTC (permalink / raw)
  To: xiaoliang.yang_1, po.liu, claudiu.manoil, alexandru.marginean,
	vladimir.oltean, leoyang.li, mingkai.hu, andrew, f.fainelli,
	vivien.didelot, davem, jiri, idosch, kuba, vinicius.gomes,
	nikolay, roopa, netdev, linux-kernel, horatiu.vultur,
	alexandre.belloni, allan.nielsen, joergen.andreasen,
	UNGLinuxDriver, linux-devel

From: Vladimir Oltean <vladimir.oltean@nxp.com>

There are some targets (register blocks) in the Ocelot switch that are
instantiated more than once. For example, the VCAP IS1, IS2 and ES0
blocks all share the same register layout for interacting with the cache
for the TCAM and the action RAM.

For the VCAPs, the procedure for servicing them is actually common. We
just need an API specifying which VCAP we are talking to, and we do that
via these raw ocelot_target_read and ocelot_target_write accessors.

In plain ocelot_read, the target is encoded into the register enum
itself:

	u16 target = reg >> TARGET_OFFSET;

For the VCAPs, the registers are currently defined like this:

	enum ocelot_reg {
	[...]
		S2_CORE_UPDATE_CTRL = S2 << TARGET_OFFSET,
		S2_CORE_MV_CFG,
		S2_CACHE_ENTRY_DAT,
		S2_CACHE_MASK_DAT,
		S2_CACHE_ACTION_DAT,
		S2_CACHE_CNT_DAT,
		S2_CACHE_TG_DAT,
	[...]
	};

which is precisely what we want to avoid, because we'd have to duplicate
the same register map for S1 and for S0, and then figure out how to pass
VCAP instance-specific registers to the ocelot_read calls (basically
another lookup table that undoes the effect of shifting with
TARGET_OFFSET).

So for some targets, propose a more raw API, similar to what is
currently done with ocelot_port_readl and ocelot_port_writel. Those
targets can only be accessed with ocelot_target_{read,write} and not
with ocelot_{read,write} after the conversion, which is fine.

The VCAP registers are not actually modified to use this new API as of
this patch. They will be modified in the next one.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 drivers/net/ethernet/mscc/ocelot_io.c | 17 +++++++++++++++++
 include/soc/mscc/ocelot.h             | 14 ++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/drivers/net/ethernet/mscc/ocelot_io.c b/drivers/net/ethernet/mscc/ocelot_io.c
index b229b1cb68ef..9b52d82f5399 100644
--- a/drivers/net/ethernet/mscc/ocelot_io.c
+++ b/drivers/net/ethernet/mscc/ocelot_io.c
@@ -59,6 +59,23 @@ void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg)
 }
 EXPORT_SYMBOL(ocelot_port_writel);
 
+u32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target,
+			    u32 reg, u32 offset)
+{
+	u32 val;
+
+	regmap_read(ocelot->targets[target],
+		    ocelot->map[target][reg] + offset, &val);
+	return val;
+}
+
+void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target,
+			      u32 val, u32 reg, u32 offset)
+{
+	regmap_write(ocelot->targets[target],
+		     ocelot->map[target][reg] + offset, val);
+}
+
 int ocelot_regfields_init(struct ocelot *ocelot,
 			  const struct reg_field *const regfields)
 {
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index 4953e9994df3..2ac08f3b8f68 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -578,6 +578,16 @@ struct ocelot_policer {
 #define ocelot_rmw_rix(ocelot, val, m, reg, ri) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_RSZ * (ri))
 #define ocelot_rmw(ocelot, val, m, reg) __ocelot_rmw_ix(ocelot, val, m, reg, 0)
 
+#define ocelot_target_read_ix(ocelot, target, reg, gi, ri) __ocelot_target_read_ix(ocelot, target, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
+#define ocelot_target_read_gix(ocelot, target, reg, gi) __ocelot_target_read_ix(ocelot, target, reg, reg##_GSZ * (gi))
+#define ocelot_target_read_rix(ocelot, target, reg, ri) __ocelot_target_read_ix(ocelot, target, reg, reg##_RSZ * (ri))
+#define ocelot_target_read(ocelot, target, reg) __ocelot_target_read_ix(ocelot, target, reg, 0)
+
+#define ocelot_target_write_ix(ocelot, target, val, reg, gi, ri) __ocelot_target_write_ix(ocelot, target, val, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
+#define ocelot_target_write_gix(ocelot, target, val, reg, gi) __ocelot_target_write_ix(ocelot, target, val, reg, reg##_GSZ * (gi))
+#define ocelot_target_write_rix(ocelot, target, val, reg, ri) __ocelot_target_write_ix(ocelot, target, val, reg, reg##_RSZ * (ri))
+#define ocelot_target_write(ocelot, target, val, reg) __ocelot_target_write_ix(ocelot, target, val, reg, 0)
+
 /* I/O */
 u32 ocelot_port_readl(struct ocelot_port *port, u32 reg);
 void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg);
@@ -585,6 +595,10 @@ u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
 void __ocelot_write_ix(struct ocelot *ocelot, u32 val, u32 reg, u32 offset);
 void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, u32 reg,
 		     u32 offset);
+u32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target,
+			    u32 reg, u32 offset);
+void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target,
+			      u32 val, u32 reg, u32 offset);
 
 /* Hardware initialization */
 int ocelot_regfields_init(struct ocelot *ocelot,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 net-next 02/10] net: mscc: ocelot: generalize existing code for VCAP
  2020-06-02  5:18 [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Xiaoliang Yang
  2020-06-02  5:18 ` [PATCH v2 net-next 01/10] net: mscc: ocelot: introduce a new ocelot_target_{read,write} API Xiaoliang Yang
@ 2020-06-02  5:18 ` Xiaoliang Yang
  2020-06-02  5:18 ` [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index Xiaoliang Yang
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 29+ messages in thread
From: Xiaoliang Yang @ 2020-06-02  5:18 UTC (permalink / raw)
  To: xiaoliang.yang_1, po.liu, claudiu.manoil, alexandru.marginean,
	vladimir.oltean, leoyang.li, mingkai.hu, andrew, f.fainelli,
	vivien.didelot, davem, jiri, idosch, kuba, vinicius.gomes,
	nikolay, roopa, netdev, linux-kernel, horatiu.vultur,
	alexandre.belloni, allan.nielsen, joergen.andreasen,
	UNGLinuxDriver, linux-devel

From: Vladimir Oltean <vladimir.oltean@nxp.com>

The Ocelot driver only supports VCAP IS2, the security enforcement block
which implements Access Control List actions (trap, drop, police).

In preparation of VCAP IS1 support, generalize the existing code to work
with any VCAP. In that direction, move all VCAP instantiation-specific
data to struct vcap_props, and pass that as an argument to each function
that does the key and action packing. Only the high-level functions need
to have access to ocelot->vcap[VCAP_IS2].

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
---
 drivers/net/dsa/ocelot/felix.c            |   2 -
 drivers/net/dsa/ocelot/felix.h            |   2 -
 drivers/net/dsa/ocelot/felix_vsc9959.c    |  25 +-
 drivers/net/ethernet/mscc/ocelot_ace.c    | 400 ++++++++++++----------
 drivers/net/ethernet/mscc/ocelot_board.c  |   5 +-
 drivers/net/ethernet/mscc/ocelot_flower.c |   1 +
 drivers/net/ethernet/mscc/ocelot_regs.c   |  20 +-
 drivers/net/ethernet/mscc/ocelot_s2.h     |  64 ----
 include/soc/mscc/ocelot.h                 |  21 +-
 include/soc/mscc/ocelot_vcap.h            |  62 ++++
 10 files changed, 313 insertions(+), 289 deletions(-)
 delete mode 100644 drivers/net/ethernet/mscc/ocelot_s2.h

diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 66648986e6e3..4508d6063fd9 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -432,8 +432,6 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
 	ocelot->num_stats	= felix->info->num_stats;
 	ocelot->shared_queue_sz	= felix->info->shared_queue_sz;
 	ocelot->num_mact_rows	= felix->info->num_mact_rows;
-	ocelot->vcap_is2_keys	= felix->info->vcap_is2_keys;
-	ocelot->vcap_is2_actions= felix->info->vcap_is2_actions;
 	ocelot->vcap		= felix->info->vcap;
 	ocelot->ops		= felix->info->ops;
 
diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h
index a891736ca006..b1b6ecfa5a55 100644
--- a/drivers/net/dsa/ocelot/felix.h
+++ b/drivers/net/dsa/ocelot/felix.h
@@ -21,8 +21,6 @@ struct felix_info {
 	unsigned int			num_stats;
 	int				num_ports;
 	int                             num_tx_queues;
-	struct vcap_field		*vcap_is2_keys;
-	struct vcap_field		*vcap_is2_actions;
 	const struct vcap_props		*vcap;
 	int				switch_pci_bar;
 	int				imdio_pci_bar;
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index 1dd9e348152d..ef3bf875e64c 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -156,14 +156,16 @@ static const u32 vsc9959_qs_regmap[] = {
 	REG_RESERVED(QS_INH_DBG),
 };
 
-static const u32 vsc9959_s2_regmap[] = {
-	REG(S2_CORE_UPDATE_CTRL,		0x000000),
-	REG(S2_CORE_MV_CFG,			0x000004),
-	REG(S2_CACHE_ENTRY_DAT,			0x000008),
-	REG(S2_CACHE_MASK_DAT,			0x000108),
-	REG(S2_CACHE_ACTION_DAT,		0x000208),
-	REG(S2_CACHE_CNT_DAT,			0x000308),
-	REG(S2_CACHE_TG_DAT,			0x000388),
+static const u32 vsc9959_vcap_regmap[] = {
+	/* VCAP_CORE_CFG */
+	REG(VCAP_CORE_UPDATE_CTRL,		0x000000),
+	REG(VCAP_CORE_MV_CFG,			0x000004),
+	/* VCAP_CORE_CACHE */
+	REG(VCAP_CACHE_ENTRY_DAT,		0x000008),
+	REG(VCAP_CACHE_MASK_DAT,		0x000108),
+	REG(VCAP_CACHE_ACTION_DAT,		0x000208),
+	REG(VCAP_CACHE_CNT_DAT,			0x000308),
+	REG(VCAP_CACHE_TG_DAT,			0x000388),
 };
 
 static const u32 vsc9959_qsys_regmap[] = {
@@ -335,7 +337,7 @@ static const u32 *vsc9959_regmap[] = {
 	[QSYS]	= vsc9959_qsys_regmap,
 	[REW]	= vsc9959_rew_regmap,
 	[SYS]	= vsc9959_sys_regmap,
-	[S2]	= vsc9959_s2_regmap,
+	[S2]	= vsc9959_vcap_regmap,
 	[PTP]	= vsc9959_ptp_regmap,
 	[GCB]	= vsc9959_gcb_regmap,
 };
@@ -677,6 +679,9 @@ static const struct vcap_props vsc9959_vcap_props[] = {
 		},
 		.counter_words = 4,
 		.counter_width = 32,
+		.target = S2,
+		.keys = vsc9959_vcap_is2_keys,
+		.actions = vsc9959_vcap_is2_actions,
 	},
 };
 
@@ -1401,8 +1406,6 @@ struct felix_info felix_info_vsc9959 = {
 	.ops			= &vsc9959_ops,
 	.stats_layout		= vsc9959_stats_layout,
 	.num_stats		= ARRAY_SIZE(vsc9959_stats_layout),
-	.vcap_is2_keys		= vsc9959_vcap_is2_keys,
-	.vcap_is2_actions	= vsc9959_vcap_is2_actions,
 	.vcap			= vsc9959_vcap_props,
 	.shared_queue_sz	= 128 * 1024,
 	.num_mact_rows		= 2048,
diff --git a/drivers/net/ethernet/mscc/ocelot_ace.c b/drivers/net/ethernet/mscc/ocelot_ace.c
index dfd82a3baab2..748c618db7d8 100644
--- a/drivers/net/ethernet/mscc/ocelot_ace.c
+++ b/drivers/net/ethernet/mscc/ocelot_ace.c
@@ -9,7 +9,6 @@
 #include <soc/mscc/ocelot_vcap.h>
 #include "ocelot_police.h"
 #include "ocelot_ace.h"
-#include "ocelot_s2.h"
 
 #define OCELOT_POLICER_DISCARD 0x17f
 #define ENTRY_WIDTH 32
@@ -48,126 +47,138 @@ struct vcap_data {
 	u32 tg_mask; /* Current type-group mask */
 };
 
-static u32 vcap_s2_read_update_ctrl(struct ocelot *ocelot)
+static u32 vcap_read_update_ctrl(struct ocelot *ocelot,
+				 const struct vcap_props *vcap)
 {
-	return ocelot_read(ocelot, S2_CORE_UPDATE_CTRL);
+	return ocelot_target_read(ocelot, vcap->target, VCAP_CORE_UPDATE_CTRL);
 }
 
-static void vcap_cmd(struct ocelot *ocelot, u16 ix, int cmd, int sel)
+static void vcap_cmd(struct ocelot *ocelot, const struct vcap_props *vcap,
+		     u16 ix, int cmd, int sel)
 {
-	const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
+	u32 value = (VCAP_CORE_UPDATE_CTRL_UPDATE_CMD(cmd) |
+		     VCAP_CORE_UPDATE_CTRL_UPDATE_ADDR(ix) |
+		     VCAP_CORE_UPDATE_CTRL_UPDATE_SHOT);
 
-	u32 value = (S2_CORE_UPDATE_CTRL_UPDATE_CMD(cmd) |
-		     S2_CORE_UPDATE_CTRL_UPDATE_ADDR(ix) |
-		     S2_CORE_UPDATE_CTRL_UPDATE_SHOT);
-
-	if ((sel & VCAP_SEL_ENTRY) && ix >= vcap_is2->entry_count)
+	if ((sel & VCAP_SEL_ENTRY) && ix >= vcap->entry_count)
 		return;
 
 	if (!(sel & VCAP_SEL_ENTRY))
-		value |= S2_CORE_UPDATE_CTRL_UPDATE_ENTRY_DIS;
+		value |= VCAP_CORE_UPDATE_CTRL_UPDATE_ENTRY_DIS;
 
 	if (!(sel & VCAP_SEL_ACTION))
-		value |= S2_CORE_UPDATE_CTRL_UPDATE_ACTION_DIS;
+		value |= VCAP_CORE_UPDATE_CTRL_UPDATE_ACTION_DIS;
 
 	if (!(sel & VCAP_SEL_COUNTER))
-		value |= S2_CORE_UPDATE_CTRL_UPDATE_CNT_DIS;
+		value |= VCAP_CORE_UPDATE_CTRL_UPDATE_CNT_DIS;
+
+	ocelot_target_write(ocelot, vcap->target, value, VCAP_CORE_UPDATE_CTRL);
 
-	ocelot_write(ocelot, value, S2_CORE_UPDATE_CTRL);
-	readx_poll_timeout(vcap_s2_read_update_ctrl, ocelot, value,
-				(value & S2_CORE_UPDATE_CTRL_UPDATE_SHOT) == 0,
-				10, 100000);
+	read_poll_timeout(vcap_read_update_ctrl, value,
+			  (value & VCAP_CORE_UPDATE_CTRL_UPDATE_SHOT) == 0,
+			  10, 100000, false, ocelot, vcap);
 }
 
 /* Convert from 0-based row to VCAP entry row and run command */
-static void vcap_row_cmd(struct ocelot *ocelot, u32 row, int cmd, int sel)
+static void vcap_row_cmd(struct ocelot *ocelot, const struct vcap_props *vcap,
+			 u32 row, int cmd, int sel)
 {
-	const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
-
-	vcap_cmd(ocelot, vcap_is2->entry_count - row - 1, cmd, sel);
+	vcap_cmd(ocelot, vcap, vcap->entry_count - row - 1, cmd, sel);
 }
 
-static void vcap_entry2cache(struct ocelot *ocelot, struct vcap_data *data)
+static void vcap_entry2cache(struct ocelot *ocelot,
+			     const struct vcap_props *vcap,
+			     struct vcap_data *data)
 {
-	const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
 	u32 entry_words, i;
 
-	entry_words = DIV_ROUND_UP(vcap_is2->entry_width, ENTRY_WIDTH);
+	entry_words = DIV_ROUND_UP(vcap->entry_width, ENTRY_WIDTH);
 
 	for (i = 0; i < entry_words; i++) {
-		ocelot_write_rix(ocelot, data->entry[i], S2_CACHE_ENTRY_DAT, i);
-		ocelot_write_rix(ocelot, ~data->mask[i], S2_CACHE_MASK_DAT, i);
+		ocelot_target_write_rix(ocelot, vcap->target, data->entry[i],
+					VCAP_CACHE_ENTRY_DAT, i);
+		ocelot_target_write_rix(ocelot, vcap->target, ~data->mask[i],
+					VCAP_CACHE_MASK_DAT, i);
 	}
-	ocelot_write(ocelot, data->tg, S2_CACHE_TG_DAT);
+	ocelot_target_write(ocelot, vcap->target, data->tg, VCAP_CACHE_TG_DAT);
 }
 
-static void vcap_cache2entry(struct ocelot *ocelot, struct vcap_data *data)
+static void vcap_cache2entry(struct ocelot *ocelot,
+			     const struct vcap_props *vcap,
+			     struct vcap_data *data)
 {
-	const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
 	u32 entry_words, i;
 
-	entry_words = DIV_ROUND_UP(vcap_is2->entry_width, ENTRY_WIDTH);
+	entry_words = DIV_ROUND_UP(vcap->entry_width, ENTRY_WIDTH);
 
 	for (i = 0; i < entry_words; i++) {
-		data->entry[i] = ocelot_read_rix(ocelot, S2_CACHE_ENTRY_DAT, i);
+		data->entry[i] = ocelot_target_read_rix(ocelot, vcap->target,
+							VCAP_CACHE_ENTRY_DAT, i);
 		// Invert mask
-		data->mask[i] = ~ocelot_read_rix(ocelot, S2_CACHE_MASK_DAT, i);
+		data->mask[i] = ~ocelot_target_read_rix(ocelot, vcap->target,
+							VCAP_CACHE_MASK_DAT, i);
 	}
-	data->tg = ocelot_read(ocelot, S2_CACHE_TG_DAT);
+	data->tg = ocelot_target_read(ocelot, vcap->target, VCAP_CACHE_TG_DAT);
 }
 
-static void vcap_action2cache(struct ocelot *ocelot, struct vcap_data *data)
+static void vcap_action2cache(struct ocelot *ocelot,
+			      const struct vcap_props *vcap,
+			      struct vcap_data *data)
 {
-	const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
 	u32 action_words, i, width, mask;
 
 	/* Encode action type */
-	width = vcap_is2->action_type_width;
+	width = vcap->action_type_width;
 	if (width) {
 		mask = GENMASK(width, 0);
 		data->action[0] = ((data->action[0] & ~mask) | data->type);
 	}
 
-	action_words = DIV_ROUND_UP(vcap_is2->action_width, ENTRY_WIDTH);
+	action_words = DIV_ROUND_UP(vcap->action_width, ENTRY_WIDTH);
 
 	for (i = 0; i < action_words; i++)
-		ocelot_write_rix(ocelot, data->action[i], S2_CACHE_ACTION_DAT,
-				 i);
+		ocelot_target_write_rix(ocelot, vcap->target, data->action[i],
+					VCAP_CACHE_ACTION_DAT, i);
 
-	for (i = 0; i < vcap_is2->counter_words; i++)
-		ocelot_write_rix(ocelot, data->counter[i], S2_CACHE_CNT_DAT, i);
+	for (i = 0; i < vcap->counter_words; i++)
+		ocelot_target_write_rix(ocelot, vcap->target, data->counter[i],
+					VCAP_CACHE_CNT_DAT, i);
 }
 
-static void vcap_cache2action(struct ocelot *ocelot, struct vcap_data *data)
+static void vcap_cache2action(struct ocelot *ocelot,
+			      const struct vcap_props *vcap,
+			      struct vcap_data *data)
 {
-	const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
 	u32 action_words, i, width;
 
-	action_words = DIV_ROUND_UP(vcap_is2->action_width, ENTRY_WIDTH);
+	action_words = DIV_ROUND_UP(vcap->action_width, ENTRY_WIDTH);
 
 	for (i = 0; i < action_words; i++)
-		data->action[i] = ocelot_read_rix(ocelot, S2_CACHE_ACTION_DAT,
-						  i);
+		data->action[i] = ocelot_target_read_rix(ocelot, vcap->target,
+							 VCAP_CACHE_ACTION_DAT,
+							 i);
 
-	for (i = 0; i < vcap_is2->counter_words; i++)
-		data->counter[i] = ocelot_read_rix(ocelot, S2_CACHE_CNT_DAT, i);
+	for (i = 0; i < vcap->counter_words; i++)
+		data->counter[i] = ocelot_target_read_rix(ocelot, vcap->target,
+							  VCAP_CACHE_CNT_DAT,
+							  i);
 
 	/* Extract action type */
-	width = vcap_is2->action_type_width;
+	width = vcap->action_type_width;
 	data->type = (width ? (data->action[0] & GENMASK(width, 0)) : 0);
 }
 
 /* Calculate offsets for entry */
-static void is2_data_get(struct ocelot *ocelot, struct vcap_data *data, int ix)
+static void vcap_data_offset_get(const struct vcap_props *vcap,
+				 struct vcap_data *data, int ix)
 {
-	const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
 	u32 i, col, offset, count, cnt, base;
-	u32 width = vcap_is2->tg_width;
+	u32 width = vcap->tg_width;
 
 	count = (data->tg_sw == VCAP_TG_HALF ? 2 : 4);
 	col = (ix % 2);
-	cnt = (vcap_is2->sw_count / count);
-	base = (vcap_is2->sw_count - col * cnt - cnt);
+	cnt = (vcap->sw_count / count);
+	base = (vcap->sw_count - col * cnt - cnt);
 	data->tg_value = 0;
 	data->tg_mask = 0;
 	for (i = 0; i < cnt; i++) {
@@ -178,13 +189,13 @@ static void is2_data_get(struct ocelot *ocelot, struct vcap_data *data, int ix)
 
 	/* Calculate key/action/counter offsets */
 	col = (count - col - 1);
-	data->key_offset = (base * vcap_is2->entry_width) / vcap_is2->sw_count;
-	data->counter_offset = (cnt * col * vcap_is2->counter_width);
+	data->key_offset = (base * vcap->entry_width) / vcap->sw_count;
+	data->counter_offset = (cnt * col * vcap->counter_width);
 	i = data->type;
-	width = vcap_is2->action_table[i].width;
-	cnt = vcap_is2->action_table[i].count;
-	data->action_offset =
-		(((cnt * col * width) / count) + vcap_is2->action_type_width);
+	width = vcap->action_table[i].width;
+	cnt = vcap->action_table[i].count;
+	data->action_offset = (((cnt * col * width) / count) +
+			      vcap->action_type_width);
 }
 
 static void vcap_data_set(u32 *data, u32 offset, u32 len, u32 value)
@@ -222,22 +233,21 @@ static void vcap_key_field_set(struct vcap_data *data, u32 offset, u32 width,
 	vcap_data_set(data->mask, offset + data->key_offset, width, mask);
 }
 
-static void vcap_key_set(struct ocelot *ocelot, struct vcap_data *data,
-			 enum vcap_is2_half_key_field field,
-			 u32 value, u32 mask)
+static void vcap_key_set(const struct vcap_props *vcap, struct vcap_data *data,
+			 int field, u32 value, u32 mask)
 {
-	u32 offset = ocelot->vcap_is2_keys[field].offset;
-	u32 length = ocelot->vcap_is2_keys[field].length;
+	u32 offset = vcap->keys[field].offset;
+	u32 length = vcap->keys[field].length;
 
 	vcap_key_field_set(data, offset, length, value, mask);
 }
 
-static void vcap_key_bytes_set(struct ocelot *ocelot, struct vcap_data *data,
-			       enum vcap_is2_half_key_field field,
+static void vcap_key_bytes_set(const struct vcap_props *vcap,
+			       struct vcap_data *data, int field,
 			       u8 *val, u8 *msk)
 {
-	u32 offset = ocelot->vcap_is2_keys[field].offset;
-	u32 count  = ocelot->vcap_is2_keys[field].length;
+	u32 offset = vcap->keys[field].offset;
+	u32 count  = vcap->keys[field].length;
 	u32 i, j, n = 0, value = 0, mask = 0;
 
 	WARN_ON(count % 8);
@@ -263,37 +273,37 @@ static void vcap_key_bytes_set(struct ocelot *ocelot, struct vcap_data *data,
 	}
 }
 
-static void vcap_key_l4_port_set(struct ocelot *ocelot, struct vcap_data *data,
-				 enum vcap_is2_half_key_field field,
+static void vcap_key_l4_port_set(const struct vcap_props *vcap,
+				 struct vcap_data *data, int field,
 				 struct ocelot_vcap_udp_tcp *port)
 {
-	u32 offset = ocelot->vcap_is2_keys[field].offset;
-	u32 length = ocelot->vcap_is2_keys[field].length;
+	u32 offset = vcap->keys[field].offset;
+	u32 length = vcap->keys[field].length;
 
 	WARN_ON(length != 16);
 
 	vcap_key_field_set(data, offset, length, port->value, port->mask);
 }
 
-static void vcap_key_bit_set(struct ocelot *ocelot, struct vcap_data *data,
-			     enum vcap_is2_half_key_field field,
+static void vcap_key_bit_set(const struct vcap_props *vcap,
+			     struct vcap_data *data, int field,
 			     enum ocelot_vcap_bit val)
 {
-	u32 offset = ocelot->vcap_is2_keys[field].offset;
-	u32 length = ocelot->vcap_is2_keys[field].length;
 	u32 value = (val == OCELOT_VCAP_BIT_1 ? 1 : 0);
 	u32 msk = (val == OCELOT_VCAP_BIT_ANY ? 0 : 1);
+	u32 offset = vcap->keys[field].offset;
+	u32 length = vcap->keys[field].length;
 
 	WARN_ON(length != 1);
 
 	vcap_key_field_set(data, offset, length, value, msk);
 }
 
-static void vcap_action_set(struct ocelot *ocelot, struct vcap_data *data,
-			    enum vcap_is2_action_field field, u32 value)
+static void vcap_action_set(const struct vcap_props *vcap,
+			    struct vcap_data *data, int field, u32 value)
 {
-	int offset = ocelot->vcap_is2_actions[field].offset;
-	int length = ocelot->vcap_is2_actions[field].length;
+	int offset = vcap->actions[field].offset;
+	int length = vcap->actions[field].length;
 
 	vcap_data_set(data->action, offset + data->action_offset, length,
 		      value);
@@ -302,32 +312,34 @@ static void vcap_action_set(struct ocelot *ocelot, struct vcap_data *data,
 static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data,
 			   struct ocelot_ace_rule *ace)
 {
+	const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS2];
+
 	switch (ace->action) {
 	case OCELOT_ACL_ACTION_DROP:
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_PORT_MASK, 0);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_MASK_MODE, 1);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_ENA, 1);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_IDX,
+		vcap_action_set(vcap, data, VCAP_IS2_ACT_PORT_MASK, 0);
+		vcap_action_set(vcap, data, VCAP_IS2_ACT_MASK_MODE, 1);
+		vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_ENA, 1);
+		vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_IDX,
 				OCELOT_POLICER_DISCARD);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_COPY_ENA, 0);
+		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;
 	case OCELOT_ACL_ACTION_TRAP:
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_PORT_MASK, 0);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_MASK_MODE, 1);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_ENA, 0);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_IDX, 0);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_COPY_ENA, 1);
+		vcap_action_set(vcap, data, VCAP_IS2_ACT_PORT_MASK, 0);
+		vcap_action_set(vcap, data, VCAP_IS2_ACT_MASK_MODE, 1);
+		vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_ENA, 0);
+		vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_IDX, 0);
+		vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
+		vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_COPY_ENA, 1);
 		break;
 	case OCELOT_ACL_ACTION_POLICE:
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_PORT_MASK, 0);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_MASK_MODE, 0);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_ENA, 1);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_IDX,
+		vcap_action_set(vcap, data, VCAP_IS2_ACT_PORT_MASK, 0);
+		vcap_action_set(vcap, data, VCAP_IS2_ACT_MASK_MODE, 0);
+		vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_ENA, 1);
+		vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_IDX,
 				ace->pol_ix);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
-		vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_COPY_ENA, 0);
+		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;
 	}
 }
@@ -335,7 +347,7 @@ static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data,
 static void is2_entry_set(struct ocelot *ocelot, int ix,
 			  struct ocelot_ace_rule *ace)
 {
-	const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
+	const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS2];
 	u32 val, msk, type, type_mask = 0xf, i, count;
 	struct ocelot_ace_vlan *tag = &ace->vlan;
 	struct ocelot_vcap_u64 payload;
@@ -346,52 +358,52 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
 	memset(&data, 0, sizeof(data));
 
 	/* Read row */
-	vcap_row_cmd(ocelot, row, VCAP_CMD_READ, VCAP_SEL_ALL);
-	vcap_cache2entry(ocelot, &data);
-	vcap_cache2action(ocelot, &data);
+	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;
-	is2_data_get(ocelot, &data, ix);
+	vcap_data_offset_get(vcap, &data, ix);
 	data.tg = (data.tg & ~data.tg_mask);
 	if (ace->prio != 0)
 		data.tg |= data.tg_value;
 
 	data.type = IS2_ACTION_TYPE_NORMAL;
 
-	vcap_key_set(ocelot, &data, VCAP_IS2_HK_PAG, 0, 0);
-	vcap_key_set(ocelot, &data, VCAP_IS2_HK_IGR_PORT_MASK, 0,
+	vcap_key_set(vcap, &data, VCAP_IS2_HK_PAG, 0, 0);
+	vcap_key_set(vcap, &data, VCAP_IS2_HK_IGR_PORT_MASK, 0,
 		     ~ace->ingress_port_mask);
-	vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_FIRST, OCELOT_VCAP_BIT_1);
-	vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_HOST_MATCH,
+	vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_FIRST, OCELOT_VCAP_BIT_ANY);
+	vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_HOST_MATCH,
 			 OCELOT_VCAP_BIT_ANY);
-	vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L2_MC, ace->dmac_mc);
-	vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L2_BC, ace->dmac_bc);
-	vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_VLAN_TAGGED, tag->tagged);
-	vcap_key_set(ocelot, &data, VCAP_IS2_HK_VID,
+	vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L2_MC, ace->dmac_mc);
+	vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L2_BC, ace->dmac_bc);
+	vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_VLAN_TAGGED, tag->tagged);
+	vcap_key_set(vcap, &data, VCAP_IS2_HK_VID,
 		     tag->vid.value, tag->vid.mask);
-	vcap_key_set(ocelot, &data, VCAP_IS2_HK_PCP,
+	vcap_key_set(vcap, &data, VCAP_IS2_HK_PCP,
 		     tag->pcp.value[0], tag->pcp.mask[0]);
-	vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_DEI, tag->dei);
+	vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_DEI, tag->dei);
 
 	switch (ace->type) {
 	case OCELOT_ACE_TYPE_ETYPE: {
 		struct ocelot_ace_frame_etype *etype = &ace->frame.etype;
 
 		type = IS2_TYPE_ETYPE;
-		vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_DMAC,
+		vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_DMAC,
 				   etype->dmac.value, etype->dmac.mask);
-		vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_SMAC,
+		vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_SMAC,
 				   etype->smac.value, etype->smac.mask);
-		vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_MAC_ETYPE_ETYPE,
+		vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_ETYPE,
 				   etype->etype.value, etype->etype.mask);
 		/* Clear unused bits */
-		vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0,
+		vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0,
 			     0, 0);
-		vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1,
+		vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1,
 			     0, 0);
-		vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2,
+		vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2,
 			     0, 0);
-		vcap_key_bytes_set(ocelot, &data,
+		vcap_key_bytes_set(vcap, &data,
 				   VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0,
 				   etype->data.value, etype->data.mask);
 		break;
@@ -400,15 +412,15 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
 		struct ocelot_ace_frame_llc *llc = &ace->frame.llc;
 
 		type = IS2_TYPE_LLC;
-		vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_DMAC,
+		vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_DMAC,
 				   llc->dmac.value, llc->dmac.mask);
-		vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_SMAC,
+		vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_SMAC,
 				   llc->smac.value, llc->smac.mask);
 		for (i = 0; i < 4; i++) {
 			payload.value[i] = llc->llc.value[i];
 			payload.mask[i] = llc->llc.mask[i];
 		}
-		vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_MAC_LLC_L2_LLC,
+		vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_LLC_L2_LLC,
 				   payload.value, payload.mask);
 		break;
 	}
@@ -416,11 +428,11 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
 		struct ocelot_ace_frame_snap *snap = &ace->frame.snap;
 
 		type = IS2_TYPE_SNAP;
-		vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_DMAC,
+		vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_DMAC,
 				   snap->dmac.value, snap->dmac.mask);
-		vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_SMAC,
+		vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_SMAC,
 				   snap->smac.value, snap->smac.mask);
-		vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_MAC_SNAP_L2_SNAP,
+		vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_SNAP_L2_SNAP,
 				   ace->frame.snap.snap.value,
 				   ace->frame.snap.snap.mask);
 		break;
@@ -429,24 +441,24 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
 		struct ocelot_ace_frame_arp *arp = &ace->frame.arp;
 
 		type = IS2_TYPE_ARP;
-		vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_MAC_ARP_SMAC,
+		vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_ARP_SMAC,
 				   arp->smac.value, arp->smac.mask);
-		vcap_key_bit_set(ocelot, &data,
+		vcap_key_bit_set(vcap, &data,
 				 VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK,
 				 arp->ethernet);
-		vcap_key_bit_set(ocelot, &data,
+		vcap_key_bit_set(vcap, &data,
 				 VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK,
 				 arp->ip);
-		vcap_key_bit_set(ocelot, &data,
+		vcap_key_bit_set(vcap, &data,
 				 VCAP_IS2_HK_MAC_ARP_LEN_OK,
 				 arp->length);
-		vcap_key_bit_set(ocelot, &data,
+		vcap_key_bit_set(vcap, &data,
 				 VCAP_IS2_HK_MAC_ARP_TARGET_MATCH,
 				 arp->dmac_match);
-		vcap_key_bit_set(ocelot, &data,
+		vcap_key_bit_set(vcap, &data,
 				 VCAP_IS2_HK_MAC_ARP_SENDER_MATCH,
 				 arp->smac_match);
-		vcap_key_bit_set(ocelot, &data,
+		vcap_key_bit_set(vcap, &data,
 				 VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN,
 				 arp->unknown);
 
@@ -455,15 +467,15 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
 		       (arp->arp == OCELOT_VCAP_BIT_0 ? 2 : 0));
 		msk = ((arp->req == OCELOT_VCAP_BIT_ANY ? 0 : 1) |
 		       (arp->arp == OCELOT_VCAP_BIT_ANY ? 0 : 2));
-		vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ARP_OPCODE,
+		vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ARP_OPCODE,
 			     val, msk);
-		vcap_key_bytes_set(ocelot, &data,
+		vcap_key_bytes_set(vcap, &data,
 				   VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP,
 				   arp->dip.value.addr, arp->dip.mask.addr);
-		vcap_key_bytes_set(ocelot, &data,
+		vcap_key_bytes_set(vcap, &data,
 				   VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP,
 				   arp->sip.value.addr, arp->sip.mask.addr);
-		vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP,
+		vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP,
 			     0, 0);
 		break;
 	}
@@ -532,22 +544,22 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
 			seq_zero = ipv6->seq_zero;
 		}
 
-		vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_IP4,
+		vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_IP4,
 				 ipv4 ? OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
-		vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L3_FRAGMENT,
+		vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L3_FRAGMENT,
 				 fragment);
-		vcap_key_set(ocelot, &data, VCAP_IS2_HK_L3_FRAG_OFS_GT0, 0, 0);
-		vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L3_OPTIONS,
+		vcap_key_set(vcap, &data, VCAP_IS2_HK_L3_FRAG_OFS_GT0, 0, 0);
+		vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L3_OPTIONS,
 				 options);
-		vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_IP4_L3_TTL_GT0,
+		vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_IP4_L3_TTL_GT0,
 				 ttl);
-		vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L3_TOS,
+		vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L3_TOS,
 				   ds.value, ds.mask);
-		vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L3_IP4_DIP,
+		vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L3_IP4_DIP,
 				   dip.value.addr, dip.mask.addr);
-		vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L3_IP4_SIP,
+		vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L3_IP4_SIP,
 				   sip.value.addr, sip.mask.addr);
-		vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_DIP_EQ_SIP,
+		vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_DIP_EQ_SIP,
 				 sip_eq_dip);
 		val = proto.value[0];
 		msk = proto.mask[0];
@@ -556,33 +568,33 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
 			/* UDP/TCP protocol match */
 			tcp = (val == 6 ?
 			       OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
-			vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_TCP, tcp);
-			vcap_key_l4_port_set(ocelot, &data,
+			vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_TCP, tcp);
+			vcap_key_l4_port_set(vcap, &data,
 					     VCAP_IS2_HK_L4_DPORT, dport);
-			vcap_key_l4_port_set(ocelot, &data,
+			vcap_key_l4_port_set(vcap, &data,
 					     VCAP_IS2_HK_L4_SPORT, sport);
-			vcap_key_set(ocelot, &data, VCAP_IS2_HK_L4_RNG, 0, 0);
-			vcap_key_bit_set(ocelot, &data,
+			vcap_key_set(vcap, &data, VCAP_IS2_HK_L4_RNG, 0, 0);
+			vcap_key_bit_set(vcap, &data,
 					 VCAP_IS2_HK_L4_SPORT_EQ_DPORT,
 					 sport_eq_dport);
-			vcap_key_bit_set(ocelot, &data,
+			vcap_key_bit_set(vcap, &data,
 					 VCAP_IS2_HK_L4_SEQUENCE_EQ0,
 					 seq_zero);
-			vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_FIN,
+			vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_FIN,
 					 tcp_fin);
-			vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_SYN,
+			vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_SYN,
 					 tcp_syn);
-			vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_RST,
+			vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_RST,
 					 tcp_rst);
-			vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_PSH,
+			vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_PSH,
 					 tcp_psh);
-			vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_ACK,
+			vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_ACK,
 					 tcp_ack);
-			vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_URG,
+			vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_URG,
 					 tcp_urg);
-			vcap_key_set(ocelot, &data, VCAP_IS2_HK_L4_1588_DOM,
+			vcap_key_set(vcap, &data, VCAP_IS2_HK_L4_1588_DOM,
 				     0, 0);
-			vcap_key_set(ocelot, &data, VCAP_IS2_HK_L4_1588_VER,
+			vcap_key_set(vcap, &data, VCAP_IS2_HK_L4_1588_VER,
 				     0, 0);
 		} else {
 			if (msk == 0) {
@@ -596,10 +608,10 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
 					payload.mask[i] = ip_data->mask[i];
 				}
 			}
-			vcap_key_bytes_set(ocelot, &data,
+			vcap_key_bytes_set(vcap, &data,
 					   VCAP_IS2_HK_IP4_L3_PROTO,
 					   proto.value, proto.mask);
-			vcap_key_bytes_set(ocelot, &data,
+			vcap_key_bytes_set(vcap, &data,
 					   VCAP_IS2_HK_L3_PAYLOAD,
 					   payload.value, payload.mask);
 		}
@@ -609,42 +621,44 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
 	default:
 		type = 0;
 		type_mask = 0;
-		count = vcap_is2->entry_width / 2;
+		count = vcap->entry_width / 2;
 		/* Iterate over the non-common part of the key and
 		 * clear entry data
 		 */
-		for (i = ocelot->vcap_is2_keys[VCAP_IS2_HK_L2_DMAC].offset;
+		for (i = vcap->keys[VCAP_IS2_HK_L2_DMAC].offset;
 		     i < count; i += ENTRY_WIDTH) {
 			vcap_key_field_set(&data, i, min(32u, count - i), 0, 0);
 		}
 		break;
 	}
 
-	vcap_key_set(ocelot, &data, VCAP_IS2_TYPE, type, type_mask);
+	vcap_key_set(vcap, &data, VCAP_IS2_TYPE, type, type_mask);
 	is2_action_set(ocelot, &data, ace);
 	vcap_data_set(data.counter, data.counter_offset,
-		      vcap_is2->counter_width, ace->stats.pkts);
+		       vcap->counter_width, ace->stats.pkts);
 
 	/* Write row */
-	vcap_entry2cache(ocelot, &data);
-	vcap_action2cache(ocelot, &data);
-	vcap_row_cmd(ocelot, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
+	vcap_entry2cache(ocelot, vcap, &data);
+	vcap_action2cache(ocelot, vcap, &data);
+	vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
 }
 
-static void is2_entry_get(struct ocelot *ocelot, struct ocelot_ace_rule *rule,
-			  int ix)
+static void vcap_entry_get(struct ocelot *ocelot, struct ocelot_ace_rule *rule,
+			   int ix)
 {
-	const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
+	const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS2];
 	struct vcap_data data;
-	int row = (ix / 2);
+	int row, count;
 	u32 cnt;
 
-	vcap_row_cmd(ocelot, row, VCAP_CMD_READ, VCAP_SEL_COUNTER);
-	vcap_cache2action(ocelot, &data);
 	data.tg_sw = VCAP_TG_HALF;
-	is2_data_get(ocelot, &data, ix);
+	count = (1 << (data.tg_sw - 1));
+	row = (ix / count);
+	vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_READ, VCAP_SEL_COUNTER);
+	vcap_cache2action(ocelot, vcap, &data);
+	vcap_data_offset_get(vcap, &data, ix);
 	cnt = vcap_data_get(data.counter, data.counter_offset,
-			    vcap_is2->counter_width);
+			       vcap->counter_width);
 
 	rule->stats.pkts = cnt;
 }
@@ -924,7 +938,7 @@ int ocelot_ace_rule_stats_update(struct ocelot *ocelot,
 	int index;
 
 	index = ocelot_ace_rule_get_index_id(block, rule);
-	is2_entry_get(ocelot, rule, index);
+	vcap_entry_get(ocelot, rule, index);
 
 	/* After we get the result we need to clear the counters */
 	tmp = ocelot_ace_rule_get_rule_index(block, index);
@@ -934,22 +948,29 @@ int ocelot_ace_rule_stats_update(struct ocelot *ocelot,
 	return 0;
 }
 
-int ocelot_ace_init(struct ocelot *ocelot)
+static void vcap_init(struct ocelot *ocelot, const struct vcap_props *vcap)
 {
-	const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
-	struct ocelot_acl_block *block = &ocelot->acl_block;
 	struct vcap_data data;
 
 	memset(&data, 0, sizeof(data));
 
-	vcap_entry2cache(ocelot, &data);
-	ocelot_write(ocelot, vcap_is2->entry_count, S2_CORE_MV_CFG);
-	vcap_cmd(ocelot, 0, VCAP_CMD_INITIALIZE, VCAP_SEL_ENTRY);
+	vcap_entry2cache(ocelot, vcap, &data);
+	ocelot_target_write(ocelot, vcap->target, vcap->entry_count,
+			    VCAP_CORE_MV_CFG);
+	vcap_cmd(ocelot, vcap, 0, VCAP_CMD_INITIALIZE, VCAP_SEL_ENTRY);
 
-	vcap_action2cache(ocelot, &data);
-	ocelot_write(ocelot, vcap_is2->action_count, S2_CORE_MV_CFG);
-	vcap_cmd(ocelot, 0, VCAP_CMD_INITIALIZE,
+	vcap_action2cache(ocelot, vcap, &data);
+	ocelot_target_write(ocelot, vcap->target, vcap->action_count,
+			    VCAP_CORE_MV_CFG);
+	vcap_cmd(ocelot, vcap, 0, VCAP_CMD_INITIALIZE,
 		 VCAP_SEL_ACTION | VCAP_SEL_COUNTER);
+}
+
+int ocelot_ace_init(struct ocelot *ocelot)
+{
+	struct ocelot_acl_block *block = &ocelot->acl_block;
+
+	vcap_init(ocelot, &ocelot->vcap[VCAP_IS2]);
 
 	/* Create a policer that will drop the frames for the cpu.
 	 * This policer will be used as action in the acl rules to drop
@@ -967,8 +988,7 @@ int ocelot_ace_init(struct ocelot *ocelot)
 			 OCELOT_POLICER_DISCARD);
 
 	block->pol_lpr = OCELOT_POLICER_DISCARD - 1;
-
-	INIT_LIST_HEAD(&ocelot->acl_block.rules);
+	INIT_LIST_HEAD(&block->rules);
 
 	return 0;
 }
diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c
index 4a15d2ff8b70..db1b4935c48b 100644
--- a/drivers/net/ethernet/mscc/ocelot_board.c
+++ b/drivers/net/ethernet/mscc/ocelot_board.c
@@ -364,6 +364,9 @@ static const struct vcap_props vsc7514_vcap_props[] = {
 		},
 		.counter_words = 4,
 		.counter_width = 32,
+		.target = S2,
+		.keys = vsc7514_vcap_is2_keys,
+		.actions = vsc7514_vcap_is2_actions,
 	},
 };
 
@@ -482,8 +485,6 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
 	ocelot->ports = devm_kcalloc(&pdev->dev, ocelot->num_phys_ports,
 				     sizeof(struct ocelot_port *), GFP_KERNEL);
 
-	ocelot->vcap_is2_keys = vsc7514_vcap_is2_keys;
-	ocelot->vcap_is2_actions = vsc7514_vcap_is2_actions;
 	ocelot->vcap = vsc7514_vcap_props;
 
 	ocelot_init(ocelot);
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index 5ce172e22b43..891925f73cbc 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -5,6 +5,7 @@
 
 #include <net/pkt_cls.h>
 #include <net/tc_act/tc_gact.h>
+#include <soc/mscc/ocelot_vcap.h>
 
 #include "ocelot_ace.h"
 
diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c
index 81d81ff75646..18ce99730406 100644
--- a/drivers/net/ethernet/mscc/ocelot_regs.c
+++ b/drivers/net/ethernet/mscc/ocelot_regs.c
@@ -224,14 +224,16 @@ static const u32 ocelot_sys_regmap[] = {
 	REG(SYS_PTP_CFG,                   0x0006c4),
 };
 
-static const u32 ocelot_s2_regmap[] = {
-	REG(S2_CORE_UPDATE_CTRL,           0x000000),
-	REG(S2_CORE_MV_CFG,                0x000004),
-	REG(S2_CACHE_ENTRY_DAT,            0x000008),
-	REG(S2_CACHE_MASK_DAT,             0x000108),
-	REG(S2_CACHE_ACTION_DAT,           0x000208),
-	REG(S2_CACHE_CNT_DAT,              0x000308),
-	REG(S2_CACHE_TG_DAT,               0x000388),
+static const u32 ocelot_vcap_regmap[] = {
+	/* VCAP_CORE_CFG */
+	REG(VCAP_CORE_UPDATE_CTRL,         0x000000),
+	REG(VCAP_CORE_MV_CFG,              0x000004),
+	/* VCAP_CORE_CACHE */
+	REG(VCAP_CACHE_ENTRY_DAT,          0x000008),
+	REG(VCAP_CACHE_MASK_DAT,           0x000108),
+	REG(VCAP_CACHE_ACTION_DAT,         0x000208),
+	REG(VCAP_CACHE_CNT_DAT,            0x000308),
+	REG(VCAP_CACHE_TG_DAT,             0x000388),
 };
 
 static const u32 ocelot_ptp_regmap[] = {
@@ -252,7 +254,7 @@ static const u32 *ocelot_regmap[] = {
 	[QSYS] = ocelot_qsys_regmap,
 	[REW] = ocelot_rew_regmap,
 	[SYS] = ocelot_sys_regmap,
-	[S2] = ocelot_s2_regmap,
+	[S2] = ocelot_vcap_regmap,
 	[PTP] = ocelot_ptp_regmap,
 };
 
diff --git a/drivers/net/ethernet/mscc/ocelot_s2.h b/drivers/net/ethernet/mscc/ocelot_s2.h
deleted file mode 100644
index 80107bec2e45..000000000000
--- a/drivers/net/ethernet/mscc/ocelot_s2.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
-/* Microsemi Ocelot Switch driver
- * Copyright (c) 2018 Microsemi Corporation
- */
-
-#ifndef _OCELOT_S2_CORE_H_
-#define _OCELOT_S2_CORE_H_
-
-#define S2_CORE_UPDATE_CTRL_UPDATE_CMD(x)      (((x) << 22) & GENMASK(24, 22))
-#define S2_CORE_UPDATE_CTRL_UPDATE_CMD_M       GENMASK(24, 22)
-#define S2_CORE_UPDATE_CTRL_UPDATE_CMD_X(x)    (((x) & GENMASK(24, 22)) >> 22)
-#define S2_CORE_UPDATE_CTRL_UPDATE_ENTRY_DIS   BIT(21)
-#define S2_CORE_UPDATE_CTRL_UPDATE_ACTION_DIS  BIT(20)
-#define S2_CORE_UPDATE_CTRL_UPDATE_CNT_DIS     BIT(19)
-#define S2_CORE_UPDATE_CTRL_UPDATE_ADDR(x)     (((x) << 3) & GENMASK(18, 3))
-#define S2_CORE_UPDATE_CTRL_UPDATE_ADDR_M      GENMASK(18, 3)
-#define S2_CORE_UPDATE_CTRL_UPDATE_ADDR_X(x)   (((x) & GENMASK(18, 3)) >> 3)
-#define S2_CORE_UPDATE_CTRL_UPDATE_SHOT        BIT(2)
-#define S2_CORE_UPDATE_CTRL_CLEAR_CACHE        BIT(1)
-#define S2_CORE_UPDATE_CTRL_MV_TRAFFIC_IGN     BIT(0)
-
-#define S2_CORE_MV_CFG_MV_NUM_POS(x)           (((x) << 16) & GENMASK(31, 16))
-#define S2_CORE_MV_CFG_MV_NUM_POS_M            GENMASK(31, 16)
-#define S2_CORE_MV_CFG_MV_NUM_POS_X(x)         (((x) & GENMASK(31, 16)) >> 16)
-#define S2_CORE_MV_CFG_MV_SIZE(x)              ((x) & GENMASK(15, 0))
-#define S2_CORE_MV_CFG_MV_SIZE_M               GENMASK(15, 0)
-
-#define S2_CACHE_ENTRY_DAT_RSZ                 0x4
-
-#define S2_CACHE_MASK_DAT_RSZ                  0x4
-
-#define S2_CACHE_ACTION_DAT_RSZ                0x4
-
-#define S2_CACHE_CNT_DAT_RSZ                   0x4
-
-#define S2_STICKY_VCAP_ROW_DELETED_STICKY      BIT(0)
-
-#define S2_BIST_CTRL_TCAM_BIST                 BIT(1)
-#define S2_BIST_CTRL_TCAM_INIT                 BIT(0)
-
-#define S2_BIST_CFG_TCAM_BIST_SOE_ENA          BIT(8)
-#define S2_BIST_CFG_TCAM_HCG_DIS               BIT(7)
-#define S2_BIST_CFG_TCAM_CG_DIS                BIT(6)
-#define S2_BIST_CFG_TCAM_BIAS(x)               ((x) & GENMASK(5, 0))
-#define S2_BIST_CFG_TCAM_BIAS_M                GENMASK(5, 0)
-
-#define S2_BIST_STAT_BIST_RT_ERR               BIT(15)
-#define S2_BIST_STAT_BIST_PENC_ERR             BIT(14)
-#define S2_BIST_STAT_BIST_COMP_ERR             BIT(13)
-#define S2_BIST_STAT_BIST_ADDR_ERR             BIT(12)
-#define S2_BIST_STAT_BIST_BL1E_ERR             BIT(11)
-#define S2_BIST_STAT_BIST_BL1_ERR              BIT(10)
-#define S2_BIST_STAT_BIST_BL0E_ERR             BIT(9)
-#define S2_BIST_STAT_BIST_BL0_ERR              BIT(8)
-#define S2_BIST_STAT_BIST_PH1_ERR              BIT(7)
-#define S2_BIST_STAT_BIST_PH0_ERR              BIT(6)
-#define S2_BIST_STAT_BIST_PV1_ERR              BIT(5)
-#define S2_BIST_STAT_BIST_PV0_ERR              BIT(4)
-#define S2_BIST_STAT_BIST_RUN                  BIT(3)
-#define S2_BIST_STAT_BIST_ERR                  BIT(2)
-#define S2_BIST_STAT_BIST_BUSY                 BIT(1)
-#define S2_BIST_STAT_TCAM_RDY                  BIT(0)
-
-#endif /* _OCELOT_S2_CORE_H_ */
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index 2ac08f3b8f68..91357b1c8f31 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -376,13 +376,6 @@ enum ocelot_reg {
 	SYS_CM_DATA_RD,
 	SYS_CM_OP,
 	SYS_CM_DATA,
-	S2_CORE_UPDATE_CTRL = S2 << TARGET_OFFSET,
-	S2_CORE_MV_CFG,
-	S2_CACHE_ENTRY_DAT,
-	S2_CACHE_MASK_DAT,
-	S2_CACHE_ACTION_DAT,
-	S2_CACHE_CNT_DAT,
-	S2_CACHE_TG_DAT,
 	PTP_PIN_CFG = PTP << TARGET_OFFSET,
 	PTP_PIN_TOD_SEC_MSB,
 	PTP_PIN_TOD_SEC_LSB,
@@ -395,6 +388,18 @@ enum ocelot_reg {
 	GCB_SOFT_RST = GCB << TARGET_OFFSET,
 };
 
+enum {
+	/* VCAP_CORE_CFG */
+	VCAP_CORE_UPDATE_CTRL,
+	VCAP_CORE_MV_CFG,
+	/* VCAP_CORE_CACHE */
+	VCAP_CACHE_ENTRY_DAT,
+	VCAP_CACHE_MASK_DAT,
+	VCAP_CACHE_ACTION_DAT,
+	VCAP_CACHE_CNT_DAT,
+	VCAP_CACHE_TG_DAT,
+};
+
 enum ocelot_regfield {
 	ANA_ADVLEARN_VLAN_CHK,
 	ANA_ADVLEARN_LEARN_MIRROR,
@@ -537,8 +542,6 @@ struct ocelot {
 
 	struct ocelot_acl_block		acl_block;
 
-	const struct vcap_field		*vcap_is2_keys;
-	const struct vcap_field		*vcap_is2_actions;
 	const struct vcap_props		*vcap;
 
 	/* Workqueue to check statistics for overflow with its lock */
diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h
index 5748373ab4d3..26d9384b3657 100644
--- a/include/soc/mscc/ocelot_vcap.h
+++ b/include/soc/mscc/ocelot_vcap.h
@@ -6,6 +6,8 @@
 #ifndef _OCELOT_VCAP_H_
 #define _OCELOT_VCAP_H_
 
+#include "ocelot.h"
+
 /* =================================================================
  *  VCAP Common
  * =================================================================
@@ -33,6 +35,11 @@ struct vcap_props {
 	} action_table[2];
 	u16 counter_words; /* Number of counter words */
 	u16 counter_width; /* Counter width (in bits) */
+
+	enum ocelot_target		target;
+
+	const struct vcap_field		*keys;
+	const struct vcap_field		*actions;
 };
 
 /* VCAP Type-Group values */
@@ -41,6 +48,61 @@ struct vcap_props {
 #define VCAP_TG_HALF 2 /* Half entry */
 #define VCAP_TG_QUARTER 3 /* Quarter entry */
 
+#define VCAP_CORE_UPDATE_CTRL_UPDATE_CMD(x)      (((x) << 22) & GENMASK(24, 22))
+#define VCAP_CORE_UPDATE_CTRL_UPDATE_CMD_M       GENMASK(24, 22)
+#define VCAP_CORE_UPDATE_CTRL_UPDATE_CMD_X(x)    (((x) & GENMASK(24, 22)) >> 22)
+#define VCAP_CORE_UPDATE_CTRL_UPDATE_ENTRY_DIS   BIT(21)
+#define VCAP_CORE_UPDATE_CTRL_UPDATE_ACTION_DIS  BIT(20)
+#define VCAP_CORE_UPDATE_CTRL_UPDATE_CNT_DIS     BIT(19)
+#define VCAP_CORE_UPDATE_CTRL_UPDATE_ADDR(x)     (((x) << 3) & GENMASK(18, 3))
+#define VCAP_CORE_UPDATE_CTRL_UPDATE_ADDR_M      GENMASK(18, 3)
+#define VCAP_CORE_UPDATE_CTRL_UPDATE_ADDR_X(x)   (((x) & GENMASK(18, 3)) >> 3)
+#define VCAP_CORE_UPDATE_CTRL_UPDATE_SHOT        BIT(2)
+#define VCAP_CORE_UPDATE_CTRL_CLEAR_CACHE        BIT(1)
+#define VCAP_CORE_UPDATE_CTRL_MV_TRAFFIC_IGN     BIT(0)
+
+#define VCAP_CORE_MV_CFG_MV_NUM_POS(x)           (((x) << 16) & GENMASK(31, 16))
+#define VCAP_CORE_MV_CFG_MV_NUM_POS_M            GENMASK(31, 16)
+#define VCAP_CORE_MV_CFG_MV_NUM_POS_X(x)         (((x) & GENMASK(31, 16)) >> 16)
+#define VCAP_CORE_MV_CFG_MV_SIZE(x)              ((x) & GENMASK(15, 0))
+#define VCAP_CORE_MV_CFG_MV_SIZE_M               GENMASK(15, 0)
+
+#define VCAP_CACHE_ENTRY_DAT_RSZ                 0x4
+
+#define VCAP_CACHE_MASK_DAT_RSZ                  0x4
+
+#define VCAP_CACHE_ACTION_DAT_RSZ                0x4
+
+#define VCAP_CACHE_CNT_DAT_RSZ                   0x4
+
+#define VCAP_STICKY_VCAP_ROW_DELETED_STICKY      BIT(0)
+
+#define TCAM_BIST_CTRL_TCAM_BIST                 BIT(1)
+#define TCAM_BIST_CTRL_TCAM_INIT                 BIT(0)
+
+#define TCAM_BIST_CFG_TCAM_BIST_SOE_ENA          BIT(8)
+#define TCAM_BIST_CFG_TCAM_HCG_DIS               BIT(7)
+#define TCAM_BIST_CFG_TCAM_CG_DIS                BIT(6)
+#define TCAM_BIST_CFG_TCAM_BIAS(x)               ((x) & GENMASK(5, 0))
+#define TCAM_BIST_CFG_TCAM_BIAS_M                GENMASK(5, 0)
+
+#define TCAM_BIST_STAT_BIST_RT_ERR               BIT(15)
+#define TCAM_BIST_STAT_BIST_PENC_ERR             BIT(14)
+#define TCAM_BIST_STAT_BIST_COMP_ERR             BIT(13)
+#define TCAM_BIST_STAT_BIST_ADDR_ERR             BIT(12)
+#define TCAM_BIST_STAT_BIST_BL1E_ERR             BIT(11)
+#define TCAM_BIST_STAT_BIST_BL1_ERR              BIT(10)
+#define TCAM_BIST_STAT_BIST_BL0E_ERR             BIT(9)
+#define TCAM_BIST_STAT_BIST_BL0_ERR              BIT(8)
+#define TCAM_BIST_STAT_BIST_PH1_ERR              BIT(7)
+#define TCAM_BIST_STAT_BIST_PH0_ERR              BIT(6)
+#define TCAM_BIST_STAT_BIST_PV1_ERR              BIT(5)
+#define TCAM_BIST_STAT_BIST_PV0_ERR              BIT(4)
+#define TCAM_BIST_STAT_BIST_RUN                  BIT(3)
+#define TCAM_BIST_STAT_BIST_ERR                  BIT(2)
+#define TCAM_BIST_STAT_BIST_BUSY                 BIT(1)
+#define TCAM_BIST_STAT_TCAM_RDY                  BIT(0)
+
 /* =================================================================
  *  VCAP IS2
  * =================================================================
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index
  2020-06-02  5:18 [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Xiaoliang Yang
  2020-06-02  5:18 ` [PATCH v2 net-next 01/10] net: mscc: ocelot: introduce a new ocelot_target_{read,write} API Xiaoliang Yang
  2020-06-02  5:18 ` [PATCH v2 net-next 02/10] net: mscc: ocelot: generalize existing code for VCAP Xiaoliang Yang
@ 2020-06-02  5:18 ` Xiaoliang Yang
  2020-06-02  8:36   ` Allan W. Nielsen
  2020-06-02  5:18 ` [PATCH v2 net-next 04/10] net: mscc: ocelot: change vcap to be compatible with full and quad entry Xiaoliang Yang
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Xiaoliang Yang @ 2020-06-02  5:18 UTC (permalink / raw)
  To: xiaoliang.yang_1, po.liu, claudiu.manoil, alexandru.marginean,
	vladimir.oltean, leoyang.li, mingkai.hu, andrew, f.fainelli,
	vivien.didelot, davem, jiri, idosch, kuba, vinicius.gomes,
	nikolay, roopa, netdev, linux-kernel, horatiu.vultur,
	alexandre.belloni, allan.nielsen, joergen.andreasen,
	UNGLinuxDriver, linux-devel

There are three hardware TCAMs for ocelot chips: IS1, IS2 and ES0. Each
one supports different actions. The hardware flow order is: IS1->IS2->ES0.

This patch add three blocks to store rules according to chain index.
chain 0 is offloaded to IS1, chain 1 is offloaded to IS2, and egress chain
0 is offloaded to ES0.

Using action goto chain to express flow order as follows:
	tc filter add dev swp0 chain 0 parent ffff: flower skip_sw \
	action goto chain 1

Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
---
 drivers/net/ethernet/mscc/ocelot_ace.c    | 51 +++++++++++++++--------
 drivers/net/ethernet/mscc/ocelot_ace.h    |  7 ++--
 drivers/net/ethernet/mscc/ocelot_flower.c | 46 +++++++++++++++++---
 include/soc/mscc/ocelot.h                 |  2 +-
 include/soc/mscc/ocelot_vcap.h            |  4 +-
 5 files changed, 81 insertions(+), 29 deletions(-)

diff --git a/drivers/net/ethernet/mscc/ocelot_ace.c b/drivers/net/ethernet/mscc/ocelot_ace.c
index 748c618db7d8..b76593b40097 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;
 	}
 }
 
@@ -644,9 +646,9 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
 }
 
 static void vcap_entry_get(struct ocelot *ocelot, struct ocelot_ace_rule *rule,
-			   int ix)
+			   int ix, int block_id)
 {
-	const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS2];
+	const struct vcap_props *vcap = &ocelot->vcap[block_id];
 	struct vcap_data data;
 	int row, count;
 	u32 cnt;
@@ -663,6 +665,19 @@ static void vcap_entry_get(struct ocelot *ocelot, struct ocelot_ace_rule *rule,
 	rule->stats.pkts = cnt;
 }
 
+static void vcap_entry_set(struct ocelot *ocelot, int ix,
+			   struct ocelot_ace_rule *ace,
+			   int block_id)
+{
+	switch (block_id) {
+	case VCAP_IS2:
+		is2_entry_set(ocelot, ix, ace);
+		break;
+	default:
+		break;
+	}
+}
+
 static void ocelot_ace_rule_add(struct ocelot *ocelot,
 				struct ocelot_acl_block *block,
 				struct ocelot_ace_rule *rule)
@@ -790,7 +805,7 @@ static bool ocelot_ace_is_problematic_non_mac_etype(struct ocelot_ace_rule *ace)
 static bool ocelot_exclusive_mac_etype_ace_rules(struct ocelot *ocelot,
 						 struct ocelot_ace_rule *ace)
 {
-	struct ocelot_acl_block *block = &ocelot->acl_block;
+	struct ocelot_acl_block *block = &ocelot->acl_block[VCAP_IS2];
 	struct ocelot_ace_rule *tmp;
 	unsigned long port;
 	int i;
@@ -824,15 +839,16 @@ static bool ocelot_exclusive_mac_etype_ace_rules(struct ocelot *ocelot,
 	return true;
 }
 
-int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
+int ocelot_ace_rule_offload_add(struct ocelot *ocelot, int block_id,
 				struct ocelot_ace_rule *rule,
 				struct netlink_ext_ack *extack)
 {
-	struct ocelot_acl_block *block = &ocelot->acl_block;
+	struct ocelot_acl_block *block = &ocelot->acl_block[block_id];
 	struct ocelot_ace_rule *ace;
 	int i, index;
 
-	if (!ocelot_exclusive_mac_etype_ace_rules(ocelot, rule)) {
+	if (block_id == VCAP_IS2 &&
+	    !ocelot_exclusive_mac_etype_ace_rules(ocelot, rule)) {
 		NL_SET_ERR_MSG_MOD(extack,
 				   "Cannot mix MAC_ETYPE with non-MAC_ETYPE rules");
 		return -EBUSY;
@@ -847,11 +863,11 @@ int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
 	/* Move down the rules to make place for the new rule */
 	for (i = block->count - 1; i > index; i--) {
 		ace = ocelot_ace_rule_get_rule_index(block, i);
-		is2_entry_set(ocelot, i, ace);
+		vcap_entry_set(ocelot, i, ace, block_id);
 	}
 
 	/* Now insert the new rule */
-	is2_entry_set(ocelot, index, rule);
+	vcap_entry_set(ocelot, index, rule, block_id);
 	return 0;
 }
 
@@ -902,10 +918,10 @@ static void ocelot_ace_rule_del(struct ocelot *ocelot,
 	block->count--;
 }
 
-int ocelot_ace_rule_offload_del(struct ocelot *ocelot,
+int ocelot_ace_rule_offload_del(struct ocelot *ocelot, int block_id,
 				struct ocelot_ace_rule *rule)
 {
-	struct ocelot_acl_block *block = &ocelot->acl_block;
+	struct ocelot_acl_block *block = &ocelot->acl_block[block_id];
 	struct ocelot_ace_rule del_ace;
 	struct ocelot_ace_rule *ace;
 	int i, index;
@@ -921,29 +937,29 @@ int ocelot_ace_rule_offload_del(struct ocelot *ocelot,
 	/* Move up all the blocks over the deleted rule */
 	for (i = index; i < block->count; i++) {
 		ace = ocelot_ace_rule_get_rule_index(block, i);
-		is2_entry_set(ocelot, i, ace);
+		vcap_entry_set(ocelot, i, ace, block_id);
 	}
 
 	/* Now delete the last rule, because it is duplicated */
-	is2_entry_set(ocelot, block->count, &del_ace);
+	vcap_entry_set(ocelot, block->count, &del_ace, block_id);
 
 	return 0;
 }
 
-int ocelot_ace_rule_stats_update(struct ocelot *ocelot,
+int ocelot_ace_rule_stats_update(struct ocelot *ocelot, int block_id,
 				 struct ocelot_ace_rule *rule)
 {
-	struct ocelot_acl_block *block = &ocelot->acl_block;
+	struct ocelot_acl_block *block = &ocelot->acl_block[block_id];
 	struct ocelot_ace_rule *tmp;
 	int index;
 
 	index = ocelot_ace_rule_get_index_id(block, rule);
-	vcap_entry_get(ocelot, rule, index);
+	vcap_entry_get(ocelot, rule, index, block_id);
 
 	/* After we get the result we need to clear the counters */
 	tmp = ocelot_ace_rule_get_rule_index(block, index);
 	tmp->stats.pkts = 0;
-	is2_entry_set(ocelot, index, tmp);
+	vcap_entry_set(ocelot, index, tmp, block_id);
 
 	return 0;
 }
@@ -968,7 +984,7 @@ static void vcap_init(struct ocelot *ocelot, const struct vcap_props *vcap)
 
 int ocelot_ace_init(struct ocelot *ocelot)
 {
-	struct ocelot_acl_block *block = &ocelot->acl_block;
+	struct ocelot_acl_block *block;
 
 	vcap_init(ocelot, &ocelot->vcap[VCAP_IS2]);
 
@@ -987,6 +1003,7 @@ int ocelot_ace_init(struct ocelot *ocelot)
 	ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_CIR_STATE,
 			 OCELOT_POLICER_DISCARD);
 
+	block = &ocelot->acl_block[VCAP_IS2];
 	block->pol_lpr = OCELOT_POLICER_DISCARD - 1;
 	INIT_LIST_HEAD(&block->rules);
 
diff --git a/drivers/net/ethernet/mscc/ocelot_ace.h b/drivers/net/ethernet/mscc/ocelot_ace.h
index 099e177f2617..a9fd99401a65 100644
--- a/drivers/net/ethernet/mscc/ocelot_ace.h
+++ b/drivers/net/ethernet/mscc/ocelot_ace.h
@@ -175,6 +175,7 @@ struct ocelot_ace_frame_ipv6 {
 };
 
 enum ocelot_ace_action {
+	OCELOT_ACL_ACTION_NULL,
 	OCELOT_ACL_ACTION_DROP,
 	OCELOT_ACL_ACTION_TRAP,
 	OCELOT_ACL_ACTION_POLICE,
@@ -214,12 +215,12 @@ struct ocelot_ace_rule {
 	u32 pol_ix;
 };
 
-int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
+int ocelot_ace_rule_offload_add(struct ocelot *ocelot, int block_id,
 				struct ocelot_ace_rule *rule,
 				struct netlink_ext_ack *extack);
-int ocelot_ace_rule_offload_del(struct ocelot *ocelot,
+int ocelot_ace_rule_offload_del(struct ocelot *ocelot, int block_id,
 				struct ocelot_ace_rule *rule);
-int ocelot_ace_rule_stats_update(struct ocelot *ocelot,
+int ocelot_ace_rule_stats_update(struct ocelot *ocelot, int block_id,
 				 struct ocelot_ace_rule *rule);
 
 int ocelot_ace_init(struct ocelot *ocelot);
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index 891925f73cbc..a1f7b6b28170 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -9,13 +9,26 @@
 
 #include "ocelot_ace.h"
 
+static int ocelot_block_id_get(int chain, bool ingress)
+{
+	/* Select TCAM blocks by using chain index. Rules in chain 0 are
+	 * implemented on IS1, chain 1 are implemented on IS2, and egress
+	 * chain corresponds to ES0 block.
+	 */
+	if (ingress)
+		return chain ? VCAP_IS2 : VCAP_IS1;
+	else
+		return VCAP_ES0;
+}
+
 static int ocelot_flower_parse_action(struct flow_cls_offload *f,
 				      struct ocelot_ace_rule *ace)
 {
+	struct netlink_ext_ack *extack = f->common.extack;
 	const struct flow_action_entry *a;
+	int i, allowed_chain = 0;
 	s64 burst;
 	u64 rate;
-	int i;
 
 	if (!flow_offload_has_one_action(&f->rule->action))
 		return -EOPNOTSUPP;
@@ -28,9 +41,11 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
 		switch (a->id) {
 		case FLOW_ACTION_DROP:
 			ace->action = OCELOT_ACL_ACTION_DROP;
+			allowed_chain = 1;
 			break;
 		case FLOW_ACTION_TRAP:
 			ace->action = OCELOT_ACL_ACTION_TRAP;
+			allowed_chain = 1;
 			break;
 		case FLOW_ACTION_POLICE:
 			ace->action = OCELOT_ACL_ACTION_POLICE;
@@ -38,10 +53,23 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
 			ace->pol.rate = div_u64(rate, 1000) * 8;
 			burst = rate * PSCHED_NS2TICKS(a->police.burst);
 			ace->pol.burst = div_u64(burst, PSCHED_TICKS_PER_SEC);
+			allowed_chain = 1;
+			break;
+		case FLOW_ACTION_GOTO:
+			if (a->chain_index != f->common.chain_index + 1) {
+				NL_SET_ERR_MSG_MOD(extack, "HW only support goto next chain\n");
+				return -EOPNOTSUPP;
+			}
+			ace->action = OCELOT_ACL_ACTION_NULL;
+			allowed_chain = f->common.chain_index;
 			break;
 		default:
 			return -EOPNOTSUPP;
 		}
+		if (f->common.chain_index != allowed_chain) {
+			NL_SET_ERR_MSG_MOD(extack, "Action is not supported on this chain\n");
+			return -EOPNOTSUPP;
+		}
 	}
 
 	return 0;
@@ -205,7 +233,7 @@ int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
 			      struct flow_cls_offload *f, bool ingress)
 {
 	struct ocelot_ace_rule *ace;
-	int ret;
+	int ret, block_id;
 
 	ace = ocelot_ace_rule_create(ocelot, port, f);
 	if (!ace)
@@ -216,8 +244,10 @@ int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
 		kfree(ace);
 		return ret;
 	}
+	block_id = ocelot_block_id_get(f->common.chain_index, ingress);
 
-	return ocelot_ace_rule_offload_add(ocelot, ace, f->common.extack);
+	return ocelot_ace_rule_offload_add(ocelot, block_id, ace,
+					   f->common.extack);
 }
 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
 
@@ -225,11 +255,13 @@ int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
 			      struct flow_cls_offload *f, bool ingress)
 {
 	struct ocelot_ace_rule ace;
+	int block_id;
 
 	ace.prio = f->common.prio;
 	ace.id = f->cookie;
+	block_id = ocelot_block_id_get(f->common.chain_index, ingress);
 
-	return ocelot_ace_rule_offload_del(ocelot, &ace);
+	return ocelot_ace_rule_offload_del(ocelot, block_id, &ace);
 }
 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
 
@@ -237,11 +269,13 @@ int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
 			    struct flow_cls_offload *f, bool ingress)
 {
 	struct ocelot_ace_rule ace;
-	int ret;
+	int ret, block_id;
 
 	ace.prio = f->common.prio;
 	ace.id = f->cookie;
-	ret = ocelot_ace_rule_stats_update(ocelot, &ace);
+	block_id = ocelot_block_id_get(f->common.chain_index, ingress);
+
+	ret = ocelot_ace_rule_stats_update(ocelot, block_id, &ace);
 	if (ret)
 		return ret;
 
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index 91357b1c8f31..4b2320bdc036 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -540,7 +540,7 @@ struct ocelot {
 
 	struct list_head		multicast;
 
-	struct ocelot_acl_block		acl_block;
+	struct ocelot_acl_block		acl_block[3];
 
 	const struct vcap_props		*vcap;
 
diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h
index 26d9384b3657..495847a40490 100644
--- a/include/soc/mscc/ocelot_vcap.h
+++ b/include/soc/mscc/ocelot_vcap.h
@@ -14,9 +14,9 @@
  */
 
 enum {
-	/* VCAP_IS1, */
+	VCAP_IS1,
 	VCAP_IS2,
-	/* VCAP_ES0, */
+	VCAP_ES0,
 };
 
 struct vcap_props {
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 net-next 04/10] net: mscc: ocelot: change vcap to be compatible with full and quad entry
  2020-06-02  5:18 [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Xiaoliang Yang
                   ` (2 preceding siblings ...)
  2020-06-02  5:18 ` [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index Xiaoliang Yang
@ 2020-06-02  5:18 ` Xiaoliang Yang
  2020-06-02  5:18 ` [PATCH v2 net-next 05/10] net: mscc: ocelot: VCAP IS1 support Xiaoliang Yang
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 29+ messages in thread
From: Xiaoliang Yang @ 2020-06-02  5:18 UTC (permalink / raw)
  To: xiaoliang.yang_1, po.liu, claudiu.manoil, alexandru.marginean,
	vladimir.oltean, leoyang.li, mingkai.hu, andrew, f.fainelli,
	vivien.didelot, davem, jiri, idosch, kuba, vinicius.gomes,
	nikolay, roopa, netdev, linux-kernel, horatiu.vultur,
	alexandre.belloni, allan.nielsen, joergen.andreasen,
	UNGLinuxDriver, linux-devel

When calculating vcap data offset, the function only supports half key
entry. This patch modify vcap_data_offset_get function to calculate a
correct data offset when setting VCAP Type-Group to VCAP_TG_FULL or
VCAP_TG_QUARTER.

Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
---
 drivers/net/ethernet/mscc/ocelot_ace.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mscc/ocelot_ace.c b/drivers/net/ethernet/mscc/ocelot_ace.c
index b76593b40097..8c384b0771bb 100644
--- a/drivers/net/ethernet/mscc/ocelot_ace.c
+++ b/drivers/net/ethernet/mscc/ocelot_ace.c
@@ -175,8 +175,8 @@ static void vcap_data_offset_get(const struct vcap_props *vcap,
 	u32 i, col, offset, count, cnt, base;
 	u32 width = vcap->tg_width;
 
-	count = (data->tg_sw == VCAP_TG_HALF ? 2 : 4);
-	col = (ix % 2);
+	count = (1 << (data->tg_sw - 1));
+	col = (ix % count);
 	cnt = (vcap->sw_count / count);
 	base = (vcap->sw_count - col * cnt - cnt);
 	data->tg_value = 0;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 net-next 05/10] net: mscc: ocelot: VCAP IS1 support
  2020-06-02  5:18 [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Xiaoliang Yang
                   ` (3 preceding siblings ...)
  2020-06-02  5:18 ` [PATCH v2 net-next 04/10] net: mscc: ocelot: change vcap to be compatible with full and quad entry Xiaoliang Yang
@ 2020-06-02  5:18 ` Xiaoliang Yang
  2020-06-02 16:16   ` Jakub Kicinski
  2020-06-02  5:18 ` [PATCH v2 net-next 06/10] net: mscc: ocelot: VCAP ES0 support Xiaoliang Yang
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Xiaoliang Yang @ 2020-06-02  5:18 UTC (permalink / raw)
  To: xiaoliang.yang_1, po.liu, claudiu.manoil, alexandru.marginean,
	vladimir.oltean, leoyang.li, mingkai.hu, andrew, f.fainelli,
	vivien.didelot, davem, jiri, idosch, kuba, vinicius.gomes,
	nikolay, roopa, netdev, linux-kernel, horatiu.vultur,
	alexandre.belloni, allan.nielsen, joergen.andreasen,
	UNGLinuxDriver, linux-devel

VCAP IS1 is a VCAP module which can filter MAC, IP, VLAN, protocol, and
TCP/UDP ports keys, and do Qos classified and VLAN retag actions.

This patch added VCAP IS1 support in ocelot ace driver, which can supports
vlan modify and skbedit priority 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@nxp.com>
---
 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    |  11 ++
 drivers/net/ethernet/mscc/ocelot_flower.c |  11 ++
 drivers/net/ethernet/mscc/ocelot_regs.c   |   1 +
 include/soc/mscc/ocelot.h                 |   1 +
 include/soc/mscc/ocelot_vcap.h            |  91 ++++++++++
 8 files changed, 421 insertions(+), 1 deletion(-)

diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index ef3bf875e64c..f08a5f1c61a5 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -16,6 +16,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)
@@ -337,6 +339,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,
@@ -369,6 +372,11 @@ static const struct resource vsc9959_target_io_res[] = {
 		.end	= 0x001ffff,
 		.name	= "sys",
 	},
+	[S1] = {
+		.start	= 0x0050000,
+		.end	= 0x00503ff,
+		.name	= "s1",
+	},
 	[S2] = {
 		.start	= 0x0060000,
 		.end	= 0x00603ff,
@@ -559,6 +567,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},
@@ -658,6 +740,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 9cfe1fd98c30..533e907af0e9 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 8c384b0771bb..bf21e4c5a9db 100644
--- a/drivers/net/ethernet/mscc/ocelot_ace.c
+++ b/drivers/net/ethernet/mscc/ocelot_ace.c
@@ -645,6 +645,197 @@ 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_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;
+	case OCELOT_ACL_ACTION_PRIORITY:
+		vcap_action_set(vcap, data, VCAP_IS1_ACT_QOS_ENA, 1);
+		vcap_action_set(vcap, data, VCAP_IS1_ACT_QOS_VAL,
+				ace->qos_val);
+		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, int block_id)
 {
@@ -670,6 +861,9 @@ static void vcap_entry_set(struct ocelot *ocelot, int ix,
 			   int block_id)
 {
 	switch (block_id) {
+	case VCAP_IS1:
+		is1_entry_set(ocelot, ix, ace);
+		break;
 	case VCAP_IS2:
 		is2_entry_set(ocelot, ix, ace);
 		break;
@@ -986,6 +1180,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.
@@ -1005,7 +1200,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 a9fd99401a65..bb2df6adaefd 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 */
@@ -179,6 +186,8 @@ enum ocelot_ace_action {
 	OCELOT_ACL_ACTION_DROP,
 	OCELOT_ACL_ACTION_TRAP,
 	OCELOT_ACL_ACTION_POLICE,
+	OCELOT_ACL_ACTION_VLAN_MODIFY,
+	OCELOT_ACL_ACTION_PRIORITY,
 };
 
 struct ocelot_ace_stats {
@@ -200,6 +209,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 {
@@ -213,6 +223,7 @@ struct ocelot_ace_rule {
 	} frame;
 	struct ocelot_policer pol;
 	u32 pol_ix;
+	u8 qos_val;
 };
 
 int ocelot_ace_rule_offload_add(struct ocelot *ocelot, int block_id,
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index a1f7b6b28170..7f1a40ede652 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -63,6 +63,17 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
 			ace->action = OCELOT_ACL_ACTION_NULL;
 			allowed_chain = f->common.chain_index;
 			break;
+		case FLOW_ACTION_VLAN_MANGLE:
+			ace->action = OCELOT_ACL_ACTION_VLAN_MODIFY;
+			ace->vlan_modify.vid = a->vlan.vid;
+			ace->vlan_modify.pcp = a->vlan.prio;
+			allowed_chain = 0;
+			break;
+		case FLOW_ACTION_PRIORITY:
+			ace->action = OCELOT_ACL_ACTION_PRIORITY;
+			ace->qos_val = a->priority;
+			allowed_chain = 0;
+			break;
 		default:
 			return -EOPNOTSUPP;
 		}
diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c
index 18ce99730406..2be74b275685 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 4b2320bdc036..1768ad1ca4e6 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 495847a40490..9e83757f9b02 100644
--- a/include/soc/mscc/ocelot_vcap.h
+++ b/include/soc/mscc/ocelot_vcap.h
@@ -264,4 +264,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


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 net-next 06/10] net: mscc: ocelot: VCAP ES0 support
  2020-06-02  5:18 [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Xiaoliang Yang
                   ` (4 preceding siblings ...)
  2020-06-02  5:18 ` [PATCH v2 net-next 05/10] net: mscc: ocelot: VCAP IS1 support Xiaoliang Yang
@ 2020-06-02  5:18 ` Xiaoliang Yang
  2020-06-02 16:17   ` Jakub Kicinski
  2020-06-02  5:18 ` [PATCH v2 net-next 07/10] net: mscc: ocelot: multiple actions support Xiaoliang Yang
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 29+ messages in thread
From: Xiaoliang Yang @ 2020-06-02  5:18 UTC (permalink / raw)
  To: xiaoliang.yang_1, po.liu, claudiu.manoil, alexandru.marginean,
	vladimir.oltean, leoyang.li, mingkai.hu, andrew, f.fainelli,
	vivien.didelot, davem, jiri, idosch, kuba, vinicius.gomes,
	nikolay, roopa, netdev, linux-kernel, horatiu.vultur,
	alexandre.belloni, allan.nielsen, joergen.andreasen,
	UNGLinuxDriver, linux-devel

VCAP ES0 is an egress VCAP working on all outgoing frames.
This patch added ES0 driver to support vlan push action of tc filter.
Usage:
	tc filter add dev swp1 egress protocol 802.1Q flower skip_sw
	vlan_id 1 vlan_prio 1 action vlan push id 2 priority 2

Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
---
 drivers/net/dsa/ocelot/felix_vsc9959.c    | 59 ++++++++++++++++++
 drivers/net/ethernet/mscc/ocelot.c        |  4 ++
 drivers/net/ethernet/mscc/ocelot_ace.c    | 74 ++++++++++++++++++++++-
 drivers/net/ethernet/mscc/ocelot_ace.h    |  2 +
 drivers/net/ethernet/mscc/ocelot_flower.c | 29 ++++++---
 include/soc/mscc/ocelot.h                 |  1 +
 include/soc/mscc/ocelot_vcap.h            | 42 +++++++++++++
 7 files changed, 203 insertions(+), 8 deletions(-)

diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index f08a5f1c61a5..fceba87509ba 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -18,6 +18,7 @@
 #define VSC9959_VCAP_PORT_CNT		6
 #define VSC9959_VCAP_IS1_CNT		256
 #define VSC9959_VCAP_IS1_ENTRY_WIDTH	376
+#define VSC9959_VCAP_ES0_CNT            1024
 
 /* TODO: should find a better place for these */
 #define USXGMII_BMCR_RESET		BIT(15)
@@ -339,6 +340,7 @@ static const u32 *vsc9959_regmap[] = {
 	[QSYS]	= vsc9959_qsys_regmap,
 	[REW]	= vsc9959_rew_regmap,
 	[SYS]	= vsc9959_sys_regmap,
+	[S0]	= vsc9959_vcap_regmap,
 	[S1]	= vsc9959_vcap_regmap,
 	[S2]	= vsc9959_vcap_regmap,
 	[PTP]	= vsc9959_ptp_regmap,
@@ -372,6 +374,11 @@ static const struct resource vsc9959_target_io_res[] = {
 		.end	= 0x001ffff,
 		.name	= "sys",
 	},
+	[S0] = {
+		.start	= 0x0040000,
+		.end	= 0x00403ff,
+		.name	= "s0",
+	},
 	[S1] = {
 		.start	= 0x0050000,
 		.end	= 0x00503ff,
@@ -567,6 +574,38 @@ static const struct ocelot_stat_layout vsc9959_stats_layout[] = {
 	{ .offset = 0x111,	.name = "drop_green_prio_7", },
 };
 
+struct vcap_field vsc9959_vcap_es0_keys[] = {
+	[VCAP_ES0_EGR_PORT]			= {  0,   3},
+	[VCAP_ES0_IGR_PORT]			= {  3,	  3},
+	[VCAP_ES0_RSV]				= {  6,	  2},
+	[VCAP_ES0_L2_MC]			= {  8,	  1},
+	[VCAP_ES0_L2_BC]			= {  9,	  1},
+	[VCAP_ES0_VID]				= { 10,	 12},
+	[VCAP_ES0_DP]				= { 22,	  1},
+	[VCAP_ES0_PCP]				= { 23,	  3},
+};
+
+struct vcap_field vsc9959_vcap_es0_actions[] = {
+	[VCAP_ES0_ACT_PUSH_OUTER_TAG]		= {  0,  2},
+	[VCAP_ES0_ACT_PUSH_INNER_TAG]		= {  2,  1},
+	[VCAP_ES0_ACT_TAG_A_TPID_SEL]		= {  3,  2},
+	[VCAP_ES0_ACT_TAG_A_VID_SEL]		= {  5,  1},
+	[VCAP_ES0_ACT_TAG_A_PCP_SEL]		= {  6,  2},
+	[VCAP_ES0_ACT_TAG_A_DEI_SEL]		= {  8,  2},
+	[VCAP_ES0_ACT_TAG_B_TPID_SEL]		= { 10,  2},
+	[VCAP_ES0_ACT_TAG_B_VID_SEL]		= { 12,  1},
+	[VCAP_ES0_ACT_TAG_B_PCP_SEL]		= { 13,  2},
+	[VCAP_ES0_ACT_TAG_B_DEI_SEL]		= { 15,  2},
+	[VCAP_ES0_ACT_VID_A_VAL]		= { 17, 12},
+	[VCAP_ES0_ACT_PCP_A_VAL]		= { 29,  3},
+	[VCAP_ES0_ACT_DEI_A_VAL]		= { 32,  1},
+	[VCAP_ES0_ACT_VID_B_VAL]		= { 33, 12},
+	[VCAP_ES0_ACT_PCP_B_VAL]		= { 45,  3},
+	[VCAP_ES0_ACT_DEI_B_VAL]		= { 48,  1},
+	[VCAP_ES0_ACT_RSV]			= { 49, 23},
+	[VCAP_ES0_ACT_HIT_STICKY]		= { 72,  1},
+};
+
 struct vcap_field vsc9959_vcap_is1_keys[] = {
 	[VCAP_IS1_HK_TYPE]			= {  0,   1},
 	[VCAP_IS1_HK_LOOKUP]			= {  1,   2},
@@ -740,6 +779,26 @@ struct vcap_field vsc9959_vcap_is2_actions[] = {
 };
 
 static const struct vcap_props vsc9959_vcap_props[] = {
+	[VCAP_ES0] = {
+		.tg_width = 1,
+		.sw_count = 1,
+		.entry_count = VSC9959_VCAP_ES0_CNT,
+		.entry_width = 29,
+		.action_count = VSC9959_VCAP_ES0_CNT + 6,
+		.action_width = 72,
+		.action_type_width = 0,
+		.action_table = {
+			[ES0_ACTION_TYPE_NORMAL] = {
+				.width = 72,
+				.count = 1
+			},
+		},
+		.counter_words = 1,
+		.counter_width = 1,
+		.target = S0,
+		.keys = vsc9959_vcap_es0_keys,
+		.actions = vsc9959_vcap_es0_actions,
+	},
 	[VCAP_IS1] = {
 		.tg_width = 2,
 		.sw_count = 4,
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 533e907af0e9..7556a43e2698 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -143,6 +143,10 @@ static void ocelot_vcap_enable(struct ocelot *ocelot, int port)
 			 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);
+
+	ocelot_rmw_gix(ocelot, REW_PORT_CFG_ES0_EN,
+		       REW_PORT_CFG_ES0_EN,
+		       REW_PORT_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 bf21e4c5a9db..76d679b8d15e 100644
--- a/drivers/net/ethernet/mscc/ocelot_ace.c
+++ b/drivers/net/ethernet/mscc/ocelot_ace.c
@@ -836,6 +836,69 @@ static void is1_entry_set(struct ocelot *ocelot, int ix,
 	vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
 }
 
+static void es0_action_set(struct ocelot *ocelot, struct vcap_data *data,
+			   struct ocelot_ace_rule *ace)
+{
+	const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
+
+	switch (ace->action) {
+	case OCELOT_ACL_ACTION_VLAN_PUSH:
+		vcap_action_set(vcap, data, VCAP_ES0_ACT_PUSH_OUTER_TAG, 1);
+		vcap_action_set(vcap, data, VCAP_ES0_ACT_TAG_A_VID_SEL, 1);
+		vcap_action_set(vcap, data, VCAP_ES0_ACT_VID_A_VAL,
+				ace->vlan_modify.vid);
+		vcap_action_set(vcap, data, VCAP_ES0_ACT_TAG_A_PCP_SEL, 1);
+		vcap_action_set(vcap, data, VCAP_ES0_ACT_PCP_A_VAL,
+				ace->vlan_modify.pcp);
+		break;
+	default:
+		break;
+	}
+}
+
+static void es0_entry_set(struct ocelot *ocelot, int ix,
+			  struct ocelot_ace_rule *ace)
+{
+	const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
+	struct ocelot_ace_vlan *tag = &ace->vlan;
+	struct ocelot_vcap_u64 payload;
+	struct vcap_data data;
+	int row = ix;
+	u32 msk = 0x7;
+
+	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_FULL;
+	data.type = ES0_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_ES0_EGR_PORT, ace->egress_port, msk);
+	vcap_key_bit_set(vcap, &data, VCAP_ES0_L2_MC, ace->dmac_mc);
+	vcap_key_bit_set(vcap, &data, VCAP_ES0_L2_BC, ace->dmac_bc);
+	vcap_key_set(vcap, &data, VCAP_ES0_VID,
+		     tag->vid.value, tag->vid.mask);
+	vcap_key_set(vcap, &data, VCAP_ES0_PCP,
+		     tag->pcp.value[0], tag->pcp.mask[0]);
+
+	es0_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, int block_id)
 {
@@ -844,7 +907,11 @@ static void vcap_entry_get(struct ocelot *ocelot, struct ocelot_ace_rule *rule,
 	int row, count;
 	u32 cnt;
 
-	data.tg_sw = VCAP_TG_HALF;
+	if (block_id == VCAP_ES0)
+		data.tg_sw = VCAP_TG_FULL;
+	else
+		data.tg_sw = VCAP_TG_HALF;
+
 	count = (1 << (data.tg_sw - 1));
 	row = (ix / count);
 	vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_READ, VCAP_SEL_COUNTER);
@@ -867,6 +934,9 @@ static void vcap_entry_set(struct ocelot *ocelot, int ix,
 	case VCAP_IS2:
 		is2_entry_set(ocelot, ix, ace);
 		break;
+	case VCAP_ES0:
+		es0_entry_set(ocelot, ix, ace);
+		break;
 	default:
 		break;
 	}
@@ -1180,6 +1250,7 @@ int ocelot_ace_init(struct ocelot *ocelot)
 {
 	struct ocelot_acl_block *block;
 
+	vcap_init(ocelot, &ocelot->vcap[VCAP_ES0]);
 	vcap_init(ocelot, &ocelot->vcap[VCAP_IS1]);
 	vcap_init(ocelot, &ocelot->vcap[VCAP_IS2]);
 
@@ -1200,6 +1271,7 @@ int ocelot_ace_init(struct ocelot *ocelot)
 
 	block = &ocelot->acl_block[VCAP_IS2];
 	block->pol_lpr = OCELOT_POLICER_DISCARD - 1;
+	INIT_LIST_HEAD(&ocelot->acl_block[VCAP_ES0].rules);
 	INIT_LIST_HEAD(&ocelot->acl_block[VCAP_IS1].rules);
 	INIT_LIST_HEAD(&ocelot->acl_block[VCAP_IS2].rules);
 
diff --git a/drivers/net/ethernet/mscc/ocelot_ace.h b/drivers/net/ethernet/mscc/ocelot_ace.h
index bb2df6adaefd..70fe45d747fb 100644
--- a/drivers/net/ethernet/mscc/ocelot_ace.h
+++ b/drivers/net/ethernet/mscc/ocelot_ace.h
@@ -188,6 +188,7 @@ enum ocelot_ace_action {
 	OCELOT_ACL_ACTION_POLICE,
 	OCELOT_ACL_ACTION_VLAN_MODIFY,
 	OCELOT_ACL_ACTION_PRIORITY,
+	OCELOT_ACL_ACTION_VLAN_PUSH,
 };
 
 struct ocelot_ace_stats {
@@ -205,6 +206,7 @@ struct ocelot_ace_rule {
 	enum ocelot_ace_action action;
 	struct ocelot_ace_stats stats;
 	unsigned long ingress_port_mask;
+	u8 egress_port;
 
 	enum ocelot_vcap_bit dmac_mc;
 	enum ocelot_vcap_bit dmac_bc;
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index 7f1a40ede652..d598e103c796 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -22,11 +22,13 @@ static int ocelot_block_id_get(int chain, bool ingress)
 }
 
 static int ocelot_flower_parse_action(struct flow_cls_offload *f,
-				      struct ocelot_ace_rule *ace)
+				      struct ocelot_ace_rule *ace,
+				      bool ingress)
 {
 	struct netlink_ext_ack *extack = f->common.extack;
 	const struct flow_action_entry *a;
 	int i, allowed_chain = 0;
+	bool allowed_ingress = 1;
 	s64 burst;
 	u64 rate;
 
@@ -74,10 +76,18 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
 			ace->qos_val = a->priority;
 			allowed_chain = 0;
 			break;
+		case FLOW_ACTION_VLAN_PUSH:
+			ace->action = OCELOT_ACL_ACTION_VLAN_PUSH;
+			ace->vlan_modify.vid = a->vlan.vid;
+			ace->vlan_modify.pcp = a->vlan.prio;
+			allowed_ingress = 0;
+			allowed_chain = 0;
+			break;
 		default:
 			return -EOPNOTSUPP;
 		}
-		if (f->common.chain_index != allowed_chain) {
+		if (f->common.chain_index != allowed_chain ||
+		    allowed_ingress != ingress) {
 			NL_SET_ERR_MSG_MOD(extack, "Action is not supported on this chain\n");
 			return -EOPNOTSUPP;
 		}
@@ -87,7 +97,8 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
 }
 
 static int ocelot_flower_parse(struct flow_cls_offload *f,
-			       struct ocelot_ace_rule *ace)
+			       struct ocelot_ace_rule *ace,
+			       bool ingress)
 {
 	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
 	struct flow_dissector *dissector = rule->match.dissector;
@@ -223,11 +234,12 @@ static int ocelot_flower_parse(struct flow_cls_offload *f,
 
 	ace->prio = f->common.prio;
 	ace->id = f->cookie;
-	return ocelot_flower_parse_action(f, ace);
+	return ocelot_flower_parse_action(f, ace, ingress);
 }
 
 static
 struct ocelot_ace_rule *ocelot_ace_rule_create(struct ocelot *ocelot, int port,
+					       bool ingress,
 					       struct flow_cls_offload *f)
 {
 	struct ocelot_ace_rule *ace;
@@ -236,7 +248,10 @@ struct ocelot_ace_rule *ocelot_ace_rule_create(struct ocelot *ocelot, int port,
 	if (!ace)
 		return NULL;
 
-	ace->ingress_port_mask = BIT(port);
+	if (ingress)
+		ace->ingress_port_mask = BIT(port);
+	else
+		ace->egress_port = port;
 	return ace;
 }
 
@@ -246,11 +261,11 @@ int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
 	struct ocelot_ace_rule *ace;
 	int ret, block_id;
 
-	ace = ocelot_ace_rule_create(ocelot, port, f);
+	ace = ocelot_ace_rule_create(ocelot, port, ingress, f);
 	if (!ace)
 		return -ENOMEM;
 
-	ret = ocelot_flower_parse(f, ace);
+	ret = ocelot_flower_parse(f, ace, ingress);
 	if (ret) {
 		kfree(ace);
 		return ret;
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index 1768ad1ca4e6..4a86eb9c714e 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -107,6 +107,7 @@ enum ocelot_target {
 	QSYS,
 	REW,
 	SYS,
+	S0,
 	S1,
 	S2,
 	HSIO,
diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h
index 9e83757f9b02..0c882c588629 100644
--- a/include/soc/mscc/ocelot_vcap.h
+++ b/include/soc/mscc/ocelot_vcap.h
@@ -355,4 +355,46 @@ enum vcap_is1_action_field {
 	VCAP_IS1_ACT_HIT_STICKY,
 };
 
+/* =================================================================
+ *  VCAP ES0
+ * =================================================================
+ */
+
+enum {
+	ES0_ACTION_TYPE_NORMAL,
+	ES0_ACTION_TYPE_MAX,
+};
+
+enum vcap_es0_key_field {
+	VCAP_ES0_EGR_PORT,
+	VCAP_ES0_IGR_PORT,
+	VCAP_ES0_RSV,
+	VCAP_ES0_L2_MC,
+	VCAP_ES0_L2_BC,
+	VCAP_ES0_VID,
+	VCAP_ES0_DP,
+	VCAP_ES0_PCP,
+};
+
+enum vcap_es0_action_field {
+	VCAP_ES0_ACT_PUSH_OUTER_TAG,
+	VCAP_ES0_ACT_PUSH_INNER_TAG,
+	VCAP_ES0_ACT_TAG_A_TPID_SEL,
+	VCAP_ES0_ACT_TAG_A_VID_SEL,
+	VCAP_ES0_ACT_TAG_A_PCP_SEL,
+	VCAP_ES0_ACT_TAG_A_DEI_SEL,
+	VCAP_ES0_ACT_TAG_B_TPID_SEL,
+	VCAP_ES0_ACT_TAG_B_VID_SEL,
+	VCAP_ES0_ACT_TAG_B_PCP_SEL,
+	VCAP_ES0_ACT_TAG_B_DEI_SEL,
+	VCAP_ES0_ACT_VID_A_VAL,
+	VCAP_ES0_ACT_PCP_A_VAL,
+	VCAP_ES0_ACT_DEI_A_VAL,
+	VCAP_ES0_ACT_VID_B_VAL,
+	VCAP_ES0_ACT_PCP_B_VAL,
+	VCAP_ES0_ACT_DEI_B_VAL,
+	VCAP_ES0_ACT_RSV,
+	VCAP_ES0_ACT_HIT_STICKY,
+};
+
 #endif /* _OCELOT_VCAP_H_ */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 net-next 07/10] net: mscc: ocelot: multiple actions support
  2020-06-02  5:18 [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Xiaoliang Yang
                   ` (5 preceding siblings ...)
  2020-06-02  5:18 ` [PATCH v2 net-next 06/10] net: mscc: ocelot: VCAP ES0 support Xiaoliang Yang
@ 2020-06-02  5:18 ` Xiaoliang Yang
  2020-06-02  5:18 ` [PATCH v2 net-next 08/10] net: ocelot: return error if rule is not found Xiaoliang Yang
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 29+ messages in thread
From: Xiaoliang Yang @ 2020-06-02  5:18 UTC (permalink / raw)
  To: xiaoliang.yang_1, po.liu, claudiu.manoil, alexandru.marginean,
	vladimir.oltean, leoyang.li, mingkai.hu, andrew, f.fainelli,
	vivien.didelot, davem, jiri, idosch, kuba, vinicius.gomes,
	nikolay, roopa, netdev, linux-kernel, horatiu.vultur,
	alexandre.belloni, allan.nielsen, joergen.andreasen,
	UNGLinuxDriver, linux-devel

Support multiple actions for each flower rule, multiple actions can only
set on the same VCAP, and all actions can mix with action goto chain.
Action drop, trap, and police on VCAP IS2 could not be mixed.

Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
---
 drivers/net/ethernet/mscc/ocelot_ace.c    | 15 +++++++++------
 drivers/net/ethernet/mscc/ocelot_ace.h    |  8 +++++++-
 drivers/net/ethernet/mscc/ocelot_flower.c | 14 +++++++++-----
 3 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/mscc/ocelot_ace.c b/drivers/net/ethernet/mscc/ocelot_ace.c
index 76d679b8d15e..bf2b7a03c832 100644
--- a/drivers/net/ethernet/mscc/ocelot_ace.c
+++ b/drivers/net/ethernet/mscc/ocelot_ace.c
@@ -651,20 +651,23 @@ static void is1_action_set(struct ocelot *ocelot, struct vcap_data *data,
 	const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS1];
 
 	switch (ace->action) {
+	case OCELOT_ACL_ACTION_PRIORITY:
 	case OCELOT_ACL_ACTION_VLAN_MODIFY:
-		vcap_action_set(vcap, data, VCAP_IS1_ACT_VID_REPLACE_ENA, 1);
+		vcap_action_set(vcap, data, VCAP_IS1_ACT_VID_REPLACE_ENA,
+				ace->vlan_modify.ena);
 		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_DEI_ENA,
+				ace->vlan_modify.ena);
 		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;
-	case OCELOT_ACL_ACTION_PRIORITY:
-		vcap_action_set(vcap, data, VCAP_IS1_ACT_QOS_ENA, 1);
+
+		vcap_action_set(vcap, data, VCAP_IS1_ACT_QOS_ENA,
+				ace->qos_modify.ena);
 		vcap_action_set(vcap, data, VCAP_IS1_ACT_QOS_VAL,
-				ace->qos_val);
+				ace->qos_modify.qos_val);
 		break;
 	default:
 		break;
diff --git a/drivers/net/ethernet/mscc/ocelot_ace.h b/drivers/net/ethernet/mscc/ocelot_ace.h
index 70fe45d747fb..02fa81b3fe92 100644
--- a/drivers/net/ethernet/mscc/ocelot_ace.h
+++ b/drivers/net/ethernet/mscc/ocelot_ace.h
@@ -97,6 +97,12 @@ struct ocelot_ace_action_vlan {
 	u16 vid;
 	u8 pcp;
 	u8 dei;
+	u8 ena;
+};
+
+struct ocelot_ace_action_qos {
+	u8 qos_val;
+	u8 ena;
 };
 
 struct ocelot_ace_frame_etype {
@@ -212,6 +218,7 @@ struct ocelot_ace_rule {
 	enum ocelot_vcap_bit dmac_bc;
 	struct ocelot_ace_vlan vlan;
 	struct ocelot_ace_action_vlan vlan_modify;
+	struct ocelot_ace_action_qos qos_modify;
 
 	enum ocelot_ace_type type;
 	union {
@@ -225,7 +232,6 @@ struct ocelot_ace_rule {
 	} frame;
 	struct ocelot_policer pol;
 	u32 pol_ix;
-	u8 qos_val;
 };
 
 int ocelot_ace_rule_offload_add(struct ocelot *ocelot, int block_id,
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index d598e103c796..6ce37f152f12 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -32,9 +32,6 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
 	s64 burst;
 	u64 rate;
 
-	if (!flow_offload_has_one_action(&f->rule->action))
-		return -EOPNOTSUPP;
-
 	if (!flow_action_basic_hw_stats_check(&f->rule->action,
 					      f->common.extack))
 		return -EOPNOTSUPP;
@@ -42,14 +39,20 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
 	flow_action_for_each(i, a, &f->rule->action) {
 		switch (a->id) {
 		case FLOW_ACTION_DROP:
+			if (i)
+				return -EOPNOTSUPP;
 			ace->action = OCELOT_ACL_ACTION_DROP;
 			allowed_chain = 1;
 			break;
 		case FLOW_ACTION_TRAP:
+			if (i)
+				return -EOPNOTSUPP;
 			ace->action = OCELOT_ACL_ACTION_TRAP;
 			allowed_chain = 1;
 			break;
 		case FLOW_ACTION_POLICE:
+			if (i)
+				return -EOPNOTSUPP;
 			ace->action = OCELOT_ACL_ACTION_POLICE;
 			rate = a->police.rate_bytes_ps;
 			ace->pol.rate = div_u64(rate, 1000) * 8;
@@ -62,18 +65,19 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
 				NL_SET_ERR_MSG_MOD(extack, "HW only support goto next chain\n");
 				return -EOPNOTSUPP;
 			}
-			ace->action = OCELOT_ACL_ACTION_NULL;
 			allowed_chain = f->common.chain_index;
 			break;
 		case FLOW_ACTION_VLAN_MANGLE:
 			ace->action = OCELOT_ACL_ACTION_VLAN_MODIFY;
+			ace->vlan_modify.ena = 1;
 			ace->vlan_modify.vid = a->vlan.vid;
 			ace->vlan_modify.pcp = a->vlan.prio;
 			allowed_chain = 0;
 			break;
 		case FLOW_ACTION_PRIORITY:
 			ace->action = OCELOT_ACL_ACTION_PRIORITY;
-			ace->qos_val = a->priority;
+			ace->qos_modify.ena = 1;
+			ace->qos_modify.qos_val = a->priority;
 			allowed_chain = 0;
 			break;
 		case FLOW_ACTION_VLAN_PUSH:
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 net-next 08/10] net: ocelot: return error if rule is not found
  2020-06-02  5:18 [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Xiaoliang Yang
                   ` (6 preceding siblings ...)
  2020-06-02  5:18 ` [PATCH v2 net-next 07/10] net: mscc: ocelot: multiple actions support Xiaoliang Yang
@ 2020-06-02  5:18 ` Xiaoliang Yang
  2020-06-02  5:18 ` [PATCH v2 net-next 09/10] net: dsa: felix: correct VCAP IS2 keys offset Xiaoliang Yang
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 29+ messages in thread
From: Xiaoliang Yang @ 2020-06-02  5:18 UTC (permalink / raw)
  To: xiaoliang.yang_1, po.liu, claudiu.manoil, alexandru.marginean,
	vladimir.oltean, leoyang.li, mingkai.hu, andrew, f.fainelli,
	vivien.didelot, davem, jiri, idosch, kuba, vinicius.gomes,
	nikolay, roopa, netdev, linux-kernel, horatiu.vultur,
	alexandre.belloni, allan.nielsen, joergen.andreasen,
	UNGLinuxDriver, linux-devel

Return error if rule is not found in rule list to avoid Kernel panic.

Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
---
 drivers/net/ethernet/mscc/ocelot_ace.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mscc/ocelot_ace.c b/drivers/net/ethernet/mscc/ocelot_ace.c
index bf2b7a03c832..2ba2859fa2cd 100644
--- a/drivers/net/ethernet/mscc/ocelot_ace.c
+++ b/drivers/net/ethernet/mscc/ocelot_ace.c
@@ -982,9 +982,9 @@ static int ocelot_ace_rule_get_index_id(struct ocelot_acl_block *block,
 	list_for_each_entry(tmp, &block->rules, list) {
 		++index;
 		if (rule->id == tmp->id)
-			break;
+			return index;
 	}
-	return index;
+	return -ENOENT;
 }
 
 static struct ocelot_ace_rule*
@@ -1197,6 +1197,8 @@ int ocelot_ace_rule_offload_del(struct ocelot *ocelot, int block_id,
 
 	/* Gets index of the rule */
 	index = ocelot_ace_rule_get_index_id(block, rule);
+	if (index < 0)
+		return -ENOENT;
 
 	/* Delete rule */
 	ocelot_ace_rule_del(ocelot, block, rule);
@@ -1221,6 +1223,9 @@ int ocelot_ace_rule_stats_update(struct ocelot *ocelot, int block_id,
 	int index;
 
 	index = ocelot_ace_rule_get_index_id(block, rule);
+	if (index < 0)
+		return -ENOENT;
+
 	vcap_entry_get(ocelot, rule, index, block_id);
 
 	/* After we get the result we need to clear the counters */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 net-next 09/10] net: dsa: felix: correct VCAP IS2 keys offset
  2020-06-02  5:18 [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Xiaoliang Yang
                   ` (7 preceding siblings ...)
  2020-06-02  5:18 ` [PATCH v2 net-next 08/10] net: ocelot: return error if rule is not found Xiaoliang Yang
@ 2020-06-02  5:18 ` Xiaoliang Yang
  2020-06-02  5:18 ` [PATCH v2 net-next 10/10] net: dsa: tag_ocelot: use VLAN information from tagging header when available Xiaoliang Yang
  2020-06-02  8:03 ` [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Vladimir Oltean
  10 siblings, 0 replies; 29+ messages in thread
From: Xiaoliang Yang @ 2020-06-02  5:18 UTC (permalink / raw)
  To: xiaoliang.yang_1, po.liu, claudiu.manoil, alexandru.marginean,
	vladimir.oltean, leoyang.li, mingkai.hu, andrew, f.fainelli,
	vivien.didelot, davem, jiri, idosch, kuba, vinicius.gomes,
	nikolay, roopa, netdev, linux-kernel, horatiu.vultur,
	alexandre.belloni, allan.nielsen, joergen.andreasen,
	UNGLinuxDriver, linux-devel

Some of IS2 IP4_TCP_UDP keys are not correct, like L4_DPORT, L4_SPORT
and other L4 keys. It causes the issue that VCAP IS2 could not filter
a right dst/src port for TCP/UDP packages.

Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
---
 drivers/net/dsa/ocelot/felix_vsc9959.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index fceba87509ba..539f3c062b50 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -730,17 +730,17 @@ struct vcap_field vsc9959_vcap_is2_keys[] = {
 	[VCAP_IS2_HK_DIP_EQ_SIP]		= {118,   1},
 	/* IP4_TCP_UDP (TYPE=100) */
 	[VCAP_IS2_HK_TCP]			= {119,   1},
-	[VCAP_IS2_HK_L4_SPORT]			= {120,  16},
-	[VCAP_IS2_HK_L4_DPORT]			= {136,  16},
+	[VCAP_IS2_HK_L4_DPORT]			= {120,  16},
+	[VCAP_IS2_HK_L4_SPORT]			= {136,  16},
 	[VCAP_IS2_HK_L4_RNG]			= {152,   8},
 	[VCAP_IS2_HK_L4_SPORT_EQ_DPORT]		= {160,   1},
 	[VCAP_IS2_HK_L4_SEQUENCE_EQ0]		= {161,   1},
-	[VCAP_IS2_HK_L4_URG]			= {162,   1},
-	[VCAP_IS2_HK_L4_ACK]			= {163,   1},
-	[VCAP_IS2_HK_L4_PSH]			= {164,   1},
-	[VCAP_IS2_HK_L4_RST]			= {165,   1},
-	[VCAP_IS2_HK_L4_SYN]			= {166,   1},
-	[VCAP_IS2_HK_L4_FIN]			= {167,   1},
+	[VCAP_IS2_HK_L4_FIN]			= {162,   1},
+	[VCAP_IS2_HK_L4_SYN]			= {163,   1},
+	[VCAP_IS2_HK_L4_RST]			= {164,   1},
+	[VCAP_IS2_HK_L4_PSH]			= {165,   1},
+	[VCAP_IS2_HK_L4_ACK]			= {166,   1},
+	[VCAP_IS2_HK_L4_URG]			= {167,   1},
 	[VCAP_IS2_HK_L4_1588_DOM]		= {168,   8},
 	[VCAP_IS2_HK_L4_1588_VER]		= {176,   4},
 	/* IP4_OTHER (TYPE=101) */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 net-next 10/10] net: dsa: tag_ocelot: use VLAN information from tagging header when available
  2020-06-02  5:18 [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Xiaoliang Yang
                   ` (8 preceding siblings ...)
  2020-06-02  5:18 ` [PATCH v2 net-next 09/10] net: dsa: felix: correct VCAP IS2 keys offset Xiaoliang Yang
@ 2020-06-02  5:18 ` Xiaoliang Yang
  2020-06-02  8:03 ` [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Vladimir Oltean
  10 siblings, 0 replies; 29+ messages in thread
From: Xiaoliang Yang @ 2020-06-02  5:18 UTC (permalink / raw)
  To: xiaoliang.yang_1, po.liu, claudiu.manoil, alexandru.marginean,
	vladimir.oltean, leoyang.li, mingkai.hu, andrew, f.fainelli,
	vivien.didelot, davem, jiri, idosch, kuba, vinicius.gomes,
	nikolay, roopa, netdev, linux-kernel, horatiu.vultur,
	alexandre.belloni, allan.nielsen, joergen.andreasen,
	UNGLinuxDriver, linux-devel

From: Vladimir Oltean <vladimir.oltean@nxp.com>

When the Extraction Frame Header contains a valid classified VLAN, use
that instead of the VLAN header present in the packet.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 net/dsa/tag_ocelot.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/net/dsa/tag_ocelot.c b/net/dsa/tag_ocelot.c
index b0c98ee4e13b..253188b0e56b 100644
--- a/net/dsa/tag_ocelot.c
+++ b/net/dsa/tag_ocelot.c
@@ -181,9 +181,16 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
 				  struct net_device *netdev,
 				  struct packet_type *pt)
 {
+	struct dsa_port *cpu_dp = netdev->dsa_ptr;
+	struct dsa_switch *ds = cpu_dp->ds;
+	struct ocelot *ocelot = ds->priv;
+	struct ocelot_port *ocelot_port;
 	u64 src_port, qos_class;
 	u8 *start = skb->data;
+	struct ethhdr *hdr;
 	u8 *extraction;
+	u64 vlan_tci;
+	u16 vid;
 
 	/* Revert skb->data by the amount consumed by the DSA master,
 	 * so it points to the beginning of the frame.
@@ -211,6 +218,7 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
 
 	packing(extraction, &src_port,  46, 43, OCELOT_TAG_LEN, UNPACK, 0);
 	packing(extraction, &qos_class, 19, 17, OCELOT_TAG_LEN, UNPACK, 0);
+	packing(extraction, &vlan_tci,  15,  0, OCELOT_TAG_LEN, UNPACK, 0);
 
 	skb->dev = dsa_master_find_slave(netdev, 0, src_port);
 	if (!skb->dev)
@@ -225,6 +233,27 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
 	skb->offload_fwd_mark = 1;
 	skb->priority = qos_class;
 
+	/* The VID from the extraction header contains the classified VLAN. But
+	 * if VLAN awareness is off and no retagging is done via VCAP IS1, that
+	 * classified VID will always be the pvid of the src_port.
+	 * port. We want Linux to see the classified VID, but only if the switch
+	 * intended to send the packet as untagged, i.e. if the VID is different
+	 * than the CPU port's untagged (native) VID.
+	 */
+	vid = vlan_tci & VLAN_VID_MASK;
+	hdr = eth_hdr(skb);
+	ocelot_port = ocelot->ports[src_port];
+	if (hdr->h_proto == htons(ETH_P_8021Q) && vid != ocelot_port->pvid) {
+		u16 dummy_vlan_tci;
+
+		skb_push_rcsum(skb, ETH_HLEN);
+		__skb_vlan_pop(skb, &dummy_vlan_tci);
+		skb_pull_rcsum(skb, ETH_HLEN);
+		skb_reset_network_header(skb);
+		skb_reset_transport_header(skb);
+		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci);
+	}
+
 	return skb;
 }
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support
  2020-06-02  5:18 [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Xiaoliang Yang
                   ` (9 preceding siblings ...)
  2020-06-02  5:18 ` [PATCH v2 net-next 10/10] net: dsa: tag_ocelot: use VLAN information from tagging header when available Xiaoliang Yang
@ 2020-06-02  8:03 ` Vladimir Oltean
  2020-06-02  8:49   ` [EXT] " Xiaoliang Yang
  10 siblings, 1 reply; 29+ messages in thread
From: Vladimir Oltean @ 2020-06-02  8:03 UTC (permalink / raw)
  To: Xiaoliang Yang
  Cc: Po Liu, Claudiu Manoil, Alexandru Marginean, Vladimir Oltean,
	Li Yang, Mingkai Hu, Andrew Lunn, Florian Fainelli,
	Vivien Didelot, David S. Miller, Jiri Pirko, Ido Schimmel,
	Jakub Kicinski, Vinicius Costa Gomes, Nikolay Aleksandrov,
	Roopa Prabhu, netdev, lkml, Horatiu Vultur, Alexandre Belloni,
	Allan W. Nielsen, Joergen Andreasen,
	Microchip Linux Driver Support, linux-devel

Hi Xiaoliang,

On Tue, 2 Jun 2020 at 08:25, Xiaoliang Yang <xiaoliang.yang_1@nxp.com> wrote:
>
> This series patches adds support for VCAP IS1 and ES0 module, each VCAP
> correspond to a flow chain to offload.
>
> VCAP IS1 supports FLOW_ACTION_VLAN_MANGLE action to filter MAC, IP,
> VLAN, protocol, and TCP/UDP ports keys and retag vlian tag,
> FLOW_ACTION_PRIORITY action to classify packages to different Qos in hw.
>
> VCAP ES0 supports FLOW_ACTION_VLAN_PUSH action to filter vlan keys
> and push a specific vlan tag to frames.
>
> Changes since v1->v2:
>  - Use different chain to assign rules to different hardware VCAP, and
>    use action goto chain to express flow order.
>  - Add FLOW_ACTION_PRIORITY to add Qos classification on VCAP IS1.
>  - Multiple actions support.
>  - Fix some code issues.
>
> Vladimir Oltean (3):
>   net: mscc: ocelot: introduce a new ocelot_target_{read,write} API
>   net: mscc: ocelot: generalize existing code for VCAP
>   net: dsa: tag_ocelot: use VLAN information from tagging header when
>     available
>
> Xiaoliang Yang (7):
>   net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by
>     chain index
>   net: mscc: ocelot: change vcap to be compatible with full and quad
>     entry
>   net: mscc: ocelot: VCAP IS1 support
>   net: mscc: ocelot: VCAP ES0 support
>   net: mscc: ocelot: multiple actions support
>   net: ocelot: return error if rule is not found
>   net: dsa: felix: correct VCAP IS2 keys offset
>
>  drivers/net/dsa/ocelot/felix.c            |   2 -
>  drivers/net/dsa/ocelot/felix.h            |   2 -
>  drivers/net/dsa/ocelot/felix_vsc9959.c    | 202 +++++-
>  drivers/net/ethernet/mscc/ocelot.c        |  11 +
>  drivers/net/ethernet/mscc/ocelot_ace.c    | 729 ++++++++++++++++------
>  drivers/net/ethernet/mscc/ocelot_ace.h    |  26 +-
>  drivers/net/ethernet/mscc/ocelot_board.c  |   5 +-
>  drivers/net/ethernet/mscc/ocelot_flower.c |  95 ++-
>  drivers/net/ethernet/mscc/ocelot_io.c     |  17 +
>  drivers/net/ethernet/mscc/ocelot_regs.c   |  21 +-
>  drivers/net/ethernet/mscc/ocelot_s2.h     |  64 --
>  include/soc/mscc/ocelot.h                 |  39 +-
>  include/soc/mscc/ocelot_vcap.h            | 199 +++++-
>  net/dsa/tag_ocelot.c                      |  29 +
>  14 files changed, 1105 insertions(+), 336 deletions(-)
>  delete mode 100644 drivers/net/ethernet/mscc/ocelot_s2.h
>
> --
> 2.17.1
>

First of all, net-next has just closed yesterday and will be closed
for the following 2 weeks:
http://vger.kernel.org/~davem/net-next.html

Secondly, could you give an example of how different chains could
express the fact that rules are executed in parallel between the IS1,
IS2 and ES0 TCAMs?

Thanks,
-Vladimir

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index
  2020-06-02  5:18 ` [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index Xiaoliang Yang
@ 2020-06-02  8:36   ` Allan W. Nielsen
  2020-06-03 10:04     ` Vladimir Oltean
  0 siblings, 1 reply; 29+ messages in thread
From: Allan W. Nielsen @ 2020-06-02  8:36 UTC (permalink / raw)
  To: Xiaoliang Yang
  Cc: po.liu, claudiu.manoil, alexandru.marginean, vladimir.oltean,
	leoyang.li, mingkai.hu, andrew, f.fainelli, vivien.didelot,
	davem, jiri, idosch, kuba, vinicius.gomes, nikolay, roopa,
	netdev, linux-kernel, horatiu.vultur, alexandre.belloni,
	joergen.andreasen, UNGLinuxDriver, linux-devel

Hi Xiaoliang,

Happy to see that you are moving in the directions of multi chain - this
seems ilke a much better fit to me.


On 02.06.2020 13:18, Xiaoliang Yang wrote:
>There are three hardware TCAMs for ocelot chips: IS1, IS2 and ES0. Each
>one supports different actions. The hardware flow order is: IS1->IS2->ES0.
>
>This patch add three blocks to store rules according to chain index.
>chain 0 is offloaded to IS1, chain 1 is offloaded to IS2, and egress chain
>0 is offloaded to ES0.

Using "static" allocation to to say chain-X goes to TCAM Y, also seems
like the right approach to me. Given the capabilities of the HW, this
will most likely be the easiest scheme to implement and to explain to
the end-user.

But I think we should make some adjustments to this mapping schema.

Here are some important "things" I would like to consider when defining
this schema:

- As you explain, we have 3 TCAMs (IS1, IS2 and ES0), but we have 3
   parallel lookups in IS1 and 2 parallel lookups in IS2 - and also these
   TCAMs has a wide verity of keys.

- We can utilize these multiple parallel lookups such that it seems like
   they are done in serial (that is if they do not touch the same
   actions), but as they are done in parallel they can not influence each
   other.

- We can let IS1 influence the IS2 lookup (like the GOTO actions was
   intended to be used).

- The chip also has other QoS classification facilities which sits
   before the TCAM (take a look at 3.7.3 QoS, DP, and DSCP Classification
   in vsc7514 datasheet). It we at some point in time want to enable
   this, then I think we need to do that in the same tc-flower framework.

Here is my initial suggestion for an alternative chain-schema:

Chain 0:           The default chain - today this is in IS2. If we proceed
                    with this as is - then this will change.
Chain 1-9999:      These are offloaded by "basic" classification.
Chain 10000-19999: These are offloaded in IS1
                    Chain 10000: Lookup-0 in IS1, and here we could limit the
                                 action to do QoS related stuff (priority
                                 update)
                    Chain 11000: Lookup-1 in IS1, here we could do VLAN
                                 stuff
                    Chain 12000: Lookup-2 in IS1, here we could apply the
                                 "PAG" which is essentially a GOTO.

Chain 20000-29999: These are offloaded in IS2
                    Chain 20000-20255: Lookup-0 in IS2, where CHAIN-ID -
                                       20000 is the PAG value.
                    Chain 21000-21000: Lookup-1 in IS2.

All these chains should be optional - users should only need to
configure the chains they need. To make this work, we need to configure
both the desired actions (could be priority update) and the goto action.
Remember in HW, all packets goes through this process, while in SW they
only follow the "goto" path.

An example could be (I have not tested this yet - sorry):

tc qdisc add dev eth0 ingress

# Activate lookup 11000. We can not do any other rules in chain 0, also
# this implicitly means that we do not want any chains <11000.
tc filter add dev eth0 parent ffff: chain 0 
    action
    matchall goto 11000

tc filter add dev eth0 parent ffff: chain 11000 \
    flower src_mac 00:01:00:00:00:00/00:ff:00:00:00:00 \
    action \
    vlan modify id 1234 \
    pipe \
    goto 20001

tc filter add dev eth0 parent ffff: chain 20001 ...

Maybe it would be an idea to create some use-cases, implement them in a
test which can pass with today's SW, and then once we have a common
understanding of what we want, we can implement it?

/Allan

>Using action goto chain to express flow order as follows:
>        tc filter add dev swp0 chain 0 parent ffff: flower skip_sw \
>        action goto chain 1
>
>Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
>---
> drivers/net/ethernet/mscc/ocelot_ace.c    | 51 +++++++++++++++--------
> drivers/net/ethernet/mscc/ocelot_ace.h    |  7 ++--
> drivers/net/ethernet/mscc/ocelot_flower.c | 46 +++++++++++++++++---
> include/soc/mscc/ocelot.h                 |  2 +-
> include/soc/mscc/ocelot_vcap.h            |  4 +-
> 5 files changed, 81 insertions(+), 29 deletions(-)
>
>diff --git a/drivers/net/ethernet/mscc/ocelot_ace.c b/drivers/net/ethernet/mscc/ocelot_ace.c
>index 748c618db7d8..b76593b40097 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;
>        }
> }
>
>@@ -644,9 +646,9 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
> }
>
> static void vcap_entry_get(struct ocelot *ocelot, struct ocelot_ace_rule *rule,
>-                          int ix)
>+                          int ix, int block_id)
> {
>-       const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS2];
>+       const struct vcap_props *vcap = &ocelot->vcap[block_id];
>        struct vcap_data data;
>        int row, count;
>        u32 cnt;
>@@ -663,6 +665,19 @@ static void vcap_entry_get(struct ocelot *ocelot, struct ocelot_ace_rule *rule,
>        rule->stats.pkts = cnt;
> }
>
>+static void vcap_entry_set(struct ocelot *ocelot, int ix,
>+                          struct ocelot_ace_rule *ace,
>+                          int block_id)
>+{
>+       switch (block_id) {
>+       case VCAP_IS2:
>+               is2_entry_set(ocelot, ix, ace);
>+               break;
>+       default:
>+               break;
>+       }
>+}
>+
> static void ocelot_ace_rule_add(struct ocelot *ocelot,
>                                struct ocelot_acl_block *block,
>                                struct ocelot_ace_rule *rule)
>@@ -790,7 +805,7 @@ static bool ocelot_ace_is_problematic_non_mac_etype(struct ocelot_ace_rule *ace)
> static bool ocelot_exclusive_mac_etype_ace_rules(struct ocelot *ocelot,
>                                                 struct ocelot_ace_rule *ace)
> {
>-       struct ocelot_acl_block *block = &ocelot->acl_block;
>+       struct ocelot_acl_block *block = &ocelot->acl_block[VCAP_IS2];
>        struct ocelot_ace_rule *tmp;
>        unsigned long port;
>        int i;
>@@ -824,15 +839,16 @@ static bool ocelot_exclusive_mac_etype_ace_rules(struct ocelot *ocelot,
>        return true;
> }
>
>-int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
>+int ocelot_ace_rule_offload_add(struct ocelot *ocelot, int block_id,
>                                struct ocelot_ace_rule *rule,
>                                struct netlink_ext_ack *extack)
> {
>-       struct ocelot_acl_block *block = &ocelot->acl_block;
>+       struct ocelot_acl_block *block = &ocelot->acl_block[block_id];
>        struct ocelot_ace_rule *ace;
>        int i, index;
>
>-       if (!ocelot_exclusive_mac_etype_ace_rules(ocelot, rule)) {
>+       if (block_id == VCAP_IS2 &&
>+           !ocelot_exclusive_mac_etype_ace_rules(ocelot, rule)) {
>                NL_SET_ERR_MSG_MOD(extack,
>                                   "Cannot mix MAC_ETYPE with non-MAC_ETYPE rules");
>                return -EBUSY;
>@@ -847,11 +863,11 @@ int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
>        /* Move down the rules to make place for the new rule */
>        for (i = block->count - 1; i > index; i--) {
>                ace = ocelot_ace_rule_get_rule_index(block, i);
>-               is2_entry_set(ocelot, i, ace);
>+               vcap_entry_set(ocelot, i, ace, block_id);
>        }
>
>        /* Now insert the new rule */
>-       is2_entry_set(ocelot, index, rule);
>+       vcap_entry_set(ocelot, index, rule, block_id);
>        return 0;
> }
>
>@@ -902,10 +918,10 @@ static void ocelot_ace_rule_del(struct ocelot *ocelot,
>        block->count--;
> }
>
>-int ocelot_ace_rule_offload_del(struct ocelot *ocelot,
>+int ocelot_ace_rule_offload_del(struct ocelot *ocelot, int block_id,
>                                struct ocelot_ace_rule *rule)
> {
>-       struct ocelot_acl_block *block = &ocelot->acl_block;
>+       struct ocelot_acl_block *block = &ocelot->acl_block[block_id];
>        struct ocelot_ace_rule del_ace;
>        struct ocelot_ace_rule *ace;
>        int i, index;
>@@ -921,29 +937,29 @@ int ocelot_ace_rule_offload_del(struct ocelot *ocelot,
>        /* Move up all the blocks over the deleted rule */
>        for (i = index; i < block->count; i++) {
>                ace = ocelot_ace_rule_get_rule_index(block, i);
>-               is2_entry_set(ocelot, i, ace);
>+               vcap_entry_set(ocelot, i, ace, block_id);
>        }
>
>        /* Now delete the last rule, because it is duplicated */
>-       is2_entry_set(ocelot, block->count, &del_ace);
>+       vcap_entry_set(ocelot, block->count, &del_ace, block_id);
>
>        return 0;
> }
>
>-int ocelot_ace_rule_stats_update(struct ocelot *ocelot,
>+int ocelot_ace_rule_stats_update(struct ocelot *ocelot, int block_id,
>                                 struct ocelot_ace_rule *rule)
> {
>-       struct ocelot_acl_block *block = &ocelot->acl_block;
>+       struct ocelot_acl_block *block = &ocelot->acl_block[block_id];
>        struct ocelot_ace_rule *tmp;
>        int index;
>
>        index = ocelot_ace_rule_get_index_id(block, rule);
>-       vcap_entry_get(ocelot, rule, index);
>+       vcap_entry_get(ocelot, rule, index, block_id);
>
>        /* After we get the result we need to clear the counters */
>        tmp = ocelot_ace_rule_get_rule_index(block, index);
>        tmp->stats.pkts = 0;
>-       is2_entry_set(ocelot, index, tmp);
>+       vcap_entry_set(ocelot, index, tmp, block_id);
>
>        return 0;
> }
>@@ -968,7 +984,7 @@ static void vcap_init(struct ocelot *ocelot, const struct vcap_props *vcap)
>
> int ocelot_ace_init(struct ocelot *ocelot)
> {
>-       struct ocelot_acl_block *block = &ocelot->acl_block;
>+       struct ocelot_acl_block *block;
>
>        vcap_init(ocelot, &ocelot->vcap[VCAP_IS2]);
>
>@@ -987,6 +1003,7 @@ int ocelot_ace_init(struct ocelot *ocelot)
>        ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_CIR_STATE,
>                         OCELOT_POLICER_DISCARD);
>
>+       block = &ocelot->acl_block[VCAP_IS2];
>        block->pol_lpr = OCELOT_POLICER_DISCARD - 1;
>        INIT_LIST_HEAD(&block->rules);
>
>diff --git a/drivers/net/ethernet/mscc/ocelot_ace.h b/drivers/net/ethernet/mscc/ocelot_ace.h
>index 099e177f2617..a9fd99401a65 100644
>--- a/drivers/net/ethernet/mscc/ocelot_ace.h
>+++ b/drivers/net/ethernet/mscc/ocelot_ace.h
>@@ -175,6 +175,7 @@ struct ocelot_ace_frame_ipv6 {
> };
>
> enum ocelot_ace_action {
>+       OCELOT_ACL_ACTION_NULL,
>        OCELOT_ACL_ACTION_DROP,
>        OCELOT_ACL_ACTION_TRAP,
>        OCELOT_ACL_ACTION_POLICE,
>@@ -214,12 +215,12 @@ struct ocelot_ace_rule {
>        u32 pol_ix;
> };
>
>-int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
>+int ocelot_ace_rule_offload_add(struct ocelot *ocelot, int block_id,
>                                struct ocelot_ace_rule *rule,
>                                struct netlink_ext_ack *extack);
>-int ocelot_ace_rule_offload_del(struct ocelot *ocelot,
>+int ocelot_ace_rule_offload_del(struct ocelot *ocelot, int block_id,
>                                struct ocelot_ace_rule *rule);
>-int ocelot_ace_rule_stats_update(struct ocelot *ocelot,
>+int ocelot_ace_rule_stats_update(struct ocelot *ocelot, int block_id,
>                                 struct ocelot_ace_rule *rule);
>
> int ocelot_ace_init(struct ocelot *ocelot);
>diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
>index 891925f73cbc..a1f7b6b28170 100644
>--- a/drivers/net/ethernet/mscc/ocelot_flower.c
>+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
>@@ -9,13 +9,26 @@
>
> #include "ocelot_ace.h"
>
>+static int ocelot_block_id_get(int chain, bool ingress)
>+{
>+       /* Select TCAM blocks by using chain index. Rules in chain 0 are
>+        * implemented on IS1, chain 1 are implemented on IS2, and egress
>+        * chain corresponds to ES0 block.
>+        */
>+       if (ingress)
>+               return chain ? VCAP_IS2 : VCAP_IS1;
>+       else
>+               return VCAP_ES0;
>+}
>+
> static int ocelot_flower_parse_action(struct flow_cls_offload *f,
>                                      struct ocelot_ace_rule *ace)
> {
>+       struct netlink_ext_ack *extack = f->common.extack;
>        const struct flow_action_entry *a;
>+       int i, allowed_chain = 0;
>        s64 burst;
>        u64 rate;
>-       int i;
>
>        if (!flow_offload_has_one_action(&f->rule->action))
>                return -EOPNOTSUPP;
>@@ -28,9 +41,11 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
>                switch (a->id) {
>                case FLOW_ACTION_DROP:
>                        ace->action = OCELOT_ACL_ACTION_DROP;
>+                       allowed_chain = 1;
>                        break;
>                case FLOW_ACTION_TRAP:
>                        ace->action = OCELOT_ACL_ACTION_TRAP;
>+                       allowed_chain = 1;
>                        break;
>                case FLOW_ACTION_POLICE:
>                        ace->action = OCELOT_ACL_ACTION_POLICE;
>@@ -38,10 +53,23 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
>                        ace->pol.rate = div_u64(rate, 1000) * 8;
>                        burst = rate * PSCHED_NS2TICKS(a->police.burst);
>                        ace->pol.burst = div_u64(burst, PSCHED_TICKS_PER_SEC);
>+                       allowed_chain = 1;
>+                       break;
>+               case FLOW_ACTION_GOTO:
>+                       if (a->chain_index != f->common.chain_index + 1) {
>+                               NL_SET_ERR_MSG_MOD(extack, "HW only support goto next chain\n");
>+                               return -EOPNOTSUPP;
>+                       }
>+                       ace->action = OCELOT_ACL_ACTION_NULL;
>+                       allowed_chain = f->common.chain_index;
>                        break;
>                default:
>                        return -EOPNOTSUPP;
>                }
>+               if (f->common.chain_index != allowed_chain) {
>+                       NL_SET_ERR_MSG_MOD(extack, "Action is not supported on this chain\n");
>+                       return -EOPNOTSUPP;
>+               }
>        }
>
>        return 0;
>@@ -205,7 +233,7 @@ int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
>                              struct flow_cls_offload *f, bool ingress)
> {
>        struct ocelot_ace_rule *ace;
>-       int ret;
>+       int ret, block_id;
>
>        ace = ocelot_ace_rule_create(ocelot, port, f);
>        if (!ace)
>@@ -216,8 +244,10 @@ int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
>                kfree(ace);
>                return ret;
>        }
>+       block_id = ocelot_block_id_get(f->common.chain_index, ingress);
>
>-       return ocelot_ace_rule_offload_add(ocelot, ace, f->common.extack);
>+       return ocelot_ace_rule_offload_add(ocelot, block_id, ace,
>+                                          f->common.extack);
> }
> EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
>
>@@ -225,11 +255,13 @@ int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
>                              struct flow_cls_offload *f, bool ingress)
> {
>        struct ocelot_ace_rule ace;
>+       int block_id;
>
>        ace.prio = f->common.prio;
>        ace.id = f->cookie;
>+       block_id = ocelot_block_id_get(f->common.chain_index, ingress);
>
>-       return ocelot_ace_rule_offload_del(ocelot, &ace);
>+       return ocelot_ace_rule_offload_del(ocelot, block_id, &ace);
> }
> EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
>
>@@ -237,11 +269,13 @@ int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
>                            struct flow_cls_offload *f, bool ingress)
> {
>        struct ocelot_ace_rule ace;
>-       int ret;
>+       int ret, block_id;
>
>        ace.prio = f->common.prio;
>        ace.id = f->cookie;
>-       ret = ocelot_ace_rule_stats_update(ocelot, &ace);
>+       block_id = ocelot_block_id_get(f->common.chain_index, ingress);
>+
>+       ret = ocelot_ace_rule_stats_update(ocelot, block_id, &ace);
>        if (ret)
>                return ret;
>
>diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
>index 91357b1c8f31..4b2320bdc036 100644
>--- a/include/soc/mscc/ocelot.h
>+++ b/include/soc/mscc/ocelot.h
>@@ -540,7 +540,7 @@ struct ocelot {
>
>        struct list_head                multicast;
>
>-       struct ocelot_acl_block         acl_block;
>+       struct ocelot_acl_block         acl_block[3];
>
>        const struct vcap_props         *vcap;
>
>diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h
>index 26d9384b3657..495847a40490 100644
>--- a/include/soc/mscc/ocelot_vcap.h
>+++ b/include/soc/mscc/ocelot_vcap.h
>@@ -14,9 +14,9 @@
>  */
>
> enum {
>-       /* VCAP_IS1, */
>+       VCAP_IS1,
>        VCAP_IS2,
>-       /* VCAP_ES0, */
>+       VCAP_ES0,
> };
>
> struct vcap_props {
>--
>2.17.1
>
/Allan

^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [EXT] Re: [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support
  2020-06-02  8:03 ` [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Vladimir Oltean
@ 2020-06-02  8:49   ` Xiaoliang Yang
  2020-06-09 11:35     ` Vladimir Oltean
  0 siblings, 1 reply; 29+ messages in thread
From: Xiaoliang Yang @ 2020-06-02  8:49 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Po Liu, Claudiu Manoil, Alexandru Marginean, Vladimir Oltean,
	Leo Li, Mingkai Hu, Andrew Lunn, Florian Fainelli,
	Vivien Didelot, David S. Miller, Jiri Pirko, Ido Schimmel,
	Jakub Kicinski, Vinicius Costa Gomes, Nikolay Aleksandrov,
	Roopa Prabhu, netdev, lkml, Horatiu Vultur, Alexandre Belloni,
	Allan W. Nielsen, Joergen Andreasen,
	Microchip Linux Driver Support, linux-devel

Hi Vladimir,

On Tus, 2 Jun 2020 at 16:04,
> First of all, net-next has just closed yesterday and will be closed for the following 2 weeks:
> https://eur01.safelinks.protection.outlook.com/?url=http:%2F%2Fvger.kernel.org%2F~davem%2Fnet-next.html&amp;data=02%7C01% 7Cxiaoliang.yang_1%40nxp.com%7C2fad4495dabc4f4ca5fd08d806cb70af%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637266818117666386&amp;sdata=ziVybWb4HzYXanehF5KwNv5RJL%2BZz6NeFvrZWg657B8%3D&amp;reserved=0
>
> Secondly, could you give an example of how different chains could express the fact that rules are executed in parallel between the IS1,
> IS2 and ES0 TCAMs?
>

Different TCAMs are not running in parallel, they have flow order: IS1->IS2->ES0. Using goto chain to express the flow order. 
For example:
	tc qdisc add dev swp0 ingress
	tc filter add dev swp0 chain 0 protocol 802.1Q parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action vlan modify id 2 priority 2 action goto chain 1
	tc filter add dev swp0 chain 1 protocol 802.1Q parent ffff: flower skip_sw vlan_id 2 vlan_prio 2 action drop
In this example, package with (vid=1,pcp=1) vlan tag will be modified to (vid=2,pcp=2) vlan tag on IS1, then will be dropped on IS2.

If there is no rule match on IS1, it will still lookup on IS2. We can set a rule on chain 0 to express this:
	tc filter add dev swp0 chain 0 parent ffff: flower skip_sw action goto chain 1

In addition, VSC9959 chip has PSFP and "Sequence Generation recovery" modules are running after IS2, the flow order like this: IS1->IS2->PSFP-> "Sequence Generation recovery" ->ES0, we can also add chains like this to express these two modules in future.

BTW, where should I sent patches to due to net-next closed?

Thanks,
Xiaoliang Yang

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 net-next 05/10] net: mscc: ocelot: VCAP IS1 support
  2020-06-02  5:18 ` [PATCH v2 net-next 05/10] net: mscc: ocelot: VCAP IS1 support Xiaoliang Yang
@ 2020-06-02 16:16   ` Jakub Kicinski
  0 siblings, 0 replies; 29+ messages in thread
From: Jakub Kicinski @ 2020-06-02 16:16 UTC (permalink / raw)
  To: Xiaoliang Yang
  Cc: po.liu, claudiu.manoil, alexandru.marginean, vladimir.oltean,
	leoyang.li, mingkai.hu, andrew, f.fainelli, vivien.didelot,
	davem, jiri, idosch, vinicius.gomes, nikolay, roopa, netdev,
	linux-kernel, horatiu.vultur, alexandre.belloni, allan.nielsen,
	joergen.andreasen, UNGLinuxDriver, linux-devel

On Tue,  2 Jun 2020 13:18:23 +0800 Xiaoliang Yang wrote:
> VCAP IS1 is a VCAP module which can filter MAC, IP, VLAN, protocol, and
> TCP/UDP ports keys, and do Qos classified and VLAN retag actions.
> 
> This patch added VCAP IS1 support in ocelot ace driver, which can supports
> vlan modify and skbedit priority 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@nxp.com>

drivers/net/dsa/ocelot/felix_vsc9959.c:570:19: warning: symbol 'vsc9959_vcap_is1_keys' was not declared. Should it be static?
drivers/net/dsa/ocelot/felix_vsc9959.c:621:19: warning: symbol 'vsc9959_vcap_is1_actions' was not declared. Should it be static?
drivers/net/ethernet/mscc/ocelot_ace.c: In function ‘is1_entry_set’:
drivers/net/ethernet/mscc/ocelot_ace.c:733:27: warning: variable ‘ip_data’ set but not used [-Wunused-but-set-variable]
 733 |   struct ocelot_vcap_u48 *ip_data;
     |                           ^~~~~~~
drivers/net/ethernet/mscc/ocelot_ace.c:732:32: warning: variable ‘ds’ set but not used [-Wunused-but-set-variable]
 732 |   struct ocelot_vcap_u8 proto, ds;
     |                                ^~
drivers/net/ethernet/mscc/ocelot_ace.c:727:51: warning: variable ‘tcp_psh’ set but not used [-Wunused-but-set-variable]
 727 |   enum ocelot_vcap_bit tcp_fin, tcp_syn, tcp_rst, tcp_psh;
     |                                                   ^~~~~~~
drivers/net/ethernet/mscc/ocelot_ace.c:727:42: warning: variable ‘tcp_rst’ set but not used [-Wunused-but-set-variable]
 727 |   enum ocelot_vcap_bit tcp_fin, tcp_syn, tcp_rst, tcp_psh;
     |                                          ^~~~~~~
drivers/net/ethernet/mscc/ocelot_ace.c:727:33: warning: variable ‘tcp_syn’ set but not used [-Wunused-but-set-variable]
 727 |   enum ocelot_vcap_bit tcp_fin, tcp_syn, tcp_rst, tcp_psh;
     |                                 ^~~~~~~
drivers/net/ethernet/mscc/ocelot_ace.c:727:24: warning: variable ‘tcp_fin’ set but not used [-Wunused-but-set-variable]
 727 |   enum ocelot_vcap_bit tcp_fin, tcp_syn, tcp_rst, tcp_psh;
     |                        ^~~~~~~
drivers/net/ethernet/mscc/ocelot_ace.c:726:33: warning: variable ‘tcp_urg’ set but not used [-Wunused-but-set-variable]
 726 |   enum ocelot_vcap_bit tcp_ack, tcp_urg;
     |                                 ^~~~~~~
drivers/net/ethernet/mscc/ocelot_ace.c:726:24: warning: variable ‘tcp_ack’ set but not used [-Wunused-but-set-variable]
 726 |   enum ocelot_vcap_bit tcp_ack, tcp_urg;
     |                        ^~~~~~~
drivers/net/ethernet/mscc/ocelot_ace.c:725:24: warning: variable ‘ttl’ set but not used [-Wunused-but-set-variable]
 725 |   enum ocelot_vcap_bit ttl, fragment, options;
     |                        ^~~
drivers/net/ethernet/mscc/ocelot_ace.c:724:24: warning: variable ‘seq_zero’ set but not used [-Wunused-but-set-variable]
 724 |   enum ocelot_vcap_bit seq_zero, tcp;
     |                        ^~~~~~~~
drivers/net/ethernet/mscc/ocelot_ace.c:723:36: warning: variable ‘sport_eq_dport’ set but not used [-Wunused-but-set-variable]
 723 |   enum ocelot_vcap_bit sip_eq_dip, sport_eq_dport;
     |                                    ^~~~~~~~~~~~~~
drivers/net/ethernet/mscc/ocelot_ace.c:723:24: warning: variable ‘sip_eq_dip’ set but not used [-Wunused-but-set-variable]
 723 |   enum ocelot_vcap_bit sip_eq_dip, sport_eq_dport;
     |                        ^~~~~~~~~~

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 net-next 06/10] net: mscc: ocelot: VCAP ES0 support
  2020-06-02  5:18 ` [PATCH v2 net-next 06/10] net: mscc: ocelot: VCAP ES0 support Xiaoliang Yang
@ 2020-06-02 16:17   ` Jakub Kicinski
  0 siblings, 0 replies; 29+ messages in thread
From: Jakub Kicinski @ 2020-06-02 16:17 UTC (permalink / raw)
  To: Xiaoliang Yang
  Cc: po.liu, claudiu.manoil, alexandru.marginean, vladimir.oltean,
	leoyang.li, mingkai.hu, andrew, f.fainelli, vivien.didelot,
	davem, jiri, idosch, vinicius.gomes, nikolay, roopa, netdev,
	linux-kernel, horatiu.vultur, alexandre.belloni, allan.nielsen,
	joergen.andreasen, UNGLinuxDriver, linux-devel

On Tue,  2 Jun 2020 13:18:24 +0800 Xiaoliang Yang wrote:
> VCAP ES0 is an egress VCAP working on all outgoing frames.
> This patch added ES0 driver to support vlan push action of tc filter.
> Usage:
> 	tc filter add dev swp1 egress protocol 802.1Q flower skip_sw
> 	vlan_id 1 vlan_prio 1 action vlan push id 2 priority 2
> 
> Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>

Please make sure code builds cleanly with W=1 C=1 flags.

drivers/net/dsa/ocelot/felix_vsc9959.c:577:19: warning: symbol 'vsc9959_vcap_es0_keys' was not declared. Should it be static?
drivers/net/dsa/ocelot/felix_vsc9959.c:588:19: warning: symbol 'vsc9959_vcap_es0_actions' was not declared. Should it be static?

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index
  2020-06-02  8:36   ` Allan W. Nielsen
@ 2020-06-03 10:04     ` Vladimir Oltean
  2020-06-08 13:56       ` Allan W. Nielsen
  0 siblings, 1 reply; 29+ messages in thread
From: Vladimir Oltean @ 2020-06-03 10:04 UTC (permalink / raw)
  To: Allan W. Nielsen
  Cc: Xiaoliang Yang, Po Liu, Claudiu Manoil, Alexandru Marginean,
	Vladimir Oltean, Li Yang, Mingkai Hu, Andrew Lunn,
	Florian Fainelli, Vivien Didelot, David S. Miller, Jiri Pirko,
	Ido Schimmel, Jakub Kicinski, Vinicius Costa Gomes,
	Nikolay Aleksandrov, Roopa Prabhu, netdev, lkml, Horatiu Vultur,
	Alexandre Belloni, Joergen Andreasen,
	Microchip Linux Driver Support, linux-devel

Hi Allan,

On Tue, 2 Jun 2020 at 11:38, Allan W. Nielsen
<allan.nielsen@microchip.com> wrote:
>
> Hi Xiaoliang,
>
> Happy to see that you are moving in the directions of multi chain - this
> seems ilke a much better fit to me.
>
>
> On 02.06.2020 13:18, Xiaoliang Yang wrote:
> >There are three hardware TCAMs for ocelot chips: IS1, IS2 and ES0. Each
> >one supports different actions. The hardware flow order is: IS1->IS2->ES0.
> >
> >This patch add three blocks to store rules according to chain index.
> >chain 0 is offloaded to IS1, chain 1 is offloaded to IS2, and egress chain
> >0 is offloaded to ES0.
>
> Using "static" allocation to to say chain-X goes to TCAM Y, also seems
> like the right approach to me. Given the capabilities of the HW, this
> will most likely be the easiest scheme to implement and to explain to
> the end-user.
>
> But I think we should make some adjustments to this mapping schema.
>
> Here are some important "things" I would like to consider when defining
> this schema:
>
> - As you explain, we have 3 TCAMs (IS1, IS2 and ES0), but we have 3
>    parallel lookups in IS1 and 2 parallel lookups in IS2 - and also these
>    TCAMs has a wide verity of keys.
>
> - We can utilize these multiple parallel lookups such that it seems like
>    they are done in serial (that is if they do not touch the same
>    actions), but as they are done in parallel they can not influence each
>    other.
>
> - We can let IS1 influence the IS2 lookup (like the GOTO actions was
>    intended to be used).
>
> - The chip also has other QoS classification facilities which sits
>    before the TCAM (take a look at 3.7.3 QoS, DP, and DSCP Classification
>    in vsc7514 datasheet). It we at some point in time want to enable
>    this, then I think we need to do that in the same tc-flower framework.
>
> Here is my initial suggestion for an alternative chain-schema:
>
> Chain 0:           The default chain - today this is in IS2. If we proceed
>                     with this as is - then this will change.
> Chain 1-9999:      These are offloaded by "basic" classification.
> Chain 10000-19999: These are offloaded in IS1
>                     Chain 10000: Lookup-0 in IS1, and here we could limit the
>                                  action to do QoS related stuff (priority
>                                  update)
>                     Chain 11000: Lookup-1 in IS1, here we could do VLAN
>                                  stuff
>                     Chain 12000: Lookup-2 in IS1, here we could apply the
>                                  "PAG" which is essentially a GOTO.
>
> Chain 20000-29999: These are offloaded in IS2
>                     Chain 20000-20255: Lookup-0 in IS2, where CHAIN-ID -
>                                        20000 is the PAG value.
>                     Chain 21000-21000: Lookup-1 in IS2.
>
> All these chains should be optional - users should only need to
> configure the chains they need. To make this work, we need to configure
> both the desired actions (could be priority update) and the goto action.
> Remember in HW, all packets goes through this process, while in SW they
> only follow the "goto" path.
>
> An example could be (I have not tested this yet - sorry):
>
> tc qdisc add dev eth0 ingress
>
> # Activate lookup 11000. We can not do any other rules in chain 0, also
> # this implicitly means that we do not want any chains <11000.
> tc filter add dev eth0 parent ffff: chain 0
>     action
>     matchall goto 11000
>
> tc filter add dev eth0 parent ffff: chain 11000 \
>     flower src_mac 00:01:00:00:00:00/00:ff:00:00:00:00 \
>     action \
>     vlan modify id 1234 \
>     pipe \
>     goto 20001
>
> tc filter add dev eth0 parent ffff: chain 20001 ...
>
> Maybe it would be an idea to create some use-cases, implement them in a
> test which can pass with today's SW, and then once we have a common
> understanding of what we want, we can implement it?
>
> /Allan
>
> >Using action goto chain to express flow order as follows:
> >        tc filter add dev swp0 chain 0 parent ffff: flower skip_sw \
> >        action goto chain 1
> >
> >Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
> >---
> > drivers/net/ethernet/mscc/ocelot_ace.c    | 51 +++++++++++++++--------
> > drivers/net/ethernet/mscc/ocelot_ace.h    |  7 ++--
> > drivers/net/ethernet/mscc/ocelot_flower.c | 46 +++++++++++++++++---
> > include/soc/mscc/ocelot.h                 |  2 +-
> > include/soc/mscc/ocelot_vcap.h            |  4 +-
> > 5 files changed, 81 insertions(+), 29 deletions(-)

> /Allan

What would be the advantage, from a user perspective, in exposing the
3 IS1 lookups as separate chains with orthogonal actions?
If the user wants to add an IS1 action that performs QoS
classification, VLAN classification and selects a custom PAG, they
would have to install 3 separate filters with the same key, each into
its own chain. Then the driver would be smart enough to figure out
that the 3 keys are actually the same, so it could merge them.
In comparison, we could just add a single filter to the IS1 chain,
with 3 actions (skbedit priority, vlan modify, goto is2).

Thanks,
-Vladimir

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index
  2020-06-03 10:04     ` Vladimir Oltean
@ 2020-06-08 13:56       ` Allan W. Nielsen
  2020-06-09 12:55         ` Vladimir Oltean
  0 siblings, 1 reply; 29+ messages in thread
From: Allan W. Nielsen @ 2020-06-08 13:56 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Xiaoliang Yang, Po Liu, Claudiu Manoil, Alexandru Marginean,
	Vladimir Oltean, Li Yang, Mingkai Hu, Andrew Lunn,
	Florian Fainelli, Vivien Didelot, David S. Miller, Jiri Pirko,
	Ido Schimmel, Jakub Kicinski, Vinicius Costa Gomes,
	Nikolay Aleksandrov, Roopa Prabhu, netdev, lkml, Horatiu Vultur,
	Alexandre Belloni, Joergen Andreasen,
	Microchip Linux Driver Support, linux-devel

On 03.06.2020 13:04, Vladimir Oltean wrote:
>On Tue, 2 Jun 2020 at 11:38, Allan W. Nielsen
><allan.nielsen@microchip.com> wrote:
>>
>> Hi Xiaoliang,
>>
>> Happy to see that you are moving in the directions of multi chain - this
>> seems ilke a much better fit to me.
>>
>>
>> On 02.06.2020 13:18, Xiaoliang Yang wrote:
>> >There are three hardware TCAMs for ocelot chips: IS1, IS2 and ES0. Each
>> >one supports different actions. The hardware flow order is: IS1->IS2->ES0.
>> >
>> >This patch add three blocks to store rules according to chain index.
>> >chain 0 is offloaded to IS1, chain 1 is offloaded to IS2, and egress chain
>> >0 is offloaded to ES0.
>>
>> Using "static" allocation to to say chain-X goes to TCAM Y, also seems
>> like the right approach to me. Given the capabilities of the HW, this
>> will most likely be the easiest scheme to implement and to explain to
>> the end-user.
>>
>> But I think we should make some adjustments to this mapping schema.
>>
>> Here are some important "things" I would like to consider when defining
>> this schema:
>>
>> - As you explain, we have 3 TCAMs (IS1, IS2 and ES0), but we have 3
>>    parallel lookups in IS1 and 2 parallel lookups in IS2 - and also these
>>    TCAMs has a wide verity of keys.
>>
>> - We can utilize these multiple parallel lookups such that it seems like
>>    they are done in serial (that is if they do not touch the same
>>    actions), but as they are done in parallel they can not influence each
>>    other.
>>
>> - We can let IS1 influence the IS2 lookup (like the GOTO actions was
>>    intended to be used).
>>
>> - The chip also has other QoS classification facilities which sits
>>    before the TCAM (take a look at 3.7.3 QoS, DP, and DSCP Classification
>>    in vsc7514 datasheet). It we at some point in time want to enable
>>    this, then I think we need to do that in the same tc-flower framework.
>>
>> Here is my initial suggestion for an alternative chain-schema:
>>
>> Chain 0:           The default chain - today this is in IS2. If we proceed
>>                     with this as is - then this will change.
>> Chain 1-9999:      These are offloaded by "basic" classification.
>> Chain 10000-19999: These are offloaded in IS1
>>                     Chain 10000: Lookup-0 in IS1, and here we could limit the
>>                                  action to do QoS related stuff (priority
>>                                  update)
>>                     Chain 11000: Lookup-1 in IS1, here we could do VLAN
>>                                  stuff
>>                     Chain 12000: Lookup-2 in IS1, here we could apply the
>>                                  "PAG" which is essentially a GOTO.
>>
>> Chain 20000-29999: These are offloaded in IS2
>>                     Chain 20000-20255: Lookup-0 in IS2, where CHAIN-ID -
>>                                        20000 is the PAG value.
>>                     Chain 21000-21000: Lookup-1 in IS2.
>>
>> All these chains should be optional - users should only need to
>> configure the chains they need. To make this work, we need to configure
>> both the desired actions (could be priority update) and the goto action.
>> Remember in HW, all packets goes through this process, while in SW they
>> only follow the "goto" path.
>>
>> An example could be (I have not tested this yet - sorry):
>>
>> tc qdisc add dev eth0 ingress
>>
>> # Activate lookup 11000. We can not do any other rules in chain 0, also
>> # this implicitly means that we do not want any chains <11000.
>> tc filter add dev eth0 parent ffff: chain 0
>>     action
>>     matchall goto 11000
>>
>> tc filter add dev eth0 parent ffff: chain 11000 \
>>     flower src_mac 00:01:00:00:00:00/00:ff:00:00:00:00 \
>>     action \
>>     vlan modify id 1234 \
>>     pipe \
>>     goto 20001
>>
>> tc filter add dev eth0 parent ffff: chain 20001 ...
>>
>> Maybe it would be an idea to create some use-cases, implement them in a
>> test which can pass with today's SW, and then once we have a common
>> understanding of what we want, we can implement it?
>>
>> /Allan
>>
>> >Using action goto chain to express flow order as follows:
>> >        tc filter add dev swp0 chain 0 parent ffff: flower skip_sw \
>> >        action goto chain 1
>> >
>> >Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
>> >---
>> > drivers/net/ethernet/mscc/ocelot_ace.c    | 51 +++++++++++++++--------
>> > drivers/net/ethernet/mscc/ocelot_ace.h    |  7 ++--
>> > drivers/net/ethernet/mscc/ocelot_flower.c | 46 +++++++++++++++++---
>> > include/soc/mscc/ocelot.h                 |  2 +-
>> > include/soc/mscc/ocelot_vcap.h            |  4 +-
>> > 5 files changed, 81 insertions(+), 29 deletions(-)
>
>> /Allan
>
>What would be the advantage, from a user perspective, in exposing the
>3 IS1 lookups as separate chains with orthogonal actions?
>If the user wants to add an IS1 action that performs QoS
>classification, VLAN classification and selects a custom PAG, they
>would have to install 3 separate filters with the same key, each into
>its own chain. Then the driver would be smart enough to figure out
>that the 3 keys are actually the same, so it could merge them.
>In comparison, we could just add a single filter to the IS1 chain,
>with 3 actions (skbedit priority, vlan modify, goto is2).

Hi, I realize I forgot to answer this one - sorry.

The reason for this design is that we have use-cases where the rules to
do QoS classification must not impact VLAN classification. The easiest
way to do that, it to have it in separated lookups.

But we could make this more flexible to support your use-case better. A
alternative approach would be to assign exclusive-right-to-action on
first use. If the user choose to use the VLAN update in a given loopup,
then it cannot be used in others.

If the user attempt to use a given action across different lookups we
need to return an error.

Would that work for you? Any downside in such approach?

/Allan


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [EXT] Re: [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support
  2020-06-02  8:49   ` [EXT] " Xiaoliang Yang
@ 2020-06-09 11:35     ` Vladimir Oltean
  0 siblings, 0 replies; 29+ messages in thread
From: Vladimir Oltean @ 2020-06-09 11:35 UTC (permalink / raw)
  To: Xiaoliang Yang
  Cc: Po Liu, Claudiu Manoil, Alexandru Marginean, Vladimir Oltean,
	Leo Li, Mingkai Hu, Andrew Lunn, Florian Fainelli,
	Vivien Didelot, David S. Miller, Jiri Pirko, Ido Schimmel,
	Jakub Kicinski, Vinicius Costa Gomes, Nikolay Aleksandrov,
	Roopa Prabhu, netdev, lkml, Horatiu Vultur, Alexandre Belloni,
	Allan W. Nielsen, Joergen Andreasen,
	Microchip Linux Driver Support, linux-devel

Hi Xiaoliang,

On Tue, 2 Jun 2020 at 11:50, Xiaoliang Yang <xiaoliang.yang_1@nxp.com> wrote:
>
> Hi Vladimir,
>
> On Tus, 2 Jun 2020 at 16:04,
> > First of all, net-next has just closed yesterday and will be closed for the following 2 weeks:
> > https://eur01.safelinks.protection.outlook.com/?url=http:%2F%2Fvger.kernel.org%2F~davem%2Fnet-next.html&amp;data=02%7C01% 7Cxiaoliang.yang_1%40nxp.com%7C2fad4495dabc4f4ca5fd08d806cb70af%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637266818117666386&amp;sdata=ziVybWb4HzYXanehF5KwNv5RJL%2BZz6NeFvrZWg657B8%3D&amp;reserved=0
> >
> > Secondly, could you give an example of how different chains could express the fact that rules are executed in parallel between the IS1,
> > IS2 and ES0 TCAMs?
> >
>
> Different TCAMs are not running in parallel, they have flow order: IS1->IS2->ES0. Using goto chain to express the flow order.
> For example:
>         tc qdisc add dev swp0 ingress
>         tc filter add dev swp0 chain 0 protocol 802.1Q parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action vlan modify id 2 priority 2 action goto chain 1
>         tc filter add dev swp0 chain 1 protocol 802.1Q parent ffff: flower skip_sw vlan_id 2 vlan_prio 2 action drop
> In this example, package with (vid=1,pcp=1) vlan tag will be modified to (vid=2,pcp=2) vlan tag on IS1, then will be dropped on IS2.
>
> If there is no rule match on IS1, it will still lookup on IS2. We can set a rule on chain 0 to express this:
>         tc filter add dev swp0 chain 0 parent ffff: flower skip_sw action goto chain 1
>
> In addition, VSC9959 chip has PSFP and "Sequence Generation recovery" modules are running after IS2, the flow order like this: IS1->IS2->PSFP-> "Sequence Generation recovery" ->ES0, we can also add chains like this to express these two modules in future.
>

I've been pondering over what is a good abstraction for 802.1CB and I
don't think that it would be a tc action. After reading Annex C "Frame
Replication and Elimination for Reliability in systems" in
8021CB-2017, I think maybe it should be modeled as a stacked net
device a la hsr, but with the ability to add its own stream filtering
rules and actions (a la bridge fdb).
But for the PSFP policers, in principle I think you are correct, we
could designate a static chain id for those.

> BTW, where should I sent patches to due to net-next closed?
>

You can keep sending patches just as you did. There's nothing wrong
with doing that as long as you're only doing it for the feedback (RFC
== Request For Comments).
Since David receives a lot of patches and the backlog builds up very
quickly, he just rejects patches sent to net-next during the merge
window instead of queuing them up.
Patches that are bugfixes (not the case here, just in general) can be
sent to the net tree at all times (even during the merge window).
In all cases, the mailing list is the same, just the --subject-prefix
is different (net, net-next, rfc).

> Thanks,
> Xiaoliang Yang

Thanks,
-Vladimir

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index
  2020-06-08 13:56       ` Allan W. Nielsen
@ 2020-06-09 12:55         ` Vladimir Oltean
  2020-06-10 18:18           ` Allan W. Nielsen
  0 siblings, 1 reply; 29+ messages in thread
From: Vladimir Oltean @ 2020-06-09 12:55 UTC (permalink / raw)
  To: Allan W. Nielsen
  Cc: Xiaoliang Yang, Po Liu, Claudiu Manoil, Alexandru Marginean,
	Vladimir Oltean, Li Yang, Mingkai Hu, Andrew Lunn,
	Florian Fainelli, Vivien Didelot, David S. Miller, Jiri Pirko,
	Ido Schimmel, Jakub Kicinski, Vinicius Costa Gomes,
	Nikolay Aleksandrov, Roopa Prabhu, netdev, lkml, Horatiu Vultur,
	Alexandre Belloni, Joergen Andreasen,
	Microchip Linux Driver Support, linux-devel

Hi Allan,

On Mon, 8 Jun 2020 at 16:56, Allan W. Nielsen
<allan.nielsen@microchip.com> wrote:
>
> On 03.06.2020 13:04, Vladimir Oltean wrote:
> >On Tue, 2 Jun 2020 at 11:38, Allan W. Nielsen
> ><allan.nielsen@microchip.com> wrote:
> >>
> >> Hi Xiaoliang,
> >>
> >> Happy to see that you are moving in the directions of multi chain - this
> >> seems ilke a much better fit to me.
> >>
> >>
> >> On 02.06.2020 13:18, Xiaoliang Yang wrote:
> >> >There are three hardware TCAMs for ocelot chips: IS1, IS2 and ES0. Each
> >> >one supports different actions. The hardware flow order is: IS1->IS2->ES0.
> >> >
> >> >This patch add three blocks to store rules according to chain index.
> >> >chain 0 is offloaded to IS1, chain 1 is offloaded to IS2, and egress chain
> >> >0 is offloaded to ES0.
> >>
> >> Using "static" allocation to to say chain-X goes to TCAM Y, also seems
> >> like the right approach to me. Given the capabilities of the HW, this
> >> will most likely be the easiest scheme to implement and to explain to
> >> the end-user.
> >>
> >> But I think we should make some adjustments to this mapping schema.
> >>
> >> Here are some important "things" I would like to consider when defining
> >> this schema:
> >>
> >> - As you explain, we have 3 TCAMs (IS1, IS2 and ES0), but we have 3
> >>    parallel lookups in IS1 and 2 parallel lookups in IS2 - and also these
> >>    TCAMs has a wide verity of keys.
> >>
> >> - We can utilize these multiple parallel lookups such that it seems like
> >>    they are done in serial (that is if they do not touch the same
> >>    actions), but as they are done in parallel they can not influence each
> >>    other.
> >>
> >> - We can let IS1 influence the IS2 lookup (like the GOTO actions was
> >>    intended to be used).
> >>
> >> - The chip also has other QoS classification facilities which sits
> >>    before the TCAM (take a look at 3.7.3 QoS, DP, and DSCP Classification
> >>    in vsc7514 datasheet). It we at some point in time want to enable
> >>    this, then I think we need to do that in the same tc-flower framework.
> >>
> >> Here is my initial suggestion for an alternative chain-schema:
> >>
> >> Chain 0:           The default chain - today this is in IS2. If we proceed
> >>                     with this as is - then this will change.
> >> Chain 1-9999:      These are offloaded by "basic" classification.
> >> Chain 10000-19999: These are offloaded in IS1
> >>                     Chain 10000: Lookup-0 in IS1, and here we could limit the
> >>                                  action to do QoS related stuff (priority
> >>                                  update)
> >>                     Chain 11000: Lookup-1 in IS1, here we could do VLAN
> >>                                  stuff
> >>                     Chain 12000: Lookup-2 in IS1, here we could apply the
> >>                                  "PAG" which is essentially a GOTO.
> >>
> >> Chain 20000-29999: These are offloaded in IS2
> >>                     Chain 20000-20255: Lookup-0 in IS2, where CHAIN-ID -
> >>                                        20000 is the PAG value.
> >>                     Chain 21000-21000: Lookup-1 in IS2.
> >>
> >> All these chains should be optional - users should only need to
> >> configure the chains they need. To make this work, we need to configure
> >> both the desired actions (could be priority update) and the goto action.
> >> Remember in HW, all packets goes through this process, while in SW they
> >> only follow the "goto" path.
> >>
> >> An example could be (I have not tested this yet - sorry):
> >>
> >> tc qdisc add dev eth0 ingress
> >>
> >> # Activate lookup 11000. We can not do any other rules in chain 0, also
> >> # this implicitly means that we do not want any chains <11000.
> >> tc filter add dev eth0 parent ffff: chain 0
> >>     action
> >>     matchall goto 11000
> >>
> >> tc filter add dev eth0 parent ffff: chain 11000 \
> >>     flower src_mac 00:01:00:00:00:00/00:ff:00:00:00:00 \
> >>     action \
> >>     vlan modify id 1234 \
> >>     pipe \
> >>     goto 20001
> >>
> >> tc filter add dev eth0 parent ffff: chain 20001 ...
> >>
> >> Maybe it would be an idea to create some use-cases, implement them in a
> >> test which can pass with today's SW, and then once we have a common
> >> understanding of what we want, we can implement it?
> >>
> >> /Allan
> >>
> >> >Using action goto chain to express flow order as follows:
> >> >        tc filter add dev swp0 chain 0 parent ffff: flower skip_sw \
> >> >        action goto chain 1
> >> >
> >> >Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
> >> >---
> >> > drivers/net/ethernet/mscc/ocelot_ace.c    | 51 +++++++++++++++--------
> >> > drivers/net/ethernet/mscc/ocelot_ace.h    |  7 ++--
> >> > drivers/net/ethernet/mscc/ocelot_flower.c | 46 +++++++++++++++++---
> >> > include/soc/mscc/ocelot.h                 |  2 +-
> >> > include/soc/mscc/ocelot_vcap.h            |  4 +-
> >> > 5 files changed, 81 insertions(+), 29 deletions(-)
> >
> >> /Allan
> >
> >What would be the advantage, from a user perspective, in exposing the
> >3 IS1 lookups as separate chains with orthogonal actions?
> >If the user wants to add an IS1 action that performs QoS
> >classification, VLAN classification and selects a custom PAG, they
> >would have to install 3 separate filters with the same key, each into
> >its own chain. Then the driver would be smart enough to figure out
> >that the 3 keys are actually the same, so it could merge them.
> >In comparison, we could just add a single filter to the IS1 chain,
> >with 3 actions (skbedit priority, vlan modify, goto is2).
>
> Hi, I realize I forgot to answer this one - sorry.
>
> The reason for this design is that we have use-cases where the rules to
> do QoS classification must not impact VLAN classification. The easiest
> way to do that, it to have it in separated lookups.
>

Impact in the sense that an IS1 rule for VLAN classification might
'steal' packets from an IS1 rule for QoS classification (since the
TCAM stops after the first matching entry in each lookup)?
Such as:

tc filter add dev swp0 ingress protocol 802.1Q flower vlan_ethtype
ipv4 action skbedit priority 3
tc filter add dev swp0 ingress protocol 802.1Q flower vlan_id 0
vlan_prio 2 action vlan modify id 12 priority 1

The trouble with this TCAM seems to be that it doesn't support the
'pipe' control, so rules on overlapping keys will have unpredictable
results. So if we had these 2 rules in the same lookup in hardware,
then an IPv4 packet tagged with VID 0 and PCP 2 would get classified
to QoS class 3 but would not get retagged to VID 12 PCP 1, right?

So we should error out if the rule's control is 'pipe' (I haven't
checked if we can do that, I hope we can), and basically only 'goto'
something.
Which brings the discussion to "goto where?".
From the IS1 chain for QoS classification, you could goto the IS1
chain for VLAN classification, ok, that's your example. Is this goto
optional? (i.e. can you goto a PAG in IS2 directly, and in that case
would VLAN classification be skipped in hardware for the packets that
skip it in software?)
Your suggestion of having an entire chain for PAG selection suggests
to me that the rules in chain 10000 (IS1 for QoS classification) would
need to have a non-optional goto to chain 11000 (IS1 for VLAN
classification), which in turn would have a non-optional goto to chain
12000, where there would be a bunch of rules with just a goto action
that selects the IS2 policy. You can't have a goto from chains 10000
or 11000 directly into an IS2 chain (either the default policy of 0 or
a custom one).

> But we could make this more flexible to support your use-case better. A
> alternative approach would be to assign exclusive-right-to-action on
> first use. If the user choose to use the VLAN update in a given loopup,
> then it cannot be used in others.
>
> If the user attempt to use a given action across different lookups we
> need to return an error.
>
> Would that work for you? Any downside in such approach?
>
> /Allan
>

No, I definitely wasn't trying to suggest that.
If I understand correctly what you're proposing, then I don't
necessarily have anything against breaking compatibility with the
current single-chain layout. Our users will definitely need an extra
book for filling in TCAM filters (the other one being on how to use tc
in general), but on the other hand, at the end of the day, having
things like the actions rigidly assigned to static id's per chain is
the more sane thing to do given the TCAM design.

My only concern was literally that duplicating filter keys in a bunch
of different chains (all of which eventually land in the same TCAM,
just in different lookups) might result in waste of TCAM space. In
Felix, VCAP IS1 has space for 512 half key entries.
Consider just the trivial example when the user wants to do something like:

tc filter add dev swp0 ingress protocol 802.1Q flower \
        vlan_ethtype ipv4 src_ip 192.168.1.1 \
        action skbedit priority 1 \
        action vlan modify id 101 priority 1
tc filter add dev swp0 ingress protocol 802.1Q flower \
        vlan_ethtype ipv4 src_ip 192.168.1.2 \
        action skbedit priority 2 \
        action vlan modify id 101 priority 2

and 100 more rules like that.
With a forced "1-action-per-chain" split, the rules would have to look
like this:

Chain 10000:
tc filter add dev swp0 ingress protocol 802.1Q flower \
        vlan_ethtype ipv4 src_ip 192.168.1.1 \
        action skbedit priority 1
tc filter add dev swp0 ingress protocol 802.1Q flower \
        vlan_ethtype ipv4 src_ip 192.168.1.2 \
        action skbedit priority 2

Chain 11000:
tc filter add dev swp0 ingress protocol 802.1Q flower \
        vlan_ethtype ipv4 src_ip 192.168.1.1 \
        action vlan modify id 101 priority 1
tc filter add dev swp0 ingress protocol 802.1Q flower \
        vlan_ethtype ipv4 src_ip 192.168.1.2 \
        action vlan modify id 101 priority 2

So I would just like to avoid this latter approach consuming 200
entries. It sounds to me like it would need pretty complicated
bookkeeping in the driver.

Also, another topic: would the lookups in VCAP IS2 be ever exposed to
the user? Looking at the VSC7514 datasheet Table 60 "MASK_MODE and
PORT_MASK Combinations" (for how the action vectors resulted from
different lookups combine into a single result), I think it's
relatively difficult to make sense out of it.

And last question: why the large spacing between chain IDs in your example?

Thanks,
-Vladimir

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index
  2020-06-09 12:55         ` Vladimir Oltean
@ 2020-06-10 18:18           ` Allan W. Nielsen
  2020-07-16  6:49             ` [EXT] " Xiaoliang Yang
  0 siblings, 1 reply; 29+ messages in thread
From: Allan W. Nielsen @ 2020-06-10 18:18 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Xiaoliang Yang, Po Liu, Claudiu Manoil, Alexandru Marginean,
	Vladimir Oltean, Li Yang, Mingkai Hu, Andrew Lunn,
	Florian Fainelli, Vivien Didelot, David S. Miller, Jiri Pirko,
	Ido Schimmel, Jakub Kicinski, Vinicius Costa Gomes,
	Nikolay Aleksandrov, Roopa Prabhu, netdev, lkml, Horatiu Vultur,
	Alexandre Belloni, Joergen Andreasen,
	Microchip Linux Driver Support, linux-devel

On 09.06.2020 15:55, Vladimir Oltean wrote:
>EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>
>Hi Allan,
>
>On Mon, 8 Jun 2020 at 16:56, Allan W. Nielsen
><allan.nielsen@microchip.com> wrote:
>>
>> On 03.06.2020 13:04, Vladimir Oltean wrote:
>> >On Tue, 2 Jun 2020 at 11:38, Allan W. Nielsen
>> ><allan.nielsen@microchip.com> wrote:
>> >>
>> >> Hi Xiaoliang,
>> >>
>> >> Happy to see that you are moving in the directions of multi chain - this
>> >> seems ilke a much better fit to me.
>> >>
>> >>
>> >> On 02.06.2020 13:18, Xiaoliang Yang wrote:
>> >> >There are three hardware TCAMs for ocelot chips: IS1, IS2 and ES0. Each
>> >> >one supports different actions. The hardware flow order is: IS1->IS2->ES0.
>> >> >
>> >> >This patch add three blocks to store rules according to chain index.
>> >> >chain 0 is offloaded to IS1, chain 1 is offloaded to IS2, and egress chain
>> >> >0 is offloaded to ES0.
>> >>
>> >> Using "static" allocation to to say chain-X goes to TCAM Y, also seems
>> >> like the right approach to me. Given the capabilities of the HW, this
>> >> will most likely be the easiest scheme to implement and to explain to
>> >> the end-user.
>> >>
>> >> But I think we should make some adjustments to this mapping schema.
>> >>
>> >> Here are some important "things" I would like to consider when defining
>> >> this schema:
>> >>
>> >> - As you explain, we have 3 TCAMs (IS1, IS2 and ES0), but we have 3
>> >>    parallel lookups in IS1 and 2 parallel lookups in IS2 - and also these
>> >>    TCAMs has a wide verity of keys.
>> >>
>> >> - We can utilize these multiple parallel lookups such that it seems like
>> >>    they are done in serial (that is if they do not touch the same
>> >>    actions), but as they are done in parallel they can not influence each
>> >>    other.
>> >>
>> >> - We can let IS1 influence the IS2 lookup (like the GOTO actions was
>> >>    intended to be used).
>> >>
>> >> - The chip also has other QoS classification facilities which sits
>> >>    before the TCAM (take a look at 3.7.3 QoS, DP, and DSCP Classification
>> >>    in vsc7514 datasheet). It we at some point in time want to enable
>> >>    this, then I think we need to do that in the same tc-flower framework.
>> >>
>> >> Here is my initial suggestion for an alternative chain-schema:
>> >>
>> >> Chain 0:           The default chain - today this is in IS2. If we proceed
>> >>                     with this as is - then this will change.
>> >> Chain 1-9999:      These are offloaded by "basic" classification.
>> >> Chain 10000-19999: These are offloaded in IS1
>> >>                     Chain 10000: Lookup-0 in IS1, and here we could limit the
>> >>                                  action to do QoS related stuff (priority
>> >>                                  update)
>> >>                     Chain 11000: Lookup-1 in IS1, here we could do VLAN
>> >>                                  stuff
>> >>                     Chain 12000: Lookup-2 in IS1, here we could apply the
>> >>                                  "PAG" which is essentially a GOTO.
>> >>
>> >> Chain 20000-29999: These are offloaded in IS2
>> >>                     Chain 20000-20255: Lookup-0 in IS2, where CHAIN-ID -
>> >>                                        20000 is the PAG value.
>> >>                     Chain 21000-21000: Lookup-1 in IS2.
>> >>
>> >> All these chains should be optional - users should only need to
>> >> configure the chains they need. To make this work, we need to configure
>> >> both the desired actions (could be priority update) and the goto action.
>> >> Remember in HW, all packets goes through this process, while in SW they
>> >> only follow the "goto" path.
>> >>
>> >> An example could be (I have not tested this yet - sorry):
>> >>
>> >> tc qdisc add dev eth0 ingress
>> >>
>> >> # Activate lookup 11000. We can not do any other rules in chain 0, also
>> >> # this implicitly means that we do not want any chains <11000.
>> >> tc filter add dev eth0 parent ffff: chain 0
>> >>     action
>> >>     matchall goto 11000
>> >>
>> >> tc filter add dev eth0 parent ffff: chain 11000 \
>> >>     flower src_mac 00:01:00:00:00:00/00:ff:00:00:00:00 \
>> >>     action \
>> >>     vlan modify id 1234 \
>> >>     pipe \
>> >>     goto 20001
>> >>
>> >> tc filter add dev eth0 parent ffff: chain 20001 ...
>> >>
>> >> Maybe it would be an idea to create some use-cases, implement them in a
>> >> test which can pass with today's SW, and then once we have a common
>> >> understanding of what we want, we can implement it?
>> >>
>> >> /Allan
>> >>
>> >> >Using action goto chain to express flow order as follows:
>> >> >        tc filter add dev swp0 chain 0 parent ffff: flower skip_sw \
>> >> >        action goto chain 1
>> >> >
>> >> >Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
>> >> >---
>> >> > drivers/net/ethernet/mscc/ocelot_ace.c    | 51 +++++++++++++++--------
>> >> > drivers/net/ethernet/mscc/ocelot_ace.h    |  7 ++--
>> >> > drivers/net/ethernet/mscc/ocelot_flower.c | 46 +++++++++++++++++---
>> >> > include/soc/mscc/ocelot.h                 |  2 +-
>> >> > include/soc/mscc/ocelot_vcap.h            |  4 +-
>> >> > 5 files changed, 81 insertions(+), 29 deletions(-)
>> >
>> >> /Allan
>> >
>> >What would be the advantage, from a user perspective, in exposing the
>> >3 IS1 lookups as separate chains with orthogonal actions?
>> >If the user wants to add an IS1 action that performs QoS
>> >classification, VLAN classification and selects a custom PAG, they
>> >would have to install 3 separate filters with the same key, each into
>> >its own chain. Then the driver would be smart enough to figure out
>> >that the 3 keys are actually the same, so it could merge them.
>> >In comparison, we could just add a single filter to the IS1 chain,
>> >with 3 actions (skbedit priority, vlan modify, goto is2).
>>
>> Hi, I realize I forgot to answer this one - sorry.
>>
>> The reason for this design is that we have use-cases where the rules to
>> do QoS classification must not impact VLAN classification. The easiest
>> way to do that, it to have it in separated lookups.
>>
>
>Impact in the sense that an IS1 rule for VLAN classification might
>'steal' packets from an IS1 rule for QoS classification (since the
>TCAM stops after the first matching entry in each lookup)?
>Such as:
>
>tc filter add dev swp0 ingress protocol 802.1Q flower vlan_ethtype
>ipv4 action skbedit priority 3
>tc filter add dev swp0 ingress protocol 802.1Q flower vlan_id 0
>vlan_prio 2 action vlan modify id 12 priority 1
Yes, this is a good example

>The trouble with this TCAM seems to be that it doesn't support the
>'pipe' control, so rules on overlapping keys will have unpredictable
>results.
I think we may have a mis-understanding in what the pipe action does.

It does not continue evaluting rules in the chain - it only continue
evaluating the list of actions assiciated to the matched rule.

At least, this is my understanding and it seems to align with the
experiments I have done.

>So if we had these 2 rules in the same lookup in hardware,
>then an IPv4 packet tagged with VID 0 and PCP 2 would get classified
>to QoS class 3 but would not get retagged to VID 12 PCP 1, right?
Yes. And you will get the same in "pure" SW.

>So we should error out if the rule's control is 'pipe' (I haven't
>checked if we can do that, I hope we can), and basically only 'goto'
>something.
No - I think this is the "pipe" misunderstanding from above.

But we cannot support "reclassify", "continue" and "pass". We should
error out on that.

>Which brings the discussion to "goto where?".
>From the IS1 chain for QoS classification, you could goto the IS1
>chain for VLAN classification, ok, that's your example. Is this goto
>optional? (i.e. can you goto a PAG in IS2 directly, and in that case
>would VLAN classification be skipped in hardware for the packets that
>skip it in software?)
You are right, these GOTOs are not really optional, and not as flexible
as the SW implementation.

The HW take the same path every time. But if we do not put any rules in
IS1-lookup2, then it is the same as if IS1-lookup2 is skipped.

This mean:
   If we want to use IS1, lookup 0, 1 and 2
    - then we need a match-all in chain 0 to goto 10000
    - then all rules in IS1/0 (10000) must goto IS1/1 (11000).
    - then all rules in IS1/1 (11000) must goto IS1/2 (12000).
   If we want to use IS1, lookup 0, 1
    - then we need a match-all in chain 0 to goto 10000
    - then all rules in IS1/0 (10000) must goto IS1/1 (11000).
   If we want to use IS1, lookup 0
    - then we need a match-all in chain 0 to goto 10000

I skiped the "goto" IS2 on purpose - we will get to it with your next
question.

>Your suggestion of having an entire chain for PAG selection suggests
>to me that the rules in chain 10000 (IS1 for QoS classification) would
>need to have a non-optional goto to chain 11000 (IS1 for VLAN
>classification), which in turn would have a non-optional goto to chain
>12000, where there would be a bunch of rules with just a goto action
>that selects the IS2 policy. You can't have a goto from chains 10000
>or 11000 directly into an IS2 chain (either the default policy of 0 or
>a custom one).

I suggest a dedicated lookup for PAG because in the TCAM/HW
implementation this is an action, and we need the 3 parallel lookups not
to use the same actions.

This also means that this needs to be the last-is1-look chain, which can
goto IS2 (with a dedicated PAG).


>> But we could make this more flexible to support your use-case better. A
>> alternative approach would be to assign exclusive-right-to-action on
>> first use. If the user choose to use the VLAN update in a given loopup,
>> then it cannot be used in others.
>>
>> If the user attempt to use a given action across different lookups we
>> need to return an error.
>>
>> Would that work for you? Any downside in such approach?
>
>No, I definitely wasn't trying to suggest that.
But we may want to consider that, as it would be more flexible.

>If I understand correctly what you're proposing, then I don't
>necessarily have anything against breaking compatibility with the
>current single-chain layout. Our users will definitely need an extra
>book for filling in TCAM filters (the other one being on how to use tc
>in general), but on the other hand, at the end of the day, having
>things like the actions rigidly assigned to static id's per chain is
>the more sane thing to do given the TCAM design.
I agree. Documenting this to an extend that is actually understandable
is a challenge.

>My only concern was literally that duplicating filter keys in a bunch
>of different chains (all of which eventually land in the same TCAM,
>just in different lookups) might result in waste of TCAM space. In
>Felix, VCAP IS1 has space for 512 half key entries.
>Consider just the trivial example when the user wants to do something like:
>
>tc filter add dev swp0 ingress protocol 802.1Q flower \
>        vlan_ethtype ipv4 src_ip 192.168.1.1 \
>        action skbedit priority 1 \
>        action vlan modify id 101 priority 1
>tc filter add dev swp0 ingress protocol 802.1Q flower \
>        vlan_ethtype ipv4 src_ip 192.168.1.2 \
>        action skbedit priority 2 \
>        action vlan modify id 101 priority 2
>
>and 100 more rules like that.
>With a forced "1-action-per-chain" split, the rules would have to look
>like this:
>
>Chain 10000:
>tc filter add dev swp0 ingress protocol 802.1Q flower \
>        vlan_ethtype ipv4 src_ip 192.168.1.1 \
>        action skbedit priority 1
>tc filter add dev swp0 ingress protocol 802.1Q flower \
>        vlan_ethtype ipv4 src_ip 192.168.1.2 \
>        action skbedit priority 2
>
>Chain 11000:
>tc filter add dev swp0 ingress protocol 802.1Q flower \
>        vlan_ethtype ipv4 src_ip 192.168.1.1 \
>        action vlan modify id 101 priority 1
>tc filter add dev swp0 ingress protocol 802.1Q flower \
>        vlan_ethtype ipv4 src_ip 192.168.1.2 \
>        action vlan modify id 101 priority 2
>
>So I would just like to avoid this latter approach consuming 200
>entries. It sounds to me like it would need pretty complicated
>bookkeeping in the driver.
Yes, I think it is a valid twist which we should address. I see no
problem in "dynamic" assign what chain own what action.

>Also, another topic: would the lookups in VCAP IS2 be ever exposed to
>the user? Looking at the VSC7514 datasheet Table 60 "MASK_MODE and
>PORT_MASK Combinations" (for how the action vectors resulted from
>different lookups combine into a single result), I think it's
>relatively difficult to make sense out of it.
It is not too easy to understand - but this is basically just the
"hooks" to assign actions to a give lookup.

>And last question: why the large spacing between chain IDs in your example?
It is an attempt to make the validation and documentation easier.

TCAM (1, 2)
|Lookup number (0, 1, 2)
|| PAG ID
|| |
vv/-\
20123

The following chains will be valid: 0, 10000, 11000, 12000, 20000-20255,
21000.

- Rules in chain 10000 must point to a higher number, but can not "skip
   any numbers"
- Rules in chain 11000 must point to a higher number, but can not "skip
   any numbers"
- Rules in chain 12000 must point to a higher number, but can not "skip
   any numbers"
- Rules in chain 20000-20255 must point to none, or 21000
- Rules in 21000 can not have any goto.

The user decide how many chains to use.

Example could be only to use 12000, 20010, 20020.

Maybe there is a better way - I'm open for other suggestions.

But be aware, this is still not fully thought through. Before
implementing I will need to understand how the templates and the shared
blocks works as well.

/Allan


^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [EXT] Re: [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index
  2020-06-10 18:18           ` Allan W. Nielsen
@ 2020-07-16  6:49             ` Xiaoliang Yang
  2020-07-16  8:50               ` Joergen Andreasen
  0 siblings, 1 reply; 29+ messages in thread
From: Xiaoliang Yang @ 2020-07-16  6:49 UTC (permalink / raw)
  To: Allan W. Nielsen, Vladimir Oltean
  Cc: Po Liu, Claudiu Manoil, Alexandru Marginean, Vladimir Oltean,
	Leo Li, Mingkai Hu, Andrew Lunn, Florian Fainelli,
	Vivien Didelot, David S. Miller, Jiri Pirko, Ido Schimmel,
	Jakub Kicinski, Vinicius Costa Gomes, Nikolay Aleksandrov,
	Roopa Prabhu, netdev, lkml, Horatiu Vultur, Alexandre Belloni,
	Joergen Andreasen, Microchip Linux Driver Support, linux-devel

Hi Allan,

On 11.06.2002 2:18, Allan W. Nielsen <allan.nielsen@microchip.com> wrote:
>> >> Here is my initial suggestion for an alternative chain-schema:
>> >>
>> >> Chain 0:           The default chain - today this is in IS2. If we proceed
>> >>                     with this as is - then this will change.
>> >> Chain 1-9999:      These are offloaded by "basic" classification.
>> >> Chain 10000-19999: These are offloaded in IS1
>> >>                     Chain 10000: Lookup-0 in IS1, and here we could limit the
>> >>                                  action to do QoS related stuff (priority
>> >>                                  update)
>> >>                     Chain 11000: Lookup-1 in IS1, here we could do VLAN
>> >>                                  stuff
>> >>                     Chain 12000: Lookup-2 in IS1, here we could apply the
>> >>                                  "PAG" which is essentially a GOTO.
>> >>
>> >> Chain 20000-29999: These are offloaded in IS2
>> >>                     Chain 20000-20255: Lookup-0 in IS2, where CHAIN-ID -
>> >>                                        20000 is the PAG value.
>> >>                     Chain 21000-21000: Lookup-1 in IS2.
>> >>
>> >> All these chains should be optional - users should only need to 
>> >> configure the chains they need. To make this work, we need to 
>> >> configure both the desired actions (could be priority update) and the goto action.
>> >> Remember in HW, all packets goes through this process, while in SW 
>> >> they only follow the "goto" path.
>> >>

I agree with this chain assignment, following is an example to set rules:

1. Set a matchall rule for each chain, the last chain do not need goto chain action.
# tc filter add dev swp0 chain 0 flower skip_sw action goto chain 10000
# tc filter add dev swp0 chain 10000 flower skip_sw action goto chain 21000
In driver, use these rules to register the chain.

2. Set normal rules.
# tc filter add dev swp0 chain 10000 protocol 802.1Q parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action skbedit priority 1 action goto chain 21000
# tc filter add dev swp0 chain 21000 protocol 802.1Q parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action drop

In driver, we check if the chain ID has been registered, and goto chain is the same as first matchall rule, if is not, then return error. Each rule need has goto action except last chain.

I also have check about chain template, it can not set an action template for each chain, so I think it's no use for our case. If this way to set rules is OK, I will update the patch to do as this.

Thanks,
Xiaoliang Yang


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [EXT] Re: [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index
  2020-07-16  6:49             ` [EXT] " Xiaoliang Yang
@ 2020-07-16  8:50               ` Joergen Andreasen
  2020-07-16 10:37                 ` Xiaoliang Yang
  0 siblings, 1 reply; 29+ messages in thread
From: Joergen Andreasen @ 2020-07-16  8:50 UTC (permalink / raw)
  To: Xiaoliang Yang
  Cc: Allan W. Nielsen, Vladimir Oltean, Po Liu, Claudiu Manoil,
	Alexandru Marginean, Vladimir Oltean, Leo Li, Mingkai Hu,
	Andrew Lunn, Florian Fainelli, Vivien Didelot, David S. Miller,
	Jiri Pirko, Ido Schimmel, Jakub Kicinski, Vinicius Costa Gomes,
	Nikolay Aleksandrov, Roopa Prabhu, netdev, lkml, Horatiu Vultur,
	Alexandre Belloni, Microchip Linux Driver Support, linux-devel

Hi Xiaoliang,

The 07/16/2020 06:49, Xiaoliang Yang wrote:
> Hi Allan,
> 
> On 11.06.2002 2:18, Allan W. Nielsen <allan.nielsen@microchip.com> wrote:
> >> >> Here is my initial suggestion for an alternative chain-schema:
> >> >>
> >> >> Chain 0:           The default chain - today this is in IS2. If we proceed
> >> >>                     with this as is - then this will change.
> >> >> Chain 1-9999:      These are offloaded by "basic" classification.
> >> >> Chain 10000-19999: These are offloaded in IS1
> >> >>                     Chain 10000: Lookup-0 in IS1, and here we could limit the
> >> >>                                  action to do QoS related stuff (priority
> >> >>                                  update)
> >> >>                     Chain 11000: Lookup-1 in IS1, here we could do VLAN
> >> >>                                  stuff
> >> >>                     Chain 12000: Lookup-2 in IS1, here we could apply the
> >> >>                                  "PAG" which is essentially a GOTO.
> >> >>
> >> >> Chain 20000-29999: These are offloaded in IS2
> >> >>                     Chain 20000-20255: Lookup-0 in IS2, where CHAIN-ID -
> >> >>                                        20000 is the PAG value.
> >> >>                     Chain 21000-21000: Lookup-1 in IS2.
> >> >>
> >> >> All these chains should be optional - users should only need to
> >> >> configure the chains they need. To make this work, we need to
> >> >> configure both the desired actions (could be priority update) and the goto action.
> >> >> Remember in HW, all packets goes through this process, while in SW
> >> >> they only follow the "goto" path.
> >> >>
> 
> I agree with this chain assignment, following is an example to set rules:
> 
> 1. Set a matchall rule for each chain, the last chain do not need goto chain action.
> # tc filter add dev swp0 chain 0 flower skip_sw action goto chain 10000
> # tc filter add dev swp0 chain 10000 flower skip_sw action goto chain 21000
> In driver, use these rules to register the chain.
> 
> 2. Set normal rules.
> # tc filter add dev swp0 chain 10000 protocol 802.1Q parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action skbedit priority 1 action goto chain 21000
> # tc filter add dev swp0 chain 21000 protocol 802.1Q parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action drop
> 
> In driver, we check if the chain ID has been registered, and goto chain is the same as first matchall rule, if is not, then return error. Each rule need has goto action except last chain.
> 
> I also have check about chain template, it can not set an action template for each chain, so I think it's no use for our case. If this way to set rules is OK, I will update the patch to do as this.
> 
> Thanks,
> Xiaoliang Yang
> 

I agree that you cannot set an action template for each chain but you can set a match template which for example can be used for setting up which IS1 key to generate for the device/port.
The template ensures that you cannot add an illegal match.
I have attached a snippet from a testcase I wrote in order to test these ideas.
Note that not all actions are valid for the hardware.

SMAC       = "00:00:00:11:11:11"
DMAC       = "00:00:00:dd:dd:dd"
VID1       = 0x10
VID2       = 0x20
PCP1       = 3
PCP2       = 5
DEI        = 1
SIP        = "10.10.0.1"
DIP        = "10.10.0.2"

IS1_L0     = 10000 # IS1 lookup 0
IS1_L1     = 11000 # IS1 lookup 1
IS1_L2     = 12000 # IS1 lookup 2

IS2_L0     = 20000 # IS2 lookup 0 # IS2 20000 - 20255 -> pag 0-255
IS2_L0_P1  = 20001 # IS2 lookup 0 pag 1
IS2_L0_P2  = 20002 # IS2 lookup 0 pag 2

IS2_L1     = 21000 # IS2 lookup 1

$skip = "skip_hw" # or "skip_sw"

test "Chain templates and goto" do
    t_i "'prio #' sets the sequence of filters. Lowest number = highest priority = checked first. 0..0xffff"
    t_i "'handle #' is a reference to the filter. Use this is if you need to reference the filter later. 0..0xffffffff"
    t_i "'chain #' is the chain to use. Chain 0 is the default. Different chains can have different templates. 0..0xffffffff"
    $ts.dut.run "tc qdisc add dev #{$dp[0]} clsact"

    t_i "Add templates"
    t_i "Configure the VCAP port configuration to match the shortest key that fulfill the purpose"

    t_i "Create a template that sets IS1 lookup 0 to generate S1_NORMAL with S1_DMAC_DIP_ENA"
    t_i "If you match on both src and dst you will generate S1_7TUPLE"
    $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol ip chain #{IS1_L0} flower #{$skip} "\
                "dst_mac 00:00:00:00:00:00 "\
                "dst_ip 0.0.0.0 "

    t_i "Create a template that sets IS1 lookup 1 to generate S1_5TUPLE_IP4"
    $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol ip chain #{IS1_L1} flower #{$skip} "\
                "src_ip 0.0.0.0 "\
                "dst_ip 0.0.0.0 "

    t_i "Create a template that sets IS1 lookup 2 to generate S1_DBL_VID"
    $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol 802.1ad chain #{IS1_L2} flower #{$skip} "\
                "vlan_id 0 "\
                "vlan_prio 0 "\
                "vlan_ethtype 802.1q "\
                "cvlan_id 0 "\
                "cvlan_prio 0 "

    $ts.dut.run "tc chain show dev #{$dp[0]} ingress"

    t_i "Start the chaining party. We can have other matchall rules here but the last one must goto IS1"
    $ts.dut.run "tc filter add dev #{$dp[0]} ingress protocol all prio 0xffff handle 0x1 matchall #{$skip} "\
                "action goto chain #{IS1_L0} "
    
    t_i "Insert catch all last in chain IS1_L0. Note: Protocol == all and prio = max"
    t_i "flower must be used here in order to satisfy the template although it is used as a 'matchall' filter."
    t_i "Driver must enforce that every filter in chain IS1_L0 ends with a goto chain IS1_L1"
    $ts.dut.run "tc filter add dev #{$dp[0]} ingress protocol all prio 0xffff handle 0x199 chain #{IS1_L0} flower #{$skip} "\
                "action mirred egress mirror dev #{$dp[2]} "\
                "action goto chain #{IS1_L1} "

    t_i "Insert catch all last in chain IS1_L1. Note: Protocol == all and prio = max"
    t_i "flower must be used here in order to satisfy the template although it is used as a 'matchall' filter."
    t_i "Driver must enforce that every filter in chain IS1_L1 ends with a goto chain IS1_L2"
    $ts.dut.run "tc filter add dev #{$dp[0]} ingress protocol all prio 0xffff handle 0x299 chain #{IS1_L1} flower #{$skip} "\
                "action goto chain #{IS1_L2} "

    t_i "Insert catch all last in chain IS1_L2. Note: Protocol == all and prio = max"
    t_i "flower must be used here in order to satisfy the template although it is used as a 'matchall' filter."
    t_i "Driver must enforce that every filter in chain IS1_L2 ends with a goto chain IS2_L0 + PAG value 0..255"
    $ts.dut.run "tc filter add dev #{$dp[0]} ingress protocol all prio 0xffff handle 0x399 chain #{IS1_L2} flower #{$skip} "\
                "action continue " # goto IS2!

    t_i "Insert in chain IS1_L0"
    $ts.dut.run "tc filter add dev #{$dp[0]} ingress protocol ip prio 10 handle 0x100 chain #{IS1_L0} flower #{$skip} "\
                "dst_mac #{DMAC} "\
                "dst_ip #{DIP} "\
                "action goto chain #{IS1_L1} "

    t_i "Insert in chain IS1_L1"
    $ts.dut.run "tc filter add dev #{$dp[0]} ingress protocol ip prio 11 handle 0x200 chain #{IS1_L1} flower #{$skip} "\
                "src_ip #{SIP} "\
                "dst_ip #{DIP} "\
                "action goto chain #{IS1_L2} "

    t_i "Insert in chain IS1_L1"
    $ts.dut.run "tc filter add dev #{$dp[0]} ingress protocol ip prio 12 handle 0x201 chain #{IS1_L1} flower #{$skip} "\
                "dst_ip #{DIP} "\
                "action goto chain #{IS1_L2} "

    t_i "Insert in chain IS1_L2"
    $ts.dut.run "tc filter add dev #{$dp[0]} ingress protocol 802.1ad prio 11 handle 0x300 chain #{IS1_L2} flower #{$skip} "\
                "vlan_id 10 "\
                "vlan_prio 1 "\
                "vlan_ethtype 802.1q "\
                "cvlan_id 20 "\
                "cvlan_prio 2 "\
                "action pass " # TODO: goto IS2!

    # TODO: Add IS2

    t_i "Test invalid inserts that must fail"
    $ts.dut.run_err "tc filter add dev #{$dp[0]} ingress protocol ip chain #{IS1_L0} flower #{$skip} "\
                    "src_ip 10.10.0.0/16 "\
                    "action drop"

    $ts.dut.run_err "tc filter add dev #{$dp[0]} ingress protocol ip chain #{IS1_L1} flower #{$skip} "\
                    "dst_mac aa:11:22:33:44:55/00:00:ff:00:00:00 "\
                    "action drop"

    $ts.dut.run_err "tc filter add dev #{$dp[0]} ingress protocol ip chain #{IS1_L2} flower #{$skip} "\
                    "ip_proto udp "\
                    "action drop"
end
                                                                                        

-- 
Joergen Andreasen, Microchip

^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [EXT] Re: [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index
  2020-07-16  8:50               ` Joergen Andreasen
@ 2020-07-16 10:37                 ` Xiaoliang Yang
  2020-07-16 14:45                   ` Vladimir Oltean
  0 siblings, 1 reply; 29+ messages in thread
From: Xiaoliang Yang @ 2020-07-16 10:37 UTC (permalink / raw)
  To: Joergen Andreasen
  Cc: Allan W. Nielsen, Vladimir Oltean, Po Liu, Claudiu Manoil,
	Alexandru Marginean, Vladimir Oltean, Leo Li, Mingkai Hu,
	Andrew Lunn, Florian Fainelli, Vivien Didelot, David S. Miller,
	Jiri Pirko, Ido Schimmel, Jakub Kicinski, Vinicius Costa Gomes,
	Nikolay Aleksandrov, Roopa Prabhu, netdev, lkml, Horatiu Vultur,
	Alexandre Belloni, Microchip Linux Driver Support, linux-devel

Hi Joergen,


-----Original Message-----
From: Joergen Andreasen <joergen.andreasen@microchip.com> 
Sent: 2020年7月16日 16:51

> >> >> Chain 0:           The default chain - today this is in IS2. If we proceed
> >> >>                     with this as is - then this will change.
> >> >> Chain 1-9999:      These are offloaded by "basic" classification.
> >> >> Chain 10000-19999: These are offloaded in IS1
> >> >>                     Chain 10000: Lookup-0 in IS1, and here we could limit the
> >> >>                                  action to do QoS related stuff (priority
> >> >>                                  update)
> >> >>                     Chain 11000: Lookup-1 in IS1, here we could do VLAN
> >> >>                                  stuff
> >> >>                     Chain 12000: Lookup-2 in IS1, here we could apply the
> >> >>                                  "PAG" which is essentially a GOTO.
> >> >>
> >> >> Chain 20000-29999: These are offloaded in IS2
> >> >>                     Chain 20000-20255: Lookup-0 in IS2, where CHAIN-ID -
> >> >>                                        20000 is the PAG value.
> >> >>                     Chain 21000-21000: Lookup-1 in IS2.
> >> >>
> >> >> All these chains should be optional - users should only need to 
> >> >> configure the chains they need. To make this work, we need to 
> >> >> configure both the desired actions (could be priority update) and the goto action.
> >> >> Remember in HW, all packets goes through this process, while in 
> >> >> SW they only follow the "goto" path.
> >> >>
>>
>> I agree with this chain assignment, following is an example to set rules:
>>
>> 1. Set a matchall rule for each chain, the last chain do not need goto chain action.
>> # tc filter add dev swp0 chain 0 flower skip_sw action goto chain 
>> 10000 # tc filter add dev swp0 chain 10000 flower skip_sw action goto 
>> chain 21000 In driver, use these rules to register the chain.
>>
>> 2. Set normal rules.
>> # tc filter add dev swp0 chain 10000 protocol 802.1Q parent ffff: 
>> flower skip_sw vlan_id 1 vlan_prio 1 action skbedit priority 1 action 
>> goto chain 21000 # tc filter add dev swp0 chain 21000 protocol 802.1Q 
>> parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action drop
>>
>> In driver, we check if the chain ID has been registered, and goto chain is the same as first matchall rule, if is not, then return error. Each rule need has goto action except last chain.
>>
>> I also have check about chain template, it can not set an action template for each chain, so I think it's no use for our case. If this way to set rules is OK, I will update the patch to do as this.
>>
>> Thanks,
>> Xiaoliang Yang
>

> I agree that you cannot set an action template for each chain but you can set a match template which for example can be used for setting up which IS1 key to generate for the device/port.
> The template ensures that you cannot add an illegal match.
> I have attached a snippet from a testcase I wrote in order to test these ideas.
> Note that not all actions are valid for the hardware.
>
> SMAC       = "00:00:00:11:11:11"
> DMAC       = "00:00:00:dd:dd:dd"
> VID1       = 0x10
> VID2       = 0x20
> PCP1       = 3
> PCP2       = 5
> DEI        = 1
> SIP        = "10.10.0.1"
> DIP        = "10.10.0.2"
>
> IS1_L0     = 10000 # IS1 lookup 0
> IS1_L1     = 11000 # IS1 lookup 1
> IS1_L2     = 12000 # IS1 lookup 2
>
> IS2_L0     = 20000 # IS2 lookup 0 # IS2 20000 - 20255 -> pag 0-255
> IS2_L0_P1  = 20001 # IS2 lookup 0 pag 1
> IS2_L0_P2  = 20002 # IS2 lookup 0 pag 2
>
> IS2_L1     = 21000 # IS2 lookup 1
>
> $skip = "skip_hw" # or "skip_sw"
>
> test "Chain templates and goto" do
>     t_i "'prio #' sets the sequence of filters. Lowest number = highest priority = checked first. 0..0xffff"
>     t_i "'handle #' is a reference to the filter. Use this is if you need to reference the filter later. 0..0xffffffff"
>     t_i "'chain #' is the chain to use. Chain 0 is the default. Different chains can have different templates. 0..0xffffffff"
>     $ts.dut.run "tc qdisc add dev #{$dp[0]} clsact"
>
>     t_i "Add templates"
>     t_i "Configure the VCAP port configuration to match the shortest key that fulfill the purpose"

>     t_i "Create a template that sets IS1 lookup 0 to generate S1_NORMAL with S1_DMAC_DIP_ENA"
>     t_i "If you match on both src and dst you will generate S1_7TUPLE"
>     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol ip chain #{IS1_L0} flower #{$skip} "\
>                 "dst_mac 00:00:00:00:00:00 "\
>                 "dst_ip 0.0.0.0 "
>
>     t_i "Create a template that sets IS1 lookup 1 to generate S1_5TUPLE_IP4"
>     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol ip chain #{IS1_L1} flower #{$skip} "\
>                 "src_ip 0.0.0.0 "\
>                 "dst_ip 0.0.0.0 "
>
>     t_i "Create a template that sets IS1 lookup 2 to generate S1_DBL_VID"
>     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol 802.1ad chain #{IS1_L2} flower #{$skip} "\
>                 "vlan_id 0 "\
>                 "vlan_prio 0 "\
>                 "vlan_ethtype 802.1q "\
>                 "cvlan_id 0 "\
>                 "cvlan_prio 0 "
>
>     $ts.dut.run "tc chain show dev #{$dp[0]} ingress"

Why you set different filter keys on different lookup? Each lookup only filter one type of keys?
If I want to filter a same key like dst_mac and do both QoS classified action and vlan modify action, how to implement this in the same chain #{IS1_L0} ?

I think it's more reasonable to distinguish different lookup by different action like this:
IS1_L0     = 10000 # IS1 lookup 0	# do QoS classified action
IS1_L1     = 11000 # IS1 lookup 1	# do vlan modify action
IS1_L2     = 12000 # IS1 lookup 2	# do goto PAG action

IS2_L0     = 20000 # IS2 lookup 0 # IS2 20000 - 20255 -> pag 0-255
IS2_L1 	  = 21000 # IS2 lookup 1

So it’s no need to add templates, each lookup can support filtering mac, IP or vlan tag, but only support one action.

Thanks,
Xiaoliang

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [EXT] Re: [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index
  2020-07-16 10:37                 ` Xiaoliang Yang
@ 2020-07-16 14:45                   ` Vladimir Oltean
  2020-07-17  7:34                     ` Joergen Andreasen
  0 siblings, 1 reply; 29+ messages in thread
From: Vladimir Oltean @ 2020-07-16 14:45 UTC (permalink / raw)
  To: Xiaoliang Yang
  Cc: Joergen Andreasen, Allan W. Nielsen, Po Liu, Claudiu Manoil,
	Alexandru Marginean, Vladimir Oltean, Leo Li, Mingkai Hu,
	Andrew Lunn, Florian Fainelli, Vivien Didelot, David S. Miller,
	Jiri Pirko, Ido Schimmel, Jakub Kicinski, Vinicius Costa Gomes,
	Nikolay Aleksandrov, Roopa Prabhu, netdev, lkml, Horatiu Vultur,
	Alexandre Belloni, Microchip Linux Driver Support, linux-devel

On Thu, Jul 16, 2020 at 10:37:40AM +0000, Xiaoliang Yang wrote:
> Hi Joergen,
> 
> 
> -----Original Message-----
> From: Joergen Andreasen <joergen.andreasen@microchip.com> 
> Sent: 2020年7月16日 16:51
> 
> > >> >> Chain 0:           The default chain - today this is in IS2. If we proceed
> > >> >>                     with this as is - then this will change.
> > >> >> Chain 1-9999:      These are offloaded by "basic" classification.
> > >> >> Chain 10000-19999: These are offloaded in IS1
> > >> >>                     Chain 10000: Lookup-0 in IS1, and here we could limit the
> > >> >>                                  action to do QoS related stuff (priority
> > >> >>                                  update)
> > >> >>                     Chain 11000: Lookup-1 in IS1, here we could do VLAN
> > >> >>                                  stuff
> > >> >>                     Chain 12000: Lookup-2 in IS1, here we could apply the
> > >> >>                                  "PAG" which is essentially a GOTO.
> > >> >>
> > >> >> Chain 20000-29999: These are offloaded in IS2
> > >> >>                     Chain 20000-20255: Lookup-0 in IS2, where CHAIN-ID -
> > >> >>                                        20000 is the PAG value.
> > >> >>                     Chain 21000-21000: Lookup-1 in IS2.
> > >> >>
> > >> >> All these chains should be optional - users should only need to 
> > >> >> configure the chains they need. To make this work, we need to 
> > >> >> configure both the desired actions (could be priority update) and the goto action.
> > >> >> Remember in HW, all packets goes through this process, while in 
> > >> >> SW they only follow the "goto" path.
> > >> >>
> >>
> >> I agree with this chain assignment, following is an example to set rules:
> >>
> >> 1. Set a matchall rule for each chain, the last chain do not need goto chain action.
> >> # tc filter add dev swp0 chain 0 flower skip_sw action goto chain 10000
> >> # tc filter add dev swp0 chain 10000 flower skip_sw action goto chain 21000
> >> In driver, use these rules to register the chain.
> >>
> >> 2. Set normal rules.
> >> # tc filter add dev swp0 chain 10000 protocol 802.1Q parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action skbedit priority 1 action goto chain 21000
> >> # tc filter add dev swp0 chain 21000 protocol 802.1Q parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action drop
> >>
> >> In driver, we check if the chain ID has been registered, and goto
> >> chain is the same as first matchall rule, if is not, then return
> >> error. Each rule need has goto action except last chain.
> >>
> >> I also have check about chain template, it can not set an action
> >> template for each chain, so I think it's no use for our case. If
> >> this way to set rules is OK, I will update the patch to do as this.
> >>
> >> Thanks,
> >> Xiaoliang Yang
> >
> 
> > I agree that you cannot set an action template for each chain but
> > you can set a match template which for example can be used for
> > setting up which IS1 key to generate for the device/port.
> > The template ensures that you cannot add an illegal match.
> > I have attached a snippet from a testcase I wrote in order to test these ideas.
> > Note that not all actions are valid for the hardware.
> >
> > SMAC       = "00:00:00:11:11:11"
> > DMAC       = "00:00:00:dd:dd:dd"
> > VID1       = 0x10
> > VID2       = 0x20
> > PCP1       = 3
> > PCP2       = 5
> > DEI        = 1
> > SIP        = "10.10.0.1"
> > DIP        = "10.10.0.2"
> >
> > IS1_L0     = 10000 # IS1 lookup 0
> > IS1_L1     = 11000 # IS1 lookup 1
> > IS1_L2     = 12000 # IS1 lookup 2
> >
> > IS2_L0     = 20000 # IS2 lookup 0 # IS2 20000 - 20255 -> pag 0-255
> > IS2_L0_P1  = 20001 # IS2 lookup 0 pag 1
> > IS2_L0_P2  = 20002 # IS2 lookup 0 pag 2
> >
> > IS2_L1     = 21000 # IS2 lookup 1
> >
> > $skip = "skip_hw" # or "skip_sw"
> >
> > test "Chain templates and goto" do
> >     t_i "'prio #' sets the sequence of filters. Lowest number = highest priority = checked first. 0..0xffff"
> >     t_i "'handle #' is a reference to the filter. Use this is if you need to reference the filter later. 0..0xffffffff"
> >     t_i "'chain #' is the chain to use. Chain 0 is the default. Different chains can have different templates. 0..0xffffffff"
> >     $ts.dut.run "tc qdisc add dev #{$dp[0]} clsact"
> >
> >     t_i "Add templates"
> >     t_i "Configure the VCAP port configuration to match the shortest key that fulfill the purpose"
> 
> >     t_i "Create a template that sets IS1 lookup 0 to generate S1_NORMAL with S1_DMAC_DIP_ENA"
> >     t_i "If you match on both src and dst you will generate S1_7TUPLE"
> >     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol ip chain #{IS1_L0} flower #{$skip} "\
> >                 "dst_mac 00:00:00:00:00:00 "\
> >                 "dst_ip 0.0.0.0 "
> >
> >     t_i "Create a template that sets IS1 lookup 1 to generate S1_5TUPLE_IP4"
> >     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol ip chain #{IS1_L1} flower #{$skip} "\
> >                 "src_ip 0.0.0.0 "\
> >                 "dst_ip 0.0.0.0 "
> >
> >     t_i "Create a template that sets IS1 lookup 2 to generate S1_DBL_VID"
> >     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol 802.1ad chain #{IS1_L2} flower #{$skip} "\
> >                 "vlan_id 0 "\
> >                 "vlan_prio 0 "\
> >                 "vlan_ethtype 802.1q "\
> >                 "cvlan_id 0 "\
> >                 "cvlan_prio 0 "
> >
> >     $ts.dut.run "tc chain show dev #{$dp[0]} ingress"
> 
> Why you set different filter keys on different lookup? Each lookup
> only filter one type of keys?
> If I want to filter a same key like dst_mac and do both QoS classified
> action and vlan modify action, how to implement this in the same chain
> #{IS1_L0} ?
> 
> I think it's more reasonable to distinguish different lookup by different action like this:
> IS1_L0     = 10000 # IS1 lookup 0	# do QoS classified action
> IS1_L1     = 11000 # IS1 lookup 1	# do vlan modify action
> IS1_L2     = 12000 # IS1 lookup 2	# do goto PAG action
> 
> IS2_L0     = 20000 # IS2 lookup 0 # IS2 20000 - 20255 -> pag 0-255
> IS2_L1 	  = 21000 # IS2 lookup 1
> 
> So it’s no need to add templates, each lookup can support filtering
> mac, IP or vlan tag, but only support one action.
> 
> Thanks,
> Xiaoliang

As far as I understand, he's still using the static chain numbers
exactly for that, even though he didn't explicitly mention the action
for each individual IS1 lookup.

The reason why he's also adding templates on each individual chain is to
be able to configure VCAP_S1_KEY_CFG and VCAP_S2_CFG. The configuration
of key type is per lookup.

Honestly, Joergen, I would take dynamic key configuration per lookup as
a separate item. Xiaoliang's patch series for IS1 support is pretty
large already.

Right now we have:

- In mainline:

S2_IP6_CFG
S2_IP6_CFG controls the key generation for IPv6 frames. Bits 1:0
control the first lookup and bits 3:2 control the second lookup.
0: IPv6 frames are matched against IP6_TCP_UDP or IP6_OTHER entries
1: IPv6 frames are matched against IP6_STD entries
2: IPv6 frames are matched against IP4_TCP_UDP or IP4_OTHER entries
3: IPv6 frames are matched against MAC_ETYPE entries

We set this field to 0xa (0b1010, aka 2 for both lookups: IP4_TCP_UDP).
Although we don't really parse IPv6 keys coming from tc.

Also there are these fields which we're managing dynamically through
ocelot_match_all_as_mac_etype, depending on whether there is any
MAC_ETYPE key added by the user:
S2_SNAP_DIS
S2_ARP_DIS
S2_IP_TCPUDP_DIS
S2_IP_OTHER_DIS

- In Xiaoliang's patchset:

S1_KEY_IP6_CFG
Selects key per lookup in S1 for IPv6 frames.
0: Use key S1_NORMAL
1: Use key S1_7TUPLE
2: Use key S1_5TUPLE_IP4
3: Use key S1_NORMAL_IP6
4: Use key S1_5TUPLE_IP6
5: Use key S1_DBL_VID

We set this to 2.

S1_KEY_IP4_CFG
Selects key per lookup in S1 for IPv4 frames.
0: Use key S1_NORMAL
1: Use key S1_7TUPLE
2: Use key S1_5TUPLE_IP4
3: Use key S1_DBL_VID

We set this to 2.

Your input on which tc chain template could be used for each key type is
valuable, we should create a table with all the options and associated
key sizes (and therefore, number of available filters) and post it
somewhere. I'm not completely sure that chains will be enough to
describe every key type, at least not intuitively, For example if I just
want to match on EtherType (protocol), I'll need an ETYPE (IS1) or
MAC_ETYPE (IS2) rule, but the template for that will need to be
formulated in terms of dst_mac because I don't think there's a way to
use only the protocol in a template.

But I expect we keep using some default values (perhaps even the current
ones, or deduce a valid key type from the first added rule, which is
exactly what ocelot_match_all_as_mac_etype tries to do now) and don't
expect the user to open the datasheet unless some advanced configuration
is required. Otherwise I'm not sure who is going to use this. If the
user sees a template shell script with the chains already set up,
chances are it won't be too hard to add the right actions to the right
chains. But if that is going to involve fiddling with templates to set
up the right key type, when all they want is a source IPv4 address
match, well, no chance.

If we agree that templates won't be strictly necessary for basic
functionality, we can resubmit what we have already and think more about
the best way to expose all key types. I don't honestly know about using
a flower filter with 'protocol all' and no other key as a matchall
replacement. This is going to be really, really restrictive, and this
particular restriction could even be perhaps lifted in the meantime (I
don't see a reason why 'matchall' wouldn't be allowed in a chain with a
template installed).

But Xiaoliang has a point though: there is something which can never be
supported: if I want to do QoS based on a list of filters, some of which
need a S1_7TUPLE key, and others need a S1_NORMAL_IP6 key, then I can
never do that, because in our model, there's only one chain/lookup
reserved for QoS classification (a software constraint) but we need 2
chains/lookups for the 2 different key types (a hardware constraint).
Yes, this is something hypothetical at this point, but it bothers me
that the model would be limiting us. The hardware should support QoS
classification in more than 1 IS1 lookup, no? It isn't limited to
IS1_L0. Maybe, after all, we should permit dynamic assignment of actions
to chains. This way, "the QoS on multiple key types" use case could be
supported. What do you think?

Allan also mentioned shared blocks. Do we see anything particularly
difficult with those, that we should address first?

Thanks,
-Vladimir

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [EXT] Re: [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index
  2020-07-16 14:45                   ` Vladimir Oltean
@ 2020-07-17  7:34                     ` Joergen Andreasen
  2020-07-17  9:08                       ` Vladimir Oltean
  0 siblings, 1 reply; 29+ messages in thread
From: Joergen Andreasen @ 2020-07-17  7:34 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Xiaoliang Yang, Allan W. Nielsen, Po Liu, Claudiu Manoil,
	Alexandru Marginean, Vladimir Oltean, Leo Li, Mingkai Hu,
	Andrew Lunn, Florian Fainelli, Vivien Didelot, David S. Miller,
	Jiri Pirko, Ido Schimmel, Jakub Kicinski, Vinicius Costa Gomes,
	Nikolay Aleksandrov, Roopa Prabhu, netdev, lkml, Horatiu Vultur,
	Alexandre Belloni, Microchip Linux Driver Support, linux-devel

The 07/16/2020 17:45, Vladimir Oltean wrote:
> Hi Vladimir,
> 
> On Thu, Jul 16, 2020 at 10:37:40AM +0000, Xiaoliang Yang wrote:
> > Hi Joergen,
> >
> >
> > -----Original Message-----
> > From: Joergen Andreasen <joergen.andreasen@microchip.com>
> > Sent: 2020年7月16日 16:51
> >
> > > >> >> Chain 0:           The default chain - today this is in IS2. If we proceed
> > > >> >>                     with this as is - then this will change.
> > > >> >> Chain 1-9999:      These are offloaded by "basic" classification.
> > > >> >> Chain 10000-19999: These are offloaded in IS1
> > > >> >>                     Chain 10000: Lookup-0 in IS1, and here we could limit the
> > > >> >>                                  action to do QoS related stuff (priority
> > > >> >>                                  update)
> > > >> >>                     Chain 11000: Lookup-1 in IS1, here we could do VLAN
> > > >> >>                                  stuff
> > > >> >>                     Chain 12000: Lookup-2 in IS1, here we could apply the
> > > >> >>                                  "PAG" which is essentially a GOTO.
> > > >> >>
> > > >> >> Chain 20000-29999: These are offloaded in IS2
> > > >> >>                     Chain 20000-20255: Lookup-0 in IS2, where CHAIN-ID -
> > > >> >>                                        20000 is the PAG value.
> > > >> >>                     Chain 21000-21000: Lookup-1 in IS2.
> > > >> >>
> > > >> >> All these chains should be optional - users should only need to
> > > >> >> configure the chains they need. To make this work, we need to
> > > >> >> configure both the desired actions (could be priority update) and the goto action.
> > > >> >> Remember in HW, all packets goes through this process, while in
> > > >> >> SW they only follow the "goto" path.
> > > >> >>
> > >>
> > >> I agree with this chain assignment, following is an example to set rules:
> > >>
> > >> 1. Set a matchall rule for each chain, the last chain do not need goto chain action.
> > >> # tc filter add dev swp0 chain 0 flower skip_sw action goto chain 10000
> > >> # tc filter add dev swp0 chain 10000 flower skip_sw action goto chain 21000
> > >> In driver, use these rules to register the chain.
> > >>
> > >> 2. Set normal rules.
> > >> # tc filter add dev swp0 chain 10000 protocol 802.1Q parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action skbedit priority 1 action goto chain 21000
> > >> # tc filter add dev swp0 chain 21000 protocol 802.1Q parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action drop
> > >>
> > >> In driver, we check if the chain ID has been registered, and goto
> > >> chain is the same as first matchall rule, if is not, then return
> > >> error. Each rule need has goto action except last chain.
> > >>
> > >> I also have check about chain template, it can not set an action
> > >> template for each chain, so I think it's no use for our case. If
> > >> this way to set rules is OK, I will update the patch to do as this.
> > >>
> > >> Thanks,
> > >> Xiaoliang Yang
> > >
> >
> > > I agree that you cannot set an action template for each chain but
> > > you can set a match template which for example can be used for
> > > setting up which IS1 key to generate for the device/port.
> > > The template ensures that you cannot add an illegal match.
> > > I have attached a snippet from a testcase I wrote in order to test these ideas.
> > > Note that not all actions are valid for the hardware.
> > >
> > > SMAC       = "00:00:00:11:11:11"
> > > DMAC       = "00:00:00:dd:dd:dd"
> > > VID1       = 0x10
> > > VID2       = 0x20
> > > PCP1       = 3
> > > PCP2       = 5
> > > DEI        = 1
> > > SIP        = "10.10.0.1"
> > > DIP        = "10.10.0.2"
> > >
> > > IS1_L0     = 10000 # IS1 lookup 0
> > > IS1_L1     = 11000 # IS1 lookup 1
> > > IS1_L2     = 12000 # IS1 lookup 2
> > >
> > > IS2_L0     = 20000 # IS2 lookup 0 # IS2 20000 - 20255 -> pag 0-255
> > > IS2_L0_P1  = 20001 # IS2 lookup 0 pag 1
> > > IS2_L0_P2  = 20002 # IS2 lookup 0 pag 2
> > >
> > > IS2_L1     = 21000 # IS2 lookup 1
> > >
> > > $skip = "skip_hw" # or "skip_sw"
> > >
> > > test "Chain templates and goto" do
> > >     t_i "'prio #' sets the sequence of filters. Lowest number = highest priority = checked first. 0..0xffff"
> > >     t_i "'handle #' is a reference to the filter. Use this is if you need to reference the filter later. 0..0xffffffff"
> > >     t_i "'chain #' is the chain to use. Chain 0 is the default. Different chains can have different templates. 0..0xffffffff"
> > >     $ts.dut.run "tc qdisc add dev #{$dp[0]} clsact"
> > >
> > >     t_i "Add templates"
> > >     t_i "Configure the VCAP port configuration to match the shortest key that fulfill the purpose"
> >
> > >     t_i "Create a template that sets IS1 lookup 0 to generate S1_NORMAL with S1_DMAC_DIP_ENA"
> > >     t_i "If you match on both src and dst you will generate S1_7TUPLE"
> > >     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol ip chain #{IS1_L0} flower #{$skip} "\
> > >                 "dst_mac 00:00:00:00:00:00 "\
> > >                 "dst_ip 0.0.0.0 "
> > >
> > >     t_i "Create a template that sets IS1 lookup 1 to generate S1_5TUPLE_IP4"
> > >     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol ip chain #{IS1_L1} flower #{$skip} "\
> > >                 "src_ip 0.0.0.0 "\
> > >                 "dst_ip 0.0.0.0 "
> > >
> > >     t_i "Create a template that sets IS1 lookup 2 to generate S1_DBL_VID"
> > >     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol 802.1ad chain #{IS1_L2} flower #{$skip} "\
> > >                 "vlan_id 0 "\
> > >                 "vlan_prio 0 "\
> > >                 "vlan_ethtype 802.1q "\
> > >                 "cvlan_id 0 "\
> > >                 "cvlan_prio 0 "
> > >
> > >     $ts.dut.run "tc chain show dev #{$dp[0]} ingress"
> >
> > Why you set different filter keys on different lookup? Each lookup
> > only filter one type of keys?
> > If I want to filter a same key like dst_mac and do both QoS classified
> > action and vlan modify action, how to implement this in the same chain
> > #{IS1_L0} ?
> >
> > I think it's more reasonable to distinguish different lookup by different action like this:
> > IS1_L0     = 10000 # IS1 lookup 0     # do QoS classified action
> > IS1_L1     = 11000 # IS1 lookup 1     # do vlan modify action
> > IS1_L2     = 12000 # IS1 lookup 2     # do goto PAG action
> >
> > IS2_L0     = 20000 # IS2 lookup 0 # IS2 20000 - 20255 -> pag 0-255
> > IS2_L1          = 21000 # IS2 lookup 1
> >
> > So it’s no need to add templates, each lookup can support filtering
> > mac, IP or vlan tag, but only support one action.
> >
> > Thanks,
> > Xiaoliang
> 
> As far as I understand, he's still using the static chain numbers
> exactly for that, even though he didn't explicitly mention the action
> for each individual IS1 lookup.
> 
> The reason why he's also adding templates on each individual chain is to
> be able to configure VCAP_S1_KEY_CFG and VCAP_S2_CFG. The configuration
> of key type is per lookup.
> 
> Honestly, Joergen, I would take dynamic key configuration per lookup as
> a separate item. Xiaoliang's patch series for IS1 support is pretty
> large already.
> 
> Right now we have:
> 
> - In mainline:
> 
> S2_IP6_CFG
> S2_IP6_CFG controls the key generation for IPv6 frames. Bits 1:0
> control the first lookup and bits 3:2 control the second lookup.
> 0: IPv6 frames are matched against IP6_TCP_UDP or IP6_OTHER entries
> 1: IPv6 frames are matched against IP6_STD entries
> 2: IPv6 frames are matched against IP4_TCP_UDP or IP4_OTHER entries
> 3: IPv6 frames are matched against MAC_ETYPE entries
> 
> We set this field to 0xa (0b1010, aka 2 for both lookups: IP4_TCP_UDP).
> Although we don't really parse IPv6 keys coming from tc.
> 
> Also there are these fields which we're managing dynamically through
> ocelot_match_all_as_mac_etype, depending on whether there is any
> MAC_ETYPE key added by the user:
> S2_SNAP_DIS
> S2_ARP_DIS
> S2_IP_TCPUDP_DIS
> S2_IP_OTHER_DIS
> 
> - In Xiaoliang's patchset:
> 
> S1_KEY_IP6_CFG
> Selects key per lookup in S1 for IPv6 frames.
> 0: Use key S1_NORMAL
> 1: Use key S1_7TUPLE
> 2: Use key S1_5TUPLE_IP4
> 3: Use key S1_NORMAL_IP6
> 4: Use key S1_5TUPLE_IP6
> 5: Use key S1_DBL_VID
> 
> We set this to 2.
> 
> S1_KEY_IP4_CFG
> Selects key per lookup in S1 for IPv4 frames.
> 0: Use key S1_NORMAL
> 1: Use key S1_7TUPLE
> 2: Use key S1_5TUPLE_IP4
> 3: Use key S1_DBL_VID
> 
> We set this to 2.
> 
> Your input on which tc chain template could be used for each key type is
> valuable, we should create a table with all the options and associated
> key sizes (and therefore, number of available filters) and post it
> somewhere. I'm not completely sure that chains will be enough to
> describe every key type, at least not intuitively, For example if I just
> want to match on EtherType (protocol), I'll need an ETYPE (IS1) or
> MAC_ETYPE (IS2) rule, but the template for that will need to be
> formulated in terms of dst_mac because I don't think there's a way to
> use only the protocol in a template.
> 
> But I expect we keep using some default values (perhaps even the current
> ones, or deduce a valid key type from the first added rule, which is
> exactly what ocelot_match_all_as_mac_etype tries to do now) and don't
> expect the user to open the datasheet unless some advanced configuration
> is required. Otherwise I'm not sure who is going to use this. If the
> user sees a template shell script with the chains already set up,
> chances are it won't be too hard to add the right actions to the right
> chains. But if that is going to involve fiddling with templates to set
> up the right key type, when all they want is a source IPv4 address
> match, well, no chance.
> 
> If we agree that templates won't be strictly necessary for basic
> functionality, we can resubmit what we have already and think more about
> the best way to expose all key types. I don't honestly know about using
> a flower filter with 'protocol all' and no other key as a matchall
> replacement. This is going to be really, really restrictive, and this
> particular restriction could even be perhaps lifted in the meantime (I
> don't see a reason why 'matchall' wouldn't be allowed in a chain with a
> template installed).
> 
> But Xiaoliang has a point though: there is something which can never be
> supported: if I want to do QoS based on a list of filters, some of which
> need a S1_7TUPLE key, and others need a S1_NORMAL_IP6 key, then I can
> never do that, because in our model, there's only one chain/lookup
> reserved for QoS classification (a software constraint) but we need 2
> chains/lookups for the 2 different key types (a hardware constraint).
> Yes, this is something hypothetical at this point, but it bothers me
> that the model would be limiting us. The hardware should support QoS
> classification in more than 1 IS1 lookup, no? It isn't limited to
> IS1_L0. Maybe, after all, we should permit dynamic assignment of actions
> to chains. This way, "the QoS on multiple key types" use case could be
> supported. What do you think?
> 
> Allan also mentioned shared blocks. Do we see anything particularly
> difficult with those, that we should address first?
> 
> Thanks,
> -Vladimir

I agree that dynamic key configuration per lookup should be taken as a separate item.
I was just mentioning it because I think it is the only way to derive per port
key type generation with the current 'tc' command set.

The hardware supports all kind of actions in all lookups but mixing QoS and VLAN
actions in same lookup could be hard to understand for the user.

Let us say we want to apply a QoS action to <dip,dport> and a VLAN action to <dip>.
The most specific rule (the QoS action) must be specified first in the TCAM and
if it matches, the lookup terminates and no VLAN action is applied to <dip>.
To solve this, the user must assign both QoS and VLAN action in the <dip,dport>
rule which is probably not very intuitive.

The raseon for using a flower filter with an empty key as the final 'catch all'
is that you cannot add a matchall filter in a chain configured with flower.
I haven't checked how ineffective this is in the sw path but it works as expected.

I don't see any problems with shared blocks. They could be used for setting
IGR_PORT_MASK if you want to apply a filter to more than one interface.

-- 
Joergen Andreasen, Microchip

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [EXT] Re: [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index
  2020-07-17  7:34                     ` Joergen Andreasen
@ 2020-07-17  9:08                       ` Vladimir Oltean
  2020-07-17 19:10                         ` Allan W. Nielsen
  0 siblings, 1 reply; 29+ messages in thread
From: Vladimir Oltean @ 2020-07-17  9:08 UTC (permalink / raw)
  To: Joergen Andreasen
  Cc: Xiaoliang Yang, Allan W. Nielsen, Po Liu, Claudiu Manoil,
	Alexandru Marginean, Vladimir Oltean, Leo Li, Mingkai Hu,
	Andrew Lunn, Florian Fainelli, Vivien Didelot, David S. Miller,
	Jiri Pirko, Ido Schimmel, Jakub Kicinski, Vinicius Costa Gomes,
	Nikolay Aleksandrov, Roopa Prabhu, netdev, lkml, Horatiu Vultur,
	Alexandre Belloni, Microchip Linux Driver Support, linux-devel

On Fri, Jul 17, 2020 at 09:34:11AM +0200, Joergen Andreasen wrote:
> The 07/16/2020 17:45, Vladimir Oltean wrote:
> > Hi Vladimir,
> > 
> > On Thu, Jul 16, 2020 at 10:37:40AM +0000, Xiaoliang Yang wrote:
> > > Hi Joergen,
> > >
> > >
> > > -----Original Message-----
> > > From: Joergen Andreasen <joergen.andreasen@microchip.com>
> > > Sent: 2020年7月16日 16:51
> > >
> > > > >> >> Chain 0:           The default chain - today this is in IS2. If we proceed
> > > > >> >>                     with this as is - then this will change.
> > > > >> >> Chain 1-9999:      These are offloaded by "basic" classification.
> > > > >> >> Chain 10000-19999: These are offloaded in IS1
> > > > >> >>                     Chain 10000: Lookup-0 in IS1, and here we could limit the
> > > > >> >>                                  action to do QoS related stuff (priority
> > > > >> >>                                  update)
> > > > >> >>                     Chain 11000: Lookup-1 in IS1, here we could do VLAN
> > > > >> >>                                  stuff
> > > > >> >>                     Chain 12000: Lookup-2 in IS1, here we could apply the
> > > > >> >>                                  "PAG" which is essentially a GOTO.
> > > > >> >>
> > > > >> >> Chain 20000-29999: These are offloaded in IS2
> > > > >> >>                     Chain 20000-20255: Lookup-0 in IS2, where CHAIN-ID -
> > > > >> >>                                        20000 is the PAG value.
> > > > >> >>                     Chain 21000-21000: Lookup-1 in IS2.
> > > > >> >>
> > > > >> >> All these chains should be optional - users should only need to
> > > > >> >> configure the chains they need. To make this work, we need to
> > > > >> >> configure both the desired actions (could be priority update) and the goto action.
> > > > >> >> Remember in HW, all packets goes through this process, while in
> > > > >> >> SW they only follow the "goto" path.
> > > > >> >>
> > > >>
> > > >> I agree with this chain assignment, following is an example to set rules:
> > > >>
> > > >> 1. Set a matchall rule for each chain, the last chain do not need goto chain action.
> > > >> # tc filter add dev swp0 chain 0 flower skip_sw action goto chain 10000
> > > >> # tc filter add dev swp0 chain 10000 flower skip_sw action goto chain 21000
> > > >> In driver, use these rules to register the chain.
> > > >>
> > > >> 2. Set normal rules.
> > > >> # tc filter add dev swp0 chain 10000 protocol 802.1Q parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action skbedit priority 1 action goto chain 21000
> > > >> # tc filter add dev swp0 chain 21000 protocol 802.1Q parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action drop
> > > >>
> > > >> In driver, we check if the chain ID has been registered, and goto
> > > >> chain is the same as first matchall rule, if is not, then return
> > > >> error. Each rule need has goto action except last chain.
> > > >>
> > > >> I also have check about chain template, it can not set an action
> > > >> template for each chain, so I think it's no use for our case. If
> > > >> this way to set rules is OK, I will update the patch to do as this.
> > > >>
> > > >> Thanks,
> > > >> Xiaoliang Yang
> > > >
> > >
> > > > I agree that you cannot set an action template for each chain but
> > > > you can set a match template which for example can be used for
> > > > setting up which IS1 key to generate for the device/port.
> > > > The template ensures that you cannot add an illegal match.
> > > > I have attached a snippet from a testcase I wrote in order to test these ideas.
> > > > Note that not all actions are valid for the hardware.
> > > >
> > > > SMAC       = "00:00:00:11:11:11"
> > > > DMAC       = "00:00:00:dd:dd:dd"
> > > > VID1       = 0x10
> > > > VID2       = 0x20
> > > > PCP1       = 3
> > > > PCP2       = 5
> > > > DEI        = 1
> > > > SIP        = "10.10.0.1"
> > > > DIP        = "10.10.0.2"
> > > >
> > > > IS1_L0     = 10000 # IS1 lookup 0
> > > > IS1_L1     = 11000 # IS1 lookup 1
> > > > IS1_L2     = 12000 # IS1 lookup 2
> > > >
> > > > IS2_L0     = 20000 # IS2 lookup 0 # IS2 20000 - 20255 -> pag 0-255
> > > > IS2_L0_P1  = 20001 # IS2 lookup 0 pag 1
> > > > IS2_L0_P2  = 20002 # IS2 lookup 0 pag 2
> > > >
> > > > IS2_L1     = 21000 # IS2 lookup 1
> > > >
> > > > $skip = "skip_hw" # or "skip_sw"
> > > >
> > > > test "Chain templates and goto" do
> > > >     t_i "'prio #' sets the sequence of filters. Lowest number = highest priority = checked first. 0..0xffff"
> > > >     t_i "'handle #' is a reference to the filter. Use this is if you need to reference the filter later. 0..0xffffffff"
> > > >     t_i "'chain #' is the chain to use. Chain 0 is the default. Different chains can have different templates. 0..0xffffffff"
> > > >     $ts.dut.run "tc qdisc add dev #{$dp[0]} clsact"
> > > >
> > > >     t_i "Add templates"
> > > >     t_i "Configure the VCAP port configuration to match the shortest key that fulfill the purpose"
> > >
> > > >     t_i "Create a template that sets IS1 lookup 0 to generate S1_NORMAL with S1_DMAC_DIP_ENA"
> > > >     t_i "If you match on both src and dst you will generate S1_7TUPLE"
> > > >     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol ip chain #{IS1_L0} flower #{$skip} "\
> > > >                 "dst_mac 00:00:00:00:00:00 "\
> > > >                 "dst_ip 0.0.0.0 "
> > > >
> > > >     t_i "Create a template that sets IS1 lookup 1 to generate S1_5TUPLE_IP4"
> > > >     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol ip chain #{IS1_L1} flower #{$skip} "\
> > > >                 "src_ip 0.0.0.0 "\
> > > >                 "dst_ip 0.0.0.0 "
> > > >
> > > >     t_i "Create a template that sets IS1 lookup 2 to generate S1_DBL_VID"
> > > >     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol 802.1ad chain #{IS1_L2} flower #{$skip} "\
> > > >                 "vlan_id 0 "\
> > > >                 "vlan_prio 0 "\
> > > >                 "vlan_ethtype 802.1q "\
> > > >                 "cvlan_id 0 "\
> > > >                 "cvlan_prio 0 "
> > > >
> > > >     $ts.dut.run "tc chain show dev #{$dp[0]} ingress"
> > >
> > > Why you set different filter keys on different lookup? Each lookup
> > > only filter one type of keys?
> > > If I want to filter a same key like dst_mac and do both QoS classified
> > > action and vlan modify action, how to implement this in the same chain
> > > #{IS1_L0} ?
> > >
> > > I think it's more reasonable to distinguish different lookup by different action like this:
> > > IS1_L0     = 10000 # IS1 lookup 0     # do QoS classified action
> > > IS1_L1     = 11000 # IS1 lookup 1     # do vlan modify action
> > > IS1_L2     = 12000 # IS1 lookup 2     # do goto PAG action
> > >
> > > IS2_L0     = 20000 # IS2 lookup 0 # IS2 20000 - 20255 -> pag 0-255
> > > IS2_L1          = 21000 # IS2 lookup 1
> > >
> > > So it’s no need to add templates, each lookup can support filtering
> > > mac, IP or vlan tag, but only support one action.
> > >
> > > Thanks,
> > > Xiaoliang
> > 
> > As far as I understand, he's still using the static chain numbers
> > exactly for that, even though he didn't explicitly mention the action
> > for each individual IS1 lookup.
> > 
> > The reason why he's also adding templates on each individual chain is to
> > be able to configure VCAP_S1_KEY_CFG and VCAP_S2_CFG. The configuration
> > of key type is per lookup.
> > 
> > Honestly, Joergen, I would take dynamic key configuration per lookup as
> > a separate item. Xiaoliang's patch series for IS1 support is pretty
> > large already.
> > 
> > Right now we have:
> > 
> > - In mainline:
> > 
> > S2_IP6_CFG
> > S2_IP6_CFG controls the key generation for IPv6 frames. Bits 1:0
> > control the first lookup and bits 3:2 control the second lookup.
> > 0: IPv6 frames are matched against IP6_TCP_UDP or IP6_OTHER entries
> > 1: IPv6 frames are matched against IP6_STD entries
> > 2: IPv6 frames are matched against IP4_TCP_UDP or IP4_OTHER entries
> > 3: IPv6 frames are matched against MAC_ETYPE entries
> > 
> > We set this field to 0xa (0b1010, aka 2 for both lookups: IP4_TCP_UDP).
> > Although we don't really parse IPv6 keys coming from tc.
> > 
> > Also there are these fields which we're managing dynamically through
> > ocelot_match_all_as_mac_etype, depending on whether there is any
> > MAC_ETYPE key added by the user:
> > S2_SNAP_DIS
> > S2_ARP_DIS
> > S2_IP_TCPUDP_DIS
> > S2_IP_OTHER_DIS
> > 
> > - In Xiaoliang's patchset:
> > 
> > S1_KEY_IP6_CFG
> > Selects key per lookup in S1 for IPv6 frames.
> > 0: Use key S1_NORMAL
> > 1: Use key S1_7TUPLE
> > 2: Use key S1_5TUPLE_IP4
> > 3: Use key S1_NORMAL_IP6
> > 4: Use key S1_5TUPLE_IP6
> > 5: Use key S1_DBL_VID
> > 
> > We set this to 2.
> > 
> > S1_KEY_IP4_CFG
> > Selects key per lookup in S1 for IPv4 frames.
> > 0: Use key S1_NORMAL
> > 1: Use key S1_7TUPLE
> > 2: Use key S1_5TUPLE_IP4
> > 3: Use key S1_DBL_VID
> > 
> > We set this to 2.
> > 
> > Your input on which tc chain template could be used for each key type is
> > valuable, we should create a table with all the options and associated
> > key sizes (and therefore, number of available filters) and post it
> > somewhere. I'm not completely sure that chains will be enough to
> > describe every key type, at least not intuitively, For example if I just
> > want to match on EtherType (protocol), I'll need an ETYPE (IS1) or
> > MAC_ETYPE (IS2) rule, but the template for that will need to be
> > formulated in terms of dst_mac because I don't think there's a way to
> > use only the protocol in a template.
> > 
> > But I expect we keep using some default values (perhaps even the current
> > ones, or deduce a valid key type from the first added rule, which is
> > exactly what ocelot_match_all_as_mac_etype tries to do now) and don't
> > expect the user to open the datasheet unless some advanced configuration
> > is required. Otherwise I'm not sure who is going to use this. If the
> > user sees a template shell script with the chains already set up,
> > chances are it won't be too hard to add the right actions to the right
> > chains. But if that is going to involve fiddling with templates to set
> > up the right key type, when all they want is a source IPv4 address
> > match, well, no chance.
> > 
> > If we agree that templates won't be strictly necessary for basic
> > functionality, we can resubmit what we have already and think more about
> > the best way to expose all key types. I don't honestly know about using
> > a flower filter with 'protocol all' and no other key as a matchall
> > replacement. This is going to be really, really restrictive, and this
> > particular restriction could even be perhaps lifted in the meantime (I
> > don't see a reason why 'matchall' wouldn't be allowed in a chain with a
> > template installed).
> > 
> > But Xiaoliang has a point though: there is something which can never be
> > supported: if I want to do QoS based on a list of filters, some of which
> > need a S1_7TUPLE key, and others need a S1_NORMAL_IP6 key, then I can
> > never do that, because in our model, there's only one chain/lookup
> > reserved for QoS classification (a software constraint) but we need 2
> > chains/lookups for the 2 different key types (a hardware constraint).
> > Yes, this is something hypothetical at this point, but it bothers me
> > that the model would be limiting us. The hardware should support QoS
> > classification in more than 1 IS1 lookup, no? It isn't limited to
> > IS1_L0. Maybe, after all, we should permit dynamic assignment of actions
> > to chains. This way, "the QoS on multiple key types" use case could be
> > supported. What do you think?
> > 
> > Allan also mentioned shared blocks. Do we see anything particularly
> > difficult with those, that we should address first?
> > 
> > Thanks,
> > -Vladimir
> 
> I agree that dynamic key configuration per lookup should be taken as a separate item.
> I was just mentioning it because I think it is the only way to derive per port
> key type generation with the current 'tc' command set.
> 
> The hardware supports all kind of actions in all lookups but mixing QoS and VLAN
> actions in same lookup could be hard to understand for the user.
> 
> Let us say we want to apply a QoS action to <dip,dport> and a VLAN action to <dip>.
> The most specific rule (the QoS action) must be specified first in the TCAM and

Why must the rule with the most specific key be added first to the TCAM?
Is this in reply to my comment about deriving an appropriate key type
from the first filter introduced in each lookup?

> if it matches, the lookup terminates and no VLAN action is applied to <dip>.
> To solve this, the user must assign both QoS and VLAN action in the <dip,dport>
> rule which is probably not very intuitive.
> 

If so, can't we simply alter the priority of the filters, such that the
order in which they match on packets is not the same order as which they
were introduced by the user?

Supporting multiple actions per rule could be interesting, in the sense
that the hardware supports this feature and it would be therefore nice
if it could be exposed.

I've been re-reading the discussion with you and Allan, and to be
honest, I don't completely internalize why we are doing the
1-action-per-chain now. Sorry. It has been said that the TCAM stops on
first match in each lookup, and I understand that. So we must have,
in each filter's list of actions, not only the action we want (vlan,
skbedit priority, trap, drop, police), but also an explicit 'goto'
action to the next lookup or TCAM. But if 'stealing' frames is the
problem, then it's not just a QoS action that can steal frames from a
VLAN action. But instead, a QoS action can steal frames even from
another QoS action. I mean, in your example above, with a more generic
<dip> key and another more specific <dip,dport> key, there's nothing
about the action itself that is causing this 'stealing' to occur. So, I
don't really see why we are forcing a unique action per chain/lookup,
and how that, in itself, helps with anything. With my (certainly not as
deep as yours) understanding, just chaining a goto after each action
should be enough to keep the software and the hardware behavior
identical. I would really appreciate if you could clarify my
misunderstanding.

> The raseon for using a flower filter with an empty key as the final 'catch all'
> is that you cannot add a matchall filter in a chain configured with flower.
> I haven't checked how ineffective this is in the sw path but it works as expected.
> 

I realize now I didn't explicitly mention why the 'flower' instead of
'matchall' concerns me if we use templates, and that is because one of
the use cases we are interested in (which we are not covering in this
patch series) is masked matching on the raw first 4 bytes after
EtherType. This could be done with an u32 filter, and in hardware it
would use the L3_IP4_SIP field of an S1_NORMAL half key:

L3_IP4_SIP
Overloaded fields for different frame types:
LLC frame: L3_IP4_SIP = [CTRL, PAYLOAD[0:2]]
SNAP frame: L3_IP4_SIP = [PID[2:0], PAYLOAD[0]]
IPv4 or IPv6 frame: L3_IP4_SIP = source IP address, bits [31:0]
OAM, ARP or ETYPE frame: L3_IP4_SIP = PAYLOAD[0:3]  <- we have ETYPE frame
For IPv4 or IPv6 frames, use destination IP address if
VCAP_CFG.S1_DMAC_DIP_ENA is set for ingress port.

But if tc chain templates require us to not mix different types of
filters (such as matchall and flower, u32 and flower), I think it could
become very challenging.

> I don't see any problems with shared blocks. They could be used for setting
> IGR_PORT_MASK if you want to apply a filter to more than one interface.
> 

Ok, that's what I figured too.

> -- 
> Joergen Andreasen, Microchip

Thanks,
-Vladimir

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [EXT] Re: [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index
  2020-07-17  9:08                       ` Vladimir Oltean
@ 2020-07-17 19:10                         ` Allan W. Nielsen
  2020-07-20 11:04                           ` Xiaoliang Yang
  0 siblings, 1 reply; 29+ messages in thread
From: Allan W. Nielsen @ 2020-07-17 19:10 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Joergen Andreasen, Xiaoliang Yang, Po Liu, Claudiu Manoil,
	Alexandru Marginean, Vladimir Oltean, Leo Li, Mingkai Hu,
	Andrew Lunn, Florian Fainelli, Vivien Didelot, David S. Miller,
	Jiri Pirko, Ido Schimmel, Jakub Kicinski, Vinicius Costa Gomes,
	Nikolay Aleksandrov, Roopa Prabhu, netdev, lkml, Horatiu Vultur,
	Alexandre Belloni, Microchip Linux Driver Support, linux-devel

On 17.07.2020 12:08, Vladimir Oltean wrote:
>EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>
>On Fri, Jul 17, 2020 at 09:34:11AM +0200, Joergen Andreasen wrote:
>> The 07/16/2020 17:45, Vladimir Oltean wrote:
>> > Hi Vladimir,
>> >
>> > On Thu, Jul 16, 2020 at 10:37:40AM +0000, Xiaoliang Yang wrote:
>> > > Hi Joergen,
>> > >
>> > >
>> > > -----Original Message-----
>> > > From: Joergen Andreasen <joergen.andreasen@microchip.com>
>> > > Sent: 2020年7月16日 16:51
>> > >
>> > > > >> >> Chain 0:           The default chain - today this is in IS2. If we proceed
>> > > > >> >>                     with this as is - then this will change.
>> > > > >> >> Chain 1-9999:      These are offloaded by "basic" classification.
>> > > > >> >> Chain 10000-19999: These are offloaded in IS1
>> > > > >> >>                     Chain 10000: Lookup-0 in IS1, and here we could limit the
>> > > > >> >>                                  action to do QoS related stuff (priority
>> > > > >> >>                                  update)
>> > > > >> >>                     Chain 11000: Lookup-1 in IS1, here we could do VLAN
>> > > > >> >>                                  stuff
>> > > > >> >>                     Chain 12000: Lookup-2 in IS1, here we could apply the
>> > > > >> >>                                  "PAG" which is essentially a GOTO.
>> > > > >> >>
>> > > > >> >> Chain 20000-29999: These are offloaded in IS2
>> > > > >> >>                     Chain 20000-20255: Lookup-0 in IS2, where CHAIN-ID -
>> > > > >> >>                                        20000 is the PAG value.
>> > > > >> >>                     Chain 21000-21000: Lookup-1 in IS2.
>> > > > >> >>
>> > > > >> >> All these chains should be optional - users should only need to
>> > > > >> >> configure the chains they need. To make this work, we need to
>> > > > >> >> configure both the desired actions (could be priority update) and the goto action.
>> > > > >> >> Remember in HW, all packets goes through this process, while in
>> > > > >> >> SW they only follow the "goto" path.
>> > > > >> >>
>> > > >>
>> > > >> I agree with this chain assignment, following is an example to set rules:
>> > > >>
>> > > >> 1. Set a matchall rule for each chain, the last chain do not need goto chain action.
>> > > >> # tc filter add dev swp0 chain 0 flower skip_sw action goto chain 10000
>> > > >> # tc filter add dev swp0 chain 10000 flower skip_sw action goto chain 21000
>> > > >> In driver, use these rules to register the chain.
>> > > >>
>> > > >> 2. Set normal rules.
>> > > >> # tc filter add dev swp0 chain 10000 protocol 802.1Q parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action skbedit priority 1 action goto chain 21000
>> > > >> # tc filter add dev swp0 chain 21000 protocol 802.1Q parent ffff: flower skip_sw vlan_id 1 vlan_prio 1 action drop
>> > > >>
>> > > >> In driver, we check if the chain ID has been registered, and goto
>> > > >> chain is the same as first matchall rule, if is not, then return
>> > > >> error. Each rule need has goto action except last chain.
>> > > >>
>> > > >> I also have check about chain template, it can not set an action
>> > > >> template for each chain, so I think it's no use for our case. If
>> > > >> this way to set rules is OK, I will update the patch to do as this.
>> > > >>
>> > > >> Thanks,
>> > > >> Xiaoliang Yang
>> > > >
>> > >
>> > > > I agree that you cannot set an action template for each chain but
>> > > > you can set a match template which for example can be used for
>> > > > setting up which IS1 key to generate for the device/port.
>> > > > The template ensures that you cannot add an illegal match.
>> > > > I have attached a snippet from a testcase I wrote in order to test these ideas.
>> > > > Note that not all actions are valid for the hardware.
>> > > >
>> > > > SMAC       = "00:00:00:11:11:11"
>> > > > DMAC       = "00:00:00:dd:dd:dd"
>> > > > VID1       = 0x10
>> > > > VID2       = 0x20
>> > > > PCP1       = 3
>> > > > PCP2       = 5
>> > > > DEI        = 1
>> > > > SIP        = "10.10.0.1"
>> > > > DIP        = "10.10.0.2"
>> > > >
>> > > > IS1_L0     = 10000 # IS1 lookup 0
>> > > > IS1_L1     = 11000 # IS1 lookup 1
>> > > > IS1_L2     = 12000 # IS1 lookup 2
>> > > >
>> > > > IS2_L0     = 20000 # IS2 lookup 0 # IS2 20000 - 20255 -> pag 0-255
>> > > > IS2_L0_P1  = 20001 # IS2 lookup 0 pag 1
>> > > > IS2_L0_P2  = 20002 # IS2 lookup 0 pag 2
>> > > >
>> > > > IS2_L1     = 21000 # IS2 lookup 1
>> > > >
>> > > > $skip = "skip_hw" # or "skip_sw"
>> > > >
>> > > > test "Chain templates and goto" do
>> > > >     t_i "'prio #' sets the sequence of filters. Lowest number = highest priority = checked first. 0..0xffff"
>> > > >     t_i "'handle #' is a reference to the filter. Use this is if you need to reference the filter later. 0..0xffffffff"
>> > > >     t_i "'chain #' is the chain to use. Chain 0 is the default. Different chains can have different templates. 0..0xffffffff"
>> > > >     $ts.dut.run "tc qdisc add dev #{$dp[0]} clsact"
>> > > >
>> > > >     t_i "Add templates"
>> > > >     t_i "Configure the VCAP port configuration to match the shortest key that fulfill the purpose"
>> > >
>> > > >     t_i "Create a template that sets IS1 lookup 0 to generate S1_NORMAL with S1_DMAC_DIP_ENA"
>> > > >     t_i "If you match on both src and dst you will generate S1_7TUPLE"
>> > > >     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol ip chain #{IS1_L0} flower #{$skip} "\
>> > > >                 "dst_mac 00:00:00:00:00:00 "\
>> > > >                 "dst_ip 0.0.0.0 "
>> > > >
>> > > >     t_i "Create a template that sets IS1 lookup 1 to generate S1_5TUPLE_IP4"
>> > > >     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol ip chain #{IS1_L1} flower #{$skip} "\
>> > > >                 "src_ip 0.0.0.0 "\
>> > > >                 "dst_ip 0.0.0.0 "
>> > > >
>> > > >     t_i "Create a template that sets IS1 lookup 2 to generate S1_DBL_VID"
>> > > >     $ts.dut.run "tc chain add dev #{$dp[0]} ingress protocol 802.1ad chain #{IS1_L2} flower #{$skip} "\
>> > > >                 "vlan_id 0 "\
>> > > >                 "vlan_prio 0 "\
>> > > >                 "vlan_ethtype 802.1q "\
>> > > >                 "cvlan_id 0 "\
>> > > >                 "cvlan_prio 0 "
>> > > >
>> > > >     $ts.dut.run "tc chain show dev #{$dp[0]} ingress"
>> > >
>> > > Why you set different filter keys on different lookup? Each lookup
>> > > only filter one type of keys?
>> > > If I want to filter a same key like dst_mac and do both QoS classified
>> > > action and vlan modify action, how to implement this in the same chain
>> > > #{IS1_L0} ?
>> > >
>> > > I think it's more reasonable to distinguish different lookup by different action like this:
>> > > IS1_L0     = 10000 # IS1 lookup 0     # do QoS classified action
>> > > IS1_L1     = 11000 # IS1 lookup 1     # do vlan modify action
>> > > IS1_L2     = 12000 # IS1 lookup 2     # do goto PAG action
>> > >
>> > > IS2_L0     = 20000 # IS2 lookup 0 # IS2 20000 - 20255 -> pag 0-255
>> > > IS2_L1          = 21000 # IS2 lookup 1
>> > >
>> > > So it’s no need to add templates, each lookup can support filtering
>> > > mac, IP or vlan tag, but only support one action.
>> > >
>> > > Thanks,
>> > > Xiaoliang
>> >
>> > As far as I understand, he's still using the static chain numbers
>> > exactly for that, even though he didn't explicitly mention the action
>> > for each individual IS1 lookup.
>> >
>> > The reason why he's also adding templates on each individual chain is to
>> > be able to configure VCAP_S1_KEY_CFG and VCAP_S2_CFG. The configuration
>> > of key type is per lookup.
>> >
>> > Honestly, Joergen, I would take dynamic key configuration per lookup as
>> > a separate item. Xiaoliang's patch series for IS1 support is pretty
>> > large already.
I agree, it is already really long, and I would also like if we can
focus on as small incremental steps as possible.

Maybe it would be an idea to do the ES0 independently. As there are only
1 ES0 look-up, and only 1 egress tcam this seems a lot more straight
forward. I can not remember the details of that patchs, but I remember
it as largely okay.

>> > Right now we have:
>> > - In mainline:
>> > S2_IP6_CFG
>> > S2_IP6_CFG controls the key generation for IPv6 frames. Bits 1:0
>> > control the first lookup and bits 3:2 control the second lookup.
>> > 0: IPv6 frames are matched against IP6_TCP_UDP or IP6_OTHER entries
>> > 1: IPv6 frames are matched against IP6_STD entries
>> > 2: IPv6 frames are matched against IP4_TCP_UDP or IP4_OTHER entries
>> > 3: IPv6 frames are matched against MAC_ETYPE entries
>> >
>> > We set this field to 0xa (0b1010, aka 2 for both lookups: IP4_TCP_UDP).
>> > Although we don't really parse IPv6 keys coming from tc.
>> >
>> > Also there are these fields which we're managing dynamically through
>> > ocelot_match_all_as_mac_etype, depending on whether there is any
>> > MAC_ETYPE key added by the user:
>> > S2_SNAP_DIS
>> > S2_ARP_DIS
>> > S2_IP_TCPUDP_DIS
>> > S2_IP_OTHER_DIS
As far as I recall with what we have in main-line today, we only use 1
lookup in IS2.

You added some functionallity to dynamic select the KEY depending on
what rules was installed, and some better error handling to reject
rules that could not be applied correctly.



>> > - In Xiaoliang's patchset:
>> >
>> > S1_KEY_IP6_CFG
>> > Selects key per lookup in S1 for IPv6 frames.
>> > 0: Use key S1_NORMAL
>> > 1: Use key S1_7TUPLE
>> > 2: Use key S1_5TUPLE_IP4
>> > 3: Use key S1_NORMAL_IP6
>> > 4: Use key S1_5TUPLE_IP6
>> > 5: Use key S1_DBL_VID
>> >
>> > We set this to 2.
>> >
>> > S1_KEY_IP4_CFG
>> > Selects key per lookup in S1 for IPv4 frames.
>> > 0: Use key S1_NORMAL
>> > 1: Use key S1_7TUPLE
>> > 2: Use key S1_5TUPLE_IP4
>> > 3: Use key S1_DBL_VID
>> >
>> > We set this to 2.
Any reason you prefer S1_5TUPLE_IP4 over S1_7TUPLE?


>> > Your input on which tc chain template could be used for each key type is
>> > valuable, we should create a table with all the options and associated
>> > key sizes (and therefore, number of available filters) and post it
>> > somewhere. I'm not completely sure that chains will be enough to
>> > describe every key type, at least not intuitively, For example if I just
>> > want to match on EtherType (protocol), I'll need an ETYPE (IS1) or
>> > MAC_ETYPE (IS2) rule, but the template for that will need to be
>> > formulated in terms of dst_mac because I don't think there's a way to
>> > use only the protocol in a template.
Agree.

>> > But I expect we keep using some default values (perhaps even the current
>> > ones, or deduce a valid key type from the first added rule, which is
>> > exactly what ocelot_match_all_as_mac_etype tries to do now) and don't
>> > expect the user to open the datasheet unless some advanced configuration
>> > is required. Otherwise I'm not sure who is going to use this. If the
>> > user sees a template shell script with the chains already set up,
>> > chances are it won't be too hard to add the right actions to the right
>> > chains. But if that is going to involve fiddling with templates to set
>> > up the right key type, when all they want is a source IPv4 address
>> > match, well, no chance.

My preference would be to pick the "largest" key by default. This will
mean that we will be wasting some TCAM resources - but we have more
features.

We can then at a later point add support for templates, and with the
templates we can choose the smallest key which fullfill the requirement
stated by the template.

>> > If we agree that templates won't be strictly necessary for basic
>> > functionality, we can resubmit what we have already and think more about
>> > the best way to expose all key types. I don't honestly know about using
>> > a flower filter with 'protocol all' and no other key as a matchall
>> > replacement. This is going to be really, really restrictive, and this
>> > particular restriction could even be perhaps lifted in the meantime (I
>> > don't see a reason why 'matchall' wouldn't be allowed in a chain with a
>> > template installed).
>> >
>> > But Xiaoliang has a point though: there is something which can never be
>> > supported: if I want to do QoS based on a list of filters, some of which
>> > need a S1_7TUPLE key, and others need a S1_NORMAL_IP6 key, then I can
>> > never do that, because in our model, there's only one chain/lookup
>> > reserved for QoS classification (a software constraint) but we need 2
>> > chains/lookups for the 2 different key types (a hardware constraint).
>> > Yes, this is something hypothetical at this point, but it bothers me
>> > that the model would be limiting us. The hardware should support QoS
>> > classification in more than 1 IS1 lookup, no? It isn't limited to
>> > IS1_L0. Maybe, after all, we should permit dynamic assignment of actions
>> > to chains. This way, "the QoS on multiple key types" use case could be
>> > supported. What do you think?
>> >
>> > Allan also mentioned shared blocks. Do we see anything particularly
>> > difficult with those, that we should address first?
>> >
>> > Thanks,
>> > -Vladimir
>>
>> I agree that dynamic key configuration per lookup should be taken as a separate item.
>> I was just mentioning it because I think it is the only way to derive per port
>> key type generation with the current 'tc' command set.
>>
>> The hardware supports all kind of actions in all lookups but mixing QoS and VLAN
>> actions in same lookup could be hard to understand for the user.
>>
>> Let us say we want to apply a QoS action to <dip,dport> and a VLAN action to <dip>.
>> The most specific rule (the QoS action) must be specified first in the TCAM and
>
>Why must the rule with the most specific key be added first to the TCAM?
>Is this in reply to my comment about deriving an appropriate key type
>from the first filter introduced in each lookup?
>
>> if it matches, the lookup terminates and no VLAN action is applied to <dip>.
>> To solve this, the user must assign both QoS and VLAN action in the <dip,dport>
>> rule which is probably not very intuitive.
>>
>
>If so, can't we simply alter the priority of the filters, such that the
>order in which they match on packets is not the same order as which they
>were introduced by the user?
>
>Supporting multiple actions per rule could be interesting, in the sense
>that the hardware supports this feature and it would be therefore nice
>if it could be exposed.
>
>I've been re-reading the discussion with you and Allan, and to be
>honest, I don't completely internalize why we are doing the
>1-action-per-chain now. Sorry. It has been said that the TCAM stops on
>first match in each lookup, and I understand that. So we must have,
>in each filter's list of actions, not only the action we want (vlan,
>skbedit priority, trap, drop, police), but also an explicit 'goto'
>action to the next lookup or TCAM. But if 'stealing' frames is the
>problem, then it's not just a QoS action that can steal frames from a
>VLAN action. But instead, a QoS action can steal frames even from
>another QoS action. I mean, in your example above, with a more generic
><dip> key and another more specific <dip,dport> key, there's nothing
>about the action itself that is causing this 'stealing' to occur. So, I
>don't really see why we are forcing a unique action per chain/lookup,
>and how that, in itself, helps with anything. With my (certainly not as
>deep as yours) understanding, just chaining a goto after each action
>should be enough to keep the software and the hardware behavior
>identical. I would really appreciate if you could clarify my
>misunderstanding.

The reason why I that we should make a given action exclusive owned by a
given lookup, is that then it is trivial to guarantee that the 3
look-ups which in HW is done in parallel will give the same result as in
SW where they are done in sequence.

But if we can do something less restrictive, then I'm open for it (we
might be able to do that).

>> The raseon for using a flower filter with an empty key as the final 'catch all'
>> is that you cannot add a matchall filter in a chain configured with flower.
>> I haven't checked how ineffective this is in the sw path but it works as expected.
>>
>
>I realize now I didn't explicitly mention why the 'flower' instead of
>'matchall' concerns me if we use templates, and that is because one of
>the use cases we are interested in (which we are not covering in this
>patch series) is masked matching on the raw first 4 bytes after
>EtherType. This could be done with an u32 filter, and in hardware it
>would use the L3_IP4_SIP field of an S1_NORMAL half key:
>
>L3_IP4_SIP
>Overloaded fields for different frame types:
>LLC frame: L3_IP4_SIP = [CTRL, PAYLOAD[0:2]]
>SNAP frame: L3_IP4_SIP = [PID[2:0], PAYLOAD[0]]
>IPv4 or IPv6 frame: L3_IP4_SIP = source IP address, bits [31:0]
>OAM, ARP or ETYPE frame: L3_IP4_SIP = PAYLOAD[0:3]  <- we have ETYPE frame
>For IPv4 or IPv6 frames, use destination IP address if
>VCAP_CFG.S1_DMAC_DIP_ENA is set for ingress port.
>
>But if tc chain templates require us to not mix different types of
>filters (such as matchall and flower, u32 and flower), I think it could
>become very challenging.
Okay - I will need to look deeper into to this to really understand the
consequences of mixing different types of filters. As far as Joergens
example goes, "matchall" is really the same as a flower without any
matches.

Long story short, to me the most important step here is that we come up
with a design where we can expose the 3 lookups in IS1 as separate
chains, and that we have something which behaves the same in HW and SW.

Once we have that, we can add templates, shared blocks, shared actions
etc. in the future.

I know I have not been very active on this thread for the past couple of
days, but I'm certainly interesting in continue working/reviewing this.
I will be OOO for the next 3 weeks, with very limited options for
reviewing/commenting on this, but after that I'm back again.

/Allan



^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [EXT] Re: [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index
  2020-07-17 19:10                         ` Allan W. Nielsen
@ 2020-07-20 11:04                           ` Xiaoliang Yang
  0 siblings, 0 replies; 29+ messages in thread
From: Xiaoliang Yang @ 2020-07-20 11:04 UTC (permalink / raw)
  To: Allan W. Nielsen, Vladimir Oltean
  Cc: Joergen Andreasen, Po Liu, Claudiu Manoil, Alexandru Marginean,
	Vladimir Oltean, Leo Li, Mingkai Hu, Andrew Lunn,
	Florian Fainelli, Vivien Didelot, David S. Miller, Jiri Pirko,
	Ido Schimmel, Jakub Kicinski, Vinicius Costa Gomes,
	Nikolay Aleksandrov, Roopa Prabhu, netdev, lkml, Horatiu Vultur,
	Alexandre Belloni, Microchip Linux Driver Support, linux-devel


18.07.2020 3:10, Allan wrote:
>
> Okay - I will need to look deeper into to this to really understand the consequences of mixing different types of filters. As far as Joergens example goes, "matchall" is really the same as a flower without any matches.
>
> Long story short, to me the most important step here is that we come up with a design where we can expose the 3 lookups in IS1 as separate chains, and that we have something which behaves the same in HW and SW.
>
> Once we have that, we can add templates, shared blocks, shared actions etc. in the future.
> 
> I know I have not been very active on this thread for the past couple of days, but I'm certainly interesting in continue working/reviewing this.
> I will be OOO for the next 3 weeks, with very limited options for reviewing/commenting on this, but after that I'm back again.
>
>/Allan
>

So chain template is used to configure key type on IS1, we can set one key type for each of the three lookups. In order to support all key types, we need to add half keys, full keys and quard keys support. If there is no template set, using a default "S1_7TUPLE" key type, which can cover most keys.

In general, using a default key type for each of the three lookups, and limited one action on one lookup chain, these can support three parallel lookup on IS1. Add PAG support as two lookups on IS2, then templates and shared blocks can be supported after that.

Thanks,
Xiaoliang

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2020-07-20 11:04 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-02  5:18 [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Xiaoliang Yang
2020-06-02  5:18 ` [PATCH v2 net-next 01/10] net: mscc: ocelot: introduce a new ocelot_target_{read,write} API Xiaoliang Yang
2020-06-02  5:18 ` [PATCH v2 net-next 02/10] net: mscc: ocelot: generalize existing code for VCAP Xiaoliang Yang
2020-06-02  5:18 ` [PATCH v2 net-next 03/10] net: mscc: ocelot: allocated rules to different hardware VCAP TCAMs by chain index Xiaoliang Yang
2020-06-02  8:36   ` Allan W. Nielsen
2020-06-03 10:04     ` Vladimir Oltean
2020-06-08 13:56       ` Allan W. Nielsen
2020-06-09 12:55         ` Vladimir Oltean
2020-06-10 18:18           ` Allan W. Nielsen
2020-07-16  6:49             ` [EXT] " Xiaoliang Yang
2020-07-16  8:50               ` Joergen Andreasen
2020-07-16 10:37                 ` Xiaoliang Yang
2020-07-16 14:45                   ` Vladimir Oltean
2020-07-17  7:34                     ` Joergen Andreasen
2020-07-17  9:08                       ` Vladimir Oltean
2020-07-17 19:10                         ` Allan W. Nielsen
2020-07-20 11:04                           ` Xiaoliang Yang
2020-06-02  5:18 ` [PATCH v2 net-next 04/10] net: mscc: ocelot: change vcap to be compatible with full and quad entry Xiaoliang Yang
2020-06-02  5:18 ` [PATCH v2 net-next 05/10] net: mscc: ocelot: VCAP IS1 support Xiaoliang Yang
2020-06-02 16:16   ` Jakub Kicinski
2020-06-02  5:18 ` [PATCH v2 net-next 06/10] net: mscc: ocelot: VCAP ES0 support Xiaoliang Yang
2020-06-02 16:17   ` Jakub Kicinski
2020-06-02  5:18 ` [PATCH v2 net-next 07/10] net: mscc: ocelot: multiple actions support Xiaoliang Yang
2020-06-02  5:18 ` [PATCH v2 net-next 08/10] net: ocelot: return error if rule is not found Xiaoliang Yang
2020-06-02  5:18 ` [PATCH v2 net-next 09/10] net: dsa: felix: correct VCAP IS2 keys offset Xiaoliang Yang
2020-06-02  5:18 ` [PATCH v2 net-next 10/10] net: dsa: tag_ocelot: use VLAN information from tagging header when available Xiaoliang Yang
2020-06-02  8:03 ` [PATCH v2 net-next 00/10] net: ocelot: VCAP IS1 and ES0 support Vladimir Oltean
2020-06-02  8:49   ` [EXT] " Xiaoliang Yang
2020-06-09 11:35     ` Vladimir Oltean

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).