diff options
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c | 1324 |
1 files changed, 1072 insertions, 252 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c index fbf714d027d8..157a42c63066 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c @@ -12,6 +12,24 @@ #include "spectrum.h" #include "spectrum_trap.h" +struct mlxsw_sp_trap_policer_item { + struct devlink_trap_policer policer; + u16 hw_id; +}; + +struct mlxsw_sp_trap_group_item { + struct devlink_trap_group group; + u16 hw_group_id; + u8 priority; +}; + +#define MLXSW_SP_TRAP_LISTENERS_MAX 3 + +struct mlxsw_sp_trap_item { + struct devlink_trap trap; + struct mlxsw_listener listeners_arr[MLXSW_SP_TRAP_LISTENERS_MAX]; +}; + /* All driver-specific traps must be documented in * Documentation/networking/devlink/mlxsw.rst */ @@ -107,8 +125,8 @@ static void mlxsw_sp_rx_acl_drop_listener(struct sk_buff *skb, u8 local_port, consume_skb(skb); } -static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, - void *trap_ctx) +static int __mlxsw_sp_rx_no_mark_listener(struct sk_buff *skb, u8 local_port, + void *trap_ctx) { struct devlink_port *in_devlink_port; struct mlxsw_sp_port *mlxsw_sp_port; @@ -121,7 +139,7 @@ static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, err = mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port); if (err) - return; + return err; devlink = priv_to_devlink(mlxsw_sp->core); in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, @@ -129,10 +147,71 @@ static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, skb_push(skb, ETH_HLEN); devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port, NULL); skb_pull(skb, ETH_HLEN); - skb->offload_fwd_mark = 1; + + return 0; +} + +static void mlxsw_sp_rx_no_mark_listener(struct sk_buff *skb, u8 local_port, + void *trap_ctx) +{ + int err; + + err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx); + if (err) + return; + netif_receive_skb(skb); } +static void mlxsw_sp_rx_mark_listener(struct sk_buff *skb, u8 local_port, + void *trap_ctx) +{ + skb->offload_fwd_mark = 1; + mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx); +} + +static void mlxsw_sp_rx_l3_mark_listener(struct sk_buff *skb, u8 local_port, + void *trap_ctx) +{ + skb->offload_l3_fwd_mark = 1; + skb->offload_fwd_mark = 1; + mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx); +} + +static void mlxsw_sp_rx_ptp_listener(struct sk_buff *skb, u8 local_port, + void *trap_ctx) +{ + struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); + int err; + + err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx); + if (err) + return; + + /* The PTP handler expects skb->data to point to the start of the + * Ethernet header. + */ + skb_push(skb, ETH_HLEN); + mlxsw_sp_ptp_receive(mlxsw_sp, skb, local_port); +} + +static void mlxsw_sp_rx_sample_listener(struct sk_buff *skb, u8 local_port, + void *trap_ctx) +{ + struct mlxsw_sp *mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); + int err; + + err = __mlxsw_sp_rx_no_mark_listener(skb, local_port, trap_ctx); + if (err) + return; + + /* The sample handler expects skb->data to point to the start of the + * Ethernet header. + */ + skb_push(skb, ETH_HLEN); + mlxsw_sp_sample_receive(mlxsw_sp, skb, local_port); +} + #define MLXSW_SP_TRAP_DROP(_id, _group_id) \ DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ @@ -154,6 +233,11 @@ static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ MLXSW_SP_TRAP_METADATA) +#define MLXSW_SP_TRAP_CONTROL(_id, _group_id, _action) \ + DEVLINK_TRAP_GENERIC(CONTROL, _action, _id, \ + DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ + MLXSW_SP_TRAP_METADATA) + #define MLXSW_SP_RXL_DISCARD(_id, _group_id) \ MLXSW_RXL_DIS(mlxsw_sp_rx_drop_listener, DISCARD_##_id, \ TRAP_EXCEPTION_TO_CPU, false, SP_##_group_id, \ @@ -165,9 +249,21 @@ static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, SET_FW_DEFAULT, SP_##_dis_group_id) #define MLXSW_SP_RXL_EXCEPTION(_id, _group_id, _action) \ - MLXSW_RXL(mlxsw_sp_rx_exception_listener, _id, \ + MLXSW_RXL(mlxsw_sp_rx_mark_listener, _id, \ _action, false, SP_##_group_id, SET_FW_DEFAULT) +#define MLXSW_SP_RXL_NO_MARK(_id, _group_id, _action, _is_ctrl) \ + MLXSW_RXL(mlxsw_sp_rx_no_mark_listener, _id, _action, \ + _is_ctrl, SP_##_group_id, DISCARD) + +#define MLXSW_SP_RXL_MARK(_id, _group_id, _action, _is_ctrl) \ + MLXSW_RXL(mlxsw_sp_rx_mark_listener, _id, _action, _is_ctrl, \ + SP_##_group_id, DISCARD) + +#define MLXSW_SP_RXL_L3_MARK(_id, _group_id, _action, _is_ctrl) \ + MLXSW_RXL(mlxsw_sp_rx_l3_mark_listener, _id, _action, _is_ctrl, \ + SP_##_group_id, DISCARD) + #define MLXSW_SP_TRAP_POLICER(_id, _rate, _burst) \ DEVLINK_TRAP_POLICER(_id, _rate, _burst, \ MLXSW_REG_QPCR_HIGHEST_CIR, \ @@ -176,149 +272,753 @@ static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, 1 << MLXSW_REG_QPCR_LOWEST_CBS) /* Ordered by policer identifier */ -static const struct devlink_trap_policer mlxsw_sp_trap_policers_arr[] = { - MLXSW_SP_TRAP_POLICER(1, 10 * 1024, 128), +static const struct mlxsw_sp_trap_policer_item +mlxsw_sp_trap_policer_items_arr[] = { + { + .policer = MLXSW_SP_TRAP_POLICER(1, 10 * 1024, 128), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(2, 128, 128), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(3, 128, 128), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(4, 128, 128), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(5, 16 * 1024, 128), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(6, 128, 128), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(7, 1024, 128), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(8, 20 * 1024, 1024), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(9, 128, 128), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(10, 1024, 128), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(11, 360, 128), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(12, 128, 128), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(13, 128, 128), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(14, 1024, 128), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(15, 1024, 128), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(16, 24 * 1024, 4096), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(17, 19 * 1024, 4096), + }, + { + .policer = MLXSW_SP_TRAP_POLICER(18, 1024, 128), + }, }; -static const struct devlink_trap_group mlxsw_sp_trap_groups_arr[] = { - DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 1), - DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1), - DEVLINK_TRAP_GROUP_GENERIC(TUNNEL_DROPS, 1), - DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 1), +static const struct mlxsw_sp_trap_group_item mlxsw_sp_trap_group_items_arr[] = { + { + .group = DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 1), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS, + .priority = 0, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS, + .priority = 0, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 1), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_EXCEPTIONS, + .priority = 2, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(TUNNEL_DROPS, 1), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS, + .priority = 0, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 1), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS, + .priority = 0, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(STP, 2), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_STP, + .priority = 5, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(LACP, 3), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LACP, + .priority = 5, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(LLDP, 4), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP, + .priority = 5, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(MC_SNOOPING, 5), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_MC_SNOOPING, + .priority = 3, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(DHCP, 6), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_DHCP, + .priority = 2, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(NEIGH_DISCOVERY, 7), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_NEIGH_DISCOVERY, + .priority = 2, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(BFD, 8), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BFD, + .priority = 5, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(OSPF, 9), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_OSPF, + .priority = 5, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(BGP, 10), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_BGP, + .priority = 4, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(VRRP, 11), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_VRRP, + .priority = 5, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(PIM, 12), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PIM, + .priority = 5, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(UC_LB, 13), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_LBERROR, + .priority = 0, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(LOCAL_DELIVERY, 14), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME, + .priority = 2, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(IPV6, 15), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6, + .priority = 2, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(PTP_EVENT, 16), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP0, + .priority = 5, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(PTP_GENERAL, 17), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PTP1, + .priority = 2, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_SAMPLE, 0), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_PKT_SAMPLE, + .priority = 0, + }, + { + .group = DEVLINK_TRAP_GROUP_GENERIC(ACL_TRAP, 18), + .hw_group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_FLOW_LOGGING, + .priority = 4, + }, }; -static const struct devlink_trap mlxsw_sp_traps_arr[] = { - MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS), - MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS), - MLXSW_SP_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS), - MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS), - MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS), - MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS), - MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS), - MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS), - MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS), - MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS), - MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS), - MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS), - MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS), - MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS), - MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE, L3_DROPS), - MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DROPS), - MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_DROPS), - MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_DROPS), - MLXSW_SP_TRAP_EXCEPTION(RPF, L3_DROPS), - MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_DROPS), - MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH, L3_DROPS), - MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS, L3_DROPS), - MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS, L3_DROPS), - MLXSW_SP_TRAP_DRIVER_DROP(IRIF_DISABLED, L3_DROPS), - MLXSW_SP_TRAP_DRIVER_DROP(ERIF_DISABLED, L3_DROPS), - MLXSW_SP_TRAP_DROP(NON_ROUTABLE, L3_DROPS), - MLXSW_SP_TRAP_EXCEPTION(DECAP_ERROR, TUNNEL_DROPS), - MLXSW_SP_TRAP_DROP(OVERLAY_SMAC_MC, TUNNEL_DROPS), - MLXSW_SP_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, ACL_DROPS, - DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), - MLXSW_SP_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, ACL_DROPS, - DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), +static const struct mlxsw_sp_trap_item mlxsw_sp_trap_items_arr[] = { + { + .trap = MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(ING_PACKET_SMAC_MC, L2_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(ING_SWITCH_VTAG_ALLOW, + L2_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(ING_SWITCH_VLAN, L2_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(ING_SWITCH_STP, L2_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS), + MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET, + L3_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC, + L3_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR, + L3_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC, + L3_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE, + L3_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE, + L3_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, + L3_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, + L3_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_EXCEPTIONS), + .listeners_arr = { + MLXSW_SP_RXL_EXCEPTION(MTUERROR, L3_EXCEPTIONS, + TRAP_TO_CPU), + }, + }, + { + .trap = MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS), + .listeners_arr = { + MLXSW_SP_RXL_EXCEPTION(TTLERROR, L3_EXCEPTIONS, + TRAP_TO_CPU), + }, + }, + { + .trap = MLXSW_SP_TRAP_EXCEPTION(RPF, L3_EXCEPTIONS), + .listeners_arr = { + MLXSW_SP_RXL_EXCEPTION(RPF, L3_EXCEPTIONS, TRAP_TO_CPU), + }, + }, + { + .trap = MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_EXCEPTIONS), + .listeners_arr = { + MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, L3_EXCEPTIONS, + TRAP_TO_CPU), + }, + }, + { + .trap = MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH, + L3_EXCEPTIONS), + .listeners_arr = { + MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, L3_EXCEPTIONS, + TRAP_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, L3_EXCEPTIONS, + TRAP_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER3, L3_EXCEPTIONS, + TRAP_EXCEPTION_TO_CPU), + }, + }, + { + .trap = MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS, + L3_EXCEPTIONS), + .listeners_arr = { + MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4, + L3_EXCEPTIONS, + TRAP_EXCEPTION_TO_CPU), + }, + }, + { + .trap = MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS, + L3_EXCEPTIONS), + .listeners_arr = { + MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6, + L3_EXCEPTIONS, + TRAP_EXCEPTION_TO_CPU), + }, + }, + { + .trap = MLXSW_SP_TRAP_DRIVER_DROP(IRIF_DISABLED, L3_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(ROUTER_IRIF_EN, L3_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DRIVER_DROP(ERIF_DISABLED, L3_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(ROUTER_ERIF_EN, L3_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(NON_ROUTABLE, L3_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(NON_ROUTABLE, L3_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_EXCEPTION(DECAP_ERROR, TUNNEL_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_EXCEPTION(DECAP_ECN0, TUNNEL_DISCARDS, + TRAP_EXCEPTION_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(IPIP_DECAP_ERROR, + TUNNEL_DISCARDS, + TRAP_EXCEPTION_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(DISCARD_DEC_PKT, TUNNEL_DISCARDS, + TRAP_EXCEPTION_TO_CPU), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP(OVERLAY_SMAC_MC, TUNNEL_DROPS), + .listeners_arr = { + MLXSW_SP_RXL_DISCARD(OVERLAY_SMAC_MC, TUNNEL_DISCARDS), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, + ACL_DROPS, + DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), + .listeners_arr = { + MLXSW_SP_RXL_ACL_DISCARD(INGRESS_ACL, ACL_DISCARDS, + DUMMY), + }, + }, + { + .trap = MLXSW_SP_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, + ACL_DROPS, + DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), + .listeners_arr = { + MLXSW_SP_RXL_ACL_DISCARD(EGRESS_ACL, ACL_DISCARDS, + DUMMY), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(STP, STP, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_NO_MARK(STP, STP, TRAP_TO_CPU, true), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(LACP, LACP, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_NO_MARK(LACP, LACP, TRAP_TO_CPU, true), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(LLDP, LLDP, TRAP), + .listeners_arr = { + MLXSW_RXL(mlxsw_sp_rx_ptp_listener, LLDP, TRAP_TO_CPU, + false, SP_LLDP, DISCARD), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IGMP_QUERY, MC_SNOOPING, + MIRROR_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING, + TRAP), + .listeners_arr = { + MLXSW_SP_RXL_NO_MARK(IGMP_V1_REPORT, MC_SNOOPING, + TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_REPORT, MC_SNOOPING, + TRAP), + .listeners_arr = { + MLXSW_SP_RXL_NO_MARK(IGMP_V2_REPORT, MC_SNOOPING, + TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V3_REPORT, MC_SNOOPING, + TRAP), + .listeners_arr = { + MLXSW_SP_RXL_NO_MARK(IGMP_V3_REPORT, MC_SNOOPING, + TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IGMP_V2_LEAVE, MC_SNOOPING, + TRAP), + .listeners_arr = { + MLXSW_SP_RXL_NO_MARK(IGMP_V2_LEAVE, MC_SNOOPING, + TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(MLD_QUERY, MC_SNOOPING, MIRROR), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV6_MLDV12_LISTENER_QUERY, + MC_SNOOPING, MIRROR_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_REPORT, MC_SNOOPING, + TRAP), + .listeners_arr = { + MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_REPORT, + MC_SNOOPING, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(MLD_V2_REPORT, MC_SNOOPING, + TRAP), + .listeners_arr = { + MLXSW_SP_RXL_NO_MARK(IPV6_MLDV2_LISTENER_REPORT, + MC_SNOOPING, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(MLD_V1_DONE, MC_SNOOPING, + TRAP), + .listeners_arr = { + MLXSW_SP_RXL_NO_MARK(IPV6_MLDV1_LISTENER_DONE, + MC_SNOOPING, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV4_DHCP, DHCP, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV4_DHCP, DHCP, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DHCP, DHCP, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV6_DHCP, DHCP, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(ARP_REQUEST, NEIGH_DISCOVERY, + MIRROR), + .listeners_arr = { + MLXSW_SP_RXL_MARK(ARPBC, NEIGH_DISCOVERY, MIRROR_TO_CPU, + false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY, + MIRROR), + .listeners_arr = { + MLXSW_SP_RXL_MARK(ARPUC, NEIGH_DISCOVERY, MIRROR_TO_CPU, + false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(ARP_OVERLAY, NEIGH_DISCOVERY, + TRAP), + .listeners_arr = { + MLXSW_SP_RXL_NO_MARK(NVE_DECAP_ARP, NEIGH_DISCOVERY, + TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_SOLICIT, + NEIGH_DISCOVERY, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_SOLICITATION, + NEIGH_DISCOVERY, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_NEIGH_ADVERT, + NEIGH_DISCOVERY, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(L3_IPV6_NEIGHBOR_ADVERTISEMENT, + NEIGH_DISCOVERY, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV4_BFD, BFD, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV4_BFD, BFD, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_BFD, BFD, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV6_BFD, BFD, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV4_OSPF, OSPF, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV4_OSPF, OSPF, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_OSPF, OSPF, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV6_OSPF, OSPF, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV4_BGP, BGP, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV4_BGP, BGP, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_BGP, BGP, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV6_BGP, BGP, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV4_VRRP, VRRP, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV4_VRRP, VRRP, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_VRRP, VRRP, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV6_VRRP, VRRP, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV4_PIM, PIM, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV4_PIM, PIM, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_PIM, PIM, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV6_PIM, PIM, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(UC_LB, UC_LB, MIRROR), + .listeners_arr = { + MLXSW_SP_RXL_L3_MARK(LBERROR, LBERROR, MIRROR_TO_CPU, + false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(LOCAL_ROUTE, LOCAL_DELIVERY, + TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IP2ME, IP2ME, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(EXTERNAL_ROUTE, LOCAL_DELIVERY, + TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(RTR_INGRESS0, IP2ME, TRAP_TO_CPU, + false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_UC_DIP_LINK_LOCAL_SCOPE, + LOCAL_DELIVERY, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV6_LINK_LOCAL_DEST, IP2ME, + TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV4_ROUTER_ALERT, LOCAL_DELIVERY, + TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV4, IP2ME, TRAP_TO_CPU, + false), + }, + }, + { + /* IPV6_ROUTER_ALERT is defined in uAPI as 22, but it is not + * used in this file, so undefine it. + */ + #undef IPV6_ROUTER_ALERT + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_ALERT, LOCAL_DELIVERY, + TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, IP2ME, TRAP_TO_CPU, + false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DIP_ALL_NODES, IPV6, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV6_ALL_NODES_LINK, IPV6, + TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_DIP_ALL_ROUTERS, IPV6, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(IPV6_ALL_ROUTERS_LINK, IPV6, + TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_SOLICIT, IPV6, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_SOLICITATION, IPV6, + TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_ROUTER_ADVERT, IPV6, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_ADVERTISEMENT, IPV6, + TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(IPV6_REDIRECT, IPV6, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_MARK(L3_IPV6_REDIRECTION, IPV6, + TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(PTP_EVENT, PTP_EVENT, TRAP), + .listeners_arr = { + MLXSW_RXL(mlxsw_sp_rx_ptp_listener, PTP0, TRAP_TO_CPU, + false, SP_PTP0, DISCARD), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(PTP_GENERAL, PTP_GENERAL, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_NO_MARK(PTP1, PTP1, TRAP_TO_CPU, false), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_SAMPLE, ACL_SAMPLE, + MIRROR), + .listeners_arr = { + MLXSW_RXL(mlxsw_sp_rx_sample_listener, PKT_SAMPLE, + MIRROR_TO_CPU, false, SP_PKT_SAMPLE, DISCARD), + }, + }, + { + .trap = MLXSW_SP_TRAP_CONTROL(FLOW_ACTION_TRAP, ACL_TRAP, TRAP), + .listeners_arr = { + MLXSW_SP_RXL_NO_MARK(ACL0, FLOW_LOGGING, TRAP_TO_CPU, + false), + }, + }, }; -static const struct mlxsw_listener mlxsw_sp_listeners_arr[] = { - MLXSW_SP_RXL_DISCARD(ING_PACKET_SMAC_MC, L2_DISCARDS), - MLXSW_SP_RXL_DISCARD(ING_SWITCH_VTAG_ALLOW, L2_DISCARDS), - MLXSW_SP_RXL_DISCARD(ING_SWITCH_VLAN, L2_DISCARDS), - MLXSW_SP_RXL_DISCARD(ING_SWITCH_STP, L2_DISCARDS), - MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS), - MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS), - MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS), - MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS), - MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET, L3_DISCARDS), - MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC, L3_DISCARDS), - MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS), - MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS), - MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS), - MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR, L3_DISCARDS), - MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC, L3_DISCARDS), - MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE, L3_DISCARDS), - MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DISCARDS), - MLXSW_SP_RXL_EXCEPTION(MTUERROR, L3_DISCARDS, TRAP_TO_CPU), - MLXSW_SP_RXL_EXCEPTION(TTLERROR, L3_DISCARDS, TRAP_TO_CPU), - MLXSW_SP_RXL_EXCEPTION(RPF, L3_DISCARDS, TRAP_TO_CPU), - MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, L3_DISCARDS, TRAP_TO_CPU), - MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, L3_DISCARDS, TRAP_TO_CPU), - MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, L3_DISCARDS, TRAP_TO_CPU), - MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER3, L3_DISCARDS, - TRAP_EXCEPTION_TO_CPU), - MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4, L3_DISCARDS, - TRAP_EXCEPTION_TO_CPU), - MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6, L3_DISCARDS, - TRAP_EXCEPTION_TO_CPU), - MLXSW_SP_RXL_DISCARD(ROUTER_IRIF_EN, L3_DISCARDS), - MLXSW_SP_RXL_DISCARD(ROUTER_ERIF_EN, L3_DISCARDS), - MLXSW_SP_RXL_DISCARD(NON_ROUTABLE, L3_DISCARDS), - MLXSW_SP_RXL_EXCEPTION(DECAP_ECN0, TUNNEL_DISCARDS, - TRAP_EXCEPTION_TO_CPU), - MLXSW_SP_RXL_EXCEPTION(IPIP_DECAP_ERROR, TUNNEL_DISCARDS, - TRAP_EXCEPTION_TO_CPU), - MLXSW_SP_RXL_EXCEPTION(DISCARD_DEC_PKT, TUNNEL_DISCARDS, - TRAP_EXCEPTION_TO_CPU), - MLXSW_SP_RXL_DISCARD(OVERLAY_SMAC_MC, TUNNEL_DISCARDS), - MLXSW_SP_RXL_ACL_DISCARD(INGRESS_ACL, ACL_DISCARDS, DUMMY), - MLXSW_SP_RXL_ACL_DISCARD(EGRESS_ACL, ACL_DISCARDS, DUMMY), -}; +static struct mlxsw_sp_trap_policer_item * +mlxsw_sp_trap_policer_item_lookup(struct mlxsw_sp *mlxsw_sp, u32 id) +{ + struct mlxsw_sp_trap *trap = mlxsw_sp->trap; + int i; -/* Mapping between hardware trap and devlink trap. Multiple hardware traps can - * be mapped to the same devlink trap. Order is according to - * 'mlxsw_sp_listeners_arr'. - */ -static const u16 mlxsw_sp_listener_devlink_map[] = { - DEVLINK_TRAP_GENERIC_ID_SMAC_MC, - DEVLINK_TRAP_GENERIC_ID_VLAN_TAG_MISMATCH, - DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER, - DEVLINK_TRAP_GENERIC_ID_INGRESS_STP_FILTER, - DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST, - DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST, - DEVLINK_TRAP_GENERIC_ID_PORT_LOOPBACK_FILTER, - DEVLINK_TRAP_GENERIC_ID_BLACKHOLE_ROUTE, - DEVLINK_TRAP_GENERIC_ID_NON_IP_PACKET, - DEVLINK_TRAP_GENERIC_ID_UC_DIP_MC_DMAC, - DEVLINK_TRAP_GENERIC_ID_DIP_LB, - DEVLINK_TRAP_GENERIC_ID_SIP_MC, - DEVLINK_TRAP_GENERIC_ID_SIP_LB, - DEVLINK_TRAP_GENERIC_ID_CORRUPTED_IP_HDR, - DEVLINK_TRAP_GENERIC_ID_IPV4_SIP_BC, - DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_RESERVED_SCOPE, - DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, - DEVLINK_TRAP_GENERIC_ID_MTU_ERROR, - DEVLINK_TRAP_GENERIC_ID_TTL_ERROR, - DEVLINK_TRAP_GENERIC_ID_RPF, - DEVLINK_TRAP_GENERIC_ID_REJECT_ROUTE, - DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH, - DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH, - DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH, - DEVLINK_TRAP_GENERIC_ID_IPV4_LPM_UNICAST_MISS, - DEVLINK_TRAP_GENERIC_ID_IPV6_LPM_UNICAST_MISS, - DEVLINK_MLXSW_TRAP_ID_IRIF_DISABLED, - DEVLINK_MLXSW_TRAP_ID_ERIF_DISABLED, - DEVLINK_TRAP_GENERIC_ID_NON_ROUTABLE, - DEVLINK_TRAP_GENERIC_ID_DECAP_ERROR, - DEVLINK_TRAP_GENERIC_ID_DECAP_ERROR, - DEVLINK_TRAP_GENERIC_ID_DECAP_ERROR, - DEVLINK_TRAP_GENERIC_ID_OVERLAY_SMAC_MC, - DEVLINK_TRAP_GENERIC_ID_INGRESS_FLOW_ACTION_DROP, - DEVLINK_TRAP_GENERIC_ID_EGRESS_FLOW_ACTION_DROP, -}; + for (i = 0; i < trap->policers_count; i++) { + if (trap->policer_items_arr[i].policer.id == id) + return &trap->policer_items_arr[i]; + } -#define MLXSW_SP_THIN_POLICER_ID (MLXSW_REG_HTGT_TRAP_GROUP_MAX + 1) + return NULL; +} -static struct mlxsw_sp_trap_policer_item * -mlxsw_sp_trap_policer_item_lookup(struct mlxsw_sp *mlxsw_sp, u32 id) +static struct mlxsw_sp_trap_group_item * +mlxsw_sp_trap_group_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id) +{ + struct mlxsw_sp_trap *trap = mlxsw_sp->trap; + int i; + + for (i = 0; i < trap->groups_count; i++) { + if (trap->group_items_arr[i].group.id == id) + return &trap->group_items_arr[i]; + } + + return NULL; +} + +static struct mlxsw_sp_trap_item * +mlxsw_sp_trap_item_lookup(struct mlxsw_sp *mlxsw_sp, u16 id) { - struct mlxsw_sp_trap_policer_item *policer_item; struct mlxsw_sp_trap *trap = mlxsw_sp->trap; + int i; - list_for_each_entry(policer_item, &trap->policer_item_list, list) { - if (policer_item->id == id) - return policer_item; + for (i = 0; i < trap->traps_count; i++) { + if (trap->trap_items_arr[i].trap.id == id) + return &trap->trap_items_arr[i]; } return NULL; @@ -326,14 +1026,21 @@ mlxsw_sp_trap_policer_item_lookup(struct mlxsw_sp *mlxsw_sp, u32 id) static int mlxsw_sp_trap_cpu_policers_set(struct mlxsw_sp *mlxsw_sp) { + struct mlxsw_sp_trap *trap = mlxsw_sp->trap; char qpcr_pl[MLXSW_REG_QPCR_LEN]; + u16 hw_id; /* The purpose of "thin" policer is to drop as many packets * as possible. The dummy group is using it. */ - __set_bit(MLXSW_SP_THIN_POLICER_ID, mlxsw_sp->trap->policers_usage); - mlxsw_reg_qpcr_pack(qpcr_pl, MLXSW_SP_THIN_POLICER_ID, - MLXSW_REG_QPCR_IR_UNITS_M, false, 1, 4); + hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers); + if (WARN_ON(hw_id == trap->max_policers)) + return -ENOBUFS; + + __set_bit(hw_id, trap->policers_usage); + trap->thin_policer_hw_id = hw_id; + mlxsw_reg_qpcr_pack(qpcr_pl, hw_id, MLXSW_REG_QPCR_IR_UNITS_M, + false, 1, 4); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); } @@ -342,82 +1049,214 @@ static int mlxsw_sp_trap_dummy_group_init(struct mlxsw_sp *mlxsw_sp) char htgt_pl[MLXSW_REG_HTGT_LEN]; mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_SP_DUMMY, - MLXSW_SP_THIN_POLICER_ID, 0, 1); + mlxsw_sp->trap->thin_policer_hw_id, 0, 1); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl); } -static int mlxsw_sp_trap_policers_init(struct mlxsw_sp *mlxsw_sp) +static int mlxsw_sp_trap_policer_items_arr_init(struct mlxsw_sp *mlxsw_sp) { - struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); + size_t elem_size = sizeof(struct mlxsw_sp_trap_policer_item); + u64 arr_size = ARRAY_SIZE(mlxsw_sp_trap_policer_items_arr); struct mlxsw_sp_trap *trap = mlxsw_sp->trap; u64 free_policers = 0; - u32 last_id = 0; - int err, i; + u32 last_id; + int i; for_each_clear_bit(i, trap->policers_usage, trap->max_policers) free_policers++; - if (ARRAY_SIZE(mlxsw_sp_trap_policers_arr) > free_policers) { + if (arr_size > free_policers) { dev_err(mlxsw_sp->bus_info->dev, "Exceeded number of supported packet trap policers\n"); return -ENOBUFS; } - trap->policers_arr = kcalloc(free_policers, - sizeof(struct devlink_trap_policer), - GFP_KERNEL); - if (!trap->policers_arr) + trap->policer_items_arr = kcalloc(free_policers, elem_size, GFP_KERNEL); + if (!trap->policer_items_arr) return -ENOMEM; trap->policers_count = free_policers; - for (i = 0; i < free_policers; i++) { - const struct devlink_trap_policer *policer; - - if (i < ARRAY_SIZE(mlxsw_sp_trap_policers_arr)) { - policer = &mlxsw_sp_trap_policers_arr[i]; - trap->policers_arr[i] = *policer; - last_id = policer->id; - } else { - /* Use parameters set for first policer and override - * relevant ones. - */ - policer = &mlxsw_sp_trap_policers_arr[0]; - trap->policers_arr[i] = *policer; - trap->policers_arr[i].id = ++last_id; - trap->policers_arr[i].init_rate = 1; - trap->policers_arr[i].init_burst = 16; - } + /* Initialize policer items array with pre-defined policers. */ + memcpy(trap->policer_items_arr, mlxsw_sp_trap_policer_items_arr, + elem_size * arr_size); + + /* Initialize policer items array with the rest of the available + * policers. + */ + last_id = mlxsw_sp_trap_policer_items_arr[arr_size - 1].policer.id; + for (i = arr_size; i < trap->policers_count; i++) { + const struct mlxsw_sp_trap_policer_item *policer_item; + + /* Use parameters set for first policer and override + * relevant ones. + */ + policer_item = &mlxsw_sp_trap_policer_items_arr[0]; + trap->policer_items_arr[i] = *policer_item; + trap->policer_items_arr[i].policer.id = ++last_id; + trap->policer_items_arr[i].policer.init_rate = 1; + trap->policer_items_arr[i].policer.init_burst = 16; } - INIT_LIST_HEAD(&trap->policer_item_list); + return 0; +} + +static void mlxsw_sp_trap_policer_items_arr_fini(struct mlxsw_sp *mlxsw_sp) +{ + kfree(mlxsw_sp->trap->policer_items_arr); +} + +static int mlxsw_sp_trap_policers_init(struct mlxsw_sp *mlxsw_sp) +{ + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); + const struct mlxsw_sp_trap_policer_item *policer_item; + struct mlxsw_sp_trap *trap = mlxsw_sp->trap; + int err, i; - err = devlink_trap_policers_register(devlink, trap->policers_arr, - trap->policers_count); + err = mlxsw_sp_trap_policer_items_arr_init(mlxsw_sp); if (err) - goto err_trap_policers_register; + return err; + + for (i = 0; i < trap->policers_count; i++) { + policer_item = &trap->policer_items_arr[i]; + err = devlink_trap_policers_register(devlink, + &policer_item->policer, 1); + if (err) + goto err_trap_policer_register; + } return 0; -err_trap_policers_register: - kfree(trap->policers_arr); +err_trap_policer_register: + for (i--; i >= 0; i--) { + policer_item = &trap->policer_items_arr[i]; + devlink_trap_policers_unregister(devlink, + &policer_item->policer, 1); + } + mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp); return err; } static void mlxsw_sp_trap_policers_fini(struct mlxsw_sp *mlxsw_sp) { struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); + const struct mlxsw_sp_trap_policer_item *policer_item; struct mlxsw_sp_trap *trap = mlxsw_sp->trap; + int i; - devlink_trap_policers_unregister(devlink, trap->policers_arr, - trap->policers_count); - WARN_ON(!list_empty(&trap->policer_item_list)); - kfree(trap->policers_arr); + for (i = trap->policers_count - 1; i >= 0; i--) { + policer_item = &trap->policer_items_arr[i]; + devlink_trap_policers_unregister(devlink, + &policer_item->policer, 1); + } + mlxsw_sp_trap_policer_items_arr_fini(mlxsw_sp); } -int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp) +static int mlxsw_sp_trap_groups_init(struct mlxsw_sp *mlxsw_sp) { - size_t groups_count = ARRAY_SIZE(mlxsw_sp_trap_groups_arr); struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); + const struct mlxsw_sp_trap_group_item *group_item; + struct mlxsw_sp_trap *trap = mlxsw_sp->trap; + int err, i; + + trap->group_items_arr = kmemdup(mlxsw_sp_trap_group_items_arr, + sizeof(mlxsw_sp_trap_group_items_arr), + GFP_KERNEL); + if (!trap->group_items_arr) + return -ENOMEM; + + trap->groups_count = ARRAY_SIZE(mlxsw_sp_trap_group_items_arr); + + for (i = 0; i < trap->groups_count; i++) { + group_item = &trap->group_items_arr[i]; + err = devlink_trap_groups_register(devlink, &group_item->group, + 1); + if (err) + goto err_trap_group_register; + } + + return 0; + +err_trap_group_register: + for (i--; i >= 0; i--) { + group_item = &trap->group_items_arr[i]; + devlink_trap_groups_unregister(devlink, &group_item->group, 1); + } + kfree(trap->group_items_arr); + return err; +} + +static void mlxsw_sp_trap_groups_fini(struct mlxsw_sp *mlxsw_sp) +{ + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); + struct mlxsw_sp_trap *trap = mlxsw_sp->trap; + int i; + + for (i = trap->groups_count - 1; i >= 0; i--) { + const struct mlxsw_sp_trap_group_item *group_item; + + group_item = &trap->group_items_arr[i]; + devlink_trap_groups_unregister(devlink, &group_item->group, 1); + } + kfree(trap->group_items_arr); +} + +static bool +mlxsw_sp_trap_listener_is_valid(const struct mlxsw_listener *listener) +{ + return listener->trap_id != 0; +} + +static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp) +{ + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); + struct mlxsw_sp_trap *trap = mlxsw_sp->trap; + const struct mlxsw_sp_trap_item *trap_item; + int err, i; + + trap->trap_items_arr = kmemdup(mlxsw_sp_trap_items_arr, + sizeof(mlxsw_sp_trap_items_arr), + GFP_KERNEL); + if (!trap->trap_items_arr) + return -ENOMEM; + + trap->traps_count = ARRAY_SIZE(mlxsw_sp_trap_items_arr); + + for (i = 0; i < trap->traps_count; i++) { + trap_item = &trap->trap_items_arr[i]; + err = devlink_traps_register(devlink, &trap_item->trap, 1, + mlxsw_sp); + if (err) + goto err_trap_register; + } + + return 0; + +err_trap_register: + for (i--; i >= 0; i--) { + trap_item = &trap->trap_items_arr[i]; + devlink_traps_unregister(devlink, &trap_item->trap, 1); + } + kfree(trap->trap_items_arr); + return err; +} + +static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) +{ + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); + struct mlxsw_sp_trap *trap = mlxsw_sp->trap; + int i; + + for (i = trap->traps_count - 1; i >= 0; i--) { + const struct mlxsw_sp_trap_item *trap_item; + + trap_item = &trap->trap_items_arr[i]; + devlink_traps_unregister(devlink, &trap_item->trap, 1); + } + kfree(trap->trap_items_arr); +} + +int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp) +{ int err; err = mlxsw_sp_trap_cpu_policers_set(mlxsw_sp); @@ -428,59 +1267,52 @@ int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp) if (err) return err; - if (WARN_ON(ARRAY_SIZE(mlxsw_sp_listener_devlink_map) != - ARRAY_SIZE(mlxsw_sp_listeners_arr))) - return -EINVAL; - err = mlxsw_sp_trap_policers_init(mlxsw_sp); if (err) return err; - err = devlink_trap_groups_register(devlink, mlxsw_sp_trap_groups_arr, - groups_count); + err = mlxsw_sp_trap_groups_init(mlxsw_sp); if (err) - goto err_trap_groups_register; + goto err_trap_groups_init; - err = devlink_traps_register(devlink, mlxsw_sp_traps_arr, - ARRAY_SIZE(mlxsw_sp_traps_arr), mlxsw_sp); + err = mlxsw_sp_traps_init(mlxsw_sp); if (err) - goto err_traps_register; + goto err_traps_init; return 0; -err_traps_register: - devlink_trap_groups_unregister(devlink, mlxsw_sp_trap_groups_arr, - groups_count); -err_trap_groups_register: +err_traps_init: + mlxsw_sp_trap_groups_fini(mlxsw_sp); +err_trap_groups_init: mlxsw_sp_trap_policers_fini(mlxsw_sp); return err; } void mlxsw_sp_devlink_traps_fini(struct mlxsw_sp *mlxsw_sp) { - size_t groups_count = ARRAY_SIZE(mlxsw_sp_trap_groups_arr); - struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); - - devlink_traps_unregister(devlink, mlxsw_sp_traps_arr, - ARRAY_SIZE(mlxsw_sp_traps_arr)); - devlink_trap_groups_unregister(devlink, mlxsw_sp_trap_groups_arr, - groups_count); + mlxsw_sp_traps_fini(mlxsw_sp); + mlxsw_sp_trap_groups_fini(mlxsw_sp); mlxsw_sp_trap_policers_fini(mlxsw_sp); } int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core, const struct devlink_trap *trap, void *trap_ctx) { + struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); + const struct mlxsw_sp_trap_item *trap_item; int i; - for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) { + trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); + if (WARN_ON(!trap_item)) + return -EINVAL; + + for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) { const struct mlxsw_listener *listener; int err; - if (mlxsw_sp_listener_devlink_map[i] != trap->id) + listener = &trap_item->listeners_arr[i]; + if (!mlxsw_sp_trap_listener_is_valid(listener)) continue; - listener = &mlxsw_sp_listeners_arr[i]; - err = mlxsw_core_trap_register(mlxsw_core, listener, trap_ctx); if (err) return err; @@ -492,15 +1324,20 @@ int mlxsw_sp_trap_init(struct mlxsw_core *mlxsw_core, void mlxsw_sp_trap_fini(struct mlxsw_core *mlxsw_core, const struct devlink_trap *trap, void *trap_ctx) { + struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); + const struct mlxsw_sp_trap_item *trap_item; int i; - for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) { + trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); + if (WARN_ON(!trap_item)) + return; + + for (i = MLXSW_SP_TRAP_LISTENERS_MAX - 1; i >= 0; i--) { const struct mlxsw_listener *listener; - if (mlxsw_sp_listener_devlink_map[i] != trap->id) + listener = &trap_item->listeners_arr[i]; + if (!mlxsw_sp_trap_listener_is_valid(listener)) continue; - listener = &mlxsw_sp_listeners_arr[i]; - mlxsw_core_trap_unregister(mlxsw_core, listener, trap_ctx); } } @@ -509,16 +1346,23 @@ int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core, const struct devlink_trap *trap, enum devlink_trap_action action) { + struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); + const struct mlxsw_sp_trap_item *trap_item; int i; - for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener_devlink_map); i++) { + trap_item = mlxsw_sp_trap_item_lookup(mlxsw_sp, trap->id); + if (WARN_ON(!trap_item)) + return -EINVAL; + + for (i = 0; i < MLXSW_SP_TRAP_LISTENERS_MAX; i++) { const struct mlxsw_listener *listener; bool enabled; int err; - if (mlxsw_sp_listener_devlink_map[i] != trap->id) + listener = &trap_item->listeners_arr[i]; + if (!mlxsw_sp_trap_listener_is_valid(listener)) continue; - listener = &mlxsw_sp_listeners_arr[i]; + switch (action) { case DEVLINK_TRAP_ACTION_DROP: enabled = false; @@ -544,33 +1388,12 @@ __mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, { struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); u16 hw_policer_id = MLXSW_REG_HTGT_INVALID_POLICER; + const struct mlxsw_sp_trap_group_item *group_item; char htgt_pl[MLXSW_REG_HTGT_LEN]; - u8 priority, tc, group_id; - - switch (group->id) { - case DEVLINK_TRAP_GROUP_GENERIC_ID_L2_DROPS: - group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS; - priority = 0; - tc = 1; - break; - case DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS: - group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS; - priority = 0; - tc = 1; - break; - case DEVLINK_TRAP_GROUP_GENERIC_ID_TUNNEL_DROPS: - group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_TUNNEL_DISCARDS; - priority = 0; - tc = 1; - break; - case DEVLINK_TRAP_GROUP_GENERIC_ID_ACL_DROPS: - group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_ACL_DISCARDS; - priority = 0; - tc = 1; - break; - default: + + group_item = mlxsw_sp_trap_group_item_lookup(mlxsw_sp, group->id); + if (WARN_ON(!group_item)) return -EINVAL; - } if (policer_id) { struct mlxsw_sp_trap_policer_item *policer_item; @@ -582,7 +1405,8 @@ __mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, hw_policer_id = policer_item->hw_id; } - mlxsw_reg_htgt_pack(htgt_pl, group_id, hw_policer_id, priority, tc); + mlxsw_reg_htgt_pack(htgt_pl, group_item->hw_group_id, hw_policer_id, + group_item->priority, group_item->priority); return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); } @@ -602,10 +1426,10 @@ int mlxsw_sp_trap_group_set(struct mlxsw_core *mlxsw_core, return __mlxsw_sp_trap_group_init(mlxsw_core, group, policer_id); } -static struct mlxsw_sp_trap_policer_item * -mlxsw_sp_trap_policer_item_init(struct mlxsw_sp *mlxsw_sp, u32 id) +static int +mlxsw_sp_trap_policer_item_init(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_trap_policer_item *policer_item) { - struct mlxsw_sp_trap_policer_item *policer_item; struct mlxsw_sp_trap *trap = mlxsw_sp->trap; u16 hw_id; @@ -615,27 +1439,19 @@ mlxsw_sp_trap_policer_item_init(struct mlxsw_sp *mlxsw_sp, u32 id) */ hw_id = find_first_zero_bit(trap->policers_usage, trap->max_policers); if (WARN_ON(hw_id == trap->max_policers)) - return ERR_PTR(-ENOBUFS); - - policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL); - if (!policer_item) - return ERR_PTR(-ENOMEM); + return -ENOBUFS; __set_bit(hw_id, trap->policers_usage); policer_item->hw_id = hw_id; - policer_item->id = id; - list_add_tail(&policer_item->list, &trap->policer_item_list); - return policer_item; + return 0; } static void mlxsw_sp_trap_policer_item_fini(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_trap_policer_item *policer_item) { - list_del(&policer_item->list); __clear_bit(policer_item->hw_id, mlxsw_sp->trap->policers_usage); - kfree(policer_item); } static int mlxsw_sp_trap_policer_bs(u64 burst, u8 *p_burst_size, @@ -678,9 +1494,13 @@ int mlxsw_sp_trap_policer_init(struct mlxsw_core *mlxsw_core, struct mlxsw_sp_trap_policer_item *policer_item; int err; - policer_item = mlxsw_sp_trap_policer_item_init(mlxsw_sp, policer->id); - if (IS_ERR(policer_item)) - return PTR_ERR(policer_item); + policer_item = mlxsw_sp_trap_policer_item_lookup(mlxsw_sp, policer->id); + if (WARN_ON(!policer_item)) + return -EINVAL; + + err = mlxsw_sp_trap_policer_item_init(mlxsw_sp, policer_item); + if (err) + return err; err = __mlxsw_sp_trap_policer_set(mlxsw_sp, policer_item->hw_id, policer->init_rate, |