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 struct mlxsw_sp_trap_policer_item { 16 struct devlink_trap_policer policer; 17 u16 hw_id; 18 }; 19 20 struct 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 29 struct 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 */ 38 enum { 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 51 enum { 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 62 static 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 88 static 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 112 static 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 141 static 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 167 static 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 179 static 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 186 static 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 194 static 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 211 static struct mlxsw_sp_port * 212 mlxsw_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 238 static 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 260 static 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); 292 out: 293 consume_skb(skb); 294 } 295 296 static 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); 342 out: 343 consume_skb(skb); 344 } 345 346 static 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); 378 out: 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 */ 451 static const struct mlxsw_sp_trap_policer_item 452 mlxsw_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 518 static 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 641 static 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 not 1100 * used in this file, so undefine it. 1101 */ 1102 #undef IPV6_ROUTER_ALERT 1103 .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 1190 static struct mlxsw_sp_trap_policer_item * 1191 mlxsw_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 1204 static struct mlxsw_sp_trap_group_item * 1205 mlxsw_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 1218 static struct mlxsw_sp_trap_item * 1219 mlxsw_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 1232 static 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 packets 1239 * 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 1252 static 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 1261 static 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 available 1289 * 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 override 1296 * 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 1308 static void mlxsw_sp_trap_policer_items_arr_fini(struct mlxsw_sp *mlxsw_sp) 1309 { 1310 kfree(mlxsw_sp->trap->policer_items_arr); 1311 } 1312 1313 static 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 1334 err_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 1344 static 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 1359 static 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 trap 1374 * 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 1391 static void mlxsw_sp_trap_group_items_arr_fini(struct mlxsw_sp *mlxsw_sp) 1392 { 1393 kfree(mlxsw_sp->trap->group_items_arr); 1394 } 1395 1396 static 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 1416 err_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 1425 static 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 1440 static bool 1441 mlxsw_sp_trap_listener_is_valid(const struct mlxsw_listener *listener) 1442 { 1443 return listener->trap_id != 0; 1444 } 1445 1446 static 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 trap 1461 * 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 1478 static void mlxsw_sp_trap_items_arr_fini(struct mlxsw_sp *mlxsw_sp) 1479 { 1480 kfree(mlxsw_sp->trap->trap_items_arr); 1481 } 1482 1483 static 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 1504 err_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 1513 static 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 1528 int 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 1554 err_traps_init: 1555 mlxsw_sp_trap_groups_fini(mlxsw_sp); 1556 err_trap_groups_init: 1557 mlxsw_sp_trap_policers_fini(mlxsw_sp); 1558 return err; 1559 } 1560 1561 void 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 1568 int 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 1594 void 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 1615 int 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 1660 static int 1661 __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 1694 int 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 1701 int 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 1712 static int 1713 mlxsw_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 of 1720 * policers we registered with devlink is in according with the number 1721 * 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 1733 static void 1734 mlxsw_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 1740 static 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 1755 static 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 1773 int 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 1796 err_trap_policer_set: 1797 mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item); 1798 return err; 1799 } 1800 1801 void 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 1814 int 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 1830 int 1831 mlxsw_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 1855 int 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 1881 static const struct mlxsw_sp_trap_group_item 1882 mlxsw_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 1890 static const struct mlxsw_sp_trap_item 1891 mlxsw_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 1902 static int 1903 mlxsw_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 1913 static 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 1923 const 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 1928 static const struct mlxsw_sp_trap_group_item 1929 mlxsw_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 1944 static const struct mlxsw_sp_trap_item 1945 mlxsw_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 1970 static int 1971 mlxsw_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 1981 static 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 1991 const 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