1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2019-2022 Marvell International Ltd. All rights reserved */
4 #include <linux/kernel.h>
5 #include <linux/list.h>
8 #include "prestera_hw.h"
9 #include "prestera_flow.h"
10 #include "prestera_flower.h"
11 #include "prestera_matchall.h"
12 #include "prestera_span.h"
14 static int prestera_mall_prio_check(struct prestera_flow_block *block,
15 struct tc_cls_matchall_offload *f)
21 err = prestera_flower_prio_get(block, f->common.chain_index,
22 &flower_prio_min, &flower_prio_max);
24 /* No flower filters installed on this chain. */
28 NL_SET_ERR_MSG(f->common.extack, "Failed to get flower priorities");
32 if (f->common.prio <= flower_prio_max && !block->ingress) {
33 NL_SET_ERR_MSG(f->common.extack, "Failed to add in front of existing flower rules");
36 if (f->common.prio >= flower_prio_min && block->ingress) {
37 NL_SET_ERR_MSG(f->common.extack, "Failed to add behind of existing flower rules");
44 int prestera_mall_prio_get(struct prestera_flow_block *block,
45 u32 *prio_min, u32 *prio_max)
47 if (!block->mall.bound)
50 *prio_min = block->mall.prio_min;
51 *prio_max = block->mall.prio_max;
55 static void prestera_mall_prio_update(struct prestera_flow_block *block,
56 struct tc_cls_matchall_offload *f)
58 block->mall.prio_min = min(block->mall.prio_min, f->common.prio);
59 block->mall.prio_max = max(block->mall.prio_max, f->common.prio);
62 int prestera_mall_replace(struct prestera_flow_block *block,
63 struct tc_cls_matchall_offload *f)
65 struct prestera_flow_block_binding *binding;
66 __be16 protocol = f->common.protocol;
67 struct flow_action_entry *act;
68 struct prestera_port *port;
71 if (!flow_offload_has_one_action(&f->rule->action)) {
72 NL_SET_ERR_MSG(f->common.extack,
73 "Only singular actions are supported");
77 act = &f->rule->action.entries[0];
79 if (!prestera_netdev_check(act->dev)) {
80 NL_SET_ERR_MSG(f->common.extack,
81 "Only Marvell Prestera port is supported");
84 if (!tc_cls_can_offload_and_chain0(act->dev, &f->common))
86 if (act->id != FLOW_ACTION_MIRRED)
88 if (protocol != htons(ETH_P_ALL))
91 err = prestera_mall_prio_check(block, f);
95 port = netdev_priv(act->dev);
97 list_for_each_entry(binding, &block->binding_list, list) {
98 err = prestera_span_rule_add(binding, port, block->ingress);
105 prestera_mall_prio_update(block, f);
107 block->mall.bound = true;
111 list_for_each_entry_continue_reverse(binding,
112 &block->binding_list, list)
113 prestera_span_rule_del(binding, block->ingress);
117 void prestera_mall_destroy(struct prestera_flow_block *block)
119 struct prestera_flow_block_binding *binding;
121 list_for_each_entry(binding, &block->binding_list, list)
122 prestera_span_rule_del(binding, block->ingress);
124 block->mall.prio_min = UINT_MAX;
125 block->mall.prio_max = 0;
126 block->mall.bound = false;