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(DISCARD_ROUTER3, 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 1012 static struct mlxsw_sp_trap_policer_item * 1013 mlxsw_sp_trap_policer_item_lookup(struct mlxsw_sp *mlxsw_sp, u32 id) 1014 { 1015 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1016 int i; 1017 1018 for (i = 0; i < trap->policers_count; i++) { 1019 if (trap->policer_items_arr[i].policer.id == id) 1020 return &trap->policer_items_arr[i]; 1021 } 1022 1023 return NULL; 1024 } 1025 1026 static struct mlxsw_sp_trap_group_item * 1027 mlxsw_sp_trap_group_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id) 1028 { 1029 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1030 int i; 1031 1032 for (i = 0; i < trap->groups_count; i++) { 1033 if (trap->group_items_arr[i].group.id == id) 1034 return &trap->group_items_arr[i]; 1035 } 1036 1037 return NULL; 1038 } 1039 1040 static struct mlxsw_sp_trap_item * 1041 mlxsw_sp_trap_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id) 1042 { 1043 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1044 int i; 1045 1046 for (i = 0; i < trap->traps_count; i++) { 1047 if (trap->trap_items_arr[i].trap.id == id) 1048 return &trap->trap_items_arr[i]; 1049 } 1050 1051 return NULL; 1052 } 1053 1054 static int mlxsw_sp_trap_cpu_policers_set(struct mlxsw_sp *mlxsw_sp) 1055 { 1056 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1057 char qpcr_pl[MLXSW_REG_QPCR_LEN]; 1058 u16 hw_id; 1059 1060 /* The purpose of "thin" policer is to drop as many packets 1061 * as possible. The dummy group is using it. 1062 */ 1063 hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers); 1064 if (WARN_ON(hw_id == trap->max_policers)) 1065 return -ENOBUFS; 1066 1067 __set_bit(hw_id, trap->policers_usage); 1068 trap->thin_policer_hw_id = hw_id; 1069 mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M, 1070 false, 1, 4); 1071 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 1072 } 1073 1074 static int mlxsw_sp_trap_dummy_group_init(struct mlxsw_sp *mlxsw_sp) 1075 { 1076 char htgt_pl[MLXSW_REG_HTGT_LEN]; 1077 1078 mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SP_DUMMY, 1079 mlxsw_sp->trap->thin_policer_hw_id, 0, 1); 1080 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl); 1081 } 1082 1083 static int mlxsw_sp_trap_policer_items_arr_init(struct mlxsw_sp *mlxsw_sp) 1084 { 1085 size_t arr_size = ARRAY_SIZE(mlxsw_sp_trap_policer_items_arr); 1086 size_t elem_size = sizeof(struct mlxsw_sp_trap_policer_item); 1087 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1088 size_t free_policers = 0; 1089 u32 last_id; 1090 int i; 1091 1092 for_each_clear_bit(i, trap->policers_usage, trap->max_policers) 1093 free_policers++; 1094 1095 if (arr_size > free_policers) { 1096 dev_err(mlxsw_sp->bus_info->dev, "Exceeded number of supported packet trap policers\n"); 1097 return -ENOBUFS; 1098 } 1099 1100 trap->policer_items_arr = kcalloc(free_policers, elem_size, GFP_KERNEL); 1101 if (!trap->policer_items_arr) 1102 return -ENOMEM; 1103 1104 trap->policers_count = free_policers; 1105 1106 /* Initialize policer items array with pre-defined policers. */ 1107 memcpy(trap->policer_items_arr, mlxsw_sp_trap_policer_items_arr, 1108 elem_size * arr_size); 1109 1110 /* Initialize policer items array with the rest of the available 1111 * policers. 1112 */ 1113 last_id = mlxsw_sp_trap_policer_items_arr[arr_size - 1].policer.id; 1114 for (i = arr_size; i < trap->policers_count; i++) { 1115 const struct mlxsw_sp_trap_policer_item *policer_item; 1116 1117 /* Use parameters set for first policer and override 1118 * relevant ones. 1119 */ 1120 policer_item = &mlxsw_sp_trap_policer_items_arr[0]; 1121 trap->policer_items_arr[i] = *policer_item; 1122 trap->policer_items_arr[i].policer.id = ++last_id; 1123 trap->policer_items_arr[i].policer.init_rate = 1; 1124 trap->policer_items_arr[i].policer.init_burst = 16; 1125 } 1126 1127 return 0; 1128 } 1129 1130 static void mlxsw_sp_trap_policer_items_arr_fini(struct mlxsw_sp *mlxsw_sp) 1131 { 1132 kfree(mlxsw_sp->trap->policer_items_arr); 1133 } 1134 1135 static int mlxsw_sp_trap_policers_init(struct mlxsw_sp *mlxsw_sp) 1136 { 1137 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1138 const struct mlxsw_sp_trap_policer_item *policer_item; 1139 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1140 int err, i; 1141 1142 err = mlxsw_sp_trap_policer_items_arr_init(mlxsw_sp); 1143 if (err) 1144 return err; 1145 1146 for (i = 0; i < trap->policers_count; i++) { 1147 policer_item = &trap->policer_items_arr[i]; 1148 err = devlink_trap_policers_register(devlink, 1149 &policer_item->policer, 1); 1150 if (err) 1151 goto err_trap_policer_register; 1152 } 1153 1154 return 0; 1155 1156 err_trap_policer_register: 1157 for (i--; i >= 0; i--) { 1158 policer_item = &trap->policer_items_arr[i]; 1159 devlink_trap_policers_unregister(devlink, 1160 &policer_item->policer, 1); 1161 } 1162 mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp); 1163 return err; 1164 } 1165 1166 static void mlxsw_sp_trap_policers_fini(struct mlxsw_sp *mlxsw_sp) 1167 { 1168 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1169 const struct mlxsw_sp_trap_policer_item *policer_item; 1170 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1171 int i; 1172 1173 for (i = trap->policers_count - 1; i >= 0; i--) { 1174 policer_item = &trap->policer_items_arr[i]; 1175 devlink_trap_policers_unregister(devlink, 1176 &policer_item->policer, 1); 1177 } 1178 mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp); 1179 } 1180 1181 static int mlxsw_sp_trap_group_items_arr_init(struct mlxsw_sp *mlxsw_sp) 1182 { 1183 size_t common_groups_count = ARRAY_SIZE(mlxsw_sp_trap_group_items_arr); 1184 const struct mlxsw_sp_trap_group_item *spec_group_items_arr; 1185 size_t elem_size = sizeof(struct mlxsw_sp_trap_group_item); 1186 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1187 size_t groups_count, spec_groups_count; 1188 int err; 1189 1190 err = mlxsw_sp->trap_ops->groups_init(mlxsw_sp, &spec_group_items_arr, 1191 &spec_groups_count); 1192 if (err) 1193 return err; 1194 1195 /* The group items array is created by concatenating the common trap 1196 * group items and the ASIC-specific trap group items. 1197 */ 1198 groups_count = common_groups_count + spec_groups_count; 1199 trap->group_items_arr = kcalloc(groups_count, elem_size, GFP_KERNEL); 1200 if (!trap->group_items_arr) 1201 return -ENOMEM; 1202 1203 memcpy(trap->group_items_arr, mlxsw_sp_trap_group_items_arr, 1204 elem_size * common_groups_count); 1205 memcpy(trap->group_items_arr + common_groups_count, 1206 spec_group_items_arr, elem_size * spec_groups_count); 1207 1208 trap->groups_count = groups_count; 1209 1210 return 0; 1211 } 1212 1213 static void mlxsw_sp_trap_group_items_arr_fini(struct mlxsw_sp *mlxsw_sp) 1214 { 1215 kfree(mlxsw_sp->trap->group_items_arr); 1216 } 1217 1218 static int mlxsw_sp_trap_groups_init(struct mlxsw_sp *mlxsw_sp) 1219 { 1220 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1221 const struct mlxsw_sp_trap_group_item *group_item; 1222 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1223 int err, i; 1224 1225 err = mlxsw_sp_trap_group_items_arr_init(mlxsw_sp); 1226 if (err) 1227 return err; 1228 1229 for (i = 0; i < trap->groups_count; i++) { 1230 group_item = &trap->group_items_arr[i]; 1231 err = devlink_trap_groups_register(devlink, &group_item->group, 1232 1); 1233 if (err) 1234 goto err_trap_group_register; 1235 } 1236 1237 return 0; 1238 1239 err_trap_group_register: 1240 for (i--; i >= 0; i--) { 1241 group_item = &trap->group_items_arr[i]; 1242 devlink_trap_groups_unregister(devlink, &group_item->group, 1); 1243 } 1244 mlxsw_sp_trap_group_items_arr_fini(mlxsw_sp); 1245 return err; 1246 } 1247 1248 static void mlxsw_sp_trap_groups_fini(struct mlxsw_sp *mlxsw_sp) 1249 { 1250 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1251 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1252 int i; 1253 1254 for (i = trap->groups_count - 1; i >= 0; i--) { 1255 const struct mlxsw_sp_trap_group_item *group_item; 1256 1257 group_item = &trap->group_items_arr[i]; 1258 devlink_trap_groups_unregister(devlink, &group_item->group, 1); 1259 } 1260 mlxsw_sp_trap_group_items_arr_fini(mlxsw_sp); 1261 } 1262 1263 static bool 1264 mlxsw_sp_trap_listener_is_valid(const struct mlxsw_listener *listener) 1265 { 1266 return listener->trap_id != 0; 1267 } 1268 1269 static int mlxsw_sp_trap_items_arr_init(struct mlxsw_sp *mlxsw_sp) 1270 { 1271 size_t common_traps_count = ARRAY_SIZE(mlxsw_sp_trap_items_arr); 1272 const struct mlxsw_sp_trap_item *spec_trap_items_arr; 1273 size_t elem_size = sizeof(struct mlxsw_sp_trap_item); 1274 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1275 size_t traps_count, spec_traps_count; 1276 int err; 1277 1278 err = mlxsw_sp->trap_ops->traps_init(mlxsw_sp, &spec_trap_items_arr, 1279 &spec_traps_count); 1280 if (err) 1281 return err; 1282 1283 /* The trap items array is created by concatenating the common trap 1284 * items and the ASIC-specific trap items. 1285 */ 1286 traps_count = common_traps_count + spec_traps_count; 1287 trap->trap_items_arr = kcalloc(traps_count, elem_size, GFP_KERNEL); 1288 if (!trap->trap_items_arr) 1289 return -ENOMEM; 1290 1291 memcpy(trap->trap_items_arr, mlxsw_sp_trap_items_arr, 1292 elem_size * common_traps_count); 1293 memcpy(trap->trap_items_arr + common_traps_count, 1294 spec_trap_items_arr, elem_size * spec_traps_count); 1295 1296 trap->traps_count = traps_count; 1297 1298 return 0; 1299 } 1300 1301 static void mlxsw_sp_trap_items_arr_fini(struct mlxsw_sp *mlxsw_sp) 1302 { 1303 kfree(mlxsw_sp->trap->trap_items_arr); 1304 } 1305 1306 static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp) 1307 { 1308 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1309 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1310 const struct mlxsw_sp_trap_item *trap_item; 1311 int err, i; 1312 1313 err = mlxsw_sp_trap_items_arr_init(mlxsw_sp); 1314 if (err) 1315 return err; 1316 1317 for (i = 0; i < trap->traps_count; i++) { 1318 trap_item = &trap->trap_items_arr[i]; 1319 err = devlink_traps_register(devlink, &trap_item->trap, 1, 1320 mlxsw_sp); 1321 if (err) 1322 goto err_trap_register; 1323 } 1324 1325 return 0; 1326 1327 err_trap_register: 1328 for (i--; i >= 0; i--) { 1329 trap_item = &trap->trap_items_arr[i]; 1330 devlink_traps_unregister(devlink, &trap_item->trap, 1); 1331 } 1332 mlxsw_sp_trap_items_arr_fini(mlxsw_sp); 1333 return err; 1334 } 1335 1336 static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) 1337 { 1338 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1339 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1340 int i; 1341 1342 for (i = trap->traps_count - 1; i >= 0; i--) { 1343 const struct mlxsw_sp_trap_item *trap_item; 1344 1345 trap_item = &trap->trap_items_arr[i]; 1346 devlink_traps_unregister(devlink, &trap_item->trap, 1); 1347 } 1348 mlxsw_sp_trap_items_arr_fini(mlxsw_sp); 1349 } 1350 1351 int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp) 1352 { 1353 int err; 1354 1355 err = mlxsw_sp_trap_cpu_policers_set(mlxsw_sp); 1356 if (err) 1357 return err; 1358 1359 err = mlxsw_sp_trap_dummy_group_init(mlxsw_sp); 1360 if (err) 1361 return err; 1362 1363 err = mlxsw_sp_trap_policers_init(mlxsw_sp); 1364 if (err) 1365 return err; 1366 1367 err = mlxsw_sp_trap_groups_init(mlxsw_sp); 1368 if (err) 1369 goto err_trap_groups_init; 1370 1371 err = mlxsw_sp_traps_init(mlxsw_sp); 1372 if (err) 1373 goto err_traps_init; 1374 1375 return 0; 1376 1377 err_traps_init: 1378 mlxsw_sp_trap_groups_fini(mlxsw_sp); 1379 err_trap_groups_init: 1380 mlxsw_sp_trap_policers_fini(mlxsw_sp); 1381 return err; 1382 } 1383 1384 void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp) 1385 { 1386 mlxsw_sp_traps_fini(mlxsw_sp); 1387 mlxsw_sp_trap_groups_fini(mlxsw_sp); 1388 mlxsw_sp_trap_policers_fini(mlxsw_sp); 1389 } 1390 1391 int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core, 1392 const struct devlink_trap *trap, void *trap_ctx) 1393 { 1394 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1395 const struct mlxsw_sp_trap_item *trap_item; 1396 int i; 1397 1398 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); 1399 if (WARN_ON(!trap_item)) 1400 return -EINVAL; 1401 1402 for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) { 1403 const struct mlxsw_listener *listener; 1404 int err; 1405 1406 listener = &trap_item->listeners_arr[i]; 1407 if (!mlxsw_sp_trap_listener_is_valid(listener)) 1408 continue; 1409 err = mlxsw_core_trap_register(mlxsw_core, listener, trap_ctx); 1410 if (err) 1411 return err; 1412 } 1413 1414 return 0; 1415 } 1416 1417 void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core, 1418 const struct devlink_trap *trap, void *trap_ctx) 1419 { 1420 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1421 const struct mlxsw_sp_trap_item *trap_item; 1422 int i; 1423 1424 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); 1425 if (WARN_ON(!trap_item)) 1426 return; 1427 1428 for (i = MLXSW_SP_TRAP_LISTENERS_MAX - 1; i >= 0; i--) { 1429 const struct mlxsw_listener *listener; 1430 1431 listener = &trap_item->listeners_arr[i]; 1432 if (!mlxsw_sp_trap_listener_is_valid(listener)) 1433 continue; 1434 mlxsw_core_trap_unregister(mlxsw_core, listener, trap_ctx); 1435 } 1436 } 1437 1438 int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core, 1439 const struct devlink_trap *trap, 1440 enum devlink_trap_action action, 1441 struct netlink_ext_ack *extack) 1442 { 1443 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1444 const struct mlxsw_sp_trap_item *trap_item; 1445 int i; 1446 1447 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); 1448 if (WARN_ON(!trap_item)) 1449 return -EINVAL; 1450 1451 if (trap_item->is_source) { 1452 NL_SET_ERR_MSG_MOD(extack, "Changing the action of source traps is not supported"); 1453 return -EOPNOTSUPP; 1454 } 1455 1456 for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) { 1457 const struct mlxsw_listener *listener; 1458 bool enabled; 1459 int err; 1460 1461 listener = &trap_item->listeners_arr[i]; 1462 if (!mlxsw_sp_trap_listener_is_valid(listener)) 1463 continue; 1464 1465 switch (action) { 1466 case DEVLINK_TRAP_ACTION_DROP: 1467 enabled = false; 1468 break; 1469 case DEVLINK_TRAP_ACTION_TRAP: 1470 enabled = true; 1471 break; 1472 default: 1473 return -EINVAL; 1474 } 1475 err = mlxsw_core_trap_state_set(mlxsw_core, listener, enabled); 1476 if (err) 1477 return err; 1478 } 1479 1480 return 0; 1481 } 1482 1483 static int 1484 __mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, 1485 const struct devlink_trap_group *group, 1486 u32 policer_id, struct netlink_ext_ack *extack) 1487 { 1488 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1489 u16 hw_policer_id = MLXSW_REG_HTGT_INVALID_POLICER; 1490 const struct mlxsw_sp_trap_group_item *group_item; 1491 char htgt_pl[MLXSW_REG_HTGT_LEN]; 1492 1493 group_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, group->id); 1494 if (WARN_ON(!group_item)) 1495 return -EINVAL; 1496 1497 if (group_item->fixed_policer && policer_id != group->init_policer_id) { 1498 NL_SET_ERR_MSG_MOD(extack, "Changing the policer binding of this group is not supported"); 1499 return -EOPNOTSUPP; 1500 } 1501 1502 if (policer_id) { 1503 struct mlxsw_sp_trap_policer_item *policer_item; 1504 1505 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, 1506 policer_id); 1507 if (WARN_ON(!policer_item)) 1508 return -EINVAL; 1509 hw_policer_id = policer_item->hw_id; 1510 } 1511 1512 mlxsw_reg_htgt_pack(htgt_pl, group_item->hw_group_id, hw_policer_id, 1513 group_item->priority, group_item->priority); 1514 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); 1515 } 1516 1517 int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, 1518 const struct devlink_trap_group *group) 1519 { 1520 return __mlxsw_sp_trap_group_init(mlxsw_core, group, 1521 group->init_policer_id, NULL); 1522 } 1523 1524 int mlxsw_sp_trap_group_set(struct mlxsw_core *mlxsw_core, 1525 const struct devlink_trap_group *group, 1526 const struct devlink_trap_policer *policer, 1527 struct netlink_ext_ack *extack) 1528 { 1529 u32 policer_id = policer ? policer->id : 0; 1530 1531 return __mlxsw_sp_trap_group_init(mlxsw_core, group, policer_id, 1532 extack); 1533 } 1534 1535 static int 1536 mlxsw_sp_trap_policer_item_init(struct mlxsw_sp *mlxsw_sp, 1537 struct mlxsw_sp_trap_policer_item *policer_item) 1538 { 1539 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1540 u16 hw_id; 1541 1542 /* We should be able to allocate a policer because the number of 1543 * policers we registered with devlink is in according with the number 1544 * of available policers. 1545 */ 1546 hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers); 1547 if (WARN_ON(hw_id == trap->max_policers)) 1548 return -ENOBUFS; 1549 1550 __set_bit(hw_id, trap->policers_usage); 1551 policer_item->hw_id = hw_id; 1552 1553 return 0; 1554 } 1555 1556 static void 1557 mlxsw_sp_trap_policer_item_fini(struct mlxsw_sp *mlxsw_sp, 1558 struct mlxsw_sp_trap_policer_item *policer_item) 1559 { 1560 __clear_bit(policer_item->hw_id, mlxsw_sp->trap->policers_usage); 1561 } 1562 1563 static int mlxsw_sp_trap_policer_bs(u64 burst, u8 *p_burst_size, 1564 struct netlink_ext_ack *extack) 1565 { 1566 int bs = fls64(burst) - 1; 1567 1568 if (burst != (BIT_ULL(bs))) { 1569 NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two"); 1570 return -EINVAL; 1571 } 1572 1573 *p_burst_size = bs; 1574 1575 return 0; 1576 } 1577 1578 static int __mlxsw_sp_trap_policer_set(struct mlxsw_sp *mlxsw_sp, u16 hw_id, 1579 u64 rate, u64 burst, bool clear_counter, 1580 struct netlink_ext_ack *extack) 1581 { 1582 char qpcr_pl[MLXSW_REG_QPCR_LEN]; 1583 u8 burst_size; 1584 int err; 1585 1586 err = mlxsw_sp_trap_policer_bs(burst, &burst_size, extack); 1587 if (err) 1588 return err; 1589 1590 mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M, false, 1591 rate, burst_size); 1592 mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, clear_counter); 1593 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 1594 } 1595 1596 int mlxsw_sp_trap_policer_init(struct mlxsw_core *mlxsw_core, 1597 const struct devlink_trap_policer *policer) 1598 { 1599 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1600 struct mlxsw_sp_trap_policer_item *policer_item; 1601 int err; 1602 1603 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1604 if (WARN_ON(!policer_item)) 1605 return -EINVAL; 1606 1607 err = mlxsw_sp_trap_policer_item_init(mlxsw_sp, policer_item); 1608 if (err) 1609 return err; 1610 1611 err = __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id, 1612 policer->init_rate, 1613 policer->init_burst, true, NULL); 1614 if (err) 1615 goto err_trap_policer_set; 1616 1617 return 0; 1618 1619 err_trap_policer_set: 1620 mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item); 1621 return err; 1622 } 1623 1624 void mlxsw_sp_trap_policer_fini(struct mlxsw_core *mlxsw_core, 1625 const struct devlink_trap_policer *policer) 1626 { 1627 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1628 struct mlxsw_sp_trap_policer_item *policer_item; 1629 1630 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1631 if (WARN_ON(!policer_item)) 1632 return; 1633 1634 mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item); 1635 } 1636 1637 int mlxsw_sp_trap_policer_set(struct mlxsw_core *mlxsw_core, 1638 const struct devlink_trap_policer *policer, 1639 u64 rate, u64 burst, 1640 struct netlink_ext_ack *extack) 1641 { 1642 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1643 struct mlxsw_sp_trap_policer_item *policer_item; 1644 1645 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1646 if (WARN_ON(!policer_item)) 1647 return -EINVAL; 1648 1649 return __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id, 1650 rate, burst, false, extack); 1651 } 1652 1653 int 1654 mlxsw_sp_trap_policer_counter_get(struct mlxsw_core *mlxsw_core, 1655 const struct devlink_trap_policer *policer, 1656 u64 *p_drops) 1657 { 1658 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1659 struct mlxsw_sp_trap_policer_item *policer_item; 1660 char qpcr_pl[MLXSW_REG_QPCR_LEN]; 1661 int err; 1662 1663 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1664 if (WARN_ON(!policer_item)) 1665 return -EINVAL; 1666 1667 mlxsw_reg_qpcr_pack(qpcr_pl, policer_item->hw_id, 1668 MLXSW_REG_QPCR_IR_UNITS_M, false, 0, 0); 1669 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 1670 if (err) 1671 return err; 1672 1673 *p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl); 1674 1675 return 0; 1676 } 1677 1678 int mlxsw_sp_trap_group_policer_hw_id_get(struct mlxsw_sp *mlxsw_sp, u16 id, 1679 bool *p_enabled, u16 *p_hw_id) 1680 { 1681 struct mlxsw_sp_trap_policer_item *pol_item; 1682 struct mlxsw_sp_trap_group_item *gr_item; 1683 u32 pol_id; 1684 1685 gr_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, id); 1686 if (!gr_item) 1687 return -ENOENT; 1688 1689 pol_id = gr_item->group.init_policer_id; 1690 if (!pol_id) { 1691 *p_enabled = false; 1692 return 0; 1693 } 1694 1695 pol_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, pol_id); 1696 if (WARN_ON(!pol_item)) 1697 return -ENOENT; 1698 1699 *p_enabled = true; 1700 *p_hw_id = pol_item->hw_id; 1701 return 0; 1702 } 1703 1704 static const struct mlxsw_sp_trap_group_item 1705 mlxsw_sp1_trap_group_items_arr[] = { 1706 }; 1707 1708 static const struct mlxsw_sp_trap_item 1709 mlxsw_sp1_trap_items_arr[] = { 1710 }; 1711 1712 static int 1713 mlxsw_sp1_trap_groups_init(struct mlxsw_sp *mlxsw_sp, 1714 const struct mlxsw_sp_trap_group_item **arr, 1715 size_t *p_groups_count) 1716 { 1717 *arr = mlxsw_sp1_trap_group_items_arr; 1718 *p_groups_count = ARRAY_SIZE(mlxsw_sp1_trap_group_items_arr); 1719 1720 return 0; 1721 } 1722 1723 static int mlxsw_sp1_traps_init(struct mlxsw_sp *mlxsw_sp, 1724 const struct mlxsw_sp_trap_item **arr, 1725 size_t *p_traps_count) 1726 { 1727 *arr = mlxsw_sp1_trap_items_arr; 1728 *p_traps_count = ARRAY_SIZE(mlxsw_sp1_trap_items_arr); 1729 1730 return 0; 1731 } 1732 1733 const struct mlxsw_sp_trap_ops mlxsw_sp1_trap_ops = { 1734 .groups_init = mlxsw_sp1_trap_groups_init, 1735 .traps_init = mlxsw_sp1_traps_init, 1736 }; 1737 1738 static const struct mlxsw_sp_trap_group_item 1739 mlxsw_sp2_trap_group_items_arr[] = { 1740 { 1741 .group = DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 20), 1742 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BUFFER_DISCARDS, 1743 .priority = 0, 1744 .fixed_policer = true, 1745 }, 1746 }; 1747 1748 static const struct mlxsw_sp_trap_item 1749 mlxsw_sp2_trap_items_arr[] = { 1750 { 1751 .trap = MLXSW_SP_TRAP_BUFFER_DROP(EARLY_DROP), 1752 .listeners_arr = { 1753 MLXSW_SP_RXL_BUFFER_DISCARD(INGRESS_WRED), 1754 }, 1755 .is_source = true, 1756 }, 1757 }; 1758 1759 static int 1760 mlxsw_sp2_trap_groups_init(struct mlxsw_sp *mlxsw_sp, 1761 const struct mlxsw_sp_trap_group_item **arr, 1762 size_t *p_groups_count) 1763 { 1764 *arr = mlxsw_sp2_trap_group_items_arr; 1765 *p_groups_count = ARRAY_SIZE(mlxsw_sp2_trap_group_items_arr); 1766 1767 return 0; 1768 } 1769 1770 static int mlxsw_sp2_traps_init(struct mlxsw_sp *mlxsw_sp, 1771 const struct mlxsw_sp_trap_item **arr, 1772 size_t *p_traps_count) 1773 { 1774 *arr = mlxsw_sp2_trap_items_arr; 1775 *p_traps_count = ARRAY_SIZE(mlxsw_sp2_trap_items_arr); 1776 1777 return 0; 1778 } 1779 1780 const struct mlxsw_sp_trap_ops mlxsw_sp2_trap_ops = { 1781 .groups_init = mlxsw_sp2_trap_groups_init, 1782 .traps_init = mlxsw_sp2_traps_init, 1783 }; 1784