xref: /linux/drivers/net/dsa/sja1105/sja1105_flower.c (revision 4b762fee)
1a6af7763SVladimir Oltean // SPDX-License-Identifier: GPL-2.0
23c9cfb52SVladimir Oltean /* Copyright 2020 NXP
3a6af7763SVladimir Oltean  */
4a6af7763SVladimir Oltean #include "sja1105.h"
5dfacc5a2SVladimir Oltean #include "sja1105_vl.h"
6a6af7763SVladimir Oltean 
sja1105_rule_find(struct sja1105_private * priv,unsigned long cookie)7dfacc5a2SVladimir Oltean struct sja1105_rule *sja1105_rule_find(struct sja1105_private *priv,
8a6af7763SVladimir Oltean 				       unsigned long cookie)
9a6af7763SVladimir Oltean {
10a6af7763SVladimir Oltean 	struct sja1105_rule *rule;
11a6af7763SVladimir Oltean 
12a6af7763SVladimir Oltean 	list_for_each_entry(rule, &priv->flow_block.rules, list)
13a6af7763SVladimir Oltean 		if (rule->cookie == cookie)
14a6af7763SVladimir Oltean 			return rule;
15a6af7763SVladimir Oltean 
16a6af7763SVladimir Oltean 	return NULL;
17a6af7763SVladimir Oltean }
18a6af7763SVladimir Oltean 
sja1105_find_free_l2_policer(struct sja1105_private * priv)19a6af7763SVladimir Oltean static int sja1105_find_free_l2_policer(struct sja1105_private *priv)
20a6af7763SVladimir Oltean {
21a6af7763SVladimir Oltean 	int i;
22a6af7763SVladimir Oltean 
23a6af7763SVladimir Oltean 	for (i = 0; i < SJA1105_NUM_L2_POLICERS; i++)
24a6af7763SVladimir Oltean 		if (!priv->flow_block.l2_policer_used[i])
25a6af7763SVladimir Oltean 			return i;
26a6af7763SVladimir Oltean 
27a6af7763SVladimir Oltean 	return -1;
28a6af7763SVladimir Oltean }
29a6af7763SVladimir Oltean 
sja1105_setup_bcast_policer(struct sja1105_private * priv,struct netlink_ext_ack * extack,unsigned long cookie,int port,u64 rate_bytes_per_sec,u32 burst)30a6af7763SVladimir Oltean static int sja1105_setup_bcast_policer(struct sja1105_private *priv,
31a6af7763SVladimir Oltean 				       struct netlink_ext_ack *extack,
32a6af7763SVladimir Oltean 				       unsigned long cookie, int port,
33a6af7763SVladimir Oltean 				       u64 rate_bytes_per_sec,
345f035af7SPo Liu 				       u32 burst)
35a6af7763SVladimir Oltean {
36a6af7763SVladimir Oltean 	struct sja1105_rule *rule = sja1105_rule_find(priv, cookie);
37a6af7763SVladimir Oltean 	struct sja1105_l2_policing_entry *policing;
38542043e9SVladimir Oltean 	struct dsa_switch *ds = priv->ds;
39a6af7763SVladimir Oltean 	bool new_rule = false;
40a6af7763SVladimir Oltean 	unsigned long p;
41a6af7763SVladimir Oltean 	int rc;
42a6af7763SVladimir Oltean 
43a6af7763SVladimir Oltean 	if (!rule) {
44a6af7763SVladimir Oltean 		rule = kzalloc(sizeof(*rule), GFP_KERNEL);
45a6af7763SVladimir Oltean 		if (!rule)
46a6af7763SVladimir Oltean 			return -ENOMEM;
47a6af7763SVladimir Oltean 
48a6af7763SVladimir Oltean 		rule->cookie = cookie;
49a6af7763SVladimir Oltean 		rule->type = SJA1105_RULE_BCAST_POLICER;
50a6af7763SVladimir Oltean 		rule->bcast_pol.sharindx = sja1105_find_free_l2_policer(priv);
51b70bb8d4SVladimir Oltean 		rule->key.type = SJA1105_KEY_BCAST;
52a6af7763SVladimir Oltean 		new_rule = true;
53a6af7763SVladimir Oltean 	}
54a6af7763SVladimir Oltean 
55a6af7763SVladimir Oltean 	if (rule->bcast_pol.sharindx == -1) {
56a6af7763SVladimir Oltean 		NL_SET_ERR_MSG_MOD(extack, "No more L2 policers free");
57a6af7763SVladimir Oltean 		rc = -ENOSPC;
58a6af7763SVladimir Oltean 		goto out;
59a6af7763SVladimir Oltean 	}
60a6af7763SVladimir Oltean 
61a6af7763SVladimir Oltean 	policing = priv->static_config.tables[BLK_IDX_L2_POLICING].entries;
62a6af7763SVladimir Oltean 
63542043e9SVladimir Oltean 	if (policing[(ds->num_ports * SJA1105_NUM_TC) + port].sharindx != port) {
64a6af7763SVladimir Oltean 		NL_SET_ERR_MSG_MOD(extack,
65a6af7763SVladimir Oltean 				   "Port already has a broadcast policer");
66a6af7763SVladimir Oltean 		rc = -EEXIST;
67a6af7763SVladimir Oltean 		goto out;
68a6af7763SVladimir Oltean 	}
69a6af7763SVladimir Oltean 
70a6af7763SVladimir Oltean 	rule->port_mask |= BIT(port);
71a6af7763SVladimir Oltean 
72a6af7763SVladimir Oltean 	/* Make the broadcast policers of all ports attached to this block
73a6af7763SVladimir Oltean 	 * point to the newly allocated policer
74a6af7763SVladimir Oltean 	 */
7582760d7fSVladimir Oltean 	for_each_set_bit(p, &rule->port_mask, SJA1105_MAX_NUM_PORTS) {
76542043e9SVladimir Oltean 		int bcast = (ds->num_ports * SJA1105_NUM_TC) + p;
77a6af7763SVladimir Oltean 
78a6af7763SVladimir Oltean 		policing[bcast].sharindx = rule->bcast_pol.sharindx;
79a6af7763SVladimir Oltean 	}
80a6af7763SVladimir Oltean 
81a6af7763SVladimir Oltean 	policing[rule->bcast_pol.sharindx].rate = div_u64(rate_bytes_per_sec *
82a6af7763SVladimir Oltean 							  512, 1000000);
835f035af7SPo Liu 	policing[rule->bcast_pol.sharindx].smax = burst;
845f035af7SPo Liu 
85a6af7763SVladimir Oltean 	/* TODO: support per-flow MTU */
86a6af7763SVladimir Oltean 	policing[rule->bcast_pol.sharindx].maxlen = VLAN_ETH_FRAME_LEN +
87a6af7763SVladimir Oltean 						    ETH_FCS_LEN;
88a6af7763SVladimir Oltean 
89a6af7763SVladimir Oltean 	rc = sja1105_static_config_reload(priv, SJA1105_BEST_EFFORT_POLICING);
90a6af7763SVladimir Oltean 
91a6af7763SVladimir Oltean out:
92a6af7763SVladimir Oltean 	if (rc == 0 && new_rule) {
93a6af7763SVladimir Oltean 		priv->flow_block.l2_policer_used[rule->bcast_pol.sharindx] = true;
94a6af7763SVladimir Oltean 		list_add(&rule->list, &priv->flow_block.rules);
95a6af7763SVladimir Oltean 	} else if (new_rule) {
96a6af7763SVladimir Oltean 		kfree(rule);
97a6af7763SVladimir Oltean 	}
98a6af7763SVladimir Oltean 
99a6af7763SVladimir Oltean 	return rc;
100a6af7763SVladimir Oltean }
101a6af7763SVladimir Oltean 
sja1105_setup_tc_policer(struct sja1105_private * priv,struct netlink_ext_ack * extack,unsigned long cookie,int port,int tc,u64 rate_bytes_per_sec,u32 burst)102a6af7763SVladimir Oltean static int sja1105_setup_tc_policer(struct sja1105_private *priv,
103a6af7763SVladimir Oltean 				    struct netlink_ext_ack *extack,
104a6af7763SVladimir Oltean 				    unsigned long cookie, int port, int tc,
105a6af7763SVladimir Oltean 				    u64 rate_bytes_per_sec,
1065f035af7SPo Liu 				    u32 burst)
107a6af7763SVladimir Oltean {
108a6af7763SVladimir Oltean 	struct sja1105_rule *rule = sja1105_rule_find(priv, cookie);
109a6af7763SVladimir Oltean 	struct sja1105_l2_policing_entry *policing;
110a6af7763SVladimir Oltean 	bool new_rule = false;
111a6af7763SVladimir Oltean 	unsigned long p;
112a6af7763SVladimir Oltean 	int rc;
113a6af7763SVladimir Oltean 
114a6af7763SVladimir Oltean 	if (!rule) {
115a6af7763SVladimir Oltean 		rule = kzalloc(sizeof(*rule), GFP_KERNEL);
116a6af7763SVladimir Oltean 		if (!rule)
117a6af7763SVladimir Oltean 			return -ENOMEM;
118a6af7763SVladimir Oltean 
119a6af7763SVladimir Oltean 		rule->cookie = cookie;
120a6af7763SVladimir Oltean 		rule->type = SJA1105_RULE_TC_POLICER;
121a6af7763SVladimir Oltean 		rule->tc_pol.sharindx = sja1105_find_free_l2_policer(priv);
122b70bb8d4SVladimir Oltean 		rule->key.type = SJA1105_KEY_TC;
123b70bb8d4SVladimir Oltean 		rule->key.tc.pcp = tc;
124a6af7763SVladimir Oltean 		new_rule = true;
125a6af7763SVladimir Oltean 	}
126a6af7763SVladimir Oltean 
127a6af7763SVladimir Oltean 	if (rule->tc_pol.sharindx == -1) {
128a6af7763SVladimir Oltean 		NL_SET_ERR_MSG_MOD(extack, "No more L2 policers free");
129a6af7763SVladimir Oltean 		rc = -ENOSPC;
130a6af7763SVladimir Oltean 		goto out;
131a6af7763SVladimir Oltean 	}
132a6af7763SVladimir Oltean 
133a6af7763SVladimir Oltean 	policing = priv->static_config.tables[BLK_IDX_L2_POLICING].entries;
134a6af7763SVladimir Oltean 
135a6af7763SVladimir Oltean 	if (policing[(port * SJA1105_NUM_TC) + tc].sharindx != port) {
136a6af7763SVladimir Oltean 		NL_SET_ERR_MSG_MOD(extack,
137a6af7763SVladimir Oltean 				   "Port-TC pair already has an L2 policer");
138a6af7763SVladimir Oltean 		rc = -EEXIST;
139a6af7763SVladimir Oltean 		goto out;
140a6af7763SVladimir Oltean 	}
141a6af7763SVladimir Oltean 
142a6af7763SVladimir Oltean 	rule->port_mask |= BIT(port);
143a6af7763SVladimir Oltean 
144a6af7763SVladimir Oltean 	/* Make the policers for traffic class @tc of all ports attached to
145a6af7763SVladimir Oltean 	 * this block point to the newly allocated policer
146a6af7763SVladimir Oltean 	 */
14782760d7fSVladimir Oltean 	for_each_set_bit(p, &rule->port_mask, SJA1105_MAX_NUM_PORTS) {
148a6af7763SVladimir Oltean 		int index = (p * SJA1105_NUM_TC) + tc;
149a6af7763SVladimir Oltean 
150a6af7763SVladimir Oltean 		policing[index].sharindx = rule->tc_pol.sharindx;
151a6af7763SVladimir Oltean 	}
152a6af7763SVladimir Oltean 
153a6af7763SVladimir Oltean 	policing[rule->tc_pol.sharindx].rate = div_u64(rate_bytes_per_sec *
154a6af7763SVladimir Oltean 						       512, 1000000);
1555f035af7SPo Liu 	policing[rule->tc_pol.sharindx].smax = burst;
1565f035af7SPo Liu 
157a6af7763SVladimir Oltean 	/* TODO: support per-flow MTU */
158a6af7763SVladimir Oltean 	policing[rule->tc_pol.sharindx].maxlen = VLAN_ETH_FRAME_LEN +
159a6af7763SVladimir Oltean 						 ETH_FCS_LEN;
160a6af7763SVladimir Oltean 
161a6af7763SVladimir Oltean 	rc = sja1105_static_config_reload(priv, SJA1105_BEST_EFFORT_POLICING);
162a6af7763SVladimir Oltean 
163a6af7763SVladimir Oltean out:
164a6af7763SVladimir Oltean 	if (rc == 0 && new_rule) {
165a6af7763SVladimir Oltean 		priv->flow_block.l2_policer_used[rule->tc_pol.sharindx] = true;
166a6af7763SVladimir Oltean 		list_add(&rule->list, &priv->flow_block.rules);
167a6af7763SVladimir Oltean 	} else if (new_rule) {
168a6af7763SVladimir Oltean 		kfree(rule);
169a6af7763SVladimir Oltean 	}
170a6af7763SVladimir Oltean 
171a6af7763SVladimir Oltean 	return rc;
172a6af7763SVladimir Oltean }
173a6af7763SVladimir Oltean 
sja1105_flower_policer(struct sja1105_private * priv,int port,struct netlink_ext_ack * extack,unsigned long cookie,struct sja1105_key * key,u64 rate_bytes_per_sec,u32 burst)174b70bb8d4SVladimir Oltean static int sja1105_flower_policer(struct sja1105_private *priv, int port,
175a6af7763SVladimir Oltean 				  struct netlink_ext_ack *extack,
176dfacc5a2SVladimir Oltean 				  unsigned long cookie,
177dfacc5a2SVladimir Oltean 				  struct sja1105_key *key,
178a6af7763SVladimir Oltean 				  u64 rate_bytes_per_sec,
1795f035af7SPo Liu 				  u32 burst)
180a6af7763SVladimir Oltean {
181b70bb8d4SVladimir Oltean 	switch (key->type) {
182b70bb8d4SVladimir Oltean 	case SJA1105_KEY_BCAST:
183b70bb8d4SVladimir Oltean 		return sja1105_setup_bcast_policer(priv, extack, cookie, port,
184b70bb8d4SVladimir Oltean 						   rate_bytes_per_sec, burst);
185b70bb8d4SVladimir Oltean 	case SJA1105_KEY_TC:
186b70bb8d4SVladimir Oltean 		return sja1105_setup_tc_policer(priv, extack, cookie, port,
187b70bb8d4SVladimir Oltean 						key->tc.pcp, rate_bytes_per_sec,
188b70bb8d4SVladimir Oltean 						burst);
189b70bb8d4SVladimir Oltean 	default:
190b70bb8d4SVladimir Oltean 		NL_SET_ERR_MSG_MOD(extack, "Unknown keys for policing");
191b70bb8d4SVladimir Oltean 		return -EOPNOTSUPP;
192b70bb8d4SVladimir Oltean 	}
193b70bb8d4SVladimir Oltean }
194b70bb8d4SVladimir Oltean 
sja1105_flower_parse_key(struct sja1105_private * priv,struct netlink_ext_ack * extack,struct flow_cls_offload * cls,struct sja1105_key * key)195b70bb8d4SVladimir Oltean static int sja1105_flower_parse_key(struct sja1105_private *priv,
196b70bb8d4SVladimir Oltean 				    struct netlink_ext_ack *extack,
197b70bb8d4SVladimir Oltean 				    struct flow_cls_offload *cls,
198b70bb8d4SVladimir Oltean 				    struct sja1105_key *key)
199b70bb8d4SVladimir Oltean {
200a6af7763SVladimir Oltean 	struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
201a6af7763SVladimir Oltean 	struct flow_dissector *dissector = rule->match.dissector;
202b70bb8d4SVladimir Oltean 	bool is_bcast_dmac = false;
203b70bb8d4SVladimir Oltean 	u64 dmac = U64_MAX;
204b70bb8d4SVladimir Oltean 	u16 vid = U16_MAX;
205b70bb8d4SVladimir Oltean 	u16 pcp = U16_MAX;
206a6af7763SVladimir Oltean 
207a6af7763SVladimir Oltean 	if (dissector->used_keys &
2082b3082c6SRatheesh Kannoth 	    ~(BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
2092b3082c6SRatheesh Kannoth 	      BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
2102b3082c6SRatheesh Kannoth 	      BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
2112b3082c6SRatheesh Kannoth 	      BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
212a6af7763SVladimir Oltean 		NL_SET_ERR_MSG_MOD(extack,
213a6af7763SVladimir Oltean 				   "Unsupported keys used");
214a6af7763SVladimir Oltean 		return -EOPNOTSUPP;
215a6af7763SVladimir Oltean 	}
216a6af7763SVladimir Oltean 
217*4b762feeSAsbjørn Sloth Tønnesen 	if (flow_rule_match_has_control_flags(rule, extack))
218*4b762feeSAsbjørn Sloth Tønnesen 		return -EOPNOTSUPP;
219*4b762feeSAsbjørn Sloth Tønnesen 
220a6af7763SVladimir Oltean 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
221a6af7763SVladimir Oltean 		struct flow_match_basic match;
222a6af7763SVladimir Oltean 
223a6af7763SVladimir Oltean 		flow_rule_match_basic(rule, &match);
224a6af7763SVladimir Oltean 		if (match.key->n_proto) {
225a6af7763SVladimir Oltean 			NL_SET_ERR_MSG_MOD(extack,
226a6af7763SVladimir Oltean 					   "Matching on protocol not supported");
227a6af7763SVladimir Oltean 			return -EOPNOTSUPP;
228a6af7763SVladimir Oltean 		}
229a6af7763SVladimir Oltean 	}
230a6af7763SVladimir Oltean 
231a6af7763SVladimir Oltean 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
232a6af7763SVladimir Oltean 		u8 bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
233a6af7763SVladimir Oltean 		u8 null[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
234a6af7763SVladimir Oltean 		struct flow_match_eth_addrs match;
235a6af7763SVladimir Oltean 
236a6af7763SVladimir Oltean 		flow_rule_match_eth_addrs(rule, &match);
237a6af7763SVladimir Oltean 
238a6af7763SVladimir Oltean 		if (!ether_addr_equal_masked(match.key->src, null,
239a6af7763SVladimir Oltean 					     match.mask->src)) {
240a6af7763SVladimir Oltean 			NL_SET_ERR_MSG_MOD(extack,
241a6af7763SVladimir Oltean 					   "Matching on source MAC not supported");
242a6af7763SVladimir Oltean 			return -EOPNOTSUPP;
243a6af7763SVladimir Oltean 		}
244a6af7763SVladimir Oltean 
245b70bb8d4SVladimir Oltean 		if (!ether_addr_equal(match.mask->dst, bcast)) {
246a6af7763SVladimir Oltean 			NL_SET_ERR_MSG_MOD(extack,
247b70bb8d4SVladimir Oltean 					   "Masked matching on MAC not supported");
248a6af7763SVladimir Oltean 			return -EOPNOTSUPP;
249a6af7763SVladimir Oltean 		}
250a6af7763SVladimir Oltean 
251b70bb8d4SVladimir Oltean 		dmac = ether_addr_to_u64(match.key->dst);
252b70bb8d4SVladimir Oltean 		is_bcast_dmac = ether_addr_equal(match.key->dst, bcast);
253a6af7763SVladimir Oltean 	}
254a6af7763SVladimir Oltean 
255a6af7763SVladimir Oltean 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
256a6af7763SVladimir Oltean 		struct flow_match_vlan match;
257a6af7763SVladimir Oltean 
258a6af7763SVladimir Oltean 		flow_rule_match_vlan(rule, &match);
259a6af7763SVladimir Oltean 
260b70bb8d4SVladimir Oltean 		if (match.mask->vlan_id &&
261b70bb8d4SVladimir Oltean 		    match.mask->vlan_id != VLAN_VID_MASK) {
262a6af7763SVladimir Oltean 			NL_SET_ERR_MSG_MOD(extack,
263b70bb8d4SVladimir Oltean 					   "Masked matching on VID is not supported");
264a6af7763SVladimir Oltean 			return -EOPNOTSUPP;
265a6af7763SVladimir Oltean 		}
266a6af7763SVladimir Oltean 
267b70bb8d4SVladimir Oltean 		if (match.mask->vlan_priority &&
268b70bb8d4SVladimir Oltean 		    match.mask->vlan_priority != 0x7) {
269a6af7763SVladimir Oltean 			NL_SET_ERR_MSG_MOD(extack,
270a6af7763SVladimir Oltean 					   "Masked matching on PCP is not supported");
271a6af7763SVladimir Oltean 			return -EOPNOTSUPP;
272a6af7763SVladimir Oltean 		}
273a6af7763SVladimir Oltean 
274b70bb8d4SVladimir Oltean 		if (match.mask->vlan_id)
275b70bb8d4SVladimir Oltean 			vid = match.key->vlan_id;
276b70bb8d4SVladimir Oltean 		if (match.mask->vlan_priority)
277b70bb8d4SVladimir Oltean 			pcp = match.key->vlan_priority;
278b70bb8d4SVladimir Oltean 	}
279b70bb8d4SVladimir Oltean 
280b70bb8d4SVladimir Oltean 	if (is_bcast_dmac && vid == U16_MAX && pcp == U16_MAX) {
281b70bb8d4SVladimir Oltean 		key->type = SJA1105_KEY_BCAST;
282b70bb8d4SVladimir Oltean 		return 0;
283b70bb8d4SVladimir Oltean 	}
284b70bb8d4SVladimir Oltean 	if (dmac == U64_MAX && vid == U16_MAX && pcp != U16_MAX) {
285b70bb8d4SVladimir Oltean 		key->type = SJA1105_KEY_TC;
286b70bb8d4SVladimir Oltean 		key->tc.pcp = pcp;
287b70bb8d4SVladimir Oltean 		return 0;
288b70bb8d4SVladimir Oltean 	}
289b70bb8d4SVladimir Oltean 	if (dmac != U64_MAX && vid != U16_MAX && pcp != U16_MAX) {
290b70bb8d4SVladimir Oltean 		key->type = SJA1105_KEY_VLAN_AWARE_VL;
291b70bb8d4SVladimir Oltean 		key->vl.dmac = dmac;
292b70bb8d4SVladimir Oltean 		key->vl.vid = vid;
293b70bb8d4SVladimir Oltean 		key->vl.pcp = pcp;
294b70bb8d4SVladimir Oltean 		return 0;
295b70bb8d4SVladimir Oltean 	}
296b70bb8d4SVladimir Oltean 	if (dmac != U64_MAX) {
297b70bb8d4SVladimir Oltean 		key->type = SJA1105_KEY_VLAN_UNAWARE_VL;
298b70bb8d4SVladimir Oltean 		key->vl.dmac = dmac;
299b70bb8d4SVladimir Oltean 		return 0;
300a6af7763SVladimir Oltean 	}
301a6af7763SVladimir Oltean 
302a6af7763SVladimir Oltean 	NL_SET_ERR_MSG_MOD(extack, "Not matching on any known key");
303a6af7763SVladimir Oltean 	return -EOPNOTSUPP;
304a6af7763SVladimir Oltean }
305a6af7763SVladimir Oltean 
sja1105_policer_validate(const struct flow_action * action,const struct flow_action_entry * act,struct netlink_ext_ack * extack)306d97b4b10SJianbo Liu static int sja1105_policer_validate(const struct flow_action *action,
307d97b4b10SJianbo Liu 				    const struct flow_action_entry *act,
308d97b4b10SJianbo Liu 				    struct netlink_ext_ack *extack)
309d97b4b10SJianbo Liu {
310d97b4b10SJianbo Liu 	if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
311d97b4b10SJianbo Liu 		NL_SET_ERR_MSG_MOD(extack,
312d97b4b10SJianbo Liu 				   "Offload not supported when exceed action is not drop");
313d97b4b10SJianbo Liu 		return -EOPNOTSUPP;
314d97b4b10SJianbo Liu 	}
315d97b4b10SJianbo Liu 
316d97b4b10SJianbo Liu 	if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
317d97b4b10SJianbo Liu 	    act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
318d97b4b10SJianbo Liu 		NL_SET_ERR_MSG_MOD(extack,
319d97b4b10SJianbo Liu 				   "Offload not supported when conform action is not pipe or ok");
320d97b4b10SJianbo Liu 		return -EOPNOTSUPP;
321d97b4b10SJianbo Liu 	}
322d97b4b10SJianbo Liu 
323d97b4b10SJianbo Liu 	if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
324d97b4b10SJianbo Liu 	    !flow_action_is_last_entry(action, act)) {
325d97b4b10SJianbo Liu 		NL_SET_ERR_MSG_MOD(extack,
326d97b4b10SJianbo Liu 				   "Offload not supported when conform action is ok, but action is not last");
327d97b4b10SJianbo Liu 		return -EOPNOTSUPP;
328d97b4b10SJianbo Liu 	}
329d97b4b10SJianbo Liu 
330d97b4b10SJianbo Liu 	if (act->police.peakrate_bytes_ps ||
331d97b4b10SJianbo Liu 	    act->police.avrate || act->police.overhead) {
332d97b4b10SJianbo Liu 		NL_SET_ERR_MSG_MOD(extack,
333d97b4b10SJianbo Liu 				   "Offload not supported when peakrate/avrate/overhead is configured");
334d97b4b10SJianbo Liu 		return -EOPNOTSUPP;
335d97b4b10SJianbo Liu 	}
336d97b4b10SJianbo Liu 
337d97b4b10SJianbo Liu 	if (act->police.rate_pkt_ps) {
338d97b4b10SJianbo Liu 		NL_SET_ERR_MSG_MOD(extack,
339d97b4b10SJianbo Liu 				   "QoS offload not support packets per second");
340d97b4b10SJianbo Liu 		return -EOPNOTSUPP;
341d97b4b10SJianbo Liu 	}
342d97b4b10SJianbo Liu 
343d97b4b10SJianbo Liu 	return 0;
344d97b4b10SJianbo Liu }
345d97b4b10SJianbo Liu 
sja1105_cls_flower_add(struct dsa_switch * ds,int port,struct flow_cls_offload * cls,bool ingress)346a6af7763SVladimir Oltean int sja1105_cls_flower_add(struct dsa_switch *ds, int port,
347a6af7763SVladimir Oltean 			   struct flow_cls_offload *cls, bool ingress)
348a6af7763SVladimir Oltean {
349a6af7763SVladimir Oltean 	struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
350a6af7763SVladimir Oltean 	struct netlink_ext_ack *extack = cls->common.extack;
351a6af7763SVladimir Oltean 	struct sja1105_private *priv = ds->priv;
352a6af7763SVladimir Oltean 	const struct flow_action_entry *act;
353b70bb8d4SVladimir Oltean 	unsigned long cookie = cls->cookie;
354834f8933SVladimir Oltean 	bool routing_rule = false;
355b70bb8d4SVladimir Oltean 	struct sja1105_key key;
356834f8933SVladimir Oltean 	bool gate_rule = false;
357dfacc5a2SVladimir Oltean 	bool vl_rule = false;
358b70bb8d4SVladimir Oltean 	int rc, i;
359b70bb8d4SVladimir Oltean 
360b70bb8d4SVladimir Oltean 	rc = sja1105_flower_parse_key(priv, extack, cls, &key);
361b70bb8d4SVladimir Oltean 	if (rc)
362b70bb8d4SVladimir Oltean 		return rc;
363b70bb8d4SVladimir Oltean 
364a6af7763SVladimir Oltean 	flow_action_for_each(i, act, &rule->action) {
365a6af7763SVladimir Oltean 		switch (act->id) {
366a6af7763SVladimir Oltean 		case FLOW_ACTION_POLICE:
367d97b4b10SJianbo Liu 			rc = sja1105_policer_validate(&rule->action, act, extack);
368d97b4b10SJianbo Liu 			if (rc)
3696a56e199SBaowen Zheng 				goto out;
3706a56e199SBaowen Zheng 
371dfacc5a2SVladimir Oltean 			rc = sja1105_flower_policer(priv, port, extack, cookie,
372dfacc5a2SVladimir Oltean 						    &key,
373a6af7763SVladimir Oltean 						    act->police.rate_bytes_ps,
374a6af7763SVladimir Oltean 						    act->police.burst);
375b70bb8d4SVladimir Oltean 			if (rc)
376b70bb8d4SVladimir Oltean 				goto out;
377a6af7763SVladimir Oltean 			break;
378dfacc5a2SVladimir Oltean 		case FLOW_ACTION_TRAP: {
379dfacc5a2SVladimir Oltean 			int cpu = dsa_upstream_port(ds, port);
380dfacc5a2SVladimir Oltean 
381834f8933SVladimir Oltean 			routing_rule = true;
382dfacc5a2SVladimir Oltean 			vl_rule = true;
383dfacc5a2SVladimir Oltean 
384dfacc5a2SVladimir Oltean 			rc = sja1105_vl_redirect(priv, port, extack, cookie,
385dfacc5a2SVladimir Oltean 						 &key, BIT(cpu), true);
386dfacc5a2SVladimir Oltean 			if (rc)
387dfacc5a2SVladimir Oltean 				goto out;
388dfacc5a2SVladimir Oltean 			break;
389dfacc5a2SVladimir Oltean 		}
390dfacc5a2SVladimir Oltean 		case FLOW_ACTION_REDIRECT: {
391dfacc5a2SVladimir Oltean 			struct dsa_port *to_dp;
392dfacc5a2SVladimir Oltean 
393dfacc5a2SVladimir Oltean 			to_dp = dsa_port_from_netdev(act->dev);
394dfacc5a2SVladimir Oltean 			if (IS_ERR(to_dp)) {
395dfacc5a2SVladimir Oltean 				NL_SET_ERR_MSG_MOD(extack,
396dfacc5a2SVladimir Oltean 						   "Destination not a switch port");
397dfacc5a2SVladimir Oltean 				return -EOPNOTSUPP;
398dfacc5a2SVladimir Oltean 			}
399dfacc5a2SVladimir Oltean 
400834f8933SVladimir Oltean 			routing_rule = true;
401dfacc5a2SVladimir Oltean 			vl_rule = true;
402dfacc5a2SVladimir Oltean 
403dfacc5a2SVladimir Oltean 			rc = sja1105_vl_redirect(priv, port, extack, cookie,
404dfacc5a2SVladimir Oltean 						 &key, BIT(to_dp->index), true);
405dfacc5a2SVladimir Oltean 			if (rc)
406dfacc5a2SVladimir Oltean 				goto out;
407dfacc5a2SVladimir Oltean 			break;
408dfacc5a2SVladimir Oltean 		}
409dfacc5a2SVladimir Oltean 		case FLOW_ACTION_DROP:
410dfacc5a2SVladimir Oltean 			vl_rule = true;
411dfacc5a2SVladimir Oltean 
412dfacc5a2SVladimir Oltean 			rc = sja1105_vl_redirect(priv, port, extack, cookie,
413dfacc5a2SVladimir Oltean 						 &key, 0, false);
414dfacc5a2SVladimir Oltean 			if (rc)
415dfacc5a2SVladimir Oltean 				goto out;
416dfacc5a2SVladimir Oltean 			break;
417834f8933SVladimir Oltean 		case FLOW_ACTION_GATE:
418834f8933SVladimir Oltean 			gate_rule = true;
419834f8933SVladimir Oltean 			vl_rule = true;
420834f8933SVladimir Oltean 
421834f8933SVladimir Oltean 			rc = sja1105_vl_gate(priv, port, extack, cookie,
4225a995900SBaowen Zheng 					     &key, act->hw_index,
423834f8933SVladimir Oltean 					     act->gate.prio,
424834f8933SVladimir Oltean 					     act->gate.basetime,
425834f8933SVladimir Oltean 					     act->gate.cycletime,
426834f8933SVladimir Oltean 					     act->gate.cycletimeext,
427834f8933SVladimir Oltean 					     act->gate.num_entries,
428834f8933SVladimir Oltean 					     act->gate.entries);
429834f8933SVladimir Oltean 			if (rc)
430834f8933SVladimir Oltean 				goto out;
431834f8933SVladimir Oltean 			break;
432a6af7763SVladimir Oltean 		default:
433a6af7763SVladimir Oltean 			NL_SET_ERR_MSG_MOD(extack,
434a6af7763SVladimir Oltean 					   "Action not supported");
435b70bb8d4SVladimir Oltean 			rc = -EOPNOTSUPP;
436b70bb8d4SVladimir Oltean 			goto out;
437a6af7763SVladimir Oltean 		}
438a6af7763SVladimir Oltean 	}
439dfacc5a2SVladimir Oltean 
440834f8933SVladimir Oltean 	if (vl_rule && !rc) {
441834f8933SVladimir Oltean 		/* Delay scheduling configuration until DESTPORTS has been
442834f8933SVladimir Oltean 		 * populated by all other actions.
443834f8933SVladimir Oltean 		 */
444834f8933SVladimir Oltean 		if (gate_rule) {
445834f8933SVladimir Oltean 			if (!routing_rule) {
446834f8933SVladimir Oltean 				NL_SET_ERR_MSG_MOD(extack,
447834f8933SVladimir Oltean 						   "Can only offload gate action together with redirect or trap");
448834f8933SVladimir Oltean 				return -EOPNOTSUPP;
449834f8933SVladimir Oltean 			}
450834f8933SVladimir Oltean 			rc = sja1105_init_scheduling(priv);
451834f8933SVladimir Oltean 			if (rc)
452834f8933SVladimir Oltean 				goto out;
453834f8933SVladimir Oltean 		}
454834f8933SVladimir Oltean 
455dfacc5a2SVladimir Oltean 		rc = sja1105_static_config_reload(priv, SJA1105_VIRTUAL_LINKS);
456834f8933SVladimir Oltean 	}
457dfacc5a2SVladimir Oltean 
458b70bb8d4SVladimir Oltean out:
459a6af7763SVladimir Oltean 	return rc;
460a6af7763SVladimir Oltean }
461a6af7763SVladimir Oltean 
sja1105_cls_flower_del(struct dsa_switch * ds,int port,struct flow_cls_offload * cls,bool ingress)462a6af7763SVladimir Oltean int sja1105_cls_flower_del(struct dsa_switch *ds, int port,
463a6af7763SVladimir Oltean 			   struct flow_cls_offload *cls, bool ingress)
464a6af7763SVladimir Oltean {
465a6af7763SVladimir Oltean 	struct sja1105_private *priv = ds->priv;
466a6af7763SVladimir Oltean 	struct sja1105_rule *rule = sja1105_rule_find(priv, cls->cookie);
467a6af7763SVladimir Oltean 	struct sja1105_l2_policing_entry *policing;
468a6af7763SVladimir Oltean 	int old_sharindx;
469a6af7763SVladimir Oltean 
470a6af7763SVladimir Oltean 	if (!rule)
471a6af7763SVladimir Oltean 		return 0;
472a6af7763SVladimir Oltean 
473dfacc5a2SVladimir Oltean 	if (rule->type == SJA1105_RULE_VL)
474dfacc5a2SVladimir Oltean 		return sja1105_vl_delete(priv, port, rule, cls->common.extack);
475dfacc5a2SVladimir Oltean 
476a6af7763SVladimir Oltean 	policing = priv->static_config.tables[BLK_IDX_L2_POLICING].entries;
477a6af7763SVladimir Oltean 
478a6af7763SVladimir Oltean 	if (rule->type == SJA1105_RULE_BCAST_POLICER) {
479542043e9SVladimir Oltean 		int bcast = (ds->num_ports * SJA1105_NUM_TC) + port;
480a6af7763SVladimir Oltean 
481a6af7763SVladimir Oltean 		old_sharindx = policing[bcast].sharindx;
482a6af7763SVladimir Oltean 		policing[bcast].sharindx = port;
483a6af7763SVladimir Oltean 	} else if (rule->type == SJA1105_RULE_TC_POLICER) {
484b70bb8d4SVladimir Oltean 		int index = (port * SJA1105_NUM_TC) + rule->key.tc.pcp;
485a6af7763SVladimir Oltean 
486a6af7763SVladimir Oltean 		old_sharindx = policing[index].sharindx;
487a6af7763SVladimir Oltean 		policing[index].sharindx = port;
488a6af7763SVladimir Oltean 	} else {
489a6af7763SVladimir Oltean 		return -EINVAL;
490a6af7763SVladimir Oltean 	}
491a6af7763SVladimir Oltean 
492a6af7763SVladimir Oltean 	rule->port_mask &= ~BIT(port);
493a6af7763SVladimir Oltean 	if (!rule->port_mask) {
494a6af7763SVladimir Oltean 		priv->flow_block.l2_policer_used[old_sharindx] = false;
495a6af7763SVladimir Oltean 		list_del(&rule->list);
496a6af7763SVladimir Oltean 		kfree(rule);
497a6af7763SVladimir Oltean 	}
498a6af7763SVladimir Oltean 
499a6af7763SVladimir Oltean 	return sja1105_static_config_reload(priv, SJA1105_BEST_EFFORT_POLICING);
500a6af7763SVladimir Oltean }
501a6af7763SVladimir Oltean 
sja1105_cls_flower_stats(struct dsa_switch * ds,int port,struct flow_cls_offload * cls,bool ingress)502834f8933SVladimir Oltean int sja1105_cls_flower_stats(struct dsa_switch *ds, int port,
503834f8933SVladimir Oltean 			     struct flow_cls_offload *cls, bool ingress)
504834f8933SVladimir Oltean {
505834f8933SVladimir Oltean 	struct sja1105_private *priv = ds->priv;
506834f8933SVladimir Oltean 	struct sja1105_rule *rule = sja1105_rule_find(priv, cls->cookie);
507834f8933SVladimir Oltean 	int rc;
508834f8933SVladimir Oltean 
509834f8933SVladimir Oltean 	if (!rule)
510834f8933SVladimir Oltean 		return 0;
511834f8933SVladimir Oltean 
512834f8933SVladimir Oltean 	if (rule->type != SJA1105_RULE_VL)
513834f8933SVladimir Oltean 		return 0;
514834f8933SVladimir Oltean 
515834f8933SVladimir Oltean 	rc = sja1105_vl_stats(priv, port, rule, &cls->stats,
516834f8933SVladimir Oltean 			      cls->common.extack);
517834f8933SVladimir Oltean 	if (rc)
518834f8933SVladimir Oltean 		return rc;
519834f8933SVladimir Oltean 
520834f8933SVladimir Oltean 	return 0;
521834f8933SVladimir Oltean }
522834f8933SVladimir Oltean 
sja1105_flower_setup(struct dsa_switch * ds)523a6af7763SVladimir Oltean void sja1105_flower_setup(struct dsa_switch *ds)
524a6af7763SVladimir Oltean {
525a6af7763SVladimir Oltean 	struct sja1105_private *priv = ds->priv;
526a6af7763SVladimir Oltean 	int port;
527a6af7763SVladimir Oltean 
528a6af7763SVladimir Oltean 	INIT_LIST_HEAD(&priv->flow_block.rules);
529a6af7763SVladimir Oltean 
530542043e9SVladimir Oltean 	for (port = 0; port < ds->num_ports; port++)
531a6af7763SVladimir Oltean 		priv->flow_block.l2_policer_used[port] = true;
532a6af7763SVladimir Oltean }
533a6af7763SVladimir Oltean 
sja1105_flower_teardown(struct dsa_switch * ds)534a6af7763SVladimir Oltean void sja1105_flower_teardown(struct dsa_switch *ds)
535a6af7763SVladimir Oltean {
536a6af7763SVladimir Oltean 	struct sja1105_private *priv = ds->priv;
537a6af7763SVladimir Oltean 	struct sja1105_rule *rule;
538a6af7763SVladimir Oltean 	struct list_head *pos, *n;
539a6af7763SVladimir Oltean 
540a6af7763SVladimir Oltean 	list_for_each_safe(pos, n, &priv->flow_block.rules) {
541a6af7763SVladimir Oltean 		rule = list_entry(pos, struct sja1105_rule, list);
542a6af7763SVladimir Oltean 		list_del(&rule->list);
543a6af7763SVladimir Oltean 		kfree(rule);
544a6af7763SVladimir Oltean 	}
545a6af7763SVladimir Oltean }
546