1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /* Copyright (c) 2017-2020 Mellanox Technologies. All rights reserved */
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include <linux/kernel.h>
5*4882a593Smuzhiyun #include <linux/errno.h>
6*4882a593Smuzhiyun #include <linux/netdevice.h>
7*4882a593Smuzhiyun #include <net/flow_offload.h>
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include "spectrum.h"
10*4882a593Smuzhiyun #include "spectrum_span.h"
11*4882a593Smuzhiyun #include "reg.h"
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun static struct mlxsw_sp_mall_entry *
mlxsw_sp_mall_entry_find(struct mlxsw_sp_flow_block * block,unsigned long cookie)14*4882a593Smuzhiyun mlxsw_sp_mall_entry_find(struct mlxsw_sp_flow_block *block, unsigned long cookie)
15*4882a593Smuzhiyun {
16*4882a593Smuzhiyun struct mlxsw_sp_mall_entry *mall_entry;
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun list_for_each_entry(mall_entry, &block->mall.list, list)
19*4882a593Smuzhiyun if (mall_entry->cookie == cookie)
20*4882a593Smuzhiyun return mall_entry;
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun return NULL;
23*4882a593Smuzhiyun }
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun static int
mlxsw_sp_mall_port_mirror_add(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_mall_entry * mall_entry)26*4882a593Smuzhiyun mlxsw_sp_mall_port_mirror_add(struct mlxsw_sp_port *mlxsw_sp_port,
27*4882a593Smuzhiyun struct mlxsw_sp_mall_entry *mall_entry)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
30*4882a593Smuzhiyun struct mlxsw_sp_span_agent_parms agent_parms = {};
31*4882a593Smuzhiyun struct mlxsw_sp_span_trigger_parms parms;
32*4882a593Smuzhiyun enum mlxsw_sp_span_trigger trigger;
33*4882a593Smuzhiyun int err;
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun if (!mall_entry->mirror.to_dev) {
36*4882a593Smuzhiyun netdev_err(mlxsw_sp_port->dev, "Could not find requested device\n");
37*4882a593Smuzhiyun return -EINVAL;
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun agent_parms.to_dev = mall_entry->mirror.to_dev;
41*4882a593Smuzhiyun err = mlxsw_sp_span_agent_get(mlxsw_sp, &mall_entry->mirror.span_id,
42*4882a593Smuzhiyun &agent_parms);
43*4882a593Smuzhiyun if (err)
44*4882a593Smuzhiyun return err;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port,
47*4882a593Smuzhiyun mall_entry->ingress);
48*4882a593Smuzhiyun if (err)
49*4882a593Smuzhiyun goto err_analyzed_port_get;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun trigger = mall_entry->ingress ? MLXSW_SP_SPAN_TRIGGER_INGRESS :
52*4882a593Smuzhiyun MLXSW_SP_SPAN_TRIGGER_EGRESS;
53*4882a593Smuzhiyun parms.span_id = mall_entry->mirror.span_id;
54*4882a593Smuzhiyun err = mlxsw_sp_span_agent_bind(mlxsw_sp, trigger, mlxsw_sp_port,
55*4882a593Smuzhiyun &parms);
56*4882a593Smuzhiyun if (err)
57*4882a593Smuzhiyun goto err_agent_bind;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun return 0;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun err_agent_bind:
62*4882a593Smuzhiyun mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, mall_entry->ingress);
63*4882a593Smuzhiyun err_analyzed_port_get:
64*4882a593Smuzhiyun mlxsw_sp_span_agent_put(mlxsw_sp, mall_entry->mirror.span_id);
65*4882a593Smuzhiyun return err;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun static void
mlxsw_sp_mall_port_mirror_del(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_mall_entry * mall_entry)69*4882a593Smuzhiyun mlxsw_sp_mall_port_mirror_del(struct mlxsw_sp_port *mlxsw_sp_port,
70*4882a593Smuzhiyun struct mlxsw_sp_mall_entry *mall_entry)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
73*4882a593Smuzhiyun struct mlxsw_sp_span_trigger_parms parms;
74*4882a593Smuzhiyun enum mlxsw_sp_span_trigger trigger;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun trigger = mall_entry->ingress ? MLXSW_SP_SPAN_TRIGGER_INGRESS :
77*4882a593Smuzhiyun MLXSW_SP_SPAN_TRIGGER_EGRESS;
78*4882a593Smuzhiyun parms.span_id = mall_entry->mirror.span_id;
79*4882a593Smuzhiyun mlxsw_sp_span_agent_unbind(mlxsw_sp, trigger, mlxsw_sp_port, &parms);
80*4882a593Smuzhiyun mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, mall_entry->ingress);
81*4882a593Smuzhiyun mlxsw_sp_span_agent_put(mlxsw_sp, mall_entry->mirror.span_id);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
mlxsw_sp_mall_port_sample_set(struct mlxsw_sp_port * mlxsw_sp_port,bool enable,u32 rate)84*4882a593Smuzhiyun static int mlxsw_sp_mall_port_sample_set(struct mlxsw_sp_port *mlxsw_sp_port,
85*4882a593Smuzhiyun bool enable, u32 rate)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
88*4882a593Smuzhiyun char mpsc_pl[MLXSW_REG_MPSC_LEN];
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun mlxsw_reg_mpsc_pack(mpsc_pl, mlxsw_sp_port->local_port, enable, rate);
91*4882a593Smuzhiyun return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpsc), mpsc_pl);
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun static int
mlxsw_sp_mall_port_sample_add(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_mall_entry * mall_entry)95*4882a593Smuzhiyun mlxsw_sp_mall_port_sample_add(struct mlxsw_sp_port *mlxsw_sp_port,
96*4882a593Smuzhiyun struct mlxsw_sp_mall_entry *mall_entry)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun int err;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun if (rtnl_dereference(mlxsw_sp_port->sample)) {
101*4882a593Smuzhiyun netdev_err(mlxsw_sp_port->dev, "sample already active\n");
102*4882a593Smuzhiyun return -EEXIST;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun rcu_assign_pointer(mlxsw_sp_port->sample, &mall_entry->sample);
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun err = mlxsw_sp_mall_port_sample_set(mlxsw_sp_port, true,
107*4882a593Smuzhiyun mall_entry->sample.rate);
108*4882a593Smuzhiyun if (err)
109*4882a593Smuzhiyun goto err_port_sample_set;
110*4882a593Smuzhiyun return 0;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun err_port_sample_set:
113*4882a593Smuzhiyun RCU_INIT_POINTER(mlxsw_sp_port->sample, NULL);
114*4882a593Smuzhiyun return err;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun static void
mlxsw_sp_mall_port_sample_del(struct mlxsw_sp_port * mlxsw_sp_port)118*4882a593Smuzhiyun mlxsw_sp_mall_port_sample_del(struct mlxsw_sp_port *mlxsw_sp_port)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun if (!mlxsw_sp_port->sample)
121*4882a593Smuzhiyun return;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun mlxsw_sp_mall_port_sample_set(mlxsw_sp_port, false, 1);
124*4882a593Smuzhiyun RCU_INIT_POINTER(mlxsw_sp_port->sample, NULL);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun static int
mlxsw_sp_mall_port_rule_add(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_mall_entry * mall_entry)128*4882a593Smuzhiyun mlxsw_sp_mall_port_rule_add(struct mlxsw_sp_port *mlxsw_sp_port,
129*4882a593Smuzhiyun struct mlxsw_sp_mall_entry *mall_entry)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun switch (mall_entry->type) {
132*4882a593Smuzhiyun case MLXSW_SP_MALL_ACTION_TYPE_MIRROR:
133*4882a593Smuzhiyun return mlxsw_sp_mall_port_mirror_add(mlxsw_sp_port, mall_entry);
134*4882a593Smuzhiyun case MLXSW_SP_MALL_ACTION_TYPE_SAMPLE:
135*4882a593Smuzhiyun return mlxsw_sp_mall_port_sample_add(mlxsw_sp_port, mall_entry);
136*4882a593Smuzhiyun default:
137*4882a593Smuzhiyun WARN_ON(1);
138*4882a593Smuzhiyun return -EINVAL;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun static void
mlxsw_sp_mall_port_rule_del(struct mlxsw_sp_port * mlxsw_sp_port,struct mlxsw_sp_mall_entry * mall_entry)143*4882a593Smuzhiyun mlxsw_sp_mall_port_rule_del(struct mlxsw_sp_port *mlxsw_sp_port,
144*4882a593Smuzhiyun struct mlxsw_sp_mall_entry *mall_entry)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun switch (mall_entry->type) {
147*4882a593Smuzhiyun case MLXSW_SP_MALL_ACTION_TYPE_MIRROR:
148*4882a593Smuzhiyun mlxsw_sp_mall_port_mirror_del(mlxsw_sp_port, mall_entry);
149*4882a593Smuzhiyun break;
150*4882a593Smuzhiyun case MLXSW_SP_MALL_ACTION_TYPE_SAMPLE:
151*4882a593Smuzhiyun mlxsw_sp_mall_port_sample_del(mlxsw_sp_port);
152*4882a593Smuzhiyun break;
153*4882a593Smuzhiyun default:
154*4882a593Smuzhiyun WARN_ON(1);
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
mlxsw_sp_mall_prio_update(struct mlxsw_sp_flow_block * block)158*4882a593Smuzhiyun static void mlxsw_sp_mall_prio_update(struct mlxsw_sp_flow_block *block)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun struct mlxsw_sp_mall_entry *mall_entry;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun if (list_empty(&block->mall.list))
163*4882a593Smuzhiyun return;
164*4882a593Smuzhiyun block->mall.min_prio = UINT_MAX;
165*4882a593Smuzhiyun block->mall.max_prio = 0;
166*4882a593Smuzhiyun list_for_each_entry(mall_entry, &block->mall.list, list) {
167*4882a593Smuzhiyun if (mall_entry->priority < block->mall.min_prio)
168*4882a593Smuzhiyun block->mall.min_prio = mall_entry->priority;
169*4882a593Smuzhiyun if (mall_entry->priority > block->mall.max_prio)
170*4882a593Smuzhiyun block->mall.max_prio = mall_entry->priority;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
mlxsw_sp_mall_replace(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_flow_block * block,struct tc_cls_matchall_offload * f)174*4882a593Smuzhiyun int mlxsw_sp_mall_replace(struct mlxsw_sp *mlxsw_sp,
175*4882a593Smuzhiyun struct mlxsw_sp_flow_block *block,
176*4882a593Smuzhiyun struct tc_cls_matchall_offload *f)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun struct mlxsw_sp_flow_block_binding *binding;
179*4882a593Smuzhiyun struct mlxsw_sp_mall_entry *mall_entry;
180*4882a593Smuzhiyun __be16 protocol = f->common.protocol;
181*4882a593Smuzhiyun struct flow_action_entry *act;
182*4882a593Smuzhiyun unsigned int flower_min_prio;
183*4882a593Smuzhiyun unsigned int flower_max_prio;
184*4882a593Smuzhiyun bool flower_prio_valid;
185*4882a593Smuzhiyun int err;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun if (!flow_offload_has_one_action(&f->rule->action)) {
188*4882a593Smuzhiyun NL_SET_ERR_MSG(f->common.extack, "Only singular actions are supported");
189*4882a593Smuzhiyun return -EOPNOTSUPP;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun if (f->common.chain_index) {
193*4882a593Smuzhiyun NL_SET_ERR_MSG(f->common.extack, "Only chain 0 is supported");
194*4882a593Smuzhiyun return -EOPNOTSUPP;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun if (mlxsw_sp_flow_block_is_mixed_bound(block)) {
198*4882a593Smuzhiyun NL_SET_ERR_MSG(f->common.extack, "Only not mixed bound blocks are supported");
199*4882a593Smuzhiyun return -EOPNOTSUPP;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun err = mlxsw_sp_flower_prio_get(mlxsw_sp, block, f->common.chain_index,
203*4882a593Smuzhiyun &flower_min_prio, &flower_max_prio);
204*4882a593Smuzhiyun if (err) {
205*4882a593Smuzhiyun if (err != -ENOENT) {
206*4882a593Smuzhiyun NL_SET_ERR_MSG(f->common.extack, "Failed to get flower priorities");
207*4882a593Smuzhiyun return err;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun flower_prio_valid = false;
210*4882a593Smuzhiyun /* No flower filters are installed in specified chain. */
211*4882a593Smuzhiyun } else {
212*4882a593Smuzhiyun flower_prio_valid = true;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun mall_entry = kzalloc(sizeof(*mall_entry), GFP_KERNEL);
216*4882a593Smuzhiyun if (!mall_entry)
217*4882a593Smuzhiyun return -ENOMEM;
218*4882a593Smuzhiyun mall_entry->cookie = f->cookie;
219*4882a593Smuzhiyun mall_entry->priority = f->common.prio;
220*4882a593Smuzhiyun mall_entry->ingress = mlxsw_sp_flow_block_is_ingress_bound(block);
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun act = &f->rule->action.entries[0];
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun if (act->id == FLOW_ACTION_MIRRED && protocol == htons(ETH_P_ALL)) {
225*4882a593Smuzhiyun if (flower_prio_valid && mall_entry->ingress &&
226*4882a593Smuzhiyun mall_entry->priority >= flower_min_prio) {
227*4882a593Smuzhiyun NL_SET_ERR_MSG(f->common.extack, "Failed to add behind existing flower rules");
228*4882a593Smuzhiyun err = -EOPNOTSUPP;
229*4882a593Smuzhiyun goto errout;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun if (flower_prio_valid && !mall_entry->ingress &&
232*4882a593Smuzhiyun mall_entry->priority <= flower_max_prio) {
233*4882a593Smuzhiyun NL_SET_ERR_MSG(f->common.extack, "Failed to add in front of existing flower rules");
234*4882a593Smuzhiyun err = -EOPNOTSUPP;
235*4882a593Smuzhiyun goto errout;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun mall_entry->type = MLXSW_SP_MALL_ACTION_TYPE_MIRROR;
238*4882a593Smuzhiyun mall_entry->mirror.to_dev = act->dev;
239*4882a593Smuzhiyun } else if (act->id == FLOW_ACTION_SAMPLE &&
240*4882a593Smuzhiyun protocol == htons(ETH_P_ALL)) {
241*4882a593Smuzhiyun if (!mall_entry->ingress) {
242*4882a593Smuzhiyun NL_SET_ERR_MSG(f->common.extack, "Sample is not supported on egress");
243*4882a593Smuzhiyun err = -EOPNOTSUPP;
244*4882a593Smuzhiyun goto errout;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun if (flower_prio_valid &&
247*4882a593Smuzhiyun mall_entry->priority >= flower_min_prio) {
248*4882a593Smuzhiyun NL_SET_ERR_MSG(f->common.extack, "Failed to add behind existing flower rules");
249*4882a593Smuzhiyun err = -EOPNOTSUPP;
250*4882a593Smuzhiyun goto errout;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun if (act->sample.rate > MLXSW_REG_MPSC_RATE_MAX) {
253*4882a593Smuzhiyun NL_SET_ERR_MSG(f->common.extack, "Sample rate not supported");
254*4882a593Smuzhiyun err = -EOPNOTSUPP;
255*4882a593Smuzhiyun goto errout;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun mall_entry->type = MLXSW_SP_MALL_ACTION_TYPE_SAMPLE;
258*4882a593Smuzhiyun mall_entry->sample.psample_group = act->sample.psample_group;
259*4882a593Smuzhiyun mall_entry->sample.truncate = act->sample.truncate;
260*4882a593Smuzhiyun mall_entry->sample.trunc_size = act->sample.trunc_size;
261*4882a593Smuzhiyun mall_entry->sample.rate = act->sample.rate;
262*4882a593Smuzhiyun } else {
263*4882a593Smuzhiyun err = -EOPNOTSUPP;
264*4882a593Smuzhiyun goto errout;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun list_for_each_entry(binding, &block->binding_list, list) {
268*4882a593Smuzhiyun err = mlxsw_sp_mall_port_rule_add(binding->mlxsw_sp_port,
269*4882a593Smuzhiyun mall_entry);
270*4882a593Smuzhiyun if (err)
271*4882a593Smuzhiyun goto rollback;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun block->rule_count++;
275*4882a593Smuzhiyun if (mall_entry->ingress)
276*4882a593Smuzhiyun block->egress_blocker_rule_count++;
277*4882a593Smuzhiyun else
278*4882a593Smuzhiyun block->ingress_blocker_rule_count++;
279*4882a593Smuzhiyun list_add_tail(&mall_entry->list, &block->mall.list);
280*4882a593Smuzhiyun mlxsw_sp_mall_prio_update(block);
281*4882a593Smuzhiyun return 0;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun rollback:
284*4882a593Smuzhiyun list_for_each_entry_continue_reverse(binding, &block->binding_list,
285*4882a593Smuzhiyun list)
286*4882a593Smuzhiyun mlxsw_sp_mall_port_rule_del(binding->mlxsw_sp_port, mall_entry);
287*4882a593Smuzhiyun errout:
288*4882a593Smuzhiyun kfree(mall_entry);
289*4882a593Smuzhiyun return err;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
mlxsw_sp_mall_destroy(struct mlxsw_sp_flow_block * block,struct tc_cls_matchall_offload * f)292*4882a593Smuzhiyun void mlxsw_sp_mall_destroy(struct mlxsw_sp_flow_block *block,
293*4882a593Smuzhiyun struct tc_cls_matchall_offload *f)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun struct mlxsw_sp_flow_block_binding *binding;
296*4882a593Smuzhiyun struct mlxsw_sp_mall_entry *mall_entry;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun mall_entry = mlxsw_sp_mall_entry_find(block, f->cookie);
299*4882a593Smuzhiyun if (!mall_entry) {
300*4882a593Smuzhiyun NL_SET_ERR_MSG(f->common.extack, "Entry not found");
301*4882a593Smuzhiyun return;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun list_del(&mall_entry->list);
305*4882a593Smuzhiyun if (mall_entry->ingress)
306*4882a593Smuzhiyun block->egress_blocker_rule_count--;
307*4882a593Smuzhiyun else
308*4882a593Smuzhiyun block->ingress_blocker_rule_count--;
309*4882a593Smuzhiyun block->rule_count--;
310*4882a593Smuzhiyun list_for_each_entry(binding, &block->binding_list, list)
311*4882a593Smuzhiyun mlxsw_sp_mall_port_rule_del(binding->mlxsw_sp_port, mall_entry);
312*4882a593Smuzhiyun kfree_rcu(mall_entry, rcu); /* sample RX packets may be in-flight */
313*4882a593Smuzhiyun mlxsw_sp_mall_prio_update(block);
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
mlxsw_sp_mall_port_bind(struct mlxsw_sp_flow_block * block,struct mlxsw_sp_port * mlxsw_sp_port)316*4882a593Smuzhiyun int mlxsw_sp_mall_port_bind(struct mlxsw_sp_flow_block *block,
317*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun struct mlxsw_sp_mall_entry *mall_entry;
320*4882a593Smuzhiyun int err;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun list_for_each_entry(mall_entry, &block->mall.list, list) {
323*4882a593Smuzhiyun err = mlxsw_sp_mall_port_rule_add(mlxsw_sp_port, mall_entry);
324*4882a593Smuzhiyun if (err)
325*4882a593Smuzhiyun goto rollback;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun return 0;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun rollback:
330*4882a593Smuzhiyun list_for_each_entry_continue_reverse(mall_entry, &block->mall.list,
331*4882a593Smuzhiyun list)
332*4882a593Smuzhiyun mlxsw_sp_mall_port_rule_del(mlxsw_sp_port, mall_entry);
333*4882a593Smuzhiyun return err;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun
mlxsw_sp_mall_port_unbind(struct mlxsw_sp_flow_block * block,struct mlxsw_sp_port * mlxsw_sp_port)336*4882a593Smuzhiyun void mlxsw_sp_mall_port_unbind(struct mlxsw_sp_flow_block *block,
337*4882a593Smuzhiyun struct mlxsw_sp_port *mlxsw_sp_port)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun struct mlxsw_sp_mall_entry *mall_entry;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun list_for_each_entry(mall_entry, &block->mall.list, list)
342*4882a593Smuzhiyun mlxsw_sp_mall_port_rule_del(mlxsw_sp_port, mall_entry);
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
mlxsw_sp_mall_prio_get(struct mlxsw_sp_flow_block * block,u32 chain_index,unsigned int * p_min_prio,unsigned int * p_max_prio)345*4882a593Smuzhiyun int mlxsw_sp_mall_prio_get(struct mlxsw_sp_flow_block *block, u32 chain_index,
346*4882a593Smuzhiyun unsigned int *p_min_prio, unsigned int *p_max_prio)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun if (chain_index || list_empty(&block->mall.list))
349*4882a593Smuzhiyun /* In case there are no matchall rules, the caller
350*4882a593Smuzhiyun * receives -ENOENT to indicate there is no need
351*4882a593Smuzhiyun * to check the priorities.
352*4882a593Smuzhiyun */
353*4882a593Smuzhiyun return -ENOENT;
354*4882a593Smuzhiyun *p_min_prio = block->mall.min_prio;
355*4882a593Smuzhiyun *p_max_prio = block->mall.max_prio;
356*4882a593Smuzhiyun return 0;
357*4882a593Smuzhiyun }
358