diff options
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlxsw/spectrum.c')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 322 |
1 files changed, 192 insertions, 130 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index e0d7d5a..fece974 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2698,54 +2698,8 @@ static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg, } } -static struct mlxsw_event_listener mlxsw_sp_pude_event = { - .func = mlxsw_sp_pude_event_func, - .trap_id = MLXSW_TRAP_ID_PUDE, -}; - -static int mlxsw_sp_event_register(struct mlxsw_sp *mlxsw_sp, - enum mlxsw_event_trap_id trap_id) -{ - struct mlxsw_event_listener *el; - char hpkt_pl[MLXSW_REG_HPKT_LEN]; - int err; - - switch (trap_id) { - case MLXSW_TRAP_ID_PUDE: - el = &mlxsw_sp_pude_event; - break; - } - err = mlxsw_core_event_listener_register(mlxsw_sp->core, el, mlxsw_sp); - if (err) - return err; - - mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_FORWARD, trap_id); - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(hpkt), hpkt_pl); - if (err) - goto err_event_trap_set; - - return 0; - -err_event_trap_set: - mlxsw_core_event_listener_unregister(mlxsw_sp->core, el, mlxsw_sp); - return err; -} - -static void mlxsw_sp_event_unregister(struct mlxsw_sp *mlxsw_sp, - enum mlxsw_event_trap_id trap_id) -{ - struct mlxsw_event_listener *el; - - switch (trap_id) { - case MLXSW_TRAP_ID_PUDE: - el = &mlxsw_sp_pude_event; - break; - } - mlxsw_core_event_listener_unregister(mlxsw_sp->core, el, mlxsw_sp); -} - -static void mlxsw_sp_rx_listener_func(struct sk_buff *skb, u8 local_port, - void *priv) +static void mlxsw_sp_rx_listener_no_mark_func(struct sk_buff *skb, + u8 local_port, void *priv) { struct mlxsw_sp *mlxsw_sp = priv; struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port]; @@ -2773,107 +2727,212 @@ static void mlxsw_sp_rx_listener_mark_func(struct sk_buff *skb, u8 local_port, void *priv) { skb->offload_fwd_mark = 1; - return mlxsw_sp_rx_listener_func(skb, local_port, priv); + return mlxsw_sp_rx_listener_no_mark_func(skb, local_port, priv); +} + +#define MLXSW_SP_RXL_NO_MARK(_trap_id, _action, _trap_group, _is_ctrl) \ + MLXSW_RXL(mlxsw_sp_rx_listener_no_mark_func, _trap_id, _action, \ + _is_ctrl, SP_##_trap_group, DISCARD) + +#define MLXSW_SP_RXL_MARK(_trap_id, _action, _trap_group, _is_ctrl) \ + MLXSW_RXL(mlxsw_sp_rx_listener_mark_func, _trap_id, _action, \ + _is_ctrl, SP_##_trap_group, DISCARD) + +#define MLXSW_SP_EVENTL(_func, _trap_id) \ + MLXSW_EVENTL(_func, _trap_id, SP_EVENT) + +static const struct mlxsw_listener mlxsw_sp_listener[] = { + /* Events */ + MLXSW_SP_EVENTL(mlxsw_sp_pude_event_func, PUDE), + /* L2 traps */ + MLXSW_SP_RXL_NO_MARK(STP, TRAP_TO_CPU, STP, true), + MLXSW_SP_RXL_NO_MARK(LACP, TRAP_TO_CPU, LACP, true), + MLXSW_SP_RXL_NO_MARK(LLDP, TRAP_TO_CPU, LLDP, true), + MLXSW_SP_RXL_MARK(DHCP, MIRROR_TO_CPU, DHCP, false), + MLXSW_SP_RXL_MARK(IGMP_QUERY, MIRROR_TO_CPU, IGMP, false), + MLXSW_SP_RXL_NO_MARK(IGMP_V1_REPORT, TRAP_TO_CPU, IGMP, false), + MLXSW_SP_RXL_NO_MARK(IGMP_V2_REPORT, TRAP_TO_CPU, IGMP, false), + MLXSW_SP_RXL_NO_MARK(IGMP_V2_LEAVE, TRAP_TO_CPU, IGMP, false), + MLXSW_SP_RXL_NO_MARK(IGMP_V3_REPORT, TRAP_TO_CPU, IGMP, false), + MLXSW_SP_RXL_MARK(ARPBC, MIRROR_TO_CPU, ARP, false), + MLXSW_SP_RXL_MARK(ARPUC, MIRROR_TO_CPU, ARP, false), + /* L3 traps */ + MLXSW_SP_RXL_NO_MARK(MTUERROR, TRAP_TO_CPU, ROUTER_EXP, false), + MLXSW_SP_RXL_NO_MARK(TTLERROR, TRAP_TO_CPU, ROUTER_EXP, false), + MLXSW_SP_RXL_NO_MARK(LBERROR, TRAP_TO_CPU, ROUTER_EXP, false), + MLXSW_SP_RXL_MARK(OSPF, TRAP_TO_CPU, OSPF, false), + MLXSW_SP_RXL_NO_MARK(IP2ME, TRAP_TO_CPU, IP2ME, false), + MLXSW_SP_RXL_NO_MARK(RTR_INGRESS0, TRAP_TO_CPU, REMOTE_ROUTE, false), + MLXSW_SP_RXL_NO_MARK(HOST_MISS_IPV4, TRAP_TO_CPU, ARP_MISS, false), + MLXSW_SP_RXL_NO_MARK(BGP_IPV4, TRAP_TO_CPU, BGP_IPV4, false), +}; + +static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core) +{ + char qpcr_pl[MLXSW_REG_QPCR_LEN]; + enum mlxsw_reg_qpcr_ir_units ir_units; + int max_cpu_policers; + bool is_bytes; + u8 burst_size; + u32 rate; + int i, err; + + if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_CPU_POLICERS)) + return -EIO; + + max_cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS); + + ir_units = MLXSW_REG_QPCR_IR_UNITS_M; + for (i = 0; i < max_cpu_policers; i++) { + is_bytes = false; + switch (i) { + case MLXSW_REG_HTGT_TRAP_GROUP_SP_STP: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_LACP: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_OSPF: + rate = 128; + burst_size = 7; + break; + case MLXSW_REG_HTGT_TRAP_GROUP_SP_IGMP: + rate = 16 * 1024; + burst_size = 10; + break; + case MLXSW_REG_HTGT_TRAP_GROUP_SP_BGP_IPV4: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_ARP: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_DHCP: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_ARP_MISS: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_ROUTER_EXP: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_REMOTE_ROUTE: + rate = 1024; + burst_size = 7; + break; + case MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME: + is_bytes = true; + rate = 4 * 1024; + burst_size = 4; + break; + default: + continue; + } + + mlxsw_reg_qpcr_pack(qpcr_pl, i, ir_units, is_bytes, rate, + burst_size); + err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(qpcr), qpcr_pl); + if (err) + return err; + } + + return 0; } -#define MLXSW_SP_RXL(_func, _trap_id, _action) \ - { \ - .func = _func, \ - .local_port = MLXSW_PORT_DONT_CARE, \ - .trap_id = MLXSW_TRAP_ID_##_trap_id, \ - .action = MLXSW_REG_HPKT_ACTION_##_action, \ +static int mlxsw_sp_trap_groups_set(struct mlxsw_core *mlxsw_core) +{ + char htgt_pl[MLXSW_REG_HTGT_LEN]; + enum mlxsw_reg_htgt_trap_group i; + int max_cpu_policers; + int max_trap_groups; + u8 priority, tc; + u16 policer_id; + int err; + + if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_TRAP_GROUPS)) + return -EIO; + + max_trap_groups = MLXSW_CORE_RES_GET(mlxsw_core, MAX_TRAP_GROUPS); + max_cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS); + + for (i = 0; i < max_trap_groups; i++) { + policer_id = i; + switch (i) { + case MLXSW_REG_HTGT_TRAP_GROUP_SP_STP: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_LACP: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_OSPF: + priority = 5; + tc = 5; + break; + case MLXSW_REG_HTGT_TRAP_GROUP_SP_BGP_IPV4: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_DHCP: + priority = 4; + tc = 4; + break; + case MLXSW_REG_HTGT_TRAP_GROUP_SP_IGMP: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME: + priority = 3; + tc = 3; + break; + case MLXSW_REG_HTGT_TRAP_GROUP_SP_ARP: + priority = 2; + tc = 2; + break; + case MLXSW_REG_HTGT_TRAP_GROUP_SP_ARP_MISS: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_ROUTER_EXP: + case MLXSW_REG_HTGT_TRAP_GROUP_SP_REMOTE_ROUTE: + priority = 1; + tc = 1; + break; + case MLXSW_REG_HTGT_TRAP_GROUP_SP_EVENT: + priority = MLXSW_REG_HTGT_DEFAULT_PRIORITY; + tc = MLXSW_REG_HTGT_DEFAULT_TC; + policer_id = MLXSW_REG_HTGT_INVALID_POLICER; + break; + default: + continue; + } + + if (max_cpu_policers <= policer_id && + policer_id != MLXSW_REG_HTGT_INVALID_POLICER) + return -EIO; + + mlxsw_reg_htgt_pack(htgt_pl, i, policer_id, priority, tc); + err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); + if (err) + return err; } -static const struct mlxsw_rx_listener mlxsw_sp_rx_listener[] = { - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, FDB_MC, TRAP_TO_CPU), - /* Traps for specific L2 packet types, not trapped as FDB MC */ - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, STP, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, LACP, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, EAPOL, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, LLDP, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, MMRP, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, MVRP, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, RPVST, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_mark_func, DHCP, MIRROR_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_mark_func, IGMP_QUERY, MIRROR_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, IGMP_V1_REPORT, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, IGMP_V2_REPORT, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, IGMP_V2_LEAVE, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, IGMP_V3_REPORT, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_mark_func, ARPBC, MIRROR_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_mark_func, ARPUC, MIRROR_TO_CPU), - /* L3 traps */ - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, MTUERROR, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, TTLERROR, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, LBERROR, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_mark_func, OSPF, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, IP2ME, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, RTR_INGRESS0, TRAP_TO_CPU), - MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, HOST_MISS_IPV4, TRAP_TO_CPU), -}; + return 0; +} static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp) { - char htgt_pl[MLXSW_REG_HTGT_LEN]; - char hpkt_pl[MLXSW_REG_HPKT_LEN]; int i; int err; - mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_RX); - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl); + err = mlxsw_sp_cpu_policers_set(mlxsw_sp->core); if (err) return err; - mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_CTRL); - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(htgt), htgt_pl); + err = mlxsw_sp_trap_groups_set(mlxsw_sp->core); if (err) return err; - for (i = 0; i < ARRAY_SIZE(mlxsw_sp_rx_listener); i++) { - err = mlxsw_core_rx_listener_register(mlxsw_sp->core, - &mlxsw_sp_rx_listener[i], - mlxsw_sp); + for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener); i++) { + err = mlxsw_core_trap_register(mlxsw_sp->core, + &mlxsw_sp_listener[i], + mlxsw_sp); if (err) - goto err_rx_listener_register; + goto err_listener_register; - mlxsw_reg_hpkt_pack(hpkt_pl, mlxsw_sp_rx_listener[i].action, - mlxsw_sp_rx_listener[i].trap_id); - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(hpkt), hpkt_pl); - if (err) - goto err_rx_trap_set; } return 0; -err_rx_trap_set: - mlxsw_core_rx_listener_unregister(mlxsw_sp->core, - &mlxsw_sp_rx_listener[i], - mlxsw_sp); -err_rx_listener_register: +err_listener_register: for (i--; i >= 0; i--) { - mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_DISCARD, - mlxsw_sp_rx_listener[i].trap_id); - mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(hpkt), hpkt_pl); - - mlxsw_core_rx_listener_unregister(mlxsw_sp->core, - &mlxsw_sp_rx_listener[i], - mlxsw_sp); + mlxsw_core_trap_unregister(mlxsw_sp->core, + &mlxsw_sp_listener[i], + mlxsw_sp); } return err; } static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) { - char hpkt_pl[MLXSW_REG_HPKT_LEN]; int i; - for (i = 0; i < ARRAY_SIZE(mlxsw_sp_rx_listener); i++) { - mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_DISCARD, - mlxsw_sp_rx_listener[i].trap_id); - mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(hpkt), hpkt_pl); - - mlxsw_core_rx_listener_unregister(mlxsw_sp->core, - &mlxsw_sp_rx_listener[i], - mlxsw_sp); + for (i = 0; i < ARRAY_SIZE(mlxsw_sp_listener); i++) { + mlxsw_core_trap_unregister(mlxsw_sp->core, + &mlxsw_sp_listener[i], + mlxsw_sp); } } @@ -2958,6 +3017,17 @@ static void mlxsw_sp_lag_fini(struct mlxsw_sp *mlxsw_sp) kfree(mlxsw_sp->lags); } +static int mlxsw_sp_basic_trap_groups_set(struct mlxsw_core *mlxsw_core) +{ + char htgt_pl[MLXSW_REG_HTGT_LEN]; + + mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_EMAD, + MLXSW_REG_HTGT_INVALID_POLICER, + MLXSW_REG_HTGT_DEFAULT_PRIORITY, + MLXSW_REG_HTGT_DEFAULT_TC); + return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); +} + static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, const struct mlxsw_bus_info *mlxsw_bus_info) { @@ -2976,16 +3046,10 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, return err; } - err = mlxsw_sp_event_register(mlxsw_sp, MLXSW_TRAP_ID_PUDE); - if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Failed to register for PUDE events\n"); - return err; - } - err = mlxsw_sp_traps_init(mlxsw_sp); if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps for RX\n"); - goto err_rx_listener_register; + dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps\n"); + return err; } err = mlxsw_sp_flood_init(mlxsw_sp); @@ -3045,8 +3109,6 @@ err_lag_init: err_buffers_init: err_flood_init: mlxsw_sp_traps_fini(mlxsw_sp); -err_rx_listener_register: - mlxsw_sp_event_unregister(mlxsw_sp, MLXSW_TRAP_ID_PUDE); return err; } @@ -3061,7 +3123,6 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) mlxsw_sp_lag_fini(mlxsw_sp); mlxsw_sp_buffers_fini(mlxsw_sp); mlxsw_sp_traps_fini(mlxsw_sp); - mlxsw_sp_event_unregister(mlxsw_sp, MLXSW_TRAP_ID_PUDE); WARN_ON(!list_empty(&mlxsw_sp->vfids.list)); WARN_ON(!list_empty(&mlxsw_sp->fids)); } @@ -3103,6 +3164,7 @@ static struct mlxsw_driver mlxsw_sp_driver = { .priv_size = sizeof(struct mlxsw_sp), .init = mlxsw_sp_init, .fini = mlxsw_sp_fini, + .basic_trap_groups_set = mlxsw_sp_basic_trap_groups_set, .port_split = mlxsw_sp_port_split, .port_unsplit = mlxsw_sp_port_unsplit, .sb_pool_get = mlxsw_sp_sb_pool_get, |