1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2019 Mellanox Technologies. All rights reserved */ 3 4 #include <linux/kernel.h> 5 #include <net/devlink.h> 6 #include <uapi/linux/devlink.h> 7 8 #include "core.h" 9 #include "reg.h" 10 #include "spectrum.h" 11 12 /* All driver-specific traps must be documented in 13 * Documentation/networking/devlink/mlxsw.rst 14 */ 15 enum { 16 DEVLINK_MLXSW_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX, 17 DEVLINK_MLXSW_TRAP_ID_IRIF_DISABLED, 18 DEVLINK_MLXSW_TRAP_ID_ERIF_DISABLED, 19 }; 20 21 #define DEVLINK_MLXSW_TRAP_NAME_IRIF_DISABLED \ 22 "irif_disabled" 23 #define DEVLINK_MLXSW_TRAP_NAME_ERIF_DISABLED \ 24 "erif_disabled" 25 26 #define MLXSW_SP_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT 27 28 static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, 29 u8 local_port, 30 struct mlxsw_sp_port *mlxsw_sp_port) 31 { 32 struct mlxsw_sp_port_pcpu_stats *pcpu_stats; 33 34 if (unlikely(!mlxsw_sp_port)) { 35 dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n", 36 local_port); 37 kfree_skb(skb); 38 return -EINVAL; 39 } 40 41 skb->dev = mlxsw_sp_port->dev; 42 43 pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats); 44 u64_stats_update_begin(&pcpu_stats->syncp); 45 pcpu_stats->rx_packets++; 46 pcpu_stats->rx_bytes += skb->len; 47 u64_stats_update_end(&pcpu_stats->syncp); 48 49 skb->protocol = eth_type_trans(skb, skb->dev); 50 51 return 0; 52 } 53 54 static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port, 55 void *trap_ctx) 56 { 57 struct devlink_port *in_devlink_port; 58 struct mlxsw_sp_port *mlxsw_sp_port; 59 struct mlxsw_sp *mlxsw_sp; 60 struct devlink *devlink; 61 int err; 62 63 mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); 64 mlxsw_sp_port = mlxsw_sp->ports[local_port]; 65 66 err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port); 67 if (err) 68 return; 69 70 devlink = priv_to_devlink(mlxsw_sp->core); 71 in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, 72 local_port); 73 skb_push(skb, ETH_HLEN); 74 devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL); 75 consume_skb(skb); 76 } 77 78 static void mlxsw_sp_rx_acl_drop_listener(struct sk_buff *skb, u8 local_port, 79 void *trap_ctx) 80 { 81 u32 cookie_index = mlxsw_skb_cb(skb)->cookie_index; 82 const struct flow_action_cookie *fa_cookie; 83 struct devlink_port *in_devlink_port; 84 struct mlxsw_sp_port *mlxsw_sp_port; 85 struct mlxsw_sp *mlxsw_sp; 86 struct devlink *devlink; 87 int err; 88 89 mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); 90 mlxsw_sp_port = mlxsw_sp->ports[local_port]; 91 92 err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port); 93 if (err) 94 return; 95 96 devlink = priv_to_devlink(mlxsw_sp->core); 97 in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, 98 local_port); 99 skb_push(skb, ETH_HLEN); 100 rcu_read_lock(); 101 fa_cookie = mlxsw_sp_acl_act_cookie_lookup(mlxsw_sp, cookie_index); 102 devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, fa_cookie); 103 rcu_read_unlock(); 104 consume_skb(skb); 105 } 106 107 static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, 108 void *trap_ctx) 109 { 110 struct devlink_port *in_devlink_port; 111 struct mlxsw_sp_port *mlxsw_sp_port; 112 struct mlxsw_sp *mlxsw_sp; 113 struct devlink *devlink; 114 int err; 115 116 mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); 117 mlxsw_sp_port = mlxsw_sp->ports[local_port]; 118 119 err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port); 120 if (err) 121 return; 122 123 devlink = priv_to_devlink(mlxsw_sp->core); 124 in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, 125 local_port); 126 skb_push(skb, ETH_HLEN); 127 devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL); 128 skb_pull(skb, ETH_HLEN); 129 skb->offload_fwd_mark = 1; 130 netif_receive_skb(skb); 131 } 132 133 #define MLXSW_SP_TRAP_DROP(_id, _group_id) \ 134 DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 135 DEVLINK_TRAP_GROUP_GENERIC(_group_id), \ 136 MLXSW_SP_TRAP_METADATA) 137 138 #define MLXSW_SP_TRAP_DROP_EXT(_id, _group_id, _metadata) \ 139 DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 140 DEVLINK_TRAP_GROUP_GENERIC(_group_id), \ 141 MLXSW_SP_TRAP_METADATA | (_metadata)) 142 143 #define MLXSW_SP_TRAP_DRIVER_DROP(_id, _group_id) \ 144 DEVLINK_TRAP_DRIVER(DROP, DROP, DEVLINK_MLXSW_TRAP_ID_##_id, \ 145 DEVLINK_MLXSW_TRAP_NAME_##_id, \ 146 DEVLINK_TRAP_GROUP_GENERIC(_group_id), \ 147 MLXSW_SP_TRAP_METADATA) 148 149 #define MLXSW_SP_TRAP_EXCEPTION(_id, _group_id) \ 150 DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \ 151 DEVLINK_TRAP_GROUP_GENERIC(_group_id), \ 152 MLXSW_SP_TRAP_METADATA) 153 154 #define MLXSW_SP_RXL_DISCARD(_id, _group_id) \ 155 MLXSW_RXL_DIS(mlxsw_sp_rx_drop_listener, DISCARD_##_id, \ 156 TRAP_EXCEPTION_TO_CPU, false, SP_##_group_id, \ 157 SET_FW_DEFAULT, SP_##_group_id) 158 159 #define MLXSW_SP_RXL_ACL_DISCARD(_id, _en_group_id, _dis_group_id) \ 160 MLXSW_RXL_DIS(mlxsw_sp_rx_acl_drop_listener, DISCARD_##_id, \ 161 TRAP_EXCEPTION_TO_CPU, false, SP_##_en_group_id, \ 162 SET_FW_DEFAULT, SP_##_dis_group_id) 163 164 #define MLXSW_SP_RXL_EXCEPTION(_id, _group_id, _action) \ 165 MLXSW_RXL(mlxsw_sp_rx_exception_listener, _id, \ 166 _action, false, SP_##_group_id, SET_FW_DEFAULT) 167 168 static const struct devlink_trap mlxsw_sp_traps_arr[] = { 169 MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS), 170 MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS), 171 MLXSW_SP_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS), 172 MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS), 173 MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS), 174 MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS), 175 MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS), 176 MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS), 177 MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS), 178 MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS), 179 MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS), 180 MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS), 181 MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS), 182 MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS), 183 MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE, L3_DROPS), 184 MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DROPS), 185 MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_DROPS), 186 MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_DROPS), 187 MLXSW_SP_TRAP_EXCEPTION(RPF, L3_DROPS), 188 MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_DROPS), 189 MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH, L3_DROPS), 190 MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS, L3_DROPS), 191 MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS, L3_DROPS), 192 MLXSW_SP_TRAP_DRIVER_DROP(IRIF_DISABLED, L3_DROPS), 193 MLXSW_SP_TRAP_DRIVER_DROP(ERIF_DISABLED, L3_DROPS), 194 MLXSW_SP_TRAP_DROP(NON_ROUTABLE, L3_DROPS), 195 MLXSW_SP_TRAP_EXCEPTION(DECAP_ERROR, TUNNEL_DROPS), 196 MLXSW_SP_TRAP_DROP(OVERLAY_SMAC_MC, TUNNEL_DROPS), 197 MLXSW_SP_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, ACL_DROPS, 198 DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 199 MLXSW_SP_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, ACL_DROPS, 200 DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 201 }; 202 203 static const struct mlxsw_listener mlxsw_sp_listeners_arr[] = { 204 MLXSW_SP_RXL_DISCARD(ING_PACKET_SMAC_MC, L2_DISCARDS), 205 MLXSW_SP_RXL_DISCARD(ING_SWITCH_VTAG_ALLOW, L2_DISCARDS), 206 MLXSW_SP_RXL_DISCARD(ING_SWITCH_VLAN, L2_DISCARDS), 207 MLXSW_SP_RXL_DISCARD(ING_SWITCH_STP, L2_DISCARDS), 208 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS), 209 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS), 210 MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS), 211 MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS), 212 MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET, L3_DISCARDS), 213 MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC, L3_DISCARDS), 214 MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS), 215 MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS), 216 MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS), 217 MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR, L3_DISCARDS), 218 MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC, L3_DISCARDS), 219 MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE, L3_DISCARDS), 220 MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DISCARDS), 221 MLXSW_SP_RXL_EXCEPTION(MTUERROR, ROUTER_EXP, TRAP_TO_CPU), 222 MLXSW_SP_RXL_EXCEPTION(TTLERROR, ROUTER_EXP, TRAP_TO_CPU), 223 MLXSW_SP_RXL_EXCEPTION(RPF, RPF, TRAP_TO_CPU), 224 MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, REMOTE_ROUTE, TRAP_TO_CPU), 225 MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, HOST_MISS, TRAP_TO_CPU), 226 MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, HOST_MISS, TRAP_TO_CPU), 227 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER3, REMOTE_ROUTE, 228 TRAP_EXCEPTION_TO_CPU), 229 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4, ROUTER_EXP, 230 TRAP_EXCEPTION_TO_CPU), 231 MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6, ROUTER_EXP, 232 TRAP_EXCEPTION_TO_CPU), 233 MLXSW_SP_RXL_DISCARD(ROUTER_IRIF_EN, L3_DISCARDS), 234 MLXSW_SP_RXL_DISCARD(ROUTER_ERIF_EN, L3_DISCARDS), 235 MLXSW_SP_RXL_DISCARD(NON_ROUTABLE, L3_DISCARDS), 236 MLXSW_SP_RXL_EXCEPTION(DECAP_ECN0, ROUTER_EXP, TRAP_EXCEPTION_TO_CPU), 237 MLXSW_SP_RXL_EXCEPTION(IPIP_DECAP_ERROR, ROUTER_EXP, 238 TRAP_EXCEPTION_TO_CPU), 239 MLXSW_SP_RXL_EXCEPTION(DISCARD_DEC_PKT, TUNNEL_DISCARDS, 240 TRAP_EXCEPTION_TO_CPU), 241 MLXSW_SP_RXL_DISCARD(OVERLAY_SMAC_MC, TUNNEL_DISCARDS), 242 MLXSW_SP_RXL_ACL_DISCARD(INGRESS_ACL, ACL_DISCARDS, DUMMY), 243 MLXSW_SP_RXL_ACL_DISCARD(EGRESS_ACL, ACL_DISCARDS, DUMMY), 244 }; 245 246 /* Mapping between hardware trap and devlink trap. Multiple hardware traps can 247 * be mapped to the same devlink trap. Order is according to 248 * 'mlxsw_sp_listeners_arr'. 249 */ 250 static const u16 mlxsw_sp_listener_devlink_map[] = { 251 DEVLINK_TRAP_GENERIC_ID_SMAC_MC, 252 DEVLINK_TRAP_GENERIC_ID_VLAN_TAG_MISMATCH, 253 DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER, 254 DEVLINK_TRAP_GENERIC_ID_INGRESS_STP_FILTER, 255 DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST, 256 DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST, 257 DEVLINK_TRAP_GENERIC_ID_PORT_LOOPBACK_FILTER, 258 DEVLINK_TRAP_GENERIC_ID_BLACKHOLE_ROUTE, 259 DEVLINK_TRAP_GENERIC_ID_NON_IP_PACKET, 260 DEVLINK_TRAP_GENERIC_ID_UC_DIP_MC_DMAC, 261 DEVLINK_TRAP_GENERIC_ID_DIP_LB, 262 DEVLINK_TRAP_GENERIC_ID_SIP_MC, 263 DEVLINK_TRAP_GENERIC_ID_SIP_LB, 264 DEVLINK_TRAP_GENERIC_ID_CORRUPTED_IP_HDR, 265 DEVLINK_TRAP_GENERIC_ID_IPV4_SIP_BC, 266 DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_RESERVED_SCOPE, 267 DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, 268 DEVLINK_TRAP_GENERIC_ID_MTU_ERROR, 269 DEVLINK_TRAP_GENERIC_ID_TTL_ERROR, 270 DEVLINK_TRAP_GENERIC_ID_RPF, 271 DEVLINK_TRAP_GENERIC_ID_REJECT_ROUTE, 272 DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH, 273 DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH, 274 DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH, 275 DEVLINK_TRAP_GENERIC_ID_IPV4_LPM_UNICAST_MISS, 276 DEVLINK_TRAP_GENERIC_ID_IPV6_LPM_UNICAST_MISS, 277 DEVLINK_MLXSW_TRAP_ID_IRIF_DISABLED, 278 DEVLINK_MLXSW_TRAP_ID_ERIF_DISABLED, 279 DEVLINK_TRAP_GENERIC_ID_NON_ROUTABLE, 280 DEVLINK_TRAP_GENERIC_ID_DECAP_ERROR, 281 DEVLINK_TRAP_GENERIC_ID_DECAP_ERROR, 282 DEVLINK_TRAP_GENERIC_ID_DECAP_ERROR, 283 DEVLINK_TRAP_GENERIC_ID_OVERLAY_SMAC_MC, 284 DEVLINK_TRAP_GENERIC_ID_INGRESS_FLOW_ACTION_DROP, 285 DEVLINK_TRAP_GENERIC_ID_EGRESS_FLOW_ACTION_DROP, 286 }; 287 288 #define MLXSW_SP_DISCARD_POLICER_ID (MLXSW_REG_HTGT_TRAP_GROUP_MAX + 1) 289 #define MLXSW_SP_THIN_POLICER_ID (MLXSW_SP_DISCARD_POLICER_ID + 1) 290 291 static int mlxsw_sp_trap_cpu_policers_set(struct mlxsw_sp *mlxsw_sp) 292 { 293 char qpcr_pl[MLXSW_REG_QPCR_LEN]; 294 int err; 295 296 mlxsw_reg_qpcr_pack(qpcr_pl, MLXSW_SP_DISCARD_POLICER_ID, 297 MLXSW_REG_QPCR_IR_UNITS_M, false, 10 * 1024, 7); 298 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 299 if (err) 300 return err; 301 302 /* The purpose of "thin" policer is to drop as many packets 303 * as possible. The dummy group is using it. 304 */ 305 mlxsw_reg_qpcr_pack(qpcr_pl, MLXSW_SP_THIN_POLICER_ID, 306 MLXSW_REG_QPCR_IR_UNITS_M, false, 1, 4); 307 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 308 } 309 310 static int mlxsw_sp_trap_dummy_group_init(struct mlxsw_sp *mlxsw_sp) 311 { 312 char htgt_pl[MLXSW_REG_HTGT_LEN]; 313 314 mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SP_DUMMY, 315 MLXSW_SP_THIN_POLICER_ID, 0, 1); 316 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl); 317 } 318 319 int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp) 320 { 321 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 322 int err; 323 324 err = mlxsw_sp_trap_cpu_policers_set(mlxsw_sp); 325 if (err) 326 return err; 327 328 err = mlxsw_sp_trap_dummy_group_init(mlxsw_sp); 329 if (err) 330 return err; 331 332 if (WARN_ON(ARRAY_SIZE(mlxsw_sp_listener_devlink_map) != 333 ARRAY_SIZE(mlxsw_sp_listeners_arr))) 334 return -EINVAL; 335 336 return devlink_traps_register(devlink, mlxsw_sp_traps_arr, 337 ARRAY_SIZE(mlxsw_sp_traps_arr), 338 mlxsw_sp); 339 } 340 341 void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp) 342 { 343 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 344 345 devlink_traps_unregister(devlink, mlxsw_sp_traps_arr, 346 ARRAY_SIZE(mlxsw_sp_traps_arr)); 347 } 348 349 int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core, 350 const struct devlink_trap *trap, void *trap_ctx) 351 { 352 int i; 353 354 for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) { 355 const struct mlxsw_listener *listener; 356 int err; 357 358 if (mlxsw_sp_listener_devlink_map[i] != trap->id) 359 continue; 360 listener = &mlxsw_sp_listeners_arr[i]; 361 362 err = mlxsw_core_trap_register(mlxsw_core, listener, trap_ctx); 363 if (err) 364 return err; 365 } 366 367 return 0; 368 } 369 370 void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core, 371 const struct devlink_trap *trap, void *trap_ctx) 372 { 373 int i; 374 375 for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) { 376 const struct mlxsw_listener *listener; 377 378 if (mlxsw_sp_listener_devlink_map[i] != trap->id) 379 continue; 380 listener = &mlxsw_sp_listeners_arr[i]; 381 382 mlxsw_core_trap_unregister(mlxsw_core, listener, trap_ctx); 383 } 384 } 385 386 int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core, 387 const struct devlink_trap *trap, 388 enum devlink_trap_action action) 389 { 390 int i; 391 392 for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) { 393 const struct mlxsw_listener *listener; 394 bool enabled; 395 int err; 396 397 if (mlxsw_sp_listener_devlink_map[i] != trap->id) 398 continue; 399 listener = &mlxsw_sp_listeners_arr[i]; 400 switch (action) { 401 case DEVLINK_TRAP_ACTION_DROP: 402 enabled = false; 403 break; 404 case DEVLINK_TRAP_ACTION_TRAP: 405 enabled = true; 406 break; 407 default: 408 return -EINVAL; 409 } 410 err = mlxsw_core_trap_state_set(mlxsw_core, listener, enabled); 411 if (err) 412 return err; 413 } 414 415 return 0; 416 } 417 418 int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, 419 const struct devlink_trap_group *group) 420 { 421 char htgt_pl[MLXSW_REG_HTGT_LEN]; 422 u8 priority, tc, group_id; 423 u16 policer_id; 424 425 switch (group->id) { 426 case DEVLINK_TRAP_GROUP_GENERIC_ID_L2_DROPS: 427 group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS; 428 policer_id = MLXSW_SP_DISCARD_POLICER_ID; 429 priority = 0; 430 tc = 1; 431 break; 432 case DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS: 433 group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS; 434 policer_id = MLXSW_SP_DISCARD_POLICER_ID; 435 priority = 0; 436 tc = 1; 437 break; 438 case DEVLINK_TRAP_GROUP_GENERIC_ID_TUNNEL_DROPS: 439 group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS; 440 policer_id = MLXSW_SP_DISCARD_POLICER_ID; 441 priority = 0; 442 tc = 1; 443 break; 444 case DEVLINK_TRAP_GROUP_GENERIC_ID_ACL_DROPS: 445 group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS; 446 policer_id = MLXSW_SP_DISCARD_POLICER_ID; 447 priority = 0; 448 tc = 1; 449 break; 450 default: 451 return -EINVAL; 452 } 453 454 mlxsw_reg_htgt_pack(htgt_pl, group_id, policer_id, priority, tc); 455 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); 456 } 457