Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2019 Mellanox Technologies. All rights reserved */
0003 
0004 #include <linux/bitops.h>
0005 #include <linux/kernel.h>
0006 #include <linux/netlink.h>
0007 #include <net/devlink.h>
0008 #include <uapi/linux/devlink.h>
0009 
0010 #include "core.h"
0011 #include "reg.h"
0012 #include "spectrum.h"
0013 #include "spectrum_trap.h"
0014 
0015 struct mlxsw_sp_trap_policer_item {
0016     struct devlink_trap_policer policer;
0017     u16 hw_id;
0018 };
0019 
0020 struct mlxsw_sp_trap_group_item {
0021     struct devlink_trap_group group;
0022     u16 hw_group_id;
0023     u8 priority;
0024     u8 fixed_policer:1; /* Whether policer binding can change */
0025 };
0026 
0027 #define MLXSW_SP_TRAP_LISTENERS_MAX 3
0028 
0029 struct mlxsw_sp_trap_item {
0030     struct devlink_trap trap;
0031     struct mlxsw_listener listeners_arr[MLXSW_SP_TRAP_LISTENERS_MAX];
0032     u8 is_source:1;
0033 };
0034 
0035 /* All driver-specific traps must be documented in
0036  * Documentation/networking/devlink/mlxsw.rst
0037  */
0038 enum {
0039     DEVLINK_MLXSW_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX,
0040     DEVLINK_MLXSW_TRAP_ID_IRIF_DISABLED,
0041     DEVLINK_MLXSW_TRAP_ID_ERIF_DISABLED,
0042 };
0043 
0044 #define DEVLINK_MLXSW_TRAP_NAME_IRIF_DISABLED \
0045     "irif_disabled"
0046 #define DEVLINK_MLXSW_TRAP_NAME_ERIF_DISABLED \
0047     "erif_disabled"
0048 
0049 #define MLXSW_SP_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT
0050 
0051 enum {
0052     /* Packet was mirrored from ingress. */
0053     MLXSW_SP_MIRROR_REASON_INGRESS = 1,
0054     /* Packet was mirrored from policy engine. */
0055     MLXSW_SP_MIRROR_REASON_POLICY_ENGINE = 2,
0056     /* Packet was early dropped. */
0057     MLXSW_SP_MIRROR_REASON_INGRESS_WRED = 9,
0058     /* Packet was mirrored from egress. */
0059     MLXSW_SP_MIRROR_REASON_EGRESS = 14,
0060 };
0061 
0062 static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
0063                 u16 local_port,
0064                 struct mlxsw_sp_port *mlxsw_sp_port)
0065 {
0066     struct mlxsw_sp_port_pcpu_stats *pcpu_stats;
0067 
0068     if (unlikely(!mlxsw_sp_port)) {
0069         dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n",
0070                      local_port);
0071         kfree_skb(skb);
0072         return -EINVAL;
0073     }
0074 
0075     skb->dev = mlxsw_sp_port->dev;
0076 
0077     pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats);
0078     u64_stats_update_begin(&pcpu_stats->syncp);
0079     pcpu_stats->rx_packets++;
0080     pcpu_stats->rx_bytes += skb->len;
0081     u64_stats_update_end(&pcpu_stats->syncp);
0082 
0083     skb->protocol = eth_type_trans(skb, skb->dev);
0084 
0085     return 0;
0086 }
0087 
0088 static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u16 local_port,
0089                       void *trap_ctx)
0090 {
0091     struct devlink_port *in_devlink_port;
0092     struct mlxsw_sp_port *mlxsw_sp_port;
0093     struct mlxsw_sp *mlxsw_sp;
0094     struct devlink *devlink;
0095     int err;
0096 
0097     mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
0098     mlxsw_sp_port = mlxsw_sp->ports[local_port];
0099 
0100     err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
0101     if (err)
0102         return;
0103 
0104     devlink = priv_to_devlink(mlxsw_sp->core);
0105     in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
0106                                local_port);
0107     skb_push(skb, ETH_HLEN);
0108     devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL);
0109     consume_skb(skb);
0110 }
0111 
0112 static void mlxsw_sp_rx_acl_drop_listener(struct sk_buff *skb, u16 local_port,
0113                       void *trap_ctx)
0114 {
0115     u32 cookie_index = mlxsw_skb_cb(skb)->rx_md_info.cookie_index;
0116     const struct flow_action_cookie *fa_cookie;
0117     struct devlink_port *in_devlink_port;
0118     struct mlxsw_sp_port *mlxsw_sp_port;
0119     struct mlxsw_sp *mlxsw_sp;
0120     struct devlink *devlink;
0121     int err;
0122 
0123     mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
0124     mlxsw_sp_port = mlxsw_sp->ports[local_port];
0125 
0126     err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
0127     if (err)
0128         return;
0129 
0130     devlink = priv_to_devlink(mlxsw_sp->core);
0131     in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
0132                                local_port);
0133     skb_push(skb, ETH_HLEN);
0134     rcu_read_lock();
0135     fa_cookie = mlxsw_sp_acl_act_cookie_lookup(mlxsw_sp, cookie_index);
0136     devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, fa_cookie);
0137     rcu_read_unlock();
0138     consume_skb(skb);
0139 }
0140 
0141 static int __mlxsw_sp_rx_no_mark_listener(struct sk_buff *skb, u16 local_port,
0142                       void *trap_ctx)
0143 {
0144     struct devlink_port *in_devlink_port;
0145     struct mlxsw_sp_port *mlxsw_sp_port;
0146     struct mlxsw_sp *mlxsw_sp;
0147     struct devlink *devlink;
0148     int err;
0149 
0150     mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
0151     mlxsw_sp_port = mlxsw_sp->ports[local_port];
0152 
0153     err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
0154     if (err)
0155         return err;
0156 
0157     devlink = priv_to_devlink(mlxsw_sp->core);
0158     in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
0159                                local_port);
0160     skb_push(skb, ETH_HLEN);
0161     devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL);
0162     skb_pull(skb, ETH_HLEN);
0163 
0164     return 0;
0165 }
0166 
0167 static void mlxsw_sp_rx_no_mark_listener(struct sk_buff *skb, u16 local_port,
0168                      void *trap_ctx)
0169 {
0170     int err;
0171 
0172     err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
0173     if (err)
0174         return;
0175 
0176     netif_receive_skb(skb);
0177 }
0178 
0179 static void mlxsw_sp_rx_mark_listener(struct sk_buff *skb, u16 local_port,
0180                       void *trap_ctx)
0181 {
0182     skb->offload_fwd_mark = 1;
0183     mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
0184 }
0185 
0186 static void mlxsw_sp_rx_l3_mark_listener(struct sk_buff *skb, u16 local_port,
0187                      void *trap_ctx)
0188 {
0189     skb->offload_l3_fwd_mark = 1;
0190     skb->offload_fwd_mark = 1;
0191     mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
0192 }
0193 
0194 static void mlxsw_sp_rx_ptp_listener(struct sk_buff *skb, u16 local_port,
0195                      void *trap_ctx)
0196 {
0197     struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
0198     int err;
0199 
0200     err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
0201     if (err)
0202         return;
0203 
0204     /* The PTP handler expects skb->data to point to the start of the
0205      * Ethernet header.
0206      */
0207     skb_push(skb, ETH_HLEN);
0208     mlxsw_sp_ptp_receive(mlxsw_sp, skb, local_port);
0209 }
0210 
0211 static struct mlxsw_sp_port *
0212 mlxsw_sp_sample_tx_port_get(struct mlxsw_sp *mlxsw_sp,
0213                 const struct mlxsw_rx_md_info *rx_md_info)
0214 {
0215     u16 local_port;
0216 
0217     if (!rx_md_info->tx_port_valid)
0218         return NULL;
0219 
0220     if (rx_md_info->tx_port_is_lag)
0221         local_port = mlxsw_core_lag_mapping_get(mlxsw_sp->core,
0222                             rx_md_info->tx_lag_id,
0223                             rx_md_info->tx_lag_port_index);
0224     else
0225         local_port = rx_md_info->tx_sys_port;
0226 
0227     if (local_port >= mlxsw_core_max_ports(mlxsw_sp->core))
0228         return NULL;
0229 
0230     return mlxsw_sp->ports[local_port];
0231 }
0232 
0233 /* The latency units are determined according to MOGCR.mirror_latency_units. It
0234  * defaults to 64 nanoseconds.
0235  */
0236 #define MLXSW_SP_MIRROR_LATENCY_SHIFT   6
0237 
0238 static void mlxsw_sp_psample_md_init(struct mlxsw_sp *mlxsw_sp,
0239                      struct psample_metadata *md,
0240                      struct sk_buff *skb, int in_ifindex,
0241                      bool truncate, u32 trunc_size)
0242 {
0243     struct mlxsw_rx_md_info *rx_md_info = &mlxsw_skb_cb(skb)->rx_md_info;
0244     struct mlxsw_sp_port *mlxsw_sp_port;
0245 
0246     md->trunc_size = truncate ? trunc_size : skb->len;
0247     md->in_ifindex = in_ifindex;
0248     mlxsw_sp_port = mlxsw_sp_sample_tx_port_get(mlxsw_sp, rx_md_info);
0249     md->out_ifindex = mlxsw_sp_port && mlxsw_sp_port->dev ?
0250               mlxsw_sp_port->dev->ifindex : 0;
0251     md->out_tc_valid = rx_md_info->tx_tc_valid;
0252     md->out_tc = rx_md_info->tx_tc;
0253     md->out_tc_occ_valid = rx_md_info->tx_congestion_valid;
0254     md->out_tc_occ = rx_md_info->tx_congestion;
0255     md->latency_valid = rx_md_info->latency_valid;
0256     md->latency = rx_md_info->latency;
0257     md->latency <<= MLXSW_SP_MIRROR_LATENCY_SHIFT;
0258 }
0259 
0260 static void mlxsw_sp_rx_sample_listener(struct sk_buff *skb, u16 local_port,
0261                     void *trap_ctx)
0262 {
0263     struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
0264     struct mlxsw_sp_sample_trigger trigger;
0265     struct mlxsw_sp_sample_params *params;
0266     struct mlxsw_sp_port *mlxsw_sp_port;
0267     struct psample_metadata md = {};
0268     int err;
0269 
0270     err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
0271     if (err)
0272         return;
0273 
0274     mlxsw_sp_port = mlxsw_sp->ports[local_port];
0275     if (!mlxsw_sp_port)
0276         goto out;
0277 
0278     trigger.type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_INGRESS;
0279     trigger.local_port = local_port;
0280     params = mlxsw_sp_sample_trigger_params_lookup(mlxsw_sp, &trigger);
0281     if (!params)
0282         goto out;
0283 
0284     /* The psample module expects skb->data to point to the start of the
0285      * Ethernet header.
0286      */
0287     skb_push(skb, ETH_HLEN);
0288     mlxsw_sp_psample_md_init(mlxsw_sp, &md, skb,
0289                  mlxsw_sp_port->dev->ifindex, params->truncate,
0290                  params->trunc_size);
0291     psample_sample_packet(params->psample_group, skb, params->rate, &md);
0292 out:
0293     consume_skb(skb);
0294 }
0295 
0296 static void mlxsw_sp_rx_sample_tx_listener(struct sk_buff *skb, u16 local_port,
0297                        void *trap_ctx)
0298 {
0299     struct mlxsw_rx_md_info *rx_md_info = &mlxsw_skb_cb(skb)->rx_md_info;
0300     struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
0301     struct mlxsw_sp_port *mlxsw_sp_port, *mlxsw_sp_port_tx;
0302     struct mlxsw_sp_sample_trigger trigger;
0303     struct mlxsw_sp_sample_params *params;
0304     struct psample_metadata md = {};
0305     int err;
0306 
0307     /* Locally generated packets are not reported from the policy engine
0308      * trigger, so do not report them from the egress trigger as well.
0309      */
0310     if (local_port == MLXSW_PORT_CPU_PORT)
0311         goto out;
0312 
0313     err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
0314     if (err)
0315         return;
0316 
0317     mlxsw_sp_port = mlxsw_sp->ports[local_port];
0318     if (!mlxsw_sp_port)
0319         goto out;
0320 
0321     /* Packet was sampled from Tx, so we need to retrieve the sample
0322      * parameters based on the Tx port and not the Rx port.
0323      */
0324     mlxsw_sp_port_tx = mlxsw_sp_sample_tx_port_get(mlxsw_sp, rx_md_info);
0325     if (!mlxsw_sp_port_tx)
0326         goto out;
0327 
0328     trigger.type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_EGRESS;
0329     trigger.local_port = mlxsw_sp_port_tx->local_port;
0330     params = mlxsw_sp_sample_trigger_params_lookup(mlxsw_sp, &trigger);
0331     if (!params)
0332         goto out;
0333 
0334     /* The psample module expects skb->data to point to the start of the
0335      * Ethernet header.
0336      */
0337     skb_push(skb, ETH_HLEN);
0338     mlxsw_sp_psample_md_init(mlxsw_sp, &md, skb,
0339                  mlxsw_sp_port->dev->ifindex, params->truncate,
0340                  params->trunc_size);
0341     psample_sample_packet(params->psample_group, skb, params->rate, &md);
0342 out:
0343     consume_skb(skb);
0344 }
0345 
0346 static void mlxsw_sp_rx_sample_acl_listener(struct sk_buff *skb, u16 local_port,
0347                         void *trap_ctx)
0348 {
0349     struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
0350     struct mlxsw_sp_sample_trigger trigger = {
0351         .type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_POLICY_ENGINE,
0352     };
0353     struct mlxsw_sp_sample_params *params;
0354     struct mlxsw_sp_port *mlxsw_sp_port;
0355     struct psample_metadata md = {};
0356     int err;
0357 
0358     err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx);
0359     if (err)
0360         return;
0361 
0362     mlxsw_sp_port = mlxsw_sp->ports[local_port];
0363     if (!mlxsw_sp_port)
0364         goto out;
0365 
0366     params = mlxsw_sp_sample_trigger_params_lookup(mlxsw_sp, &trigger);
0367     if (!params)
0368         goto out;
0369 
0370     /* The psample module expects skb->data to point to the start of the
0371      * Ethernet header.
0372      */
0373     skb_push(skb, ETH_HLEN);
0374     mlxsw_sp_psample_md_init(mlxsw_sp, &md, skb,
0375                  mlxsw_sp_port->dev->ifindex, params->truncate,
0376                  params->trunc_size);
0377     psample_sample_packet(params->psample_group, skb, params->rate, &md);
0378 out:
0379     consume_skb(skb);
0380 }
0381 
0382 #define MLXSW_SP_TRAP_DROP(_id, _group_id)                    \
0383     DEVLINK_TRAP_GENERIC(DROP, DROP, _id,                     \
0384                  DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,       \
0385                  MLXSW_SP_TRAP_METADATA)
0386 
0387 #define MLXSW_SP_TRAP_DROP_EXT(_id, _group_id, _metadata)             \
0388     DEVLINK_TRAP_GENERIC(DROP, DROP, _id,                     \
0389                  DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,       \
0390                  MLXSW_SP_TRAP_METADATA | (_metadata))
0391 
0392 #define MLXSW_SP_TRAP_BUFFER_DROP(_id)                        \
0393     DEVLINK_TRAP_GENERIC(DROP, TRAP, _id,                     \
0394                  DEVLINK_TRAP_GROUP_GENERIC_ID_BUFFER_DROPS,      \
0395                  MLXSW_SP_TRAP_METADATA)
0396 
0397 #define MLXSW_SP_TRAP_DRIVER_DROP(_id, _group_id)                 \
0398     DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_MLXSW_TRAP_ID_##_id,          \
0399                 DEVLINK_MLXSW_TRAP_NAME_##_id,            \
0400                 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,        \
0401                 MLXSW_SP_TRAP_METADATA)
0402 
0403 #define MLXSW_SP_TRAP_EXCEPTION(_id, _group_id)           \
0404     DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id,                \
0405                  DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,       \
0406                  MLXSW_SP_TRAP_METADATA)
0407 
0408 #define MLXSW_SP_TRAP_CONTROL(_id, _group_id, _action)                \
0409     DEVLINK_TRAP_GENERIC(CONTROL, _action, _id,               \
0410                  DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,       \
0411                  MLXSW_SP_TRAP_METADATA)
0412 
0413 #define MLXSW_SP_RXL_DISCARD(_id, _group_id)                      \
0414     MLXSW_RXL_DIS(mlxsw_sp_rx_drop_listener, DISCARD_##_id,           \
0415               TRAP_EXCEPTION_TO_CPU, false, SP_##_group_id,       \
0416               SET_FW_DEFAULT, SP_##_group_id)
0417 
0418 #define MLXSW_SP_RXL_ACL_DISCARD(_id, _en_group_id, _dis_group_id)        \
0419     MLXSW_RXL_DIS(mlxsw_sp_rx_acl_drop_listener, DISCARD_##_id,       \
0420               TRAP_EXCEPTION_TO_CPU, false, SP_##_en_group_id,        \
0421               SET_FW_DEFAULT, SP_##_dis_group_id)
0422 
0423 #define MLXSW_SP_RXL_BUFFER_DISCARD(_mirror_reason)               \
0424     MLXSW_RXL_MIRROR(mlxsw_sp_rx_drop_listener, 0, SP_BUFFER_DISCARDS,    \
0425              MLXSW_SP_MIRROR_REASON_##_mirror_reason)
0426 
0427 #define MLXSW_SP_RXL_EXCEPTION(_id, _group_id, _action)               \
0428     MLXSW_RXL(mlxsw_sp_rx_mark_listener, _id,                 \
0429            _action, false, SP_##_group_id, SET_FW_DEFAULT)
0430 
0431 #define MLXSW_SP_RXL_NO_MARK(_id, _group_id, _action, _is_ctrl)           \
0432     MLXSW_RXL(mlxsw_sp_rx_no_mark_listener, _id, _action,             \
0433           _is_ctrl, SP_##_group_id, DISCARD)
0434 
0435 #define MLXSW_SP_RXL_MARK(_id, _group_id, _action, _is_ctrl)              \
0436     MLXSW_RXL(mlxsw_sp_rx_mark_listener, _id, _action, _is_ctrl,          \
0437           SP_##_group_id, DISCARD)
0438 
0439 #define MLXSW_SP_RXL_L3_MARK(_id, _group_id, _action, _is_ctrl)           \
0440     MLXSW_RXL(mlxsw_sp_rx_l3_mark_listener, _id, _action, _is_ctrl,       \
0441           SP_##_group_id, DISCARD)
0442 
0443 #define MLXSW_SP_TRAP_POLICER(_id, _rate, _burst)                 \
0444     DEVLINK_TRAP_POLICER(_id, _rate, _burst,                  \
0445                  MLXSW_REG_QPCR_HIGHEST_CIR,              \
0446                  MLXSW_REG_QPCR_LOWEST_CIR,               \
0447                  1 << MLXSW_REG_QPCR_HIGHEST_CBS,             \
0448                  1 << MLXSW_REG_QPCR_LOWEST_CBS)
0449 
0450 /* Ordered by policer identifier */
0451 static const struct mlxsw_sp_trap_policer_item
0452 mlxsw_sp_trap_policer_items_arr[] = {
0453     {
0454         .policer = MLXSW_SP_TRAP_POLICER(1, 10 * 1024, 4096),
0455     },
0456     {
0457         .policer = MLXSW_SP_TRAP_POLICER(2, 128, 128),
0458     },
0459     {
0460         .policer = MLXSW_SP_TRAP_POLICER(3, 128, 128),
0461     },
0462     {
0463         .policer = MLXSW_SP_TRAP_POLICER(4, 128, 128),
0464     },
0465     {
0466         .policer = MLXSW_SP_TRAP_POLICER(5, 16 * 1024, 8192),
0467     },
0468     {
0469         .policer = MLXSW_SP_TRAP_POLICER(6, 128, 128),
0470     },
0471     {
0472         .policer = MLXSW_SP_TRAP_POLICER(7, 1024, 512),
0473     },
0474     {
0475         .policer = MLXSW_SP_TRAP_POLICER(8, 20 * 1024, 8192),
0476     },
0477     {
0478         .policer = MLXSW_SP_TRAP_POLICER(9, 128, 128),
0479     },
0480     {
0481         .policer = MLXSW_SP_TRAP_POLICER(10, 1024, 512),
0482     },
0483     {
0484         .policer = MLXSW_SP_TRAP_POLICER(11, 256, 128),
0485     },
0486     {
0487         .policer = MLXSW_SP_TRAP_POLICER(12, 128, 128),
0488     },
0489     {
0490         .policer = MLXSW_SP_TRAP_POLICER(13, 128, 128),
0491     },
0492     {
0493         .policer = MLXSW_SP_TRAP_POLICER(14, 1024, 512),
0494     },
0495     {
0496         .policer = MLXSW_SP_TRAP_POLICER(15, 1024, 512),
0497     },
0498     {
0499         .policer = MLXSW_SP_TRAP_POLICER(16, 24 * 1024, 16384),
0500     },
0501     {
0502         .policer = MLXSW_SP_TRAP_POLICER(17, 19 * 1024, 8192),
0503     },
0504     {
0505         .policer = MLXSW_SP_TRAP_POLICER(18, 1024, 512),
0506     },
0507     {
0508         .policer = MLXSW_SP_TRAP_POLICER(19, 1024, 512),
0509     },
0510     {
0511         .policer = MLXSW_SP_TRAP_POLICER(20, 10240, 4096),
0512     },
0513 };
0514 
0515 static const struct mlxsw_sp_trap_group_item mlxsw_sp_trap_group_items_arr[] = {
0516     {
0517         .group = DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 1),
0518         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS,
0519         .priority = 0,
0520     },
0521     {
0522         .group = DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1),
0523         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS,
0524         .priority = 0,
0525     },
0526     {
0527         .group = DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 1),
0528         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_EXCEPTIONS,
0529         .priority = 2,
0530     },
0531     {
0532         .group = DEVLINK_TRAP_GROUP_GENERIC(TUNNEL_DROPS, 1),
0533         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS,
0534         .priority = 0,
0535     },
0536     {
0537         .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 1),
0538         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS,
0539         .priority = 0,
0540     },
0541     {
0542         .group = DEVLINK_TRAP_GROUP_GENERIC(STP, 2),
0543         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_STP,
0544         .priority = 5,
0545     },
0546     {
0547         .group = DEVLINK_TRAP_GROUP_GENERIC(LACP, 3),
0548         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LACP,
0549         .priority = 5,
0550     },
0551     {
0552         .group = DEVLINK_TRAP_GROUP_GENERIC(LLDP, 4),
0553         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP,
0554         .priority = 5,
0555     },
0556     {
0557         .group = DEVLINK_TRAP_GROUP_GENERIC(MC_SNOOPING, 5),
0558         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_MC_SNOOPING,
0559         .priority = 3,
0560     },
0561     {
0562         .group = DEVLINK_TRAP_GROUP_GENERIC(DHCP, 6),
0563         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_DHCP,
0564         .priority = 2,
0565     },
0566     {
0567         .group = DEVLINK_TRAP_GROUP_GENERIC(NEIGH_DISCOVERY, 7),
0568         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_NEIGH_DISCOVERY,
0569         .priority = 2,
0570     },
0571     {
0572         .group = DEVLINK_TRAP_GROUP_GENERIC(BFD, 8),
0573         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BFD,
0574         .priority = 5,
0575     },
0576     {
0577         .group = DEVLINK_TRAP_GROUP_GENERIC(OSPF, 9),
0578         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_OSPF,
0579         .priority = 5,
0580     },
0581     {
0582         .group = DEVLINK_TRAP_GROUP_GENERIC(BGP, 10),
0583         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BGP,
0584         .priority = 4,
0585     },
0586     {
0587         .group = DEVLINK_TRAP_GROUP_GENERIC(VRRP, 11),
0588         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_VRRP,
0589         .priority = 5,
0590     },
0591     {
0592         .group = DEVLINK_TRAP_GROUP_GENERIC(PIM, 12),
0593         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PIM,
0594         .priority = 5,
0595     },
0596     {
0597         .group = DEVLINK_TRAP_GROUP_GENERIC(UC_LB, 13),
0598         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LBERROR,
0599         .priority = 0,
0600     },
0601     {
0602         .group = DEVLINK_TRAP_GROUP_GENERIC(LOCAL_DELIVERY, 14),
0603         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME,
0604         .priority = 2,
0605     },
0606     {
0607         .group = DEVLINK_TRAP_GROUP_GENERIC(EXTERNAL_DELIVERY, 19),
0608         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_EXTERNAL_ROUTE,
0609         .priority = 1,
0610     },
0611     {
0612         .group = DEVLINK_TRAP_GROUP_GENERIC(IPV6, 15),
0613         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6,
0614         .priority = 2,
0615     },
0616     {
0617         .group = DEVLINK_TRAP_GROUP_GENERIC(PTP_EVENT, 16),
0618         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0,
0619         .priority = 5,
0620     },
0621     {
0622         .group = DEVLINK_TRAP_GROUP_GENERIC(PTP_GENERAL, 17),
0623         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1,
0624         .priority = 2,
0625     },
0626     {
0627         .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_TRAP, 18),
0628         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_FLOW_LOGGING,
0629         .priority = 4,
0630     },
0631 };
0632 
0633 static const struct mlxsw_sp_trap_item mlxsw_sp_trap_items_arr[] = {
0634     {
0635         .trap = MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS),
0636         .listeners_arr = {
0637             MLXSW_SP_RXL_DISCARD(ING_PACKET_SMAC_MC, L2_DISCARDS),
0638         },
0639     },
0640     {
0641         .trap = MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS),
0642         .listeners_arr = {
0643             MLXSW_SP_RXL_DISCARD(ING_SWITCH_VTAG_ALLOW,
0644                          L2_DISCARDS),
0645         },
0646     },
0647     {
0648         .trap = MLXSW_SP_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS),
0649         .listeners_arr = {
0650             MLXSW_SP_RXL_DISCARD(ING_SWITCH_VLAN, L2_DISCARDS),
0651         },
0652     },
0653     {
0654         .trap = MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS),
0655         .listeners_arr = {
0656             MLXSW_SP_RXL_DISCARD(ING_SWITCH_STP, L2_DISCARDS),
0657         },
0658     },
0659     {
0660         .trap = MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS),
0661         .listeners_arr = {
0662             MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS),
0663             MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS),
0664         },
0665     },
0666     {
0667         .trap = MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS),
0668         .listeners_arr = {
0669             MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS),
0670         },
0671     },
0672     {
0673         .trap = MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS),
0674         .listeners_arr = {
0675             MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS),
0676         },
0677     },
0678     {
0679         .trap = MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS),
0680         .listeners_arr = {
0681             MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET,
0682                          L3_DISCARDS),
0683         },
0684     },
0685     {
0686         .trap = MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS),
0687         .listeners_arr = {
0688             MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC,
0689                          L3_DISCARDS),
0690         },
0691     },
0692     {
0693         .trap = MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS),
0694         .listeners_arr = {
0695             MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS),
0696         },
0697     },
0698     {
0699         .trap = MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS),
0700         .listeners_arr = {
0701             MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS),
0702         },
0703     },
0704     {
0705         .trap = MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS),
0706         .listeners_arr = {
0707             MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS),
0708         },
0709     },
0710     {
0711         .trap = MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS),
0712         .listeners_arr = {
0713             MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR,
0714                          L3_DISCARDS),
0715         },
0716     },
0717     {
0718         .trap = MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS),
0719         .listeners_arr = {
0720             MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC,
0721                          L3_DISCARDS),
0722         },
0723     },
0724     {
0725         .trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE,
0726                        L3_DROPS),
0727         .listeners_arr = {
0728             MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE,
0729                          L3_DISCARDS),
0730         },
0731     },
0732     {
0733         .trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE,
0734                        L3_DROPS),
0735         .listeners_arr = {
0736             MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE,
0737                          L3_DISCARDS),
0738         },
0739     },
0740     {
0741         .trap = MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_EXCEPTIONS),
0742         .listeners_arr = {
0743             MLXSW_SP_RXL_EXCEPTION(MTUERROR, L3_EXCEPTIONS,
0744                            TRAP_TO_CPU),
0745         },
0746     },
0747     {
0748         .trap = MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS),
0749         .listeners_arr = {
0750             MLXSW_SP_RXL_EXCEPTION(TTLERROR, L3_EXCEPTIONS,
0751                            TRAP_TO_CPU),
0752         },
0753     },
0754     {
0755         .trap = MLXSW_SP_TRAP_EXCEPTION(RPF, L3_EXCEPTIONS),
0756         .listeners_arr = {
0757             MLXSW_SP_RXL_EXCEPTION(RPF, L3_EXCEPTIONS, TRAP_TO_CPU),
0758         },
0759     },
0760     {
0761         .trap = MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_EXCEPTIONS),
0762         .listeners_arr = {
0763             MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, L3_EXCEPTIONS,
0764                            TRAP_TO_CPU),
0765         },
0766     },
0767     {
0768         .trap = MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH,
0769                         L3_EXCEPTIONS),
0770         .listeners_arr = {
0771             MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, L3_EXCEPTIONS,
0772                            TRAP_TO_CPU),
0773             MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, L3_EXCEPTIONS,
0774                            TRAP_TO_CPU),
0775             MLXSW_SP_RXL_EXCEPTION(RTR_EGRESS0, L3_EXCEPTIONS,
0776                            TRAP_EXCEPTION_TO_CPU),
0777         },
0778     },
0779     {
0780         .trap = MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS,
0781                         L3_EXCEPTIONS),
0782         .listeners_arr = {
0783             MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4,
0784                            L3_EXCEPTIONS,
0785                            TRAP_EXCEPTION_TO_CPU),
0786         },
0787     },
0788     {
0789         .trap = MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS,
0790                         L3_EXCEPTIONS),
0791         .listeners_arr = {
0792             MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6,
0793                            L3_EXCEPTIONS,
0794                            TRAP_EXCEPTION_TO_CPU),
0795         },
0796     },
0797     {
0798         .trap = MLXSW_SP_TRAP_DRIVER_DROP(IRIF_DISABLED, L3_DROPS),
0799         .listeners_arr = {
0800             MLXSW_SP_RXL_DISCARD(ROUTER_IRIF_EN, L3_DISCARDS),
0801         },
0802     },
0803     {
0804         .trap = MLXSW_SP_TRAP_DRIVER_DROP(ERIF_DISABLED, L3_DROPS),
0805         .listeners_arr = {
0806             MLXSW_SP_RXL_DISCARD(ROUTER_ERIF_EN, L3_DISCARDS),
0807         },
0808     },
0809     {
0810         .trap = MLXSW_SP_TRAP_DROP(NON_ROUTABLE, L3_DROPS),
0811         .listeners_arr = {
0812             MLXSW_SP_RXL_DISCARD(NON_ROUTABLE, L3_DISCARDS),
0813         },
0814     },
0815     {
0816         .trap = MLXSW_SP_TRAP_EXCEPTION(DECAP_ERROR, TUNNEL_DROPS),
0817         .listeners_arr = {
0818             MLXSW_SP_RXL_EXCEPTION(DECAP_ECN0, TUNNEL_DISCARDS,
0819                            TRAP_EXCEPTION_TO_CPU),
0820             MLXSW_SP_RXL_EXCEPTION(IPIP_DECAP_ERROR,
0821                            TUNNEL_DISCARDS,
0822                            TRAP_EXCEPTION_TO_CPU),
0823             MLXSW_SP_RXL_EXCEPTION(DISCARD_DEC_PKT, TUNNEL_DISCARDS,
0824                            TRAP_EXCEPTION_TO_CPU),
0825         },
0826     },
0827     {
0828         .trap = MLXSW_SP_TRAP_DROP(OVERLAY_SMAC_MC, TUNNEL_DROPS),
0829         .listeners_arr = {
0830             MLXSW_SP_RXL_DISCARD(OVERLAY_SMAC_MC, TUNNEL_DISCARDS),
0831         },
0832     },
0833     {
0834         .trap = MLXSW_SP_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP,
0835                            ACL_DROPS,
0836                            DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),
0837         .listeners_arr = {
0838             MLXSW_SP_RXL_ACL_DISCARD(INGRESS_ACL, ACL_DISCARDS,
0839                          DUMMY),
0840         },
0841     },
0842     {
0843         .trap = MLXSW_SP_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP,
0844                            ACL_DROPS,
0845                            DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),
0846         .listeners_arr = {
0847             MLXSW_SP_RXL_ACL_DISCARD(EGRESS_ACL, ACL_DISCARDS,
0848                          DUMMY),
0849         },
0850     },
0851     {
0852         .trap = MLXSW_SP_TRAP_CONTROL(STP, STP, TRAP),
0853         .listeners_arr = {
0854             MLXSW_SP_RXL_NO_MARK(STP, STP, TRAP_TO_CPU, true),
0855         },
0856     },
0857     {
0858         .trap = MLXSW_SP_TRAP_CONTROL(LACP, LACP, TRAP),
0859         .listeners_arr = {
0860             MLXSW_SP_RXL_NO_MARK(LACP, LACP, TRAP_TO_CPU, true),
0861         },
0862     },
0863     {
0864         .trap = MLXSW_SP_TRAP_CONTROL(LLDP, LLDP, TRAP),
0865         .listeners_arr = {
0866             MLXSW_RXL(mlxsw_sp_rx_ptp_listener, LLDP, TRAP_TO_CPU,
0867                   true, SP_LLDP, DISCARD),
0868         },
0869     },
0870     {
0871         .trap = MLXSW_SP_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR),
0872         .listeners_arr = {
0873             MLXSW_SP_RXL_MARK(IGMP_QUERY, MC_SNOOPING,
0874                       MIRROR_TO_CPU, false),
0875         },
0876     },
0877     {
0878         .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING,
0879                           TRAP),
0880         .listeners_arr = {
0881             MLXSW_SP_RXL_NO_MARK(IGMP_V1_REPORT, MC_SNOOPING,
0882                          TRAP_TO_CPU, false),
0883         },
0884     },
0885     {
0886         .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_REPORT, MC_SNOOPING,
0887                           TRAP),
0888         .listeners_arr = {
0889             MLXSW_SP_RXL_NO_MARK(IGMP_V2_REPORT, MC_SNOOPING,
0890                          TRAP_TO_CPU, false),
0891         },
0892     },
0893     {
0894         .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V3_REPORT, MC_SNOOPING,
0895                           TRAP),
0896         .listeners_arr = {
0897             MLXSW_SP_RXL_NO_MARK(IGMP_V3_REPORT, MC_SNOOPING,
0898                          TRAP_TO_CPU, false),
0899         },
0900     },
0901     {
0902         .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_LEAVE, MC_SNOOPING,
0903                           TRAP),
0904         .listeners_arr = {
0905             MLXSW_SP_RXL_NO_MARK(IGMP_V2_LEAVE, MC_SNOOPING,
0906                          TRAP_TO_CPU, false),
0907         },
0908     },
0909     {
0910         .trap = MLXSW_SP_TRAP_CONTROL(MLD_QUERY, MC_SNOOPING, MIRROR),
0911         .listeners_arr = {
0912             MLXSW_SP_RXL_MARK(IPV6_MLDV12_LISTENER_QUERY,
0913                       MC_SNOOPING, MIRROR_TO_CPU, false),
0914         },
0915     },
0916     {
0917         .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_REPORT, MC_SNOOPING,
0918                           TRAP),
0919         .listeners_arr = {
0920             MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_REPORT,
0921                          MC_SNOOPING, TRAP_TO_CPU, false),
0922         },
0923     },
0924     {
0925         .trap = MLXSW_SP_TRAP_CONTROL(MLD_V2_REPORT, MC_SNOOPING,
0926                           TRAP),
0927         .listeners_arr = {
0928             MLXSW_SP_RXL_NO_MARK(IPV6_MLDV2_LISTENER_REPORT,
0929                          MC_SNOOPING, TRAP_TO_CPU, false),
0930         },
0931     },
0932     {
0933         .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_DONE, MC_SNOOPING,
0934                           TRAP),
0935         .listeners_arr = {
0936             MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_DONE,
0937                          MC_SNOOPING, TRAP_TO_CPU, false),
0938         },
0939     },
0940     {
0941         .trap = MLXSW_SP_TRAP_CONTROL(IPV4_DHCP, DHCP, TRAP),
0942         .listeners_arr = {
0943             MLXSW_SP_RXL_MARK(IPV4_DHCP, DHCP, TRAP_TO_CPU, false),
0944         },
0945     },
0946     {
0947         .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DHCP, DHCP, TRAP),
0948         .listeners_arr = {
0949             MLXSW_SP_RXL_MARK(IPV6_DHCP, DHCP, TRAP_TO_CPU, false),
0950         },
0951     },
0952     {
0953         .trap = MLXSW_SP_TRAP_CONTROL(ARP_REQUEST, NEIGH_DISCOVERY,
0954                           MIRROR),
0955         .listeners_arr = {
0956             MLXSW_SP_RXL_MARK(ROUTER_ARPBC, NEIGH_DISCOVERY,
0957                       TRAP_TO_CPU, false),
0958         },
0959     },
0960     {
0961         .trap = MLXSW_SP_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY,
0962                           MIRROR),
0963         .listeners_arr = {
0964             MLXSW_SP_RXL_MARK(ROUTER_ARPUC, NEIGH_DISCOVERY,
0965                       TRAP_TO_CPU, false),
0966         },
0967     },
0968     {
0969         .trap = MLXSW_SP_TRAP_CONTROL(ARP_OVERLAY, NEIGH_DISCOVERY,
0970                           TRAP),
0971         .listeners_arr = {
0972             MLXSW_SP_RXL_NO_MARK(NVE_DECAP_ARP, NEIGH_DISCOVERY,
0973                          TRAP_TO_CPU, false),
0974         },
0975     },
0976     {
0977         .trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_SOLICIT,
0978                           NEIGH_DISCOVERY, TRAP),
0979         .listeners_arr = {
0980             MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_SOLICITATION,
0981                       NEIGH_DISCOVERY, TRAP_TO_CPU, false),
0982         },
0983     },
0984     {
0985         .trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_ADVERT,
0986                           NEIGH_DISCOVERY, TRAP),
0987         .listeners_arr = {
0988             MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_ADVERTISEMENT,
0989                       NEIGH_DISCOVERY, TRAP_TO_CPU, false),
0990         },
0991     },
0992     {
0993         .trap = MLXSW_SP_TRAP_CONTROL(IPV4_BFD, BFD, TRAP),
0994         .listeners_arr = {
0995             MLXSW_SP_RXL_MARK(IPV4_BFD, BFD, TRAP_TO_CPU, false),
0996         },
0997     },
0998     {
0999         .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 
1165 static struct mlxsw_sp_trap_policer_item *
1166 mlxsw_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 
1179 static struct mlxsw_sp_trap_group_item *
1180 mlxsw_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 
1193 static struct mlxsw_sp_trap_item *
1194 mlxsw_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 
1207 static 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 
1227 static 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 
1236 static 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 
1283 static void mlxsw_sp_trap_policer_items_arr_fini(struct mlxsw_sp *mlxsw_sp)
1284 {
1285     kfree(mlxsw_sp->trap->policer_items_arr);
1286 }
1287 
1288 static 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 = devl_trap_policers_register(devlink,
1302                           &policer_item->policer, 1);
1303         if (err)
1304             goto err_trap_policer_register;
1305     }
1306 
1307     return 0;
1308 
1309 err_trap_policer_register:
1310     for (i--; i >= 0; i--) {
1311         policer_item = &trap->policer_items_arr[i];
1312         devl_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 
1319 static 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         devl_trap_policers_unregister(devlink,
1329                           &policer_item->policer, 1);
1330     }
1331     mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp);
1332 }
1333 
1334 static 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 
1366 static void mlxsw_sp_trap_group_items_arr_fini(struct mlxsw_sp *mlxsw_sp)
1367 {
1368     kfree(mlxsw_sp->trap->group_items_arr);
1369 }
1370 
1371 static 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 = devl_trap_groups_register(devlink, &group_item->group, 1);
1385         if (err)
1386             goto err_trap_group_register;
1387     }
1388 
1389     return 0;
1390 
1391 err_trap_group_register:
1392     for (i--; i >= 0; i--) {
1393         group_item = &trap->group_items_arr[i];
1394         devl_trap_groups_unregister(devlink, &group_item->group, 1);
1395     }
1396     mlxsw_sp_trap_group_items_arr_fini(mlxsw_sp);
1397     return err;
1398 }
1399 
1400 static void mlxsw_sp_trap_groups_fini(struct mlxsw_sp *mlxsw_sp)
1401 {
1402     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1403     struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1404     int i;
1405 
1406     for (i = trap->groups_count - 1; i >= 0; i--) {
1407         const struct mlxsw_sp_trap_group_item *group_item;
1408 
1409         group_item = &trap->group_items_arr[i];
1410         devl_trap_groups_unregister(devlink, &group_item->group, 1);
1411     }
1412     mlxsw_sp_trap_group_items_arr_fini(mlxsw_sp);
1413 }
1414 
1415 static bool
1416 mlxsw_sp_trap_listener_is_valid(const struct mlxsw_listener *listener)
1417 {
1418     return listener->trap_id != 0;
1419 }
1420 
1421 static int mlxsw_sp_trap_items_arr_init(struct mlxsw_sp *mlxsw_sp)
1422 {
1423     size_t common_traps_count = ARRAY_SIZE(mlxsw_sp_trap_items_arr);
1424     const struct mlxsw_sp_trap_item *spec_trap_items_arr;
1425     size_t elem_size = sizeof(struct mlxsw_sp_trap_item);
1426     struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1427     size_t traps_count, spec_traps_count;
1428     int err;
1429 
1430     err = mlxsw_sp->trap_ops->traps_init(mlxsw_sp, &spec_trap_items_arr,
1431                          &spec_traps_count);
1432     if (err)
1433         return err;
1434 
1435     /* The trap items array is created by concatenating the common trap
1436      * items and the ASIC-specific trap items.
1437      */
1438     traps_count = common_traps_count + spec_traps_count;
1439     trap->trap_items_arr = kcalloc(traps_count, elem_size, GFP_KERNEL);
1440     if (!trap->trap_items_arr)
1441         return -ENOMEM;
1442 
1443     memcpy(trap->trap_items_arr, mlxsw_sp_trap_items_arr,
1444            elem_size * common_traps_count);
1445     memcpy(trap->trap_items_arr + common_traps_count,
1446            spec_trap_items_arr, elem_size * spec_traps_count);
1447 
1448     trap->traps_count = traps_count;
1449 
1450     return 0;
1451 }
1452 
1453 static void mlxsw_sp_trap_items_arr_fini(struct mlxsw_sp *mlxsw_sp)
1454 {
1455     kfree(mlxsw_sp->trap->trap_items_arr);
1456 }
1457 
1458 static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)
1459 {
1460     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1461     struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1462     const struct mlxsw_sp_trap_item *trap_item;
1463     int err, i;
1464 
1465     err = mlxsw_sp_trap_items_arr_init(mlxsw_sp);
1466     if (err)
1467         return err;
1468 
1469     for (i = 0; i < trap->traps_count; i++) {
1470         trap_item = &trap->trap_items_arr[i];
1471         err = devl_traps_register(devlink, &trap_item->trap, 1,
1472                       mlxsw_sp);
1473         if (err)
1474             goto err_trap_register;
1475     }
1476 
1477     return 0;
1478 
1479 err_trap_register:
1480     for (i--; i >= 0; i--) {
1481         trap_item = &trap->trap_items_arr[i];
1482         devl_traps_unregister(devlink, &trap_item->trap, 1);
1483     }
1484     mlxsw_sp_trap_items_arr_fini(mlxsw_sp);
1485     return err;
1486 }
1487 
1488 static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp)
1489 {
1490     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1491     struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1492     int i;
1493 
1494     for (i = trap->traps_count - 1; i >= 0; i--) {
1495         const struct mlxsw_sp_trap_item *trap_item;
1496 
1497         trap_item = &trap->trap_items_arr[i];
1498         devl_traps_unregister(devlink, &trap_item->trap, 1);
1499     }
1500     mlxsw_sp_trap_items_arr_fini(mlxsw_sp);
1501 }
1502 
1503 int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp)
1504 {
1505     int err;
1506 
1507     err = mlxsw_sp_trap_cpu_policers_set(mlxsw_sp);
1508     if (err)
1509         return err;
1510 
1511     err = mlxsw_sp_trap_dummy_group_init(mlxsw_sp);
1512     if (err)
1513         return err;
1514 
1515     err = mlxsw_sp_trap_policers_init(mlxsw_sp);
1516     if (err)
1517         return err;
1518 
1519     err = mlxsw_sp_trap_groups_init(mlxsw_sp);
1520     if (err)
1521         goto err_trap_groups_init;
1522 
1523     err = mlxsw_sp_traps_init(mlxsw_sp);
1524     if (err)
1525         goto err_traps_init;
1526 
1527     return 0;
1528 
1529 err_traps_init:
1530     mlxsw_sp_trap_groups_fini(mlxsw_sp);
1531 err_trap_groups_init:
1532     mlxsw_sp_trap_policers_fini(mlxsw_sp);
1533     return err;
1534 }
1535 
1536 void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp)
1537 {
1538     mlxsw_sp_traps_fini(mlxsw_sp);
1539     mlxsw_sp_trap_groups_fini(mlxsw_sp);
1540     mlxsw_sp_trap_policers_fini(mlxsw_sp);
1541 }
1542 
1543 int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core,
1544                const struct devlink_trap *trap, void *trap_ctx)
1545 {
1546     struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1547     const struct mlxsw_sp_trap_item *trap_item;
1548     int i;
1549 
1550     trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);
1551     if (WARN_ON(!trap_item))
1552         return -EINVAL;
1553 
1554     for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) {
1555         const struct mlxsw_listener *listener;
1556         int err;
1557 
1558         listener = &trap_item->listeners_arr[i];
1559         if (!mlxsw_sp_trap_listener_is_valid(listener))
1560             continue;
1561         err = mlxsw_core_trap_register(mlxsw_core, listener, trap_ctx);
1562         if (err)
1563             return err;
1564     }
1565 
1566     return 0;
1567 }
1568 
1569 void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core,
1570             const struct devlink_trap *trap, void *trap_ctx)
1571 {
1572     struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1573     const struct mlxsw_sp_trap_item *trap_item;
1574     int i;
1575 
1576     trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);
1577     if (WARN_ON(!trap_item))
1578         return;
1579 
1580     for (i = MLXSW_SP_TRAP_LISTENERS_MAX - 1; i >= 0; i--) {
1581         const struct mlxsw_listener *listener;
1582 
1583         listener = &trap_item->listeners_arr[i];
1584         if (!mlxsw_sp_trap_listener_is_valid(listener))
1585             continue;
1586         mlxsw_core_trap_unregister(mlxsw_core, listener, trap_ctx);
1587     }
1588 }
1589 
1590 int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core,
1591                  const struct devlink_trap *trap,
1592                  enum devlink_trap_action action,
1593                  struct netlink_ext_ack *extack)
1594 {
1595     struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1596     const struct mlxsw_sp_trap_item *trap_item;
1597     int i;
1598 
1599     trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);
1600     if (WARN_ON(!trap_item))
1601         return -EINVAL;
1602 
1603     if (trap_item->is_source) {
1604         NL_SET_ERR_MSG_MOD(extack, "Changing the action of source traps is not supported");
1605         return -EOPNOTSUPP;
1606     }
1607 
1608     for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) {
1609         const struct mlxsw_listener *listener;
1610         bool enabled;
1611         int err;
1612 
1613         listener = &trap_item->listeners_arr[i];
1614         if (!mlxsw_sp_trap_listener_is_valid(listener))
1615             continue;
1616 
1617         switch (action) {
1618         case DEVLINK_TRAP_ACTION_DROP:
1619             enabled = false;
1620             break;
1621         case DEVLINK_TRAP_ACTION_TRAP:
1622             enabled = true;
1623             break;
1624         default:
1625             return -EINVAL;
1626         }
1627         err = mlxsw_core_trap_state_set(mlxsw_core, listener, enabled);
1628         if (err)
1629             return err;
1630     }
1631 
1632     return 0;
1633 }
1634 
1635 static int
1636 __mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core,
1637                const struct devlink_trap_group *group,
1638                u32 policer_id, struct netlink_ext_ack *extack)
1639 {
1640     struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1641     u16 hw_policer_id = MLXSW_REG_HTGT_INVALID_POLICER;
1642     const struct mlxsw_sp_trap_group_item *group_item;
1643     char htgt_pl[MLXSW_REG_HTGT_LEN];
1644 
1645     group_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, group->id);
1646     if (WARN_ON(!group_item))
1647         return -EINVAL;
1648 
1649     if (group_item->fixed_policer && policer_id != group->init_policer_id) {
1650         NL_SET_ERR_MSG_MOD(extack, "Changing the policer binding of this group is not supported");
1651         return -EOPNOTSUPP;
1652     }
1653 
1654     if (policer_id) {
1655         struct mlxsw_sp_trap_policer_item *policer_item;
1656 
1657         policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp,
1658                                  policer_id);
1659         if (WARN_ON(!policer_item))
1660             return -EINVAL;
1661         hw_policer_id = policer_item->hw_id;
1662     }
1663 
1664     mlxsw_reg_htgt_pack(htgt_pl, group_item->hw_group_id, hw_policer_id,
1665                 group_item->priority, group_item->priority);
1666     return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
1667 }
1668 
1669 int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core,
1670                  const struct devlink_trap_group *group)
1671 {
1672     return __mlxsw_sp_trap_group_init(mlxsw_core, group,
1673                       group->init_policer_id, NULL);
1674 }
1675 
1676 int mlxsw_sp_trap_group_set(struct mlxsw_core *mlxsw_core,
1677                 const struct devlink_trap_group *group,
1678                 const struct devlink_trap_policer *policer,
1679                 struct netlink_ext_ack *extack)
1680 {
1681     u32 policer_id = policer ? policer->id : 0;
1682 
1683     return __mlxsw_sp_trap_group_init(mlxsw_core, group, policer_id,
1684                       extack);
1685 }
1686 
1687 static int
1688 mlxsw_sp_trap_policer_item_init(struct mlxsw_sp *mlxsw_sp,
1689                 struct mlxsw_sp_trap_policer_item *policer_item)
1690 {
1691     struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
1692     u16 hw_id;
1693 
1694     /* We should be able to allocate a policer because the number of
1695      * policers we registered with devlink is in according with the number
1696      * of available policers.
1697      */
1698     hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers);
1699     if (WARN_ON(hw_id == trap->max_policers))
1700         return -ENOBUFS;
1701 
1702     __set_bit(hw_id, trap->policers_usage);
1703     policer_item->hw_id = hw_id;
1704 
1705     return 0;
1706 }
1707 
1708 static void
1709 mlxsw_sp_trap_policer_item_fini(struct mlxsw_sp *mlxsw_sp,
1710                 struct mlxsw_sp_trap_policer_item *policer_item)
1711 {
1712     __clear_bit(policer_item->hw_id, mlxsw_sp->trap->policers_usage);
1713 }
1714 
1715 static int mlxsw_sp_trap_policer_bs(u64 burst, u8 *p_burst_size,
1716                     struct netlink_ext_ack *extack)
1717 {
1718     int bs = fls64(burst) - 1;
1719 
1720     if (burst != (BIT_ULL(bs))) {
1721         NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two");
1722         return -EINVAL;
1723     }
1724 
1725     *p_burst_size = bs;
1726 
1727     return 0;
1728 }
1729 
1730 static int __mlxsw_sp_trap_policer_set(struct mlxsw_sp *mlxsw_sp, u16 hw_id,
1731                        u64 rate, u64 burst, bool clear_counter,
1732                        struct netlink_ext_ack *extack)
1733 {
1734     char qpcr_pl[MLXSW_REG_QPCR_LEN];
1735     u8 burst_size;
1736     int err;
1737 
1738     err = mlxsw_sp_trap_policer_bs(burst, &burst_size, extack);
1739     if (err)
1740         return err;
1741 
1742     mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M, false,
1743                 rate, burst_size);
1744     mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, clear_counter);
1745     return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
1746 }
1747 
1748 int mlxsw_sp_trap_policer_init(struct mlxsw_core *mlxsw_core,
1749                    const struct devlink_trap_policer *policer)
1750 {
1751     struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1752     struct mlxsw_sp_trap_policer_item *policer_item;
1753     int err;
1754 
1755     policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1756     if (WARN_ON(!policer_item))
1757         return -EINVAL;
1758 
1759     err = mlxsw_sp_trap_policer_item_init(mlxsw_sp, policer_item);
1760     if (err)
1761         return err;
1762 
1763     err = __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id,
1764                       policer->init_rate,
1765                       policer->init_burst, true, NULL);
1766     if (err)
1767         goto err_trap_policer_set;
1768 
1769     return 0;
1770 
1771 err_trap_policer_set:
1772     mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item);
1773     return err;
1774 }
1775 
1776 void mlxsw_sp_trap_policer_fini(struct mlxsw_core *mlxsw_core,
1777                 const struct devlink_trap_policer *policer)
1778 {
1779     struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1780     struct mlxsw_sp_trap_policer_item *policer_item;
1781 
1782     policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1783     if (WARN_ON(!policer_item))
1784         return;
1785 
1786     mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item);
1787 }
1788 
1789 int mlxsw_sp_trap_policer_set(struct mlxsw_core *mlxsw_core,
1790                   const struct devlink_trap_policer *policer,
1791                   u64 rate, u64 burst,
1792                   struct netlink_ext_ack *extack)
1793 {
1794     struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1795     struct mlxsw_sp_trap_policer_item *policer_item;
1796 
1797     policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1798     if (WARN_ON(!policer_item))
1799         return -EINVAL;
1800 
1801     return __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id,
1802                        rate, burst, false, extack);
1803 }
1804 
1805 int
1806 mlxsw_sp_trap_policer_counter_get(struct mlxsw_core *mlxsw_core,
1807                   const struct devlink_trap_policer *policer,
1808                   u64 *p_drops)
1809 {
1810     struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
1811     struct mlxsw_sp_trap_policer_item *policer_item;
1812     char qpcr_pl[MLXSW_REG_QPCR_LEN];
1813     int err;
1814 
1815     policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
1816     if (WARN_ON(!policer_item))
1817         return -EINVAL;
1818 
1819     mlxsw_reg_qpcr_pack(qpcr_pl, policer_item->hw_id,
1820                 MLXSW_REG_QPCR_IR_UNITS_M, false, 0, 0);
1821     err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
1822     if (err)
1823         return err;
1824 
1825     *p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl);
1826 
1827     return 0;
1828 }
1829 
1830 int mlxsw_sp_trap_group_policer_hw_id_get(struct mlxsw_sp *mlxsw_sp, u16 id,
1831                       bool *p_enabled, u16 *p_hw_id)
1832 {
1833     struct mlxsw_sp_trap_policer_item *pol_item;
1834     struct mlxsw_sp_trap_group_item *gr_item;
1835     u32 pol_id;
1836 
1837     gr_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, id);
1838     if (!gr_item)
1839         return -ENOENT;
1840 
1841     pol_id = gr_item->group.init_policer_id;
1842     if (!pol_id) {
1843         *p_enabled = false;
1844         return 0;
1845     }
1846 
1847     pol_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, pol_id);
1848     if (WARN_ON(!pol_item))
1849         return -ENOENT;
1850 
1851     *p_enabled = true;
1852     *p_hw_id = pol_item->hw_id;
1853     return 0;
1854 }
1855 
1856 static const struct mlxsw_sp_trap_group_item
1857 mlxsw_sp1_trap_group_items_arr[] = {
1858     {
1859         .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0),
1860         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PKT_SAMPLE,
1861         .priority = 0,
1862     },
1863 };
1864 
1865 static const struct mlxsw_sp_trap_item
1866 mlxsw_sp1_trap_items_arr[] = {
1867     {
1868         .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_SAMPLE, ACL_SAMPLE,
1869                           MIRROR),
1870         .listeners_arr = {
1871             MLXSW_RXL(mlxsw_sp_rx_sample_listener, PKT_SAMPLE,
1872                   MIRROR_TO_CPU, false, SP_PKT_SAMPLE, DISCARD),
1873         },
1874     },
1875 };
1876 
1877 static int
1878 mlxsw_sp1_trap_groups_init(struct mlxsw_sp *mlxsw_sp,
1879                const struct mlxsw_sp_trap_group_item **arr,
1880                size_t *p_groups_count)
1881 {
1882     *arr = mlxsw_sp1_trap_group_items_arr;
1883     *p_groups_count = ARRAY_SIZE(mlxsw_sp1_trap_group_items_arr);
1884 
1885     return 0;
1886 }
1887 
1888 static int mlxsw_sp1_traps_init(struct mlxsw_sp *mlxsw_sp,
1889                 const struct mlxsw_sp_trap_item **arr,
1890                 size_t *p_traps_count)
1891 {
1892     *arr = mlxsw_sp1_trap_items_arr;
1893     *p_traps_count = ARRAY_SIZE(mlxsw_sp1_trap_items_arr);
1894 
1895     return 0;
1896 }
1897 
1898 const struct mlxsw_sp_trap_ops mlxsw_sp1_trap_ops = {
1899     .groups_init = mlxsw_sp1_trap_groups_init,
1900     .traps_init = mlxsw_sp1_traps_init,
1901 };
1902 
1903 static const struct mlxsw_sp_trap_group_item
1904 mlxsw_sp2_trap_group_items_arr[] = {
1905     {
1906         .group = DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 20),
1907         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BUFFER_DISCARDS,
1908         .priority = 0,
1909         .fixed_policer = true,
1910     },
1911     {
1912         .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0),
1913         .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PKT_SAMPLE,
1914         .priority = 0,
1915         .fixed_policer = true,
1916     },
1917 };
1918 
1919 static const struct mlxsw_sp_trap_item
1920 mlxsw_sp2_trap_items_arr[] = {
1921     {
1922         .trap = MLXSW_SP_TRAP_BUFFER_DROP(EARLY_DROP),
1923         .listeners_arr = {
1924             MLXSW_SP_RXL_BUFFER_DISCARD(INGRESS_WRED),
1925         },
1926         .is_source = true,
1927     },
1928     {
1929         .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_SAMPLE, ACL_SAMPLE,
1930                           MIRROR),
1931         .listeners_arr = {
1932             MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_listener, 1,
1933                      SP_PKT_SAMPLE,
1934                      MLXSW_SP_MIRROR_REASON_INGRESS),
1935             MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_tx_listener, 1,
1936                      SP_PKT_SAMPLE,
1937                      MLXSW_SP_MIRROR_REASON_EGRESS),
1938             MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_acl_listener, 1,
1939                      SP_PKT_SAMPLE,
1940                      MLXSW_SP_MIRROR_REASON_POLICY_ENGINE),
1941         },
1942     },
1943 };
1944 
1945 static int
1946 mlxsw_sp2_trap_groups_init(struct mlxsw_sp *mlxsw_sp,
1947                const struct mlxsw_sp_trap_group_item **arr,
1948                size_t *p_groups_count)
1949 {
1950     *arr = mlxsw_sp2_trap_group_items_arr;
1951     *p_groups_count = ARRAY_SIZE(mlxsw_sp2_trap_group_items_arr);
1952 
1953     return 0;
1954 }
1955 
1956 static int mlxsw_sp2_traps_init(struct mlxsw_sp *mlxsw_sp,
1957                 const struct mlxsw_sp_trap_item **arr,
1958                 size_t *p_traps_count)
1959 {
1960     *arr = mlxsw_sp2_trap_items_arr;
1961     *p_traps_count = ARRAY_SIZE(mlxsw_sp2_trap_items_arr);
1962 
1963     return 0;
1964 }
1965 
1966 const struct mlxsw_sp_trap_ops mlxsw_sp2_trap_ops = {
1967     .groups_init = mlxsw_sp2_trap_groups_init,
1968     .traps_init = mlxsw_sp2_traps_init,
1969 };