1995 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* 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 328 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 in36 * Documentation/networking/devlink/mlxsw.rst37 */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_PORT50 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 the205 * 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 else225 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. It234 * defaults to 64 nanoseconds.235 */236#define MLXSW_SP_MIRROR_LATENCY_SHIFT 6237 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 the285 * 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 engine308 * 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 sample322 * 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 the335 * 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 the371 * 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_item452mlxsw_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 .policer = MLXSW_SP_TRAP_POLICER(21, 128, 128),515 },516};517 518static const struct mlxsw_sp_trap_group_item mlxsw_sp_trap_group_items_arr[] = {519 {520 .group = DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 1),521 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS,522 .priority = 0,523 },524 {525 .group = DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1),526 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS,527 .priority = 0,528 },529 {530 .group = DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 1),531 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_EXCEPTIONS,532 .priority = 2,533 },534 {535 .group = DEVLINK_TRAP_GROUP_GENERIC(TUNNEL_DROPS, 1),536 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS,537 .priority = 0,538 },539 {540 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 1),541 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS,542 .priority = 0,543 },544 {545 .group = DEVLINK_TRAP_GROUP_GENERIC(STP, 2),546 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_STP,547 .priority = 5,548 },549 {550 .group = DEVLINK_TRAP_GROUP_GENERIC(LACP, 3),551 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LACP,552 .priority = 5,553 },554 {555 .group = DEVLINK_TRAP_GROUP_GENERIC(LLDP, 4),556 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP,557 .priority = 5,558 },559 {560 .group = DEVLINK_TRAP_GROUP_GENERIC(MC_SNOOPING, 5),561 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_MC_SNOOPING,562 .priority = 3,563 },564 {565 .group = DEVLINK_TRAP_GROUP_GENERIC(DHCP, 6),566 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_DHCP,567 .priority = 2,568 },569 {570 .group = DEVLINK_TRAP_GROUP_GENERIC(NEIGH_DISCOVERY, 7),571 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_NEIGH_DISCOVERY,572 .priority = 2,573 },574 {575 .group = DEVLINK_TRAP_GROUP_GENERIC(BFD, 8),576 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BFD,577 .priority = 5,578 },579 {580 .group = DEVLINK_TRAP_GROUP_GENERIC(OSPF, 9),581 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_OSPF,582 .priority = 5,583 },584 {585 .group = DEVLINK_TRAP_GROUP_GENERIC(BGP, 10),586 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BGP,587 .priority = 4,588 },589 {590 .group = DEVLINK_TRAP_GROUP_GENERIC(VRRP, 11),591 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_VRRP,592 .priority = 5,593 },594 {595 .group = DEVLINK_TRAP_GROUP_GENERIC(PIM, 12),596 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PIM,597 .priority = 5,598 },599 {600 .group = DEVLINK_TRAP_GROUP_GENERIC(UC_LB, 13),601 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LBERROR,602 .priority = 0,603 },604 {605 .group = DEVLINK_TRAP_GROUP_GENERIC(LOCAL_DELIVERY, 14),606 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME,607 .priority = 2,608 },609 {610 .group = DEVLINK_TRAP_GROUP_GENERIC(EXTERNAL_DELIVERY, 19),611 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_EXTERNAL_ROUTE,612 .priority = 1,613 },614 {615 .group = DEVLINK_TRAP_GROUP_GENERIC(IPV6, 15),616 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6,617 .priority = 2,618 },619 {620 .group = DEVLINK_TRAP_GROUP_GENERIC(PTP_EVENT, 16),621 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0,622 .priority = 5,623 },624 {625 .group = DEVLINK_TRAP_GROUP_GENERIC(PTP_GENERAL, 17),626 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1,627 .priority = 2,628 },629 {630 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_TRAP, 18),631 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_FLOW_LOGGING,632 .priority = 4,633 },634 {635 .group = DEVLINK_TRAP_GROUP_GENERIC(EAPOL, 21),636 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_EAPOL,637 .priority = 5,638 },639};640 641static const struct mlxsw_sp_trap_item mlxsw_sp_trap_items_arr[] = {642 {643 .trap = MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS),644 .listeners_arr = {645 MLXSW_SP_RXL_DISCARD(ING_PACKET_SMAC_MC, L2_DISCARDS),646 },647 },648 {649 .trap = MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS),650 .listeners_arr = {651 MLXSW_SP_RXL_DISCARD(ING_SWITCH_VTAG_ALLOW,652 L2_DISCARDS),653 },654 },655 {656 .trap = MLXSW_SP_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS),657 .listeners_arr = {658 MLXSW_SP_RXL_DISCARD(ING_SWITCH_VLAN, L2_DISCARDS),659 },660 },661 {662 .trap = MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS),663 .listeners_arr = {664 MLXSW_SP_RXL_DISCARD(ING_SWITCH_STP, L2_DISCARDS),665 },666 },667 {668 .trap = MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS),669 .listeners_arr = {670 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS),671 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS),672 },673 },674 {675 .trap = MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS),676 .listeners_arr = {677 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS),678 },679 },680 {681 .trap = MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS),682 .listeners_arr = {683 MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS),684 },685 },686 {687 .trap = MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS),688 .listeners_arr = {689 MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET,690 L3_DISCARDS),691 },692 },693 {694 .trap = MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS),695 .listeners_arr = {696 MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC,697 L3_DISCARDS),698 },699 },700 {701 .trap = MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS),702 .listeners_arr = {703 MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS),704 },705 },706 {707 .trap = MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS),708 .listeners_arr = {709 MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS),710 },711 },712 {713 .trap = MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS),714 .listeners_arr = {715 MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS),716 },717 },718 {719 .trap = MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS),720 .listeners_arr = {721 MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR,722 L3_DISCARDS),723 },724 },725 {726 .trap = MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS),727 .listeners_arr = {728 MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC,729 L3_DISCARDS),730 },731 },732 {733 .trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE,734 L3_DROPS),735 .listeners_arr = {736 MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE,737 L3_DISCARDS),738 },739 },740 {741 .trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE,742 L3_DROPS),743 .listeners_arr = {744 MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE,745 L3_DISCARDS),746 },747 },748 {749 .trap = MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_EXCEPTIONS),750 .listeners_arr = {751 MLXSW_SP_RXL_EXCEPTION(MTUERROR, L3_EXCEPTIONS,752 TRAP_TO_CPU),753 },754 },755 {756 .trap = MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS),757 .listeners_arr = {758 MLXSW_SP_RXL_EXCEPTION(TTLERROR, L3_EXCEPTIONS,759 TRAP_TO_CPU),760 },761 },762 {763 .trap = MLXSW_SP_TRAP_EXCEPTION(RPF, L3_EXCEPTIONS),764 .listeners_arr = {765 MLXSW_SP_RXL_EXCEPTION(RPF, L3_EXCEPTIONS, TRAP_TO_CPU),766 },767 },768 {769 .trap = MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_EXCEPTIONS),770 .listeners_arr = {771 MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, L3_EXCEPTIONS,772 TRAP_TO_CPU),773 },774 },775 {776 .trap = MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH,777 L3_EXCEPTIONS),778 .listeners_arr = {779 MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, L3_EXCEPTIONS,780 TRAP_TO_CPU),781 MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, L3_EXCEPTIONS,782 TRAP_TO_CPU),783 MLXSW_SP_RXL_EXCEPTION(RTR_EGRESS0, L3_EXCEPTIONS,784 TRAP_EXCEPTION_TO_CPU),785 },786 },787 {788 .trap = MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS,789 L3_EXCEPTIONS),790 .listeners_arr = {791 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4,792 L3_EXCEPTIONS,793 TRAP_EXCEPTION_TO_CPU),794 },795 },796 {797 .trap = MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS,798 L3_EXCEPTIONS),799 .listeners_arr = {800 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6,801 L3_EXCEPTIONS,802 TRAP_EXCEPTION_TO_CPU),803 },804 },805 {806 .trap = MLXSW_SP_TRAP_DRIVER_DROP(IRIF_DISABLED, L3_DROPS),807 .listeners_arr = {808 MLXSW_SP_RXL_DISCARD(ROUTER_IRIF_EN, L3_DISCARDS),809 },810 },811 {812 .trap = MLXSW_SP_TRAP_DRIVER_DROP(ERIF_DISABLED, L3_DROPS),813 .listeners_arr = {814 MLXSW_SP_RXL_DISCARD(ROUTER_ERIF_EN, L3_DISCARDS),815 },816 },817 {818 .trap = MLXSW_SP_TRAP_DROP(NON_ROUTABLE, L3_DROPS),819 .listeners_arr = {820 MLXSW_SP_RXL_DISCARD(NON_ROUTABLE, L3_DISCARDS),821 },822 },823 {824 .trap = MLXSW_SP_TRAP_EXCEPTION(DECAP_ERROR, TUNNEL_DROPS),825 .listeners_arr = {826 MLXSW_SP_RXL_EXCEPTION(DECAP_ECN0, TUNNEL_DISCARDS,827 TRAP_EXCEPTION_TO_CPU),828 MLXSW_SP_RXL_EXCEPTION(IPIP_DECAP_ERROR,829 TUNNEL_DISCARDS,830 TRAP_EXCEPTION_TO_CPU),831 MLXSW_SP_RXL_EXCEPTION(DISCARD_DEC_PKT, TUNNEL_DISCARDS,832 TRAP_EXCEPTION_TO_CPU),833 },834 },835 {836 .trap = MLXSW_SP_TRAP_DROP(OVERLAY_SMAC_MC, TUNNEL_DROPS),837 .listeners_arr = {838 MLXSW_SP_RXL_DISCARD(OVERLAY_SMAC_MC, TUNNEL_DISCARDS),839 },840 },841 {842 .trap = MLXSW_SP_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP,843 ACL_DROPS,844 DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),845 .listeners_arr = {846 MLXSW_SP_RXL_ACL_DISCARD(INGRESS_ACL, ACL_DISCARDS,847 DUMMY),848 },849 },850 {851 .trap = MLXSW_SP_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP,852 ACL_DROPS,853 DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),854 .listeners_arr = {855 MLXSW_SP_RXL_ACL_DISCARD(EGRESS_ACL, ACL_DISCARDS,856 DUMMY),857 },858 },859 {860 .trap = MLXSW_SP_TRAP_CONTROL(STP, STP, TRAP),861 .listeners_arr = {862 MLXSW_SP_RXL_NO_MARK(STP, STP, TRAP_TO_CPU, true),863 },864 },865 {866 .trap = MLXSW_SP_TRAP_CONTROL(LACP, LACP, TRAP),867 .listeners_arr = {868 MLXSW_SP_RXL_NO_MARK(LACP, LACP, TRAP_TO_CPU, true),869 },870 },871 {872 .trap = MLXSW_SP_TRAP_CONTROL(LLDP, LLDP, TRAP),873 .listeners_arr = {874 MLXSW_RXL(mlxsw_sp_rx_ptp_listener, LLDP, TRAP_TO_CPU,875 true, SP_LLDP, DISCARD),876 },877 },878 {879 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR),880 .listeners_arr = {881 MLXSW_SP_RXL_MARK(IGMP_QUERY, MC_SNOOPING,882 MIRROR_TO_CPU, false),883 },884 },885 {886 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING,887 TRAP),888 .listeners_arr = {889 MLXSW_SP_RXL_NO_MARK(IGMP_V1_REPORT, MC_SNOOPING,890 TRAP_TO_CPU, false),891 },892 },893 {894 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_REPORT, MC_SNOOPING,895 TRAP),896 .listeners_arr = {897 MLXSW_SP_RXL_NO_MARK(IGMP_V2_REPORT, MC_SNOOPING,898 TRAP_TO_CPU, false),899 },900 },901 {902 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V3_REPORT, MC_SNOOPING,903 TRAP),904 .listeners_arr = {905 MLXSW_SP_RXL_NO_MARK(IGMP_V3_REPORT, MC_SNOOPING,906 TRAP_TO_CPU, false),907 },908 },909 {910 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_LEAVE, MC_SNOOPING,911 TRAP),912 .listeners_arr = {913 MLXSW_SP_RXL_NO_MARK(IGMP_V2_LEAVE, MC_SNOOPING,914 TRAP_TO_CPU, false),915 },916 },917 {918 .trap = MLXSW_SP_TRAP_CONTROL(MLD_QUERY, MC_SNOOPING, MIRROR),919 .listeners_arr = {920 MLXSW_SP_RXL_MARK(IPV6_MLDV12_LISTENER_QUERY,921 MC_SNOOPING, MIRROR_TO_CPU, false),922 },923 },924 {925 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_REPORT, MC_SNOOPING,926 TRAP),927 .listeners_arr = {928 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_REPORT,929 MC_SNOOPING, TRAP_TO_CPU, false),930 },931 },932 {933 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V2_REPORT, MC_SNOOPING,934 TRAP),935 .listeners_arr = {936 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV2_LISTENER_REPORT,937 MC_SNOOPING, TRAP_TO_CPU, false),938 },939 },940 {941 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_DONE, MC_SNOOPING,942 TRAP),943 .listeners_arr = {944 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_DONE,945 MC_SNOOPING, TRAP_TO_CPU, false),946 },947 },948 {949 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_DHCP, DHCP, TRAP),950 .listeners_arr = {951 MLXSW_SP_RXL_MARK(IPV4_DHCP, DHCP, TRAP_TO_CPU, false),952 },953 },954 {955 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DHCP, DHCP, TRAP),956 .listeners_arr = {957 MLXSW_SP_RXL_MARK(IPV6_DHCP, DHCP, TRAP_TO_CPU, false),958 },959 },960 {961 .trap = MLXSW_SP_TRAP_CONTROL(ARP_REQUEST, NEIGH_DISCOVERY,962 MIRROR),963 .listeners_arr = {964 MLXSW_SP_RXL_MARK(ROUTER_ARPBC, NEIGH_DISCOVERY,965 TRAP_TO_CPU, false),966 },967 },968 {969 .trap = MLXSW_SP_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY,970 MIRROR),971 .listeners_arr = {972 MLXSW_SP_RXL_MARK(ROUTER_ARPUC, NEIGH_DISCOVERY,973 TRAP_TO_CPU, false),974 },975 },976 {977 .trap = MLXSW_SP_TRAP_CONTROL(ARP_OVERLAY, NEIGH_DISCOVERY,978 TRAP),979 .listeners_arr = {980 MLXSW_SP_RXL_NO_MARK(NVE_DECAP_ARP, NEIGH_DISCOVERY,981 TRAP_TO_CPU, false),982 },983 },984 {985 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_SOLICIT,986 NEIGH_DISCOVERY, TRAP),987 .listeners_arr = {988 MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_SOLICITATION,989 NEIGH_DISCOVERY, TRAP_TO_CPU, false),990 },991 },992 {993 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_ADVERT,994 NEIGH_DISCOVERY, TRAP),995 .listeners_arr = {996 MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_ADVERTISEMENT,997 NEIGH_DISCOVERY, TRAP_TO_CPU, false),998 },999 },1000 {1001 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_BFD, BFD, TRAP),1002 .listeners_arr = {1003 MLXSW_SP_RXL_MARK(IPV4_BFD, BFD, TRAP_TO_CPU, false),1004 },1005 },1006 {1007 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_BFD, BFD, TRAP),1008 .listeners_arr = {1009 MLXSW_SP_RXL_MARK(IPV6_BFD, BFD, TRAP_TO_CPU, false),1010 },1011 },1012 {1013 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_OSPF, OSPF, TRAP),1014 .listeners_arr = {1015 MLXSW_SP_RXL_MARK(IPV4_OSPF, OSPF, TRAP_TO_CPU, false),1016 },1017 },1018 {1019 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_OSPF, OSPF, TRAP),1020 .listeners_arr = {1021 MLXSW_SP_RXL_MARK(IPV6_OSPF, OSPF, TRAP_TO_CPU, false),1022 },1023 },1024 {1025 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_BGP, BGP, TRAP),1026 .listeners_arr = {1027 MLXSW_SP_RXL_MARK(IPV4_BGP, BGP, TRAP_TO_CPU, false),1028 },1029 },1030 {1031 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_BGP, BGP, TRAP),1032 .listeners_arr = {1033 MLXSW_SP_RXL_MARK(IPV6_BGP, BGP, TRAP_TO_CPU, false),1034 },1035 },1036 {1037 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_VRRP, VRRP, TRAP),1038 .listeners_arr = {1039 MLXSW_SP_RXL_MARK(IPV4_VRRP, VRRP, TRAP_TO_CPU, false),1040 },1041 },1042 {1043 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_VRRP, VRRP, TRAP),1044 .listeners_arr = {1045 MLXSW_SP_RXL_MARK(IPV6_VRRP, VRRP, TRAP_TO_CPU, false),1046 },1047 },1048 {1049 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_PIM, PIM, TRAP),1050 .listeners_arr = {1051 MLXSW_SP_RXL_MARK(IPV4_PIM, PIM, TRAP_TO_CPU, false),1052 },1053 },1054 {1055 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_PIM, PIM, TRAP),1056 .listeners_arr = {1057 MLXSW_SP_RXL_MARK(IPV6_PIM, PIM, TRAP_TO_CPU, false),1058 },1059 },1060 {1061 .trap = MLXSW_SP_TRAP_CONTROL(UC_LB, UC_LB, MIRROR),1062 .listeners_arr = {1063 MLXSW_SP_RXL_L3_MARK(LBERROR, LBERROR, MIRROR_TO_CPU,1064 false),1065 },1066 },1067 {1068 .trap = MLXSW_SP_TRAP_CONTROL(LOCAL_ROUTE, LOCAL_DELIVERY,1069 TRAP),1070 .listeners_arr = {1071 MLXSW_SP_RXL_MARK(IP2ME, IP2ME, TRAP_TO_CPU, false),1072 },1073 },1074 {1075 .trap = MLXSW_SP_TRAP_CONTROL(EXTERNAL_ROUTE, EXTERNAL_DELIVERY,1076 TRAP),1077 .listeners_arr = {1078 MLXSW_SP_RXL_MARK(RTR_INGRESS0, EXTERNAL_ROUTE,1079 TRAP_TO_CPU, false),1080 },1081 },1082 {1083 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_UC_DIP_LINK_LOCAL_SCOPE,1084 LOCAL_DELIVERY, TRAP),1085 .listeners_arr = {1086 MLXSW_SP_RXL_MARK(IPV6_LINK_LOCAL_DEST, IP2ME,1087 TRAP_TO_CPU, false),1088 },1089 },1090 {1091 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_ROUTER_ALERT, LOCAL_DELIVERY,1092 TRAP),1093 .listeners_arr = {1094 MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV4, IP2ME, TRAP_TO_CPU,1095 false),1096 },1097 },1098 {1099 /* IPV6_ROUTER_ALERT is defined in uAPI as 22, but it is not1100 * used in this file, so undefine it.1101 */1102 #undef IPV6_ROUTER_ALERT1103 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_ALERT, LOCAL_DELIVERY,1104 TRAP),1105 .listeners_arr = {1106 MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, IP2ME, TRAP_TO_CPU,1107 false),1108 },1109 },1110 {1111 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DIP_ALL_NODES, IPV6, TRAP),1112 .listeners_arr = {1113 MLXSW_SP_RXL_MARK(IPV6_ALL_NODES_LINK, IPV6,1114 TRAP_TO_CPU, false),1115 },1116 },1117 {1118 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DIP_ALL_ROUTERS, IPV6, TRAP),1119 .listeners_arr = {1120 MLXSW_SP_RXL_MARK(IPV6_ALL_ROUTERS_LINK, IPV6,1121 TRAP_TO_CPU, false),1122 },1123 },1124 {1125 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_SOLICIT, IPV6, TRAP),1126 .listeners_arr = {1127 MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_SOLICITATION, IPV6,1128 TRAP_TO_CPU, false),1129 },1130 },1131 {1132 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_ADVERT, IPV6, TRAP),1133 .listeners_arr = {1134 MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_ADVERTISEMENT, IPV6,1135 TRAP_TO_CPU, false),1136 },1137 },1138 {1139 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_REDIRECT, IPV6, TRAP),1140 .listeners_arr = {1141 MLXSW_SP_RXL_MARK(L3_IPV6_REDIRECTION, IPV6,1142 TRAP_TO_CPU, false),1143 },1144 },1145 {1146 .trap = MLXSW_SP_TRAP_CONTROL(PTP_EVENT, PTP_EVENT, TRAP),1147 .listeners_arr = {1148 MLXSW_RXL(mlxsw_sp_rx_ptp_listener, PTP0, TRAP_TO_CPU,1149 false, SP_PTP0, DISCARD),1150 },1151 },1152 {1153 .trap = MLXSW_SP_TRAP_CONTROL(PTP_GENERAL, PTP_GENERAL, TRAP),1154 .listeners_arr = {1155 MLXSW_SP_RXL_NO_MARK(PTP1, PTP1, TRAP_TO_CPU, false),1156 },1157 },1158 {1159 .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_TRAP, ACL_TRAP, TRAP),1160 .listeners_arr = {1161 MLXSW_SP_RXL_NO_MARK(ACL0, FLOW_LOGGING, TRAP_TO_CPU,1162 false),1163 },1164 },1165 {1166 .trap = MLXSW_SP_TRAP_DROP(BLACKHOLE_NEXTHOP, L3_DROPS),1167 .listeners_arr = {1168 MLXSW_SP_RXL_DISCARD(ROUTER3, L3_DISCARDS),1169 },1170 },1171 {1172 .trap = MLXSW_SP_TRAP_CONTROL(EAPOL, EAPOL, TRAP),1173 .listeners_arr = {1174 MLXSW_SP_RXL_NO_MARK(EAPOL, EAPOL, TRAP_TO_CPU, true),1175 },1176 },1177 {1178 .trap = MLXSW_SP_TRAP_DROP(LOCKED_PORT, L2_DROPS),1179 .listeners_arr = {1180 MLXSW_RXL_DIS(mlxsw_sp_rx_drop_listener, FDB_MISS,1181 TRAP_EXCEPTION_TO_CPU, false,1182 SP_L2_DISCARDS, DISCARD, SP_L2_DISCARDS),1183 MLXSW_RXL_DIS(mlxsw_sp_rx_drop_listener, FDB_MISMATCH,1184 TRAP_EXCEPTION_TO_CPU, false,1185 SP_L2_DISCARDS, DISCARD, SP_L2_DISCARDS),1186 },1187 },1188};1189 1190static struct mlxsw_sp_trap_policer_item *1191mlxsw_sp_trap_policer_item_lookup(struct mlxsw_sp *mlxsw_sp, u32 id)1192{1193 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;1194 int i;1195 1196 for (i = 0; i < trap->policers_count; i++) {1197 if (trap->policer_items_arr[i].policer.id == id)1198 return &trap->policer_items_arr[i];1199 }1200 1201 return NULL;1202}1203 1204static struct mlxsw_sp_trap_group_item *1205mlxsw_sp_trap_group_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id)1206{1207 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;1208 int i;1209 1210 for (i = 0; i < trap->groups_count; i++) {1211 if (trap->group_items_arr[i].group.id == id)1212 return &trap->group_items_arr[i];1213 }1214 1215 return NULL;1216}1217 1218static struct mlxsw_sp_trap_item *1219mlxsw_sp_trap_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id)1220{1221 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;1222 int i;1223 1224 for (i = 0; i < trap->traps_count; i++) {1225 if (trap->trap_items_arr[i].trap.id == id)1226 return &trap->trap_items_arr[i];1227 }1228 1229 return NULL;1230}1231 1232static int mlxsw_sp_trap_cpu_policers_set(struct mlxsw_sp *mlxsw_sp)1233{1234 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;1235 char qpcr_pl[MLXSW_REG_QPCR_LEN];1236 u16 hw_id;1237 1238 /* The purpose of "thin" policer is to drop as many packets1239 * as possible. The dummy group is using it.1240 */1241 hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers);1242 if (WARN_ON(hw_id == trap->max_policers))1243 return -ENOBUFS;1244 1245 __set_bit(hw_id, trap->policers_usage);1246 trap->thin_policer_hw_id = hw_id;1247 mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M,1248 false, 1, 4);1249 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);1250}1251 1252static int mlxsw_sp_trap_dummy_group_init(struct mlxsw_sp *mlxsw_sp)1253{1254 char htgt_pl[MLXSW_REG_HTGT_LEN];1255 1256 mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SP_DUMMY,1257 mlxsw_sp->trap->thin_policer_hw_id, 0, 1);1258 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl);1259}1260 1261static int mlxsw_sp_trap_policer_items_arr_init(struct mlxsw_sp *mlxsw_sp)1262{1263 size_t arr_size = ARRAY_SIZE(mlxsw_sp_trap_policer_items_arr);1264 size_t elem_size = sizeof(struct mlxsw_sp_trap_policer_item);1265 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;1266 size_t free_policers = 0;1267 u32 last_id;1268 int i;1269 1270 for_each_clear_bit(i, trap->policers_usage, trap->max_policers)1271 free_policers++;1272 1273 if (arr_size > free_policers) {1274 dev_err(mlxsw_sp->bus_info->dev, "Exceeded number of supported packet trap policers\n");1275 return -ENOBUFS;1276 }1277 1278 trap->policer_items_arr = kcalloc(free_policers, elem_size, GFP_KERNEL);1279 if (!trap->policer_items_arr)1280 return -ENOMEM;1281 1282 trap->policers_count = free_policers;1283 1284 /* Initialize policer items array with pre-defined policers. */1285 memcpy(trap->policer_items_arr, mlxsw_sp_trap_policer_items_arr,1286 elem_size * arr_size);1287 1288 /* Initialize policer items array with the rest of the available1289 * policers.1290 */1291 last_id = mlxsw_sp_trap_policer_items_arr[arr_size - 1].policer.id;1292 for (i = arr_size; i < trap->policers_count; i++) {1293 const struct mlxsw_sp_trap_policer_item *policer_item;1294 1295 /* Use parameters set for first policer and override1296 * relevant ones.1297 */1298 policer_item = &mlxsw_sp_trap_policer_items_arr[0];1299 trap->policer_items_arr[i] = *policer_item;1300 trap->policer_items_arr[i].policer.id = ++last_id;1301 trap->policer_items_arr[i].policer.init_rate = 1;1302 trap->policer_items_arr[i].policer.init_burst = 16;1303 }1304 1305 return 0;1306}1307 1308static void mlxsw_sp_trap_policer_items_arr_fini(struct mlxsw_sp *mlxsw_sp)1309{1310 kfree(mlxsw_sp->trap->policer_items_arr);1311}1312 1313static int mlxsw_sp_trap_policers_init(struct mlxsw_sp *mlxsw_sp)1314{1315 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);1316 const struct mlxsw_sp_trap_policer_item *policer_item;1317 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;1318 int err, i;1319 1320 err = mlxsw_sp_trap_policer_items_arr_init(mlxsw_sp);1321 if (err)1322 return err;1323 1324 for (i = 0; i < trap->policers_count; i++) {1325 policer_item = &trap->policer_items_arr[i];1326 err = devl_trap_policers_register(devlink,1327 &policer_item->policer, 1);1328 if (err)1329 goto err_trap_policer_register;1330 }1331 1332 return 0;1333 1334err_trap_policer_register:1335 for (i--; i >= 0; i--) {1336 policer_item = &trap->policer_items_arr[i];1337 devl_trap_policers_unregister(devlink,1338 &policer_item->policer, 1);1339 }1340 mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp);1341 return err;1342}1343 1344static void mlxsw_sp_trap_policers_fini(struct mlxsw_sp *mlxsw_sp)1345{1346 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);1347 const struct mlxsw_sp_trap_policer_item *policer_item;1348 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;1349 int i;1350 1351 for (i = trap->policers_count - 1; i >= 0; i--) {1352 policer_item = &trap->policer_items_arr[i];1353 devl_trap_policers_unregister(devlink,1354 &policer_item->policer, 1);1355 }1356 mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp);1357}1358 1359static int mlxsw_sp_trap_group_items_arr_init(struct mlxsw_sp *mlxsw_sp)1360{1361 size_t common_groups_count = ARRAY_SIZE(mlxsw_sp_trap_group_items_arr);1362 const struct mlxsw_sp_trap_group_item *spec_group_items_arr;1363 size_t elem_size = sizeof(struct mlxsw_sp_trap_group_item);1364 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;1365 size_t groups_count, spec_groups_count;1366 int err;1367 1368 err = mlxsw_sp->trap_ops->groups_init(mlxsw_sp, &spec_group_items_arr,1369 &spec_groups_count);1370 if (err)1371 return err;1372 1373 /* The group items array is created by concatenating the common trap1374 * group items and the ASIC-specific trap group items.1375 */1376 groups_count = common_groups_count + spec_groups_count;1377 trap->group_items_arr = kcalloc(groups_count, elem_size, GFP_KERNEL);1378 if (!trap->group_items_arr)1379 return -ENOMEM;1380 1381 memcpy(trap->group_items_arr, mlxsw_sp_trap_group_items_arr,1382 elem_size * common_groups_count);1383 memcpy(trap->group_items_arr + common_groups_count,1384 spec_group_items_arr, elem_size * spec_groups_count);1385 1386 trap->groups_count = groups_count;1387 1388 return 0;1389}1390 1391static void mlxsw_sp_trap_group_items_arr_fini(struct mlxsw_sp *mlxsw_sp)1392{1393 kfree(mlxsw_sp->trap->group_items_arr);1394}1395 1396static int mlxsw_sp_trap_groups_init(struct mlxsw_sp *mlxsw_sp)1397{1398 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);1399 const struct mlxsw_sp_trap_group_item *group_item;1400 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;1401 int err, i;1402 1403 err = mlxsw_sp_trap_group_items_arr_init(mlxsw_sp);1404 if (err)1405 return err;1406 1407 for (i = 0; i < trap->groups_count; i++) {1408 group_item = &trap->group_items_arr[i];1409 err = devl_trap_groups_register(devlink, &group_item->group, 1);1410 if (err)1411 goto err_trap_group_register;1412 }1413 1414 return 0;1415 1416err_trap_group_register:1417 for (i--; i >= 0; i--) {1418 group_item = &trap->group_items_arr[i];1419 devl_trap_groups_unregister(devlink, &group_item->group, 1);1420 }1421 mlxsw_sp_trap_group_items_arr_fini(mlxsw_sp);1422 return err;1423}1424 1425static void mlxsw_sp_trap_groups_fini(struct mlxsw_sp *mlxsw_sp)1426{1427 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);1428 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;1429 int i;1430 1431 for (i = trap->groups_count - 1; i >= 0; i--) {1432 const struct mlxsw_sp_trap_group_item *group_item;1433 1434 group_item = &trap->group_items_arr[i];1435 devl_trap_groups_unregister(devlink, &group_item->group, 1);1436 }1437 mlxsw_sp_trap_group_items_arr_fini(mlxsw_sp);1438}1439 1440static bool1441mlxsw_sp_trap_listener_is_valid(const struct mlxsw_listener *listener)1442{1443 return listener->trap_id != 0;1444}1445 1446static int mlxsw_sp_trap_items_arr_init(struct mlxsw_sp *mlxsw_sp)1447{1448 size_t common_traps_count = ARRAY_SIZE(mlxsw_sp_trap_items_arr);1449 const struct mlxsw_sp_trap_item *spec_trap_items_arr;1450 size_t elem_size = sizeof(struct mlxsw_sp_trap_item);1451 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;1452 size_t traps_count, spec_traps_count;1453 int err;1454 1455 err = mlxsw_sp->trap_ops->traps_init(mlxsw_sp, &spec_trap_items_arr,1456 &spec_traps_count);1457 if (err)1458 return err;1459 1460 /* The trap items array is created by concatenating the common trap1461 * items and the ASIC-specific trap items.1462 */1463 traps_count = common_traps_count + spec_traps_count;1464 trap->trap_items_arr = kcalloc(traps_count, elem_size, GFP_KERNEL);1465 if (!trap->trap_items_arr)1466 return -ENOMEM;1467 1468 memcpy(trap->trap_items_arr, mlxsw_sp_trap_items_arr,1469 elem_size * common_traps_count);1470 memcpy(trap->trap_items_arr + common_traps_count,1471 spec_trap_items_arr, elem_size * spec_traps_count);1472 1473 trap->traps_count = traps_count;1474 1475 return 0;1476}1477 1478static void mlxsw_sp_trap_items_arr_fini(struct mlxsw_sp *mlxsw_sp)1479{1480 kfree(mlxsw_sp->trap->trap_items_arr);1481}1482 1483static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)1484{1485 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);1486 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;1487 const struct mlxsw_sp_trap_item *trap_item;1488 int err, i;1489 1490 err = mlxsw_sp_trap_items_arr_init(mlxsw_sp);1491 if (err)1492 return err;1493 1494 for (i = 0; i < trap->traps_count; i++) {1495 trap_item = &trap->trap_items_arr[i];1496 err = devl_traps_register(devlink, &trap_item->trap, 1,1497 mlxsw_sp);1498 if (err)1499 goto err_trap_register;1500 }1501 1502 return 0;1503 1504err_trap_register:1505 for (i--; i >= 0; i--) {1506 trap_item = &trap->trap_items_arr[i];1507 devl_traps_unregister(devlink, &trap_item->trap, 1);1508 }1509 mlxsw_sp_trap_items_arr_fini(mlxsw_sp);1510 return err;1511}1512 1513static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp)1514{1515 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);1516 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;1517 int i;1518 1519 for (i = trap->traps_count - 1; i >= 0; i--) {1520 const struct mlxsw_sp_trap_item *trap_item;1521 1522 trap_item = &trap->trap_items_arr[i];1523 devl_traps_unregister(devlink, &trap_item->trap, 1);1524 }1525 mlxsw_sp_trap_items_arr_fini(mlxsw_sp);1526}1527 1528int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp)1529{1530 int err;1531 1532 err = mlxsw_sp_trap_cpu_policers_set(mlxsw_sp);1533 if (err)1534 return err;1535 1536 err = mlxsw_sp_trap_dummy_group_init(mlxsw_sp);1537 if (err)1538 return err;1539 1540 err = mlxsw_sp_trap_policers_init(mlxsw_sp);1541 if (err)1542 return err;1543 1544 err = mlxsw_sp_trap_groups_init(mlxsw_sp);1545 if (err)1546 goto err_trap_groups_init;1547 1548 err = mlxsw_sp_traps_init(mlxsw_sp);1549 if (err)1550 goto err_traps_init;1551 1552 return 0;1553 1554err_traps_init:1555 mlxsw_sp_trap_groups_fini(mlxsw_sp);1556err_trap_groups_init:1557 mlxsw_sp_trap_policers_fini(mlxsw_sp);1558 return err;1559}1560 1561void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp)1562{1563 mlxsw_sp_traps_fini(mlxsw_sp);1564 mlxsw_sp_trap_groups_fini(mlxsw_sp);1565 mlxsw_sp_trap_policers_fini(mlxsw_sp);1566}1567 1568int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core,1569 const struct devlink_trap *trap, void *trap_ctx)1570{1571 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);1572 const struct mlxsw_sp_trap_item *trap_item;1573 int i;1574 1575 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);1576 if (WARN_ON(!trap_item))1577 return -EINVAL;1578 1579 for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) {1580 const struct mlxsw_listener *listener;1581 int err;1582 1583 listener = &trap_item->listeners_arr[i];1584 if (!mlxsw_sp_trap_listener_is_valid(listener))1585 continue;1586 err = mlxsw_core_trap_register(mlxsw_core, listener, trap_ctx);1587 if (err)1588 return err;1589 }1590 1591 return 0;1592}1593 1594void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core,1595 const struct devlink_trap *trap, void *trap_ctx)1596{1597 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);1598 const struct mlxsw_sp_trap_item *trap_item;1599 int i;1600 1601 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);1602 if (WARN_ON(!trap_item))1603 return;1604 1605 for (i = MLXSW_SP_TRAP_LISTENERS_MAX - 1; i >= 0; i--) {1606 const struct mlxsw_listener *listener;1607 1608 listener = &trap_item->listeners_arr[i];1609 if (!mlxsw_sp_trap_listener_is_valid(listener))1610 continue;1611 mlxsw_core_trap_unregister(mlxsw_core, listener, trap_ctx);1612 }1613}1614 1615int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core,1616 const struct devlink_trap *trap,1617 enum devlink_trap_action action,1618 struct netlink_ext_ack *extack)1619{1620 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);1621 const struct mlxsw_sp_trap_item *trap_item;1622 int i;1623 1624 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id);1625 if (WARN_ON(!trap_item))1626 return -EINVAL;1627 1628 if (trap_item->is_source) {1629 NL_SET_ERR_MSG_MOD(extack, "Changing the action of source traps is not supported");1630 return -EOPNOTSUPP;1631 }1632 1633 for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) {1634 const struct mlxsw_listener *listener;1635 bool enabled;1636 int err;1637 1638 listener = &trap_item->listeners_arr[i];1639 if (!mlxsw_sp_trap_listener_is_valid(listener))1640 continue;1641 1642 switch (action) {1643 case DEVLINK_TRAP_ACTION_DROP:1644 enabled = false;1645 break;1646 case DEVLINK_TRAP_ACTION_TRAP:1647 enabled = true;1648 break;1649 default:1650 return -EINVAL;1651 }1652 err = mlxsw_core_trap_state_set(mlxsw_core, listener, enabled);1653 if (err)1654 return err;1655 }1656 1657 return 0;1658}1659 1660static int1661__mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core,1662 const struct devlink_trap_group *group,1663 u32 policer_id, struct netlink_ext_ack *extack)1664{1665 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);1666 u16 hw_policer_id = MLXSW_REG_HTGT_INVALID_POLICER;1667 const struct mlxsw_sp_trap_group_item *group_item;1668 char htgt_pl[MLXSW_REG_HTGT_LEN];1669 1670 group_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, group->id);1671 if (WARN_ON(!group_item))1672 return -EINVAL;1673 1674 if (group_item->fixed_policer && policer_id != group->init_policer_id) {1675 NL_SET_ERR_MSG_MOD(extack, "Changing the policer binding of this group is not supported");1676 return -EOPNOTSUPP;1677 }1678 1679 if (policer_id) {1680 struct mlxsw_sp_trap_policer_item *policer_item;1681 1682 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp,1683 policer_id);1684 if (WARN_ON(!policer_item))1685 return -EINVAL;1686 hw_policer_id = policer_item->hw_id;1687 }1688 1689 mlxsw_reg_htgt_pack(htgt_pl, group_item->hw_group_id, hw_policer_id,1690 group_item->priority, group_item->priority);1691 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);1692}1693 1694int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core,1695 const struct devlink_trap_group *group)1696{1697 return __mlxsw_sp_trap_group_init(mlxsw_core, group,1698 group->init_policer_id, NULL);1699}1700 1701int mlxsw_sp_trap_group_set(struct mlxsw_core *mlxsw_core,1702 const struct devlink_trap_group *group,1703 const struct devlink_trap_policer *policer,1704 struct netlink_ext_ack *extack)1705{1706 u32 policer_id = policer ? policer->id : 0;1707 1708 return __mlxsw_sp_trap_group_init(mlxsw_core, group, policer_id,1709 extack);1710}1711 1712static int1713mlxsw_sp_trap_policer_item_init(struct mlxsw_sp *mlxsw_sp,1714 struct mlxsw_sp_trap_policer_item *policer_item)1715{1716 struct mlxsw_sp_trap *trap = mlxsw_sp->trap;1717 u16 hw_id;1718 1719 /* We should be able to allocate a policer because the number of1720 * policers we registered with devlink is in according with the number1721 * of available policers.1722 */1723 hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers);1724 if (WARN_ON(hw_id == trap->max_policers))1725 return -ENOBUFS;1726 1727 __set_bit(hw_id, trap->policers_usage);1728 policer_item->hw_id = hw_id;1729 1730 return 0;1731}1732 1733static void1734mlxsw_sp_trap_policer_item_fini(struct mlxsw_sp *mlxsw_sp,1735 struct mlxsw_sp_trap_policer_item *policer_item)1736{1737 __clear_bit(policer_item->hw_id, mlxsw_sp->trap->policers_usage);1738}1739 1740static int mlxsw_sp_trap_policer_bs(u64 burst, u8 *p_burst_size,1741 struct netlink_ext_ack *extack)1742{1743 int bs = fls64(burst) - 1;1744 1745 if (burst != (BIT_ULL(bs))) {1746 NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two");1747 return -EINVAL;1748 }1749 1750 *p_burst_size = bs;1751 1752 return 0;1753}1754 1755static int __mlxsw_sp_trap_policer_set(struct mlxsw_sp *mlxsw_sp, u16 hw_id,1756 u64 rate, u64 burst, bool clear_counter,1757 struct netlink_ext_ack *extack)1758{1759 char qpcr_pl[MLXSW_REG_QPCR_LEN];1760 u8 burst_size;1761 int err;1762 1763 err = mlxsw_sp_trap_policer_bs(burst, &burst_size, extack);1764 if (err)1765 return err;1766 1767 mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M, false,1768 rate, burst_size);1769 mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, clear_counter);1770 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);1771}1772 1773int mlxsw_sp_trap_policer_init(struct mlxsw_core *mlxsw_core,1774 const struct devlink_trap_policer *policer)1775{1776 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);1777 struct mlxsw_sp_trap_policer_item *policer_item;1778 int err;1779 1780 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);1781 if (WARN_ON(!policer_item))1782 return -EINVAL;1783 1784 err = mlxsw_sp_trap_policer_item_init(mlxsw_sp, policer_item);1785 if (err)1786 return err;1787 1788 err = __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id,1789 policer->init_rate,1790 policer->init_burst, true, NULL);1791 if (err)1792 goto err_trap_policer_set;1793 1794 return 0;1795 1796err_trap_policer_set:1797 mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item);1798 return err;1799}1800 1801void mlxsw_sp_trap_policer_fini(struct mlxsw_core *mlxsw_core,1802 const struct devlink_trap_policer *policer)1803{1804 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);1805 struct mlxsw_sp_trap_policer_item *policer_item;1806 1807 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);1808 if (WARN_ON(!policer_item))1809 return;1810 1811 mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item);1812}1813 1814int mlxsw_sp_trap_policer_set(struct mlxsw_core *mlxsw_core,1815 const struct devlink_trap_policer *policer,1816 u64 rate, u64 burst,1817 struct netlink_ext_ack *extack)1818{1819 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);1820 struct mlxsw_sp_trap_policer_item *policer_item;1821 1822 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);1823 if (WARN_ON(!policer_item))1824 return -EINVAL;1825 1826 return __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id,1827 rate, burst, false, extack);1828}1829 1830int1831mlxsw_sp_trap_policer_counter_get(struct mlxsw_core *mlxsw_core,1832 const struct devlink_trap_policer *policer,1833 u64 *p_drops)1834{1835 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);1836 struct mlxsw_sp_trap_policer_item *policer_item;1837 char qpcr_pl[MLXSW_REG_QPCR_LEN];1838 int err;1839 1840 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id);1841 if (WARN_ON(!policer_item))1842 return -EINVAL;1843 1844 mlxsw_reg_qpcr_pack(qpcr_pl, policer_item->hw_id,1845 MLXSW_REG_QPCR_IR_UNITS_M, false, 0, 0);1846 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);1847 if (err)1848 return err;1849 1850 *p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl);1851 1852 return 0;1853}1854 1855int mlxsw_sp_trap_group_policer_hw_id_get(struct mlxsw_sp *mlxsw_sp, u16 id,1856 bool *p_enabled, u16 *p_hw_id)1857{1858 struct mlxsw_sp_trap_policer_item *pol_item;1859 struct mlxsw_sp_trap_group_item *gr_item;1860 u32 pol_id;1861 1862 gr_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, id);1863 if (!gr_item)1864 return -ENOENT;1865 1866 pol_id = gr_item->group.init_policer_id;1867 if (!pol_id) {1868 *p_enabled = false;1869 return 0;1870 }1871 1872 pol_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, pol_id);1873 if (WARN_ON(!pol_item))1874 return -ENOENT;1875 1876 *p_enabled = true;1877 *p_hw_id = pol_item->hw_id;1878 return 0;1879}1880 1881static const struct mlxsw_sp_trap_group_item1882mlxsw_sp1_trap_group_items_arr[] = {1883 {1884 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0),1885 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PKT_SAMPLE,1886 .priority = 0,1887 },1888};1889 1890static const struct mlxsw_sp_trap_item1891mlxsw_sp1_trap_items_arr[] = {1892 {1893 .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_SAMPLE, ACL_SAMPLE,1894 MIRROR),1895 .listeners_arr = {1896 MLXSW_RXL(mlxsw_sp_rx_sample_listener, PKT_SAMPLE,1897 MIRROR_TO_CPU, false, SP_PKT_SAMPLE, DISCARD),1898 },1899 },1900};1901 1902static int1903mlxsw_sp1_trap_groups_init(struct mlxsw_sp *mlxsw_sp,1904 const struct mlxsw_sp_trap_group_item **arr,1905 size_t *p_groups_count)1906{1907 *arr = mlxsw_sp1_trap_group_items_arr;1908 *p_groups_count = ARRAY_SIZE(mlxsw_sp1_trap_group_items_arr);1909 1910 return 0;1911}1912 1913static int mlxsw_sp1_traps_init(struct mlxsw_sp *mlxsw_sp,1914 const struct mlxsw_sp_trap_item **arr,1915 size_t *p_traps_count)1916{1917 *arr = mlxsw_sp1_trap_items_arr;1918 *p_traps_count = ARRAY_SIZE(mlxsw_sp1_trap_items_arr);1919 1920 return 0;1921}1922 1923const struct mlxsw_sp_trap_ops mlxsw_sp1_trap_ops = {1924 .groups_init = mlxsw_sp1_trap_groups_init,1925 .traps_init = mlxsw_sp1_traps_init,1926};1927 1928static const struct mlxsw_sp_trap_group_item1929mlxsw_sp2_trap_group_items_arr[] = {1930 {1931 .group = DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 20),1932 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BUFFER_DISCARDS,1933 .priority = 0,1934 .fixed_policer = true,1935 },1936 {1937 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0),1938 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PKT_SAMPLE,1939 .priority = 0,1940 .fixed_policer = true,1941 },1942};1943 1944static const struct mlxsw_sp_trap_item1945mlxsw_sp2_trap_items_arr[] = {1946 {1947 .trap = MLXSW_SP_TRAP_BUFFER_DROP(EARLY_DROP),1948 .listeners_arr = {1949 MLXSW_SP_RXL_BUFFER_DISCARD(INGRESS_WRED),1950 },1951 .is_source = true,1952 },1953 {1954 .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_SAMPLE, ACL_SAMPLE,1955 MIRROR),1956 .listeners_arr = {1957 MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_listener, 1,1958 SP_PKT_SAMPLE,1959 MLXSW_SP_MIRROR_REASON_INGRESS),1960 MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_tx_listener, 1,1961 SP_PKT_SAMPLE,1962 MLXSW_SP_MIRROR_REASON_EGRESS),1963 MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_acl_listener, 1,1964 SP_PKT_SAMPLE,1965 MLXSW_SP_MIRROR_REASON_POLICY_ENGINE),1966 },1967 },1968};1969 1970static int1971mlxsw_sp2_trap_groups_init(struct mlxsw_sp *mlxsw_sp,1972 const struct mlxsw_sp_trap_group_item **arr,1973 size_t *p_groups_count)1974{1975 *arr = mlxsw_sp2_trap_group_items_arr;1976 *p_groups_count = ARRAY_SIZE(mlxsw_sp2_trap_group_items_arr);1977 1978 return 0;1979}1980 1981static int mlxsw_sp2_traps_init(struct mlxsw_sp *mlxsw_sp,1982 const struct mlxsw_sp_trap_item **arr,1983 size_t *p_traps_count)1984{1985 *arr = mlxsw_sp2_trap_items_arr;1986 *p_traps_count = ARRAY_SIZE(mlxsw_sp2_trap_items_arr);1987 1988 return 0;1989}1990 1991const struct mlxsw_sp_trap_ops mlxsw_sp2_trap_ops = {1992 .groups_init = mlxsw_sp2_trap_groups_init,1993 .traps_init = mlxsw_sp2_traps_init,1994};1995