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