1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch driver
3  * Copyright (c) 2019 Microsemi Corporation
4  */
5 
6 #include <net/pkt_cls.h>
7 #include <net/tc_act/tc_gact.h>
8 
9 #include "ocelot_ace.h"
10 
11 struct ocelot_port_block {
12 	struct ocelot_acl_block *block;
13 	struct ocelot_port *port;
14 };
15 
16 static u16 get_prio(u32 prio)
17 {
18 	/* prio starts from 0x1000 while the ids starts from 0 */
19 	return prio >> 16;
20 }
21 
22 static int ocelot_flower_parse_action(struct flow_cls_offload *f,
23 				      struct ocelot_ace_rule *rule)
24 {
25 	const struct flow_action_entry *a;
26 	int i;
27 
28 	if (f->rule->action.num_entries != 1)
29 		return -EOPNOTSUPP;
30 
31 	flow_action_for_each(i, a, &f->rule->action) {
32 		switch (a->id) {
33 		case FLOW_ACTION_DROP:
34 			rule->action = OCELOT_ACL_ACTION_DROP;
35 			break;
36 		case FLOW_ACTION_TRAP:
37 			rule->action = OCELOT_ACL_ACTION_TRAP;
38 			break;
39 		default:
40 			return -EOPNOTSUPP;
41 		}
42 	}
43 
44 	return 0;
45 }
46 
47 static int ocelot_flower_parse(struct flow_cls_offload *f,
48 			       struct ocelot_ace_rule *ocelot_rule)
49 {
50 	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
51 	struct flow_dissector *dissector = rule->match.dissector;
52 
53 	if (dissector->used_keys &
54 	    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
55 	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
56 	      BIT(FLOW_DISSECTOR_KEY_PORTS) |
57 	      BIT(FLOW_DISSECTOR_KEY_VLAN) |
58 	      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
59 	      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
60 	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
61 		return -EOPNOTSUPP;
62 	}
63 
64 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
65 		struct flow_match_control match;
66 
67 		flow_rule_match_control(rule, &match);
68 	}
69 
70 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
71 		struct flow_match_eth_addrs match;
72 		u16 proto = ntohs(f->common.protocol);
73 
74 		/* The hw support mac matches only for MAC_ETYPE key,
75 		 * therefore if other matches(port, tcp flags, etc) are added
76 		 * then just bail out
77 		 */
78 		if ((dissector->used_keys &
79 		    (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
80 		     BIT(FLOW_DISSECTOR_KEY_BASIC) |
81 		     BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
82 		    (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
83 		     BIT(FLOW_DISSECTOR_KEY_BASIC) |
84 		     BIT(FLOW_DISSECTOR_KEY_CONTROL)))
85 			return -EOPNOTSUPP;
86 
87 		if (proto == ETH_P_IP ||
88 		    proto == ETH_P_IPV6 ||
89 		    proto == ETH_P_ARP)
90 			return -EOPNOTSUPP;
91 
92 		flow_rule_match_eth_addrs(rule, &match);
93 		ocelot_rule->type = OCELOT_ACE_TYPE_ETYPE;
94 		ether_addr_copy(ocelot_rule->frame.etype.dmac.value,
95 				match.key->dst);
96 		ether_addr_copy(ocelot_rule->frame.etype.smac.value,
97 				match.key->src);
98 		ether_addr_copy(ocelot_rule->frame.etype.dmac.mask,
99 				match.mask->dst);
100 		ether_addr_copy(ocelot_rule->frame.etype.smac.mask,
101 				match.mask->src);
102 		goto finished_key_parsing;
103 	}
104 
105 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
106 		struct flow_match_basic match;
107 
108 		flow_rule_match_basic(rule, &match);
109 		if (ntohs(match.key->n_proto) == ETH_P_IP) {
110 			ocelot_rule->type = OCELOT_ACE_TYPE_IPV4;
111 			ocelot_rule->frame.ipv4.proto.value[0] =
112 				match.key->ip_proto;
113 			ocelot_rule->frame.ipv4.proto.mask[0] =
114 				match.mask->ip_proto;
115 		}
116 		if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
117 			ocelot_rule->type = OCELOT_ACE_TYPE_IPV6;
118 			ocelot_rule->frame.ipv6.proto.value[0] =
119 				match.key->ip_proto;
120 			ocelot_rule->frame.ipv6.proto.mask[0] =
121 				match.mask->ip_proto;
122 		}
123 	}
124 
125 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
126 	    ntohs(f->common.protocol) == ETH_P_IP) {
127 		struct flow_match_ipv4_addrs match;
128 		u8 *tmp;
129 
130 		flow_rule_match_ipv4_addrs(rule, &match);
131 		tmp = &ocelot_rule->frame.ipv4.sip.value.addr[0];
132 		memcpy(tmp, &match.key->src, 4);
133 
134 		tmp = &ocelot_rule->frame.ipv4.sip.mask.addr[0];
135 		memcpy(tmp, &match.mask->src, 4);
136 
137 		tmp = &ocelot_rule->frame.ipv4.dip.value.addr[0];
138 		memcpy(tmp, &match.key->dst, 4);
139 
140 		tmp = &ocelot_rule->frame.ipv4.dip.mask.addr[0];
141 		memcpy(tmp, &match.mask->dst, 4);
142 	}
143 
144 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
145 	    ntohs(f->common.protocol) == ETH_P_IPV6) {
146 		return -EOPNOTSUPP;
147 	}
148 
149 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
150 		struct flow_match_ports match;
151 
152 		flow_rule_match_ports(rule, &match);
153 		ocelot_rule->frame.ipv4.sport.value = ntohs(match.key->src);
154 		ocelot_rule->frame.ipv4.sport.mask = ntohs(match.mask->src);
155 		ocelot_rule->frame.ipv4.dport.value = ntohs(match.key->dst);
156 		ocelot_rule->frame.ipv4.dport.mask = ntohs(match.mask->dst);
157 	}
158 
159 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
160 		struct flow_match_vlan match;
161 
162 		flow_rule_match_vlan(rule, &match);
163 		ocelot_rule->type = OCELOT_ACE_TYPE_ANY;
164 		ocelot_rule->vlan.vid.value = match.key->vlan_id;
165 		ocelot_rule->vlan.vid.mask = match.mask->vlan_id;
166 		ocelot_rule->vlan.pcp.value[0] = match.key->vlan_priority;
167 		ocelot_rule->vlan.pcp.mask[0] = match.mask->vlan_priority;
168 	}
169 
170 finished_key_parsing:
171 	ocelot_rule->prio = get_prio(f->common.prio);
172 	ocelot_rule->id = f->cookie;
173 	return ocelot_flower_parse_action(f, ocelot_rule);
174 }
175 
176 static
177 struct ocelot_ace_rule *ocelot_ace_rule_create(struct flow_cls_offload *f,
178 					       struct ocelot_port_block *block)
179 {
180 	struct ocelot_ace_rule *rule;
181 
182 	rule = kzalloc(sizeof(*rule), GFP_KERNEL);
183 	if (!rule)
184 		return NULL;
185 
186 	rule->port = block->port;
187 	rule->chip_port = block->port->chip_port;
188 	return rule;
189 }
190 
191 static int ocelot_flower_replace(struct flow_cls_offload *f,
192 				 struct ocelot_port_block *port_block)
193 {
194 	struct ocelot_ace_rule *rule;
195 	int ret;
196 
197 	rule = ocelot_ace_rule_create(f, port_block);
198 	if (!rule)
199 		return -ENOMEM;
200 
201 	ret = ocelot_flower_parse(f, rule);
202 	if (ret) {
203 		kfree(rule);
204 		return ret;
205 	}
206 
207 	ret = ocelot_ace_rule_offload_add(rule);
208 	if (ret)
209 		return ret;
210 
211 	port_block->port->tc.offload_cnt++;
212 	return 0;
213 }
214 
215 static int ocelot_flower_destroy(struct flow_cls_offload *f,
216 				 struct ocelot_port_block *port_block)
217 {
218 	struct ocelot_ace_rule rule;
219 	int ret;
220 
221 	rule.prio = get_prio(f->common.prio);
222 	rule.port = port_block->port;
223 	rule.id = f->cookie;
224 
225 	ret = ocelot_ace_rule_offload_del(&rule);
226 	if (ret)
227 		return ret;
228 
229 	port_block->port->tc.offload_cnt--;
230 	return 0;
231 }
232 
233 static int ocelot_flower_stats_update(struct flow_cls_offload *f,
234 				      struct ocelot_port_block *port_block)
235 {
236 	struct ocelot_ace_rule rule;
237 	int ret;
238 
239 	rule.prio = get_prio(f->common.prio);
240 	rule.port = port_block->port;
241 	rule.id = f->cookie;
242 	ret = ocelot_ace_rule_stats_update(&rule);
243 	if (ret)
244 		return ret;
245 
246 	flow_stats_update(&f->stats, 0x0, rule.stats.pkts, 0x0);
247 	return 0;
248 }
249 
250 static int ocelot_setup_tc_cls_flower(struct flow_cls_offload *f,
251 				      struct ocelot_port_block *port_block)
252 {
253 	switch (f->command) {
254 	case FLOW_CLS_REPLACE:
255 		return ocelot_flower_replace(f, port_block);
256 	case FLOW_CLS_DESTROY:
257 		return ocelot_flower_destroy(f, port_block);
258 	case FLOW_CLS_STATS:
259 		return ocelot_flower_stats_update(f, port_block);
260 	default:
261 		return -EOPNOTSUPP;
262 	}
263 }
264 
265 static int ocelot_setup_tc_block_cb_flower(enum tc_setup_type type,
266 					   void *type_data, void *cb_priv)
267 {
268 	struct ocelot_port_block *port_block = cb_priv;
269 
270 	if (!tc_cls_can_offload_and_chain0(port_block->port->dev, type_data))
271 		return -EOPNOTSUPP;
272 
273 	switch (type) {
274 	case TC_SETUP_CLSFLOWER:
275 		return ocelot_setup_tc_cls_flower(type_data, cb_priv);
276 	case TC_SETUP_CLSMATCHALL:
277 		return 0;
278 	default:
279 		return -EOPNOTSUPP;
280 	}
281 }
282 
283 static struct ocelot_port_block*
284 ocelot_port_block_create(struct ocelot_port *port)
285 {
286 	struct ocelot_port_block *port_block;
287 
288 	port_block = kzalloc(sizeof(*port_block), GFP_KERNEL);
289 	if (!port_block)
290 		return NULL;
291 
292 	port_block->port = port;
293 
294 	return port_block;
295 }
296 
297 static void ocelot_port_block_destroy(struct ocelot_port_block *block)
298 {
299 	kfree(block);
300 }
301 
302 static void ocelot_tc_block_unbind(void *cb_priv)
303 {
304 	struct ocelot_port_block *port_block = cb_priv;
305 
306 	ocelot_port_block_destroy(port_block);
307 }
308 
309 int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
310 				      struct flow_block_offload *f)
311 {
312 	struct ocelot_port_block *port_block;
313 	struct flow_block_cb *block_cb;
314 	int ret;
315 
316 	if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
317 		return -EOPNOTSUPP;
318 
319 	block_cb = flow_block_cb_lookup(f->block,
320 					ocelot_setup_tc_block_cb_flower, port);
321 	if (!block_cb) {
322 		port_block = ocelot_port_block_create(port);
323 		if (!port_block)
324 			return -ENOMEM;
325 
326 		block_cb = flow_block_cb_alloc(ocelot_setup_tc_block_cb_flower,
327 					       port, port_block,
328 					       ocelot_tc_block_unbind);
329 		if (IS_ERR(block_cb)) {
330 			ret = PTR_ERR(block_cb);
331 			goto err_cb_register;
332 		}
333 		flow_block_cb_add(block_cb, f);
334 		list_add_tail(&block_cb->driver_list, f->driver_block_list);
335 	} else {
336 		port_block = flow_block_cb_priv(block_cb);
337 	}
338 
339 	flow_block_cb_incref(block_cb);
340 	return 0;
341 
342 err_cb_register:
343 	ocelot_port_block_destroy(port_block);
344 
345 	return ret;
346 }
347 
348 void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
349 					 struct flow_block_offload *f)
350 {
351 	struct flow_block_cb *block_cb;
352 
353 	block_cb = flow_block_cb_lookup(f->block,
354 					ocelot_setup_tc_block_cb_flower, port);
355 	if (!block_cb)
356 		return;
357 
358 	if (!flow_block_cb_decref(block_cb)) {
359 		flow_block_cb_remove(block_cb, f);
360 		list_del(&block_cb->driver_list);
361 	}
362 }
363