--- v7
+++ v4
@@ -1,172 +1,69 @@
-PSFP support gate and police action. This patch add the gate and police
-action to flower parse action, check chain ID to determine which block
-to offload. Adding psfp callback functions to add, delete and update gate
-and police in PSFP table if hardware supports it.
+Some chips in the ocelot series such as VSC9959 support Per-Stream
+Filtering and Policing(PSFP), which is processing after VCAP blocks.
+We set this block on chain 30000 and set vcap IS2 chain to goto PSFP
+chain if hardware support.
Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
---
- drivers/net/ethernet/mscc/ocelot.c | 3 ++
- drivers/net/ethernet/mscc/ocelot_flower.c | 52 ++++++++++++++++++++++-
- include/soc/mscc/ocelot.h | 5 +++
- include/soc/mscc/ocelot_vcap.h | 1 +
- 4 files changed, 59 insertions(+), 2 deletions(-)
+ drivers/net/ethernet/mscc/ocelot_flower.c | 17 ++++++++++++++---
+ 1 file changed, 14 insertions(+), 3 deletions(-)
-diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
-index 9e981913d6ba..95920668feb0 100644
---- a/drivers/net/ethernet/mscc/ocelot.c
-+++ b/drivers/net/ethernet/mscc/ocelot.c
-@@ -2352,6 +2352,9 @@ int ocelot_init(struct ocelot *ocelot)
- ocelot_vcap_init(ocelot);
- ocelot_cpu_port_init(ocelot);
-
-+ if (ocelot->ops->psfp_init)
-+ ocelot->ops->psfp_init(ocelot);
-+
- for (port = 0; port < ocelot->num_phys_ports; port++) {
- /* Clear all counters (5 groups) */
- ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port) |
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
-index ed609bc4398e..b22966e15acf 100644
+index 8b843d3c9189..ce812194e44c 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
-@@ -280,10 +280,14 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
- filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
- break;
- case FLOW_ACTION_POLICE:
-+ if (filter->block_id == PSFP_BLOCK_ID) {
-+ filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
-+ break;
-+ }
- if (filter->block_id != VCAP_IS2 ||
- filter->lookup != 0) {
- NL_SET_ERR_MSG_MOD(extack,
-- "Police action can only be offloaded to VCAP IS2 lookup 0");
-+ "Police action can only be offloaded to VCAP IS2 lookup 0 or PSFP");
- return -EOPNOTSUPP;
- }
- if (filter->goto_target != -1) {
-@@ -410,6 +414,14 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
- filter->action.pcp_a_val = a->vlan.prio;
- filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
- break;
-+ case FLOW_ACTION_GATE:
-+ if (filter->block_id != PSFP_BLOCK_ID) {
-+ NL_SET_ERR_MSG_MOD(extack,
-+ "Gate action can only be offloaded to PSFP chain");
-+ return -EOPNOTSUPP;
-+ }
-+ filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
-+ break;
- default:
- NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
- return -EOPNOTSUPP;
-@@ -700,6 +712,10 @@ static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
- if (ret)
- return ret;
+@@ -20,6 +20,9 @@
+ (1 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP)
+ #define VCAP_IS2_CHAIN(lookup, pag) \
+ (2 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP + (pag))
++/* PSFP chain and block ID */
++#define PSFP_BLOCK_ID OCELOT_NUM_VCAP_BLOCKS
++#define OCELOT_PSFP_CHAIN (3 * VCAP_BLOCK)
-+ /* PSFP filter need to parse key by stream identification function. */
-+ if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD)
-+ return 0;
+ static int ocelot_chain_to_block(int chain, bool ingress)
+ {
+@@ -46,6 +49,9 @@ static int ocelot_chain_to_block(int chain, bool ingress)
+ if (chain == VCAP_IS2_CHAIN(lookup, pag))
+ return VCAP_IS2;
+
++ if (chain == OCELOT_PSFP_CHAIN)
++ return PSFP_BLOCK_ID;
+
- return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
+ return -EOPNOTSUPP;
}
-@@ -803,6 +819,15 @@ int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
- if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
- return ocelot_vcap_dummy_filter_add(ocelot, filter);
+@@ -84,7 +90,8 @@ static bool ocelot_is_goto_target_valid(int goto_target, int chain,
+ goto_target == VCAP_IS1_CHAIN(1) ||
+ goto_target == VCAP_IS1_CHAIN(2) ||
+ goto_target == VCAP_IS2_CHAIN(0, 0) ||
+- goto_target == VCAP_IS2_CHAIN(1, 0));
++ goto_target == VCAP_IS2_CHAIN(1, 0) ||
++ goto_target == OCELOT_PSFP_CHAIN);
-+ if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD) {
-+ kfree(filter);
-+ if (ocelot->ops->psfp_filter_add)
-+ return ocelot->ops->psfp_filter_add(ocelot, f);
+ if (chain == VCAP_IS1_CHAIN(0))
+ return (goto_target == VCAP_IS1_CHAIN(1));
+@@ -111,7 +118,11 @@ static bool ocelot_is_goto_target_valid(int goto_target, int chain,
+ if (chain == VCAP_IS2_CHAIN(0, pag))
+ return (goto_target == VCAP_IS2_CHAIN(1, pag));
+
+- /* VCAP IS2 lookup 1 cannot jump anywhere */
++ /* VCAP IS2 lookup 1 can goto to PSFP block if hardware support */
++ for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
++ if (chain == VCAP_IS2_CHAIN(1, pag))
++ return (goto_target == OCELOT_PSFP_CHAIN);
+
-+ NL_SET_ERR_MSG_MOD(extack, "PSFP chain is not supported in HW");
-+ return -EOPNOTSUPP;
-+ }
-+
- return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
+ return false;
}
- EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
-@@ -818,6 +843,13 @@ int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
- if (block_id < 0)
- return 0;
-+ if (block_id == PSFP_BLOCK_ID) {
-+ if (ocelot->ops->psfp_filter_del)
-+ return ocelot->ops->psfp_filter_del(ocelot, f);
-+
-+ return -EOPNOTSUPP;
-+ }
-+
- block = &ocelot->block[block_id];
+@@ -353,7 +364,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
- filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
-@@ -836,12 +868,25 @@ int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
- {
- struct ocelot_vcap_filter *filter;
- struct ocelot_vcap_block *block;
-+ struct flow_stats stats = {0};
- int block_id, ret;
-
- block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
- if (block_id < 0)
- return 0;
-
-+ if (block_id == PSFP_BLOCK_ID) {
-+ if (ocelot->ops->psfp_stats_get) {
-+ ret = ocelot->ops->psfp_stats_get(ocelot, f, &stats);
-+ if (ret)
-+ return ret;
-+
-+ goto stats_update;
-+ }
-+
-+ return -EOPNOTSUPP;
-+ }
-+
- block = &ocelot->block[block_id];
-
- filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
-@@ -852,7 +897,10 @@ int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
- if (ret)
- return ret;
-
-- flow_stats_update(&f->stats, 0x0, filter->stats.pkts, 0, 0x0,
-+ stats.pkts = filter->stats.pkts;
-+
-+stats_update:
-+ flow_stats_update(&f->stats, 0x0, stats.pkts, stats.drops, 0x0,
- FLOW_ACTION_HW_STATS_IMMEDIATE);
- return 0;
- }
-diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
-index 1d5ff11e4100..e9985ace59c0 100644
---- a/include/soc/mscc/ocelot.h
-+++ b/include/soc/mscc/ocelot.h
-@@ -555,6 +555,11 @@ struct ocelot_ops {
- u16 (*wm_enc)(u16 value);
- u16 (*wm_dec)(u16 value);
- void (*wm_stat)(u32 val, u32 *inuse, u32 *maxuse);
-+ void (*psfp_init)(struct ocelot *ocelot);
-+ int (*psfp_filter_add)(struct ocelot *ocelot, struct flow_cls_offload *f);
-+ int (*psfp_filter_del)(struct ocelot *ocelot, struct flow_cls_offload *f);
-+ int (*psfp_stats_get)(struct ocelot *ocelot, struct flow_cls_offload *f,
-+ struct flow_stats *stats);
- };
-
- struct ocelot_vcap_block {
-diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h
-index eeb1142aa1b1..9cca2f8e61a2 100644
---- a/include/soc/mscc/ocelot_vcap.h
-+++ b/include/soc/mscc/ocelot_vcap.h
-@@ -656,6 +656,7 @@ enum ocelot_vcap_filter_type {
- OCELOT_VCAP_FILTER_DUMMY,
- OCELOT_VCAP_FILTER_PAG,
- OCELOT_VCAP_FILTER_OFFLOAD,
-+ OCELOT_PSFP_FILTER_OFFLOAD,
- };
-
- struct ocelot_vcap_id {
+ if (filter->goto_target == -1) {
+ if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) ||
+- chain == 0) {
++ chain == 0 || filter->block_id == PSFP_BLOCK_ID) {
+ allow_missing_goto_target = true;
+ } else {
+ NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action");
--
2.17.1