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 .policer = MLXSW_SP_TRAP_POLICER(19, 1024, 512), 333 }, 334 }; 335 336 static const struct mlxsw_sp_trap_group_item mlxsw_sp_trap_group_items_arr[] = { 337 { 338 .group = DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 1), 339 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS, 340 .priority = 0, 341 }, 342 { 343 .group = DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1), 344 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS, 345 .priority = 0, 346 }, 347 { 348 .group = DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 1), 349 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_EXCEPTIONS, 350 .priority = 2, 351 }, 352 { 353 .group = DEVLINK_TRAP_GROUP_GENERIC(TUNNEL_DROPS, 1), 354 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS, 355 .priority = 0, 356 }, 357 { 358 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 1), 359 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS, 360 .priority = 0, 361 }, 362 { 363 .group = DEVLINK_TRAP_GROUP_GENERIC(STP, 2), 364 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_STP, 365 .priority = 5, 366 }, 367 { 368 .group = DEVLINK_TRAP_GROUP_GENERIC(LACP, 3), 369 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LACP, 370 .priority = 5, 371 }, 372 { 373 .group = DEVLINK_TRAP_GROUP_GENERIC(LLDP, 4), 374 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP, 375 .priority = 5, 376 }, 377 { 378 .group = DEVLINK_TRAP_GROUP_GENERIC(MC_SNOOPING, 5), 379 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_MC_SNOOPING, 380 .priority = 3, 381 }, 382 { 383 .group = DEVLINK_TRAP_GROUP_GENERIC(DHCP, 6), 384 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_DHCP, 385 .priority = 2, 386 }, 387 { 388 .group = DEVLINK_TRAP_GROUP_GENERIC(NEIGH_DISCOVERY, 7), 389 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_NEIGH_DISCOVERY, 390 .priority = 2, 391 }, 392 { 393 .group = DEVLINK_TRAP_GROUP_GENERIC(BFD, 8), 394 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BFD, 395 .priority = 5, 396 }, 397 { 398 .group = DEVLINK_TRAP_GROUP_GENERIC(OSPF, 9), 399 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_OSPF, 400 .priority = 5, 401 }, 402 { 403 .group = DEVLINK_TRAP_GROUP_GENERIC(BGP, 10), 404 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BGP, 405 .priority = 4, 406 }, 407 { 408 .group = DEVLINK_TRAP_GROUP_GENERIC(VRRP, 11), 409 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_VRRP, 410 .priority = 5, 411 }, 412 { 413 .group = DEVLINK_TRAP_GROUP_GENERIC(PIM, 12), 414 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PIM, 415 .priority = 5, 416 }, 417 { 418 .group = DEVLINK_TRAP_GROUP_GENERIC(UC_LB, 13), 419 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LBERROR, 420 .priority = 0, 421 }, 422 { 423 .group = DEVLINK_TRAP_GROUP_GENERIC(LOCAL_DELIVERY, 14), 424 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME, 425 .priority = 2, 426 }, 427 { 428 .group = DEVLINK_TRAP_GROUP_GENERIC(EXTERNAL_DELIVERY, 19), 429 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_EXTERNAL_ROUTE, 430 .priority = 1, 431 }, 432 { 433 .group = DEVLINK_TRAP_GROUP_GENERIC(IPV6, 15), 434 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6, 435 .priority = 2, 436 }, 437 { 438 .group = DEVLINK_TRAP_GROUP_GENERIC(PTP_EVENT, 16), 439 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0, 440 .priority = 5, 441 }, 442 { 443 .group = DEVLINK_TRAP_GROUP_GENERIC(PTP_GENERAL, 17), 444 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1, 445 .priority = 2, 446 }, 447 { 448 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0), 449 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PKT_SAMPLE, 450 .priority = 0, 451 }, 452 { 453 .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_TRAP, 18), 454 .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_FLOW_LOGGING, 455 .priority = 4, 456 }, 457 }; 458 459 static const struct mlxsw_sp_trap_item mlxsw_sp_trap_items_arr[] = { 460 { 461 .trap = MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS), 462 .listeners_arr = { 463 MLXSW_SP_RXL_DISCARD(ING_PACKET_SMAC_MC, L2_DISCARDS), 464 }, 465 }, 466 { 467 .trap = MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS), 468 .listeners_arr = { 469 MLXSW_SP_RXL_DISCARD(ING_SWITCH_VTAG_ALLOW, 470 L2_DISCARDS), 471 }, 472 }, 473 { 474 .trap = MLXSW_SP_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS), 475 .listeners_arr = { 476 MLXSW_SP_RXL_DISCARD(ING_SWITCH_VLAN, L2_DISCARDS), 477 }, 478 }, 479 { 480 .trap = MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS), 481 .listeners_arr = { 482 MLXSW_SP_RXL_DISCARD(ING_SWITCH_STP, L2_DISCARDS), 483 }, 484 }, 485 { 486 .trap = MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS), 487 .listeners_arr = { 488 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS), 489 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS), 490 }, 491 }, 492 { 493 .trap = MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS), 494 .listeners_arr = { 495 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS), 496 }, 497 }, 498 { 499 .trap = MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS), 500 .listeners_arr = { 501 MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS), 502 }, 503 }, 504 { 505 .trap = MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS), 506 .listeners_arr = { 507 MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET, 508 L3_DISCARDS), 509 }, 510 }, 511 { 512 .trap = MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS), 513 .listeners_arr = { 514 MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC, 515 L3_DISCARDS), 516 }, 517 }, 518 { 519 .trap = MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS), 520 .listeners_arr = { 521 MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS), 522 }, 523 }, 524 { 525 .trap = MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS), 526 .listeners_arr = { 527 MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS), 528 }, 529 }, 530 { 531 .trap = MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS), 532 .listeners_arr = { 533 MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS), 534 }, 535 }, 536 { 537 .trap = MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS), 538 .listeners_arr = { 539 MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR, 540 L3_DISCARDS), 541 }, 542 }, 543 { 544 .trap = MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS), 545 .listeners_arr = { 546 MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC, 547 L3_DISCARDS), 548 }, 549 }, 550 { 551 .trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE, 552 L3_DROPS), 553 .listeners_arr = { 554 MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE, 555 L3_DISCARDS), 556 }, 557 }, 558 { 559 .trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, 560 L3_DROPS), 561 .listeners_arr = { 562 MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, 563 L3_DISCARDS), 564 }, 565 }, 566 { 567 .trap = MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_EXCEPTIONS), 568 .listeners_arr = { 569 MLXSW_SP_RXL_EXCEPTION(MTUERROR, L3_EXCEPTIONS, 570 TRAP_TO_CPU), 571 }, 572 }, 573 { 574 .trap = MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS), 575 .listeners_arr = { 576 MLXSW_SP_RXL_EXCEPTION(TTLERROR, L3_EXCEPTIONS, 577 TRAP_TO_CPU), 578 }, 579 }, 580 { 581 .trap = MLXSW_SP_TRAP_EXCEPTION(RPF, L3_EXCEPTIONS), 582 .listeners_arr = { 583 MLXSW_SP_RXL_EXCEPTION(RPF, L3_EXCEPTIONS, TRAP_TO_CPU), 584 }, 585 }, 586 { 587 .trap = MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_EXCEPTIONS), 588 .listeners_arr = { 589 MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, L3_EXCEPTIONS, 590 TRAP_TO_CPU), 591 }, 592 }, 593 { 594 .trap = MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH, 595 L3_EXCEPTIONS), 596 .listeners_arr = { 597 MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, L3_EXCEPTIONS, 598 TRAP_TO_CPU), 599 MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, L3_EXCEPTIONS, 600 TRAP_TO_CPU), 601 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER3, L3_EXCEPTIONS, 602 TRAP_EXCEPTION_TO_CPU), 603 }, 604 }, 605 { 606 .trap = MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS, 607 L3_EXCEPTIONS), 608 .listeners_arr = { 609 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4, 610 L3_EXCEPTIONS, 611 TRAP_EXCEPTION_TO_CPU), 612 }, 613 }, 614 { 615 .trap = MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS, 616 L3_EXCEPTIONS), 617 .listeners_arr = { 618 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6, 619 L3_EXCEPTIONS, 620 TRAP_EXCEPTION_TO_CPU), 621 }, 622 }, 623 { 624 .trap = MLXSW_SP_TRAP_DRIVER_DROP(IRIF_DISABLED, L3_DROPS), 625 .listeners_arr = { 626 MLXSW_SP_RXL_DISCARD(ROUTER_IRIF_EN, L3_DISCARDS), 627 }, 628 }, 629 { 630 .trap = MLXSW_SP_TRAP_DRIVER_DROP(ERIF_DISABLED, L3_DROPS), 631 .listeners_arr = { 632 MLXSW_SP_RXL_DISCARD(ROUTER_ERIF_EN, L3_DISCARDS), 633 }, 634 }, 635 { 636 .trap = MLXSW_SP_TRAP_DROP(NON_ROUTABLE, L3_DROPS), 637 .listeners_arr = { 638 MLXSW_SP_RXL_DISCARD(NON_ROUTABLE, L3_DISCARDS), 639 }, 640 }, 641 { 642 .trap = MLXSW_SP_TRAP_EXCEPTION(DECAP_ERROR, TUNNEL_DROPS), 643 .listeners_arr = { 644 MLXSW_SP_RXL_EXCEPTION(DECAP_ECN0, TUNNEL_DISCARDS, 645 TRAP_EXCEPTION_TO_CPU), 646 MLXSW_SP_RXL_EXCEPTION(IPIP_DECAP_ERROR, 647 TUNNEL_DISCARDS, 648 TRAP_EXCEPTION_TO_CPU), 649 MLXSW_SP_RXL_EXCEPTION(DISCARD_DEC_PKT, TUNNEL_DISCARDS, 650 TRAP_EXCEPTION_TO_CPU), 651 }, 652 }, 653 { 654 .trap = MLXSW_SP_TRAP_DROP(OVERLAY_SMAC_MC, TUNNEL_DROPS), 655 .listeners_arr = { 656 MLXSW_SP_RXL_DISCARD(OVERLAY_SMAC_MC, TUNNEL_DISCARDS), 657 }, 658 }, 659 { 660 .trap = MLXSW_SP_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, 661 ACL_DROPS, 662 DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 663 .listeners_arr = { 664 MLXSW_SP_RXL_ACL_DISCARD(INGRESS_ACL, ACL_DISCARDS, 665 DUMMY), 666 }, 667 }, 668 { 669 .trap = MLXSW_SP_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, 670 ACL_DROPS, 671 DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 672 .listeners_arr = { 673 MLXSW_SP_RXL_ACL_DISCARD(EGRESS_ACL, ACL_DISCARDS, 674 DUMMY), 675 }, 676 }, 677 { 678 .trap = MLXSW_SP_TRAP_CONTROL(STP, STP, TRAP), 679 .listeners_arr = { 680 MLXSW_SP_RXL_NO_MARK(STP, STP, TRAP_TO_CPU, true), 681 }, 682 }, 683 { 684 .trap = MLXSW_SP_TRAP_CONTROL(LACP, LACP, TRAP), 685 .listeners_arr = { 686 MLXSW_SP_RXL_NO_MARK(LACP, LACP, TRAP_TO_CPU, true), 687 }, 688 }, 689 { 690 .trap = MLXSW_SP_TRAP_CONTROL(LLDP, LLDP, TRAP), 691 .listeners_arr = { 692 MLXSW_RXL(mlxsw_sp_rx_ptp_listener, LLDP, TRAP_TO_CPU, 693 false, SP_LLDP, DISCARD), 694 }, 695 }, 696 { 697 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR), 698 .listeners_arr = { 699 MLXSW_SP_RXL_MARK(IGMP_QUERY, MC_SNOOPING, 700 MIRROR_TO_CPU, false), 701 }, 702 }, 703 { 704 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING, 705 TRAP), 706 .listeners_arr = { 707 MLXSW_SP_RXL_NO_MARK(IGMP_V1_REPORT, MC_SNOOPING, 708 TRAP_TO_CPU, false), 709 }, 710 }, 711 { 712 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_REPORT, MC_SNOOPING, 713 TRAP), 714 .listeners_arr = { 715 MLXSW_SP_RXL_NO_MARK(IGMP_V2_REPORT, MC_SNOOPING, 716 TRAP_TO_CPU, false), 717 }, 718 }, 719 { 720 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V3_REPORT, MC_SNOOPING, 721 TRAP), 722 .listeners_arr = { 723 MLXSW_SP_RXL_NO_MARK(IGMP_V3_REPORT, MC_SNOOPING, 724 TRAP_TO_CPU, false), 725 }, 726 }, 727 { 728 .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_LEAVE, MC_SNOOPING, 729 TRAP), 730 .listeners_arr = { 731 MLXSW_SP_RXL_NO_MARK(IGMP_V2_LEAVE, MC_SNOOPING, 732 TRAP_TO_CPU, false), 733 }, 734 }, 735 { 736 .trap = MLXSW_SP_TRAP_CONTROL(MLD_QUERY, MC_SNOOPING, MIRROR), 737 .listeners_arr = { 738 MLXSW_SP_RXL_MARK(IPV6_MLDV12_LISTENER_QUERY, 739 MC_SNOOPING, MIRROR_TO_CPU, false), 740 }, 741 }, 742 { 743 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_REPORT, MC_SNOOPING, 744 TRAP), 745 .listeners_arr = { 746 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_REPORT, 747 MC_SNOOPING, TRAP_TO_CPU, false), 748 }, 749 }, 750 { 751 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V2_REPORT, MC_SNOOPING, 752 TRAP), 753 .listeners_arr = { 754 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV2_LISTENER_REPORT, 755 MC_SNOOPING, TRAP_TO_CPU, false), 756 }, 757 }, 758 { 759 .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_DONE, MC_SNOOPING, 760 TRAP), 761 .listeners_arr = { 762 MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_DONE, 763 MC_SNOOPING, TRAP_TO_CPU, false), 764 }, 765 }, 766 { 767 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_DHCP, DHCP, TRAP), 768 .listeners_arr = { 769 MLXSW_SP_RXL_MARK(IPV4_DHCP, DHCP, TRAP_TO_CPU, false), 770 }, 771 }, 772 { 773 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DHCP, DHCP, TRAP), 774 .listeners_arr = { 775 MLXSW_SP_RXL_MARK(IPV6_DHCP, DHCP, TRAP_TO_CPU, false), 776 }, 777 }, 778 { 779 .trap = MLXSW_SP_TRAP_CONTROL(ARP_REQUEST, NEIGH_DISCOVERY, 780 MIRROR), 781 .listeners_arr = { 782 MLXSW_SP_RXL_MARK(ARPBC, NEIGH_DISCOVERY, MIRROR_TO_CPU, 783 false), 784 }, 785 }, 786 { 787 .trap = MLXSW_SP_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY, 788 MIRROR), 789 .listeners_arr = { 790 MLXSW_SP_RXL_MARK(ARPUC, NEIGH_DISCOVERY, MIRROR_TO_CPU, 791 false), 792 }, 793 }, 794 { 795 .trap = MLXSW_SP_TRAP_CONTROL(ARP_OVERLAY, NEIGH_DISCOVERY, 796 TRAP), 797 .listeners_arr = { 798 MLXSW_SP_RXL_NO_MARK(NVE_DECAP_ARP, NEIGH_DISCOVERY, 799 TRAP_TO_CPU, false), 800 }, 801 }, 802 { 803 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_SOLICIT, 804 NEIGH_DISCOVERY, TRAP), 805 .listeners_arr = { 806 MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_SOLICITATION, 807 NEIGH_DISCOVERY, TRAP_TO_CPU, false), 808 }, 809 }, 810 { 811 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_ADVERT, 812 NEIGH_DISCOVERY, TRAP), 813 .listeners_arr = { 814 MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_ADVERTISEMENT, 815 NEIGH_DISCOVERY, TRAP_TO_CPU, false), 816 }, 817 }, 818 { 819 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_BFD, BFD, TRAP), 820 .listeners_arr = { 821 MLXSW_SP_RXL_MARK(IPV4_BFD, BFD, TRAP_TO_CPU, false), 822 }, 823 }, 824 { 825 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_BFD, BFD, TRAP), 826 .listeners_arr = { 827 MLXSW_SP_RXL_MARK(IPV6_BFD, BFD, TRAP_TO_CPU, false), 828 }, 829 }, 830 { 831 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_OSPF, OSPF, TRAP), 832 .listeners_arr = { 833 MLXSW_SP_RXL_MARK(IPV4_OSPF, OSPF, TRAP_TO_CPU, false), 834 }, 835 }, 836 { 837 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_OSPF, OSPF, TRAP), 838 .listeners_arr = { 839 MLXSW_SP_RXL_MARK(IPV6_OSPF, OSPF, TRAP_TO_CPU, false), 840 }, 841 }, 842 { 843 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_BGP, BGP, TRAP), 844 .listeners_arr = { 845 MLXSW_SP_RXL_MARK(IPV4_BGP, BGP, TRAP_TO_CPU, false), 846 }, 847 }, 848 { 849 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_BGP, BGP, TRAP), 850 .listeners_arr = { 851 MLXSW_SP_RXL_MARK(IPV6_BGP, BGP, TRAP_TO_CPU, false), 852 }, 853 }, 854 { 855 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_VRRP, VRRP, TRAP), 856 .listeners_arr = { 857 MLXSW_SP_RXL_MARK(IPV4_VRRP, VRRP, TRAP_TO_CPU, false), 858 }, 859 }, 860 { 861 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_VRRP, VRRP, TRAP), 862 .listeners_arr = { 863 MLXSW_SP_RXL_MARK(IPV6_VRRP, VRRP, TRAP_TO_CPU, false), 864 }, 865 }, 866 { 867 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_PIM, PIM, TRAP), 868 .listeners_arr = { 869 MLXSW_SP_RXL_MARK(IPV4_PIM, PIM, TRAP_TO_CPU, false), 870 }, 871 }, 872 { 873 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_PIM, PIM, TRAP), 874 .listeners_arr = { 875 MLXSW_SP_RXL_MARK(IPV6_PIM, PIM, TRAP_TO_CPU, false), 876 }, 877 }, 878 { 879 .trap = MLXSW_SP_TRAP_CONTROL(UC_LB, UC_LB, MIRROR), 880 .listeners_arr = { 881 MLXSW_SP_RXL_L3_MARK(LBERROR, LBERROR, MIRROR_TO_CPU, 882 false), 883 }, 884 }, 885 { 886 .trap = MLXSW_SP_TRAP_CONTROL(LOCAL_ROUTE, LOCAL_DELIVERY, 887 TRAP), 888 .listeners_arr = { 889 MLXSW_SP_RXL_MARK(IP2ME, IP2ME, TRAP_TO_CPU, false), 890 }, 891 }, 892 { 893 .trap = MLXSW_SP_TRAP_CONTROL(EXTERNAL_ROUTE, EXTERNAL_DELIVERY, 894 TRAP), 895 .listeners_arr = { 896 MLXSW_SP_RXL_MARK(RTR_INGRESS0, EXTERNAL_ROUTE, 897 TRAP_TO_CPU, false), 898 }, 899 }, 900 { 901 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_UC_DIP_LINK_LOCAL_SCOPE, 902 LOCAL_DELIVERY, TRAP), 903 .listeners_arr = { 904 MLXSW_SP_RXL_MARK(IPV6_LINK_LOCAL_DEST, IP2ME, 905 TRAP_TO_CPU, false), 906 }, 907 }, 908 { 909 .trap = MLXSW_SP_TRAP_CONTROL(IPV4_ROUTER_ALERT, LOCAL_DELIVERY, 910 TRAP), 911 .listeners_arr = { 912 MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV4, IP2ME, TRAP_TO_CPU, 913 false), 914 }, 915 }, 916 { 917 /* IPV6_ROUTER_ALERT is defined in uAPI as 22, but it is not 918 * used in this file, so undefine it. 919 */ 920 #undef IPV6_ROUTER_ALERT 921 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_ALERT, LOCAL_DELIVERY, 922 TRAP), 923 .listeners_arr = { 924 MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, IP2ME, TRAP_TO_CPU, 925 false), 926 }, 927 }, 928 { 929 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DIP_ALL_NODES, IPV6, TRAP), 930 .listeners_arr = { 931 MLXSW_SP_RXL_MARK(IPV6_ALL_NODES_LINK, IPV6, 932 TRAP_TO_CPU, false), 933 }, 934 }, 935 { 936 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DIP_ALL_ROUTERS, IPV6, TRAP), 937 .listeners_arr = { 938 MLXSW_SP_RXL_MARK(IPV6_ALL_ROUTERS_LINK, IPV6, 939 TRAP_TO_CPU, false), 940 }, 941 }, 942 { 943 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_SOLICIT, IPV6, TRAP), 944 .listeners_arr = { 945 MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_SOLICITATION, IPV6, 946 TRAP_TO_CPU, false), 947 }, 948 }, 949 { 950 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_ADVERT, IPV6, TRAP), 951 .listeners_arr = { 952 MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_ADVERTISEMENT, IPV6, 953 TRAP_TO_CPU, false), 954 }, 955 }, 956 { 957 .trap = MLXSW_SP_TRAP_CONTROL(IPV6_REDIRECT, IPV6, TRAP), 958 .listeners_arr = { 959 MLXSW_SP_RXL_MARK(L3_IPV6_REDIRECTION, IPV6, 960 TRAP_TO_CPU, false), 961 }, 962 }, 963 { 964 .trap = MLXSW_SP_TRAP_CONTROL(PTP_EVENT, PTP_EVENT, TRAP), 965 .listeners_arr = { 966 MLXSW_RXL(mlxsw_sp_rx_ptp_listener, PTP0, TRAP_TO_CPU, 967 false, SP_PTP0, DISCARD), 968 }, 969 }, 970 { 971 .trap = MLXSW_SP_TRAP_CONTROL(PTP_GENERAL, PTP_GENERAL, TRAP), 972 .listeners_arr = { 973 MLXSW_SP_RXL_NO_MARK(PTP1, PTP1, TRAP_TO_CPU, false), 974 }, 975 }, 976 { 977 .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_SAMPLE, ACL_SAMPLE, 978 MIRROR), 979 .listeners_arr = { 980 MLXSW_RXL(mlxsw_sp_rx_sample_listener, PKT_SAMPLE, 981 MIRROR_TO_CPU, false, SP_PKT_SAMPLE, DISCARD), 982 }, 983 }, 984 { 985 .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_TRAP, ACL_TRAP, TRAP), 986 .listeners_arr = { 987 MLXSW_SP_RXL_NO_MARK(ACL0, FLOW_LOGGING, TRAP_TO_CPU, 988 false), 989 }, 990 }, 991 }; 992 993 static struct mlxsw_sp_trap_policer_item * 994 mlxsw_sp_trap_policer_item_lookup(struct mlxsw_sp *mlxsw_sp, u32 id) 995 { 996 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 997 int i; 998 999 for (i = 0; i < trap->policers_count; i++) { 1000 if (trap->policer_items_arr[i].policer.id == id) 1001 return &trap->policer_items_arr[i]; 1002 } 1003 1004 return NULL; 1005 } 1006 1007 static struct mlxsw_sp_trap_group_item * 1008 mlxsw_sp_trap_group_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id) 1009 { 1010 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1011 int i; 1012 1013 for (i = 0; i < trap->groups_count; i++) { 1014 if (trap->group_items_arr[i].group.id == id) 1015 return &trap->group_items_arr[i]; 1016 } 1017 1018 return NULL; 1019 } 1020 1021 static struct mlxsw_sp_trap_item * 1022 mlxsw_sp_trap_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id) 1023 { 1024 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1025 int i; 1026 1027 for (i = 0; i < trap->traps_count; i++) { 1028 if (trap->trap_items_arr[i].trap.id == id) 1029 return &trap->trap_items_arr[i]; 1030 } 1031 1032 return NULL; 1033 } 1034 1035 static int mlxsw_sp_trap_cpu_policers_set(struct mlxsw_sp *mlxsw_sp) 1036 { 1037 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1038 char qpcr_pl[MLXSW_REG_QPCR_LEN]; 1039 u16 hw_id; 1040 1041 /* The purpose of "thin" policer is to drop as many packets 1042 * as possible. The dummy group is using it. 1043 */ 1044 hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers); 1045 if (WARN_ON(hw_id == trap->max_policers)) 1046 return -ENOBUFS; 1047 1048 __set_bit(hw_id, trap->policers_usage); 1049 trap->thin_policer_hw_id = hw_id; 1050 mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M, 1051 false, 1, 4); 1052 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 1053 } 1054 1055 static int mlxsw_sp_trap_dummy_group_init(struct mlxsw_sp *mlxsw_sp) 1056 { 1057 char htgt_pl[MLXSW_REG_HTGT_LEN]; 1058 1059 mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SP_DUMMY, 1060 mlxsw_sp->trap->thin_policer_hw_id, 0, 1); 1061 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl); 1062 } 1063 1064 static int mlxsw_sp_trap_policer_items_arr_init(struct mlxsw_sp *mlxsw_sp) 1065 { 1066 size_t elem_size = sizeof(struct mlxsw_sp_trap_policer_item); 1067 u64 arr_size = ARRAY_SIZE(mlxsw_sp_trap_policer_items_arr); 1068 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1069 u64 free_policers = 0; 1070 u32 last_id; 1071 int i; 1072 1073 for_each_clear_bit(i, trap->policers_usage, trap->max_policers) 1074 free_policers++; 1075 1076 if (arr_size > free_policers) { 1077 dev_err(mlxsw_sp->bus_info->dev, "Exceeded number of supported packet trap policers\n"); 1078 return -ENOBUFS; 1079 } 1080 1081 trap->policer_items_arr = kcalloc(free_policers, elem_size, GFP_KERNEL); 1082 if (!trap->policer_items_arr) 1083 return -ENOMEM; 1084 1085 trap->policers_count = free_policers; 1086 1087 /* Initialize policer items array with pre-defined policers. */ 1088 memcpy(trap->policer_items_arr, mlxsw_sp_trap_policer_items_arr, 1089 elem_size * arr_size); 1090 1091 /* Initialize policer items array with the rest of the available 1092 * policers. 1093 */ 1094 last_id = mlxsw_sp_trap_policer_items_arr[arr_size - 1].policer.id; 1095 for (i = arr_size; i < trap->policers_count; i++) { 1096 const struct mlxsw_sp_trap_policer_item *policer_item; 1097 1098 /* Use parameters set for first policer and override 1099 * relevant ones. 1100 */ 1101 policer_item = &mlxsw_sp_trap_policer_items_arr[0]; 1102 trap->policer_items_arr[i] = *policer_item; 1103 trap->policer_items_arr[i].policer.id = ++last_id; 1104 trap->policer_items_arr[i].policer.init_rate = 1; 1105 trap->policer_items_arr[i].policer.init_burst = 16; 1106 } 1107 1108 return 0; 1109 } 1110 1111 static void mlxsw_sp_trap_policer_items_arr_fini(struct mlxsw_sp *mlxsw_sp) 1112 { 1113 kfree(mlxsw_sp->trap->policer_items_arr); 1114 } 1115 1116 static int mlxsw_sp_trap_policers_init(struct mlxsw_sp *mlxsw_sp) 1117 { 1118 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1119 const struct mlxsw_sp_trap_policer_item *policer_item; 1120 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1121 int err, i; 1122 1123 err = mlxsw_sp_trap_policer_items_arr_init(mlxsw_sp); 1124 if (err) 1125 return err; 1126 1127 for (i = 0; i < trap->policers_count; i++) { 1128 policer_item = &trap->policer_items_arr[i]; 1129 err = devlink_trap_policers_register(devlink, 1130 &policer_item->policer, 1); 1131 if (err) 1132 goto err_trap_policer_register; 1133 } 1134 1135 return 0; 1136 1137 err_trap_policer_register: 1138 for (i--; i >= 0; i--) { 1139 policer_item = &trap->policer_items_arr[i]; 1140 devlink_trap_policers_unregister(devlink, 1141 &policer_item->policer, 1); 1142 } 1143 mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp); 1144 return err; 1145 } 1146 1147 static void mlxsw_sp_trap_policers_fini(struct mlxsw_sp *mlxsw_sp) 1148 { 1149 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1150 const struct mlxsw_sp_trap_policer_item *policer_item; 1151 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1152 int i; 1153 1154 for (i = trap->policers_count - 1; i >= 0; i--) { 1155 policer_item = &trap->policer_items_arr[i]; 1156 devlink_trap_policers_unregister(devlink, 1157 &policer_item->policer, 1); 1158 } 1159 mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp); 1160 } 1161 1162 static int mlxsw_sp_trap_groups_init(struct mlxsw_sp *mlxsw_sp) 1163 { 1164 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1165 const struct mlxsw_sp_trap_group_item *group_item; 1166 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1167 int err, i; 1168 1169 trap->group_items_arr = kmemdup(mlxsw_sp_trap_group_items_arr, 1170 sizeof(mlxsw_sp_trap_group_items_arr), 1171 GFP_KERNEL); 1172 if (!trap->group_items_arr) 1173 return -ENOMEM; 1174 1175 trap->groups_count = ARRAY_SIZE(mlxsw_sp_trap_group_items_arr); 1176 1177 for (i = 0; i < trap->groups_count; i++) { 1178 group_item = &trap->group_items_arr[i]; 1179 err = devlink_trap_groups_register(devlink, &group_item->group, 1180 1); 1181 if (err) 1182 goto err_trap_group_register; 1183 } 1184 1185 return 0; 1186 1187 err_trap_group_register: 1188 for (i--; i >= 0; i--) { 1189 group_item = &trap->group_items_arr[i]; 1190 devlink_trap_groups_unregister(devlink, &group_item->group, 1); 1191 } 1192 kfree(trap->group_items_arr); 1193 return err; 1194 } 1195 1196 static void mlxsw_sp_trap_groups_fini(struct mlxsw_sp *mlxsw_sp) 1197 { 1198 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1199 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1200 int i; 1201 1202 for (i = trap->groups_count - 1; i >= 0; i--) { 1203 const struct mlxsw_sp_trap_group_item *group_item; 1204 1205 group_item = &trap->group_items_arr[i]; 1206 devlink_trap_groups_unregister(devlink, &group_item->group, 1); 1207 } 1208 kfree(trap->group_items_arr); 1209 } 1210 1211 static bool 1212 mlxsw_sp_trap_listener_is_valid(const struct mlxsw_listener *listener) 1213 { 1214 return listener->trap_id != 0; 1215 } 1216 1217 static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp) 1218 { 1219 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1220 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1221 const struct mlxsw_sp_trap_item *trap_item; 1222 int err, i; 1223 1224 trap->trap_items_arr = kmemdup(mlxsw_sp_trap_items_arr, 1225 sizeof(mlxsw_sp_trap_items_arr), 1226 GFP_KERNEL); 1227 if (!trap->trap_items_arr) 1228 return -ENOMEM; 1229 1230 trap->traps_count = ARRAY_SIZE(mlxsw_sp_trap_items_arr); 1231 1232 for (i = 0; i < trap->traps_count; i++) { 1233 trap_item = &trap->trap_items_arr[i]; 1234 err = devlink_traps_register(devlink, &trap_item->trap, 1, 1235 mlxsw_sp); 1236 if (err) 1237 goto err_trap_register; 1238 } 1239 1240 return 0; 1241 1242 err_trap_register: 1243 for (i--; i >= 0; i--) { 1244 trap_item = &trap->trap_items_arr[i]; 1245 devlink_traps_unregister(devlink, &trap_item->trap, 1); 1246 } 1247 kfree(trap->trap_items_arr); 1248 return err; 1249 } 1250 1251 static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) 1252 { 1253 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 1254 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1255 int i; 1256 1257 for (i = trap->traps_count - 1; i >= 0; i--) { 1258 const struct mlxsw_sp_trap_item *trap_item; 1259 1260 trap_item = &trap->trap_items_arr[i]; 1261 devlink_traps_unregister(devlink, &trap_item->trap, 1); 1262 } 1263 kfree(trap->trap_items_arr); 1264 } 1265 1266 int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp) 1267 { 1268 int err; 1269 1270 err = mlxsw_sp_trap_cpu_policers_set(mlxsw_sp); 1271 if (err) 1272 return err; 1273 1274 err = mlxsw_sp_trap_dummy_group_init(mlxsw_sp); 1275 if (err) 1276 return err; 1277 1278 err = mlxsw_sp_trap_policers_init(mlxsw_sp); 1279 if (err) 1280 return err; 1281 1282 err = mlxsw_sp_trap_groups_init(mlxsw_sp); 1283 if (err) 1284 goto err_trap_groups_init; 1285 1286 err = mlxsw_sp_traps_init(mlxsw_sp); 1287 if (err) 1288 goto err_traps_init; 1289 1290 return 0; 1291 1292 err_traps_init: 1293 mlxsw_sp_trap_groups_fini(mlxsw_sp); 1294 err_trap_groups_init: 1295 mlxsw_sp_trap_policers_fini(mlxsw_sp); 1296 return err; 1297 } 1298 1299 void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp) 1300 { 1301 mlxsw_sp_traps_fini(mlxsw_sp); 1302 mlxsw_sp_trap_groups_fini(mlxsw_sp); 1303 mlxsw_sp_trap_policers_fini(mlxsw_sp); 1304 } 1305 1306 int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core, 1307 const struct devlink_trap *trap, void *trap_ctx) 1308 { 1309 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1310 const struct mlxsw_sp_trap_item *trap_item; 1311 int i; 1312 1313 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); 1314 if (WARN_ON(!trap_item)) 1315 return -EINVAL; 1316 1317 for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) { 1318 const struct mlxsw_listener *listener; 1319 int err; 1320 1321 listener = &trap_item->listeners_arr[i]; 1322 if (!mlxsw_sp_trap_listener_is_valid(listener)) 1323 continue; 1324 err = mlxsw_core_trap_register(mlxsw_core, listener, trap_ctx); 1325 if (err) 1326 return err; 1327 } 1328 1329 return 0; 1330 } 1331 1332 void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core, 1333 const struct devlink_trap *trap, void *trap_ctx) 1334 { 1335 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1336 const struct mlxsw_sp_trap_item *trap_item; 1337 int i; 1338 1339 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); 1340 if (WARN_ON(!trap_item)) 1341 return; 1342 1343 for (i = MLXSW_SP_TRAP_LISTENERS_MAX - 1; i >= 0; i--) { 1344 const struct mlxsw_listener *listener; 1345 1346 listener = &trap_item->listeners_arr[i]; 1347 if (!mlxsw_sp_trap_listener_is_valid(listener)) 1348 continue; 1349 mlxsw_core_trap_unregister(mlxsw_core, listener, trap_ctx); 1350 } 1351 } 1352 1353 int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core, 1354 const struct devlink_trap *trap, 1355 enum devlink_trap_action action) 1356 { 1357 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1358 const struct mlxsw_sp_trap_item *trap_item; 1359 int i; 1360 1361 trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); 1362 if (WARN_ON(!trap_item)) 1363 return -EINVAL; 1364 1365 for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) { 1366 const struct mlxsw_listener *listener; 1367 bool enabled; 1368 int err; 1369 1370 listener = &trap_item->listeners_arr[i]; 1371 if (!mlxsw_sp_trap_listener_is_valid(listener)) 1372 continue; 1373 1374 switch (action) { 1375 case DEVLINK_TRAP_ACTION_DROP: 1376 enabled = false; 1377 break; 1378 case DEVLINK_TRAP_ACTION_TRAP: 1379 enabled = true; 1380 break; 1381 default: 1382 return -EINVAL; 1383 } 1384 err = mlxsw_core_trap_state_set(mlxsw_core, listener, enabled); 1385 if (err) 1386 return err; 1387 } 1388 1389 return 0; 1390 } 1391 1392 static int 1393 __mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, 1394 const struct devlink_trap_group *group, 1395 u32 policer_id) 1396 { 1397 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1398 u16 hw_policer_id = MLXSW_REG_HTGT_INVALID_POLICER; 1399 const struct mlxsw_sp_trap_group_item *group_item; 1400 char htgt_pl[MLXSW_REG_HTGT_LEN]; 1401 1402 group_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, group->id); 1403 if (WARN_ON(!group_item)) 1404 return -EINVAL; 1405 1406 if (policer_id) { 1407 struct mlxsw_sp_trap_policer_item *policer_item; 1408 1409 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, 1410 policer_id); 1411 if (WARN_ON(!policer_item)) 1412 return -EINVAL; 1413 hw_policer_id = policer_item->hw_id; 1414 } 1415 1416 mlxsw_reg_htgt_pack(htgt_pl, group_item->hw_group_id, hw_policer_id, 1417 group_item->priority, group_item->priority); 1418 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); 1419 } 1420 1421 int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, 1422 const struct devlink_trap_group *group) 1423 { 1424 return __mlxsw_sp_trap_group_init(mlxsw_core, group, 1425 group->init_policer_id); 1426 } 1427 1428 int mlxsw_sp_trap_group_set(struct mlxsw_core *mlxsw_core, 1429 const struct devlink_trap_group *group, 1430 const struct devlink_trap_policer *policer) 1431 { 1432 u32 policer_id = policer ? policer->id : 0; 1433 1434 return __mlxsw_sp_trap_group_init(mlxsw_core, group, policer_id); 1435 } 1436 1437 static int 1438 mlxsw_sp_trap_policer_item_init(struct mlxsw_sp *mlxsw_sp, 1439 struct mlxsw_sp_trap_policer_item *policer_item) 1440 { 1441 struct mlxsw_sp_trap *trap = mlxsw_sp->trap; 1442 u16 hw_id; 1443 1444 /* We should be able to allocate a policer because the number of 1445 * policers we registered with devlink is in according with the number 1446 * of available policers. 1447 */ 1448 hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers); 1449 if (WARN_ON(hw_id == trap->max_policers)) 1450 return -ENOBUFS; 1451 1452 __set_bit(hw_id, trap->policers_usage); 1453 policer_item->hw_id = hw_id; 1454 1455 return 0; 1456 } 1457 1458 static void 1459 mlxsw_sp_trap_policer_item_fini(struct mlxsw_sp *mlxsw_sp, 1460 struct mlxsw_sp_trap_policer_item *policer_item) 1461 { 1462 __clear_bit(policer_item->hw_id, mlxsw_sp->trap->policers_usage); 1463 } 1464 1465 static int mlxsw_sp_trap_policer_bs(u64 burst, u8 *p_burst_size, 1466 struct netlink_ext_ack *extack) 1467 { 1468 int bs = fls64(burst) - 1; 1469 1470 if (burst != (BIT_ULL(bs))) { 1471 NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two"); 1472 return -EINVAL; 1473 } 1474 1475 *p_burst_size = bs; 1476 1477 return 0; 1478 } 1479 1480 static int __mlxsw_sp_trap_policer_set(struct mlxsw_sp *mlxsw_sp, u16 hw_id, 1481 u64 rate, u64 burst, bool clear_counter, 1482 struct netlink_ext_ack *extack) 1483 { 1484 char qpcr_pl[MLXSW_REG_QPCR_LEN]; 1485 u8 burst_size; 1486 int err; 1487 1488 err = mlxsw_sp_trap_policer_bs(burst, &burst_size, extack); 1489 if (err) 1490 return err; 1491 1492 mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M, false, 1493 rate, burst_size); 1494 mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, clear_counter); 1495 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 1496 } 1497 1498 int mlxsw_sp_trap_policer_init(struct mlxsw_core *mlxsw_core, 1499 const struct devlink_trap_policer *policer) 1500 { 1501 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1502 struct mlxsw_sp_trap_policer_item *policer_item; 1503 int err; 1504 1505 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1506 if (WARN_ON(!policer_item)) 1507 return -EINVAL; 1508 1509 err = mlxsw_sp_trap_policer_item_init(mlxsw_sp, policer_item); 1510 if (err) 1511 return err; 1512 1513 err = __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id, 1514 policer->init_rate, 1515 policer->init_burst, true, NULL); 1516 if (err) 1517 goto err_trap_policer_set; 1518 1519 return 0; 1520 1521 err_trap_policer_set: 1522 mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item); 1523 return err; 1524 } 1525 1526 void mlxsw_sp_trap_policer_fini(struct mlxsw_core *mlxsw_core, 1527 const struct devlink_trap_policer *policer) 1528 { 1529 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1530 struct mlxsw_sp_trap_policer_item *policer_item; 1531 1532 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1533 if (WARN_ON(!policer_item)) 1534 return; 1535 1536 mlxsw_sp_trap_policer_item_fini(mlxsw_sp, policer_item); 1537 } 1538 1539 int mlxsw_sp_trap_policer_set(struct mlxsw_core *mlxsw_core, 1540 const struct devlink_trap_policer *policer, 1541 u64 rate, u64 burst, 1542 struct netlink_ext_ack *extack) 1543 { 1544 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1545 struct mlxsw_sp_trap_policer_item *policer_item; 1546 1547 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1548 if (WARN_ON(!policer_item)) 1549 return -EINVAL; 1550 1551 return __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id, 1552 rate, burst, false, extack); 1553 } 1554 1555 int 1556 mlxsw_sp_trap_policer_counter_get(struct mlxsw_core *mlxsw_core, 1557 const struct devlink_trap_policer *policer, 1558 u64 *p_drops) 1559 { 1560 struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 1561 struct mlxsw_sp_trap_policer_item *policer_item; 1562 char qpcr_pl[MLXSW_REG_QPCR_LEN]; 1563 int err; 1564 1565 policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); 1566 if (WARN_ON(!policer_item)) 1567 return -EINVAL; 1568 1569 mlxsw_reg_qpcr_pack(qpcr_pl, policer_item->hw_id, 1570 MLXSW_REG_QPCR_IR_UNITS_M, false, 0, 0); 1571 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 1572 if (err) 1573 return err; 1574 1575 *p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl); 1576 1577 return 0; 1578 } 1579