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 void prestera_devlink_traps_fini(struct prestera_switch *sw);
 349
 350static int prestera_drop_counter_get(struct devlink *devlink,
 351                                     const struct devlink_trap *trap,
 352                                     u64 *p_drops);
 353
 354static 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
 376static int prestera_trap_init(struct devlink *devlink,
 377                              const struct devlink_trap *trap, void *trap_ctx);
 378
 379static 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
 384static int prestera_devlink_traps_register(struct prestera_switch *sw);
 385
 386static 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
 393struct 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
 403void prestera_devlink_free(struct prestera_switch *sw)
 404{
 405        struct devlink *dl = priv_to_devlink(sw);
 406
 407        devlink_free(dl);
 408}
 409
 410int 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
 432void 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
 444int 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
 467void prestera_devlink_port_unregister(struct prestera_port *port)
 468{
 469        devlink_port_unregister(&port->dl_port);
 470}
 471
 472void prestera_devlink_port_set(struct prestera_port *port)
 473{
 474        devlink_port_type_eth_set(&port->dl_port, port->dev);
 475}
 476
 477void prestera_devlink_port_clear(struct prestera_port *port)
 478{
 479        devlink_port_type_clear(&port->dl_port);
 480}
 481
 482struct 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
 489static 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
 529err_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);
 536err_groups_register:
 537        kfree(trap_data->trap_items_arr);
 538err_trap_items_alloc:
 539        kfree(trap_data);
 540        return err;
 541}
 542
 543static struct prestera_trap_item *
 544prestera_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
 559void 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
 575static struct prestera_trap_item *
 576prestera_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
 589static 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
 605static 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
 614static 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
 628static 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