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