1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch driver
3 * Copyright (c) 2019 Microsemi Corporation
6 #include <net/pkt_cls.h>
7 #include <net/tc_act/tc_gact.h>
8 #include <soc/mscc/ocelot_vcap.h>
9 #include "ocelot_police.h"
10 #include "ocelot_vcap.h"
12 /* Arbitrarily chosen constants for encoding the VCAP block and lookup number
13 * into the chain number. This is UAPI.
15 #define VCAP_BLOCK 10000
16 #define VCAP_LOOKUP 1000
17 #define VCAP_IS1_NUM_LOOKUPS 3
18 #define VCAP_IS2_NUM_LOOKUPS 2
19 #define VCAP_IS2_NUM_PAG 256
20 #define VCAP_IS1_CHAIN(lookup) \
21 (1 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP)
22 #define VCAP_IS2_CHAIN(lookup, pag) \
23 (2 * VCAP_BLOCK + (lookup) * VCAP_LOOKUP + (pag))
24 /* PSFP chain and block ID */
25 #define PSFP_BLOCK_ID OCELOT_NUM_VCAP_BLOCKS
26 #define OCELOT_PSFP_CHAIN (3 * VCAP_BLOCK)
28 static int ocelot_chain_to_block(int chain, bool ingress)
38 /* Backwards compatibility with older, single-chain tc-flower
39 * offload support in Ocelot
44 for (lookup = 0; lookup < VCAP_IS1_NUM_LOOKUPS; lookup++)
45 if (chain == VCAP_IS1_CHAIN(lookup))
48 for (lookup = 0; lookup < VCAP_IS2_NUM_LOOKUPS; lookup++)
49 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
50 if (chain == VCAP_IS2_CHAIN(lookup, pag))
53 if (chain == OCELOT_PSFP_CHAIN)
59 /* Caller must ensure this is a valid IS1 or IS2 chain first,
60 * by calling ocelot_chain_to_block.
62 static int ocelot_chain_to_lookup(int chain)
64 /* Backwards compatibility with older, single-chain tc-flower
65 * offload support in Ocelot
70 return (chain / VCAP_LOOKUP) % 10;
73 /* Caller must ensure this is a valid IS2 chain first,
74 * by calling ocelot_chain_to_block.
76 static int ocelot_chain_to_pag(int chain)
80 /* Backwards compatibility with older, single-chain tc-flower
81 * offload support in Ocelot
86 lookup = ocelot_chain_to_lookup(chain);
88 /* calculate PAG value as chain index relative to the first PAG */
89 return chain - VCAP_IS2_CHAIN(lookup, 0);
92 static bool ocelot_is_goto_target_valid(int goto_target, int chain,
97 /* Can't offload GOTO in VCAP ES0 */
99 return (goto_target < 0);
101 /* Non-optional GOTOs */
103 /* VCAP IS1 can be skipped, either partially or completely */
104 return (goto_target == VCAP_IS1_CHAIN(0) ||
105 goto_target == VCAP_IS1_CHAIN(1) ||
106 goto_target == VCAP_IS1_CHAIN(2) ||
107 goto_target == VCAP_IS2_CHAIN(0, 0) ||
108 goto_target == VCAP_IS2_CHAIN(1, 0) ||
109 goto_target == OCELOT_PSFP_CHAIN);
111 if (chain == VCAP_IS1_CHAIN(0))
112 return (goto_target == VCAP_IS1_CHAIN(1));
114 if (chain == VCAP_IS1_CHAIN(1))
115 return (goto_target == VCAP_IS1_CHAIN(2));
117 /* Lookup 2 of VCAP IS1 can really support non-optional GOTOs,
118 * using a Policy Association Group (PAG) value, which is an 8-bit
119 * value encoding a VCAP IS2 target chain.
121 if (chain == VCAP_IS1_CHAIN(2)) {
122 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
123 if (goto_target == VCAP_IS2_CHAIN(0, pag))
129 /* Non-optional GOTO from VCAP IS2 lookup 0 to lookup 1.
130 * We cannot change the PAG at this point.
132 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
133 if (chain == VCAP_IS2_CHAIN(0, pag))
134 return (goto_target == VCAP_IS2_CHAIN(1, pag));
136 /* VCAP IS2 lookup 1 can goto to PSFP block if hardware support */
137 for (pag = 0; pag < VCAP_IS2_NUM_PAG; pag++)
138 if (chain == VCAP_IS2_CHAIN(1, pag))
139 return (goto_target == OCELOT_PSFP_CHAIN);
144 static struct ocelot_vcap_filter *
145 ocelot_find_vcap_filter_that_points_at(struct ocelot *ocelot, int chain)
147 struct ocelot_vcap_filter *filter;
148 struct ocelot_vcap_block *block;
151 block_id = ocelot_chain_to_block(chain, true);
155 if (block_id == VCAP_IS2) {
156 block = &ocelot->block[VCAP_IS1];
158 list_for_each_entry(filter, &block->rules, list)
159 if (filter->type == OCELOT_VCAP_FILTER_PAG &&
160 filter->goto_target == chain)
164 list_for_each_entry(filter, &ocelot->dummy_rules, list)
165 if (filter->goto_target == chain)
172 ocelot_flower_parse_ingress_vlan_modify(struct ocelot *ocelot, int port,
173 struct ocelot_vcap_filter *filter,
174 const struct flow_action_entry *a,
175 struct netlink_ext_ack *extack)
177 struct ocelot_port *ocelot_port = ocelot->ports[port];
179 if (filter->goto_target != -1) {
180 NL_SET_ERR_MSG_MOD(extack,
181 "Last action must be GOTO");
185 if (!ocelot_port->vlan_aware) {
186 NL_SET_ERR_MSG_MOD(extack,
187 "Can only modify VLAN under VLAN aware bridge");
191 filter->action.vid_replace_ena = true;
192 filter->action.pcp_dei_ena = true;
193 filter->action.vid = a->vlan.vid;
194 filter->action.pcp = a->vlan.prio;
195 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
201 ocelot_flower_parse_egress_vlan_modify(struct ocelot_vcap_filter *filter,
202 const struct flow_action_entry *a,
203 struct netlink_ext_ack *extack)
205 enum ocelot_tag_tpid_sel tpid;
207 switch (ntohs(a->vlan.proto)) {
209 tpid = OCELOT_TAG_TPID_SEL_8021Q;
212 tpid = OCELOT_TAG_TPID_SEL_8021AD;
215 NL_SET_ERR_MSG_MOD(extack,
216 "Cannot modify custom TPID");
220 filter->action.tag_a_tpid_sel = tpid;
221 filter->action.push_outer_tag = OCELOT_ES0_TAG;
222 filter->action.tag_a_vid_sel = OCELOT_ES0_VID_PLUS_CLASSIFIED_VID;
223 filter->action.vid_a_val = a->vlan.vid;
224 filter->action.pcp_a_val = a->vlan.prio;
225 filter->action.tag_a_pcp_sel = OCELOT_ES0_PCP;
226 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
231 static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
232 bool ingress, struct flow_cls_offload *f,
233 struct ocelot_vcap_filter *filter)
235 const struct flow_action *action = &f->rule->action;
236 struct netlink_ext_ack *extack = f->common.extack;
237 bool allow_missing_goto_target = false;
238 const struct flow_action_entry *a;
239 enum ocelot_tag_tpid_sel tpid;
240 int i, chain, egress_port;
245 if (!flow_action_basic_hw_stats_check(&f->rule->action,
249 chain = f->common.chain_index;
250 filter->block_id = ocelot_chain_to_block(chain, ingress);
251 if (filter->block_id < 0) {
252 NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
255 if (filter->block_id == VCAP_IS1 || filter->block_id == VCAP_IS2)
256 filter->lookup = ocelot_chain_to_lookup(chain);
257 if (filter->block_id == VCAP_IS2)
258 filter->pag = ocelot_chain_to_pag(chain);
260 filter->goto_target = -1;
261 filter->type = OCELOT_VCAP_FILTER_DUMMY;
263 flow_action_for_each(i, a, action) {
265 case FLOW_ACTION_DROP:
266 if (filter->block_id != VCAP_IS2) {
267 NL_SET_ERR_MSG_MOD(extack,
268 "Drop action can only be offloaded to VCAP IS2");
271 if (filter->goto_target != -1) {
272 NL_SET_ERR_MSG_MOD(extack,
273 "Last action must be GOTO");
276 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
277 filter->action.port_mask = 0;
278 filter->action.police_ena = true;
279 filter->action.pol_ix = OCELOT_POLICER_DISCARD;
280 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
282 case FLOW_ACTION_TRAP:
283 if (filter->block_id != VCAP_IS2 ||
284 filter->lookup != 0) {
285 NL_SET_ERR_MSG_MOD(extack,
286 "Trap action can only be offloaded to VCAP IS2 lookup 0");
289 if (filter->goto_target != -1) {
290 NL_SET_ERR_MSG_MOD(extack,
291 "Last action must be GOTO");
294 filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
295 filter->action.port_mask = 0;
296 filter->action.cpu_copy_ena = true;
297 filter->action.cpu_qu_num = 0;
298 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
299 filter->is_trap = true;
301 case FLOW_ACTION_POLICE:
302 if (filter->block_id == PSFP_BLOCK_ID) {
303 filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
306 if (filter->block_id != VCAP_IS2 ||
307 filter->lookup != 0) {
308 NL_SET_ERR_MSG_MOD(extack,
309 "Police action can only be offloaded to VCAP IS2 lookup 0 or PSFP");
312 if (filter->goto_target != -1) {
313 NL_SET_ERR_MSG_MOD(extack,
314 "Last action must be GOTO");
318 err = ocelot_policer_validate(action, a, extack);
322 filter->action.police_ena = true;
324 pol_ix = a->hw_index + ocelot->vcap_pol.base;
325 pol_max = ocelot->vcap_pol.max;
327 if (ocelot->vcap_pol.max2 && pol_ix > pol_max) {
328 pol_ix += ocelot->vcap_pol.base2 - pol_max - 1;
329 pol_max = ocelot->vcap_pol.max2;
332 if (pol_ix >= pol_max)
335 filter->action.pol_ix = pol_ix;
337 rate = a->police.rate_bytes_ps;
338 filter->action.pol.rate = div_u64(rate, 1000) * 8;
339 filter->action.pol.burst = a->police.burst;
340 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
342 case FLOW_ACTION_REDIRECT:
343 if (filter->block_id != VCAP_IS2) {
344 NL_SET_ERR_MSG_MOD(extack,
345 "Redirect action can only be offloaded to VCAP IS2");
348 if (filter->goto_target != -1) {
349 NL_SET_ERR_MSG_MOD(extack,
350 "Last action must be GOTO");
353 egress_port = ocelot->ops->netdev_to_port(a->dev);
354 if (egress_port < 0) {
355 NL_SET_ERR_MSG_MOD(extack,
356 "Destination not an ocelot port");
359 filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
360 filter->action.port_mask = BIT(egress_port);
361 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
363 case FLOW_ACTION_MIRRED:
364 if (filter->block_id != VCAP_IS2) {
365 NL_SET_ERR_MSG_MOD(extack,
366 "Mirror action can only be offloaded to VCAP IS2");
369 if (filter->goto_target != -1) {
370 NL_SET_ERR_MSG_MOD(extack,
371 "Last action must be GOTO");
374 egress_port = ocelot->ops->netdev_to_port(a->dev);
375 if (egress_port < 0) {
376 NL_SET_ERR_MSG_MOD(extack,
377 "Destination not an ocelot port");
380 filter->egress_port.value = egress_port;
381 filter->action.mirror_ena = true;
382 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
384 case FLOW_ACTION_VLAN_POP:
385 if (filter->block_id != VCAP_IS1) {
386 NL_SET_ERR_MSG_MOD(extack,
387 "VLAN pop action can only be offloaded to VCAP IS1");
390 if (filter->goto_target != -1) {
391 NL_SET_ERR_MSG_MOD(extack,
392 "Last action must be GOTO");
395 filter->action.vlan_pop_cnt_ena = true;
396 filter->action.vlan_pop_cnt++;
397 if (filter->action.vlan_pop_cnt > 2) {
398 NL_SET_ERR_MSG_MOD(extack,
399 "Cannot pop more than 2 VLAN headers");
402 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
404 case FLOW_ACTION_VLAN_MANGLE:
405 if (filter->block_id == VCAP_IS1) {
406 err = ocelot_flower_parse_ingress_vlan_modify(ocelot, port,
409 } else if (filter->block_id == VCAP_ES0) {
410 err = ocelot_flower_parse_egress_vlan_modify(filter, a,
413 NL_SET_ERR_MSG_MOD(extack,
414 "VLAN modify action can only be offloaded to VCAP IS1 or ES0");
420 case FLOW_ACTION_PRIORITY:
421 if (filter->block_id != VCAP_IS1) {
422 NL_SET_ERR_MSG_MOD(extack,
423 "Priority action can only be offloaded to VCAP IS1");
426 if (filter->goto_target != -1) {
427 NL_SET_ERR_MSG_MOD(extack,
428 "Last action must be GOTO");
431 filter->action.qos_ena = true;
432 filter->action.qos_val = a->priority;
433 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
435 case FLOW_ACTION_GOTO:
436 filter->goto_target = a->chain_index;
438 if (filter->block_id == VCAP_IS1 && filter->lookup == 2) {
439 int pag = ocelot_chain_to_pag(filter->goto_target);
441 filter->action.pag_override_mask = 0xff;
442 filter->action.pag_val = pag;
443 filter->type = OCELOT_VCAP_FILTER_PAG;
446 case FLOW_ACTION_VLAN_PUSH:
447 if (filter->block_id != VCAP_ES0) {
448 NL_SET_ERR_MSG_MOD(extack,
449 "VLAN push action can only be offloaded to VCAP ES0");
452 switch (ntohs(a->vlan.proto)) {
454 tpid = OCELOT_TAG_TPID_SEL_8021Q;
457 tpid = OCELOT_TAG_TPID_SEL_8021AD;
460 NL_SET_ERR_MSG_MOD(extack,
461 "Cannot push custom TPID");
464 filter->action.tag_a_tpid_sel = tpid;
465 filter->action.push_outer_tag = OCELOT_ES0_TAG;
466 filter->action.tag_a_vid_sel = OCELOT_ES0_VID;
467 filter->action.vid_a_val = a->vlan.vid;
468 filter->action.pcp_a_val = a->vlan.prio;
469 filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
471 case FLOW_ACTION_GATE:
472 if (filter->block_id != PSFP_BLOCK_ID) {
473 NL_SET_ERR_MSG_MOD(extack,
474 "Gate action can only be offloaded to PSFP chain");
477 filter->type = OCELOT_PSFP_FILTER_OFFLOAD;
480 NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
485 if (filter->goto_target == -1) {
486 if ((filter->block_id == VCAP_IS2 && filter->lookup == 1) ||
487 chain == 0 || filter->block_id == PSFP_BLOCK_ID) {
488 allow_missing_goto_target = true;
490 NL_SET_ERR_MSG_MOD(extack, "Missing GOTO action");
495 if (!ocelot_is_goto_target_valid(filter->goto_target, chain, ingress) &&
496 !allow_missing_goto_target) {
497 NL_SET_ERR_MSG_MOD(extack, "Cannot offload this GOTO target");
504 static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port,
505 struct flow_cls_offload *f,
506 struct ocelot_vcap_filter *filter)
508 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
509 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
510 int key_length = vcap->keys[VCAP_ES0_IGR_PORT].length;
511 struct netlink_ext_ack *extack = f->common.extack;
512 struct net_device *dev, *indev;
513 struct flow_match_meta match;
516 flow_rule_match_meta(rule, &match);
518 if (!match.mask->ingress_ifindex)
521 if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
522 NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask");
526 dev = ocelot->ops->port_to_netdev(ocelot, port);
530 indev = __dev_get_by_index(dev_net(dev), match.key->ingress_ifindex);
532 NL_SET_ERR_MSG_MOD(extack,
533 "Can't find the ingress port to match on");
537 ingress_port = ocelot->ops->netdev_to_port(indev);
538 if (ingress_port < 0) {
539 NL_SET_ERR_MSG_MOD(extack,
540 "Can only offload an ocelot ingress port");
543 if (ingress_port == port) {
544 NL_SET_ERR_MSG_MOD(extack,
545 "Ingress port is equal to the egress port");
549 filter->ingress_port.value = ingress_port;
550 filter->ingress_port.mask = GENMASK(key_length - 1, 0);
556 ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
557 struct flow_cls_offload *f,
558 struct ocelot_vcap_filter *filter)
560 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
561 struct flow_dissector *dissector = rule->match.dissector;
562 struct netlink_ext_ack *extack = f->common.extack;
563 u16 proto = ntohs(f->common.protocol);
564 bool match_protocol = true;
567 if (dissector->used_keys &
568 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
569 BIT(FLOW_DISSECTOR_KEY_BASIC) |
570 BIT(FLOW_DISSECTOR_KEY_META) |
571 BIT(FLOW_DISSECTOR_KEY_PORTS) |
572 BIT(FLOW_DISSECTOR_KEY_VLAN) |
573 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
574 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
575 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
579 /* For VCAP ES0 (egress rewriter) we can match on the ingress port */
581 ret = ocelot_flower_parse_indev(ocelot, port, f, filter);
586 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
587 struct flow_match_control match;
589 flow_rule_match_control(rule, &match);
592 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
593 struct flow_match_eth_addrs match;
595 if (filter->block_id == VCAP_ES0) {
596 NL_SET_ERR_MSG_MOD(extack,
597 "VCAP ES0 cannot match on MAC address");
601 /* The hw support mac matches only for MAC_ETYPE key,
602 * therefore if other matches(port, tcp flags, etc) are added
605 if ((dissector->used_keys &
606 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
607 BIT(FLOW_DISSECTOR_KEY_BASIC) |
608 BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
609 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
610 BIT(FLOW_DISSECTOR_KEY_BASIC) |
611 BIT(FLOW_DISSECTOR_KEY_CONTROL)))
614 flow_rule_match_eth_addrs(rule, &match);
616 if (filter->block_id == VCAP_IS1 &&
617 !is_zero_ether_addr(match.mask->dst)) {
618 NL_SET_ERR_MSG_MOD(extack,
619 "Key type S1_NORMAL cannot match on destination MAC");
623 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
624 ether_addr_copy(filter->key.etype.dmac.value,
626 ether_addr_copy(filter->key.etype.smac.value,
628 ether_addr_copy(filter->key.etype.dmac.mask,
630 ether_addr_copy(filter->key.etype.smac.mask,
632 goto finished_key_parsing;
635 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
636 struct flow_match_basic match;
638 flow_rule_match_basic(rule, &match);
639 if (ntohs(match.key->n_proto) == ETH_P_IP) {
640 if (filter->block_id == VCAP_ES0) {
641 NL_SET_ERR_MSG_MOD(extack,
642 "VCAP ES0 cannot match on IP protocol");
646 filter->key_type = OCELOT_VCAP_KEY_IPV4;
647 filter->key.ipv4.proto.value[0] =
649 filter->key.ipv4.proto.mask[0] =
650 match.mask->ip_proto;
651 match_protocol = false;
653 if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
654 if (filter->block_id == VCAP_ES0) {
655 NL_SET_ERR_MSG_MOD(extack,
656 "VCAP ES0 cannot match on IP protocol");
660 filter->key_type = OCELOT_VCAP_KEY_IPV6;
661 filter->key.ipv6.proto.value[0] =
663 filter->key.ipv6.proto.mask[0] =
664 match.mask->ip_proto;
665 match_protocol = false;
669 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
671 struct flow_match_ipv4_addrs match;
674 if (filter->block_id == VCAP_ES0) {
675 NL_SET_ERR_MSG_MOD(extack,
676 "VCAP ES0 cannot match on IP address");
680 flow_rule_match_ipv4_addrs(rule, &match);
682 if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
683 NL_SET_ERR_MSG_MOD(extack,
684 "Key type S1_NORMAL cannot match on destination IP");
688 tmp = &filter->key.ipv4.sip.value.addr[0];
689 memcpy(tmp, &match.key->src, 4);
691 tmp = &filter->key.ipv4.sip.mask.addr[0];
692 memcpy(tmp, &match.mask->src, 4);
694 tmp = &filter->key.ipv4.dip.value.addr[0];
695 memcpy(tmp, &match.key->dst, 4);
697 tmp = &filter->key.ipv4.dip.mask.addr[0];
698 memcpy(tmp, &match.mask->dst, 4);
699 match_protocol = false;
702 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
703 proto == ETH_P_IPV6) {
707 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
708 struct flow_match_ports match;
710 if (filter->block_id == VCAP_ES0) {
711 NL_SET_ERR_MSG_MOD(extack,
712 "VCAP ES0 cannot match on L4 ports");
716 flow_rule_match_ports(rule, &match);
717 filter->key.ipv4.sport.value = ntohs(match.key->src);
718 filter->key.ipv4.sport.mask = ntohs(match.mask->src);
719 filter->key.ipv4.dport.value = ntohs(match.key->dst);
720 filter->key.ipv4.dport.mask = ntohs(match.mask->dst);
721 match_protocol = false;
724 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
725 struct flow_match_vlan match;
727 flow_rule_match_vlan(rule, &match);
728 filter->key_type = OCELOT_VCAP_KEY_ANY;
729 filter->vlan.vid.value = match.key->vlan_id;
730 filter->vlan.vid.mask = match.mask->vlan_id;
731 filter->vlan.pcp.value[0] = match.key->vlan_priority;
732 filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
733 match_protocol = false;
736 finished_key_parsing:
737 if (match_protocol && proto != ETH_P_ALL) {
738 if (filter->block_id == VCAP_ES0) {
739 NL_SET_ERR_MSG_MOD(extack,
740 "VCAP ES0 cannot match on L2 proto");
744 /* TODO: support SNAP, LLC etc */
745 if (proto < ETH_P_802_3_MIN)
747 filter->key_type = OCELOT_VCAP_KEY_ETYPE;
748 *(__be16 *)filter->key.etype.etype.value = htons(proto);
749 *(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
751 /* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
756 static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
757 struct flow_cls_offload *f,
758 struct ocelot_vcap_filter *filter)
762 filter->prio = f->common.prio;
763 filter->id.cookie = f->cookie;
764 filter->id.tc_offload = true;
766 ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
770 /* PSFP filter need to parse key by stream identification function. */
771 if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD)
774 return ocelot_flower_parse_key(ocelot, port, ingress, f, filter);
777 static struct ocelot_vcap_filter
778 *ocelot_vcap_filter_create(struct ocelot *ocelot, int port, bool ingress,
779 struct flow_cls_offload *f)
781 struct ocelot_vcap_filter *filter;
783 filter = kzalloc(sizeof(*filter), GFP_KERNEL);
788 filter->ingress_port_mask = BIT(port);
790 const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
791 int key_length = vcap->keys[VCAP_ES0_EGR_PORT].length;
793 filter->egress_port.value = port;
794 filter->egress_port.mask = GENMASK(key_length - 1, 0);
800 static int ocelot_vcap_dummy_filter_add(struct ocelot *ocelot,
801 struct ocelot_vcap_filter *filter)
803 list_add(&filter->list, &ocelot->dummy_rules);
808 static int ocelot_vcap_dummy_filter_del(struct ocelot *ocelot,
809 struct ocelot_vcap_filter *filter)
811 list_del(&filter->list);
817 /* If we have an egress VLAN modification rule, we need to actually write the
818 * delta between the input VLAN (from the key) and the output VLAN (from the
819 * action), but the action was parsed first. So we need to patch the delta into
823 ocelot_flower_patch_es0_vlan_modify(struct ocelot_vcap_filter *filter,
824 struct netlink_ext_ack *extack)
826 if (filter->block_id != VCAP_ES0 ||
827 filter->action.tag_a_vid_sel != OCELOT_ES0_VID_PLUS_CLASSIFIED_VID)
830 if (filter->vlan.vid.mask != VLAN_VID_MASK) {
831 NL_SET_ERR_MSG_MOD(extack,
832 "VCAP ES0 VLAN rewriting needs a full VLAN in the key");
836 filter->action.vid_a_val -= filter->vlan.vid.value;
837 filter->action.vid_a_val &= VLAN_VID_MASK;
842 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
843 struct flow_cls_offload *f, bool ingress)
845 struct netlink_ext_ack *extack = f->common.extack;
846 struct ocelot_vcap_filter *filter;
847 int chain = f->common.chain_index;
850 if (chain && !ocelot_find_vcap_filter_that_points_at(ocelot, chain)) {
851 NL_SET_ERR_MSG_MOD(extack, "No default GOTO action points to this chain");
855 block_id = ocelot_chain_to_block(chain, ingress);
857 NL_SET_ERR_MSG_MOD(extack, "Cannot offload to this chain");
861 filter = ocelot_vcap_block_find_filter_by_id(&ocelot->block[block_id],
864 /* Filter already exists on other ports */
866 NL_SET_ERR_MSG_MOD(extack, "VCAP ES0 does not support shared filters");
870 filter->ingress_port_mask |= BIT(port);
872 return ocelot_vcap_filter_replace(ocelot, filter);
875 /* Filter didn't exist, create it now */
876 filter = ocelot_vcap_filter_create(ocelot, port, ingress, f);
880 ret = ocelot_flower_parse(ocelot, port, ingress, f, filter);
886 ret = ocelot_flower_patch_es0_vlan_modify(filter, extack);
892 /* The non-optional GOTOs for the TCAM skeleton don't need
893 * to be actually offloaded.
895 if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
896 return ocelot_vcap_dummy_filter_add(ocelot, filter);
898 if (filter->type == OCELOT_PSFP_FILTER_OFFLOAD) {
900 if (ocelot->ops->psfp_filter_add)
901 return ocelot->ops->psfp_filter_add(ocelot, port, f);
903 NL_SET_ERR_MSG_MOD(extack, "PSFP chain is not supported in HW");
907 return ocelot_vcap_filter_add(ocelot, filter, f->common.extack);
909 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
911 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
912 struct flow_cls_offload *f, bool ingress)
914 struct ocelot_vcap_filter *filter;
915 struct ocelot_vcap_block *block;
918 block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
922 if (block_id == PSFP_BLOCK_ID) {
923 if (ocelot->ops->psfp_filter_del)
924 return ocelot->ops->psfp_filter_del(ocelot, f);
929 block = &ocelot->block[block_id];
931 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
935 if (filter->type == OCELOT_VCAP_FILTER_DUMMY)
936 return ocelot_vcap_dummy_filter_del(ocelot, filter);
939 filter->ingress_port_mask &= ~BIT(port);
940 if (filter->ingress_port_mask)
941 return ocelot_vcap_filter_replace(ocelot, filter);
944 return ocelot_vcap_filter_del(ocelot, filter);
946 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
948 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
949 struct flow_cls_offload *f, bool ingress)
951 struct ocelot_vcap_filter *filter;
952 struct ocelot_vcap_block *block;
953 struct flow_stats stats = {0};
956 block_id = ocelot_chain_to_block(f->common.chain_index, ingress);
960 if (block_id == PSFP_BLOCK_ID) {
961 if (ocelot->ops->psfp_stats_get) {
962 ret = ocelot->ops->psfp_stats_get(ocelot, f, &stats);
972 block = &ocelot->block[block_id];
974 filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie, true);
975 if (!filter || filter->type == OCELOT_VCAP_FILTER_DUMMY)
978 ret = ocelot_vcap_filter_stats_update(ocelot, filter);
982 stats.pkts = filter->stats.pkts;
985 flow_stats_update(&f->stats, 0x0, stats.pkts, stats.drops, 0x0,
986 FLOW_ACTION_HW_STATS_IMMEDIATE);
989 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);