treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / net / ethernet / mscc / ocelot_flower.c
blob3d65b99b97343409d9ec1d7cbf11777392debe5e
1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch driver
3 * Copyright (c) 2019 Microsemi Corporation
4 */
6 #include <net/pkt_cls.h>
7 #include <net/tc_act/tc_gact.h>
9 #include "ocelot_ace.h"
11 struct ocelot_port_block {
12 struct ocelot_acl_block *block;
13 struct ocelot_port_private *priv;
16 static int ocelot_flower_parse_action(struct flow_cls_offload *f,
17 struct ocelot_ace_rule *rule)
19 const struct flow_action_entry *a;
20 int i;
22 if (f->rule->action.num_entries != 1)
23 return -EOPNOTSUPP;
25 flow_action_for_each(i, a, &f->rule->action) {
26 switch (a->id) {
27 case FLOW_ACTION_DROP:
28 rule->action = OCELOT_ACL_ACTION_DROP;
29 break;
30 case FLOW_ACTION_TRAP:
31 rule->action = OCELOT_ACL_ACTION_TRAP;
32 break;
33 default:
34 return -EOPNOTSUPP;
38 return 0;
41 static int ocelot_flower_parse(struct flow_cls_offload *f,
42 struct ocelot_ace_rule *ocelot_rule)
44 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
45 struct flow_dissector *dissector = rule->match.dissector;
47 if (dissector->used_keys &
48 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
49 BIT(FLOW_DISSECTOR_KEY_BASIC) |
50 BIT(FLOW_DISSECTOR_KEY_PORTS) |
51 BIT(FLOW_DISSECTOR_KEY_VLAN) |
52 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
53 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
54 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
55 return -EOPNOTSUPP;
58 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
59 struct flow_match_control match;
61 flow_rule_match_control(rule, &match);
64 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
65 struct flow_match_eth_addrs match;
66 u16 proto = ntohs(f->common.protocol);
68 /* The hw support mac matches only for MAC_ETYPE key,
69 * therefore if other matches(port, tcp flags, etc) are added
70 * then just bail out
72 if ((dissector->used_keys &
73 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
74 BIT(FLOW_DISSECTOR_KEY_BASIC) |
75 BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
76 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
77 BIT(FLOW_DISSECTOR_KEY_BASIC) |
78 BIT(FLOW_DISSECTOR_KEY_CONTROL)))
79 return -EOPNOTSUPP;
81 if (proto == ETH_P_IP ||
82 proto == ETH_P_IPV6 ||
83 proto == ETH_P_ARP)
84 return -EOPNOTSUPP;
86 flow_rule_match_eth_addrs(rule, &match);
87 ocelot_rule->type = OCELOT_ACE_TYPE_ETYPE;
88 ether_addr_copy(ocelot_rule->frame.etype.dmac.value,
89 match.key->dst);
90 ether_addr_copy(ocelot_rule->frame.etype.smac.value,
91 match.key->src);
92 ether_addr_copy(ocelot_rule->frame.etype.dmac.mask,
93 match.mask->dst);
94 ether_addr_copy(ocelot_rule->frame.etype.smac.mask,
95 match.mask->src);
96 goto finished_key_parsing;
99 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
100 struct flow_match_basic match;
102 flow_rule_match_basic(rule, &match);
103 if (ntohs(match.key->n_proto) == ETH_P_IP) {
104 ocelot_rule->type = OCELOT_ACE_TYPE_IPV4;
105 ocelot_rule->frame.ipv4.proto.value[0] =
106 match.key->ip_proto;
107 ocelot_rule->frame.ipv4.proto.mask[0] =
108 match.mask->ip_proto;
110 if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
111 ocelot_rule->type = OCELOT_ACE_TYPE_IPV6;
112 ocelot_rule->frame.ipv6.proto.value[0] =
113 match.key->ip_proto;
114 ocelot_rule->frame.ipv6.proto.mask[0] =
115 match.mask->ip_proto;
119 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
120 ntohs(f->common.protocol) == ETH_P_IP) {
121 struct flow_match_ipv4_addrs match;
122 u8 *tmp;
124 flow_rule_match_ipv4_addrs(rule, &match);
125 tmp = &ocelot_rule->frame.ipv4.sip.value.addr[0];
126 memcpy(tmp, &match.key->src, 4);
128 tmp = &ocelot_rule->frame.ipv4.sip.mask.addr[0];
129 memcpy(tmp, &match.mask->src, 4);
131 tmp = &ocelot_rule->frame.ipv4.dip.value.addr[0];
132 memcpy(tmp, &match.key->dst, 4);
134 tmp = &ocelot_rule->frame.ipv4.dip.mask.addr[0];
135 memcpy(tmp, &match.mask->dst, 4);
138 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
139 ntohs(f->common.protocol) == ETH_P_IPV6) {
140 return -EOPNOTSUPP;
143 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
144 struct flow_match_ports match;
146 flow_rule_match_ports(rule, &match);
147 ocelot_rule->frame.ipv4.sport.value = ntohs(match.key->src);
148 ocelot_rule->frame.ipv4.sport.mask = ntohs(match.mask->src);
149 ocelot_rule->frame.ipv4.dport.value = ntohs(match.key->dst);
150 ocelot_rule->frame.ipv4.dport.mask = ntohs(match.mask->dst);
153 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
154 struct flow_match_vlan match;
156 flow_rule_match_vlan(rule, &match);
157 ocelot_rule->type = OCELOT_ACE_TYPE_ANY;
158 ocelot_rule->vlan.vid.value = match.key->vlan_id;
159 ocelot_rule->vlan.vid.mask = match.mask->vlan_id;
160 ocelot_rule->vlan.pcp.value[0] = match.key->vlan_priority;
161 ocelot_rule->vlan.pcp.mask[0] = match.mask->vlan_priority;
164 finished_key_parsing:
165 ocelot_rule->prio = f->common.prio;
166 ocelot_rule->id = f->cookie;
167 return ocelot_flower_parse_action(f, ocelot_rule);
170 static
171 struct ocelot_ace_rule *ocelot_ace_rule_create(struct flow_cls_offload *f,
172 struct ocelot_port_block *block)
174 struct ocelot_ace_rule *rule;
176 rule = kzalloc(sizeof(*rule), GFP_KERNEL);
177 if (!rule)
178 return NULL;
180 rule->port = &block->priv->port;
181 rule->chip_port = block->priv->chip_port;
182 return rule;
185 static int ocelot_flower_replace(struct flow_cls_offload *f,
186 struct ocelot_port_block *port_block)
188 struct ocelot_ace_rule *rule;
189 int ret;
191 rule = ocelot_ace_rule_create(f, port_block);
192 if (!rule)
193 return -ENOMEM;
195 ret = ocelot_flower_parse(f, rule);
196 if (ret) {
197 kfree(rule);
198 return ret;
201 ret = ocelot_ace_rule_offload_add(rule);
202 if (ret)
203 return ret;
205 port_block->priv->tc.offload_cnt++;
206 return 0;
209 static int ocelot_flower_destroy(struct flow_cls_offload *f,
210 struct ocelot_port_block *port_block)
212 struct ocelot_ace_rule rule;
213 int ret;
215 rule.prio = f->common.prio;
216 rule.port = &port_block->priv->port;
217 rule.id = f->cookie;
219 ret = ocelot_ace_rule_offload_del(&rule);
220 if (ret)
221 return ret;
223 port_block->priv->tc.offload_cnt--;
224 return 0;
227 static int ocelot_flower_stats_update(struct flow_cls_offload *f,
228 struct ocelot_port_block *port_block)
230 struct ocelot_ace_rule rule;
231 int ret;
233 rule.prio = f->common.prio;
234 rule.port = &port_block->priv->port;
235 rule.id = f->cookie;
236 ret = ocelot_ace_rule_stats_update(&rule);
237 if (ret)
238 return ret;
240 flow_stats_update(&f->stats, 0x0, rule.stats.pkts, 0x0);
241 return 0;
244 static int ocelot_setup_tc_cls_flower(struct flow_cls_offload *f,
245 struct ocelot_port_block *port_block)
247 switch (f->command) {
248 case FLOW_CLS_REPLACE:
249 return ocelot_flower_replace(f, port_block);
250 case FLOW_CLS_DESTROY:
251 return ocelot_flower_destroy(f, port_block);
252 case FLOW_CLS_STATS:
253 return ocelot_flower_stats_update(f, port_block);
254 default:
255 return -EOPNOTSUPP;
259 static int ocelot_setup_tc_block_cb_flower(enum tc_setup_type type,
260 void *type_data, void *cb_priv)
262 struct ocelot_port_block *port_block = cb_priv;
264 if (!tc_cls_can_offload_and_chain0(port_block->priv->dev, type_data))
265 return -EOPNOTSUPP;
267 switch (type) {
268 case TC_SETUP_CLSFLOWER:
269 return ocelot_setup_tc_cls_flower(type_data, cb_priv);
270 case TC_SETUP_CLSMATCHALL:
271 return 0;
272 default:
273 return -EOPNOTSUPP;
277 static struct ocelot_port_block*
278 ocelot_port_block_create(struct ocelot_port_private *priv)
280 struct ocelot_port_block *port_block;
282 port_block = kzalloc(sizeof(*port_block), GFP_KERNEL);
283 if (!port_block)
284 return NULL;
286 port_block->priv = priv;
288 return port_block;
291 static void ocelot_port_block_destroy(struct ocelot_port_block *block)
293 kfree(block);
296 static void ocelot_tc_block_unbind(void *cb_priv)
298 struct ocelot_port_block *port_block = cb_priv;
300 ocelot_port_block_destroy(port_block);
303 int ocelot_setup_tc_block_flower_bind(struct ocelot_port_private *priv,
304 struct flow_block_offload *f)
306 struct ocelot_port_block *port_block;
307 struct flow_block_cb *block_cb;
308 int ret;
310 if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
311 return -EOPNOTSUPP;
313 block_cb = flow_block_cb_lookup(f->block,
314 ocelot_setup_tc_block_cb_flower, priv);
315 if (!block_cb) {
316 port_block = ocelot_port_block_create(priv);
317 if (!port_block)
318 return -ENOMEM;
320 block_cb = flow_block_cb_alloc(ocelot_setup_tc_block_cb_flower,
321 priv, port_block,
322 ocelot_tc_block_unbind);
323 if (IS_ERR(block_cb)) {
324 ret = PTR_ERR(block_cb);
325 goto err_cb_register;
327 flow_block_cb_add(block_cb, f);
328 list_add_tail(&block_cb->driver_list, f->driver_block_list);
329 } else {
330 port_block = flow_block_cb_priv(block_cb);
333 flow_block_cb_incref(block_cb);
334 return 0;
336 err_cb_register:
337 ocelot_port_block_destroy(port_block);
339 return ret;
342 void ocelot_setup_tc_block_flower_unbind(struct ocelot_port_private *priv,
343 struct flow_block_offload *f)
345 struct flow_block_cb *block_cb;
347 block_cb = flow_block_cb_lookup(f->block,
348 ocelot_setup_tc_block_cb_flower, priv);
349 if (!block_cb)
350 return;
352 if (!flow_block_cb_decref(block_cb)) {
353 flow_block_cb_remove(block_cb, f);
354 list_del(&block_cb->driver_list);