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 */
12enum {
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
116struct prestera_trap {
117 struct devlink_trap trap;
118 u8 cpu_code;
119};
120
121struct prestera_trap_item {
122 enum devlink_trap_action action;
123 void *trap_ctx;
124};
125
126struct 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
162static 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. */
183static 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
348static int prestera_drop_counter_get(struct devlink *devlink,
349 const struct devlink_trap *trap,
350 u64 *p_drops);
351
352static int prestera_dl_info_get(struct devlink *dl,
353 struct devlink_info_req *req,
354 struct netlink_ext_ack *extack)
355{
356 struct prestera_switch *sw = devlink_priv(devlink: dl);
357 char buf[16];
358
359 snprintf(buf, size: sizeof(buf), fmt: "%d.%d.%d",
360 sw->dev->fw_rev.maj,
361 sw->dev->fw_rev.min,
362 sw->dev->fw_rev.sub);
363
364 return devlink_info_version_running_put(req,
365 DEVLINK_INFO_VERSION_GENERIC_FW,
366 version_value: buf);
367}
368
369static int prestera_trap_init(struct devlink *devlink,
370 const struct devlink_trap *trap, void *trap_ctx);
371
372static int prestera_trap_action_set(struct devlink *devlink,
373 const struct devlink_trap *trap,
374 enum devlink_trap_action action,
375 struct netlink_ext_ack *extack);
376
377static const struct devlink_ops prestera_dl_ops = {
378 .info_get = prestera_dl_info_get,
379 .trap_init = prestera_trap_init,
380 .trap_action_set = prestera_trap_action_set,
381 .trap_drop_counter_get = prestera_drop_counter_get,
382};
383
384struct prestera_switch *prestera_devlink_alloc(struct prestera_device *dev)
385{
386 struct devlink *dl;
387
388 dl = devlink_alloc(ops: &prestera_dl_ops, priv_size: sizeof(struct prestera_switch),
389 dev: dev->dev);
390
391 return devlink_priv(devlink: dl);
392}
393
394void prestera_devlink_free(struct prestera_switch *sw)
395{
396 struct devlink *dl = priv_to_devlink(priv: sw);
397
398 devlink_free(devlink: dl);
399}
400
401void prestera_devlink_register(struct prestera_switch *sw)
402{
403 struct devlink *dl = priv_to_devlink(priv: sw);
404
405 devlink_register(devlink: dl);
406}
407
408void prestera_devlink_unregister(struct prestera_switch *sw)
409{
410 struct devlink *dl = priv_to_devlink(priv: sw);
411
412 devlink_unregister(devlink: dl);
413}
414
415int prestera_devlink_port_register(struct prestera_port *port)
416{
417 struct prestera_switch *sw = port->sw;
418 struct devlink *dl = priv_to_devlink(priv: sw);
419 struct devlink_port_attrs attrs = {};
420 int err;
421
422 attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
423 attrs.phys.port_number = port->fp_id;
424 attrs.switch_id.id_len = sizeof(sw->id);
425 memcpy(attrs.switch_id.id, &sw->id, attrs.switch_id.id_len);
426
427 devlink_port_attrs_set(devlink_port: &port->dl_port, devlink_port_attrs: &attrs);
428
429 err = devlink_port_register(devlink: dl, devlink_port: &port->dl_port, port_index: port->fp_id);
430 if (err) {
431 dev_err(prestera_dev(sw), "devlink_port_register failed: %d\n", err);
432 return err;
433 }
434
435 return 0;
436}
437
438void prestera_devlink_port_unregister(struct prestera_port *port)
439{
440 devlink_port_unregister(devlink_port: &port->dl_port);
441}
442
443int prestera_devlink_traps_register(struct prestera_switch *sw)
444{
445 const u32 groups_count = ARRAY_SIZE(prestera_trap_groups_arr);
446 const u32 traps_count = ARRAY_SIZE(prestera_trap_items_arr);
447 struct devlink *devlink = priv_to_devlink(priv: sw);
448 struct prestera_trap_data *trap_data;
449 struct prestera_trap *prestera_trap;
450 int err, i;
451
452 trap_data = kzalloc(size: sizeof(*trap_data), GFP_KERNEL);
453 if (!trap_data)
454 return -ENOMEM;
455
456 trap_data->trap_items_arr = kcalloc(n: traps_count,
457 size: sizeof(struct prestera_trap_item),
458 GFP_KERNEL);
459 if (!trap_data->trap_items_arr) {
460 err = -ENOMEM;
461 goto err_trap_items_alloc;
462 }
463
464 trap_data->sw = sw;
465 trap_data->traps_count = traps_count;
466 sw->trap_data = trap_data;
467
468 err = devlink_trap_groups_register(devlink, groups: prestera_trap_groups_arr,
469 groups_count);
470 if (err)
471 goto err_groups_register;
472
473 for (i = 0; i < traps_count; i++) {
474 prestera_trap = &prestera_trap_items_arr[i];
475 err = devlink_traps_register(devlink, traps: &prestera_trap->trap, traps_count: 1,
476 priv: sw);
477 if (err)
478 goto err_trap_register;
479 }
480
481 return 0;
482
483err_trap_register:
484 for (i--; i >= 0; i--) {
485 prestera_trap = &prestera_trap_items_arr[i];
486 devlink_traps_unregister(devlink, traps: &prestera_trap->trap, traps_count: 1);
487 }
488 devlink_trap_groups_unregister(devlink, groups: prestera_trap_groups_arr,
489 groups_count);
490err_groups_register:
491 kfree(objp: trap_data->trap_items_arr);
492err_trap_items_alloc:
493 kfree(objp: trap_data);
494 return err;
495}
496
497static struct prestera_trap_item *
498prestera_get_trap_item_by_cpu_code(struct prestera_switch *sw, u8 cpu_code)
499{
500 struct prestera_trap_data *trap_data = sw->trap_data;
501 struct prestera_trap *prestera_trap;
502 int i;
503
504 for (i = 0; i < trap_data->traps_count; i++) {
505 prestera_trap = &prestera_trap_items_arr[i];
506 if (cpu_code == prestera_trap->cpu_code)
507 return &trap_data->trap_items_arr[i];
508 }
509
510 return NULL;
511}
512
513void prestera_devlink_trap_report(struct prestera_port *port,
514 struct sk_buff *skb, u8 cpu_code)
515{
516 struct prestera_trap_item *trap_item;
517 struct devlink *devlink;
518
519 devlink = port->dl_port.devlink;
520
521 trap_item = prestera_get_trap_item_by_cpu_code(sw: port->sw, cpu_code);
522 if (unlikely(!trap_item))
523 return;
524
525 devlink_trap_report(devlink, skb, trap_ctx: trap_item->trap_ctx,
526 in_devlink_port: &port->dl_port, NULL);
527}
528
529static struct prestera_trap_item *
530prestera_devlink_trap_item_lookup(struct prestera_switch *sw, u16 trap_id)
531{
532 struct prestera_trap_data *trap_data = sw->trap_data;
533 int i;
534
535 for (i = 0; i < ARRAY_SIZE(prestera_trap_items_arr); i++) {
536 if (prestera_trap_items_arr[i].trap.id == trap_id)
537 return &trap_data->trap_items_arr[i];
538 }
539
540 return NULL;
541}
542
543static int prestera_trap_init(struct devlink *devlink,
544 const struct devlink_trap *trap, void *trap_ctx)
545{
546 struct prestera_switch *sw = devlink_priv(devlink);
547 struct prestera_trap_item *trap_item;
548
549 trap_item = prestera_devlink_trap_item_lookup(sw, trap_id: trap->id);
550 if (WARN_ON(!trap_item))
551 return -EINVAL;
552
553 trap_item->trap_ctx = trap_ctx;
554 trap_item->action = trap->init_action;
555
556 return 0;
557}
558
559static int prestera_trap_action_set(struct devlink *devlink,
560 const struct devlink_trap *trap,
561 enum devlink_trap_action action,
562 struct netlink_ext_ack *extack)
563{
564 /* Currently, driver does not support trap action altering */
565 return -EOPNOTSUPP;
566}
567
568static int prestera_drop_counter_get(struct devlink *devlink,
569 const struct devlink_trap *trap,
570 u64 *p_drops)
571{
572 struct prestera_switch *sw = devlink_priv(devlink);
573 enum prestera_hw_cpu_code_cnt_t cpu_code_type =
574 PRESTERA_HW_CPU_CODE_CNT_TYPE_DROP;
575 struct prestera_trap *prestera_trap =
576 container_of(trap, struct prestera_trap, trap);
577
578 return prestera_hw_cpu_code_counters_get(sw, code: prestera_trap->cpu_code,
579 counter_type: cpu_code_type, packet_count: p_drops);
580}
581
582void prestera_devlink_traps_unregister(struct prestera_switch *sw)
583{
584 struct prestera_trap_data *trap_data = sw->trap_data;
585 struct devlink *dl = priv_to_devlink(priv: sw);
586 const struct devlink_trap *trap;
587 int i;
588
589 for (i = 0; i < ARRAY_SIZE(prestera_trap_items_arr); ++i) {
590 trap = &prestera_trap_items_arr[i].trap;
591 devlink_traps_unregister(devlink: dl, traps: trap, traps_count: 1);
592 }
593
594 devlink_trap_groups_unregister(devlink: dl, groups: prestera_trap_groups_arr,
595 ARRAY_SIZE(prestera_trap_groups_arr));
596 kfree(objp: trap_data->trap_items_arr);
597 kfree(objp: trap_data);
598}
599

source code of linux/drivers/net/ethernet/marvell/prestera/prestera_devlink.c