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 early dropped. */ 53 MLXSW_SP_MIRROR_REASON_INGRESS_WRED = 9, 54 }; 55 56 static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, 57 u8 local_port, 58 struct mlxsw_sp_port *mlxsw_sp_port) 59 { 60 struct mlxsw_sp_port_pcpu_stats *pcpu_stats; 61 62 if (unlikely(!mlxsw_sp_port)) { 63 dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n", 64 local_port); 65 kfree_skb(skb); 66 return -EINVAL; 67 } 68 69 skb->dev = mlxsw_sp_port->dev; 70 71 pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats); 72 u64_stats_update_begin(&pcpu_stats->syncp); 73 pcpu_stats->rx_packets++; 74 pcpu_stats->rx_bytes += skb->len; 75 u64_stats_update_end(&pcpu_stats->syncp); 76 77 skb->protocol = eth_type_trans(skb, skb->dev); 78 79 return 0; 80 } 81 82 static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port, 83 void *trap_ctx) 84 { 85 struct devlink_port *in_devlink_port; 86 struct mlxsw_sp_port *mlxsw_sp_port; 87 struct mlxsw_sp *mlxsw_sp; 88 struct devlink *devlink; 89 int err; 90 91 mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); 92 mlxsw_sp_port = mlxsw_sp->ports[local_port]; 93 94 err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port); 95 if (err) 96 return; 97 98 devlink = priv_to_devlink(mlxsw_sp->core); 99 in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, 100 local_port); 101 skb_push(skb, ETH_HLEN); 102 devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL); 103 consume_skb(skb); 104 } 105 106 static void mlxsw_sp_rx_acl_drop_listener(struct sk_buff *skb, u8 local_port, 107 void *trap_ctx) 108 { 109 u32 cookie_index = mlxsw_skb_cb(skb)->cookie_index; 110 const struct flow_action_cookie *fa_cookie; 111 struct devlink_port *in_devlink_port; 112 struct mlxsw_sp_port *mlxsw_sp_port; 113 struct mlxsw_sp *mlxsw_sp; 114 struct devlink *devlink; 115 int err; 116 117 mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); 118 mlxsw_sp_port = mlxsw_sp->ports[local_port]; 119 120 err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port); 121 if (err) 122 return; 123 124 devlink = priv_to_devlink(mlxsw_sp->core); 125 in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, 126 local_port); 127 skb_push(skb, ETH_HLEN); 128 rcu_read_lock(); 129 fa_cookie = mlxsw_sp_acl_act_cookie_lookup(mlxsw_sp, cookie_index); 130 devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, fa_cookie); 131 rcu_read_unlock(); 132 consume_skb(skb); 133 } 134 135 static int __mlxsw_sp_rx_no_mark_listener(struct sk_buff *skb, u8 local_port, 136 void *trap_ctx) 137 { 138 struct devlink_port *in_devlink_port; 139 struct mlxsw_sp_port *mlxsw_sp_port; 140 struct mlxsw_sp *mlxsw_sp; 141 struct devlink *devlink; 142 int err; 143 144 mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); 145 mlxsw_sp_port = mlxsw_sp->ports[local_port]; 146 147 err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port); 148 if (err) 149 return err; 150 151 devlink = priv_to_devlink(mlxsw_sp->core); 152 in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, 153 local_port); 154 skb_push(skb, ETH_HLEN); 155 devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL); 156 skb_pull(skb, ETH_HLEN); 157 158 return 0; 159 } 160 161 static void mlxsw_sp_rx_no_mark_listener(struct sk_buff *skb, u8 local_port, 162 void *trap_ctx) 163 { 164 int err; 165 166 err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx); 167 if (err) 168 return; 169 170 netif_receive_skb(skb); 171 } 172 173 static void mlxsw_sp_rx_mark_listener(struct sk_buff *skb, u8 local_port, 174 void *trap_ctx) 175 { 176 skb->offload_fwd_mark = 1; 177 mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx); 178 } 179 180 static void mlxsw_sp_rx_l3_mark_listener(struct sk_buff *skb, u8 local_port, 181 void *trap_ctx) 182 { 183 skb->offload_l3_fwd_mark = 1; 184 skb->offload_fwd_mark = 1; 185 mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx); 186 } 187 188 static void mlxsw_sp_rx_ptp_listener(struct sk_buff *skb, u8 local_port, 189 void *trap_ctx) 190 { 191 struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); 192 int err; 193 194 err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx); 195 if (err) 196 return; 197 198 /* The PTP handler expects skb->data to point to the start of the 199 * Ethernet header. 200 */ 201 skb_push(skb, ETH_HLEN); 202 mlxsw_sp_ptp_receive(mlxsw_sp, skb, local_port); 203 } 204 205 static void mlxsw_sp_rx_sample_listener(struct sk_buff *skb, u8 local_port, 206 void *trap_ctx) 207 { 208 struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); 209 int err; 210 211 err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx); 212 if (err) 213 return; 214 215 /* The sample handler expects skb->data to point to the start of the 216 * Ethernet header. 217 */ 218 skb_push(skb, ETH_HLEN); 219 mlxsw_sp_sample_receive(mlxsw_sp, skb, local_port); 220 } 221 222 #define MLXSW_SP_TRAP_DROP(_id, _group_id) \ 223 DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 224 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 225 MLXSW_SP_TRAP_METADATA) 226 227 #define MLXSW_SP_TRAP_DROP_EXT(_id, _group_id, _metadata) \ 228 DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 229 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 230 MLXSW_SP_TRAP_METADATA | (_metadata)) 231 232 #define MLXSW_SP_TRAP_BUFFER_DROP(_id) \ 233 DEVLINK_TRAP_GENERIC(DROP, TRAP, _id, \ 234 DEVLINK_TRAP_GROUP_GENERIC_ID_BUFFER_DROPS, \ 235 MLXSW_SP_TRAP_METADATA) 236 237 #define MLXSW_SP_TRAP_DRIVER_DROP(_id, _group_id) \ 238 DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_MLXSW_TRAP_ID_##_id, \ 239 DEVLINK_MLXSW_TRAP_NAME_##_id, \ 240 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 241 MLXSW_SP_TRAP_METADATA) 242 243 #define MLXSW_SP_TRAP_EXCEPTION(_id, _group_id) \ 244 DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \ 245 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 246 MLXSW_SP_TRAP_METADATA) 247 248 #define MLXSW_SP_TRAP_CONTROL(_id, _group_id, _action) \ 249 DEVLINK_TRAP_GENERIC(CONTROL, _action, _id, \ 250 DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 251 MLXSW_SP_TRAP_METADATA) 252 253 #define MLXSW_SP_RXL_DISCARD(_id, _group_id) \ 254 MLXSW_RXL_DIS(mlxsw_sp_rx_drop_listener, DISCARD_##_id, \ 255 TRAP_EXCEPTION_TO_CPU, false, SP_##_group_id, \ 256 SET_FW_DEFAULT, SP_##_group_id) 257 258 #define MLXSW_SP_RXL_ACL_DISCARD(_id, _en_group_id, _dis_group_id) \ 259 MLXSW_RXL_DIS(mlxsw_sp_rx_acl_drop_listener, DISCARD_##_id, \ 260 TRAP_EXCEPTION_TO_CPU, false, SP_##_en_group_id, \ 261 SET_FW_DEFAULT, SP_##_dis_group_id) 262 263 #define MLXSW_SP_RXL_BUFFER_DISCARD(_mirror_reason) \ 264 MLXSW_RXL_MIRROR(mlxsw_sp_rx_drop_listener, 0, SP_BUFFER_DISCARDS, \ 265 MLXSW_SP_MIRROR_REASON_##_mirror_reason) 266 267 #define MLXSW_SP_RXL_EXCEPTION(_id, _group_id, _action) \ 268 MLXSW_RXL(mlxsw_sp_rx_mark_listener, _id, \ 269 _action, false, SP_##_group_id, SET_FW_DEFAULT) 270 271 #define MLXSW_SP_RXL_NO_MARK(_id, _group_id, _action, _is_ctrl) \ 272 MLXSW_RXL(mlxsw_sp_rx_no_mark_listener, _id, _action, \ 273 _is_ctrl, SP_##_group_id, DISCARD) 274 275 #define MLXSW_SP_RXL_MARK(_id, _group_id, _action, _is_ctrl) \ 276 MLXSW_RXL(mlxsw_sp_rx_mark_listener, _id, _action, _is_ctrl, \ 277 SP_##_group_id, DISCARD) 278 279 #define MLXSW_SP_RXL_L3_MARK(_id, _group_id, _action, _is_ctrl) \ 280 MLXSW_RXL(mlxsw_sp_rx_l3_mark_listener, _id, _action, _is_ctrl, \ 281 SP_##_group_id, DISCARD) 282 283 #define MLXSW_SP_TRAP_POLICER(_id, _rate, _burst) \ 284 DEVLINK_TRAP_POLICER(_id, _rate, _burst, \ 285 MLXSW_REG_QPCR_HIGHEST_CIR, \ 286 MLXSW_REG_QPCR_LOWEST_CIR, \ 287 1 << MLXSW_REG_QPCR_HIGHEST_CBS, \ 288 1 << MLXSW_REG_QPCR_LOWEST_CBS) 289 290 /* Ordered by policer identifier */ 291 static const struct mlxsw_sp_trap_policer_item 292 mlxsw_sp_trap_policer_items_arr[] = { 293 { 294 .policer = MLXSW_SP_TRAP_POLICER(1, 10 * 1024, 4096), 295 }, 296 { 297 .policer = MLXSW_SP_TRAP_POLICER(2, 128, 128), 298 }, 299 { 300 .policer = MLXSW_SP_TRAP_POLICER(3, 128, 128), 301 }, 302 { 303 .policer = MLXSW_SP_TRAP_POLICER(4, 128, 128), 304 }, 305 { 306 .policer = MLXSW_SP_TRAP_POLICER(5, 16 * 1024, 8192), 307 }, 308 { 309 .policer = MLXSW_SP_TRAP_POLICER(6, 128, 128), 310 }, 311 { 312 .policer = MLXSW_SP_TRAP_POLICER(7, 1024, 512), 313 }, 314 { 315 .policer = MLXSW_SP_TRAP_POLICER(8, 20 * 1024, 8192), 316 }, 317 { 318 .policer = MLXSW_SP_TRAP_POLICER(9, 128, 128), 319 }, 320 { 321 .policer = MLXSW_SP_TRAP_POLICER(10, 1024, 512), 322 }, 323 { 324 .policer = MLXSW_SP_TRAP_POLICER(11, 256, 128), 325 }, 326 { 327 .policer = MLXSW_SP_TRAP_POLICER(12, 128, 128), 328 }, 329 { 330 .policer = MLXSW_SP_TRAP_POLICER(13, 128, 128), 331 }, 332 { 333 .policer = MLXSW_SP_TRAP_POLICER(14, 1024, 512), 334 }, 335 { 336 .policer = MLXSW_SP_TRAP_POLICER(15, 1024, 512), 337 }, 338 { 339 .policer = MLXSW_SP_TRAP_POLICER(16, 24 * 1024, 16384), 340 }, 341 { 342 .policer = MLXSW_SP_TRAP_POLICER(17, 19 * 1024, 8192), 343 }, 344 { 345 .policer = MLXSW_SP_TRAP_POLICER(18, 1024, 512), 346 }, 347 { 348 .policer = MLXSW_SP_TRAP_POLICER(19, 1024, 512), 349 }, 350 { 351 .policer = MLXSW_SP_TRAP_POLICER(20, 10240, 4096), 352 }, 353 }; 354 355 static const struct mlxsw_sp_trap_group_item mlxsw_sp_trap_group_items_arr[] = { 356 { 357 .group = DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 1), 358 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS, 359 .priority = 0, 360 }, 361 { 362 .group = DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1), 363 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS, 364 .priority = 0, 365 }, 366 { 367 .group = DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 1), 368 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_EXCEPTIONS, 369 .priority = 2, 370 }, 371 { 372 .group = DEVLINK_TRAP_GROUP_GENERIC(TUNNEL_DROPS, 1), 373 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS, 374 .priority = 0, 375 }, 376 { 377 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 1), 378 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS, 379 .priority = 0, 380 }, 381 { 382 .group = DEVLINK_TRAP_GROUP_GENERIC(STP, 2), 383 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_STP, 384 .priority = 5, 385 }, 386 { 387 .group = DEVLINK_TRAP_GROUP_GENERIC(LACP, 3), 388 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LACP, 389 .priority = 5, 390 }, 391 { 392 .group = DEVLINK_TRAP_GROUP_GENERIC(LLDP, 4), 393 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP, 394 .priority = 5, 395 }, 396 { 397 .group = DEVLINK_TRAP_GROUP_GENERIC(MC_SNOOPING, 5), 398 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_MC_SNOOPING, 399 .priority = 3, 400 }, 401 { 402 .group = DEVLINK_TRAP_GROUP_GENERIC(DHCP, 6), 403 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_DHCP, 404 .priority = 2, 405 }, 406 { 407 .group = DEVLINK_TRAP_GROUP_GENERIC(NEIGH_DISCOVERY, 7), 408 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_NEIGH_DISCOVERY, 409 .priority = 2, 410 }, 411 { 412 .group = DEVLINK_TRAP_GROUP_GENERIC(BFD, 8), 413 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BFD, 414 .priority = 5, 415 }, 416 { 417 .group = DEVLINK_TRAP_GROUP_GENERIC(OSPF, 9), 418 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_OSPF, 419 .priority = 5, 420 }, 421 { 422 .group = DEVLINK_TRAP_GROUP_GENERIC(BGP, 10), 423 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BGP, 424 .priority = 4, 425 }, 426 { 427 .group = DEVLINK_TRAP_GROUP_GENERIC(VRRP, 11), 428 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_VRRP, 429 .priority = 5, 430 }, 431 { 432 .group = DEVLINK_TRAP_GROUP_GENERIC(PIM, 12), 433 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PIM, 434 .priority = 5, 435 }, 436 { 437 .group = DEVLINK_TRAP_GROUP_GENERIC(UC_LB, 13), 438 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LBERROR, 439 .priority = 0, 440 }, 441 { 442 .group = DEVLINK_TRAP_GROUP_GENERIC(LOCAL_DELIVERY, 14), 443 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME, 444 .priority = 2, 445 }, 446 { 447 .group = DEVLINK_TRAP_GROUP_GENERIC(EXTERNAL_DELIVERY, 19), 448 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_EXTERNAL_ROUTE, 449 .priority = 1, 450 }, 451 { 452 .group = DEVLINK_TRAP_GROUP_GENERIC(IPV6, 15), 453 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6, 454 .priority = 2, 455 }, 456 { 457 .group = DEVLINK_TRAP_GROUP_GENERIC(PTP_EVENT, 16), 458 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0, 459 .priority = 5, 460 }, 461 { 462 .group = DEVLINK_TRAP_GROUP_GENERIC(PTP_GENERAL, 17), 463 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1, 464 .priority = 2, 465 }, 466 { 467 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0), 468 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PKT_SAMPLE, 469 .priority = 0, 470 }, 471 { 472 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_TRAP, 18), 473 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_FLOW_LOGGING, 474 .priority = 4, 475 }, 476 }; 477 478 static const struct mlxsw_sp_trap_item mlxsw_sp_trap_items_arr[] = { 479 { 480 .trap = MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS), 481 .listeners_arr = { 482 MLXSW_SP_RXL_DISCARD(ING_PACKET_SMAC_MC, L2_DISCARDS), 483 }, 484 }, 485 { 486 .trap = MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS), 487 .listeners_arr = { 488 MLXSW_SP_RXL_DISCARD(ING_SWITCH_VTAG_ALLOW, 489 L2_DISCARDS), 490 }, 491 }, 492 { 493 .trap = MLXSW_SP_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS), 494 .listeners_arr = { 495 MLXSW_SP_RXL_DISCARD(ING_SWITCH_VLAN, L2_DISCARDS), 496 }, 497 }, 498 { 499 .trap = MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS), 500 .listeners_arr = { 501 MLXSW_SP_RXL_DISCARD(ING_SWITCH_STP, L2_DISCARDS), 502 }, 503 }, 504 { 505 .trap = MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS), 506 .listeners_arr = { 507 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS), 508 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS), 509 }, 510 }, 511 { 512 .trap = MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS), 513 .listeners_arr = { 514 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS), 515 }, 516 }, 517 { 518 .trap = MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS), 519 .listeners_arr = { 520 MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS), 521 }, 522 }, 523 { 524 .trap = MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS), 525 .listeners_arr = { 526 MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET, 527 L3_DISCARDS), 528 }, 529 }, 530 { 531 .trap = MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS), 532 .listeners_arr = { 533 MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC, 534 L3_DISCARDS), 535 }, 536 }, 537 { 538 .trap = MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS), 539 .listeners_arr = { 540 MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS), 541 }, 542 }, 543 { 544 .trap = MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS), 545 .listeners_arr = { 546 MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS), 547 }, 548 }, 549 { 550 .trap = MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS), 551 .listeners_arr = { 552 MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS), 553 }, 554 }, 555 { 556 .trap = MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS), 557 .listeners_arr = { 558 MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR, 559 L3_DISCARDS), 560 }, 561 }, 562 { 563 .trap = MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS), 564 .listeners_arr = { 565 MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC, 566 L3_DISCARDS), 567 }, 568 }, 569 { 570 .trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE, 571 L3_DROPS), 572 .listeners_arr = { 573 MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE, 574 L3_DISCARDS), 575 }, 576 }, 577 { 578 .trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, 579 L3_DROPS), 580 .listeners_arr = { 581 MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, 582 L3_DISCARDS), 583 }, 584 }, 585 { 586 .trap = MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_EXCEPTIONS), 587 .listeners_arr = { 588 MLXSW_SP_RXL_EXCEPTION(MTUERROR, L3_EXCEPTIONS, 589 TRAP_TO_CPU), 590 }, 591 }, 592 { 593 .trap = MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS), 594 .listeners_arr = { 595 MLXSW_SP_RXL_EXCEPTION(TTLERROR, L3_EXCEPTIONS, 596 TRAP_TO_CPU), 597 }, 598 }, 599 { 600 .trap = MLXSW_SP_TRAP_EXCEPTION(RPF, L3_EXCEPTIONS), 601 .listeners_arr = { 602 MLXSW_SP_RXL_EXCEPTION(RPF, L3_EXCEPTIONS, TRAP_TO_CPU), 603 }, 604 }, 605 { 606 .trap = MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_EXCEPTIONS), 607 .listeners_arr = { 608 MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, L3_EXCEPTIONS, 609 TRAP_TO_CPU), 610 }, 611 }, 612 { 613 .trap = MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH, 614 L3_EXCEPTIONS), 615 .listeners_arr = { 616 MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, L3_EXCEPTIONS, 617 TRAP_TO_CPU), 618 MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, L3_EXCEPTIONS, 619 TRAP_TO_CPU), 620 MLXSW_SP_RXL_EXCEPTION(RTR_EGRESS0, L3_EXCEPTIONS, 621 TRAP_EXCEPTION_TO_CPU), 622 }, 623 }, 624 { 625 .trap = MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS, 626 L3_EXCEPTIONS), 627 .listeners_arr = { 628 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4, 629 L3_EXCEPTIONS, 630 TRAP_EXCEPTION_TO_CPU), 631 }, 632 }, 633 { 634 .trap = MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS, 635 L3_EXCEPTIONS), 636 .listeners_arr = { 637 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6, 638 L3_EXCEPTIONS, 639 TRAP_EXCEPTION_TO_CPU), 640 }, 641 }, 642 { 643 .trap = MLXSW_SP_TRAP_DRIVER_DROP(IRIF_DISABLED, L3_DROPS), 644 .listeners_arr = { 645 MLXSW_SP_RXL_DISCARD(ROUTER_IRIF_EN, L3_DISCARDS), 646 }, 647 }, 648 { 649 .trap = MLXSW_SP_TRAP_DRIVER_DROP(ERIF_DISABLED, L3_DROPS), 650 .listeners_arr = { 651 MLXSW_SP_RXL_DISCARD(ROUTER_ERIF_EN, L3_DISCARDS), 652 }, 653 }, 654 { 655 .trap = MLXSW_SP_TRAP_DROP(NON_ROUTABLE, L3_DROPS), 656 .listeners_arr = { 657 MLXSW_SP_RXL_DISCARD(NON_ROUTABLE, L3_DISCARDS), 658 }, 659 }, 660 { 661 .trap = MLXSW_SP_TRAP_EXCEPTION(DECAP_ERROR, TUNNEL_DROPS), 662 .listeners_arr = { 663 MLXSW_SP_RXL_EXCEPTION(DECAP_ECN0, TUNNEL_DISCARDS, 664 TRAP_EXCEPTION_TO_CPU), 665 MLXSW_SP_RXL_EXCEPTION(IPIP_DECAP_ERROR, 666 TUNNEL_DISCARDS, 667 TRAP_EXCEPTION_TO_CPU), 668 MLXSW_SP_RXL_EXCEPTION(DISCARD_DEC_PKT, TUNNEL_DISCARDS, 669 TRAP_EXCEPTION_TO_CPU), 670 }, 671 }, 672 { 673 .trap = MLXSW_SP_TRAP_DROP(OVERLAY_SMAC_MC, TUNNEL_DROPS), 674 .listeners_arr = { 675 MLXSW_SP_RXL_DISCARD(OVERLAY_SMAC_MC, TUNNEL_DISCARDS), 676 }, 677 }, 678 { 679 .trap = MLXSW_SP_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, 680 ACL_DROPS, 681 DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 682 .listeners_arr = { 683 MLXSW_SP_RXL_ACL_DISCARD(INGRESS_ACL, ACL_DISCARDS, 684 DUMMY), 685 }, 686 }, 687 { 688 .trap = MLXSW_SP_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, 689 ACL_DROPS, 690 DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 691 .listeners_arr = { 692 MLXSW_SP_RXL_ACL_DISCARD(EGRESS_ACL, ACL_DISCARDS, 693 DUMMY), 694 }, 695 }, 696 { 697 .trap = MLXSW_SP_TRAP_CONTROL(STP, STP, TRAP), 698 .listeners_arr = { 699 MLXSW_SP_RXL_NO_MARK(STP, STP, TRAP_TO_CPU, true), 700 }, 701 }, 702 { 703 .trap = MLXSW_SP_TRAP_CONTROL(LACP, LACP, TRAP), 704 .listeners_arr = { 705 MLXSW_SP_RXL_NO_MARK(LACP, LACP, TRAP_TO_CPU, true), 706 }, 707 }, 708 { 709 .trap = MLXSW_SP_TRAP_CONTROL(LLDP, LLDP, TRAP), 710 .listeners_arr = { 711 MLXSW_RXL(mlxsw_sp_rx_ptp_listener, LLDP, TRAP_TO_CPU, 712 false, SP_LLDP, DISCARD), 713 }, 714 }, 715 { 716 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR), 717 .listeners_arr = { 718 MLXSW_SP_RXL_MARK(IGMP_QUERY, MC_SNOOPING, 719 MIRROR_TO_CPU, false), 720 }, 721 }, 722 { 723 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING, 724 TRAP), 725 .listeners_arr = { 726 MLXSW_SP_RXL_NO_MARK(IGMP_V1_REPORT, MC_SNOOPING, 727 TRAP_TO_CPU, false), 728 }, 729 }, 730 { 731 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_REPORT, MC_SNOOPING, 732 TRAP), 733 .listeners_arr = { 734 MLXSW_SP_RXL_NO_MARK(IGMP_V2_REPORT, MC_SNOOPING, 735 TRAP_TO_CPU, false), 736 }, 737 }, 738 { 739 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V3_REPORT, MC_SNOOPING, 740 TRAP), 741 .listeners_arr = { 742 MLXSW_SP_RXL_NO_MARK(IGMP_V3_REPORT, MC_SNOOPING, 743 TRAP_TO_CPU, false), 744 }, 745 }, 746 { 747 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_LEAVE, MC_SNOOPING, 748 TRAP), 749 .listeners_arr = { 750 MLXSW_SP_RXL_NO_MARK(IGMP_V2_LEAVE, MC_SNOOPING, 751 TRAP_TO_CPU, false), 752 }, 753 }, 754 { 755 .trap = MLXSW_SP_TRAP_CONTROL(MLD_QUERY, MC_SNOOPING, MIRROR), 756 .listeners_arr = { 757 MLXSW_SP_RXL_MARK(IPV6_MLDV12_LISTENER_QUERY, 758 MC_SNOOPING, MIRROR_TO_CPU, false), 759 }, 760 }, 761 { 762 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_REPORT, MC_SNOOPING, 763 TRAP), 764 .listeners_arr = { 765 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_REPORT, 766 MC_SNOOPING, TRAP_TO_CPU, false), 767 }, 768 }, 769 { 770 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V2_REPORT, MC_SNOOPING, 771 TRAP), 772 .listeners_arr = { 773 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV2_LISTENER_REPORT, 774 MC_SNOOPING, TRAP_TO_CPU, false), 775 }, 776 }, 777 { 778 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_DONE, MC_SNOOPING, 779 TRAP), 780 .listeners_arr = { 781 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_DONE, 782 MC_SNOOPING, TRAP_TO_CPU, false), 783 }, 784 }, 785 { 786 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_DHCP, DHCP, TRAP), 787 .listeners_arr = { 788 MLXSW_SP_RXL_MARK(IPV4_DHCP, DHCP, TRAP_TO_CPU, false), 789 }, 790 }, 791 { 792 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DHCP, DHCP, TRAP), 793 .listeners_arr = { 794 MLXSW_SP_RXL_MARK(IPV6_DHCP, DHCP, TRAP_TO_CPU, false), 795 }, 796 }, 797 { 798 .trap = MLXSW_SP_TRAP_CONTROL(ARP_REQUEST, NEIGH_DISCOVERY, 799 MIRROR), 800 .listeners_arr = { 801 MLXSW_SP_RXL_MARK(ARPBC, NEIGH_DISCOVERY, MIRROR_TO_CPU, 802 false), 803 }, 804 }, 805 { 806 .trap = MLXSW_SP_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY, 807 MIRROR), 808 .listeners_arr = { 809 MLXSW_SP_RXL_MARK(ARPUC, NEIGH_DISCOVERY, MIRROR_TO_CPU, 810 false), 811 }, 812 }, 813 { 814 .trap = MLXSW_SP_TRAP_CONTROL(ARP_OVERLAY, NEIGH_DISCOVERY, 815 TRAP), 816 .listeners_arr = { 817 MLXSW_SP_RXL_NO_MARK(NVE_DECAP_ARP, NEIGH_DISCOVERY, 818 TRAP_TO_CPU, false), 819 }, 820 }, 821 { 822 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_SOLICIT, 823 NEIGH_DISCOVERY, TRAP), 824 .listeners_arr = { 825 MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_SOLICITATION, 826 NEIGH_DISCOVERY, TRAP_TO_CPU, false), 827 }, 828 }, 829 { 830 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_ADVERT, 831 NEIGH_DISCOVERY, TRAP), 832 .listeners_arr = { 833 MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_ADVERTISEMENT, 834 NEIGH_DISCOVERY, TRAP_TO_CPU, false), 835 }, 836 }, 837 { 838 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_BFD, BFD, TRAP), 839 .listeners_arr = { 840 MLXSW_SP_RXL_MARK(IPV4_BFD, BFD, TRAP_TO_CPU, false), 841 }, 842 }, 843 { 844 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_BFD, BFD, TRAP), 845 .listeners_arr = { 846 MLXSW_SP_RXL_MARK(IPV6_BFD, BFD, TRAP_TO_CPU, false), 847 }, 848 }, 849 { 850 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_OSPF, OSPF, TRAP), 851 .listeners_arr = { 852 MLXSW_SP_RXL_MARK(IPV4_OSPF, OSPF, TRAP_TO_CPU, false), 853 }, 854 }, 855 { 856 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_OSPF, OSPF, TRAP), 857 .listeners_arr = { 858 MLXSW_SP_RXL_MARK(IPV6_OSPF, OSPF, TRAP_TO_CPU, false), 859 }, 860 }, 861 { 862 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_BGP, BGP, TRAP), 863 .listeners_arr = { 864 MLXSW_SP_RXL_MARK(IPV4_BGP, BGP, TRAP_TO_CPU, false), 865 }, 866 }, 867 { 868 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_BGP, BGP, TRAP), 869 .listeners_arr = { 870 MLXSW_SP_RXL_MARK(IPV6_BGP, BGP, TRAP_TO_CPU, false), 871 }, 872 }, 873 { 874 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_VRRP, VRRP, TRAP), 875 .listeners_arr = { 876 MLXSW_SP_RXL_MARK(IPV4_VRRP, VRRP, TRAP_TO_CPU, false), 877 }, 878 }, 879 { 880 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_VRRP, VRRP, TRAP), 881 .listeners_arr = { 882 MLXSW_SP_RXL_MARK(IPV6_VRRP, VRRP, TRAP_TO_CPU, false), 883 }, 884 }, 885 { 886 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_PIM, PIM, TRAP), 887 .listeners_arr = { 888 MLXSW_SP_RXL_MARK(IPV4_PIM, PIM, TRAP_TO_CPU, false), 889 }, 890 }, 891 { 892 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_PIM, PIM, TRAP), 893 .listeners_arr = { 894 MLXSW_SP_RXL_MARK(IPV6_PIM, PIM, TRAP_TO_CPU, false), 895 }, 896 }, 897 { 898 .trap = MLXSW_SP_TRAP_CONTROL(UC_LB, UC_LB, MIRROR), 899 .listeners_arr = { 900 MLXSW_SP_RXL_L3_MARK(LBERROR, LBERROR, MIRROR_TO_CPU, 901 false), 902 }, 903 }, 904 { 905 .trap = MLXSW_SP_TRAP_CONTROL(LOCAL_ROUTE, LOCAL_DELIVERY, 906 TRAP), 907 .listeners_arr = { 908 MLXSW_SP_RXL_MARK(IP2ME, IP2ME, TRAP_TO_CPU, false), 909 }, 910 }, 911 { 912 .trap = MLXSW_SP_TRAP_CONTROL(EXTERNAL_ROUTE, EXTERNAL_DELIVERY, 913 TRAP), 914 .listeners_arr = { 915 MLXSW_SP_RXL_MARK(RTR_INGRESS0, EXTERNAL_ROUTE, 916 TRAP_TO_CPU, false), 917 }, 918 }, 919 { 920 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_UC_DIP_LINK_LOCAL_SCOPE, 921 LOCAL_DELIVERY, TRAP), 922 .listeners_arr = { 923 MLXSW_SP_RXL_MARK(IPV6_LINK_LOCAL_DEST, IP2ME, 924 TRAP_TO_CPU, false), 925 }, 926 }, 927 { 928 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_ROUTER_ALERT, LOCAL_DELIVERY, 929 TRAP), 930 .listeners_arr = { 931 MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV4, IP2ME, TRAP_TO_CPU, 932 false), 933 }, 934 }, 935 { 936 /* IPV6_ROUTER_ALERT is defined in uAPI as 22, but it is not 937 * used in this file, so undefine it. 938 */ 939 #undef IPV6_ROUTER_ALERT 940 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_ALERT, LOCAL_DELIVERY, 941 TRAP), 942 .listeners_arr = { 943 MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, IP2ME, TRAP_TO_CPU, 944 false), 945 }, 946 }, 947 { 948 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DIP_ALL_NODES, IPV6, TRAP), 949 .listeners_arr = { 950 MLXSW_SP_RXL_MARK(IPV6_ALL_NODES_LINK, IPV6, 951 TRAP_TO_CPU, false), 952 }, 953 }, 954 { 955 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DIP_ALL_ROUTERS, IPV6, TRAP), 956 .listeners_arr = { 957 MLXSW_SP_RXL_MARK(IPV6_ALL_ROUTERS_LINK, IPV6, 958 TRAP_TO_CPU, false), 959 }, 960 }, 961 { 962 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_SOLICIT, IPV6, TRAP), 963 .listeners_arr = { 964 MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_SOLICITATION, IPV6, 965 TRAP_TO_CPU, false), 966 }, 967 }, 968 { 969 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_ADVERT, IPV6, TRAP), 970 .listeners_arr = { 971 MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_ADVERTISEMENT, IPV6, 972 TRAP_TO_CPU, false), 973 }, 974 }, 975 { 976 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_REDIRECT, IPV6, TRAP), 977 .listeners_arr = { 978 MLXSW_SP_RXL_MARK(L3_IPV6_REDIRECTION, IPV6, 979 TRAP_TO_CPU, false), 980 }, 981 }, 982 { 983 .trap = MLXSW_SP_TRAP_CONTROL(PTP_EVENT, PTP_EVENT, TRAP), 984 .listeners_arr = { 985 MLXSW_RXL(mlxsw_sp_rx_ptp_listener, PTP0, TRAP_TO_CPU, 986 false, SP_PTP0, DISCARD), 987 }, 988 }, 989 { 990 .trap = MLXSW_SP_TRAP_CONTROL(PTP_GENERAL, PTP_GENERAL, TRAP), 991 .listeners_arr = { 992 MLXSW_SP_RXL_NO_MARK(PTP1, PTP1, TRAP_TO_CPU, false), 993 }, 994 }, 995 { 996 .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_SAMPLE, ACL_SAMPLE, 997 MIRROR), 998 .listeners_arr = { 999 MLXSW_RXL(mlxsw_sp_rx_sample_listener, PKT_SAMPLE, 1000 MIRROR_TO_CPU, false, SP_PKT_SAMPLE, DISCARD), 1001 }, 1002 }, 1003 { 1004 .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_TRAP, ACL_TRAP, TRAP), 1005 .listeners_arr = { 1006 MLXSW_SP_RXL_NO_MARK(ACL0, FLOW_LOGGING, TRAP_TO_CPU, 1007 false), 1008 }, 1009 }, 1010 { 1011 .trap = MLXSW_SP_TRAP_DROP(BLACKHOLE_NEXTHOP, L3_DROPS), 1012 .listeners_arr = { 1013 MLXSW_SP_RXL_DISCARD(ROUTER3, L3_DISCARDS), 1014 }, 1015 }, 1016 }; 1017 1018 static struct mlxsw_sp_trap_policer_item * 1019 mlxsw_sp_trap_policer_item_lookup(struct mlxsw_sp *mlxsw_sp, u32 id) 1020 { 1021 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1022 int i; 1023 1024 for (i = 0; i < trap->policers_count; i++) { 1025 if (trap->policer_items_arr[i].policer.id == id) 1026 return &trap->policer_items_arr[i]; 1027 } 1028 1029 return NULL; 1030 } 1031 1032 static struct mlxsw_sp_trap_group_item * 1033 mlxsw_sp_trap_group_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id) 1034 { 1035 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1036 int i; 1037 1038 for (i = 0; i < trap->groups_count; i++) { 1039 if (trap->group_items_arr[i].group.id == id) 1040 return &trap->group_items_arr[i]; 1041 } 1042 1043 return NULL; 1044 } 1045 1046 static struct mlxsw_sp_trap_item * 1047 mlxsw_sp_trap_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id) 1048 { 1049 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1050 int i; 1051 1052 for (i = 0; i < trap->traps_count; i++) { 1053 if (trap->trap_items_arr[i].trap.id == id) 1054 return &trap->trap_items_arr[i]; 1055 } 1056 1057 return NULL; 1058 } 1059 1060 static int mlxsw_sp_trap_cpu_policers_set(struct mlxsw_sp *mlxsw_sp) 1061 { 1062 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1063 char qpcr_pl[MLXSW_REG_QPCR_LEN]; 1064 u16 hw_id; 1065 1066 /* The purpose of "thin" policer is to drop as many packets 1067 * as possible. The dummy group is using it. 1068 */ 1069 hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers); 1070 if (WARN_ON(hw_id == trap->max_policers)) 1071 return -ENOBUFS; 1072 1073 __set_bit(hw_id, trap->policers_usage); 1074 trap->thin_policer_hw_id = hw_id; 1075 mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M, 1076 false, 1, 4); 1077 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 1078 } 1079 1080 static int mlxsw_sp_trap_dummy_group_init(struct mlxsw_sp *mlxsw_sp) 1081 { 1082 char htgt_pl[MLXSW_REG_HTGT_LEN]; 1083 1084 mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SP_DUMMY, 1085 mlxsw_sp->trap->thin_policer_hw_id, 0, 1); 1086 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl); 1087 } 1088 1089 static int mlxsw_sp_trap_policer_items_arr_init(struct mlxsw_sp *mlxsw_sp) 1090 { 1091 size_t arr_size = ARRAY_SIZE(mlxsw_sp_trap_policer_items_arr); 1092 size_t elem_size = sizeof(struct mlxsw_sp_trap_policer_item); 1093 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1094 size_t free_policers = 0; 1095 u32 last_id; 1096 int i; 1097 1098 for_each_clear_bit(i, trap->policers_usage, trap->max_policers) 1099 free_policers++; 1100 1101 if (arr_size > free_policers) { 1102 dev_err(mlxsw_sp->bus_info->dev, "Exceeded number of supported packet trap policers\n"); 1103 return -ENOBUFS; 1104 } 1105 1106 trap->policer_items_arr = kcalloc(free_policers, elem_size, GFP_KERNEL); 1107 if (!trap->policer_items_arr) 1108 return -ENOMEM; 1109 1110 trap->policers_count = free_policers; 1111 1112 /* Initialize policer items array with pre-defined policers. */ 1113 memcpy(trap->policer_items_arr, mlxsw_sp_trap_policer_items_arr, 1114 elem_size * arr_size); 1115 1116 /* Initialize policer items array with the rest of the available 1117 * policers. 1118 */ 1119 last_id = mlxsw_sp_trap_policer_items_arr[arr_size - 1].policer.id; 1120 for (i = arr_size; i < trap->policers_count; i++) { 1121 const struct mlxsw_sp_trap_policer_item *policer_item; 1122 1123 /* Use parameters set for first policer and override 1124 * relevant ones. 1125 */ 1126 policer_item = &mlxsw_sp_trap_policer_items_arr[0]; 1127 trap->policer_items_arr[i] = *policer_item; 1128 trap->policer_items_arr[i].policer.id = ++last_id; 1129 trap->policer_items_arr[i].policer.init_rate = 1; 1130 trap->policer_items_arr[i].policer.init_burst = 16; 1131 } 1132 1133 return 0; 1134 } 1135 1136 static void mlxsw_sp_trap_policer_items_arr_fini(struct mlxsw_sp *mlxsw_sp) 1137 { 1138 kfree(mlxsw_sp->trap->policer_items_arr); 1139 } 1140 1141 static int mlxsw_sp_trap_policers_init(struct mlxsw_sp *mlxsw_sp) 1142 { 1143 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1144 const struct mlxsw_sp_trap_policer_item *policer_item; 1145 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1146 int err, i; 1147 1148 err = mlxsw_sp_trap_policer_items_arr_init(mlxsw_sp); 1149 if (err) 1150 return err; 1151 1152 for (i = 0; i < trap->policers_count; i++) { 1153 policer_item = &trap->policer_items_arr[i]; 1154 err = devlink_trap_policers_register(devlink, 1155 &policer_item->policer, 1); 1156 if (err) 1157 goto err_trap_policer_register; 1158 } 1159 1160 return 0; 1161 1162 err_trap_policer_register: 1163 for (i--; i >= 0; i--) { 1164 policer_item = &trap->policer_items_arr[i]; 1165 devlink_trap_policers_unregister(devlink, 1166 &policer_item->policer, 1); 1167 } 1168 mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp); 1169 return err; 1170 } 1171 1172 static void mlxsw_sp_trap_policers_fini(struct mlxsw_sp *mlxsw_sp) 1173 { 1174 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1175 const struct mlxsw_sp_trap_policer_item *policer_item; 1176 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1177 int i; 1178 1179 for (i = trap->policers_count - 1; i >= 0; i--) { 1180 policer_item = &trap->policer_items_arr[i]; 1181 devlink_trap_policers_unregister(devlink, 1182 &policer_item->policer, 1); 1183 } 1184 mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp); 1185 } 1186 1187 static int mlxsw_sp_trap_group_items_arr_init(struct mlxsw_sp *mlxsw_sp) 1188 { 1189 size_t common_groups_count = ARRAY_SIZE(mlxsw_sp_trap_group_items_arr); 1190 const struct mlxsw_sp_trap_group_item *spec_group_items_arr; 1191 size_t elem_size = sizeof(struct mlxsw_sp_trap_group_item); 1192 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1193 size_t groups_count, spec_groups_count; 1194 int err; 1195 1196 err = mlxsw_sp->trap_ops->groups_init(mlxsw_sp, &spec_group_items_arr, 1197 &spec_groups_count); 1198 if (err) 1199 return err; 1200 1201 /* The group items array is created by concatenating the common trap 1202 * group items and the ASIC-specific trap group items. 1203 */ 1204 groups_count = common_groups_count + spec_groups_count; 1205 trap->group_items_arr = kcalloc(groups_count, elem_size, GFP_KERNEL); 1206 if (!trap->group_items_arr) 1207 return -ENOMEM; 1208 1209 memcpy(trap->group_items_arr, mlxsw_sp_trap_group_items_arr, 1210 elem_size * common_groups_count); 1211 memcpy(trap->group_items_arr + common_groups_count, 1212 spec_group_items_arr, elem_size * spec_groups_count); 1213 1214 trap->groups_count = groups_count; 1215 1216 return 0; 1217 } 1218 1219 static void mlxsw_sp_trap_group_items_arr_fini(struct mlxsw_sp *mlxsw_sp) 1220 { 1221 kfree(mlxsw_sp->trap->group_items_arr); 1222 } 1223 1224 static int mlxsw_sp_trap_groups_init(struct mlxsw_sp *mlxsw_sp) 1225 { 1226 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1227 const struct mlxsw_sp_trap_group_item *group_item; 1228 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1229 int err, i; 1230 1231 err = mlxsw_sp_trap_group_items_arr_init(mlxsw_sp); 1232 if (err) 1233 return err; 1234 1235 for (i = 0; i < trap->groups_count; i++) { 1236 group_item = &trap->group_items_arr[i]; 1237 err = devlink_trap_groups_register(devlink, &group_item->group, 1238 1); 1239 if (err) 1240 goto err_trap_group_register; 1241 } 1242 1243 return 0; 1244 1245 err_trap_group_register: 1246 for (i--; i >= 0; i--) { 1247 group_item = &trap->group_items_arr[i]; 1248 devlink_trap_groups_unregister(devlink, &group_item->group, 1); 1249 } 1250 mlxsw_sp_trap_group_items_arr_fini(mlxsw_sp); 1251 return err; 1252 } 1253 1254 static void mlxsw_sp_trap_groups_fini(struct mlxsw_sp *mlxsw_sp) 1255 { 1256 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1257 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1258 int i; 1259 1260 for (i = trap->groups_count - 1; i >= 0; i--) { 1261 const struct mlxsw_sp_trap_group_item *group_item; 1262 1263 group_item = &trap->group_items_arr[i]; 1264 devlink_trap_groups_unregister(devlink, &group_item->group, 1); 1265 } 1266 mlxsw_sp_trap_group_items_arr_fini(mlxsw_sp); 1267 } 1268 1269 static bool 1270 mlxsw_sp_trap_listener_is_valid(const struct mlxsw_listener *listener) 1271 { 1272 return listener->trap_id != 0; 1273 } 1274 1275 static int mlxsw_sp_trap_items_arr_init(struct mlxsw_sp *mlxsw_sp) 1276 { 1277 size_t common_traps_count = ARRAY_SIZE(mlxsw_sp_trap_items_arr); 1278 const struct mlxsw_sp_trap_item *spec_trap_items_arr; 1279 size_t elem_size = sizeof(struct mlxsw_sp_trap_item); 1280 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1281 size_t traps_count, spec_traps_count; 1282 int err; 1283 1284 err = mlxsw_sp->trap_ops->traps_init(mlxsw_sp, &spec_trap_items_arr, 1285 &spec_traps_count); 1286 if (err) 1287 return err; 1288 1289 /* The trap items array is created by concatenating the common trap 1290 * items and the ASIC-specific trap items. 1291 */ 1292 traps_count = common_traps_count + spec_traps_count; 1293 trap->trap_items_arr = kcalloc(traps_count, elem_size, GFP_KERNEL); 1294 if (!trap->trap_items_arr) 1295 return -ENOMEM; 1296 1297 memcpy(trap->trap_items_arr, mlxsw_sp_trap_items_arr, 1298 elem_size * common_traps_count); 1299 memcpy(trap->trap_items_arr + common_traps_count, 1300 spec_trap_items_arr, elem_size * spec_traps_count); 1301 1302 trap->traps_count = traps_count; 1303 1304 return 0; 1305 } 1306 1307 static void mlxsw_sp_trap_items_arr_fini(struct mlxsw_sp *mlxsw_sp) 1308 { 1309 kfree(mlxsw_sp->trap->trap_items_arr); 1310 } 1311 1312 static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp) 1313 { 1314 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1315 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1316 const struct mlxsw_sp_trap_item *trap_item; 1317 int err, i; 1318 1319 err = mlxsw_sp_trap_items_arr_init(mlxsw_sp); 1320 if (err) 1321 return err; 1322 1323 for (i = 0; i < trap->traps_count; i++) { 1324 trap_item = &trap->trap_items_arr[i]; 1325 err = devlink_traps_register(devlink, &trap_item->trap, 1, 1326 mlxsw_sp); 1327 if (err) 1328 goto err_trap_register; 1329 } 1330 1331 return 0; 1332 1333 err_trap_register: 1334 for (i--; i >= 0; i--) { 1335 trap_item = &trap->trap_items_arr[i]; 1336 devlink_traps_unregister(devlink, &trap_item->trap, 1); 1337 } 1338 mlxsw_sp_trap_items_arr_fini(mlxsw_sp); 1339 return err; 1340 } 1341 1342 static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) 1343 { 1344 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1345 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1346 int i; 1347 1348 for (i = trap->traps_count - 1; i >= 0; i--) { 1349 const struct mlxsw_sp_trap_item *trap_item; 1350 1351 trap_item = &trap->trap_items_arr[i]; 1352 devlink_traps_unregister(devlink, &trap_item->trap, 1); 1353 } 1354 mlxsw_sp_trap_items_arr_fini(mlxsw_sp); 1355 } 1356 1357 int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp) 1358 { 1359 int err; 1360 1361 err = mlxsw_sp_trap_cpu_policers_set(mlxsw_sp); 1362 if (err) 1363 return err; 1364 1365 err = mlxsw_sp_trap_dummy_group_init(mlxsw_sp); 1366 if (err) 1367 return err; 1368 1369 err = mlxsw_sp_trap_policers_init(mlxsw_sp); 1370 if (err) 1371 return err; 1372 1373 err = mlxsw_sp_trap_groups_init(mlxsw_sp); 1374 if (err) 1375 goto err_trap_groups_init; 1376 1377 err = mlxsw_sp_traps_init(mlxsw_sp); 1378 if (err) 1379 goto err_traps_init; 1380 1381 return 0; 1382 1383 err_traps_init: 1384 mlxsw_sp_trap_groups_fini(mlxsw_sp); 1385 err_trap_groups_init: 1386 mlxsw_sp_trap_policers_fini(mlxsw_sp); 1387 return err; 1388 } 1389 1390 void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp) 1391 { 1392 mlxsw_sp_traps_fini(mlxsw_sp); 1393 mlxsw_sp_trap_groups_fini(mlxsw_sp); 1394 mlxsw_sp_trap_policers_fini(mlxsw_sp); 1395 } 1396 1397 int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core, 1398 const struct devlink_trap *trap, void *trap_ctx) 1399 { 1400 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1401 const struct mlxsw_sp_trap_item *trap_item; 1402 int i; 1403 1404 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); 1405 if (WARN_ON(!trap_item)) 1406 return -EINVAL; 1407 1408 for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) { 1409 const struct mlxsw_listener *listener; 1410 int err; 1411 1412 listener = &trap_item->listeners_arr[i]; 1413 if (!mlxsw_sp_trap_listener_is_valid(listener)) 1414 continue; 1415 err = mlxsw_core_trap_register(mlxsw_core, listener, trap_ctx); 1416 if (err) 1417 return err; 1418 } 1419 1420 return 0; 1421 } 1422 1423 void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core, 1424 const struct devlink_trap *trap, void *trap_ctx) 1425 { 1426 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1427 const struct mlxsw_sp_trap_item *trap_item; 1428 int i; 1429 1430 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); 1431 if (WARN_ON(!trap_item)) 1432 return; 1433 1434 for (i = MLXSW_SP_TRAP_LISTENERS_MAX - 1; i >= 0; i--) { 1435 const struct mlxsw_listener *listener; 1436 1437 listener = &trap_item->listeners_arr[i]; 1438 if (!mlxsw_sp_trap_listener_is_valid(listener)) 1439 continue; 1440 mlxsw_core_trap_unregister(mlxsw_core, listener, trap_ctx); 1441 } 1442 } 1443 1444 int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core, 1445 const struct devlink_trap *trap, 1446 enum devlink_trap_action action, 1447 struct netlink_ext_ack *extack) 1448 { 1449 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1450 const struct mlxsw_sp_trap_item *trap_item; 1451 int i; 1452 1453 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); 1454 if (WARN_ON(!trap_item)) 1455 return -EINVAL; 1456 1457 if (trap_item->is_source) { 1458 NL_SET_ERR_MSG_MOD(extack, "Changing the action of source traps is not supported"); 1459 return -EOPNOTSUPP; 1460 } 1461 1462 for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) { 1463 const struct mlxsw_listener *listener; 1464 bool enabled; 1465 int err; 1466 1467 listener = &trap_item->listeners_arr[i]; 1468 if (!mlxsw_sp_trap_listener_is_valid(listener)) 1469 continue; 1470 1471 switch (action) { 1472 case DEVLINK_TRAP_ACTION_DROP: 1473 enabled = false; 1474 break; 1475 case DEVLINK_TRAP_ACTION_TRAP: 1476 enabled = true; 1477 break; 1478 default: 1479 return -EINVAL; 1480 } 1481 err = mlxsw_core_trap_state_set(mlxsw_core, listener, enabled); 1482 if (err) 1483 return err; 1484 } 1485 1486 return 0; 1487 } 1488 1489 static int 1490 __mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, 1491 const struct devlink_trap_group *group, 1492 u32 policer_id, struct netlink_ext_ack *extack) 1493 { 1494 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1495 u16 hw_policer_id = MLXSW_REG_HTGT_INVALID_POLICER; 1496 const struct mlxsw_sp_trap_group_item *group_item; 1497 char htgt_pl[MLXSW_REG_HTGT_LEN]; 1498 1499 group_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, group->id); 1500 if (WARN_ON(!group_item)) 1501 return -EINVAL; 1502 1503 if (group_item->fixed_policer && policer_id != group->init_policer_id) { 1504 NL_SET_ERR_MSG_MOD(extack, "Changing the policer binding of this group is not supported"); 1505 return -EOPNOTSUPP; 1506 } 1507 1508 if (policer_id) { 1509 struct mlxsw_sp_trap_policer_item *policer_item; 1510 1511 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, 1512 policer_id); 1513 if (WARN_ON(!policer_item)) 1514 return -EINVAL; 1515 hw_policer_id = policer_item->hw_id; 1516 } 1517 1518 mlxsw_reg_htgt_pack(htgt_pl, group_item->hw_group_id, hw_policer_id, 1519 group_item->priority, group_item->priority); 1520 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); 1521 } 1522 1523 int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, 1524 const struct devlink_trap_group *group) 1525 { 1526 return __mlxsw_sp_trap_group_init(mlxsw_core, group, 1527 group->init_policer_id, NULL); 1528 } 1529 1530 int mlxsw_sp_trap_group_set(struct mlxsw_core *mlxsw_core, 1531 const struct devlink_trap_group *group, 1532 const struct devlink_trap_policer *policer, 1533 struct netlink_ext_ack *extack) 1534 { 1535 u32 policer_id = policer ? policer->id : 0; 1536 1537 return __mlxsw_sp_trap_group_init(mlxsw_core, group, policer_id, 1538 extack); 1539 } 1540 1541 static int 1542 mlxsw_sp_trap_policer_item_init(struct mlxsw_sp *mlxsw_sp, 1543 struct mlxsw_sp_trap_policer_item *policer_item) 1544 { 1545 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1546 u16 hw_id; 1547 1548 /* We should be able to allocate a policer because the number of 1549 * policers we registered with devlink is in according with the number 1550 * of available policers. 1551 */ 1552 hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers); 1553 if (WARN_ON(hw_id == trap->max_policers)) 1554 return -ENOBUFS; 1555 1556 __set_bit(hw_id, trap->policers_usage); 1557 policer_item->hw_id = hw_id; 1558 1559 return 0; 1560 } 1561 1562 static void 1563 mlxsw_sp_trap_policer_item_fini(struct mlxsw_sp *mlxsw_sp, 1564 struct mlxsw_sp_trap_policer_item *policer_item) 1565 { 1566 __clear_bit(policer_item->hw_id, mlxsw_sp->trap->policers_usage); 1567 } 1568 1569 static int mlxsw_sp_trap_policer_bs(u64 burst, u8 *p_burst_size, 1570 struct netlink_ext_ack *extack) 1571 { 1572 int bs = fls64(burst) - 1; 1573 1574 if (burst != (BIT_ULL(bs))) { 1575 NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two"); 1576 return -EINVAL; 1577 } 1578 1579 *p_burst_size = bs; 1580 1581 return 0; 1582 } 1583 1584 static int __mlxsw_sp_trap_policer_set(struct mlxsw_sp *mlxsw_sp, u16 hw_id, 1585 u64 rate, u64 burst, bool clear_counter, 1586 struct netlink_ext_ack *extack) 1587 { 1588 char qpcr_pl[MLXSW_REG_QPCR_LEN]; 1589 u8 burst_size; 1590 int err; 1591 1592 err = mlxsw_sp_trap_policer_bs(burst, &burst_size, extack); 1593 if (err) 1594 return err; 1595 1596 mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M, false, 1597 rate, burst_size); 1598 mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, clear_counter); 1599 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 1600 } 1601 1602 int mlxsw_sp_trap_policer_init(struct mlxsw_core *mlxsw_core, 1603 const struct devlink_trap_policer *policer) 1604 { 1605 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1606 struct mlxsw_sp_trap_policer_item *policer_item; 1607 int err; 1608 1609 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1610 if (WARN_ON(!policer_item)) 1611 return -EINVAL; 1612 1613 err = mlxsw_sp_trap_policer_item_init(mlxsw_sp, policer_item); 1614 if (err) 1615 return err; 1616 1617 err = __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id, 1618 policer->init_rate, 1619 policer->init_burst, true, NULL); 1620 if (err) 1621 goto err_trap_policer_set; 1622 1623 return 0; 1624 1625 err_trap_policer_set: 1626 mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item); 1627 return err; 1628 } 1629 1630 void mlxsw_sp_trap_policer_fini(struct mlxsw_core *mlxsw_core, 1631 const struct devlink_trap_policer *policer) 1632 { 1633 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1634 struct mlxsw_sp_trap_policer_item *policer_item; 1635 1636 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1637 if (WARN_ON(!policer_item)) 1638 return; 1639 1640 mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item); 1641 } 1642 1643 int mlxsw_sp_trap_policer_set(struct mlxsw_core *mlxsw_core, 1644 const struct devlink_trap_policer *policer, 1645 u64 rate, u64 burst, 1646 struct netlink_ext_ack *extack) 1647 { 1648 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1649 struct mlxsw_sp_trap_policer_item *policer_item; 1650 1651 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1652 if (WARN_ON(!policer_item)) 1653 return -EINVAL; 1654 1655 return __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id, 1656 rate, burst, false, extack); 1657 } 1658 1659 int 1660 mlxsw_sp_trap_policer_counter_get(struct mlxsw_core *mlxsw_core, 1661 const struct devlink_trap_policer *policer, 1662 u64 *p_drops) 1663 { 1664 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1665 struct mlxsw_sp_trap_policer_item *policer_item; 1666 char qpcr_pl[MLXSW_REG_QPCR_LEN]; 1667 int err; 1668 1669 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1670 if (WARN_ON(!policer_item)) 1671 return -EINVAL; 1672 1673 mlxsw_reg_qpcr_pack(qpcr_pl, policer_item->hw_id, 1674 MLXSW_REG_QPCR_IR_UNITS_M, false, 0, 0); 1675 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 1676 if (err) 1677 return err; 1678 1679 *p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl); 1680 1681 return 0; 1682 } 1683 1684 int mlxsw_sp_trap_group_policer_hw_id_get(struct mlxsw_sp *mlxsw_sp, u16 id, 1685 bool *p_enabled, u16 *p_hw_id) 1686 { 1687 struct mlxsw_sp_trap_policer_item *pol_item; 1688 struct mlxsw_sp_trap_group_item *gr_item; 1689 u32 pol_id; 1690 1691 gr_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, id); 1692 if (!gr_item) 1693 return -ENOENT; 1694 1695 pol_id = gr_item->group.init_policer_id; 1696 if (!pol_id) { 1697 *p_enabled = false; 1698 return 0; 1699 } 1700 1701 pol_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, pol_id); 1702 if (WARN_ON(!pol_item)) 1703 return -ENOENT; 1704 1705 *p_enabled = true; 1706 *p_hw_id = pol_item->hw_id; 1707 return 0; 1708 } 1709 1710 static const struct mlxsw_sp_trap_group_item 1711 mlxsw_sp1_trap_group_items_arr[] = { 1712 }; 1713 1714 static const struct mlxsw_sp_trap_item 1715 mlxsw_sp1_trap_items_arr[] = { 1716 }; 1717 1718 static int 1719 mlxsw_sp1_trap_groups_init(struct mlxsw_sp *mlxsw_sp, 1720 const struct mlxsw_sp_trap_group_item **arr, 1721 size_t *p_groups_count) 1722 { 1723 *arr = mlxsw_sp1_trap_group_items_arr; 1724 *p_groups_count = ARRAY_SIZE(mlxsw_sp1_trap_group_items_arr); 1725 1726 return 0; 1727 } 1728 1729 static int mlxsw_sp1_traps_init(struct mlxsw_sp *mlxsw_sp, 1730 const struct mlxsw_sp_trap_item **arr, 1731 size_t *p_traps_count) 1732 { 1733 *arr = mlxsw_sp1_trap_items_arr; 1734 *p_traps_count = ARRAY_SIZE(mlxsw_sp1_trap_items_arr); 1735 1736 return 0; 1737 } 1738 1739 const struct mlxsw_sp_trap_ops mlxsw_sp1_trap_ops = { 1740 .groups_init = mlxsw_sp1_trap_groups_init, 1741 .traps_init = mlxsw_sp1_traps_init, 1742 }; 1743 1744 static const struct mlxsw_sp_trap_group_item 1745 mlxsw_sp2_trap_group_items_arr[] = { 1746 { 1747 .group = DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 20), 1748 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BUFFER_DISCARDS, 1749 .priority = 0, 1750 .fixed_policer = true, 1751 }, 1752 }; 1753 1754 static const struct mlxsw_sp_trap_item 1755 mlxsw_sp2_trap_items_arr[] = { 1756 { 1757 .trap = MLXSW_SP_TRAP_BUFFER_DROP(EARLY_DROP), 1758 .listeners_arr = { 1759 MLXSW_SP_RXL_BUFFER_DISCARD(INGRESS_WRED), 1760 }, 1761 .is_source = true, 1762 }, 1763 }; 1764 1765 static int 1766 mlxsw_sp2_trap_groups_init(struct mlxsw_sp *mlxsw_sp, 1767 const struct mlxsw_sp_trap_group_item **arr, 1768 size_t *p_groups_count) 1769 { 1770 *arr = mlxsw_sp2_trap_group_items_arr; 1771 *p_groups_count = ARRAY_SIZE(mlxsw_sp2_trap_group_items_arr); 1772 1773 return 0; 1774 } 1775 1776 static int mlxsw_sp2_traps_init(struct mlxsw_sp *mlxsw_sp, 1777 const struct mlxsw_sp_trap_item **arr, 1778 size_t *p_traps_count) 1779 { 1780 *arr = mlxsw_sp2_trap_items_arr; 1781 *p_traps_count = ARRAY_SIZE(mlxsw_sp2_trap_items_arr); 1782 1783 return 0; 1784 } 1785 1786 const struct mlxsw_sp_trap_ops mlxsw_sp2_trap_ops = { 1787 .groups_init = mlxsw_sp2_trap_groups_init, 1788 .traps_init = mlxsw_sp2_traps_init, 1789 }; 1790