linux/drivers/net/ethernet/marvell/prestera/prestera_devlink.c
<<
>>
Prefs
   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(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
 374static int prestera_trap_init(struct devlink *devlink,
 375                              const struct devlink_trap *trap, void *trap_ctx);
 376
 377static 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
 382static 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
 389struct 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
 399void prestera_devlink_free(struct prestera_switch *sw)
 400{
 401        struct devlink *dl = priv_to_devlink(sw);
 402
 403        devlink_free(dl);
 404}
 405
 406void prestera_devlink_register(struct prestera_switch *sw)
 407{
 408        struct devlink *dl = priv_to_devlink(sw);
 409
 410        devlink_register(dl);
 411}
 412
 413void prestera_devlink_unregister(struct prestera_switch *sw)
 414{
 415        struct devlink *dl = priv_to_devlink(sw);
 416
 417        devlink_unregister(dl);
 418}
 419
 420int 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
 443void prestera_devlink_port_unregister(struct prestera_port *port)
 444{
 445        devlink_port_unregister(&port->dl_port);
 446}
 447
 448void prestera_devlink_port_set(struct prestera_port *port)
 449{
 450        devlink_port_type_eth_set(&port->dl_port, port->dev);
 451}
 452
 453void prestera_devlink_port_clear(struct prestera_port *port)
 454{
 455        devlink_port_type_clear(&port->dl_port);
 456}
 457
 458struct 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
 465int 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
 505err_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);
 512err_groups_register:
 513        kfree(trap_data->trap_items_arr);
 514err_trap_items_alloc:
 515        kfree(trap_data);
 516        return err;
 517}
 518
 519static struct prestera_trap_item *
 520prestera_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
 535void 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
 551static struct prestera_trap_item *
 552prestera_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
 565static 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
 581static 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
 590static 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
 604void 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