cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

spectrum_trap.c (53162B)


      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				  true, 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};