linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/* Copyright (c) 2019 Mellanox Technologies. All rights reserved */
   3
   4#include <linux/bitops.h>
   5#include <linux/kernel.h>
   6#include <linux/netlink.h>
   7#include <net/devlink.h>
   8#include <uapi/linux/devlink.h>
   9
  10#include "core.h"
  11#include "reg.h"
  12#include "spectrum.h"
  13#include "spectrum_trap.h"
  14
  15struct mlxsw_sp_trap_policer_item {
  16        struct devlink_trap_policer policer;
  17        u16 hw_id;
  18};
  19
  20struct mlxsw_sp_trap_group_item {
  21        struct devlink_trap_group group;
  22        u16 hw_group_id;
  23        u8 priority;
  24        u8 fixed_policer:1; /* Whether policer binding can change */
  25};
  26
  27#define MLXSW_SP_TRAP_LISTENERS_MAX 3
  28
  29struct mlxsw_sp_trap_item {
  30        struct devlink_trap trap;
  31        struct mlxsw_listener listeners_arr[MLXSW_SP_TRAP_LISTENERS_MAX];
  32        u8 is_source:1;
  33};
  34
  35/* All driver-specific traps must be documented in
  36 * Documentation/networking/devlink/mlxsw.rst
  37 */
  38enum {
  39        DEVLINK_MLXSW_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX,
  40        DEVLINK_MLXSW_TRAP_ID_IRIF_DISABLED,
  41        DEVLINK_MLXSW_TRAP_ID_ERIF_DISABLED,
  42};
  43
  44#define DEVLINK_MLXSW_TRAP_NAME_IRIF_DISABLED \
  45        "irif_disabled"
  46#define DEVLINK_MLXSW_TRAP_NAME_ERIF_DISABLED \
  47        "erif_disabled"
  48
  49#define MLXSW_SP_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT
  50
  51enum {
  52        /* Packet was mirrored from ingress. */
  53        MLXSW_SP_MIRROR_REASON_INGRESS = 1,
  54        /* Packet was mirrored from policy engine. */
  55        MLXSW_SP_MIRROR_REASON_POLICY_ENGINE = 2,
  56        /* Packet was early dropped. */
  57        MLXSW_SP_MIRROR_REASON_INGRESS_WRED = 9,
  58        /* Packet was mirrored from egress. */
  59        MLXSW_SP_MIRROR_REASON_EGRESS = 14,
  60};
  61
  62static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
  63                                u16 local_port,
  64                                struct mlxsw_sp_port *mlxsw_sp_port)
  65{
  66        struct mlxsw_sp_port_pcpu_stats *pcpu_stats;
  67
  68        if (unlikely(!mlxsw_sp_port)) {
  69                dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n",
  70                                     local_port);
  71                kfree_skb(skb);
  72                return -EINVAL;
  73        }
  74
  75        skb->dev = mlxsw_sp_port->dev;
  76
  77        pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats);
  78        u64_stats_update_begin(&pcpu_stats->syncp);
  79        pcpu_stats->rx_packets++;
  80        pcpu_stats->rx_bytes += skb->len;
  81        u64_stats_update_end(&pcpu_stats->syncp);
  82
  83        skb->protocol = eth_type_trans(skb, skb->dev);
  84
  85        return 0;
  86}
  87
  88static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u16 local_port,
  89                                      void *trap_ctx)
  90{
  91        struct devlink_port *in_devlink_port;
  92        struct mlxsw_sp_port *mlxsw_sp_port;
  93        struct mlxsw_sp *mlxsw_sp;
  94        struct devlink *devlink;
  95        int err;
  96
  97        mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
  98        mlxsw_sp_port = mlxsw_sp->ports[local_port];
  99
 100        err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
 101        if (err)
 102                return;
 103
 104        devlink = priv_to_devlink(mlxsw_sp->core);
 105        in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
 106                                                           local_port);
 107        skb_push(skb, ETH_HLEN);
 108        devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL);
 109        consume_skb(skb);
 110}
 111
 112static void mlxsw_sp_rx_acl_drop_listener(struct sk_buff *skb, u16 local_port,
 113                                          void *trap_ctx)
 114{
 115        u32 cookie_index = mlxsw_skb_cb(skb)->rx_md_info.cookie_index;
 116        const struct flow_action_cookie *fa_cookie;
 117        struct devlink_port *in_devlink_port;
 118        struct mlxsw_sp_port *mlxsw_sp_port;
 119        struct mlxsw_sp *mlxsw_sp;
 120        struct devlink *devlink;
 121        int err;
 122
 123        mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
 124        mlxsw_sp_port = mlxsw_sp->ports[local_port];
 125
 126        err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
 127        if (err)
 128                return;
 129
 130        devlink = priv_to_devlink(mlxsw_sp->core);
 131        in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
 132                                                           local_port);
 133        skb_push(skb, ETH_HLEN);
 134        rcu_read_lock();
 135        fa_cookie = mlxsw_sp_acl_act_cookie_lookup(mlxsw_sp, cookie_index);
 136        devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, fa_cookie);
 137        rcu_read_unlock();
 138        consume_skb(skb);
 139}
 140
 141static int __mlxsw_sp_rx_no_mark_listener(struct sk_buff *skb, u16 local_port,
 142                                          void *trap_ctx)
 143{
 144        struct devlink_port *in_devlink_port;
 145        struct mlxsw_sp_port *mlxsw_sp_port;
 146        struct mlxsw_sp *mlxsw_sp;
 147        struct devlink *devlink;
 148        int err;
 149
 150        mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
 151        mlxsw_sp_port = mlxsw_sp->ports[local_port];
 152
 153        err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
 154        if (err)
 155                return err;
 156
 157        devlink = priv_to_devlink(mlxsw_sp->core);
 158        in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
 159                                                           local_port);
 160        skb_push(skb, ETH_HLEN);
 161        devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL);
 162        skb_pull(skb, ETH_HLEN);
 163
 164        return 0;
 165}
 166
 167static void mlxsw_sp_rx_no_mark_listener(struct sk_buff *skb, u16 local_port,
 168                                         void *trap_ctx)
 169{
 170        int err;
 171
 172        err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
 173        if (err)
 174                return;
 175
 176        netif_receive_skb(skb);
 177}
 178
 179static void mlxsw_sp_rx_mark_listener(struct sk_buff *skb, u16 local_port,
 180                                      void *trap_ctx)
 181{
 182        skb->offload_fwd_mark = 1;
 183        mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
 184}
 185
 186static void mlxsw_sp_rx_l3_mark_listener(struct sk_buff *skb, u16 local_port,
 187                                         void *trap_ctx)
 188{
 189        skb->offload_l3_fwd_mark = 1;
 190        skb->offload_fwd_mark = 1;
 191        mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
 192}
 193
 194static void mlxsw_sp_rx_ptp_listener(struct sk_buff *skb, u16 local_port,
 195                                     void *trap_ctx)
 196{
 197        struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
 198        int err;
 199
 200        err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
 201        if (err)
 202                return;
 203
 204        /* The PTP handler expects skb->data to point to the start of the
 205         * Ethernet header.
 206         */
 207        skb_push(skb, ETH_HLEN);
 208        mlxsw_sp_ptp_receive(mlxsw_sp, skb, local_port);
 209}
 210
 211static struct mlxsw_sp_port *
 212mlxsw_sp_sample_tx_port_get(struct mlxsw_sp *mlxsw_sp,
 213                            const struct mlxsw_rx_md_info *rx_md_info)
 214{
 215        u16 local_port;
 216
 217        if (!rx_md_info->tx_port_valid)
 218                return NULL;
 219
 220        if (rx_md_info->tx_port_is_lag)
 221                local_port = mlxsw_core_lag_mapping_get(mlxsw_sp->core,
 222                                                        rx_md_info->tx_lag_id,
 223                                                        rx_md_info->tx_lag_port_index);
 224        else
 225                local_port = rx_md_info->tx_sys_port;
 226
 227        if (local_port >= mlxsw_core_max_ports(mlxsw_sp->core))
 228                return NULL;
 229
 230        return mlxsw_sp->ports[local_port];
 231}
 232
 233/* The latency units are determined according to MOGCR.mirror_latency_units. It
 234 * defaults to 64 nanoseconds.
 235 */
 236#define MLXSW_SP_MIRROR_LATENCY_SHIFT   6
 237
 238static void mlxsw_sp_psample_md_init(struct mlxsw_sp *mlxsw_sp,
 239                                     struct psample_metadata *md,
 240                                     struct sk_buff *skb, int in_ifindex,
 241                                     bool truncate, u32 trunc_size)
 242{
 243        struct mlxsw_rx_md_info *rx_md_info = &mlxsw_skb_cb(skb)->rx_md_info;
 244        struct mlxsw_sp_port *mlxsw_sp_port;
 245
 246        md->trunc_size = truncate ? trunc_size : skb->len;
 247        md->in_ifindex = in_ifindex;
 248        mlxsw_sp_port = mlxsw_sp_sample_tx_port_get(mlxsw_sp, rx_md_info);
 249        md->out_ifindex = mlxsw_sp_port && mlxsw_sp_port->dev ?
 250                          mlxsw_sp_port->dev->ifindex : 0;
 251        md->out_tc_valid = rx_md_info->tx_tc_valid;
 252        md->out_tc = rx_md_info->tx_tc;
 253        md->out_tc_occ_valid = rx_md_info->tx_congestion_valid;
 254        md->out_tc_occ = rx_md_info->tx_congestion;
 255        md->latency_valid = rx_md_info->latency_valid;
 256        md->latency = rx_md_info->latency;
 257        md->latency <<= MLXSW_SP_MIRROR_LATENCY_SHIFT;
 258}
 259
 260static void mlxsw_sp_rx_sample_listener(struct sk_buff *skb, u16 local_port,
 261                                        void *trap_ctx)
 262{
 263        struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
 264        struct mlxsw_sp_sample_trigger trigger;
 265        struct mlxsw_sp_sample_params *params;
 266        struct mlxsw_sp_port *mlxsw_sp_port;
 267        struct psample_metadata md = {};
 268        int err;
 269
 270        err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
 271        if (err)
 272                return;
 273
 274        mlxsw_sp_port = mlxsw_sp->ports[local_port];
 275        if (!mlxsw_sp_port)
 276                goto out;
 277
 278        trigger.type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_INGRESS;
 279        trigger.local_port = local_port;
 280        params = mlxsw_sp_sample_trigger_params_lookup(mlxsw_sp, &trigger);
 281        if (!params)
 282                goto out;
 283
 284        /* The psample module expects skb->data to point to the start of the
 285         * Ethernet header.
 286         */
 287        skb_push(skb, ETH_HLEN);
 288        mlxsw_sp_psample_md_init(mlxsw_sp, &md, skb,
 289                                 mlxsw_sp_port->dev->ifindex, params->truncate,
 290                                 params->trunc_size);
 291        psample_sample_packet(params->psample_group, skb, params->rate, &md);
 292out:
 293        consume_skb(skb);
 294}
 295
 296static void mlxsw_sp_rx_sample_tx_listener(struct sk_buff *skb, u16 local_port,
 297                                           void *trap_ctx)
 298{
 299        struct mlxsw_rx_md_info *rx_md_info = &mlxsw_skb_cb(skb)->rx_md_info;
 300        struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
 301        struct mlxsw_sp_port *mlxsw_sp_port, *mlxsw_sp_port_tx;
 302        struct mlxsw_sp_sample_trigger trigger;
 303        struct mlxsw_sp_sample_params *params;
 304        struct psample_metadata md = {};
 305        int err;
 306
 307        /* Locally generated packets are not reported from the policy engine
 308         * trigger, so do not report them from the egress trigger as well.
 309         */
 310        if (local_port == MLXSW_PORT_CPU_PORT)
 311                goto out;
 312
 313        err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
 314        if (err)
 315                return;
 316
 317        mlxsw_sp_port = mlxsw_sp->ports[local_port];
 318        if (!mlxsw_sp_port)
 319                goto out;
 320
 321        /* Packet was sampled from Tx, so we need to retrieve the sample
 322         * parameters based on the Tx port and not the Rx port.
 323         */
 324        mlxsw_sp_port_tx = mlxsw_sp_sample_tx_port_get(mlxsw_sp, rx_md_info);
 325        if (!mlxsw_sp_port_tx)
 326                goto out;
 327
 328        trigger.type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_EGRESS;
 329        trigger.local_port = mlxsw_sp_port_tx->local_port;
 330        params = mlxsw_sp_sample_trigger_params_lookup(mlxsw_sp, &trigger);
 331        if (!params)
 332                goto out;
 333
 334        /* The psample module expects skb->data to point to the start of the
 335         * Ethernet header.
 336         */
 337        skb_push(skb, ETH_HLEN);
 338        mlxsw_sp_psample_md_init(mlxsw_sp, &md, skb,
 339                                 mlxsw_sp_port->dev->ifindex, params->truncate,
 340                                 params->trunc_size);
 341        psample_sample_packet(params->psample_group, skb, params->rate, &md);
 342out:
 343        consume_skb(skb);
 344}
 345
 346static void mlxsw_sp_rx_sample_acl_listener(struct sk_buff *skb, u16 local_port,
 347                                            void *trap_ctx)
 348{
 349        struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
 350        struct mlxsw_sp_sample_trigger trigger = {
 351                .type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_POLICY_ENGINE,
 352        };
 353        struct mlxsw_sp_sample_params *params;
 354        struct mlxsw_sp_port *mlxsw_sp_port;
 355        struct psample_metadata md = {};
 356        int err;
 357
 358        err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
 359        if (err)
 360                return;
 361
 362        mlxsw_sp_port = mlxsw_sp->ports[local_port];
 363        if (!mlxsw_sp_port)
 364                goto out;
 365
 366        params = mlxsw_sp_sample_trigger_params_lookup(mlxsw_sp, &trigger);
 367        if (!params)
 368                goto out;
 369
 370        /* The psample module expects skb->data to point to the start of the
 371         * Ethernet header.
 372         */
 373        skb_push(skb, ETH_HLEN);
 374        mlxsw_sp_psample_md_init(mlxsw_sp, &md, skb,
 375                                 mlxsw_sp_port->dev->ifindex, params->truncate,
 376                                 params->trunc_size);
 377        psample_sample_packet(params->psample_group, skb, params->rate, &md);
 378out:
 379        consume_skb(skb);
 380}
 381
 382#define MLXSW_SP_TRAP_DROP(_id, _group_id)                                    \
 383        DEVLINK_TRAP_GENERIC(DROP, DROP, _id,                                 \
 384                             DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,       \
 385                             MLXSW_SP_TRAP_METADATA)
 386
 387#define MLXSW_SP_TRAP_DROP_EXT(_id, _group_id, _metadata)                     \
 388        DEVLINK_TRAP_GENERIC(DROP, DROP, _id,                                 \
 389                             DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,       \
 390                             MLXSW_SP_TRAP_METADATA | (_metadata))
 391
 392#define MLXSW_SP_TRAP_BUFFER_DROP(_id)                                        \
 393        DEVLINK_TRAP_GENERIC(DROP, TRAP, _id,                                 \
 394                             DEVLINK_TRAP_GROUP_GENERIC_ID_BUFFER_DROPS,      \
 395                             MLXSW_SP_TRAP_METADATA)
 396
 397#define MLXSW_SP_TRAP_DRIVER_DROP(_id, _group_id)                             \
 398        DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_MLXSW_TRAP_ID_##_id,          \
 399                            DEVLINK_MLXSW_TRAP_NAME_##_id,                    \
 400                            DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,        \
 401                            MLXSW_SP_TRAP_METADATA)
 402
 403#define MLXSW_SP_TRAP_EXCEPTION(_id, _group_id)               \
 404        DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id,                            \
 405                             DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,       \
 406                             MLXSW_SP_TRAP_METADATA)
 407
 408#define MLXSW_SP_TRAP_CONTROL(_id, _group_id, _action)                        \
 409        DEVLINK_TRAP_GENERIC(CONTROL, _action, _id,                           \
 410                             DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,       \
 411                             MLXSW_SP_TRAP_METADATA)
 412
 413#define MLXSW_SP_RXL_DISCARD(_id, _group_id)                                  \
 414        MLXSW_RXL_DIS(mlxsw_sp_rx_drop_listener, DISCARD_##_id,               \
 415                      TRAP_EXCEPTION_TO_CPU, false, SP_##_group_id,           \
 416                      SET_FW_DEFAULT, SP_##_group_id)
 417
 418#define MLXSW_SP_RXL_ACL_DISCARD(_id, _en_group_id, _dis_group_id)            \
 419        MLXSW_RXL_DIS(mlxsw_sp_rx_acl_drop_listener, DISCARD_##_id,           \
 420                      TRAP_EXCEPTION_TO_CPU, false, SP_##_en_group_id,        \
 421                      SET_FW_DEFAULT, SP_##_dis_group_id)
 422
 423#define MLXSW_SP_RXL_BUFFER_DISCARD(_mirror_reason)                           \
 424        MLXSW_RXL_MIRROR(mlxsw_sp_rx_drop_listener, 0, SP_BUFFER_DISCARDS,    \
 425                         MLXSW_SP_MIRROR_REASON_##_mirror_reason)
 426
 427#define MLXSW_SP_RXL_EXCEPTION(_id, _group_id, _action)                       \
 428        MLXSW_RXL(mlxsw_sp_rx_mark_listener, _id,                             \
 429                   _action, false, SP_##_group_id, SET_FW_DEFAULT)
 430
 431#define MLXSW_SP_RXL_NO_MARK(_id, _group_id, _action, _is_ctrl)               \
 432        MLXSW_RXL(mlxsw_sp_rx_no_mark_listener, _id, _action,                 \
 433                  _is_ctrl, SP_##_group_id, DISCARD)
 434
 435#define MLXSW_SP_RXL_MARK(_id, _group_id, _action, _is_ctrl)                  \
 436        MLXSW_RXL(mlxsw_sp_rx_mark_listener, _id, _action, _is_ctrl,          \
 437                  SP_##_group_id, DISCARD)
 438
 439#define MLXSW_SP_RXL_L3_MARK(_id, _group_id, _action, _is_ctrl)               \
 440        MLXSW_RXL(mlxsw_sp_rx_l3_mark_listener, _id, _action, _is_ctrl,       \
 441                  SP_##_group_id, DISCARD)
 442
 443#define MLXSW_SP_TRAP_POLICER(_id, _rate, _burst)                             \
 444        DEVLINK_TRAP_POLICER(_id, _rate, _burst,                              \
 445                             MLXSW_REG_QPCR_HIGHEST_CIR,                      \
 446                             MLXSW_REG_QPCR_LOWEST_CIR,                       \
 447                             1 << MLXSW_REG_QPCR_HIGHEST_CBS,                 \
 448                             1 << MLXSW_REG_QPCR_LOWEST_CBS)
 449
 450/* Ordered by policer identifier */
 451static const struct mlxsw_sp_trap_policer_item
 452mlxsw_sp_trap_policer_items_arr[] = {
 453        {
 454                .policer = MLXSW_SP_TRAP_POLICER(1, 10 * 1024, 4096),
 455        },
 456        {
 457                .policer = MLXSW_SP_TRAP_POLICER(2, 128, 128),
 458        },
 459        {
 460                .policer = MLXSW_SP_TRAP_POLICER(3, 128, 128),
 461        },
 462        {
 463                .policer = MLXSW_SP_TRAP_POLICER(4, 128, 128),
 464        },
 465        {
 466                .policer = MLXSW_SP_TRAP_POLICER(5, 16 * 1024, 8192),
 467        },
 468        {
 469                .policer = MLXSW_SP_TRAP_POLICER(6, 128, 128),
 470        },
 471        {
 472                .policer = MLXSW_SP_TRAP_POLICER(7, 1024, 512),
 473        },
 474        {
 475                .policer = MLXSW_SP_TRAP_POLICER(8, 20 * 1024, 8192),
 476        },
 477        {
 478                .policer = MLXSW_SP_TRAP_POLICER(9, 128, 128),
 479        },
 480        {
 481                .policer = MLXSW_SP_TRAP_POLICER(10, 1024, 512),
 482        },
 483        {
 484                .policer = MLXSW_SP_TRAP_POLICER(11, 256, 128),
 485        },
 486        {
 487                .policer = MLXSW_SP_TRAP_POLICER(12, 128, 128),
 488        },
 489        {
 490                .policer = MLXSW_SP_TRAP_POLICER(13, 128, 128),
 491        },
 492        {
 493                .policer = MLXSW_SP_TRAP_POLICER(14, 1024, 512),
 494        },
 495        {
 496                .policer = MLXSW_SP_TRAP_POLICER(15, 1024, 512),
 497        },
 498        {
 499                .policer = MLXSW_SP_TRAP_POLICER(16, 24 * 1024, 16384),
 500        },
 501        {
 502                .policer = MLXSW_SP_TRAP_POLICER(17, 19 * 1024, 8192),
 503        },
 504        {
 505                .policer = MLXSW_SP_TRAP_POLICER(18, 1024, 512),
 506        },
 507        {
 508                .policer = MLXSW_SP_TRAP_POLICER(19, 1024, 512),
 509        },
 510        {
 511                .policer = MLXSW_SP_TRAP_POLICER(20, 10240, 4096),
 512        },
 513};
 514
 515static const struct mlxsw_sp_trap_group_item mlxsw_sp_trap_group_items_arr[] = {
 516        {
 517                .group = DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 1),
 518                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS,
 519                .priority = 0,
 520        },
 521        {
 522                .group = DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1),
 523                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS,
 524                .priority = 0,
 525        },
 526        {
 527                .group = DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 1),
 528                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_EXCEPTIONS,
 529                .priority = 2,
 530        },
 531        {
 532                .group = DEVLINK_TRAP_GROUP_GENERIC(TUNNEL_DROPS, 1),
 533                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS,
 534                .priority = 0,
 535        },
 536        {
 537                .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 1),
 538                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS,
 539                .priority = 0,
 540        },
 541        {
 542                .group = DEVLINK_TRAP_GROUP_GENERIC(STP, 2),
 543                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_STP,
 544                .priority = 5,
 545        },
 546        {
 547                .group = DEVLINK_TRAP_GROUP_GENERIC(LACP, 3),
 548                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LACP,
 549                .priority = 5,
 550        },
 551        {
 552                .group = DEVLINK_TRAP_GROUP_GENERIC(LLDP, 4),
 553                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP,
 554                .priority = 5,
 555        },
 556        {
 557                .group = DEVLINK_TRAP_GROUP_GENERIC(MC_SNOOPING, 5),
 558                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_MC_SNOOPING,
 559                .priority = 3,
 560        },
 561        {
 562                .group = DEVLINK_TRAP_GROUP_GENERIC(DHCP, 6),
 563                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_DHCP,
 564                .priority = 2,
 565        },
 566        {
 567                .group = DEVLINK_TRAP_GROUP_GENERIC(NEIGH_DISCOVERY, 7),
 568                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_NEIGH_DISCOVERY,
 569                .priority = 2,
 570        },
 571        {
 572                .group = DEVLINK_TRAP_GROUP_GENERIC(BFD, 8),
 573                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BFD,
 574                .priority = 5,
 575        },
 576        {
 577                .group = DEVLINK_TRAP_GROUP_GENERIC(OSPF, 9),
 578                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_OSPF,
 579                .priority = 5,
 580        },
 581        {
 582                .group = DEVLINK_TRAP_GROUP_GENERIC(BGP, 10),
 583                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BGP,
 584                .priority = 4,
 585        },
 586        {
 587                .group = DEVLINK_TRAP_GROUP_GENERIC(VRRP, 11),
 588                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_VRRP,
 589                .priority = 5,
 590        },
 591        {
 592                .group = DEVLINK_TRAP_GROUP_GENERIC(PIM, 12),
 593                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PIM,
 594                .priority = 5,
 595        },
 596        {
 597                .group = DEVLINK_TRAP_GROUP_GENERIC(UC_LB, 13),
 598                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LBERROR,
 599                .priority = 0,
 600        },
 601        {
 602                .group = DEVLINK_TRAP_GROUP_GENERIC(LOCAL_DELIVERY, 14),
 603                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME,
 604                .priority = 2,
 605        },
 606        {
 607                .group = DEVLINK_TRAP_GROUP_GENERIC(EXTERNAL_DELIVERY, 19),
 608                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_EXTERNAL_ROUTE,
 609                .priority = 1,
 610        },
 611        {
 612                .group = DEVLINK_TRAP_GROUP_GENERIC(IPV6, 15),
 613                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6,
 614                .priority = 2,
 615        },
 616        {
 617                .group = DEVLINK_TRAP_GROUP_GENERIC(PTP_EVENT, 16),
 618                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0,
 619                .priority = 5,
 620        },
 621        {
 622                .group = DEVLINK_TRAP_GROUP_GENERIC(PTP_GENERAL, 17),
 623                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1,
 624                .priority = 2,
 625        },
 626        {
 627                .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_TRAP, 18),
 628                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_FLOW_LOGGING,
 629                .priority = 4,
 630        },
 631};
 632
 633static const struct mlxsw_sp_trap_item mlxsw_sp_trap_items_arr[] = {
 634        {
 635                .trap = MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS),
 636                .listeners_arr = {
 637                        MLXSW_SP_RXL_DISCARD(ING_PACKET_SMAC_MC, L2_DISCARDS),
 638                },
 639        },
 640        {
 641                .trap = MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS),
 642                .listeners_arr = {
 643                        MLXSW_SP_RXL_DISCARD(ING_SWITCH_VTAG_ALLOW,
 644                                             L2_DISCARDS),
 645                },
 646        },
 647        {
 648                .trap = MLXSW_SP_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS),
 649                .listeners_arr = {
 650                        MLXSW_SP_RXL_DISCARD(ING_SWITCH_VLAN, L2_DISCARDS),
 651                },
 652        },
 653        {
 654                .trap = MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS),
 655                .listeners_arr = {
 656                        MLXSW_SP_RXL_DISCARD(ING_SWITCH_STP, L2_DISCARDS),
 657                },
 658        },
 659        {
 660                .trap = MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS),
 661                .listeners_arr = {
 662                        MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS),
 663                        MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS),
 664                },
 665        },
 666        {
 667                .trap = MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS),
 668                .listeners_arr = {
 669                        MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS),
 670                },
 671        },
 672        {
 673                .trap = MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS),
 674                .listeners_arr = {
 675                        MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS),
 676                },
 677        },
 678        {
 679                .trap = MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS),
 680                .listeners_arr = {
 681                        MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET,
 682                                             L3_DISCARDS),
 683                },
 684        },
 685        {
 686                .trap = MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS),
 687                .listeners_arr = {
 688                        MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC,
 689                                             L3_DISCARDS),
 690                },
 691        },
 692        {
 693                .trap = MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS),
 694                .listeners_arr = {
 695                        MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS),
 696                },
 697        },
 698        {
 699                .trap = MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS),
 700                .listeners_arr = {
 701                        MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS),
 702                },
 703        },
 704        {
 705                .trap = MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS),
 706                .listeners_arr = {
 707                        MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS),
 708                },
 709        },
 710        {
 711                .trap = MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS),
 712                .listeners_arr = {
 713                        MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR,
 714                                             L3_DISCARDS),
 715                },
 716        },
 717        {
 718                .trap = MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS),
 719                .listeners_arr = {
 720                        MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC,
 721                                             L3_DISCARDS),
 722                },
 723        },
 724        {
 725                .trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE,
 726                                           L3_DROPS),
 727                .listeners_arr = {
 728                        MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE,
 729                                             L3_DISCARDS),
 730                },
 731        },
 732        {
 733                .trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE,
 734                                           L3_DROPS),
 735                .listeners_arr = {
 736                        MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE,
 737                                             L3_DISCARDS),
 738                },
 739        },
 740        {
 741                .trap = MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_EXCEPTIONS),
 742                .listeners_arr = {
 743                        MLXSW_SP_RXL_EXCEPTION(MTUERROR, L3_EXCEPTIONS,
 744                                               TRAP_TO_CPU),
 745                },
 746        },
 747        {
 748                .trap = MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS),
 749                .listeners_arr = {
 750                        MLXSW_SP_RXL_EXCEPTION(TTLERROR, L3_EXCEPTIONS,
 751                                               TRAP_TO_CPU),
 752                },
 753        },
 754        {
 755                .trap = MLXSW_SP_TRAP_EXCEPTION(RPF, L3_EXCEPTIONS),
 756                .listeners_arr = {
 757                        MLXSW_SP_RXL_EXCEPTION(RPF, L3_EXCEPTIONS, TRAP_TO_CPU),
 758                },
 759        },
 760        {
 761                .trap = MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_EXCEPTIONS),
 762                .listeners_arr = {
 763                        MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, L3_EXCEPTIONS,
 764                                               TRAP_TO_CPU),
 765                },
 766        },
 767        {
 768                .trap = MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH,
 769                                                L3_EXCEPTIONS),
 770                .listeners_arr = {
 771                        MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, L3_EXCEPTIONS,
 772                                               TRAP_TO_CPU),
 773                        MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, L3_EXCEPTIONS,
 774                                               TRAP_TO_CPU),
 775                        MLXSW_SP_RXL_EXCEPTION(RTR_EGRESS0, L3_EXCEPTIONS,
 776                                               TRAP_EXCEPTION_TO_CPU),
 777                },
 778        },
 779        {
 780                .trap = MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS,
 781                                                L3_EXCEPTIONS),
 782                .listeners_arr = {
 783                        MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4,
 784                                               L3_EXCEPTIONS,
 785                                               TRAP_EXCEPTION_TO_CPU),
 786                },
 787        },
 788        {
 789                .trap = MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS,
 790                                                L3_EXCEPTIONS),
 791                .listeners_arr = {
 792                        MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6,
 793                                               L3_EXCEPTIONS,
 794                                               TRAP_EXCEPTION_TO_CPU),
 795                },
 796        },
 797        {
 798                .trap = MLXSW_SP_TRAP_DRIVER_DROP(IRIF_DISABLED, L3_DROPS),
 799                .listeners_arr = {
 800                        MLXSW_SP_RXL_DISCARD(ROUTER_IRIF_EN, L3_DISCARDS),
 801                },
 802        },
 803        {
 804                .trap = MLXSW_SP_TRAP_DRIVER_DROP(ERIF_DISABLED, L3_DROPS),
 805                .listeners_arr = {
 806                        MLXSW_SP_RXL_DISCARD(ROUTER_ERIF_EN, L3_DISCARDS),
 807                },
 808        },
 809        {
 810                .trap = MLXSW_SP_TRAP_DROP(NON_ROUTABLE, L3_DROPS),
 811                .listeners_arr = {
 812                        MLXSW_SP_RXL_DISCARD(NON_ROUTABLE, L3_DISCARDS),
 813                },
 814        },
 815        {
 816                .trap = MLXSW_SP_TRAP_EXCEPTION(DECAP_ERROR, TUNNEL_DROPS),
 817                .listeners_arr = {
 818                        MLXSW_SP_RXL_EXCEPTION(DECAP_ECN0, TUNNEL_DISCARDS,
 819                                               TRAP_EXCEPTION_TO_CPU),
 820                        MLXSW_SP_RXL_EXCEPTION(IPIP_DECAP_ERROR,
 821                                               TUNNEL_DISCARDS,
 822                                               TRAP_EXCEPTION_TO_CPU),
 823                        MLXSW_SP_RXL_EXCEPTION(DISCARD_DEC_PKT, TUNNEL_DISCARDS,
 824                                               TRAP_EXCEPTION_TO_CPU),
 825                },
 826        },
 827        {
 828                .trap = MLXSW_SP_TRAP_DROP(OVERLAY_SMAC_MC, TUNNEL_DROPS),
 829                .listeners_arr = {
 830                        MLXSW_SP_RXL_DISCARD(OVERLAY_SMAC_MC, TUNNEL_DISCARDS),
 831                },
 832        },
 833        {
 834                .trap = MLXSW_SP_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP,
 835                                               ACL_DROPS,
 836                                               DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),
 837                .listeners_arr = {
 838                        MLXSW_SP_RXL_ACL_DISCARD(INGRESS_ACL, ACL_DISCARDS,
 839                                                 DUMMY),
 840                },
 841        },
 842        {
 843                .trap = MLXSW_SP_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP,
 844                                               ACL_DROPS,
 845                                               DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),
 846                .listeners_arr = {
 847                        MLXSW_SP_RXL_ACL_DISCARD(EGRESS_ACL, ACL_DISCARDS,
 848                                                 DUMMY),
 849                },
 850        },
 851        {
 852                .trap = MLXSW_SP_TRAP_CONTROL(STP, STP, TRAP),
 853                .listeners_arr = {
 854                        MLXSW_SP_RXL_NO_MARK(STP, STP, TRAP_TO_CPU, true),
 855                },
 856        },
 857        {
 858                .trap = MLXSW_SP_TRAP_CONTROL(LACP, LACP, TRAP),
 859                .listeners_arr = {
 860                        MLXSW_SP_RXL_NO_MARK(LACP, LACP, TRAP_TO_CPU, true),
 861                },
 862        },
 863        {
 864                .trap = MLXSW_SP_TRAP_CONTROL(LLDP, LLDP, TRAP),
 865                .listeners_arr = {
 866                        MLXSW_RXL(mlxsw_sp_rx_ptp_listener, LLDP, TRAP_TO_CPU,
 867                                  false, SP_LLDP, DISCARD),
 868                },
 869        },
 870        {
 871                .trap = MLXSW_SP_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR),
 872                .listeners_arr = {
 873                        MLXSW_SP_RXL_MARK(IGMP_QUERY, MC_SNOOPING,
 874                                          MIRROR_TO_CPU, false),
 875                },
 876        },
 877        {
 878                .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING,
 879                                              TRAP),
 880                .listeners_arr = {
 881                        MLXSW_SP_RXL_NO_MARK(IGMP_V1_REPORT, MC_SNOOPING,
 882                                             TRAP_TO_CPU, false),
 883                },
 884        },
 885        {
 886                .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_REPORT, MC_SNOOPING,
 887                                              TRAP),
 888                .listeners_arr = {
 889                        MLXSW_SP_RXL_NO_MARK(IGMP_V2_REPORT, MC_SNOOPING,
 890                                             TRAP_TO_CPU, false),
 891                },
 892        },
 893        {
 894                .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V3_REPORT, MC_SNOOPING,
 895                                              TRAP),
 896                .listeners_arr = {
 897                        MLXSW_SP_RXL_NO_MARK(IGMP_V3_REPORT, MC_SNOOPING,
 898                                             TRAP_TO_CPU, false),
 899                },
 900        },
 901        {
 902                .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_LEAVE, MC_SNOOPING,
 903                                              TRAP),
 904                .listeners_arr = {
 905                        MLXSW_SP_RXL_NO_MARK(IGMP_V2_LEAVE, MC_SNOOPING,
 906                                             TRAP_TO_CPU, false),
 907                },
 908        },
 909        {
 910                .trap = MLXSW_SP_TRAP_CONTROL(MLD_QUERY, MC_SNOOPING, MIRROR),
 911                .listeners_arr = {
 912                        MLXSW_SP_RXL_MARK(IPV6_MLDV12_LISTENER_QUERY,
 913                                          MC_SNOOPING, MIRROR_TO_CPU, false),
 914                },
 915        },
 916        {
 917                .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_REPORT, MC_SNOOPING,
 918                                              TRAP),
 919                .listeners_arr = {
 920                        MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_REPORT,
 921                                             MC_SNOOPING, TRAP_TO_CPU, false),
 922                },
 923        },
 924        {
 925                .trap = MLXSW_SP_TRAP_CONTROL(MLD_V2_REPORT, MC_SNOOPING,
 926                                              TRAP),
 927                .listeners_arr = {
 928                        MLXSW_SP_RXL_NO_MARK(IPV6_MLDV2_LISTENER_REPORT,
 929                                             MC_SNOOPING, TRAP_TO_CPU, false),
 930                },
 931        },
 932        {
 933                .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_DONE, MC_SNOOPING,
 934                                              TRAP),
 935                .listeners_arr = {
 936                        MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_DONE,
 937                                             MC_SNOOPING, TRAP_TO_CPU, false),
 938                },
 939        },
 940        {
 941                .trap = MLXSW_SP_TRAP_CONTROL(IPV4_DHCP, DHCP, TRAP),
 942                .listeners_arr = {
 943                        MLXSW_SP_RXL_MARK(IPV4_DHCP, DHCP, TRAP_TO_CPU, false),
 944                },
 945        },
 946        {
 947                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DHCP, DHCP, TRAP),
 948                .listeners_arr = {
 949                        MLXSW_SP_RXL_MARK(IPV6_DHCP, DHCP, TRAP_TO_CPU, false),
 950                },
 951        },
 952        {
 953                .trap = MLXSW_SP_TRAP_CONTROL(ARP_REQUEST, NEIGH_DISCOVERY,
 954                                              MIRROR),
 955                .listeners_arr = {
 956                        MLXSW_SP_RXL_MARK(ARPBC, NEIGH_DISCOVERY, MIRROR_TO_CPU,
 957                                          false),
 958                },
 959        },
 960        {
 961                .trap = MLXSW_SP_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY,
 962                                              MIRROR),
 963                .listeners_arr = {
 964                        MLXSW_SP_RXL_MARK(ARPUC, NEIGH_DISCOVERY, MIRROR_TO_CPU,
 965                                          false),
 966                },
 967        },
 968        {
 969                .trap = MLXSW_SP_TRAP_CONTROL(ARP_OVERLAY, NEIGH_DISCOVERY,
 970                                              TRAP),
 971                .listeners_arr = {
 972                        MLXSW_SP_RXL_NO_MARK(NVE_DECAP_ARP, NEIGH_DISCOVERY,
 973                                             TRAP_TO_CPU, false),
 974                },
 975        },
 976        {
 977                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_SOLICIT,
 978                                              NEIGH_DISCOVERY, TRAP),
 979                .listeners_arr = {
 980                        MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_SOLICITATION,
 981                                          NEIGH_DISCOVERY, TRAP_TO_CPU, false),
 982                },
 983        },
 984        {
 985                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_ADVERT,
 986                                              NEIGH_DISCOVERY, TRAP),
 987                .listeners_arr = {
 988                        MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_ADVERTISEMENT,
 989                                          NEIGH_DISCOVERY, TRAP_TO_CPU, false),
 990                },
 991        },
 992        {
 993                .trap = MLXSW_SP_TRAP_CONTROL(IPV4_BFD, BFD, TRAP),
 994                .listeners_arr = {
 995                        MLXSW_SP_RXL_MARK(IPV4_BFD, BFD, TRAP_TO_CPU, false),
 996                },
 997        },
 998        {
 999                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_BFD, BFD, TRAP),
1000                .listeners_arr = {
1001                        MLXSW_SP_RXL_MARK(IPV6_BFD, BFD, TRAP_TO_CPU, false),
1002                },
1003        },
1004        {
1005                .trap = MLXSW_SP_TRAP_CONTROL(IPV4_OSPF, OSPF, TRAP),
1006                .listeners_arr = {
1007                        MLXSW_SP_RXL_MARK(IPV4_OSPF, OSPF, TRAP_TO_CPU, false),
1008                },
1009        },
1010        {
1011                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_OSPF, OSPF, TRAP),
1012                .listeners_arr = {
1013                        MLXSW_SP_RXL_MARK(IPV6_OSPF, OSPF, TRAP_TO_CPU, false),
1014                },
1015        },
1016        {
1017                .trap = MLXSW_SP_TRAP_CONTROL(IPV4_BGP, BGP, TRAP),
1018                .listeners_arr = {
1019                        MLXSW_SP_RXL_MARK(IPV4_BGP, BGP, TRAP_TO_CPU, false),
1020                },
1021        },
1022        {
1023                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_BGP, BGP, TRAP),
1024                .listeners_arr = {
1025                        MLXSW_SP_RXL_MARK(IPV6_BGP, BGP, TRAP_TO_CPU, false),
1026                },
1027        },
1028        {
1029                .trap = MLXSW_SP_TRAP_CONTROL(IPV4_VRRP, VRRP, TRAP),
1030                .listeners_arr = {
1031                        MLXSW_SP_RXL_MARK(IPV4_VRRP, VRRP, TRAP_TO_CPU, false),
1032                },
1033        },
1034        {
1035                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_VRRP, VRRP, TRAP),
1036                .listeners_arr = {
1037                        MLXSW_SP_RXL_MARK(IPV6_VRRP, VRRP, TRAP_TO_CPU, false),
1038                },
1039        },
1040        {
1041                .trap = MLXSW_SP_TRAP_CONTROL(IPV4_PIM, PIM, TRAP),
1042                .listeners_arr = {
1043                        MLXSW_SP_RXL_MARK(IPV4_PIM, PIM, TRAP_TO_CPU, false),
1044                },
1045        },
1046        {
1047                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_PIM, PIM, TRAP),
1048                .listeners_arr = {
1049                        MLXSW_SP_RXL_MARK(IPV6_PIM, PIM, TRAP_TO_CPU, false),
1050                },
1051        },
1052        {
1053                .trap = MLXSW_SP_TRAP_CONTROL(UC_LB, UC_LB, MIRROR),
1054                .listeners_arr = {
1055                        MLXSW_SP_RXL_L3_MARK(LBERROR, LBERROR, MIRROR_TO_CPU,
1056                                             false),
1057                },
1058        },
1059        {
1060                .trap = MLXSW_SP_TRAP_CONTROL(LOCAL_ROUTE, LOCAL_DELIVERY,
1061                                              TRAP),
1062                .listeners_arr = {
1063                        MLXSW_SP_RXL_MARK(IP2ME, IP2ME, TRAP_TO_CPU, false),
1064                },
1065        },
1066        {
1067                .trap = MLXSW_SP_TRAP_CONTROL(EXTERNAL_ROUTE, EXTERNAL_DELIVERY,
1068                                              TRAP),
1069                .listeners_arr = {
1070                        MLXSW_SP_RXL_MARK(RTR_INGRESS0, EXTERNAL_ROUTE,
1071                                          TRAP_TO_CPU, false),
1072                },
1073        },
1074        {
1075                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_UC_DIP_LINK_LOCAL_SCOPE,
1076                                              LOCAL_DELIVERY, TRAP),
1077                .listeners_arr = {
1078                        MLXSW_SP_RXL_MARK(IPV6_LINK_LOCAL_DEST, IP2ME,
1079                                          TRAP_TO_CPU, false),
1080                },
1081        },
1082        {
1083                .trap = MLXSW_SP_TRAP_CONTROL(IPV4_ROUTER_ALERT, LOCAL_DELIVERY,
1084                                              TRAP),
1085                .listeners_arr = {
1086                        MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV4, IP2ME, TRAP_TO_CPU,
1087                                          false),
1088                },
1089        },
1090        {
1091                /* IPV6_ROUTER_ALERT is defined in uAPI as 22, but it is not
1092                 * used in this file, so undefine it.
1093                 */
1094                #undef IPV6_ROUTER_ALERT
1095                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_ALERT, LOCAL_DELIVERY,
1096                                              TRAP),
1097                .listeners_arr = {
1098                        MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, IP2ME, TRAP_TO_CPU,
1099                                          false),
1100                },
1101        },
1102        {
1103                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DIP_ALL_NODES, IPV6, TRAP),
1104                .listeners_arr = {
1105                        MLXSW_SP_RXL_MARK(IPV6_ALL_NODES_LINK, IPV6,
1106                                          TRAP_TO_CPU, false),
1107                },
1108        },
1109        {
1110                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DIP_ALL_ROUTERS, IPV6, TRAP),
1111                .listeners_arr = {
1112                        MLXSW_SP_RXL_MARK(IPV6_ALL_ROUTERS_LINK, IPV6,
1113                                          TRAP_TO_CPU, false),
1114                },
1115        },
1116        {
1117                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_SOLICIT, IPV6, TRAP),
1118                .listeners_arr = {
1119                        MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_SOLICITATION, IPV6,
1120                                          TRAP_TO_CPU, false),
1121                },
1122        },
1123        {
1124                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_ADVERT, IPV6, TRAP),
1125                .listeners_arr = {
1126                        MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_ADVERTISEMENT, IPV6,
1127                                          TRAP_TO_CPU, false),
1128                },
1129        },
1130        {
1131                .trap = MLXSW_SP_TRAP_CONTROL(IPV6_REDIRECT, IPV6, TRAP),
1132                .listeners_arr = {
1133                        MLXSW_SP_RXL_MARK(L3_IPV6_REDIRECTION, IPV6,
1134                                          TRAP_TO_CPU, false),
1135                },
1136        },
1137        {
1138                .trap = MLXSW_SP_TRAP_CONTROL(PTP_EVENT, PTP_EVENT, TRAP),
1139                .listeners_arr = {
1140                        MLXSW_RXL(mlxsw_sp_rx_ptp_listener, PTP0, TRAP_TO_CPU,
1141                                  false, SP_PTP0, DISCARD),
1142                },
1143        },
1144        {
1145                .trap = MLXSW_SP_TRAP_CONTROL(PTP_GENERAL, PTP_GENERAL, TRAP),
1146                .listeners_arr = {
1147                        MLXSW_SP_RXL_NO_MARK(PTP1, PTP1, TRAP_TO_CPU, false),
1148                },
1149        },
1150        {
1151                .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_TRAP, ACL_TRAP, TRAP),
1152                .listeners_arr = {
1153                        MLXSW_SP_RXL_NO_MARK(ACL0, FLOW_LOGGING, TRAP_TO_CPU,
1154                                             false),
1155                },
1156        },
1157        {
1158                .trap = MLXSW_SP_TRAP_DROP(BLACKHOLE_NEXTHOP, L3_DROPS),
1159                .listeners_arr = {
1160                        MLXSW_SP_RXL_DISCARD(ROUTER3, L3_DISCARDS),
1161                },
1162        },
1163};
1164
1165static struct mlxsw_sp_trap_policer_item *
1166mlxsw_sp_trap_policer_item_lookup(struct mlxsw_sp *mlxsw_sp, u32 id)
1167{
1168        struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1169        int i;
1170
1171        for (i = 0; i < trap->policers_count; i++) {
1172                if (trap->policer_items_arr[i].policer.id == id)
1173                        return &trap->policer_items_arr[i];
1174        }
1175
1176        return NULL;
1177}
1178
1179static struct mlxsw_sp_trap_group_item *
1180mlxsw_sp_trap_group_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id)
1181{
1182        struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1183        int i;
1184
1185        for (i = 0; i < trap->groups_count; i++) {
1186                if (trap->group_items_arr[i].group.id == id)
1187                        return &trap->group_items_arr[i];
1188        }
1189
1190        return NULL;
1191}
1192
1193static struct mlxsw_sp_trap_item *
1194mlxsw_sp_trap_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id)
1195{
1196        struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1197        int i;
1198
1199        for (i = 0; i < trap->traps_count; i++) {
1200                if (trap->trap_items_arr[i].trap.id == id)
1201                        return &trap->trap_items_arr[i];
1202        }
1203
1204        return NULL;
1205}
1206
1207static int mlxsw_sp_trap_cpu_policers_set(struct mlxsw_sp *mlxsw_sp)
1208{
1209        struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1210        char qpcr_pl[MLXSW_REG_QPCR_LEN];
1211        u16 hw_id;
1212
1213        /* The purpose of "thin" policer is to drop as many packets
1214         * as possible. The dummy group is using it.
1215         */
1216        hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers);
1217        if (WARN_ON(hw_id == trap->max_policers))
1218                return -ENOBUFS;
1219
1220        __set_bit(hw_id, trap->policers_usage);
1221        trap->thin_policer_hw_id = hw_id;
1222        mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M,
1223                            false, 1, 4);
1224        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
1225}
1226
1227static int mlxsw_sp_trap_dummy_group_init(struct mlxsw_sp *mlxsw_sp)
1228{
1229        char htgt_pl[MLXSW_REG_HTGT_LEN];
1230
1231        mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SP_DUMMY,
1232                            mlxsw_sp->trap->thin_policer_hw_id, 0, 1);
1233        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl);
1234}
1235
1236static int mlxsw_sp_trap_policer_items_arr_init(struct mlxsw_sp *mlxsw_sp)
1237{
1238        size_t arr_size = ARRAY_SIZE(mlxsw_sp_trap_policer_items_arr);
1239        size_t elem_size = sizeof(struct mlxsw_sp_trap_policer_item);
1240        struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1241        size_t free_policers = 0;
1242        u32 last_id;
1243        int i;
1244
1245        for_each_clear_bit(i, trap->policers_usage, trap->max_policers)
1246                free_policers++;
1247
1248        if (arr_size > free_policers) {
1249                dev_err(mlxsw_sp->bus_info->dev, "Exceeded number of supported packet trap policers\n");
1250                return -ENOBUFS;
1251        }
1252
1253        trap->policer_items_arr = kcalloc(free_policers, elem_size, GFP_KERNEL);
1254        if (!trap->policer_items_arr)
1255                return -ENOMEM;
1256
1257        trap->policers_count = free_policers;
1258
1259        /* Initialize policer items array with pre-defined policers. */
1260        memcpy(trap->policer_items_arr, mlxsw_sp_trap_policer_items_arr,
1261               elem_size * arr_size);
1262
1263        /* Initialize policer items array with the rest of the available
1264         * policers.
1265         */
1266        last_id = mlxsw_sp_trap_policer_items_arr[arr_size - 1].policer.id;
1267        for (i = arr_size; i < trap->policers_count; i++) {
1268                const struct mlxsw_sp_trap_policer_item *policer_item;
1269
1270                /* Use parameters set for first policer and override
1271                 * relevant ones.
1272                 */
1273                policer_item = &mlxsw_sp_trap_policer_items_arr[0];
1274                trap->policer_items_arr[i] = *policer_item;
1275                trap->policer_items_arr[i].policer.id = ++last_id;
1276                trap->policer_items_arr[i].policer.init_rate = 1;
1277                trap->policer_items_arr[i].policer.init_burst = 16;
1278        }
1279
1280        return 0;
1281}
1282
1283static void mlxsw_sp_trap_policer_items_arr_fini(struct mlxsw_sp *mlxsw_sp)
1284{
1285        kfree(mlxsw_sp->trap->policer_items_arr);
1286}
1287
1288static int mlxsw_sp_trap_policers_init(struct mlxsw_sp *mlxsw_sp)
1289{
1290        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1291        const struct mlxsw_sp_trap_policer_item *policer_item;
1292        struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1293        int err, i;
1294
1295        err = mlxsw_sp_trap_policer_items_arr_init(mlxsw_sp);
1296        if (err)
1297                return err;
1298
1299        for (i = 0; i < trap->policers_count; i++) {
1300                policer_item = &trap->policer_items_arr[i];
1301                err = devlink_trap_policers_register(devlink,
1302                                                     &policer_item->policer, 1);
1303                if (err)
1304                        goto err_trap_policer_register;
1305        }
1306
1307        return 0;
1308
1309err_trap_policer_register:
1310        for (i--; i >= 0; i--) {
1311                policer_item = &trap->policer_items_arr[i];
1312                devlink_trap_policers_unregister(devlink,
1313                                                 &policer_item->policer, 1);
1314        }
1315        mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp);
1316        return err;
1317}
1318
1319static void mlxsw_sp_trap_policers_fini(struct mlxsw_sp *mlxsw_sp)
1320{
1321        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1322        const struct mlxsw_sp_trap_policer_item *policer_item;
1323        struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1324        int i;
1325
1326        for (i = trap->policers_count - 1; i >= 0; i--) {
1327                policer_item = &trap->policer_items_arr[i];
1328                devlink_trap_policers_unregister(devlink,
1329                                                 &policer_item->policer, 1);
1330        }
1331        mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp);
1332}
1333
1334static int mlxsw_sp_trap_group_items_arr_init(struct mlxsw_sp *mlxsw_sp)
1335{
1336        size_t common_groups_count = ARRAY_SIZE(mlxsw_sp_trap_group_items_arr);
1337        const struct mlxsw_sp_trap_group_item *spec_group_items_arr;
1338        size_t elem_size = sizeof(struct mlxsw_sp_trap_group_item);
1339        struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1340        size_t groups_count, spec_groups_count;
1341        int err;
1342
1343        err = mlxsw_sp->trap_ops->groups_init(mlxsw_sp, &spec_group_items_arr,
1344                                              &spec_groups_count);
1345        if (err)
1346                return err;
1347
1348        /* The group items array is created by concatenating the common trap
1349         * group items and the ASIC-specific trap group items.
1350         */
1351        groups_count = common_groups_count + spec_groups_count;
1352        trap->group_items_arr = kcalloc(groups_count, elem_size, GFP_KERNEL);
1353        if (!trap->group_items_arr)
1354                return -ENOMEM;
1355
1356        memcpy(trap->group_items_arr, mlxsw_sp_trap_group_items_arr,
1357               elem_size * common_groups_count);
1358        memcpy(trap->group_items_arr + common_groups_count,
1359               spec_group_items_arr, elem_size * spec_groups_count);
1360
1361        trap->groups_count = groups_count;
1362
1363        return 0;
1364}
1365
1366static void mlxsw_sp_trap_group_items_arr_fini(struct mlxsw_sp *mlxsw_sp)
1367{
1368        kfree(mlxsw_sp->trap->group_items_arr);
1369}
1370
1371static int mlxsw_sp_trap_groups_init(struct mlxsw_sp *mlxsw_sp)
1372{
1373        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1374        const struct mlxsw_sp_trap_group_item *group_item;
1375        struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1376        int err, i;
1377
1378        err = mlxsw_sp_trap_group_items_arr_init(mlxsw_sp);
1379        if (err)
1380                return err;
1381
1382        for (i = 0; i < trap->groups_count; i++) {
1383                group_item = &trap->group_items_arr[i];
1384                err = devlink_trap_groups_register(devlink, &group_item->group,
1385                                                   1);
1386                if (err)
1387                        goto err_trap_group_register;
1388        }
1389
1390        return 0;
1391
1392err_trap_group_register:
1393        for (i--; i >= 0; i--) {
1394                group_item = &trap->group_items_arr[i];
1395                devlink_trap_groups_unregister(devlink, &group_item->group, 1);
1396        }
1397        mlxsw_sp_trap_group_items_arr_fini(mlxsw_sp);
1398        return err;
1399}
1400
1401static void mlxsw_sp_trap_groups_fini(struct mlxsw_sp *mlxsw_sp)
1402{
1403        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1404        struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1405        int i;
1406
1407        for (i = trap->groups_count - 1; i >= 0; i--) {
1408                const struct mlxsw_sp_trap_group_item *group_item;
1409
1410                group_item = &trap->group_items_arr[i];
1411                devlink_trap_groups_unregister(devlink, &group_item->group, 1);
1412        }
1413        mlxsw_sp_trap_group_items_arr_fini(mlxsw_sp);
1414}
1415
1416static bool
1417mlxsw_sp_trap_listener_is_valid(const struct mlxsw_listener *listener)
1418{
1419        return listener->trap_id != 0;
1420}
1421
1422static int mlxsw_sp_trap_items_arr_init(struct mlxsw_sp *mlxsw_sp)
1423{
1424        size_t common_traps_count = ARRAY_SIZE(mlxsw_sp_trap_items_arr);
1425        const struct mlxsw_sp_trap_item *spec_trap_items_arr;
1426        size_t elem_size = sizeof(struct mlxsw_sp_trap_item);
1427        struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1428        size_t traps_count, spec_traps_count;
1429        int err;
1430
1431        err = mlxsw_sp->trap_ops->traps_init(mlxsw_sp, &spec_trap_items_arr,
1432                                             &spec_traps_count);
1433        if (err)
1434                return err;
1435
1436        /* The trap items array is created by concatenating the common trap
1437         * items and the ASIC-specific trap items.
1438         */
1439        traps_count = common_traps_count + spec_traps_count;
1440        trap->trap_items_arr = kcalloc(traps_count, elem_size, GFP_KERNEL);
1441        if (!trap->trap_items_arr)
1442                return -ENOMEM;
1443
1444        memcpy(trap->trap_items_arr, mlxsw_sp_trap_items_arr,
1445               elem_size * common_traps_count);
1446        memcpy(trap->trap_items_arr + common_traps_count,
1447               spec_trap_items_arr, elem_size * spec_traps_count);
1448
1449        trap->traps_count = traps_count;
1450
1451        return 0;
1452}
1453
1454static void mlxsw_sp_trap_items_arr_fini(struct mlxsw_sp *mlxsw_sp)
1455{
1456        kfree(mlxsw_sp->trap->trap_items_arr);
1457}
1458
1459static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)
1460{
1461        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1462        struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1463        const struct mlxsw_sp_trap_item *trap_item;
1464        int err, i;
1465
1466        err = mlxsw_sp_trap_items_arr_init(mlxsw_sp);
1467        if (err)
1468                return err;
1469
1470        for (i = 0; i < trap->traps_count; i++) {
1471                trap_item = &trap->trap_items_arr[i];
1472                err = devlink_traps_register(devlink, &trap_item->trap, 1,
1473                                             mlxsw_sp);
1474                if (err)
1475                        goto err_trap_register;
1476        }
1477
1478        return 0;
1479
1480err_trap_register:
1481        for (i--; i >= 0; i--) {
1482                trap_item = &trap->trap_items_arr[i];
1483                devlink_traps_unregister(devlink, &trap_item->trap, 1);
1484        }
1485        mlxsw_sp_trap_items_arr_fini(mlxsw_sp);
1486        return err;
1487}
1488
1489static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp)
1490{
1491        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1492        struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1493        int i;
1494
1495        for (i = trap->traps_count - 1; i >= 0; i--) {
1496                const struct mlxsw_sp_trap_item *trap_item;
1497
1498                trap_item = &trap->trap_items_arr[i];
1499                devlink_traps_unregister(devlink, &trap_item->trap, 1);
1500        }
1501        mlxsw_sp_trap_items_arr_fini(mlxsw_sp);
1502}
1503
1504int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp)
1505{
1506        int err;
1507
1508        err = mlxsw_sp_trap_cpu_policers_set(mlxsw_sp);
1509        if (err)
1510                return err;
1511
1512        err = mlxsw_sp_trap_dummy_group_init(mlxsw_sp);
1513        if (err)
1514                return err;
1515
1516        err = mlxsw_sp_trap_policers_init(mlxsw_sp);
1517        if (err)
1518                return err;
1519
1520        err = mlxsw_sp_trap_groups_init(mlxsw_sp);
1521        if (err)
1522                goto err_trap_groups_init;
1523
1524        err = mlxsw_sp_traps_init(mlxsw_sp);
1525        if (err)
1526                goto err_traps_init;
1527
1528        return 0;
1529
1530err_traps_init:
1531        mlxsw_sp_trap_groups_fini(mlxsw_sp);
1532err_trap_groups_init:
1533        mlxsw_sp_trap_policers_fini(mlxsw_sp);
1534        return err;
1535}
1536
1537void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp)
1538{
1539        mlxsw_sp_traps_fini(mlxsw_sp);
1540        mlxsw_sp_trap_groups_fini(mlxsw_sp);
1541        mlxsw_sp_trap_policers_fini(mlxsw_sp);
1542}
1543
1544int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core,
1545                       const struct devlink_trap *trap, void *trap_ctx)
1546{
1547        struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1548        const struct mlxsw_sp_trap_item *trap_item;
1549        int i;
1550
1551        trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);
1552        if (WARN_ON(!trap_item))
1553                return -EINVAL;
1554
1555        for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) {
1556                const struct mlxsw_listener *listener;
1557                int err;
1558
1559                listener = &trap_item->listeners_arr[i];
1560                if (!mlxsw_sp_trap_listener_is_valid(listener))
1561                        continue;
1562                err = mlxsw_core_trap_register(mlxsw_core, listener, trap_ctx);
1563                if (err)
1564                        return err;
1565        }
1566
1567        return 0;
1568}
1569
1570void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core,
1571                        const struct devlink_trap *trap, void *trap_ctx)
1572{
1573        struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1574        const struct mlxsw_sp_trap_item *trap_item;
1575        int i;
1576
1577        trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);
1578        if (WARN_ON(!trap_item))
1579                return;
1580
1581        for (i = MLXSW_SP_TRAP_LISTENERS_MAX - 1; i >= 0; i--) {
1582                const struct mlxsw_listener *listener;
1583
1584                listener = &trap_item->listeners_arr[i];
1585                if (!mlxsw_sp_trap_listener_is_valid(listener))
1586                        continue;
1587                mlxsw_core_trap_unregister(mlxsw_core, listener, trap_ctx);
1588        }
1589}
1590
1591int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core,
1592                             const struct devlink_trap *trap,
1593                             enum devlink_trap_action action,
1594                             struct netlink_ext_ack *extack)
1595{
1596        struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1597        const struct mlxsw_sp_trap_item *trap_item;
1598        int i;
1599
1600        trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);
1601        if (WARN_ON(!trap_item))
1602                return -EINVAL;
1603
1604        if (trap_item->is_source) {
1605                NL_SET_ERR_MSG_MOD(extack, "Changing the action of source traps is not supported");
1606                return -EOPNOTSUPP;
1607        }
1608
1609        for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) {
1610                const struct mlxsw_listener *listener;
1611                bool enabled;
1612                int err;
1613
1614                listener = &trap_item->listeners_arr[i];
1615                if (!mlxsw_sp_trap_listener_is_valid(listener))
1616                        continue;
1617
1618                switch (action) {
1619                case DEVLINK_TRAP_ACTION_DROP:
1620                        enabled = false;
1621                        break;
1622                case DEVLINK_TRAP_ACTION_TRAP:
1623                        enabled = true;
1624                        break;
1625                default:
1626                        return -EINVAL;
1627                }
1628                err = mlxsw_core_trap_state_set(mlxsw_core, listener, enabled);
1629                if (err)
1630                        return err;
1631        }
1632
1633        return 0;
1634}
1635
1636static int
1637__mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core,
1638                           const struct devlink_trap_group *group,
1639                           u32 policer_id, struct netlink_ext_ack *extack)
1640{
1641        struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1642        u16 hw_policer_id = MLXSW_REG_HTGT_INVALID_POLICER;
1643        const struct mlxsw_sp_trap_group_item *group_item;
1644        char htgt_pl[MLXSW_REG_HTGT_LEN];
1645
1646        group_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, group->id);
1647        if (WARN_ON(!group_item))
1648                return -EINVAL;
1649
1650        if (group_item->fixed_policer && policer_id != group->init_policer_id) {
1651                NL_SET_ERR_MSG_MOD(extack, "Changing the policer binding of this group is not supported");
1652                return -EOPNOTSUPP;
1653        }
1654
1655        if (policer_id) {
1656                struct mlxsw_sp_trap_policer_item *policer_item;
1657
1658                policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp,
1659                                                                 policer_id);
1660                if (WARN_ON(!policer_item))
1661                        return -EINVAL;
1662                hw_policer_id = policer_item->hw_id;
1663        }
1664
1665        mlxsw_reg_htgt_pack(htgt_pl, group_item->hw_group_id, hw_policer_id,
1666                            group_item->priority, group_item->priority);
1667        return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
1668}
1669
1670int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core,
1671                             const struct devlink_trap_group *group)
1672{
1673        return __mlxsw_sp_trap_group_init(mlxsw_core, group,
1674                                          group->init_policer_id, NULL);
1675}
1676
1677int mlxsw_sp_trap_group_set(struct mlxsw_core *mlxsw_core,
1678                            const struct devlink_trap_group *group,
1679                            const struct devlink_trap_policer *policer,
1680                            struct netlink_ext_ack *extack)
1681{
1682        u32 policer_id = policer ? policer->id : 0;
1683
1684        return __mlxsw_sp_trap_group_init(mlxsw_core, group, policer_id,
1685                                          extack);
1686}
1687
1688static int
1689mlxsw_sp_trap_policer_item_init(struct mlxsw_sp *mlxsw_sp,
1690                                struct mlxsw_sp_trap_policer_item *policer_item)
1691{
1692        struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1693        u16 hw_id;
1694
1695        /* We should be able to allocate a policer because the number of
1696         * policers we registered with devlink is in according with the number
1697         * of available policers.
1698         */
1699        hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers);
1700        if (WARN_ON(hw_id == trap->max_policers))
1701                return -ENOBUFS;
1702
1703        __set_bit(hw_id, trap->policers_usage);
1704        policer_item->hw_id = hw_id;
1705
1706        return 0;
1707}
1708
1709static void
1710mlxsw_sp_trap_policer_item_fini(struct mlxsw_sp *mlxsw_sp,
1711                                struct mlxsw_sp_trap_policer_item *policer_item)
1712{
1713        __clear_bit(policer_item->hw_id, mlxsw_sp->trap->policers_usage);
1714}
1715
1716static int mlxsw_sp_trap_policer_bs(u64 burst, u8 *p_burst_size,
1717                                    struct netlink_ext_ack *extack)
1718{
1719        int bs = fls64(burst) - 1;
1720
1721        if (burst != (BIT_ULL(bs))) {
1722                NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two");
1723                return -EINVAL;
1724        }
1725
1726        *p_burst_size = bs;
1727
1728        return 0;
1729}
1730
1731static int __mlxsw_sp_trap_policer_set(struct mlxsw_sp *mlxsw_sp, u16 hw_id,
1732                                       u64 rate, u64 burst, bool clear_counter,
1733                                       struct netlink_ext_ack *extack)
1734{
1735        char qpcr_pl[MLXSW_REG_QPCR_LEN];
1736        u8 burst_size;
1737        int err;
1738
1739        err = mlxsw_sp_trap_policer_bs(burst, &burst_size, extack);
1740        if (err)
1741                return err;
1742
1743        mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M, false,
1744                            rate, burst_size);
1745        mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, clear_counter);
1746        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
1747}
1748
1749int mlxsw_sp_trap_policer_init(struct mlxsw_core *mlxsw_core,
1750                               const struct devlink_trap_policer *policer)
1751{
1752        struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1753        struct mlxsw_sp_trap_policer_item *policer_item;
1754        int err;
1755
1756        policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1757        if (WARN_ON(!policer_item))
1758                return -EINVAL;
1759
1760        err = mlxsw_sp_trap_policer_item_init(mlxsw_sp, policer_item);
1761        if (err)
1762                return err;
1763
1764        err = __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id,
1765                                          policer->init_rate,
1766                                          policer->init_burst, true, NULL);
1767        if (err)
1768                goto err_trap_policer_set;
1769
1770        return 0;
1771
1772err_trap_policer_set:
1773        mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item);
1774        return err;
1775}
1776
1777void mlxsw_sp_trap_policer_fini(struct mlxsw_core *mlxsw_core,
1778                                const struct devlink_trap_policer *policer)
1779{
1780        struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1781        struct mlxsw_sp_trap_policer_item *policer_item;
1782
1783        policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1784        if (WARN_ON(!policer_item))
1785                return;
1786
1787        mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item);
1788}
1789
1790int mlxsw_sp_trap_policer_set(struct mlxsw_core *mlxsw_core,
1791                              const struct devlink_trap_policer *policer,
1792                              u64 rate, u64 burst,
1793                              struct netlink_ext_ack *extack)
1794{
1795        struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1796        struct mlxsw_sp_trap_policer_item *policer_item;
1797
1798        policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1799        if (WARN_ON(!policer_item))
1800                return -EINVAL;
1801
1802        return __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id,
1803                                           rate, burst, false, extack);
1804}
1805
1806int
1807mlxsw_sp_trap_policer_counter_get(struct mlxsw_core *mlxsw_core,
1808                                  const struct devlink_trap_policer *policer,
1809                                  u64 *p_drops)
1810{
1811        struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1812        struct mlxsw_sp_trap_policer_item *policer_item;
1813        char qpcr_pl[MLXSW_REG_QPCR_LEN];
1814        int err;
1815
1816        policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1817        if (WARN_ON(!policer_item))
1818                return -EINVAL;
1819
1820        mlxsw_reg_qpcr_pack(qpcr_pl, policer_item->hw_id,
1821                            MLXSW_REG_QPCR_IR_UNITS_M, false, 0, 0);
1822        err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
1823        if (err)
1824                return err;
1825
1826        *p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl);
1827
1828        return 0;
1829}
1830
1831int mlxsw_sp_trap_group_policer_hw_id_get(struct mlxsw_sp *mlxsw_sp, u16 id,
1832                                          bool *p_enabled, u16 *p_hw_id)
1833{
1834        struct mlxsw_sp_trap_policer_item *pol_item;
1835        struct mlxsw_sp_trap_group_item *gr_item;
1836        u32 pol_id;
1837
1838        gr_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, id);
1839        if (!gr_item)
1840                return -ENOENT;
1841
1842        pol_id = gr_item->group.init_policer_id;
1843        if (!pol_id) {
1844                *p_enabled = false;
1845                return 0;
1846        }
1847
1848        pol_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, pol_id);
1849        if (WARN_ON(!pol_item))
1850                return -ENOENT;
1851
1852        *p_enabled = true;
1853        *p_hw_id = pol_item->hw_id;
1854        return 0;
1855}
1856
1857static const struct mlxsw_sp_trap_group_item
1858mlxsw_sp1_trap_group_items_arr[] = {
1859        {
1860                .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0),
1861                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PKT_SAMPLE,
1862                .priority = 0,
1863        },
1864};
1865
1866static const struct mlxsw_sp_trap_item
1867mlxsw_sp1_trap_items_arr[] = {
1868        {
1869                .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_SAMPLE, ACL_SAMPLE,
1870                                              MIRROR),
1871                .listeners_arr = {
1872                        MLXSW_RXL(mlxsw_sp_rx_sample_listener, PKT_SAMPLE,
1873                                  MIRROR_TO_CPU, false, SP_PKT_SAMPLE, DISCARD),
1874                },
1875        },
1876};
1877
1878static int
1879mlxsw_sp1_trap_groups_init(struct mlxsw_sp *mlxsw_sp,
1880                           const struct mlxsw_sp_trap_group_item **arr,
1881                           size_t *p_groups_count)
1882{
1883        *arr = mlxsw_sp1_trap_group_items_arr;
1884        *p_groups_count = ARRAY_SIZE(mlxsw_sp1_trap_group_items_arr);
1885
1886        return 0;
1887}
1888
1889static int mlxsw_sp1_traps_init(struct mlxsw_sp *mlxsw_sp,
1890                                const struct mlxsw_sp_trap_item **arr,
1891                                size_t *p_traps_count)
1892{
1893        *arr = mlxsw_sp1_trap_items_arr;
1894        *p_traps_count = ARRAY_SIZE(mlxsw_sp1_trap_items_arr);
1895
1896        return 0;
1897}
1898
1899const struct mlxsw_sp_trap_ops mlxsw_sp1_trap_ops = {
1900        .groups_init = mlxsw_sp1_trap_groups_init,
1901        .traps_init = mlxsw_sp1_traps_init,
1902};
1903
1904static const struct mlxsw_sp_trap_group_item
1905mlxsw_sp2_trap_group_items_arr[] = {
1906        {
1907                .group = DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 20),
1908                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BUFFER_DISCARDS,
1909                .priority = 0,
1910                .fixed_policer = true,
1911        },
1912        {
1913                .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0),
1914                .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PKT_SAMPLE,
1915                .priority = 0,
1916                .fixed_policer = true,
1917        },
1918};
1919
1920static const struct mlxsw_sp_trap_item
1921mlxsw_sp2_trap_items_arr[] = {
1922        {
1923                .trap = MLXSW_SP_TRAP_BUFFER_DROP(EARLY_DROP),
1924                .listeners_arr = {
1925                        MLXSW_SP_RXL_BUFFER_DISCARD(INGRESS_WRED),
1926                },
1927                .is_source = true,
1928        },
1929        {
1930                .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_SAMPLE, ACL_SAMPLE,
1931                                              MIRROR),
1932                .listeners_arr = {
1933                        MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_listener, 1,
1934                                         SP_PKT_SAMPLE,
1935                                         MLXSW_SP_MIRROR_REASON_INGRESS),
1936                        MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_tx_listener, 1,
1937                                         SP_PKT_SAMPLE,
1938                                         MLXSW_SP_MIRROR_REASON_EGRESS),
1939                        MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_acl_listener, 1,
1940                                         SP_PKT_SAMPLE,
1941                                         MLXSW_SP_MIRROR_REASON_POLICY_ENGINE),
1942                },
1943        },
1944};
1945
1946static int
1947mlxsw_sp2_trap_groups_init(struct mlxsw_sp *mlxsw_sp,
1948                           const struct mlxsw_sp_trap_group_item **arr,
1949                           size_t *p_groups_count)
1950{
1951        *arr = mlxsw_sp2_trap_group_items_arr;
1952        *p_groups_count = ARRAY_SIZE(mlxsw_sp2_trap_group_items_arr);
1953
1954        return 0;
1955}
1956
1957static int mlxsw_sp2_traps_init(struct mlxsw_sp *mlxsw_sp,
1958                                const struct mlxsw_sp_trap_item **arr,
1959                                size_t *p_traps_count)
1960{
1961        *arr = mlxsw_sp2_trap_items_arr;
1962        *p_traps_count = ARRAY_SIZE(mlxsw_sp2_trap_items_arr);
1963
1964        return 0;
1965}
1966
1967const struct mlxsw_sp_trap_ops mlxsw_sp2_trap_ops = {
1968        .groups_init = mlxsw_sp2_trap_groups_init,
1969        .traps_init = mlxsw_sp2_traps_init,
1970};
1971