1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2019 Mellanox Technologies. All rights reserved */
3 
4 #include <linux/bitops.h>
5 #include <linux/kernel.h>
6 #include <linux/netlink.h>
7 #include <net/devlink.h>
8 #include <uapi/linux/devlink.h>
9 
10 #include "core.h"
11 #include "reg.h"
12 #include "spectrum.h"
13 #include "spectrum_trap.h"
14 
15 struct mlxsw_sp_trap_policer_item {
16 	struct devlink_trap_policer policer;
17 	u16 hw_id;
18 };
19 
20 struct mlxsw_sp_trap_group_item {
21 	struct devlink_trap_group group;
22 	u16 hw_group_id;
23 	u8 priority;
24 };
25 
26 #define MLXSW_SP_TRAP_LISTENERS_MAX 3
27 
28 struct mlxsw_sp_trap_item {
29 	struct devlink_trap trap;
30 	struct mlxsw_listener listeners_arr[MLXSW_SP_TRAP_LISTENERS_MAX];
31 };
32 
33 /* All driver-specific traps must be documented in
34  * Documentation/networking/devlink/mlxsw.rst
35  */
36 enum {
37 	DEVLINK_MLXSW_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX,
38 	DEVLINK_MLXSW_TRAP_ID_IRIF_DISABLED,
39 	DEVLINK_MLXSW_TRAP_ID_ERIF_DISABLED,
40 };
41 
42 #define DEVLINK_MLXSW_TRAP_NAME_IRIF_DISABLED \
43 	"irif_disabled"
44 #define DEVLINK_MLXSW_TRAP_NAME_ERIF_DISABLED \
45 	"erif_disabled"
46 
47 #define MLXSW_SP_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT
48 
49 static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
50 				u8 local_port,
51 				struct mlxsw_sp_port *mlxsw_sp_port)
52 {
53 	struct mlxsw_sp_port_pcpu_stats *pcpu_stats;
54 
55 	if (unlikely(!mlxsw_sp_port)) {
56 		dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n",
57 				     local_port);
58 		kfree_skb(skb);
59 		return -EINVAL;
60 	}
61 
62 	skb->dev = mlxsw_sp_port->dev;
63 
64 	pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats);
65 	u64_stats_update_begin(&pcpu_stats->syncp);
66 	pcpu_stats->rx_packets++;
67 	pcpu_stats->rx_bytes += skb->len;
68 	u64_stats_update_end(&pcpu_stats->syncp);
69 
70 	skb->protocol = eth_type_trans(skb, skb->dev);
71 
72 	return 0;
73 }
74 
75 static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port,
76 				      void *trap_ctx)
77 {
78 	struct devlink_port *in_devlink_port;
79 	struct mlxsw_sp_port *mlxsw_sp_port;
80 	struct mlxsw_sp *mlxsw_sp;
81 	struct devlink *devlink;
82 	int err;
83 
84 	mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
85 	mlxsw_sp_port = mlxsw_sp->ports[local_port];
86 
87 	err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
88 	if (err)
89 		return;
90 
91 	devlink = priv_to_devlink(mlxsw_sp->core);
92 	in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
93 							   local_port);
94 	skb_push(skb, ETH_HLEN);
95 	devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL);
96 	consume_skb(skb);
97 }
98 
99 static void mlxsw_sp_rx_acl_drop_listener(struct sk_buff *skb, u8 local_port,
100 					  void *trap_ctx)
101 {
102 	u32 cookie_index = mlxsw_skb_cb(skb)->cookie_index;
103 	const struct flow_action_cookie *fa_cookie;
104 	struct devlink_port *in_devlink_port;
105 	struct mlxsw_sp_port *mlxsw_sp_port;
106 	struct mlxsw_sp *mlxsw_sp;
107 	struct devlink *devlink;
108 	int err;
109 
110 	mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
111 	mlxsw_sp_port = mlxsw_sp->ports[local_port];
112 
113 	err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
114 	if (err)
115 		return;
116 
117 	devlink = priv_to_devlink(mlxsw_sp->core);
118 	in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
119 							   local_port);
120 	skb_push(skb, ETH_HLEN);
121 	rcu_read_lock();
122 	fa_cookie = mlxsw_sp_acl_act_cookie_lookup(mlxsw_sp, cookie_index);
123 	devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, fa_cookie);
124 	rcu_read_unlock();
125 	consume_skb(skb);
126 }
127 
128 static int __mlxsw_sp_rx_no_mark_listener(struct sk_buff *skb, u8 local_port,
129 					  void *trap_ctx)
130 {
131 	struct devlink_port *in_devlink_port;
132 	struct mlxsw_sp_port *mlxsw_sp_port;
133 	struct mlxsw_sp *mlxsw_sp;
134 	struct devlink *devlink;
135 	int err;
136 
137 	mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
138 	mlxsw_sp_port = mlxsw_sp->ports[local_port];
139 
140 	err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
141 	if (err)
142 		return err;
143 
144 	devlink = priv_to_devlink(mlxsw_sp->core);
145 	in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
146 							   local_port);
147 	skb_push(skb, ETH_HLEN);
148 	devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL);
149 	skb_pull(skb, ETH_HLEN);
150 
151 	return 0;
152 }
153 
154 static void mlxsw_sp_rx_no_mark_listener(struct sk_buff *skb, u8 local_port,
155 					 void *trap_ctx)
156 {
157 	int err;
158 
159 	err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
160 	if (err)
161 		return;
162 
163 	netif_receive_skb(skb);
164 }
165 
166 static void mlxsw_sp_rx_mark_listener(struct sk_buff *skb, u8 local_port,
167 				      void *trap_ctx)
168 {
169 	skb->offload_fwd_mark = 1;
170 	mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
171 }
172 
173 static void mlxsw_sp_rx_l3_mark_listener(struct sk_buff *skb, u8 local_port,
174 					 void *trap_ctx)
175 {
176 	skb->offload_l3_fwd_mark = 1;
177 	skb->offload_fwd_mark = 1;
178 	mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
179 }
180 
181 static void mlxsw_sp_rx_ptp_listener(struct sk_buff *skb, u8 local_port,
182 				     void *trap_ctx)
183 {
184 	struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
185 	int err;
186 
187 	err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
188 	if (err)
189 		return;
190 
191 	/* The PTP handler expects skb->data to point to the start of the
192 	 * Ethernet header.
193 	 */
194 	skb_push(skb, ETH_HLEN);
195 	mlxsw_sp_ptp_receive(mlxsw_sp, skb, local_port);
196 }
197 
198 static void mlxsw_sp_rx_sample_listener(struct sk_buff *skb, u8 local_port,
199 					void *trap_ctx)
200 {
201 	struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
202 	int err;
203 
204 	err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
205 	if (err)
206 		return;
207 
208 	/* The sample handler expects skb->data to point to the start of the
209 	 * Ethernet header.
210 	 */
211 	skb_push(skb, ETH_HLEN);
212 	mlxsw_sp_sample_receive(mlxsw_sp, skb, local_port);
213 }
214 
215 #define MLXSW_SP_TRAP_DROP(_id, _group_id)				      \
216 	DEVLINK_TRAP_GENERIC(DROP, DROP, _id,				      \
217 			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
218 			     MLXSW_SP_TRAP_METADATA)
219 
220 #define MLXSW_SP_TRAP_DROP_EXT(_id, _group_id, _metadata)		      \
221 	DEVLINK_TRAP_GENERIC(DROP, DROP, _id,				      \
222 			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
223 			     MLXSW_SP_TRAP_METADATA | (_metadata))
224 
225 #define MLXSW_SP_TRAP_DRIVER_DROP(_id, _group_id)			      \
226 	DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_MLXSW_TRAP_ID_##_id,	      \
227 			    DEVLINK_MLXSW_TRAP_NAME_##_id,		      \
228 			    DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
229 			    MLXSW_SP_TRAP_METADATA)
230 
231 #define MLXSW_SP_TRAP_EXCEPTION(_id, _group_id)		      \
232 	DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id,			      \
233 			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
234 			     MLXSW_SP_TRAP_METADATA)
235 
236 #define MLXSW_SP_TRAP_CONTROL(_id, _group_id, _action)			      \
237 	DEVLINK_TRAP_GENERIC(CONTROL, _action, _id,			      \
238 			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
239 			     MLXSW_SP_TRAP_METADATA)
240 
241 #define MLXSW_SP_RXL_DISCARD(_id, _group_id)				      \
242 	MLXSW_RXL_DIS(mlxsw_sp_rx_drop_listener, DISCARD_##_id,		      \
243 		      TRAP_EXCEPTION_TO_CPU, false, SP_##_group_id,	      \
244 		      SET_FW_DEFAULT, SP_##_group_id)
245 
246 #define MLXSW_SP_RXL_ACL_DISCARD(_id, _en_group_id, _dis_group_id)	      \
247 	MLXSW_RXL_DIS(mlxsw_sp_rx_acl_drop_listener, DISCARD_##_id,	      \
248 		      TRAP_EXCEPTION_TO_CPU, false, SP_##_en_group_id,	      \
249 		      SET_FW_DEFAULT, SP_##_dis_group_id)
250 
251 #define MLXSW_SP_RXL_EXCEPTION(_id, _group_id, _action)			      \
252 	MLXSW_RXL(mlxsw_sp_rx_mark_listener, _id,			      \
253 		   _action, false, SP_##_group_id, SET_FW_DEFAULT)
254 
255 #define MLXSW_SP_RXL_NO_MARK(_id, _group_id, _action, _is_ctrl)		      \
256 	MLXSW_RXL(mlxsw_sp_rx_no_mark_listener, _id, _action,		      \
257 		  _is_ctrl, SP_##_group_id, DISCARD)
258 
259 #define MLXSW_SP_RXL_MARK(_id, _group_id, _action, _is_ctrl)		      \
260 	MLXSW_RXL(mlxsw_sp_rx_mark_listener, _id, _action, _is_ctrl,	      \
261 		  SP_##_group_id, DISCARD)
262 
263 #define MLXSW_SP_RXL_L3_MARK(_id, _group_id, _action, _is_ctrl)		      \
264 	MLXSW_RXL(mlxsw_sp_rx_l3_mark_listener, _id, _action, _is_ctrl,	      \
265 		  SP_##_group_id, DISCARD)
266 
267 #define MLXSW_SP_TRAP_POLICER(_id, _rate, _burst)			      \
268 	DEVLINK_TRAP_POLICER(_id, _rate, _burst,			      \
269 			     MLXSW_REG_QPCR_HIGHEST_CIR,		      \
270 			     MLXSW_REG_QPCR_LOWEST_CIR,			      \
271 			     1 << MLXSW_REG_QPCR_HIGHEST_CBS,		      \
272 			     1 << MLXSW_REG_QPCR_LOWEST_CBS)
273 
274 /* Ordered by policer identifier */
275 static const struct mlxsw_sp_trap_policer_item
276 mlxsw_sp_trap_policer_items_arr[] = {
277 	{
278 		.policer = MLXSW_SP_TRAP_POLICER(1, 10 * 1024, 128),
279 	},
280 	{
281 		.policer = MLXSW_SP_TRAP_POLICER(2, 128, 128),
282 	},
283 	{
284 		.policer = MLXSW_SP_TRAP_POLICER(3, 128, 128),
285 	},
286 	{
287 		.policer = MLXSW_SP_TRAP_POLICER(4, 128, 128),
288 	},
289 	{
290 		.policer = MLXSW_SP_TRAP_POLICER(5, 16 * 1024, 128),
291 	},
292 	{
293 		.policer = MLXSW_SP_TRAP_POLICER(6, 128, 128),
294 	},
295 	{
296 		.policer = MLXSW_SP_TRAP_POLICER(7, 1024, 128),
297 	},
298 	{
299 		.policer = MLXSW_SP_TRAP_POLICER(8, 20 * 1024, 1024),
300 	},
301 	{
302 		.policer = MLXSW_SP_TRAP_POLICER(9, 128, 128),
303 	},
304 	{
305 		.policer = MLXSW_SP_TRAP_POLICER(10, 1024, 128),
306 	},
307 	{
308 		.policer = MLXSW_SP_TRAP_POLICER(11, 360, 128),
309 	},
310 	{
311 		.policer = MLXSW_SP_TRAP_POLICER(12, 128, 128),
312 	},
313 	{
314 		.policer = MLXSW_SP_TRAP_POLICER(13, 128, 128),
315 	},
316 	{
317 		.policer = MLXSW_SP_TRAP_POLICER(14, 1024, 128),
318 	},
319 	{
320 		.policer = MLXSW_SP_TRAP_POLICER(15, 1024, 128),
321 	},
322 	{
323 		.policer = MLXSW_SP_TRAP_POLICER(16, 24 * 1024, 4096),
324 	},
325 	{
326 		.policer = MLXSW_SP_TRAP_POLICER(17, 19 * 1024, 4096),
327 	},
328 	{
329 		.policer = MLXSW_SP_TRAP_POLICER(18, 1024, 128),
330 	},
331 	{
332 		.policer = MLXSW_SP_TRAP_POLICER(19, 1024, 512),
333 	},
334 };
335 
336 static const struct mlxsw_sp_trap_group_item mlxsw_sp_trap_group_items_arr[] = {
337 	{
338 		.group = DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 1),
339 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS,
340 		.priority = 0,
341 	},
342 	{
343 		.group = DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1),
344 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS,
345 		.priority = 0,
346 	},
347 	{
348 		.group = DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 1),
349 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_EXCEPTIONS,
350 		.priority = 2,
351 	},
352 	{
353 		.group = DEVLINK_TRAP_GROUP_GENERIC(TUNNEL_DROPS, 1),
354 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS,
355 		.priority = 0,
356 	},
357 	{
358 		.group = DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 1),
359 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS,
360 		.priority = 0,
361 	},
362 	{
363 		.group = DEVLINK_TRAP_GROUP_GENERIC(STP, 2),
364 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_STP,
365 		.priority = 5,
366 	},
367 	{
368 		.group = DEVLINK_TRAP_GROUP_GENERIC(LACP, 3),
369 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LACP,
370 		.priority = 5,
371 	},
372 	{
373 		.group = DEVLINK_TRAP_GROUP_GENERIC(LLDP, 4),
374 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP,
375 		.priority = 5,
376 	},
377 	{
378 		.group = DEVLINK_TRAP_GROUP_GENERIC(MC_SNOOPING, 5),
379 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_MC_SNOOPING,
380 		.priority = 3,
381 	},
382 	{
383 		.group = DEVLINK_TRAP_GROUP_GENERIC(DHCP, 6),
384 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_DHCP,
385 		.priority = 2,
386 	},
387 	{
388 		.group = DEVLINK_TRAP_GROUP_GENERIC(NEIGH_DISCOVERY, 7),
389 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_NEIGH_DISCOVERY,
390 		.priority = 2,
391 	},
392 	{
393 		.group = DEVLINK_TRAP_GROUP_GENERIC(BFD, 8),
394 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BFD,
395 		.priority = 5,
396 	},
397 	{
398 		.group = DEVLINK_TRAP_GROUP_GENERIC(OSPF, 9),
399 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_OSPF,
400 		.priority = 5,
401 	},
402 	{
403 		.group = DEVLINK_TRAP_GROUP_GENERIC(BGP, 10),
404 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BGP,
405 		.priority = 4,
406 	},
407 	{
408 		.group = DEVLINK_TRAP_GROUP_GENERIC(VRRP, 11),
409 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_VRRP,
410 		.priority = 5,
411 	},
412 	{
413 		.group = DEVLINK_TRAP_GROUP_GENERIC(PIM, 12),
414 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PIM,
415 		.priority = 5,
416 	},
417 	{
418 		.group = DEVLINK_TRAP_GROUP_GENERIC(UC_LB, 13),
419 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LBERROR,
420 		.priority = 0,
421 	},
422 	{
423 		.group = DEVLINK_TRAP_GROUP_GENERIC(LOCAL_DELIVERY, 14),
424 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME,
425 		.priority = 2,
426 	},
427 	{
428 		.group = DEVLINK_TRAP_GROUP_GENERIC(EXTERNAL_DELIVERY, 19),
429 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_EXTERNAL_ROUTE,
430 		.priority = 1,
431 	},
432 	{
433 		.group = DEVLINK_TRAP_GROUP_GENERIC(IPV6, 15),
434 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6,
435 		.priority = 2,
436 	},
437 	{
438 		.group = DEVLINK_TRAP_GROUP_GENERIC(PTP_EVENT, 16),
439 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0,
440 		.priority = 5,
441 	},
442 	{
443 		.group = DEVLINK_TRAP_GROUP_GENERIC(PTP_GENERAL, 17),
444 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1,
445 		.priority = 2,
446 	},
447 	{
448 		.group = DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0),
449 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PKT_SAMPLE,
450 		.priority = 0,
451 	},
452 	{
453 		.group = DEVLINK_TRAP_GROUP_GENERIC(ACL_TRAP, 18),
454 		.hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_FLOW_LOGGING,
455 		.priority = 4,
456 	},
457 };
458 
459 static const struct mlxsw_sp_trap_item mlxsw_sp_trap_items_arr[] = {
460 	{
461 		.trap = MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS),
462 		.listeners_arr = {
463 			MLXSW_SP_RXL_DISCARD(ING_PACKET_SMAC_MC, L2_DISCARDS),
464 		},
465 	},
466 	{
467 		.trap = MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS),
468 		.listeners_arr = {
469 			MLXSW_SP_RXL_DISCARD(ING_SWITCH_VTAG_ALLOW,
470 					     L2_DISCARDS),
471 		},
472 	},
473 	{
474 		.trap = MLXSW_SP_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS),
475 		.listeners_arr = {
476 			MLXSW_SP_RXL_DISCARD(ING_SWITCH_VLAN, L2_DISCARDS),
477 		},
478 	},
479 	{
480 		.trap = MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS),
481 		.listeners_arr = {
482 			MLXSW_SP_RXL_DISCARD(ING_SWITCH_STP, L2_DISCARDS),
483 		},
484 	},
485 	{
486 		.trap = MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS),
487 		.listeners_arr = {
488 			MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS),
489 			MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS),
490 		},
491 	},
492 	{
493 		.trap = MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS),
494 		.listeners_arr = {
495 			MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS),
496 		},
497 	},
498 	{
499 		.trap = MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS),
500 		.listeners_arr = {
501 			MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS),
502 		},
503 	},
504 	{
505 		.trap = MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS),
506 		.listeners_arr = {
507 			MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET,
508 					     L3_DISCARDS),
509 		},
510 	},
511 	{
512 		.trap = MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS),
513 		.listeners_arr = {
514 			MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC,
515 					     L3_DISCARDS),
516 		},
517 	},
518 	{
519 		.trap = MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS),
520 		.listeners_arr = {
521 			MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS),
522 		},
523 	},
524 	{
525 		.trap = MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS),
526 		.listeners_arr = {
527 			MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS),
528 		},
529 	},
530 	{
531 		.trap = MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS),
532 		.listeners_arr = {
533 			MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS),
534 		},
535 	},
536 	{
537 		.trap = MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS),
538 		.listeners_arr = {
539 			MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR,
540 					     L3_DISCARDS),
541 		},
542 	},
543 	{
544 		.trap = MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS),
545 		.listeners_arr = {
546 			MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC,
547 					     L3_DISCARDS),
548 		},
549 	},
550 	{
551 		.trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE,
552 					   L3_DROPS),
553 		.listeners_arr = {
554 			MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE,
555 					     L3_DISCARDS),
556 		},
557 	},
558 	{
559 		.trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE,
560 					   L3_DROPS),
561 		.listeners_arr = {
562 			MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE,
563 					     L3_DISCARDS),
564 		},
565 	},
566 	{
567 		.trap = MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_EXCEPTIONS),
568 		.listeners_arr = {
569 			MLXSW_SP_RXL_EXCEPTION(MTUERROR, L3_EXCEPTIONS,
570 					       TRAP_TO_CPU),
571 		},
572 	},
573 	{
574 		.trap = MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS),
575 		.listeners_arr = {
576 			MLXSW_SP_RXL_EXCEPTION(TTLERROR, L3_EXCEPTIONS,
577 					       TRAP_TO_CPU),
578 		},
579 	},
580 	{
581 		.trap = MLXSW_SP_TRAP_EXCEPTION(RPF, L3_EXCEPTIONS),
582 		.listeners_arr = {
583 			MLXSW_SP_RXL_EXCEPTION(RPF, L3_EXCEPTIONS, TRAP_TO_CPU),
584 		},
585 	},
586 	{
587 		.trap = MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_EXCEPTIONS),
588 		.listeners_arr = {
589 			MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, L3_EXCEPTIONS,
590 					       TRAP_TO_CPU),
591 		},
592 	},
593 	{
594 		.trap = MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH,
595 						L3_EXCEPTIONS),
596 		.listeners_arr = {
597 			MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, L3_EXCEPTIONS,
598 					       TRAP_TO_CPU),
599 			MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, L3_EXCEPTIONS,
600 					       TRAP_TO_CPU),
601 			MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER3, L3_EXCEPTIONS,
602 					       TRAP_EXCEPTION_TO_CPU),
603 		},
604 	},
605 	{
606 		.trap = MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS,
607 						L3_EXCEPTIONS),
608 		.listeners_arr = {
609 			MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4,
610 					       L3_EXCEPTIONS,
611 					       TRAP_EXCEPTION_TO_CPU),
612 		},
613 	},
614 	{
615 		.trap = MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS,
616 						L3_EXCEPTIONS),
617 		.listeners_arr = {
618 			MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6,
619 					       L3_EXCEPTIONS,
620 					       TRAP_EXCEPTION_TO_CPU),
621 		},
622 	},
623 	{
624 		.trap = MLXSW_SP_TRAP_DRIVER_DROP(IRIF_DISABLED, L3_DROPS),
625 		.listeners_arr = {
626 			MLXSW_SP_RXL_DISCARD(ROUTER_IRIF_EN, L3_DISCARDS),
627 		},
628 	},
629 	{
630 		.trap = MLXSW_SP_TRAP_DRIVER_DROP(ERIF_DISABLED, L3_DROPS),
631 		.listeners_arr = {
632 			MLXSW_SP_RXL_DISCARD(ROUTER_ERIF_EN, L3_DISCARDS),
633 		},
634 	},
635 	{
636 		.trap = MLXSW_SP_TRAP_DROP(NON_ROUTABLE, L3_DROPS),
637 		.listeners_arr = {
638 			MLXSW_SP_RXL_DISCARD(NON_ROUTABLE, L3_DISCARDS),
639 		},
640 	},
641 	{
642 		.trap = MLXSW_SP_TRAP_EXCEPTION(DECAP_ERROR, TUNNEL_DROPS),
643 		.listeners_arr = {
644 			MLXSW_SP_RXL_EXCEPTION(DECAP_ECN0, TUNNEL_DISCARDS,
645 					       TRAP_EXCEPTION_TO_CPU),
646 			MLXSW_SP_RXL_EXCEPTION(IPIP_DECAP_ERROR,
647 					       TUNNEL_DISCARDS,
648 					       TRAP_EXCEPTION_TO_CPU),
649 			MLXSW_SP_RXL_EXCEPTION(DISCARD_DEC_PKT, TUNNEL_DISCARDS,
650 					       TRAP_EXCEPTION_TO_CPU),
651 		},
652 	},
653 	{
654 		.trap = MLXSW_SP_TRAP_DROP(OVERLAY_SMAC_MC, TUNNEL_DROPS),
655 		.listeners_arr = {
656 			MLXSW_SP_RXL_DISCARD(OVERLAY_SMAC_MC, TUNNEL_DISCARDS),
657 		},
658 	},
659 	{
660 		.trap = MLXSW_SP_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP,
661 					       ACL_DROPS,
662 					       DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),
663 		.listeners_arr = {
664 			MLXSW_SP_RXL_ACL_DISCARD(INGRESS_ACL, ACL_DISCARDS,
665 						 DUMMY),
666 		},
667 	},
668 	{
669 		.trap = MLXSW_SP_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP,
670 					       ACL_DROPS,
671 					       DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),
672 		.listeners_arr = {
673 			MLXSW_SP_RXL_ACL_DISCARD(EGRESS_ACL, ACL_DISCARDS,
674 						 DUMMY),
675 		},
676 	},
677 	{
678 		.trap = MLXSW_SP_TRAP_CONTROL(STP, STP, TRAP),
679 		.listeners_arr = {
680 			MLXSW_SP_RXL_NO_MARK(STP, STP, TRAP_TO_CPU, true),
681 		},
682 	},
683 	{
684 		.trap = MLXSW_SP_TRAP_CONTROL(LACP, LACP, TRAP),
685 		.listeners_arr = {
686 			MLXSW_SP_RXL_NO_MARK(LACP, LACP, TRAP_TO_CPU, true),
687 		},
688 	},
689 	{
690 		.trap = MLXSW_SP_TRAP_CONTROL(LLDP, LLDP, TRAP),
691 		.listeners_arr = {
692 			MLXSW_RXL(mlxsw_sp_rx_ptp_listener, LLDP, TRAP_TO_CPU,
693 				  false, SP_LLDP, DISCARD),
694 		},
695 	},
696 	{
697 		.trap = MLXSW_SP_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR),
698 		.listeners_arr = {
699 			MLXSW_SP_RXL_MARK(IGMP_QUERY, MC_SNOOPING,
700 					  MIRROR_TO_CPU, false),
701 		},
702 	},
703 	{
704 		.trap = MLXSW_SP_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING,
705 					      TRAP),
706 		.listeners_arr = {
707 			MLXSW_SP_RXL_NO_MARK(IGMP_V1_REPORT, MC_SNOOPING,
708 					     TRAP_TO_CPU, false),
709 		},
710 	},
711 	{
712 		.trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_REPORT, MC_SNOOPING,
713 					      TRAP),
714 		.listeners_arr = {
715 			MLXSW_SP_RXL_NO_MARK(IGMP_V2_REPORT, MC_SNOOPING,
716 					     TRAP_TO_CPU, false),
717 		},
718 	},
719 	{
720 		.trap = MLXSW_SP_TRAP_CONTROL(IGMP_V3_REPORT, MC_SNOOPING,
721 					      TRAP),
722 		.listeners_arr = {
723 			MLXSW_SP_RXL_NO_MARK(IGMP_V3_REPORT, MC_SNOOPING,
724 					     TRAP_TO_CPU, false),
725 		},
726 	},
727 	{
728 		.trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_LEAVE, MC_SNOOPING,
729 					      TRAP),
730 		.listeners_arr = {
731 			MLXSW_SP_RXL_NO_MARK(IGMP_V2_LEAVE, MC_SNOOPING,
732 					     TRAP_TO_CPU, false),
733 		},
734 	},
735 	{
736 		.trap = MLXSW_SP_TRAP_CONTROL(MLD_QUERY, MC_SNOOPING, MIRROR),
737 		.listeners_arr = {
738 			MLXSW_SP_RXL_MARK(IPV6_MLDV12_LISTENER_QUERY,
739 					  MC_SNOOPING, MIRROR_TO_CPU, false),
740 		},
741 	},
742 	{
743 		.trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_REPORT, MC_SNOOPING,
744 					      TRAP),
745 		.listeners_arr = {
746 			MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_REPORT,
747 					     MC_SNOOPING, TRAP_TO_CPU, false),
748 		},
749 	},
750 	{
751 		.trap = MLXSW_SP_TRAP_CONTROL(MLD_V2_REPORT, MC_SNOOPING,
752 					      TRAP),
753 		.listeners_arr = {
754 			MLXSW_SP_RXL_NO_MARK(IPV6_MLDV2_LISTENER_REPORT,
755 					     MC_SNOOPING, TRAP_TO_CPU, false),
756 		},
757 	},
758 	{
759 		.trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_DONE, MC_SNOOPING,
760 					      TRAP),
761 		.listeners_arr = {
762 			MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_DONE,
763 					     MC_SNOOPING, TRAP_TO_CPU, false),
764 		},
765 	},
766 	{
767 		.trap = MLXSW_SP_TRAP_CONTROL(IPV4_DHCP, DHCP, TRAP),
768 		.listeners_arr = {
769 			MLXSW_SP_RXL_MARK(IPV4_DHCP, DHCP, TRAP_TO_CPU, false),
770 		},
771 	},
772 	{
773 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_DHCP, DHCP, TRAP),
774 		.listeners_arr = {
775 			MLXSW_SP_RXL_MARK(IPV6_DHCP, DHCP, TRAP_TO_CPU, false),
776 		},
777 	},
778 	{
779 		.trap = MLXSW_SP_TRAP_CONTROL(ARP_REQUEST, NEIGH_DISCOVERY,
780 					      MIRROR),
781 		.listeners_arr = {
782 			MLXSW_SP_RXL_MARK(ARPBC, NEIGH_DISCOVERY, MIRROR_TO_CPU,
783 					  false),
784 		},
785 	},
786 	{
787 		.trap = MLXSW_SP_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY,
788 					      MIRROR),
789 		.listeners_arr = {
790 			MLXSW_SP_RXL_MARK(ARPUC, NEIGH_DISCOVERY, MIRROR_TO_CPU,
791 					  false),
792 		},
793 	},
794 	{
795 		.trap = MLXSW_SP_TRAP_CONTROL(ARP_OVERLAY, NEIGH_DISCOVERY,
796 					      TRAP),
797 		.listeners_arr = {
798 			MLXSW_SP_RXL_NO_MARK(NVE_DECAP_ARP, NEIGH_DISCOVERY,
799 					     TRAP_TO_CPU, false),
800 		},
801 	},
802 	{
803 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_SOLICIT,
804 					      NEIGH_DISCOVERY, TRAP),
805 		.listeners_arr = {
806 			MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_SOLICITATION,
807 					  NEIGH_DISCOVERY, TRAP_TO_CPU, false),
808 		},
809 	},
810 	{
811 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_ADVERT,
812 					      NEIGH_DISCOVERY, TRAP),
813 		.listeners_arr = {
814 			MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_ADVERTISEMENT,
815 					  NEIGH_DISCOVERY, TRAP_TO_CPU, false),
816 		},
817 	},
818 	{
819 		.trap = MLXSW_SP_TRAP_CONTROL(IPV4_BFD, BFD, TRAP),
820 		.listeners_arr = {
821 			MLXSW_SP_RXL_MARK(IPV4_BFD, BFD, TRAP_TO_CPU, false),
822 		},
823 	},
824 	{
825 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_BFD, BFD, TRAP),
826 		.listeners_arr = {
827 			MLXSW_SP_RXL_MARK(IPV6_BFD, BFD, TRAP_TO_CPU, false),
828 		},
829 	},
830 	{
831 		.trap = MLXSW_SP_TRAP_CONTROL(IPV4_OSPF, OSPF, TRAP),
832 		.listeners_arr = {
833 			MLXSW_SP_RXL_MARK(IPV4_OSPF, OSPF, TRAP_TO_CPU, false),
834 		},
835 	},
836 	{
837 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_OSPF, OSPF, TRAP),
838 		.listeners_arr = {
839 			MLXSW_SP_RXL_MARK(IPV6_OSPF, OSPF, TRAP_TO_CPU, false),
840 		},
841 	},
842 	{
843 		.trap = MLXSW_SP_TRAP_CONTROL(IPV4_BGP, BGP, TRAP),
844 		.listeners_arr = {
845 			MLXSW_SP_RXL_MARK(IPV4_BGP, BGP, TRAP_TO_CPU, false),
846 		},
847 	},
848 	{
849 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_BGP, BGP, TRAP),
850 		.listeners_arr = {
851 			MLXSW_SP_RXL_MARK(IPV6_BGP, BGP, TRAP_TO_CPU, false),
852 		},
853 	},
854 	{
855 		.trap = MLXSW_SP_TRAP_CONTROL(IPV4_VRRP, VRRP, TRAP),
856 		.listeners_arr = {
857 			MLXSW_SP_RXL_MARK(IPV4_VRRP, VRRP, TRAP_TO_CPU, false),
858 		},
859 	},
860 	{
861 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_VRRP, VRRP, TRAP),
862 		.listeners_arr = {
863 			MLXSW_SP_RXL_MARK(IPV6_VRRP, VRRP, TRAP_TO_CPU, false),
864 		},
865 	},
866 	{
867 		.trap = MLXSW_SP_TRAP_CONTROL(IPV4_PIM, PIM, TRAP),
868 		.listeners_arr = {
869 			MLXSW_SP_RXL_MARK(IPV4_PIM, PIM, TRAP_TO_CPU, false),
870 		},
871 	},
872 	{
873 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_PIM, PIM, TRAP),
874 		.listeners_arr = {
875 			MLXSW_SP_RXL_MARK(IPV6_PIM, PIM, TRAP_TO_CPU, false),
876 		},
877 	},
878 	{
879 		.trap = MLXSW_SP_TRAP_CONTROL(UC_LB, UC_LB, MIRROR),
880 		.listeners_arr = {
881 			MLXSW_SP_RXL_L3_MARK(LBERROR, LBERROR, MIRROR_TO_CPU,
882 					     false),
883 		},
884 	},
885 	{
886 		.trap = MLXSW_SP_TRAP_CONTROL(LOCAL_ROUTE, LOCAL_DELIVERY,
887 					      TRAP),
888 		.listeners_arr = {
889 			MLXSW_SP_RXL_MARK(IP2ME, IP2ME, TRAP_TO_CPU, false),
890 		},
891 	},
892 	{
893 		.trap = MLXSW_SP_TRAP_CONTROL(EXTERNAL_ROUTE, EXTERNAL_DELIVERY,
894 					      TRAP),
895 		.listeners_arr = {
896 			MLXSW_SP_RXL_MARK(RTR_INGRESS0, EXTERNAL_ROUTE,
897 					  TRAP_TO_CPU, false),
898 		},
899 	},
900 	{
901 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_UC_DIP_LINK_LOCAL_SCOPE,
902 					      LOCAL_DELIVERY, TRAP),
903 		.listeners_arr = {
904 			MLXSW_SP_RXL_MARK(IPV6_LINK_LOCAL_DEST, IP2ME,
905 					  TRAP_TO_CPU, false),
906 		},
907 	},
908 	{
909 		.trap = MLXSW_SP_TRAP_CONTROL(IPV4_ROUTER_ALERT, LOCAL_DELIVERY,
910 					      TRAP),
911 		.listeners_arr = {
912 			MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV4, IP2ME, TRAP_TO_CPU,
913 					  false),
914 		},
915 	},
916 	{
917 		/* IPV6_ROUTER_ALERT is defined in uAPI as 22, but it is not
918 		 * used in this file, so undefine it.
919 		 */
920 		#undef IPV6_ROUTER_ALERT
921 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_ALERT, LOCAL_DELIVERY,
922 					      TRAP),
923 		.listeners_arr = {
924 			MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, IP2ME, TRAP_TO_CPU,
925 					  false),
926 		},
927 	},
928 	{
929 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_DIP_ALL_NODES, IPV6, TRAP),
930 		.listeners_arr = {
931 			MLXSW_SP_RXL_MARK(IPV6_ALL_NODES_LINK, IPV6,
932 					  TRAP_TO_CPU, false),
933 		},
934 	},
935 	{
936 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_DIP_ALL_ROUTERS, IPV6, TRAP),
937 		.listeners_arr = {
938 			MLXSW_SP_RXL_MARK(IPV6_ALL_ROUTERS_LINK, IPV6,
939 					  TRAP_TO_CPU, false),
940 		},
941 	},
942 	{
943 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_SOLICIT, IPV6, TRAP),
944 		.listeners_arr = {
945 			MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_SOLICITATION, IPV6,
946 					  TRAP_TO_CPU, false),
947 		},
948 	},
949 	{
950 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_ADVERT, IPV6, TRAP),
951 		.listeners_arr = {
952 			MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_ADVERTISEMENT, IPV6,
953 					  TRAP_TO_CPU, false),
954 		},
955 	},
956 	{
957 		.trap = MLXSW_SP_TRAP_CONTROL(IPV6_REDIRECT, IPV6, TRAP),
958 		.listeners_arr = {
959 			MLXSW_SP_RXL_MARK(L3_IPV6_REDIRECTION, IPV6,
960 					  TRAP_TO_CPU, false),
961 		},
962 	},
963 	{
964 		.trap = MLXSW_SP_TRAP_CONTROL(PTP_EVENT, PTP_EVENT, TRAP),
965 		.listeners_arr = {
966 			MLXSW_RXL(mlxsw_sp_rx_ptp_listener, PTP0, TRAP_TO_CPU,
967 				  false, SP_PTP0, DISCARD),
968 		},
969 	},
970 	{
971 		.trap = MLXSW_SP_TRAP_CONTROL(PTP_GENERAL, PTP_GENERAL, TRAP),
972 		.listeners_arr = {
973 			MLXSW_SP_RXL_NO_MARK(PTP1, PTP1, TRAP_TO_CPU, false),
974 		},
975 	},
976 	{
977 		.trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_SAMPLE, ACL_SAMPLE,
978 					      MIRROR),
979 		.listeners_arr = {
980 			MLXSW_RXL(mlxsw_sp_rx_sample_listener, PKT_SAMPLE,
981 				  MIRROR_TO_CPU, false, SP_PKT_SAMPLE, DISCARD),
982 		},
983 	},
984 	{
985 		.trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_TRAP, ACL_TRAP, TRAP),
986 		.listeners_arr = {
987 			MLXSW_SP_RXL_NO_MARK(ACL0, FLOW_LOGGING, TRAP_TO_CPU,
988 					     false),
989 		},
990 	},
991 };
992 
993 static struct mlxsw_sp_trap_policer_item *
994 mlxsw_sp_trap_policer_item_lookup(struct mlxsw_sp *mlxsw_sp, u32 id)
995 {
996 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
997 	int i;
998 
999 	for (i = 0; i < trap->policers_count; i++) {
1000 		if (trap->policer_items_arr[i].policer.id == id)
1001 			return &trap->policer_items_arr[i];
1002 	}
1003 
1004 	return NULL;
1005 }
1006 
1007 static struct mlxsw_sp_trap_group_item *
1008 mlxsw_sp_trap_group_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id)
1009 {
1010 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1011 	int i;
1012 
1013 	for (i = 0; i < trap->groups_count; i++) {
1014 		if (trap->group_items_arr[i].group.id == id)
1015 			return &trap->group_items_arr[i];
1016 	}
1017 
1018 	return NULL;
1019 }
1020 
1021 static struct mlxsw_sp_trap_item *
1022 mlxsw_sp_trap_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id)
1023 {
1024 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1025 	int i;
1026 
1027 	for (i = 0; i < trap->traps_count; i++) {
1028 		if (trap->trap_items_arr[i].trap.id == id)
1029 			return &trap->trap_items_arr[i];
1030 	}
1031 
1032 	return NULL;
1033 }
1034 
1035 static int mlxsw_sp_trap_cpu_policers_set(struct mlxsw_sp *mlxsw_sp)
1036 {
1037 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1038 	char qpcr_pl[MLXSW_REG_QPCR_LEN];
1039 	u16 hw_id;
1040 
1041 	/* The purpose of "thin" policer is to drop as many packets
1042 	 * as possible. The dummy group is using it.
1043 	 */
1044 	hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers);
1045 	if (WARN_ON(hw_id == trap->max_policers))
1046 		return -ENOBUFS;
1047 
1048 	__set_bit(hw_id, trap->policers_usage);
1049 	trap->thin_policer_hw_id = hw_id;
1050 	mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M,
1051 			    false, 1, 4);
1052 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
1053 }
1054 
1055 static int mlxsw_sp_trap_dummy_group_init(struct mlxsw_sp *mlxsw_sp)
1056 {
1057 	char htgt_pl[MLXSW_REG_HTGT_LEN];
1058 
1059 	mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SP_DUMMY,
1060 			    mlxsw_sp->trap->thin_policer_hw_id, 0, 1);
1061 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl);
1062 }
1063 
1064 static int mlxsw_sp_trap_policer_items_arr_init(struct mlxsw_sp *mlxsw_sp)
1065 {
1066 	size_t elem_size = sizeof(struct mlxsw_sp_trap_policer_item);
1067 	u64 arr_size = ARRAY_SIZE(mlxsw_sp_trap_policer_items_arr);
1068 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1069 	u64 free_policers = 0;
1070 	u32 last_id;
1071 	int i;
1072 
1073 	for_each_clear_bit(i, trap->policers_usage, trap->max_policers)
1074 		free_policers++;
1075 
1076 	if (arr_size > free_policers) {
1077 		dev_err(mlxsw_sp->bus_info->dev, "Exceeded number of supported packet trap policers\n");
1078 		return -ENOBUFS;
1079 	}
1080 
1081 	trap->policer_items_arr = kcalloc(free_policers, elem_size, GFP_KERNEL);
1082 	if (!trap->policer_items_arr)
1083 		return -ENOMEM;
1084 
1085 	trap->policers_count = free_policers;
1086 
1087 	/* Initialize policer items array with pre-defined policers. */
1088 	memcpy(trap->policer_items_arr, mlxsw_sp_trap_policer_items_arr,
1089 	       elem_size * arr_size);
1090 
1091 	/* Initialize policer items array with the rest of the available
1092 	 * policers.
1093 	 */
1094 	last_id = mlxsw_sp_trap_policer_items_arr[arr_size - 1].policer.id;
1095 	for (i = arr_size; i < trap->policers_count; i++) {
1096 		const struct mlxsw_sp_trap_policer_item *policer_item;
1097 
1098 		/* Use parameters set for first policer and override
1099 		 * relevant ones.
1100 		 */
1101 		policer_item = &mlxsw_sp_trap_policer_items_arr[0];
1102 		trap->policer_items_arr[i] = *policer_item;
1103 		trap->policer_items_arr[i].policer.id = ++last_id;
1104 		trap->policer_items_arr[i].policer.init_rate = 1;
1105 		trap->policer_items_arr[i].policer.init_burst = 16;
1106 	}
1107 
1108 	return 0;
1109 }
1110 
1111 static void mlxsw_sp_trap_policer_items_arr_fini(struct mlxsw_sp *mlxsw_sp)
1112 {
1113 	kfree(mlxsw_sp->trap->policer_items_arr);
1114 }
1115 
1116 static int mlxsw_sp_trap_policers_init(struct mlxsw_sp *mlxsw_sp)
1117 {
1118 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1119 	const struct mlxsw_sp_trap_policer_item *policer_item;
1120 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1121 	int err, i;
1122 
1123 	err = mlxsw_sp_trap_policer_items_arr_init(mlxsw_sp);
1124 	if (err)
1125 		return err;
1126 
1127 	for (i = 0; i < trap->policers_count; i++) {
1128 		policer_item = &trap->policer_items_arr[i];
1129 		err = devlink_trap_policers_register(devlink,
1130 						     &policer_item->policer, 1);
1131 		if (err)
1132 			goto err_trap_policer_register;
1133 	}
1134 
1135 	return 0;
1136 
1137 err_trap_policer_register:
1138 	for (i--; i >= 0; i--) {
1139 		policer_item = &trap->policer_items_arr[i];
1140 		devlink_trap_policers_unregister(devlink,
1141 						 &policer_item->policer, 1);
1142 	}
1143 	mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp);
1144 	return err;
1145 }
1146 
1147 static void mlxsw_sp_trap_policers_fini(struct mlxsw_sp *mlxsw_sp)
1148 {
1149 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1150 	const struct mlxsw_sp_trap_policer_item *policer_item;
1151 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1152 	int i;
1153 
1154 	for (i = trap->policers_count - 1; i >= 0; i--) {
1155 		policer_item = &trap->policer_items_arr[i];
1156 		devlink_trap_policers_unregister(devlink,
1157 						 &policer_item->policer, 1);
1158 	}
1159 	mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp);
1160 }
1161 
1162 static int mlxsw_sp_trap_groups_init(struct mlxsw_sp *mlxsw_sp)
1163 {
1164 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1165 	const struct mlxsw_sp_trap_group_item *group_item;
1166 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1167 	int err, i;
1168 
1169 	trap->group_items_arr = kmemdup(mlxsw_sp_trap_group_items_arr,
1170 					sizeof(mlxsw_sp_trap_group_items_arr),
1171 					GFP_KERNEL);
1172 	if (!trap->group_items_arr)
1173 		return -ENOMEM;
1174 
1175 	trap->groups_count = ARRAY_SIZE(mlxsw_sp_trap_group_items_arr);
1176 
1177 	for (i = 0; i < trap->groups_count; i++) {
1178 		group_item = &trap->group_items_arr[i];
1179 		err = devlink_trap_groups_register(devlink, &group_item->group,
1180 						   1);
1181 		if (err)
1182 			goto err_trap_group_register;
1183 	}
1184 
1185 	return 0;
1186 
1187 err_trap_group_register:
1188 	for (i--; i >= 0; i--) {
1189 		group_item = &trap->group_items_arr[i];
1190 		devlink_trap_groups_unregister(devlink, &group_item->group, 1);
1191 	}
1192 	kfree(trap->group_items_arr);
1193 	return err;
1194 }
1195 
1196 static void mlxsw_sp_trap_groups_fini(struct mlxsw_sp *mlxsw_sp)
1197 {
1198 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1199 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1200 	int i;
1201 
1202 	for (i = trap->groups_count - 1; i >= 0; i--) {
1203 		const struct mlxsw_sp_trap_group_item *group_item;
1204 
1205 		group_item = &trap->group_items_arr[i];
1206 		devlink_trap_groups_unregister(devlink, &group_item->group, 1);
1207 	}
1208 	kfree(trap->group_items_arr);
1209 }
1210 
1211 static bool
1212 mlxsw_sp_trap_listener_is_valid(const struct mlxsw_listener *listener)
1213 {
1214 	return listener->trap_id != 0;
1215 }
1216 
1217 static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)
1218 {
1219 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1220 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1221 	const struct mlxsw_sp_trap_item *trap_item;
1222 	int err, i;
1223 
1224 	trap->trap_items_arr = kmemdup(mlxsw_sp_trap_items_arr,
1225 				       sizeof(mlxsw_sp_trap_items_arr),
1226 				       GFP_KERNEL);
1227 	if (!trap->trap_items_arr)
1228 		return -ENOMEM;
1229 
1230 	trap->traps_count = ARRAY_SIZE(mlxsw_sp_trap_items_arr);
1231 
1232 	for (i = 0; i < trap->traps_count; i++) {
1233 		trap_item = &trap->trap_items_arr[i];
1234 		err = devlink_traps_register(devlink, &trap_item->trap, 1,
1235 					     mlxsw_sp);
1236 		if (err)
1237 			goto err_trap_register;
1238 	}
1239 
1240 	return 0;
1241 
1242 err_trap_register:
1243 	for (i--; i >= 0; i--) {
1244 		trap_item = &trap->trap_items_arr[i];
1245 		devlink_traps_unregister(devlink, &trap_item->trap, 1);
1246 	}
1247 	kfree(trap->trap_items_arr);
1248 	return err;
1249 }
1250 
1251 static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp)
1252 {
1253 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1254 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1255 	int i;
1256 
1257 	for (i = trap->traps_count - 1; i >= 0; i--) {
1258 		const struct mlxsw_sp_trap_item *trap_item;
1259 
1260 		trap_item = &trap->trap_items_arr[i];
1261 		devlink_traps_unregister(devlink, &trap_item->trap, 1);
1262 	}
1263 	kfree(trap->trap_items_arr);
1264 }
1265 
1266 int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp)
1267 {
1268 	int err;
1269 
1270 	err = mlxsw_sp_trap_cpu_policers_set(mlxsw_sp);
1271 	if (err)
1272 		return err;
1273 
1274 	err = mlxsw_sp_trap_dummy_group_init(mlxsw_sp);
1275 	if (err)
1276 		return err;
1277 
1278 	err = mlxsw_sp_trap_policers_init(mlxsw_sp);
1279 	if (err)
1280 		return err;
1281 
1282 	err = mlxsw_sp_trap_groups_init(mlxsw_sp);
1283 	if (err)
1284 		goto err_trap_groups_init;
1285 
1286 	err = mlxsw_sp_traps_init(mlxsw_sp);
1287 	if (err)
1288 		goto err_traps_init;
1289 
1290 	return 0;
1291 
1292 err_traps_init:
1293 	mlxsw_sp_trap_groups_fini(mlxsw_sp);
1294 err_trap_groups_init:
1295 	mlxsw_sp_trap_policers_fini(mlxsw_sp);
1296 	return err;
1297 }
1298 
1299 void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp)
1300 {
1301 	mlxsw_sp_traps_fini(mlxsw_sp);
1302 	mlxsw_sp_trap_groups_fini(mlxsw_sp);
1303 	mlxsw_sp_trap_policers_fini(mlxsw_sp);
1304 }
1305 
1306 int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core,
1307 		       const struct devlink_trap *trap, void *trap_ctx)
1308 {
1309 	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1310 	const struct mlxsw_sp_trap_item *trap_item;
1311 	int i;
1312 
1313 	trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);
1314 	if (WARN_ON(!trap_item))
1315 		return -EINVAL;
1316 
1317 	for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) {
1318 		const struct mlxsw_listener *listener;
1319 		int err;
1320 
1321 		listener = &trap_item->listeners_arr[i];
1322 		if (!mlxsw_sp_trap_listener_is_valid(listener))
1323 			continue;
1324 		err = mlxsw_core_trap_register(mlxsw_core, listener, trap_ctx);
1325 		if (err)
1326 			return err;
1327 	}
1328 
1329 	return 0;
1330 }
1331 
1332 void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core,
1333 			const struct devlink_trap *trap, void *trap_ctx)
1334 {
1335 	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1336 	const struct mlxsw_sp_trap_item *trap_item;
1337 	int i;
1338 
1339 	trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);
1340 	if (WARN_ON(!trap_item))
1341 		return;
1342 
1343 	for (i = MLXSW_SP_TRAP_LISTENERS_MAX - 1; i >= 0; i--) {
1344 		const struct mlxsw_listener *listener;
1345 
1346 		listener = &trap_item->listeners_arr[i];
1347 		if (!mlxsw_sp_trap_listener_is_valid(listener))
1348 			continue;
1349 		mlxsw_core_trap_unregister(mlxsw_core, listener, trap_ctx);
1350 	}
1351 }
1352 
1353 int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core,
1354 			     const struct devlink_trap *trap,
1355 			     enum devlink_trap_action action)
1356 {
1357 	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1358 	const struct mlxsw_sp_trap_item *trap_item;
1359 	int i;
1360 
1361 	trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);
1362 	if (WARN_ON(!trap_item))
1363 		return -EINVAL;
1364 
1365 	for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) {
1366 		const struct mlxsw_listener *listener;
1367 		bool enabled;
1368 		int err;
1369 
1370 		listener = &trap_item->listeners_arr[i];
1371 		if (!mlxsw_sp_trap_listener_is_valid(listener))
1372 			continue;
1373 
1374 		switch (action) {
1375 		case DEVLINK_TRAP_ACTION_DROP:
1376 			enabled = false;
1377 			break;
1378 		case DEVLINK_TRAP_ACTION_TRAP:
1379 			enabled = true;
1380 			break;
1381 		default:
1382 			return -EINVAL;
1383 		}
1384 		err = mlxsw_core_trap_state_set(mlxsw_core, listener, enabled);
1385 		if (err)
1386 			return err;
1387 	}
1388 
1389 	return 0;
1390 }
1391 
1392 static int
1393 __mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core,
1394 			   const struct devlink_trap_group *group,
1395 			   u32 policer_id)
1396 {
1397 	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1398 	u16 hw_policer_id = MLXSW_REG_HTGT_INVALID_POLICER;
1399 	const struct mlxsw_sp_trap_group_item *group_item;
1400 	char htgt_pl[MLXSW_REG_HTGT_LEN];
1401 
1402 	group_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, group->id);
1403 	if (WARN_ON(!group_item))
1404 		return -EINVAL;
1405 
1406 	if (policer_id) {
1407 		struct mlxsw_sp_trap_policer_item *policer_item;
1408 
1409 		policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp,
1410 								 policer_id);
1411 		if (WARN_ON(!policer_item))
1412 			return -EINVAL;
1413 		hw_policer_id = policer_item->hw_id;
1414 	}
1415 
1416 	mlxsw_reg_htgt_pack(htgt_pl, group_item->hw_group_id, hw_policer_id,
1417 			    group_item->priority, group_item->priority);
1418 	return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
1419 }
1420 
1421 int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core,
1422 			     const struct devlink_trap_group *group)
1423 {
1424 	return __mlxsw_sp_trap_group_init(mlxsw_core, group,
1425 					  group->init_policer_id);
1426 }
1427 
1428 int mlxsw_sp_trap_group_set(struct mlxsw_core *mlxsw_core,
1429 			    const struct devlink_trap_group *group,
1430 			    const struct devlink_trap_policer *policer)
1431 {
1432 	u32 policer_id = policer ? policer->id : 0;
1433 
1434 	return __mlxsw_sp_trap_group_init(mlxsw_core, group, policer_id);
1435 }
1436 
1437 static int
1438 mlxsw_sp_trap_policer_item_init(struct mlxsw_sp *mlxsw_sp,
1439 				struct mlxsw_sp_trap_policer_item *policer_item)
1440 {
1441 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1442 	u16 hw_id;
1443 
1444 	/* We should be able to allocate a policer because the number of
1445 	 * policers we registered with devlink is in according with the number
1446 	 * of available policers.
1447 	 */
1448 	hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers);
1449 	if (WARN_ON(hw_id == trap->max_policers))
1450 		return -ENOBUFS;
1451 
1452 	__set_bit(hw_id, trap->policers_usage);
1453 	policer_item->hw_id = hw_id;
1454 
1455 	return 0;
1456 }
1457 
1458 static void
1459 mlxsw_sp_trap_policer_item_fini(struct mlxsw_sp *mlxsw_sp,
1460 				struct mlxsw_sp_trap_policer_item *policer_item)
1461 {
1462 	__clear_bit(policer_item->hw_id, mlxsw_sp->trap->policers_usage);
1463 }
1464 
1465 static int mlxsw_sp_trap_policer_bs(u64 burst, u8 *p_burst_size,
1466 				    struct netlink_ext_ack *extack)
1467 {
1468 	int bs = fls64(burst) - 1;
1469 
1470 	if (burst != (BIT_ULL(bs))) {
1471 		NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two");
1472 		return -EINVAL;
1473 	}
1474 
1475 	*p_burst_size = bs;
1476 
1477 	return 0;
1478 }
1479 
1480 static int __mlxsw_sp_trap_policer_set(struct mlxsw_sp *mlxsw_sp, u16 hw_id,
1481 				       u64 rate, u64 burst, bool clear_counter,
1482 				       struct netlink_ext_ack *extack)
1483 {
1484 	char qpcr_pl[MLXSW_REG_QPCR_LEN];
1485 	u8 burst_size;
1486 	int err;
1487 
1488 	err = mlxsw_sp_trap_policer_bs(burst, &burst_size, extack);
1489 	if (err)
1490 		return err;
1491 
1492 	mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M, false,
1493 			    rate, burst_size);
1494 	mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, clear_counter);
1495 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
1496 }
1497 
1498 int mlxsw_sp_trap_policer_init(struct mlxsw_core *mlxsw_core,
1499 			       const struct devlink_trap_policer *policer)
1500 {
1501 	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1502 	struct mlxsw_sp_trap_policer_item *policer_item;
1503 	int err;
1504 
1505 	policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1506 	if (WARN_ON(!policer_item))
1507 		return -EINVAL;
1508 
1509 	err = mlxsw_sp_trap_policer_item_init(mlxsw_sp, policer_item);
1510 	if (err)
1511 		return err;
1512 
1513 	err = __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id,
1514 					  policer->init_rate,
1515 					  policer->init_burst, true, NULL);
1516 	if (err)
1517 		goto err_trap_policer_set;
1518 
1519 	return 0;
1520 
1521 err_trap_policer_set:
1522 	mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item);
1523 	return err;
1524 }
1525 
1526 void mlxsw_sp_trap_policer_fini(struct mlxsw_core *mlxsw_core,
1527 				const struct devlink_trap_policer *policer)
1528 {
1529 	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1530 	struct mlxsw_sp_trap_policer_item *policer_item;
1531 
1532 	policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1533 	if (WARN_ON(!policer_item))
1534 		return;
1535 
1536 	mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item);
1537 }
1538 
1539 int mlxsw_sp_trap_policer_set(struct mlxsw_core *mlxsw_core,
1540 			      const struct devlink_trap_policer *policer,
1541 			      u64 rate, u64 burst,
1542 			      struct netlink_ext_ack *extack)
1543 {
1544 	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1545 	struct mlxsw_sp_trap_policer_item *policer_item;
1546 
1547 	policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1548 	if (WARN_ON(!policer_item))
1549 		return -EINVAL;
1550 
1551 	return __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id,
1552 					   rate, burst, false, extack);
1553 }
1554 
1555 int
1556 mlxsw_sp_trap_policer_counter_get(struct mlxsw_core *mlxsw_core,
1557 				  const struct devlink_trap_policer *policer,
1558 				  u64 *p_drops)
1559 {
1560 	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1561 	struct mlxsw_sp_trap_policer_item *policer_item;
1562 	char qpcr_pl[MLXSW_REG_QPCR_LEN];
1563 	int err;
1564 
1565 	policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1566 	if (WARN_ON(!policer_item))
1567 		return -EINVAL;
1568 
1569 	mlxsw_reg_qpcr_pack(qpcr_pl, policer_item->hw_id,
1570 			    MLXSW_REG_QPCR_IR_UNITS_M, false, 0, 0);
1571 	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
1572 	if (err)
1573 		return err;
1574 
1575 	*p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl);
1576 
1577 	return 0;
1578 }
1579