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 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 true, SP_LLDP, DISCARD), 868 }, 869 }, 870 { 871 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR), 872 .listeners_arr = { 873 MLXSW_SP_RXL_MARK(IGMP_QUERY, MC_SNOOPING, 874 MIRROR_TO_CPU, false), 875 }, 876 }, 877 { 878 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING, 879 TRAP), 880 .listeners_arr = { 881 MLXSW_SP_RXL_NO_MARK(IGMP_V1_REPORT, MC_SNOOPING, 882 TRAP_TO_CPU, false), 883 }, 884 }, 885 { 886 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_REPORT, MC_SNOOPING, 887 TRAP), 888 .listeners_arr = { 889 MLXSW_SP_RXL_NO_MARK(IGMP_V2_REPORT, MC_SNOOPING, 890 TRAP_TO_CPU, false), 891 }, 892 }, 893 { 894 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V3_REPORT, MC_SNOOPING, 895 TRAP), 896 .listeners_arr = { 897 MLXSW_SP_RXL_NO_MARK(IGMP_V3_REPORT, MC_SNOOPING, 898 TRAP_TO_CPU, false), 899 }, 900 }, 901 { 902 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_LEAVE, MC_SNOOPING, 903 TRAP), 904 .listeners_arr = { 905 MLXSW_SP_RXL_NO_MARK(IGMP_V2_LEAVE, MC_SNOOPING, 906 TRAP_TO_CPU, false), 907 }, 908 }, 909 { 910 .trap = MLXSW_SP_TRAP_CONTROL(MLD_QUERY, MC_SNOOPING, MIRROR), 911 .listeners_arr = { 912 MLXSW_SP_RXL_MARK(IPV6_MLDV12_LISTENER_QUERY, 913 MC_SNOOPING, MIRROR_TO_CPU, false), 914 }, 915 }, 916 { 917 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_REPORT, MC_SNOOPING, 918 TRAP), 919 .listeners_arr = { 920 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_REPORT, 921 MC_SNOOPING, TRAP_TO_CPU, false), 922 }, 923 }, 924 { 925 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V2_REPORT, MC_SNOOPING, 926 TRAP), 927 .listeners_arr = { 928 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV2_LISTENER_REPORT, 929 MC_SNOOPING, TRAP_TO_CPU, false), 930 }, 931 }, 932 { 933 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_DONE, MC_SNOOPING, 934 TRAP), 935 .listeners_arr = { 936 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_DONE, 937 MC_SNOOPING, TRAP_TO_CPU, false), 938 }, 939 }, 940 { 941 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_DHCP, DHCP, TRAP), 942 .listeners_arr = { 943 MLXSW_SP_RXL_MARK(IPV4_DHCP, DHCP, TRAP_TO_CPU, false), 944 }, 945 }, 946 { 947 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DHCP, DHCP, TRAP), 948 .listeners_arr = { 949 MLXSW_SP_RXL_MARK(IPV6_DHCP, DHCP, TRAP_TO_CPU, false), 950 }, 951 }, 952 { 953 .trap = MLXSW_SP_TRAP_CONTROL(ARP_REQUEST, NEIGH_DISCOVERY, 954 MIRROR), 955 .listeners_arr = { 956 MLXSW_SP_RXL_MARK(ROUTER_ARPBC, NEIGH_DISCOVERY, 957 TRAP_TO_CPU, false), 958 }, 959 }, 960 { 961 .trap = MLXSW_SP_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY, 962 MIRROR), 963 .listeners_arr = { 964 MLXSW_SP_RXL_MARK(ROUTER_ARPUC, NEIGH_DISCOVERY, 965 TRAP_TO_CPU, 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 = devl_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 devl_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 devl_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 = devl_trap_groups_register(devlink, &group_item->group, 1); 1385 if (err) 1386 goto err_trap_group_register; 1387 } 1388 1389 return 0; 1390 1391 err_trap_group_register: 1392 for (i--; i >= 0; i--) { 1393 group_item = &trap->group_items_arr[i]; 1394 devl_trap_groups_unregister(devlink, &group_item->group, 1); 1395 } 1396 mlxsw_sp_trap_group_items_arr_fini(mlxsw_sp); 1397 return err; 1398 } 1399 1400 static void mlxsw_sp_trap_groups_fini(struct mlxsw_sp *mlxsw_sp) 1401 { 1402 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1403 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1404 int i; 1405 1406 for (i = trap->groups_count - 1; i >= 0; i--) { 1407 const struct mlxsw_sp_trap_group_item *group_item; 1408 1409 group_item = &trap->group_items_arr[i]; 1410 devl_trap_groups_unregister(devlink, &group_item->group, 1); 1411 } 1412 mlxsw_sp_trap_group_items_arr_fini(mlxsw_sp); 1413 } 1414 1415 static bool 1416 mlxsw_sp_trap_listener_is_valid(const struct mlxsw_listener *listener) 1417 { 1418 return listener->trap_id != 0; 1419 } 1420 1421 static int mlxsw_sp_trap_items_arr_init(struct mlxsw_sp *mlxsw_sp) 1422 { 1423 size_t common_traps_count = ARRAY_SIZE(mlxsw_sp_trap_items_arr); 1424 const struct mlxsw_sp_trap_item *spec_trap_items_arr; 1425 size_t elem_size = sizeof(struct mlxsw_sp_trap_item); 1426 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1427 size_t traps_count, spec_traps_count; 1428 int err; 1429 1430 err = mlxsw_sp->trap_ops->traps_init(mlxsw_sp, &spec_trap_items_arr, 1431 &spec_traps_count); 1432 if (err) 1433 return err; 1434 1435 /* The trap items array is created by concatenating the common trap 1436 * items and the ASIC-specific trap items. 1437 */ 1438 traps_count = common_traps_count + spec_traps_count; 1439 trap->trap_items_arr = kcalloc(traps_count, elem_size, GFP_KERNEL); 1440 if (!trap->trap_items_arr) 1441 return -ENOMEM; 1442 1443 memcpy(trap->trap_items_arr, mlxsw_sp_trap_items_arr, 1444 elem_size * common_traps_count); 1445 memcpy(trap->trap_items_arr + common_traps_count, 1446 spec_trap_items_arr, elem_size * spec_traps_count); 1447 1448 trap->traps_count = traps_count; 1449 1450 return 0; 1451 } 1452 1453 static void mlxsw_sp_trap_items_arr_fini(struct mlxsw_sp *mlxsw_sp) 1454 { 1455 kfree(mlxsw_sp->trap->trap_items_arr); 1456 } 1457 1458 static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp) 1459 { 1460 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1461 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1462 const struct mlxsw_sp_trap_item *trap_item; 1463 int err, i; 1464 1465 err = mlxsw_sp_trap_items_arr_init(mlxsw_sp); 1466 if (err) 1467 return err; 1468 1469 for (i = 0; i < trap->traps_count; i++) { 1470 trap_item = &trap->trap_items_arr[i]; 1471 err = devl_traps_register(devlink, &trap_item->trap, 1, 1472 mlxsw_sp); 1473 if (err) 1474 goto err_trap_register; 1475 } 1476 1477 return 0; 1478 1479 err_trap_register: 1480 for (i--; i >= 0; i--) { 1481 trap_item = &trap->trap_items_arr[i]; 1482 devl_traps_unregister(devlink, &trap_item->trap, 1); 1483 } 1484 mlxsw_sp_trap_items_arr_fini(mlxsw_sp); 1485 return err; 1486 } 1487 1488 static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) 1489 { 1490 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1491 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1492 int i; 1493 1494 for (i = trap->traps_count - 1; i >= 0; i--) { 1495 const struct mlxsw_sp_trap_item *trap_item; 1496 1497 trap_item = &trap->trap_items_arr[i]; 1498 devl_traps_unregister(devlink, &trap_item->trap, 1); 1499 } 1500 mlxsw_sp_trap_items_arr_fini(mlxsw_sp); 1501 } 1502 1503 int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp) 1504 { 1505 int err; 1506 1507 err = mlxsw_sp_trap_cpu_policers_set(mlxsw_sp); 1508 if (err) 1509 return err; 1510 1511 err = mlxsw_sp_trap_dummy_group_init(mlxsw_sp); 1512 if (err) 1513 return err; 1514 1515 err = mlxsw_sp_trap_policers_init(mlxsw_sp); 1516 if (err) 1517 return err; 1518 1519 err = mlxsw_sp_trap_groups_init(mlxsw_sp); 1520 if (err) 1521 goto err_trap_groups_init; 1522 1523 err = mlxsw_sp_traps_init(mlxsw_sp); 1524 if (err) 1525 goto err_traps_init; 1526 1527 return 0; 1528 1529 err_traps_init: 1530 mlxsw_sp_trap_groups_fini(mlxsw_sp); 1531 err_trap_groups_init: 1532 mlxsw_sp_trap_policers_fini(mlxsw_sp); 1533 return err; 1534 } 1535 1536 void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp) 1537 { 1538 mlxsw_sp_traps_fini(mlxsw_sp); 1539 mlxsw_sp_trap_groups_fini(mlxsw_sp); 1540 mlxsw_sp_trap_policers_fini(mlxsw_sp); 1541 } 1542 1543 int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core, 1544 const struct devlink_trap *trap, void *trap_ctx) 1545 { 1546 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1547 const struct mlxsw_sp_trap_item *trap_item; 1548 int i; 1549 1550 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); 1551 if (WARN_ON(!trap_item)) 1552 return -EINVAL; 1553 1554 for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) { 1555 const struct mlxsw_listener *listener; 1556 int err; 1557 1558 listener = &trap_item->listeners_arr[i]; 1559 if (!mlxsw_sp_trap_listener_is_valid(listener)) 1560 continue; 1561 err = mlxsw_core_trap_register(mlxsw_core, listener, trap_ctx); 1562 if (err) 1563 return err; 1564 } 1565 1566 return 0; 1567 } 1568 1569 void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core, 1570 const struct devlink_trap *trap, void *trap_ctx) 1571 { 1572 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1573 const struct mlxsw_sp_trap_item *trap_item; 1574 int i; 1575 1576 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); 1577 if (WARN_ON(!trap_item)) 1578 return; 1579 1580 for (i = MLXSW_SP_TRAP_LISTENERS_MAX - 1; i >= 0; i--) { 1581 const struct mlxsw_listener *listener; 1582 1583 listener = &trap_item->listeners_arr[i]; 1584 if (!mlxsw_sp_trap_listener_is_valid(listener)) 1585 continue; 1586 mlxsw_core_trap_unregister(mlxsw_core, listener, trap_ctx); 1587 } 1588 } 1589 1590 int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core, 1591 const struct devlink_trap *trap, 1592 enum devlink_trap_action action, 1593 struct netlink_ext_ack *extack) 1594 { 1595 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1596 const struct mlxsw_sp_trap_item *trap_item; 1597 int i; 1598 1599 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); 1600 if (WARN_ON(!trap_item)) 1601 return -EINVAL; 1602 1603 if (trap_item->is_source) { 1604 NL_SET_ERR_MSG_MOD(extack, "Changing the action of source traps is not supported"); 1605 return -EOPNOTSUPP; 1606 } 1607 1608 for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) { 1609 const struct mlxsw_listener *listener; 1610 bool enabled; 1611 int err; 1612 1613 listener = &trap_item->listeners_arr[i]; 1614 if (!mlxsw_sp_trap_listener_is_valid(listener)) 1615 continue; 1616 1617 switch (action) { 1618 case DEVLINK_TRAP_ACTION_DROP: 1619 enabled = false; 1620 break; 1621 case DEVLINK_TRAP_ACTION_TRAP: 1622 enabled = true; 1623 break; 1624 default: 1625 return -EINVAL; 1626 } 1627 err = mlxsw_core_trap_state_set(mlxsw_core, listener, enabled); 1628 if (err) 1629 return err; 1630 } 1631 1632 return 0; 1633 } 1634 1635 static int 1636 __mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, 1637 const struct devlink_trap_group *group, 1638 u32 policer_id, struct netlink_ext_ack *extack) 1639 { 1640 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1641 u16 hw_policer_id = MLXSW_REG_HTGT_INVALID_POLICER; 1642 const struct mlxsw_sp_trap_group_item *group_item; 1643 char htgt_pl[MLXSW_REG_HTGT_LEN]; 1644 1645 group_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, group->id); 1646 if (WARN_ON(!group_item)) 1647 return -EINVAL; 1648 1649 if (group_item->fixed_policer && policer_id != group->init_policer_id) { 1650 NL_SET_ERR_MSG_MOD(extack, "Changing the policer binding of this group is not supported"); 1651 return -EOPNOTSUPP; 1652 } 1653 1654 if (policer_id) { 1655 struct mlxsw_sp_trap_policer_item *policer_item; 1656 1657 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, 1658 policer_id); 1659 if (WARN_ON(!policer_item)) 1660 return -EINVAL; 1661 hw_policer_id = policer_item->hw_id; 1662 } 1663 1664 mlxsw_reg_htgt_pack(htgt_pl, group_item->hw_group_id, hw_policer_id, 1665 group_item->priority, group_item->priority); 1666 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); 1667 } 1668 1669 int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, 1670 const struct devlink_trap_group *group) 1671 { 1672 return __mlxsw_sp_trap_group_init(mlxsw_core, group, 1673 group->init_policer_id, NULL); 1674 } 1675 1676 int mlxsw_sp_trap_group_set(struct mlxsw_core *mlxsw_core, 1677 const struct devlink_trap_group *group, 1678 const struct devlink_trap_policer *policer, 1679 struct netlink_ext_ack *extack) 1680 { 1681 u32 policer_id = policer ? policer->id : 0; 1682 1683 return __mlxsw_sp_trap_group_init(mlxsw_core, group, policer_id, 1684 extack); 1685 } 1686 1687 static int 1688 mlxsw_sp_trap_policer_item_init(struct mlxsw_sp *mlxsw_sp, 1689 struct mlxsw_sp_trap_policer_item *policer_item) 1690 { 1691 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1692 u16 hw_id; 1693 1694 /* We should be able to allocate a policer because the number of 1695 * policers we registered with devlink is in according with the number 1696 * of available policers. 1697 */ 1698 hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers); 1699 if (WARN_ON(hw_id == trap->max_policers)) 1700 return -ENOBUFS; 1701 1702 __set_bit(hw_id, trap->policers_usage); 1703 policer_item->hw_id = hw_id; 1704 1705 return 0; 1706 } 1707 1708 static void 1709 mlxsw_sp_trap_policer_item_fini(struct mlxsw_sp *mlxsw_sp, 1710 struct mlxsw_sp_trap_policer_item *policer_item) 1711 { 1712 __clear_bit(policer_item->hw_id, mlxsw_sp->trap->policers_usage); 1713 } 1714 1715 static int mlxsw_sp_trap_policer_bs(u64 burst, u8 *p_burst_size, 1716 struct netlink_ext_ack *extack) 1717 { 1718 int bs = fls64(burst) - 1; 1719 1720 if (burst != (BIT_ULL(bs))) { 1721 NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two"); 1722 return -EINVAL; 1723 } 1724 1725 *p_burst_size = bs; 1726 1727 return 0; 1728 } 1729 1730 static int __mlxsw_sp_trap_policer_set(struct mlxsw_sp *mlxsw_sp, u16 hw_id, 1731 u64 rate, u64 burst, bool clear_counter, 1732 struct netlink_ext_ack *extack) 1733 { 1734 char qpcr_pl[MLXSW_REG_QPCR_LEN]; 1735 u8 burst_size; 1736 int err; 1737 1738 err = mlxsw_sp_trap_policer_bs(burst, &burst_size, extack); 1739 if (err) 1740 return err; 1741 1742 mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M, false, 1743 rate, burst_size); 1744 mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, clear_counter); 1745 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 1746 } 1747 1748 int mlxsw_sp_trap_policer_init(struct mlxsw_core *mlxsw_core, 1749 const struct devlink_trap_policer *policer) 1750 { 1751 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1752 struct mlxsw_sp_trap_policer_item *policer_item; 1753 int err; 1754 1755 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1756 if (WARN_ON(!policer_item)) 1757 return -EINVAL; 1758 1759 err = mlxsw_sp_trap_policer_item_init(mlxsw_sp, policer_item); 1760 if (err) 1761 return err; 1762 1763 err = __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id, 1764 policer->init_rate, 1765 policer->init_burst, true, NULL); 1766 if (err) 1767 goto err_trap_policer_set; 1768 1769 return 0; 1770 1771 err_trap_policer_set: 1772 mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item); 1773 return err; 1774 } 1775 1776 void mlxsw_sp_trap_policer_fini(struct mlxsw_core *mlxsw_core, 1777 const struct devlink_trap_policer *policer) 1778 { 1779 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1780 struct mlxsw_sp_trap_policer_item *policer_item; 1781 1782 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1783 if (WARN_ON(!policer_item)) 1784 return; 1785 1786 mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item); 1787 } 1788 1789 int mlxsw_sp_trap_policer_set(struct mlxsw_core *mlxsw_core, 1790 const struct devlink_trap_policer *policer, 1791 u64 rate, u64 burst, 1792 struct netlink_ext_ack *extack) 1793 { 1794 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1795 struct mlxsw_sp_trap_policer_item *policer_item; 1796 1797 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1798 if (WARN_ON(!policer_item)) 1799 return -EINVAL; 1800 1801 return __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id, 1802 rate, burst, false, extack); 1803 } 1804 1805 int 1806 mlxsw_sp_trap_policer_counter_get(struct mlxsw_core *mlxsw_core, 1807 const struct devlink_trap_policer *policer, 1808 u64 *p_drops) 1809 { 1810 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1811 struct mlxsw_sp_trap_policer_item *policer_item; 1812 char qpcr_pl[MLXSW_REG_QPCR_LEN]; 1813 int err; 1814 1815 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1816 if (WARN_ON(!policer_item)) 1817 return -EINVAL; 1818 1819 mlxsw_reg_qpcr_pack(qpcr_pl, policer_item->hw_id, 1820 MLXSW_REG_QPCR_IR_UNITS_M, false, 0, 0); 1821 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 1822 if (err) 1823 return err; 1824 1825 *p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl); 1826 1827 return 0; 1828 } 1829 1830 int mlxsw_sp_trap_group_policer_hw_id_get(struct mlxsw_sp *mlxsw_sp, u16 id, 1831 bool *p_enabled, u16 *p_hw_id) 1832 { 1833 struct mlxsw_sp_trap_policer_item *pol_item; 1834 struct mlxsw_sp_trap_group_item *gr_item; 1835 u32 pol_id; 1836 1837 gr_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, id); 1838 if (!gr_item) 1839 return -ENOENT; 1840 1841 pol_id = gr_item->group.init_policer_id; 1842 if (!pol_id) { 1843 *p_enabled = false; 1844 return 0; 1845 } 1846 1847 pol_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, pol_id); 1848 if (WARN_ON(!pol_item)) 1849 return -ENOENT; 1850 1851 *p_enabled = true; 1852 *p_hw_id = pol_item->hw_id; 1853 return 0; 1854 } 1855 1856 static const struct mlxsw_sp_trap_group_item 1857 mlxsw_sp1_trap_group_items_arr[] = { 1858 { 1859 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0), 1860 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PKT_SAMPLE, 1861 .priority = 0, 1862 }, 1863 }; 1864 1865 static const struct mlxsw_sp_trap_item 1866 mlxsw_sp1_trap_items_arr[] = { 1867 { 1868 .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_SAMPLE, ACL_SAMPLE, 1869 MIRROR), 1870 .listeners_arr = { 1871 MLXSW_RXL(mlxsw_sp_rx_sample_listener, PKT_SAMPLE, 1872 MIRROR_TO_CPU, false, SP_PKT_SAMPLE, DISCARD), 1873 }, 1874 }, 1875 }; 1876 1877 static int 1878 mlxsw_sp1_trap_groups_init(struct mlxsw_sp *mlxsw_sp, 1879 const struct mlxsw_sp_trap_group_item **arr, 1880 size_t *p_groups_count) 1881 { 1882 *arr = mlxsw_sp1_trap_group_items_arr; 1883 *p_groups_count = ARRAY_SIZE(mlxsw_sp1_trap_group_items_arr); 1884 1885 return 0; 1886 } 1887 1888 static int mlxsw_sp1_traps_init(struct mlxsw_sp *mlxsw_sp, 1889 const struct mlxsw_sp_trap_item **arr, 1890 size_t *p_traps_count) 1891 { 1892 *arr = mlxsw_sp1_trap_items_arr; 1893 *p_traps_count = ARRAY_SIZE(mlxsw_sp1_trap_items_arr); 1894 1895 return 0; 1896 } 1897 1898 const struct mlxsw_sp_trap_ops mlxsw_sp1_trap_ops = { 1899 .groups_init = mlxsw_sp1_trap_groups_init, 1900 .traps_init = mlxsw_sp1_traps_init, 1901 }; 1902 1903 static const struct mlxsw_sp_trap_group_item 1904 mlxsw_sp2_trap_group_items_arr[] = { 1905 { 1906 .group = DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 20), 1907 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BUFFER_DISCARDS, 1908 .priority = 0, 1909 .fixed_policer = true, 1910 }, 1911 { 1912 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0), 1913 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PKT_SAMPLE, 1914 .priority = 0, 1915 .fixed_policer = true, 1916 }, 1917 }; 1918 1919 static const struct mlxsw_sp_trap_item 1920 mlxsw_sp2_trap_items_arr[] = { 1921 { 1922 .trap = MLXSW_SP_TRAP_BUFFER_DROP(EARLY_DROP), 1923 .listeners_arr = { 1924 MLXSW_SP_RXL_BUFFER_DISCARD(INGRESS_WRED), 1925 }, 1926 .is_source = true, 1927 }, 1928 { 1929 .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_SAMPLE, ACL_SAMPLE, 1930 MIRROR), 1931 .listeners_arr = { 1932 MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_listener, 1, 1933 SP_PKT_SAMPLE, 1934 MLXSW_SP_MIRROR_REASON_INGRESS), 1935 MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_tx_listener, 1, 1936 SP_PKT_SAMPLE, 1937 MLXSW_SP_MIRROR_REASON_EGRESS), 1938 MLXSW_RXL_MIRROR(mlxsw_sp_rx_sample_acl_listener, 1, 1939 SP_PKT_SAMPLE, 1940 MLXSW_SP_MIRROR_REASON_POLICY_ENGINE), 1941 }, 1942 }, 1943 }; 1944 1945 static int 1946 mlxsw_sp2_trap_groups_init(struct mlxsw_sp *mlxsw_sp, 1947 const struct mlxsw_sp_trap_group_item **arr, 1948 size_t *p_groups_count) 1949 { 1950 *arr = mlxsw_sp2_trap_group_items_arr; 1951 *p_groups_count = ARRAY_SIZE(mlxsw_sp2_trap_group_items_arr); 1952 1953 return 0; 1954 } 1955 1956 static int mlxsw_sp2_traps_init(struct mlxsw_sp *mlxsw_sp, 1957 const struct mlxsw_sp_trap_item **arr, 1958 size_t *p_traps_count) 1959 { 1960 *arr = mlxsw_sp2_trap_items_arr; 1961 *p_traps_count = ARRAY_SIZE(mlxsw_sp2_trap_items_arr); 1962 1963 return 0; 1964 } 1965 1966 const struct mlxsw_sp_trap_ops mlxsw_sp2_trap_ops = { 1967 .groups_init = mlxsw_sp2_trap_groups_init, 1968 .traps_init = mlxsw_sp2_traps_init, 1969 }; 1970