1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */
3 
4 #include <net/devlink.h>
5 
6 #include "prestera_devlink.h"
7 #include "prestera_hw.h"
8 
9 /* All driver-specific traps must be documented in
10  * Documentation/networking/devlink/prestera.rst
11  */
12 enum {
13 	DEVLINK_PRESTERA_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX,
14 	DEVLINK_PRESTERA_TRAP_ID_ARP_BC,
15 	DEVLINK_PRESTERA_TRAP_ID_IS_IS,
16 	DEVLINK_PRESTERA_TRAP_ID_OSPF,
17 	DEVLINK_PRESTERA_TRAP_ID_IP_BC_MAC,
18 	DEVLINK_PRESTERA_TRAP_ID_ROUTER_MC,
19 	DEVLINK_PRESTERA_TRAP_ID_VRRP,
20 	DEVLINK_PRESTERA_TRAP_ID_DHCP,
21 	DEVLINK_PRESTERA_TRAP_ID_MAC_TO_ME,
22 	DEVLINK_PRESTERA_TRAP_ID_IPV4_OPTIONS,
23 	DEVLINK_PRESTERA_TRAP_ID_IP_DEFAULT_ROUTE,
24 	DEVLINK_PRESTERA_TRAP_ID_IP_TO_ME,
25 	DEVLINK_PRESTERA_TRAP_ID_IPV4_ICMP_REDIRECT,
26 	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_0,
27 	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_1,
28 	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_2,
29 	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_3,
30 	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_4,
31 	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_5,
32 	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_6,
33 	DEVLINK_PRESTERA_TRAP_ID_ACL_CODE_7,
34 	DEVLINK_PRESTERA_TRAP_ID_BGP,
35 	DEVLINK_PRESTERA_TRAP_ID_SSH,
36 	DEVLINK_PRESTERA_TRAP_ID_TELNET,
37 	DEVLINK_PRESTERA_TRAP_ID_ICMP,
38 	DEVLINK_PRESTERA_TRAP_ID_MET_RED,
39 	DEVLINK_PRESTERA_TRAP_ID_IP_SIP_IS_ZERO,
40 	DEVLINK_PRESTERA_TRAP_ID_IP_UC_DIP_DA_MISMATCH,
41 	DEVLINK_PRESTERA_TRAP_ID_ILLEGAL_IPV4_HDR,
42 	DEVLINK_PRESTERA_TRAP_ID_ILLEGAL_IP_ADDR,
43 	DEVLINK_PRESTERA_TRAP_ID_INVALID_SA,
44 	DEVLINK_PRESTERA_TRAP_ID_LOCAL_PORT,
45 	DEVLINK_PRESTERA_TRAP_ID_PORT_NO_VLAN,
46 	DEVLINK_PRESTERA_TRAP_ID_RXDMA_DROP,
47 };
48 
49 #define DEVLINK_PRESTERA_TRAP_NAME_ARP_BC \
50 	"arp_bc"
51 #define DEVLINK_PRESTERA_TRAP_NAME_IS_IS \
52 	"is_is"
53 #define DEVLINK_PRESTERA_TRAP_NAME_OSPF \
54 	"ospf"
55 #define DEVLINK_PRESTERA_TRAP_NAME_IP_BC_MAC \
56 	"ip_bc_mac"
57 #define DEVLINK_PRESTERA_TRAP_NAME_ROUTER_MC \
58 	"router_mc"
59 #define DEVLINK_PRESTERA_TRAP_NAME_VRRP \
60 	"vrrp"
61 #define DEVLINK_PRESTERA_TRAP_NAME_DHCP \
62 	"dhcp"
63 #define DEVLINK_PRESTERA_TRAP_NAME_MAC_TO_ME \
64 	"mac_to_me"
65 #define DEVLINK_PRESTERA_TRAP_NAME_IPV4_OPTIONS \
66 	"ipv4_options"
67 #define DEVLINK_PRESTERA_TRAP_NAME_IP_DEFAULT_ROUTE \
68 	"ip_default_route"
69 #define DEVLINK_PRESTERA_TRAP_NAME_IP_TO_ME \
70 	"ip_to_me"
71 #define DEVLINK_PRESTERA_TRAP_NAME_IPV4_ICMP_REDIRECT \
72 	"ipv4_icmp_redirect"
73 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_0 \
74 	"acl_code_0"
75 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_1 \
76 	"acl_code_1"
77 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_2 \
78 	"acl_code_2"
79 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_3 \
80 	"acl_code_3"
81 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_4 \
82 	"acl_code_4"
83 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_5 \
84 	"acl_code_5"
85 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_6 \
86 	"acl_code_6"
87 #define DEVLINK_PRESTERA_TRAP_NAME_ACL_CODE_7 \
88 	"acl_code_7"
89 #define DEVLINK_PRESTERA_TRAP_NAME_BGP \
90 	"bgp"
91 #define DEVLINK_PRESTERA_TRAP_NAME_SSH \
92 	"ssh"
93 #define DEVLINK_PRESTERA_TRAP_NAME_TELNET \
94 	"telnet"
95 #define DEVLINK_PRESTERA_TRAP_NAME_ICMP \
96 	"icmp"
97 #define DEVLINK_PRESTERA_TRAP_NAME_RXDMA_DROP \
98 	"rxdma_drop"
99 #define DEVLINK_PRESTERA_TRAP_NAME_PORT_NO_VLAN \
100 	"port_no_vlan"
101 #define DEVLINK_PRESTERA_TRAP_NAME_LOCAL_PORT \
102 	"local_port"
103 #define DEVLINK_PRESTERA_TRAP_NAME_INVALID_SA \
104 	"invalid_sa"
105 #define DEVLINK_PRESTERA_TRAP_NAME_ILLEGAL_IP_ADDR \
106 	"illegal_ip_addr"
107 #define DEVLINK_PRESTERA_TRAP_NAME_ILLEGAL_IPV4_HDR \
108 	"illegal_ipv4_hdr"
109 #define DEVLINK_PRESTERA_TRAP_NAME_IP_UC_DIP_DA_MISMATCH \
110 	"ip_uc_dip_da_mismatch"
111 #define DEVLINK_PRESTERA_TRAP_NAME_IP_SIP_IS_ZERO \
112 	"ip_sip_is_zero"
113 #define DEVLINK_PRESTERA_TRAP_NAME_MET_RED \
114 	"met_red"
115 
116 struct prestera_trap {
117 	struct devlink_trap trap;
118 	u8 cpu_code;
119 };
120 
121 struct prestera_trap_item {
122 	enum devlink_trap_action action;
123 	void *trap_ctx;
124 };
125 
126 struct prestera_trap_data {
127 	struct prestera_switch *sw;
128 	struct prestera_trap_item *trap_items_arr;
129 	u32 traps_count;
130 };
131 
132 #define PRESTERA_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT
133 
134 #define PRESTERA_TRAP_CONTROL(_id, _group_id, _action)			      \
135 	DEVLINK_TRAP_GENERIC(CONTROL, _action, _id,			      \
136 			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
137 			     PRESTERA_TRAP_METADATA)
138 
139 #define PRESTERA_TRAP_DRIVER_CONTROL(_id, _group_id)			      \
140 	DEVLINK_TRAP_DRIVER(CONTROL, TRAP, DEVLINK_PRESTERA_TRAP_ID_##_id,    \
141 			    DEVLINK_PRESTERA_TRAP_NAME_##_id,		      \
142 			    DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
143 			    PRESTERA_TRAP_METADATA)
144 
145 #define PRESTERA_TRAP_EXCEPTION(_id, _group_id)				      \
146 	DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id,			      \
147 			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
148 			     PRESTERA_TRAP_METADATA)
149 
150 #define PRESTERA_TRAP_DRIVER_EXCEPTION(_id, _group_id)			      \
151 	DEVLINK_TRAP_DRIVER(EXCEPTION, TRAP, DEVLINK_PRESTERA_TRAP_ID_##_id,  \
152 			    DEVLINK_PRESTERA_TRAP_NAME_##_id,		      \
153 			    DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
154 			    PRESTERA_TRAP_METADATA)
155 
156 #define PRESTERA_TRAP_DRIVER_DROP(_id, _group_id)			      \
157 	DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_PRESTERA_TRAP_ID_##_id,	      \
158 			    DEVLINK_PRESTERA_TRAP_NAME_##_id,		      \
159 			    DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
160 			    PRESTERA_TRAP_METADATA)
161 
162 static const struct devlink_trap_group prestera_trap_groups_arr[] = {
163 	/* No policer is associated with following groups (policerid == 0)*/
164 	DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0),
165 	DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 0),
166 	DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 0),
167 	DEVLINK_TRAP_GROUP_GENERIC(NEIGH_DISCOVERY, 0),
168 	DEVLINK_TRAP_GROUP_GENERIC(ACL_TRAP, 0),
169 	DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 0),
170 	DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0),
171 	DEVLINK_TRAP_GROUP_GENERIC(OSPF, 0),
172 	DEVLINK_TRAP_GROUP_GENERIC(STP, 0),
173 	DEVLINK_TRAP_GROUP_GENERIC(LACP, 0),
174 	DEVLINK_TRAP_GROUP_GENERIC(LLDP, 0),
175 	DEVLINK_TRAP_GROUP_GENERIC(VRRP, 0),
176 	DEVLINK_TRAP_GROUP_GENERIC(DHCP, 0),
177 	DEVLINK_TRAP_GROUP_GENERIC(BGP, 0),
178 	DEVLINK_TRAP_GROUP_GENERIC(LOCAL_DELIVERY, 0),
179 	DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 0),
180 };
181 
182 /* Initialize trap list, as well as associate CPU code with them. */
183 static struct prestera_trap prestera_trap_items_arr[] = {
184 	{
185 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ARP_BC, NEIGH_DISCOVERY),
186 		.cpu_code = 5,
187 	},
188 	{
189 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(IS_IS, LOCAL_DELIVERY),
190 		.cpu_code = 13,
191 	},
192 	{
193 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(OSPF, OSPF),
194 		.cpu_code = 16,
195 	},
196 	{
197 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(IP_BC_MAC, LOCAL_DELIVERY),
198 		.cpu_code = 19,
199 	},
200 	{
201 		.trap = PRESTERA_TRAP_CONTROL(STP, STP, TRAP),
202 		.cpu_code = 26,
203 	},
204 	{
205 		.trap = PRESTERA_TRAP_CONTROL(LACP, LACP, TRAP),
206 		.cpu_code = 27,
207 	},
208 	{
209 		.trap = PRESTERA_TRAP_CONTROL(LLDP, LLDP, TRAP),
210 		.cpu_code = 28,
211 	},
212 	{
213 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ROUTER_MC, LOCAL_DELIVERY),
214 		.cpu_code = 29,
215 	},
216 	{
217 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(VRRP, VRRP),
218 		.cpu_code = 30,
219 	},
220 	{
221 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(DHCP, DHCP),
222 		.cpu_code = 33,
223 	},
224 	{
225 		.trap = PRESTERA_TRAP_EXCEPTION(MTU_ERROR, L3_EXCEPTIONS),
226 		.cpu_code = 63,
227 	},
228 	{
229 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(MAC_TO_ME, LOCAL_DELIVERY),
230 		.cpu_code = 65,
231 	},
232 	{
233 		.trap = PRESTERA_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS),
234 		.cpu_code = 133,
235 	},
236 	{
237 		.trap = PRESTERA_TRAP_DRIVER_EXCEPTION(IPV4_OPTIONS,
238 						       L3_EXCEPTIONS),
239 		.cpu_code = 141,
240 	},
241 	{
242 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(IP_DEFAULT_ROUTE,
243 						     LOCAL_DELIVERY),
244 		.cpu_code = 160,
245 	},
246 	{
247 		.trap = PRESTERA_TRAP_CONTROL(LOCAL_ROUTE, LOCAL_DELIVERY,
248 					      TRAP),
249 		.cpu_code = 161,
250 	},
251 	{
252 		.trap = PRESTERA_TRAP_DRIVER_EXCEPTION(IPV4_ICMP_REDIRECT,
253 						       L3_EXCEPTIONS),
254 		.cpu_code = 180,
255 	},
256 	{
257 		.trap = PRESTERA_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY,
258 					      TRAP),
259 		.cpu_code = 188,
260 	},
261 	{
262 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_0, ACL_TRAP),
263 		.cpu_code = 192,
264 	},
265 	{
266 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_1, ACL_TRAP),
267 		.cpu_code = 193,
268 	},
269 	{
270 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_2, ACL_TRAP),
271 		.cpu_code = 194,
272 	},
273 	{
274 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_3, ACL_TRAP),
275 		.cpu_code = 195,
276 	},
277 	{
278 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_4, ACL_TRAP),
279 		.cpu_code = 196,
280 	},
281 	{
282 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_5, ACL_TRAP),
283 		.cpu_code = 197,
284 	},
285 	{
286 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_6, ACL_TRAP),
287 		.cpu_code = 198,
288 	},
289 	{
290 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ACL_CODE_7, ACL_TRAP),
291 		.cpu_code = 199,
292 	},
293 	{
294 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(BGP, BGP),
295 		.cpu_code = 206,
296 	},
297 	{
298 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(SSH, LOCAL_DELIVERY),
299 		.cpu_code = 207,
300 	},
301 	{
302 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(TELNET, LOCAL_DELIVERY),
303 		.cpu_code = 208,
304 	},
305 	{
306 		.trap = PRESTERA_TRAP_DRIVER_CONTROL(ICMP, LOCAL_DELIVERY),
307 		.cpu_code = 209,
308 	},
309 	{
310 		.trap = PRESTERA_TRAP_DRIVER_DROP(RXDMA_DROP, BUFFER_DROPS),
311 		.cpu_code = 37,
312 	},
313 	{
314 		.trap = PRESTERA_TRAP_DRIVER_DROP(PORT_NO_VLAN, L2_DROPS),
315 		.cpu_code = 39,
316 	},
317 	{
318 		.trap = PRESTERA_TRAP_DRIVER_DROP(LOCAL_PORT, L2_DROPS),
319 		.cpu_code = 56,
320 	},
321 	{
322 		.trap = PRESTERA_TRAP_DRIVER_DROP(INVALID_SA, L2_DROPS),
323 		.cpu_code = 60,
324 	},
325 	{
326 		.trap = PRESTERA_TRAP_DRIVER_DROP(ILLEGAL_IP_ADDR, L3_DROPS),
327 		.cpu_code = 136,
328 	},
329 	{
330 		.trap = PRESTERA_TRAP_DRIVER_DROP(ILLEGAL_IPV4_HDR, L3_DROPS),
331 		.cpu_code = 137,
332 	},
333 	{
334 		.trap = PRESTERA_TRAP_DRIVER_DROP(IP_UC_DIP_DA_MISMATCH,
335 						  L3_DROPS),
336 		.cpu_code = 138,
337 	},
338 	{
339 		.trap = PRESTERA_TRAP_DRIVER_DROP(IP_SIP_IS_ZERO, L3_DROPS),
340 		.cpu_code = 145,
341 	},
342 	{
343 		.trap = PRESTERA_TRAP_DRIVER_DROP(MET_RED, BUFFER_DROPS),
344 		.cpu_code = 185,
345 	},
346 };
347 
348 static void prestera_devlink_traps_fini(struct prestera_switch *sw);
349 
350 static int prestera_drop_counter_get(struct devlink *devlink,
351 				     const struct devlink_trap *trap,
352 				     u64 *p_drops);
353 
354 static int prestera_dl_info_get(struct devlink *dl,
355 				struct devlink_info_req *req,
356 				struct netlink_ext_ack *extack)
357 {
358 	struct prestera_switch *sw = devlink_priv(dl);
359 	char buf[16];
360 	int err;
361 
362 	err = devlink_info_driver_name_put(req, PRESTERA_DRV_NAME);
363 	if (err)
364 		return err;
365 
366 	snprintf(buf, sizeof(buf), "%d.%d.%d",
367 		 sw->dev->fw_rev.maj,
368 		 sw->dev->fw_rev.min,
369 		 sw->dev->fw_rev.sub);
370 
371 	return devlink_info_version_running_put(req,
372 					       DEVLINK_INFO_VERSION_GENERIC_FW,
373 					       buf);
374 }
375 
376 static int prestera_trap_init(struct devlink *devlink,
377 			      const struct devlink_trap *trap, void *trap_ctx);
378 
379 static int prestera_trap_action_set(struct devlink *devlink,
380 				    const struct devlink_trap *trap,
381 				    enum devlink_trap_action action,
382 				    struct netlink_ext_ack *extack);
383 
384 static int prestera_devlink_traps_register(struct prestera_switch *sw);
385 
386 static const struct devlink_ops prestera_dl_ops = {
387 	.info_get = prestera_dl_info_get,
388 	.trap_init = prestera_trap_init,
389 	.trap_action_set = prestera_trap_action_set,
390 	.trap_drop_counter_get = prestera_drop_counter_get,
391 };
392 
393 struct prestera_switch *prestera_devlink_alloc(struct prestera_device *dev)
394 {
395 	struct devlink *dl;
396 
397 	dl = devlink_alloc(&prestera_dl_ops, sizeof(struct prestera_switch),
398 			   dev->dev);
399 
400 	return devlink_priv(dl);
401 }
402 
403 void prestera_devlink_free(struct prestera_switch *sw)
404 {
405 	struct devlink *dl = priv_to_devlink(sw);
406 
407 	devlink_free(dl);
408 }
409 
410 int prestera_devlink_register(struct prestera_switch *sw)
411 {
412 	struct devlink *dl = priv_to_devlink(sw);
413 	int err;
414 
415 	err = devlink_register(dl);
416 	if (err) {
417 		dev_err(prestera_dev(sw), "devlink_register failed: %d\n", err);
418 		return err;
419 	}
420 
421 	err = prestera_devlink_traps_register(sw);
422 	if (err) {
423 		devlink_unregister(dl);
424 		dev_err(sw->dev->dev, "devlink_traps_register failed: %d\n",
425 			err);
426 		return err;
427 	}
428 
429 	return 0;
430 }
431 
432 void prestera_devlink_unregister(struct prestera_switch *sw)
433 {
434 	struct prestera_trap_data *trap_data = sw->trap_data;
435 	struct devlink *dl = priv_to_devlink(sw);
436 
437 	prestera_devlink_traps_fini(sw);
438 	devlink_unregister(dl);
439 
440 	kfree(trap_data->trap_items_arr);
441 	kfree(trap_data);
442 }
443 
444 int prestera_devlink_port_register(struct prestera_port *port)
445 {
446 	struct prestera_switch *sw = port->sw;
447 	struct devlink *dl = priv_to_devlink(sw);
448 	struct devlink_port_attrs attrs = {};
449 	int err;
450 
451 	attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
452 	attrs.phys.port_number = port->fp_id;
453 	attrs.switch_id.id_len = sizeof(sw->id);
454 	memcpy(attrs.switch_id.id, &sw->id, attrs.switch_id.id_len);
455 
456 	devlink_port_attrs_set(&port->dl_port, &attrs);
457 
458 	err = devlink_port_register(dl, &port->dl_port, port->fp_id);
459 	if (err) {
460 		dev_err(prestera_dev(sw), "devlink_port_register failed: %d\n", err);
461 		return err;
462 	}
463 
464 	return 0;
465 }
466 
467 void prestera_devlink_port_unregister(struct prestera_port *port)
468 {
469 	devlink_port_unregister(&port->dl_port);
470 }
471 
472 void prestera_devlink_port_set(struct prestera_port *port)
473 {
474 	devlink_port_type_eth_set(&port->dl_port, port->dev);
475 }
476 
477 void prestera_devlink_port_clear(struct prestera_port *port)
478 {
479 	devlink_port_type_clear(&port->dl_port);
480 }
481 
482 struct devlink_port *prestera_devlink_get_port(struct net_device *dev)
483 {
484 	struct prestera_port *port = netdev_priv(dev);
485 
486 	return &port->dl_port;
487 }
488 
489 static int prestera_devlink_traps_register(struct prestera_switch *sw)
490 {
491 	const u32 groups_count = ARRAY_SIZE(prestera_trap_groups_arr);
492 	const u32 traps_count = ARRAY_SIZE(prestera_trap_items_arr);
493 	struct devlink *devlink = priv_to_devlink(sw);
494 	struct prestera_trap_data *trap_data;
495 	struct prestera_trap *prestera_trap;
496 	int err, i;
497 
498 	trap_data = kzalloc(sizeof(*trap_data), GFP_KERNEL);
499 	if (!trap_data)
500 		return -ENOMEM;
501 
502 	trap_data->trap_items_arr = kcalloc(traps_count,
503 					    sizeof(struct prestera_trap_item),
504 					    GFP_KERNEL);
505 	if (!trap_data->trap_items_arr) {
506 		err = -ENOMEM;
507 		goto err_trap_items_alloc;
508 	}
509 
510 	trap_data->sw = sw;
511 	trap_data->traps_count = traps_count;
512 	sw->trap_data = trap_data;
513 
514 	err = devlink_trap_groups_register(devlink, prestera_trap_groups_arr,
515 					   groups_count);
516 	if (err)
517 		goto err_groups_register;
518 
519 	for (i = 0; i < traps_count; i++) {
520 		prestera_trap = &prestera_trap_items_arr[i];
521 		err = devlink_traps_register(devlink, &prestera_trap->trap, 1,
522 					     sw);
523 		if (err)
524 			goto err_trap_register;
525 	}
526 
527 	return 0;
528 
529 err_trap_register:
530 	for (i--; i >= 0; i--) {
531 		prestera_trap = &prestera_trap_items_arr[i];
532 		devlink_traps_unregister(devlink, &prestera_trap->trap, 1);
533 	}
534 	devlink_trap_groups_unregister(devlink, prestera_trap_groups_arr,
535 				       groups_count);
536 err_groups_register:
537 	kfree(trap_data->trap_items_arr);
538 err_trap_items_alloc:
539 	kfree(trap_data);
540 	return err;
541 }
542 
543 static struct prestera_trap_item *
544 prestera_get_trap_item_by_cpu_code(struct prestera_switch *sw, u8 cpu_code)
545 {
546 	struct prestera_trap_data *trap_data = sw->trap_data;
547 	struct prestera_trap *prestera_trap;
548 	int i;
549 
550 	for (i = 0; i < trap_data->traps_count; i++) {
551 		prestera_trap = &prestera_trap_items_arr[i];
552 		if (cpu_code == prestera_trap->cpu_code)
553 			return &trap_data->trap_items_arr[i];
554 	}
555 
556 	return NULL;
557 }
558 
559 void prestera_devlink_trap_report(struct prestera_port *port,
560 				  struct sk_buff *skb, u8 cpu_code)
561 {
562 	struct prestera_trap_item *trap_item;
563 	struct devlink *devlink;
564 
565 	devlink = port->dl_port.devlink;
566 
567 	trap_item = prestera_get_trap_item_by_cpu_code(port->sw, cpu_code);
568 	if (unlikely(!trap_item))
569 		return;
570 
571 	devlink_trap_report(devlink, skb, trap_item->trap_ctx,
572 			    &port->dl_port, NULL);
573 }
574 
575 static struct prestera_trap_item *
576 prestera_devlink_trap_item_lookup(struct prestera_switch *sw, u16 trap_id)
577 {
578 	struct prestera_trap_data *trap_data = sw->trap_data;
579 	int i;
580 
581 	for (i = 0; i < ARRAY_SIZE(prestera_trap_items_arr); i++) {
582 		if (prestera_trap_items_arr[i].trap.id == trap_id)
583 			return &trap_data->trap_items_arr[i];
584 	}
585 
586 	return NULL;
587 }
588 
589 static int prestera_trap_init(struct devlink *devlink,
590 			      const struct devlink_trap *trap, void *trap_ctx)
591 {
592 	struct prestera_switch *sw = devlink_priv(devlink);
593 	struct prestera_trap_item *trap_item;
594 
595 	trap_item = prestera_devlink_trap_item_lookup(sw, trap->id);
596 	if (WARN_ON(!trap_item))
597 		return -EINVAL;
598 
599 	trap_item->trap_ctx = trap_ctx;
600 	trap_item->action = trap->init_action;
601 
602 	return 0;
603 }
604 
605 static int prestera_trap_action_set(struct devlink *devlink,
606 				    const struct devlink_trap *trap,
607 				    enum devlink_trap_action action,
608 				    struct netlink_ext_ack *extack)
609 {
610 	/* Currently, driver does not support trap action altering */
611 	return -EOPNOTSUPP;
612 }
613 
614 static int prestera_drop_counter_get(struct devlink *devlink,
615 				     const struct devlink_trap *trap,
616 				     u64 *p_drops)
617 {
618 	struct prestera_switch *sw = devlink_priv(devlink);
619 	enum prestera_hw_cpu_code_cnt_t cpu_code_type =
620 		PRESTERA_HW_CPU_CODE_CNT_TYPE_DROP;
621 	struct prestera_trap *prestera_trap =
622 		container_of(trap, struct prestera_trap, trap);
623 
624 	return prestera_hw_cpu_code_counters_get(sw, prestera_trap->cpu_code,
625 						 cpu_code_type, p_drops);
626 }
627 
628 static void prestera_devlink_traps_fini(struct prestera_switch *sw)
629 {
630 	struct devlink *dl = priv_to_devlink(sw);
631 	const struct devlink_trap *trap;
632 	int i;
633 
634 	for (i = 0; i < ARRAY_SIZE(prestera_trap_items_arr); ++i) {
635 		trap = &prestera_trap_items_arr[i].trap;
636 		devlink_traps_unregister(dl, trap, 1);
637 	}
638 
639 	devlink_trap_groups_unregister(dl, prestera_trap_groups_arr,
640 				       ARRAY_SIZE(prestera_trap_groups_arr));
641 }
642