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