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 
15 /* All driver-specific traps must be documented in
16  * Documentation/networking/devlink/mlxsw.rst
17  */
18 enum {
19 	DEVLINK_MLXSW_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX,
20 	DEVLINK_MLXSW_TRAP_ID_IRIF_DISABLED,
21 	DEVLINK_MLXSW_TRAP_ID_ERIF_DISABLED,
22 };
23 
24 #define DEVLINK_MLXSW_TRAP_NAME_IRIF_DISABLED \
25 	"irif_disabled"
26 #define DEVLINK_MLXSW_TRAP_NAME_ERIF_DISABLED \
27 	"erif_disabled"
28 
29 #define MLXSW_SP_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT
30 
31 static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
32 				u8 local_port,
33 				struct mlxsw_sp_port *mlxsw_sp_port)
34 {
35 	struct mlxsw_sp_port_pcpu_stats *pcpu_stats;
36 
37 	if (unlikely(!mlxsw_sp_port)) {
38 		dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n",
39 				     local_port);
40 		kfree_skb(skb);
41 		return -EINVAL;
42 	}
43 
44 	skb->dev = mlxsw_sp_port->dev;
45 
46 	pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats);
47 	u64_stats_update_begin(&pcpu_stats->syncp);
48 	pcpu_stats->rx_packets++;
49 	pcpu_stats->rx_bytes += skb->len;
50 	u64_stats_update_end(&pcpu_stats->syncp);
51 
52 	skb->protocol = eth_type_trans(skb, skb->dev);
53 
54 	return 0;
55 }
56 
57 static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port,
58 				      void *trap_ctx)
59 {
60 	struct devlink_port *in_devlink_port;
61 	struct mlxsw_sp_port *mlxsw_sp_port;
62 	struct mlxsw_sp *mlxsw_sp;
63 	struct devlink *devlink;
64 	int err;
65 
66 	mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
67 	mlxsw_sp_port = mlxsw_sp->ports[local_port];
68 
69 	err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
70 	if (err)
71 		return;
72 
73 	devlink = priv_to_devlink(mlxsw_sp->core);
74 	in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
75 							   local_port);
76 	skb_push(skb, ETH_HLEN);
77 	devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL);
78 	consume_skb(skb);
79 }
80 
81 static void mlxsw_sp_rx_acl_drop_listener(struct sk_buff *skb, u8 local_port,
82 					  void *trap_ctx)
83 {
84 	u32 cookie_index = mlxsw_skb_cb(skb)->cookie_index;
85 	const struct flow_action_cookie *fa_cookie;
86 	struct devlink_port *in_devlink_port;
87 	struct mlxsw_sp_port *mlxsw_sp_port;
88 	struct mlxsw_sp *mlxsw_sp;
89 	struct devlink *devlink;
90 	int err;
91 
92 	mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
93 	mlxsw_sp_port = mlxsw_sp->ports[local_port];
94 
95 	err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
96 	if (err)
97 		return;
98 
99 	devlink = priv_to_devlink(mlxsw_sp->core);
100 	in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
101 							   local_port);
102 	skb_push(skb, ETH_HLEN);
103 	rcu_read_lock();
104 	fa_cookie = mlxsw_sp_acl_act_cookie_lookup(mlxsw_sp, cookie_index);
105 	devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, fa_cookie);
106 	rcu_read_unlock();
107 	consume_skb(skb);
108 }
109 
110 static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port,
111 					   void *trap_ctx)
112 {
113 	struct devlink_port *in_devlink_port;
114 	struct mlxsw_sp_port *mlxsw_sp_port;
115 	struct mlxsw_sp *mlxsw_sp;
116 	struct devlink *devlink;
117 	int err;
118 
119 	mlxsw_sp = devlink_trap_ctx_priv(trap_ctx);
120 	mlxsw_sp_port = mlxsw_sp->ports[local_port];
121 
122 	err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port);
123 	if (err)
124 		return;
125 
126 	devlink = priv_to_devlink(mlxsw_sp->core);
127 	in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
128 							   local_port);
129 	skb_push(skb, ETH_HLEN);
130 	devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL);
131 	skb_pull(skb, ETH_HLEN);
132 	skb->offload_fwd_mark = 1;
133 	netif_receive_skb(skb);
134 }
135 
136 #define MLXSW_SP_TRAP_DROP(_id, _group_id)				      \
137 	DEVLINK_TRAP_GENERIC(DROP, DROP, _id,				      \
138 			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
139 			     MLXSW_SP_TRAP_METADATA)
140 
141 #define MLXSW_SP_TRAP_DROP_EXT(_id, _group_id, _metadata)		      \
142 	DEVLINK_TRAP_GENERIC(DROP, DROP, _id,				      \
143 			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
144 			     MLXSW_SP_TRAP_METADATA | (_metadata))
145 
146 #define MLXSW_SP_TRAP_DRIVER_DROP(_id, _group_id)			      \
147 	DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_MLXSW_TRAP_ID_##_id,	      \
148 			    DEVLINK_MLXSW_TRAP_NAME_##_id,		      \
149 			    DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
150 			    MLXSW_SP_TRAP_METADATA)
151 
152 #define MLXSW_SP_TRAP_EXCEPTION(_id, _group_id)		      \
153 	DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id,			      \
154 			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
155 			     MLXSW_SP_TRAP_METADATA)
156 
157 #define MLXSW_SP_RXL_DISCARD(_id, _group_id)				      \
158 	MLXSW_RXL_DIS(mlxsw_sp_rx_drop_listener, DISCARD_##_id,		      \
159 		      TRAP_EXCEPTION_TO_CPU, false, SP_##_group_id,	      \
160 		      SET_FW_DEFAULT, SP_##_group_id)
161 
162 #define MLXSW_SP_RXL_ACL_DISCARD(_id, _en_group_id, _dis_group_id)	      \
163 	MLXSW_RXL_DIS(mlxsw_sp_rx_acl_drop_listener, DISCARD_##_id,	      \
164 		      TRAP_EXCEPTION_TO_CPU, false, SP_##_en_group_id,	      \
165 		      SET_FW_DEFAULT, SP_##_dis_group_id)
166 
167 #define MLXSW_SP_RXL_EXCEPTION(_id, _group_id, _action)			      \
168 	MLXSW_RXL(mlxsw_sp_rx_exception_listener, _id,			      \
169 		   _action, false, SP_##_group_id, SET_FW_DEFAULT)
170 
171 #define MLXSW_SP_TRAP_POLICER(_id, _rate, _burst)			      \
172 	DEVLINK_TRAP_POLICER(_id, _rate, _burst,			      \
173 			     MLXSW_REG_QPCR_HIGHEST_CIR,		      \
174 			     MLXSW_REG_QPCR_LOWEST_CIR,			      \
175 			     1 << MLXSW_REG_QPCR_HIGHEST_CBS,		      \
176 			     1 << MLXSW_REG_QPCR_LOWEST_CBS)
177 
178 /* Ordered by policer identifier */
179 static const struct devlink_trap_policer mlxsw_sp_trap_policers_arr[] = {
180 	MLXSW_SP_TRAP_POLICER(1, 10 * 1024, 128),
181 };
182 
183 static const struct devlink_trap_group mlxsw_sp_trap_groups_arr[] = {
184 	DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 1),
185 	DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1),
186 	DEVLINK_TRAP_GROUP_GENERIC(TUNNEL_DROPS, 1),
187 	DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 1),
188 };
189 
190 static const struct devlink_trap mlxsw_sp_traps_arr[] = {
191 	MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS),
192 	MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS),
193 	MLXSW_SP_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS),
194 	MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS),
195 	MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS),
196 	MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS),
197 	MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS),
198 	MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS),
199 	MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS),
200 	MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS),
201 	MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS),
202 	MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS),
203 	MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS),
204 	MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS),
205 	MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE, L3_DROPS),
206 	MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DROPS),
207 	MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_DROPS),
208 	MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_DROPS),
209 	MLXSW_SP_TRAP_EXCEPTION(RPF, L3_DROPS),
210 	MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_DROPS),
211 	MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH, L3_DROPS),
212 	MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS, L3_DROPS),
213 	MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS, L3_DROPS),
214 	MLXSW_SP_TRAP_DRIVER_DROP(IRIF_DISABLED, L3_DROPS),
215 	MLXSW_SP_TRAP_DRIVER_DROP(ERIF_DISABLED, L3_DROPS),
216 	MLXSW_SP_TRAP_DROP(NON_ROUTABLE, L3_DROPS),
217 	MLXSW_SP_TRAP_EXCEPTION(DECAP_ERROR, TUNNEL_DROPS),
218 	MLXSW_SP_TRAP_DROP(OVERLAY_SMAC_MC, TUNNEL_DROPS),
219 	MLXSW_SP_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, ACL_DROPS,
220 			       DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),
221 	MLXSW_SP_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, ACL_DROPS,
222 			       DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),
223 };
224 
225 static const struct mlxsw_listener mlxsw_sp_listeners_arr[] = {
226 	MLXSW_SP_RXL_DISCARD(ING_PACKET_SMAC_MC, L2_DISCARDS),
227 	MLXSW_SP_RXL_DISCARD(ING_SWITCH_VTAG_ALLOW, L2_DISCARDS),
228 	MLXSW_SP_RXL_DISCARD(ING_SWITCH_VLAN, L2_DISCARDS),
229 	MLXSW_SP_RXL_DISCARD(ING_SWITCH_STP, L2_DISCARDS),
230 	MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS),
231 	MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS),
232 	MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS),
233 	MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS),
234 	MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET, L3_DISCARDS),
235 	MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC, L3_DISCARDS),
236 	MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS),
237 	MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS),
238 	MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS),
239 	MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR, L3_DISCARDS),
240 	MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC, L3_DISCARDS),
241 	MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE, L3_DISCARDS),
242 	MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DISCARDS),
243 	MLXSW_SP_RXL_EXCEPTION(MTUERROR, L3_DISCARDS, TRAP_TO_CPU),
244 	MLXSW_SP_RXL_EXCEPTION(TTLERROR, L3_DISCARDS, TRAP_TO_CPU),
245 	MLXSW_SP_RXL_EXCEPTION(RPF, L3_DISCARDS, TRAP_TO_CPU),
246 	MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, L3_DISCARDS, TRAP_TO_CPU),
247 	MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, L3_DISCARDS, TRAP_TO_CPU),
248 	MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, L3_DISCARDS, TRAP_TO_CPU),
249 	MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER3, L3_DISCARDS,
250 			       TRAP_EXCEPTION_TO_CPU),
251 	MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4, L3_DISCARDS,
252 			       TRAP_EXCEPTION_TO_CPU),
253 	MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6, L3_DISCARDS,
254 			       TRAP_EXCEPTION_TO_CPU),
255 	MLXSW_SP_RXL_DISCARD(ROUTER_IRIF_EN, L3_DISCARDS),
256 	MLXSW_SP_RXL_DISCARD(ROUTER_ERIF_EN, L3_DISCARDS),
257 	MLXSW_SP_RXL_DISCARD(NON_ROUTABLE, L3_DISCARDS),
258 	MLXSW_SP_RXL_EXCEPTION(DECAP_ECN0, TUNNEL_DISCARDS,
259 			       TRAP_EXCEPTION_TO_CPU),
260 	MLXSW_SP_RXL_EXCEPTION(IPIP_DECAP_ERROR, TUNNEL_DISCARDS,
261 			       TRAP_EXCEPTION_TO_CPU),
262 	MLXSW_SP_RXL_EXCEPTION(DISCARD_DEC_PKT, TUNNEL_DISCARDS,
263 			       TRAP_EXCEPTION_TO_CPU),
264 	MLXSW_SP_RXL_DISCARD(OVERLAY_SMAC_MC, TUNNEL_DISCARDS),
265 	MLXSW_SP_RXL_ACL_DISCARD(INGRESS_ACL, ACL_DISCARDS, DUMMY),
266 	MLXSW_SP_RXL_ACL_DISCARD(EGRESS_ACL, ACL_DISCARDS, DUMMY),
267 };
268 
269 /* Mapping between hardware trap and devlink trap. Multiple hardware traps can
270  * be mapped to the same devlink trap. Order is according to
271  * 'mlxsw_sp_listeners_arr'.
272  */
273 static const u16 mlxsw_sp_listener_devlink_map[] = {
274 	DEVLINK_TRAP_GENERIC_ID_SMAC_MC,
275 	DEVLINK_TRAP_GENERIC_ID_VLAN_TAG_MISMATCH,
276 	DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER,
277 	DEVLINK_TRAP_GENERIC_ID_INGRESS_STP_FILTER,
278 	DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST,
279 	DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST,
280 	DEVLINK_TRAP_GENERIC_ID_PORT_LOOPBACK_FILTER,
281 	DEVLINK_TRAP_GENERIC_ID_BLACKHOLE_ROUTE,
282 	DEVLINK_TRAP_GENERIC_ID_NON_IP_PACKET,
283 	DEVLINK_TRAP_GENERIC_ID_UC_DIP_MC_DMAC,
284 	DEVLINK_TRAP_GENERIC_ID_DIP_LB,
285 	DEVLINK_TRAP_GENERIC_ID_SIP_MC,
286 	DEVLINK_TRAP_GENERIC_ID_SIP_LB,
287 	DEVLINK_TRAP_GENERIC_ID_CORRUPTED_IP_HDR,
288 	DEVLINK_TRAP_GENERIC_ID_IPV4_SIP_BC,
289 	DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_RESERVED_SCOPE,
290 	DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE,
291 	DEVLINK_TRAP_GENERIC_ID_MTU_ERROR,
292 	DEVLINK_TRAP_GENERIC_ID_TTL_ERROR,
293 	DEVLINK_TRAP_GENERIC_ID_RPF,
294 	DEVLINK_TRAP_GENERIC_ID_REJECT_ROUTE,
295 	DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH,
296 	DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH,
297 	DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH,
298 	DEVLINK_TRAP_GENERIC_ID_IPV4_LPM_UNICAST_MISS,
299 	DEVLINK_TRAP_GENERIC_ID_IPV6_LPM_UNICAST_MISS,
300 	DEVLINK_MLXSW_TRAP_ID_IRIF_DISABLED,
301 	DEVLINK_MLXSW_TRAP_ID_ERIF_DISABLED,
302 	DEVLINK_TRAP_GENERIC_ID_NON_ROUTABLE,
303 	DEVLINK_TRAP_GENERIC_ID_DECAP_ERROR,
304 	DEVLINK_TRAP_GENERIC_ID_DECAP_ERROR,
305 	DEVLINK_TRAP_GENERIC_ID_DECAP_ERROR,
306 	DEVLINK_TRAP_GENERIC_ID_OVERLAY_SMAC_MC,
307 	DEVLINK_TRAP_GENERIC_ID_INGRESS_FLOW_ACTION_DROP,
308 	DEVLINK_TRAP_GENERIC_ID_EGRESS_FLOW_ACTION_DROP,
309 };
310 
311 #define MLXSW_SP_THIN_POLICER_ID	(MLXSW_REG_HTGT_TRAP_GROUP_MAX + 1)
312 
313 static struct mlxsw_sp_trap_policer_item *
314 mlxsw_sp_trap_policer_item_lookup(struct mlxsw_sp *mlxsw_sp, u32 id)
315 {
316 	struct mlxsw_sp_trap_policer_item *policer_item;
317 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
318 
319 	list_for_each_entry(policer_item, &trap->policer_item_list, list) {
320 		if (policer_item->id == id)
321 			return policer_item;
322 	}
323 
324 	return NULL;
325 }
326 
327 static int mlxsw_sp_trap_cpu_policers_set(struct mlxsw_sp *mlxsw_sp)
328 {
329 	char qpcr_pl[MLXSW_REG_QPCR_LEN];
330 
331 	/* The purpose of "thin" policer is to drop as many packets
332 	 * as possible. The dummy group is using it.
333 	 */
334 	__set_bit(MLXSW_SP_THIN_POLICER_ID, mlxsw_sp->trap->policers_usage);
335 	mlxsw_reg_qpcr_pack(qpcr_pl, MLXSW_SP_THIN_POLICER_ID,
336 			    MLXSW_REG_QPCR_IR_UNITS_M, false, 1, 4);
337 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
338 }
339 
340 static int mlxsw_sp_trap_dummy_group_init(struct mlxsw_sp *mlxsw_sp)
341 {
342 	char htgt_pl[MLXSW_REG_HTGT_LEN];
343 
344 	mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SP_DUMMY,
345 			    MLXSW_SP_THIN_POLICER_ID, 0, 1);
346 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl);
347 }
348 
349 static int mlxsw_sp_trap_policers_init(struct mlxsw_sp *mlxsw_sp)
350 {
351 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
352 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
353 	u64 free_policers = 0;
354 	u32 last_id = 0;
355 	int err, i;
356 
357 	for_each_clear_bit(i, trap->policers_usage, trap->max_policers)
358 		free_policers++;
359 
360 	if (ARRAY_SIZE(mlxsw_sp_trap_policers_arr) > free_policers) {
361 		dev_err(mlxsw_sp->bus_info->dev, "Exceeded number of supported packet trap policers\n");
362 		return -ENOBUFS;
363 	}
364 
365 	trap->policers_arr = kcalloc(free_policers,
366 				     sizeof(struct devlink_trap_policer),
367 				     GFP_KERNEL);
368 	if (!trap->policers_arr)
369 		return -ENOMEM;
370 
371 	trap->policers_count = free_policers;
372 
373 	for (i = 0; i < free_policers; i++) {
374 		const struct devlink_trap_policer *policer;
375 
376 		if (i < ARRAY_SIZE(mlxsw_sp_trap_policers_arr)) {
377 			policer = &mlxsw_sp_trap_policers_arr[i];
378 			trap->policers_arr[i] = *policer;
379 			last_id = policer->id;
380 		} else {
381 			/* Use parameters set for first policer and override
382 			 * relevant ones.
383 			 */
384 			policer = &mlxsw_sp_trap_policers_arr[0];
385 			trap->policers_arr[i] = *policer;
386 			trap->policers_arr[i].id = ++last_id;
387 			trap->policers_arr[i].init_rate = 1;
388 			trap->policers_arr[i].init_burst = 16;
389 		}
390 	}
391 
392 	INIT_LIST_HEAD(&trap->policer_item_list);
393 
394 	err = devlink_trap_policers_register(devlink, trap->policers_arr,
395 					     trap->policers_count);
396 	if (err)
397 		goto err_trap_policers_register;
398 
399 	return 0;
400 
401 err_trap_policers_register:
402 	kfree(trap->policers_arr);
403 	return err;
404 }
405 
406 static void mlxsw_sp_trap_policers_fini(struct mlxsw_sp *mlxsw_sp)
407 {
408 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
409 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
410 
411 	devlink_trap_policers_unregister(devlink, trap->policers_arr,
412 					 trap->policers_count);
413 	WARN_ON(!list_empty(&trap->policer_item_list));
414 	kfree(trap->policers_arr);
415 }
416 
417 int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp)
418 {
419 	size_t groups_count = ARRAY_SIZE(mlxsw_sp_trap_groups_arr);
420 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
421 	int err;
422 
423 	err = mlxsw_sp_trap_cpu_policers_set(mlxsw_sp);
424 	if (err)
425 		return err;
426 
427 	err = mlxsw_sp_trap_dummy_group_init(mlxsw_sp);
428 	if (err)
429 		return err;
430 
431 	if (WARN_ON(ARRAY_SIZE(mlxsw_sp_listener_devlink_map) !=
432 		    ARRAY_SIZE(mlxsw_sp_listeners_arr)))
433 		return -EINVAL;
434 
435 	err = mlxsw_sp_trap_policers_init(mlxsw_sp);
436 	if (err)
437 		return err;
438 
439 	err = devlink_trap_groups_register(devlink, mlxsw_sp_trap_groups_arr,
440 					   groups_count);
441 	if (err)
442 		goto err_trap_groups_register;
443 
444 	err = devlink_traps_register(devlink, mlxsw_sp_traps_arr,
445 				     ARRAY_SIZE(mlxsw_sp_traps_arr), mlxsw_sp);
446 	if (err)
447 		goto err_traps_register;
448 
449 	return 0;
450 
451 err_traps_register:
452 	devlink_trap_groups_unregister(devlink, mlxsw_sp_trap_groups_arr,
453 				       groups_count);
454 err_trap_groups_register:
455 	mlxsw_sp_trap_policers_fini(mlxsw_sp);
456 	return err;
457 }
458 
459 void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp)
460 {
461 	size_t groups_count = ARRAY_SIZE(mlxsw_sp_trap_groups_arr);
462 	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
463 
464 	devlink_traps_unregister(devlink, mlxsw_sp_traps_arr,
465 				 ARRAY_SIZE(mlxsw_sp_traps_arr));
466 	devlink_trap_groups_unregister(devlink, mlxsw_sp_trap_groups_arr,
467 				       groups_count);
468 	mlxsw_sp_trap_policers_fini(mlxsw_sp);
469 }
470 
471 int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core,
472 		       const struct devlink_trap *trap, void *trap_ctx)
473 {
474 	int i;
475 
476 	for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) {
477 		const struct mlxsw_listener *listener;
478 		int err;
479 
480 		if (mlxsw_sp_listener_devlink_map[i] != trap->id)
481 			continue;
482 		listener = &mlxsw_sp_listeners_arr[i];
483 
484 		err = mlxsw_core_trap_register(mlxsw_core, listener, trap_ctx);
485 		if (err)
486 			return err;
487 	}
488 
489 	return 0;
490 }
491 
492 void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core,
493 			const struct devlink_trap *trap, void *trap_ctx)
494 {
495 	int i;
496 
497 	for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) {
498 		const struct mlxsw_listener *listener;
499 
500 		if (mlxsw_sp_listener_devlink_map[i] != trap->id)
501 			continue;
502 		listener = &mlxsw_sp_listeners_arr[i];
503 
504 		mlxsw_core_trap_unregister(mlxsw_core, listener, trap_ctx);
505 	}
506 }
507 
508 int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core,
509 			     const struct devlink_trap *trap,
510 			     enum devlink_trap_action action)
511 {
512 	int i;
513 
514 	for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) {
515 		const struct mlxsw_listener *listener;
516 		bool enabled;
517 		int err;
518 
519 		if (mlxsw_sp_listener_devlink_map[i] != trap->id)
520 			continue;
521 		listener = &mlxsw_sp_listeners_arr[i];
522 		switch (action) {
523 		case DEVLINK_TRAP_ACTION_DROP:
524 			enabled = false;
525 			break;
526 		case DEVLINK_TRAP_ACTION_TRAP:
527 			enabled = true;
528 			break;
529 		default:
530 			return -EINVAL;
531 		}
532 		err = mlxsw_core_trap_state_set(mlxsw_core, listener, enabled);
533 		if (err)
534 			return err;
535 	}
536 
537 	return 0;
538 }
539 
540 static int
541 __mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core,
542 			   const struct devlink_trap_group *group,
543 			   u32 policer_id)
544 {
545 	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
546 	u16 hw_policer_id = MLXSW_REG_HTGT_INVALID_POLICER;
547 	char htgt_pl[MLXSW_REG_HTGT_LEN];
548 	u8 priority, tc, group_id;
549 
550 	switch (group->id) {
551 	case DEVLINK_TRAP_GROUP_GENERIC_ID_L2_DROPS:
552 		group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS;
553 		priority = 0;
554 		tc = 1;
555 		break;
556 	case DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS:
557 		group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS;
558 		priority = 0;
559 		tc = 1;
560 		break;
561 	case DEVLINK_TRAP_GROUP_GENERIC_ID_TUNNEL_DROPS:
562 		group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS;
563 		priority = 0;
564 		tc = 1;
565 		break;
566 	case DEVLINK_TRAP_GROUP_GENERIC_ID_ACL_DROPS:
567 		group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS;
568 		priority = 0;
569 		tc = 1;
570 		break;
571 	default:
572 		return -EINVAL;
573 	}
574 
575 	if (policer_id) {
576 		struct mlxsw_sp_trap_policer_item *policer_item;
577 
578 		policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp,
579 								 policer_id);
580 		if (WARN_ON(!policer_item))
581 			return -EINVAL;
582 		hw_policer_id = policer_item->hw_id;
583 	}
584 
585 	mlxsw_reg_htgt_pack(htgt_pl, group_id, hw_policer_id, priority, tc);
586 	return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
587 }
588 
589 int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core,
590 			     const struct devlink_trap_group *group)
591 {
592 	return __mlxsw_sp_trap_group_init(mlxsw_core, group,
593 					  group->init_policer_id);
594 }
595 
596 int mlxsw_sp_trap_group_set(struct mlxsw_core *mlxsw_core,
597 			    const struct devlink_trap_group *group,
598 			    const struct devlink_trap_policer *policer)
599 {
600 	u32 policer_id = policer ? policer->id : 0;
601 
602 	return __mlxsw_sp_trap_group_init(mlxsw_core, group, policer_id);
603 }
604 
605 static struct mlxsw_sp_trap_policer_item *
606 mlxsw_sp_trap_policer_item_init(struct mlxsw_sp *mlxsw_sp, u32 id)
607 {
608 	struct mlxsw_sp_trap_policer_item *policer_item;
609 	struct mlxsw_sp_trap *trap = mlxsw_sp->trap;
610 	u16 hw_id;
611 
612 	/* We should be able to allocate a policer because the number of
613 	 * policers we registered with devlink is in according with the number
614 	 * of available policers.
615 	 */
616 	hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers);
617 	if (WARN_ON(hw_id == trap->max_policers))
618 		return ERR_PTR(-ENOBUFS);
619 
620 	policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL);
621 	if (!policer_item)
622 		return ERR_PTR(-ENOMEM);
623 
624 	__set_bit(hw_id, trap->policers_usage);
625 	policer_item->hw_id = hw_id;
626 	policer_item->id = id;
627 	list_add_tail(&policer_item->list, &trap->policer_item_list);
628 
629 	return policer_item;
630 }
631 
632 static void
633 mlxsw_sp_trap_policer_item_fini(struct mlxsw_sp *mlxsw_sp,
634 				struct mlxsw_sp_trap_policer_item *policer_item)
635 {
636 	list_del(&policer_item->list);
637 	__clear_bit(policer_item->hw_id, mlxsw_sp->trap->policers_usage);
638 	kfree(policer_item);
639 }
640 
641 static int mlxsw_sp_trap_policer_bs(u64 burst, u8 *p_burst_size,
642 				    struct netlink_ext_ack *extack)
643 {
644 	int bs = fls64(burst) - 1;
645 
646 	if (burst != (BIT_ULL(bs))) {
647 		NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two");
648 		return -EINVAL;
649 	}
650 
651 	*p_burst_size = bs;
652 
653 	return 0;
654 }
655 
656 static int __mlxsw_sp_trap_policer_set(struct mlxsw_sp *mlxsw_sp, u16 hw_id,
657 				       u64 rate, u64 burst, bool clear_counter,
658 				       struct netlink_ext_ack *extack)
659 {
660 	char qpcr_pl[MLXSW_REG_QPCR_LEN];
661 	u8 burst_size;
662 	int err;
663 
664 	err = mlxsw_sp_trap_policer_bs(burst, &burst_size, extack);
665 	if (err)
666 		return err;
667 
668 	mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M, false,
669 			    rate, burst_size);
670 	mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, clear_counter);
671 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
672 }
673 
674 int mlxsw_sp_trap_policer_init(struct mlxsw_core *mlxsw_core,
675 			       const struct devlink_trap_policer *policer)
676 {
677 	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
678 	struct mlxsw_sp_trap_policer_item *policer_item;
679 	int err;
680 
681 	policer_item = mlxsw_sp_trap_policer_item_init(mlxsw_sp, policer->id);
682 	if (IS_ERR(policer_item))
683 		return PTR_ERR(policer_item);
684 
685 	err = __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id,
686 					  policer->init_rate,
687 					  policer->init_burst, true, NULL);
688 	if (err)
689 		goto err_trap_policer_set;
690 
691 	return 0;
692 
693 err_trap_policer_set:
694 	mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item);
695 	return err;
696 }
697 
698 void mlxsw_sp_trap_policer_fini(struct mlxsw_core *mlxsw_core,
699 				const struct devlink_trap_policer *policer)
700 {
701 	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
702 	struct mlxsw_sp_trap_policer_item *policer_item;
703 
704 	policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
705 	if (WARN_ON(!policer_item))
706 		return;
707 
708 	mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item);
709 }
710 
711 int mlxsw_sp_trap_policer_set(struct mlxsw_core *mlxsw_core,
712 			      const struct devlink_trap_policer *policer,
713 			      u64 rate, u64 burst,
714 			      struct netlink_ext_ack *extack)
715 {
716 	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
717 	struct mlxsw_sp_trap_policer_item *policer_item;
718 
719 	policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
720 	if (WARN_ON(!policer_item))
721 		return -EINVAL;
722 
723 	return __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id,
724 					   rate, burst, false, extack);
725 }
726 
727 int
728 mlxsw_sp_trap_policer_counter_get(struct mlxsw_core *mlxsw_core,
729 				  const struct devlink_trap_policer *policer,
730 				  u64 *p_drops)
731 {
732 	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
733 	struct mlxsw_sp_trap_policer_item *policer_item;
734 	char qpcr_pl[MLXSW_REG_QPCR_LEN];
735 	int err;
736 
737 	policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);
738 	if (WARN_ON(!policer_item))
739 		return -EINVAL;
740 
741 	mlxsw_reg_qpcr_pack(qpcr_pl, policer_item->hw_id,
742 			    MLXSW_REG_QPCR_IR_UNITS_M, false, 0, 0);
743 	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
744 	if (err)
745 		return err;
746 
747 	*p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl);
748 
749 	return 0;
750 }
751