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