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