Inter-revision diff: patch 4

Comparing v4 (message) to v7 (message)

--- v4
+++ v7
@@ -1,172 +1,549 @@
-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.
+VSC9959 supports Per-Stream Filtering and Policing(PSFP) that complies
+with the IEEE 802.1Qci standard. The stream is identified by Null stream
+identification(DMAC and VLAN ID) defined in IEEE802.1CB.
+
+For PSFP, four tables need to be set up: stream table, stream filter
+table, stream gate table, and flow meter table. Identify the stream by
+parsing the tc flower keys and add it to the stream table. The stream
+filter table is automatically maintained, and its index is determined by
+SGID(flow gate index) and FMID(flow meter index).
 
 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/dsa/ocelot/felix_vsc9959.c | 443 ++++++++++++++++++++++++-
+ include/soc/mscc/ocelot.h              |   8 +
+ include/soc/mscc/ocelot_ana.h          |  10 +
+ 3 files changed, 451 insertions(+), 10 deletions(-)
 
-diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
-index 689c800caa54..565dc5cc42c3 100644
---- a/drivers/net/ethernet/mscc/ocelot.c
-+++ b/drivers/net/ethernet/mscc/ocelot.c
-@@ -2147,6 +2147,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 ce812194e44c..daeaee99933d 100644
---- a/drivers/net/ethernet/mscc/ocelot_flower.c
-+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
-@@ -220,10 +220,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) {
-@@ -356,6 +360,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;
-@@ -646,6 +658,10 @@ static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
- 	if (ret)
- 		return ret;
- 
-+	/* PSFP filter need to parse key by stream identification function. */
-+	if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD)
-+		return 0;
-+
- 	return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
+diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
+index 45c5ec7a83ea..d643e926d1bd 100644
+--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
+@@ -5,6 +5,7 @@
+ #include <linux/fsl/enetc_mdio.h>
+ #include <soc/mscc/ocelot_qsys.h>
+ #include <soc/mscc/ocelot_vcap.h>
++#include <soc/mscc/ocelot_ana.h>
+ #include <soc/mscc/ocelot_ptp.h>
+ #include <soc/mscc/ocelot_sys.h>
+ #include <soc/mscc/ocelot.h>
+@@ -292,7 +293,7 @@ static const u32 vsc9959_sys_regmap[] = {
+ 	REG_RESERVED(SYS_MMGT_FAST),
+ 	REG_RESERVED(SYS_EVENTS_DIF),
+ 	REG_RESERVED(SYS_EVENTS_CORE),
+-	REG_RESERVED(SYS_CNT),
++	REG(SYS_CNT,				0x000000),
+ 	REG(SYS_PTP_STATUS,			0x000f14),
+ 	REG(SYS_PTP_TXSTAMP,			0x000f18),
+ 	REG(SYS_PTP_NXT,			0x000f1c),
+@@ -1020,15 +1021,6 @@ static void vsc9959_wm_stat(u32 val, u32 *inuse, u32 *maxuse)
+ 	*maxuse = val & GENMASK(11, 0);
  }
  
-@@ -718,6 +734,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);
+-static const struct ocelot_ops vsc9959_ops = {
+-	.reset			= vsc9959_reset,
+-	.wm_enc			= vsc9959_wm_enc,
+-	.wm_dec			= vsc9959_wm_dec,
+-	.wm_stat		= vsc9959_wm_stat,
+-	.port_to_netdev		= felix_port_to_netdev,
+-	.netdev_to_port		= felix_netdev_to_port,
+-};
+-
+ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
+ {
+ 	struct felix *felix = ocelot_to_felix(ocelot);
+@@ -1344,6 +1336,437 @@ static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port,
+ 	}
+ }
  
-+	if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD) {
-+		kfree(filter);
-+		if (ocelot->ops->psfp_filter_add)
-+			return ocelot->ops->psfp_filter_add(ocelot, f);
-+
-+		NL_SET_ERR_MSG_MOD(extack, "PSFP chain is not supported in HW");
++#define VSC9959_PSFP_SFID_MAX			175
++#define VSC9959_PSFP_GATE_ID_MAX		183
++#define VSC9959_PSFP_POLICER_MAX		383
++
++struct felix_stream {
++	struct list_head list;
++	unsigned long id;
++	u8 dmac[ETH_ALEN];
++	u16 vid;
++	s8 prio;
++	u8 sfid_valid;
++	u8 ssid_valid;
++	u32 sfid;
++	u32 ssid;
++};
++
++struct felix_stream_filter {
++	struct list_head list;
++	refcount_t refcount;
++	u32 index;
++	u8 enable;
++	u8 sg_valid;
++	u32 sgid;
++	u8 fm_valid;
++	u32 fmid;
++	u8 prio_valid;
++	u8 prio;
++	u32 maxsdu;
++};
++
++struct felix_stream_filter_counters {
++	u32 match;
++	u32 not_pass_gate;
++	u32 not_pass_sdu;
++	u32 red;
++};
++
++static int vsc9959_stream_identify(struct flow_cls_offload *f,
++				   struct felix_stream *stream)
++{
++	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
++	struct flow_dissector *dissector = rule->match.dissector;
++
++	if (dissector->used_keys &
++	    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
++	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
++	      BIT(FLOW_DISSECTOR_KEY_VLAN) |
++	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS)))
 +		return -EOPNOTSUPP;
-+	}
-+
- 	return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
- }
- EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
-@@ -733,6 +758,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);
-+
++
++	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
++		struct flow_match_eth_addrs match;
++
++		flow_rule_match_eth_addrs(rule, &match);
++		ether_addr_copy(stream->dmac, match.key->dst);
++		if (!is_zero_ether_addr(match.mask->src))
++			return -EOPNOTSUPP;
++	} else {
 +		return -EOPNOTSUPP;
 +	}
 +
- 	block = &ocelot->block[block_id];
- 
- 	filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
-@@ -751,12 +783,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;
- 	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;
++	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
++		struct flow_match_vlan match;
++
++		flow_rule_match_vlan(rule, &match);
++		if (match.mask->vlan_priority)
++			stream->prio = match.key->vlan_priority;
++		else
++			stream->prio = -1;
++
++		if (!match.mask->vlan_id)
++			return -EOPNOTSUPP;
++		stream->vid = match.key->vlan_id;
++	} else {
++		return -EOPNOTSUPP;
++	}
++
++	stream->id = f->cookie;
++
++	return 0;
++}
++
++static int vsc9959_mact_stream_set(struct ocelot *ocelot,
++				   struct felix_stream *stream,
++				   struct netlink_ext_ack *extack)
++{
++	enum macaccess_entry_type type;
++	int ret, sfid, ssid;
++	u32 vid, dst_idx;
++	u8 mac[ETH_ALEN];
++
++	ether_addr_copy(mac, stream->dmac);
++	vid = stream->vid;
++
++	/* Stream identification desn't support to add a stream with non
++	 * existent MAC (The MAC entry has not been learned in MAC table).
++	 */
++	ret = ocelot_mact_lookup(ocelot, &dst_idx, mac, vid, &type);
++	if (ret) {
++		if (extack)
++			NL_SET_ERR_MSG_MOD(extack, "Stream is not learned in MAC table");
++		return -EOPNOTSUPP;
++	}
++
++	if ((stream->sfid_valid || stream->ssid_valid) &&
++	    type == ENTRYTYPE_NORMAL)
++		type = ENTRYTYPE_LOCKED;
++
++	sfid = stream->sfid_valid ? stream->sfid : -1;
++	ssid = stream->ssid_valid ? stream->ssid : -1;
++
++	ret = ocelot_mact_learn_streamdata(ocelot, dst_idx, mac, vid, type,
++					   sfid, ssid);
++
++	return ret;
++}
++
++static struct felix_stream *
++vsc9959_stream_table_lookup(struct list_head *stream_list,
++			    struct felix_stream *stream)
++{
++	struct felix_stream *tmp;
++
++	list_for_each_entry(tmp, stream_list, list)
++		if (ether_addr_equal(tmp->dmac, stream->dmac) &&
++		    tmp->vid == stream->vid)
++			return tmp;
++
++	return NULL;
++}
++
++static int vsc9959_stream_table_add(struct ocelot *ocelot,
++				    struct list_head *stream_list,
++				    struct felix_stream *stream,
++				    struct netlink_ext_ack *extack)
++{
++	struct felix_stream *stream_entry;
++	int ret;
++
++	stream_entry = kzalloc(sizeof(*stream_entry), GFP_KERNEL);
++	if (!stream_entry)
++		return -ENOMEM;
++
++	memcpy(stream_entry, stream, sizeof(*stream_entry));
++
++	ret = vsc9959_mact_stream_set(ocelot, stream_entry, extack);
++	if (ret) {
++		kfree(stream_entry);
++		return ret;
++	}
++
++	list_add_tail(&stream_entry->list, stream_list);
++
++	return 0;
++}
++
++static struct felix_stream *
++vsc9959_stream_table_get(struct list_head *stream_list, unsigned long id)
++{
++	struct felix_stream *tmp;
++
++	list_for_each_entry(tmp, stream_list, list)
++		if (tmp->id == id)
++			return tmp;
++
++	return NULL;
++}
++
++static void vsc9959_stream_table_del(struct ocelot *ocelot,
++				     struct felix_stream *stream)
++{
++	vsc9959_mact_stream_set(ocelot, stream, NULL);
++
++	list_del(&stream->list);
++	kfree(stream);
++}
++
++static u32 vsc9959_sfi_access_status(struct ocelot *ocelot)
++{
++	return ocelot_read(ocelot, ANA_TABLES_SFIDACCESS);
++}
++
++static int vsc9959_psfp_sfi_set(struct ocelot *ocelot,
++				struct felix_stream_filter *sfi)
++{
++	u32 val;
++
++	if (sfi->index > VSC9959_PSFP_SFID_MAX)
++		return -EINVAL;
++
++	if (!sfi->enable) {
++		ocelot_write(ocelot, ANA_TABLES_SFIDTIDX_SFID_INDEX(sfi->index),
++			     ANA_TABLES_SFIDTIDX);
++
++		val = ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE);
++		ocelot_write(ocelot, val, ANA_TABLES_SFIDACCESS);
++
++		return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val,
++					  (!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)),
++					  10, 100000);
++	}
++
++	if (sfi->sgid > VSC9959_PSFP_GATE_ID_MAX ||
++	    sfi->fmid > VSC9959_PSFP_POLICER_MAX)
++		return -EINVAL;
++
++	ocelot_write(ocelot,
++		     (sfi->sg_valid ? ANA_TABLES_SFIDTIDX_SGID_VALID : 0) |
++		     ANA_TABLES_SFIDTIDX_SGID(sfi->sgid) |
++		     (sfi->fm_valid ? ANA_TABLES_SFIDTIDX_POL_ENA : 0) |
++		     ANA_TABLES_SFIDTIDX_POL_IDX(sfi->fmid) |
++		     ANA_TABLES_SFIDTIDX_SFID_INDEX(sfi->index),
++		     ANA_TABLES_SFIDTIDX);
++
++	ocelot_write(ocelot,
++		     (sfi->prio_valid ? ANA_TABLES_SFIDACCESS_IGR_PRIO_MATCH_ENA : 0) |
++		     ANA_TABLES_SFIDACCESS_IGR_PRIO(sfi->prio) |
++		     ANA_TABLES_SFIDACCESS_MAX_SDU_LEN(sfi->maxsdu) |
++		     ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE),
++		     ANA_TABLES_SFIDACCESS);
++
++	return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val,
++				  (!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)),
++				  10, 100000);
++}
++
++static int vsc9959_psfp_sfi_table_add(struct ocelot *ocelot,
++				      struct felix_stream_filter *sfi)
++{
++	struct felix_stream_filter *sfi_entry, *tmp;
++	struct list_head *pos, *q, *last;
++	struct ocelot_psfp_list *psfp;
++	u32 insert = 0;
++	int ret;
++
++	psfp = &ocelot->psfp;
++	last = &psfp->sfi_list;
++
++	list_for_each_safe(pos, q, &psfp->sfi_list) {
++		tmp = list_entry(pos, struct felix_stream_filter, list);
++		if (sfi->sg_valid == tmp->sg_valid &&
++		    sfi->fm_valid == tmp->fm_valid &&
++		    tmp->sgid == sfi->sgid &&
++		    tmp->fmid == sfi->fmid) {
++			sfi->index = tmp->index;
++			refcount_inc(&tmp->refcount);
++			return 0;
 +		}
-+
-+		return -EOPNOTSUPP;
-+	}
-+
- 	block = &ocelot->block[block_id];
- 
- 	filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
-@@ -767,7 +812,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, 0, 0x0,
- 			  FLOW_ACTION_HW_STATS_IMMEDIATE);
- 	return 0;
- }
++		/* Make sure that the index is increasing in order. */
++		if (tmp->index == insert) {
++			last = pos;
++			insert++;
++		}
++	}
++	sfi->index = insert;
++
++	sfi_entry = kzalloc(sizeof(*sfi_entry), GFP_KERNEL);
++	if (!sfi_entry)
++		return -ENOMEM;
++
++	memcpy(sfi_entry, sfi, sizeof(*sfi_entry));
++	refcount_set(&sfi_entry->refcount, 1);
++
++	ret = vsc9959_psfp_sfi_set(ocelot, sfi_entry);
++	if (ret) {
++		kfree(sfi_entry);
++		return ret;
++	}
++
++	list_add(&sfi_entry->list, last);
++
++	return 0;
++}
++
++static void vsc9959_psfp_sfi_table_del(struct ocelot *ocelot, u32 index)
++{
++	struct felix_stream_filter *tmp, *n;
++	struct ocelot_psfp_list *psfp;
++	u8 z;
++
++	psfp = &ocelot->psfp;
++
++	list_for_each_entry_safe(tmp, n, &psfp->sfi_list, list)
++		if (tmp->index == index) {
++			z = refcount_dec_and_test(&tmp->refcount);
++			if (z) {
++				tmp->enable = 0;
++				vsc9959_psfp_sfi_set(ocelot, tmp);
++				list_del(&tmp->list);
++				kfree(tmp);
++			}
++			break;
++		}
++}
++
++static void vsc9959_psfp_counters_get(struct ocelot *ocelot, u32 index,
++				      struct felix_stream_filter_counters *counters)
++{
++	ocelot_rmw(ocelot, SYS_STAT_CFG_STAT_VIEW(index),
++		   SYS_STAT_CFG_STAT_VIEW_M,
++		   SYS_STAT_CFG);
++
++	counters->match = ocelot_read_gix(ocelot, SYS_CNT, 0x200);
++	counters->not_pass_gate = ocelot_read_gix(ocelot, SYS_CNT, 0x201);
++	counters->not_pass_sdu = ocelot_read_gix(ocelot, SYS_CNT, 0x202);
++	counters->red = ocelot_read_gix(ocelot, SYS_CNT, 0x203);
++
++	/* Clear the PSFP counter. */
++	ocelot_write(ocelot,
++		     SYS_STAT_CFG_STAT_VIEW(index) |
++		     SYS_STAT_CFG_STAT_CLEAR_SHOT(0x10),
++		     SYS_STAT_CFG);
++}
++
++static int vsc9959_psfp_filter_add(struct ocelot *ocelot,
++				   struct flow_cls_offload *f)
++{
++	struct netlink_ext_ack *extack = f->common.extack;
++	struct felix_stream_filter sfi = {0};
++	const struct flow_action_entry *a;
++	struct felix_stream *stream_entry;
++	struct felix_stream stream = {0};
++	struct ocelot_psfp_list *psfp;
++	int ret, i;
++
++	psfp = &ocelot->psfp;
++
++	ret = vsc9959_stream_identify(f, &stream);
++	if (ret) {
++		NL_SET_ERR_MSG_MOD(extack, "Only can match on VID, PCP, and dest MAC");
++		return ret;
++	}
++
++	flow_action_for_each(i, a, &f->rule->action) {
++		switch (a->id) {
++		case FLOW_ACTION_GATE:
++		case FLOW_ACTION_POLICE:
++		default:
++			return -EOPNOTSUPP;
++		}
++	}
++
++	/* Check if stream is set. */
++	stream_entry = vsc9959_stream_table_lookup(&psfp->stream_list, &stream);
++	if (stream_entry) {
++		NL_SET_ERR_MSG_MOD(extack, "This stream is already added");
++		return -EEXIST;
++	}
++
++	sfi.prio_valid = (stream.prio < 0 ? 0 : 1);
++	sfi.prio = (sfi.prio_valid ? stream.prio : 0);
++	sfi.enable = 1;
++
++	ret = vsc9959_psfp_sfi_table_add(ocelot, &sfi);
++	if (ret)
++		return ret;
++
++	stream.sfid = sfi.index;
++	stream.sfid_valid = 1;
++	ret = vsc9959_stream_table_add(ocelot, &psfp->stream_list,
++				       &stream, extack);
++	if (ret)
++		vsc9959_psfp_sfi_table_del(ocelot, stream.sfid);
++
++	return ret;
++}
++
++static int vsc9959_psfp_filter_del(struct ocelot *ocelot,
++				   struct flow_cls_offload *f)
++{
++	struct ocelot_psfp_list *psfp;
++	struct felix_stream *stream;
++
++	psfp = &ocelot->psfp;
++
++	stream = vsc9959_stream_table_get(&psfp->stream_list, f->cookie);
++	if (!stream)
++		return -ENOMEM;
++
++	vsc9959_psfp_sfi_table_del(ocelot, stream->sfid);
++
++	stream->sfid_valid = 0;
++	vsc9959_stream_table_del(ocelot, stream);
++
++	return 0;
++}
++
++static int vsc9959_psfp_stats_get(struct ocelot *ocelot,
++				  struct flow_cls_offload *f,
++				  struct flow_stats *stats)
++{
++	struct felix_stream_filter_counters counters;
++	struct ocelot_psfp_list *psfp;
++	struct felix_stream *stream;
++
++	psfp = &ocelot->psfp;
++	stream = vsc9959_stream_table_get(&psfp->stream_list, f->cookie);
++	if (!stream)
++		return -ENOMEM;
++
++	vsc9959_psfp_counters_get(ocelot, stream->sfid, &counters);
++
++	stats->pkts = counters.match;
++	stats->drops = counters.not_pass_gate + counters.not_pass_sdu +
++		       counters.red;
++
++	return 0;
++}
++
++static void vsc9959_psfp_init(struct ocelot *ocelot)
++{
++	struct ocelot_psfp_list *psfp = &ocelot->psfp;
++
++	INIT_LIST_HEAD(&psfp->stream_list);
++	INIT_LIST_HEAD(&psfp->sfi_list);
++	INIT_LIST_HEAD(&psfp->sgi_list);
++}
++
++static const struct ocelot_ops vsc9959_ops = {
++	.reset			= vsc9959_reset,
++	.wm_enc			= vsc9959_wm_enc,
++	.wm_dec			= vsc9959_wm_dec,
++	.wm_stat		= vsc9959_wm_stat,
++	.port_to_netdev		= felix_port_to_netdev,
++	.netdev_to_port		= felix_netdev_to_port,
++	.psfp_init		= vsc9959_psfp_init,
++	.psfp_filter_add	= vsc9959_psfp_filter_add,
++	.psfp_filter_del	= vsc9959_psfp_filter_del,
++	.psfp_stats_get		= vsc9959_psfp_stats_get,
++};
++
+ static const struct felix_info felix_info_vsc9959 = {
+ 	.target_io_res		= vsc9959_target_io_res,
+ 	.port_io_res		= vsc9959_port_io_res,
 diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
-index babaa5b0c026..096c38c65157 100644
+index e9985ace59c0..5ea72d274d7f 100644
 --- a/include/soc/mscc/ocelot.h
 +++ b/include/soc/mscc/ocelot.h
-@@ -564,6 +564,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);
+@@ -586,6 +586,12 @@ enum ocelot_port_tag_config {
+ 	OCELOT_PORT_TAG_TRUNK = 3,
  };
  
- struct ocelot_vcap_block {
-diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h
-index 25fd525aaf92..24b495ce140c 100644
---- a/include/soc/mscc/ocelot_vcap.h
-+++ b/include/soc/mscc/ocelot_vcap.h
-@@ -646,6 +646,7 @@ enum ocelot_vcap_filter_type {
- 	OCELOT_VCAP_FILTER_DUMMY,
- 	OCELOT_VCAP_FILTER_PAG,
- 	OCELOT_VCAP_FILTER_OFFLOAD,
-+	OCELOT_PSFP_FILTER_OFFLOAD,
- };
++struct ocelot_psfp_list {
++	struct list_head stream_list;
++	struct list_head sfi_list;
++	struct list_head sgi_list;
++};
++
+ enum ocelot_sb {
+ 	OCELOT_SB_BUF,
+ 	OCELOT_SB_REF,
+@@ -687,6 +693,8 @@ struct ocelot {
+ 	struct ocelot_vcap_block	block[3];
+ 	struct vcap_props		*vcap;
  
- struct ocelot_vcap_id {
++	struct ocelot_psfp_list		psfp;
++
+ 	/* Workqueue to check statistics for overflow with its lock */
+ 	struct mutex			stats_lock;
+ 	u64				*stats;
+diff --git a/include/soc/mscc/ocelot_ana.h b/include/soc/mscc/ocelot_ana.h
+index 1669481d9779..67e0ae05a5ab 100644
+--- a/include/soc/mscc/ocelot_ana.h
++++ b/include/soc/mscc/ocelot_ana.h
+@@ -227,6 +227,11 @@
+ #define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(x)             ((x) & GENMASK(1, 0))
+ #define ANA_TABLES_SFIDACCESS_SFID_TBL_CMD_M              GENMASK(1, 0)
+ 
++#define SFIDACCESS_CMD_IDLE                               0
++#define SFIDACCESS_CMD_READ                               1
++#define SFIDACCESS_CMD_WRITE                              2
++#define SFIDACCESS_CMD_INIT                               3
++
+ #define ANA_TABLES_SFIDTIDX_SGID_VALID                    BIT(26)
+ #define ANA_TABLES_SFIDTIDX_SGID(x)                       (((x) << 18) & GENMASK(25, 18))
+ #define ANA_TABLES_SFIDTIDX_SGID_M                        GENMASK(25, 18)
+@@ -255,6 +260,11 @@
+ #define ANA_SG_CONFIG_REG_3_INIT_IPS(x)                   (((x) << 21) & GENMASK(24, 21))
+ #define ANA_SG_CONFIG_REG_3_INIT_IPS_M                    GENMASK(24, 21)
+ #define ANA_SG_CONFIG_REG_3_INIT_IPS_X(x)                 (((x) & GENMASK(24, 21)) >> 21)
++#define ANA_SG_CONFIG_REG_3_IPV_VALID                     BIT(24)
++#define ANA_SG_CONFIG_REG_3_IPV_INVALID(x)                (((x) << 24) & GENMASK(24, 24))
++#define ANA_SG_CONFIG_REG_3_INIT_IPV(x)                   (((x) << 21) & GENMASK(23, 21))
++#define ANA_SG_CONFIG_REG_3_INIT_IPV_M                    GENMASK(23, 21)
++#define ANA_SG_CONFIG_REG_3_INIT_IPV_X(x)                 (((x) & GENMASK(23, 21)) >> 21)
+ #define ANA_SG_CONFIG_REG_3_INIT_GATE_STATE               BIT(25)
+ 
+ #define ANA_SG_GCL_GS_CONFIG_RSZ                          0x4
 -- 
 2.17.1
 
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help