diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index cec72d99d9c97d..5d3413636a6245 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -3190,10 +3190,10 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, goto err_lag_init; } - err = mlxsw_sp_fids_init(mlxsw_sp); + err = mlxsw_sp->fid_core_ops->init(mlxsw_sp); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n"); - goto err_fids_init; + goto err_fid_core_init; } err = mlxsw_sp_policers_init(mlxsw_sp); @@ -3379,8 +3379,8 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, err_traps_init: mlxsw_sp_policers_fini(mlxsw_sp); err_policers_init: - mlxsw_sp_fids_fini(mlxsw_sp); -err_fids_init: + mlxsw_sp->fid_core_ops->fini(mlxsw_sp); +err_fid_core_init: mlxsw_sp_lag_fini(mlxsw_sp); err_lag_init: mlxsw_sp_pgt_fini(mlxsw_sp); @@ -3416,7 +3416,7 @@ static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->router_ops = &mlxsw_sp1_router_ops; mlxsw_sp->listeners = mlxsw_sp1_listener; mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp1_listener); - mlxsw_sp->fid_family_arr = mlxsw_sp1_fid_family_arr; + mlxsw_sp->fid_core_ops = &mlxsw_sp1_fid_core_ops; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP1; mlxsw_sp->pgt_smpe_index_valid = true; @@ -3450,7 +3450,7 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->router_ops = &mlxsw_sp2_router_ops; mlxsw_sp->listeners = mlxsw_sp2_listener; mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener); - mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr; + mlxsw_sp->fid_core_ops = &mlxsw_sp2_fid_core_ops; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP2; mlxsw_sp->pgt_smpe_index_valid = false; @@ -3484,7 +3484,7 @@ static int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->router_ops = &mlxsw_sp2_router_ops; mlxsw_sp->listeners = mlxsw_sp2_listener; mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener); - mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr; + mlxsw_sp->fid_core_ops = &mlxsw_sp2_fid_core_ops; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3; mlxsw_sp->pgt_smpe_index_valid = false; @@ -3518,7 +3518,7 @@ static int mlxsw_sp4_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->router_ops = &mlxsw_sp2_router_ops; mlxsw_sp->listeners = mlxsw_sp2_listener; mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener); - mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr; + mlxsw_sp->fid_core_ops = &mlxsw_sp2_fid_core_ops; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP4; mlxsw_sp->pgt_smpe_index_valid = false; @@ -3552,7 +3552,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) mlxsw_sp_devlink_traps_fini(mlxsw_sp); mlxsw_sp_traps_fini(mlxsw_sp); mlxsw_sp_policers_fini(mlxsw_sp); - mlxsw_sp_fids_fini(mlxsw_sp); + mlxsw_sp->fid_core_ops->fini(mlxsw_sp); mlxsw_sp_lag_fini(mlxsw_sp); mlxsw_sp_pgt_fini(mlxsw_sp); mlxsw_sp_kvdl_fini(mlxsw_sp); @@ -3598,6 +3598,7 @@ static const struct mlxsw_config_profile mlxsw_sp2_config_profile = { .used_cqe_time_stamp_type = 1, .cqe_time_stamp_type = MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_UTC, .lag_mode_prefer_sw = true, + .flood_mode_prefer_cff = true, }; /* Reduce number of LAGs from full capacity (256) to the maximum supported LAGs @@ -3626,6 +3627,7 @@ static const struct mlxsw_config_profile mlxsw_sp4_config_profile = { .used_cqe_time_stamp_type = 1, .cqe_time_stamp_type = MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_UTC, .lag_mode_prefer_sw = true, + .flood_mode_prefer_cff = true, }; static void @@ -4515,6 +4517,10 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_port->lagged = 1; lag->ref_count++; + err = mlxsw_sp_fid_port_join_lag(mlxsw_sp_port); + if (err) + goto err_fid_port_join_lag; + /* Port is no longer usable as a router interface */ if (mlxsw_sp_port->default_vlan->fid) mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port->default_vlan); @@ -4534,6 +4540,8 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, err_replay: mlxsw_sp_router_port_leave_lag(mlxsw_sp_port, lag_dev); err_router_join: + mlxsw_sp_fid_port_leave_lag(mlxsw_sp_port); +err_fid_port_join_lag: lag->ref_count--; mlxsw_sp_port->lagged = 0; mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id, @@ -4569,6 +4577,8 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, */ mlxsw_sp_port_lag_uppers_cleanup(mlxsw_sp_port, lag_dev); + mlxsw_sp_fid_port_leave_lag(mlxsw_sp_port); + if (lag->ref_count == 1) mlxsw_sp_lag_destroy(mlxsw_sp, lag_id); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 800c461deefa4b..61612c41331023 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -205,7 +205,7 @@ struct mlxsw_sp { const struct mlxsw_sp_mall_ops *mall_ops; const struct mlxsw_sp_router_ops *router_ops; const struct mlxsw_listener *listeners; - const struct mlxsw_sp_fid_family **fid_family_arr; + const struct mlxsw_sp_fid_core_ops *fid_core_ops; size_t listeners_count; u32 lowest_shaper_bs; struct rhashtable ipv6_addr_ht; @@ -252,6 +252,11 @@ struct mlxsw_sp_ptp_ops { const struct mlxsw_tx_info *tx_info); }; +struct mlxsw_sp_fid_core_ops { + int (*init)(struct mlxsw_sp *mlxsw_sp); + void (*fini)(struct mlxsw_sp *mlxsw_sp); +}; + static inline struct mlxsw_sp_upper * mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id) { @@ -508,6 +513,8 @@ enum mlxsw_sp_flood_type { MLXSW_SP_FLOOD_TYPE_UC, MLXSW_SP_FLOOD_TYPE_BC, MLXSW_SP_FLOOD_TYPE_MC, + /* For RSP FIDs in CFF mode. */ + MLXSW_SP_FLOOD_TYPE_NOT_UC, }; int mlxsw_sp_port_get_stats_raw(struct net_device *dev, int grp, @@ -1321,11 +1328,11 @@ struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid); int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port); void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port); -int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp); -void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp); +int mlxsw_sp_fid_port_join_lag(const struct mlxsw_sp_port *mlxsw_sp_port); +void mlxsw_sp_fid_port_leave_lag(const struct mlxsw_sp_port *mlxsw_sp_port); -extern const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[]; -extern const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[]; +extern const struct mlxsw_sp_fid_core_ops mlxsw_sp1_fid_core_ops; +extern const struct mlxsw_sp_fid_core_ops mlxsw_sp2_fid_core_ops; /* spectrum_mr.c */ enum mlxsw_sp_mr_route_prio { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index aad4bb17dfb124..4011170862354d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -11,6 +11,7 @@ #include #include "spectrum.h" +#include "spectrum_router.h" #include "reg.h" struct mlxsw_sp_fid_family; @@ -71,12 +72,12 @@ static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = { struct mlxsw_sp_flood_table { enum mlxsw_sp_flood_type packet_type; - enum mlxsw_flood_table_type table_type; + enum mlxsw_flood_table_type table_type; /* For flood_mode!=CFF. */ int table_index; }; struct mlxsw_sp_fid_ops { - void (*setup)(struct mlxsw_sp_fid *fid, const void *arg); + int (*setup)(struct mlxsw_sp_fid *fid, const void *arg); int (*configure)(struct mlxsw_sp_fid *fid); void (*deconfigure)(struct mlxsw_sp_fid *fid); int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg, @@ -95,6 +96,33 @@ struct mlxsw_sp_fid_ops { const struct net_device *nve_dev); int (*vid_to_fid_rif_update)(const struct mlxsw_sp_fid *fid, const struct mlxsw_sp_rif *rif); + int (*flood_table_init)(struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_flood_table *flood_table); + int (*pgt_size)(const struct mlxsw_sp_fid_family *fid_family, + u16 *p_pgt_size); + u16 (*fid_mid)(const struct mlxsw_sp_fid *fid, + const struct mlxsw_sp_flood_table *flood_table); + void (*fid_pack)(char *sfmr_pl, const struct mlxsw_sp_fid *fid, + enum mlxsw_reg_sfmr_op op); + + /* These are specific to RFID families and we assume are only + * implemented by RFID families, if at all. + */ + int (*fid_port_init)(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_port *mlxsw_sp_port); + void (*fid_port_fini)(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_port *mlxsw_sp_port); +}; + +enum mlxsw_sp_fid_flood_profile_id { + MLXSW_SP_FID_FLOOD_PROFILE_ID_BRIDGE = 1, + MLXSW_SP_FID_FLOOD_PROFILE_ID_RSP, +}; + +struct mlxsw_sp_fid_flood_profile { + const struct mlxsw_sp_flood_table *flood_tables; + int nr_flood_tables; + const enum mlxsw_sp_fid_flood_profile_id profile_id; /* For CFF mode. */ }; struct mlxsw_sp_fid_family { @@ -104,12 +132,11 @@ struct mlxsw_sp_fid_family { u16 end_index; struct list_head fids_list; unsigned long *fids_bitmap; - const struct mlxsw_sp_flood_table *flood_tables; - int nr_flood_tables; + const struct mlxsw_sp_fid_flood_profile *flood_profile; enum mlxsw_sp_rif_type rif_type; const struct mlxsw_sp_fid_ops *ops; struct mlxsw_sp *mlxsw_sp; - bool flood_rsp; + bool flood_rsp; /* For flood_mode!=CFF. */ enum mlxsw_reg_bridge_type bridge_type; u16 pgt_base; bool smpe_index_valid; @@ -131,10 +158,20 @@ static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, }; +static const int mlxsw_sp_sfgc_not_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1, + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1, + [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1, + [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1, + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, +}; + static const int *mlxsw_sp_packet_type_sfgc_types[] = { [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types, [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types, [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types, + [MLXSW_SP_FLOOD_TYPE_NOT_UC] = mlxsw_sp_sfgc_not_uc_packet_types, }; struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp, @@ -305,10 +342,13 @@ mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid, struct mlxsw_sp_fid_family *fid_family = fid->fid_family; int i; - for (i = 0; i < fid_family->nr_flood_tables; i++) { - if (fid_family->flood_tables[i].packet_type != packet_type) + for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) { + const struct mlxsw_sp_flood_table *flood_table; + + flood_table = &fid_family->flood_profile->flood_tables[i]; + if (flood_table->packet_type != packet_type) continue; - return &fid_family->flood_tables[i]; + return flood_table; } return NULL; @@ -320,24 +360,62 @@ mlxsw_sp_fid_family_num_fids(const struct mlxsw_sp_fid_family *fid_family) return fid_family->end_index - fid_family->start_index + 1; } -static u16 -mlxsw_sp_fid_family_pgt_size(const struct mlxsw_sp_fid_family *fid_family) +static int +mlxsw_sp_fid_8021d_pgt_size(const struct mlxsw_sp_fid_family *fid_family, + u16 *p_pgt_size) { u16 num_fids = mlxsw_sp_fid_family_num_fids(fid_family); - return num_fids * fid_family->nr_flood_tables; + *p_pgt_size = num_fids * fid_family->flood_profile->nr_flood_tables; + return 0; +} + +static unsigned int mlxsw_sp_fid_rfid_port_offset_cff(unsigned int local_port) +{ + /* Port 0 is the CPU port. Since we never create RIFs based off that + * port, we don't need to count it. + */ + return WARN_ON_ONCE(!local_port) ? 0 : local_port - 1; +} + +static int +mlxsw_sp_fid_rfid_pgt_size_cff(const struct mlxsw_sp_fid_family *fid_family, + u16 *p_pgt_size) +{ + struct mlxsw_core *core = fid_family->mlxsw_sp->core; + unsigned int max_ports; + u16 pgt_size; + u16 max_lags; + int err; + + max_ports = mlxsw_core_max_ports(core); + + err = mlxsw_core_max_lag(core, &max_lags); + if (err) + return err; + + pgt_size = (mlxsw_sp_fid_rfid_port_offset_cff(max_ports) + max_lags) * + fid_family->flood_profile->nr_flood_tables; + *p_pgt_size = pgt_size; + return 0; } static u16 -mlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family *fid_family, - const struct mlxsw_sp_flood_table *flood_table, - u16 fid_offset) +mlxsw_sp_fid_pgt_base_ctl(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_flood_table *flood_table) { u16 num_fids; num_fids = mlxsw_sp_fid_family_num_fids(fid_family); - return fid_family->pgt_base + num_fids * flood_table->table_index + - fid_offset; + return fid_family->pgt_base + num_fids * flood_table->table_index; +} + +static u16 +mlxsw_sp_fid_fid_mid_ctl(const struct mlxsw_sp_fid *fid, + const struct mlxsw_sp_flood_table *flood_table) +{ + return mlxsw_sp_fid_pgt_base_ctl(fid->fid_family, flood_table) + + fid->fid_offset; } int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, @@ -348,15 +426,14 @@ int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, const struct mlxsw_sp_flood_table *flood_table; u16 mid_index; - if (WARN_ON(!fid_family->flood_tables)) + if (WARN_ON(!fid_family->flood_profile)) return -EINVAL; flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type); if (!flood_table) return -ESRCH; - mid_index = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, - fid->fid_offset); + mid_index = fid_family->ops->fid_mid(fid, flood_table); return mlxsw_sp_pgt_entry_port_set(fid_family->mlxsw_sp, mid_index, fid->fid_index, local_port, member); } @@ -410,12 +487,13 @@ u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid) return mlxsw_sp_fid_8021q_fid(fid)->vid; } -static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg) +static int mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg) { u16 vid = *(u16 *) arg; mlxsw_sp_fid_8021q_fid(fid)->vid = vid; fid->fid_offset = fid->fid_index - fid->fid_family->start_index; + return 0; } static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid) @@ -447,12 +525,51 @@ static void mlxsw_sp_fid_pack_ctl(char *sfmr_pl, fid->fid_family->bridge_type); } +static u16 +mlxsw_sp_fid_off_pgt_base_cff(const struct mlxsw_sp_fid_family *fid_family, + u16 fid_offset) +{ + return fid_family->pgt_base + + fid_offset * fid_family->flood_profile->nr_flood_tables; +} + +static u16 mlxsw_sp_fid_pgt_base_cff(const struct mlxsw_sp_fid *fid) +{ + return mlxsw_sp_fid_off_pgt_base_cff(fid->fid_family, fid->fid_offset); +} + +static void mlxsw_sp_fid_fid_pack_cff(char *sfmr_pl, + const struct mlxsw_sp_fid *fid, + enum mlxsw_reg_sfmr_op op) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + u16 pgt_base = mlxsw_sp_fid_pgt_base_cff(fid); + + mlxsw_sp_fid_pack(sfmr_pl, fid, op); + mlxsw_reg_sfmr_cff_mid_base_set(sfmr_pl, pgt_base); + mlxsw_reg_sfmr_cff_prf_id_set(sfmr_pl, + fid_family->flood_profile->profile_id); +} + +static u16 mlxsw_sp_fid_rfid_fid_offset_cff(struct mlxsw_sp *mlxsw_sp, + u16 port_lag_id, bool is_lag) +{ + u16 max_ports = mlxsw_core_max_ports(mlxsw_sp->core); + + if (is_lag) + return mlxsw_sp_fid_rfid_port_offset_cff(max_ports) + + port_lag_id; + else + return mlxsw_sp_fid_rfid_port_offset_cff(port_lag_id); +} + static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid) { struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; char sfmr_pl[MLXSW_REG_SFMR_LEN]; - mlxsw_sp_fid_pack_ctl(sfmr_pl, fid, mlxsw_sp_sfmr_op(valid)); + fid->fid_family->ops->fid_pack(sfmr_pl, fid, + mlxsw_sp_sfmr_op(valid)); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); } @@ -462,7 +579,9 @@ static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid, struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; char sfmr_pl[MLXSW_REG_SFMR_LEN]; - mlxsw_sp_fid_pack_ctl(sfmr_pl, fid, MLXSW_REG_SFMR_OP_CREATE_FID); + fid->fid_family->ops->fid_pack(sfmr_pl, fid, + MLXSW_REG_SFMR_OP_CREATE_FID); + mlxsw_reg_sfmr_vv_set(sfmr_pl, fid->vni_valid); mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(fid->vni)); mlxsw_reg_sfmr_vtfp_set(sfmr_pl, fid->nve_flood_index_valid); @@ -778,12 +897,13 @@ mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid) return container_of(fid, struct mlxsw_sp_fid_8021d, common); } -static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg) +static int mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg) { int br_ifindex = *(int *) arg; mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex; fid->fid_offset = fid->fid_index - fid->fid_family->start_index; + return 0; } static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid) @@ -1068,7 +1188,37 @@ mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid, return 0; } -static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { +static int +mlxsw_sp_fid_flood_table_init_ctl(struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_flood_table *flood_table) +{ + enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; + struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; + const int *sfgc_packet_types; + u16 mid_base; + int err, i; + + mid_base = mlxsw_sp_fid_pgt_base_ctl(fid_family, flood_table); + + sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; + for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { + char sfgc_pl[MLXSW_REG_SFGC_LEN]; + + if (!sfgc_packet_types[i]) + continue; + + mlxsw_reg_sfgc_pack(sfgc_pl, i, fid_family->bridge_type, + flood_table->table_type, 0, mid_base); + + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl); + if (err) + return err; + } + + return 0; +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_ctl = { .setup = mlxsw_sp_fid_8021d_setup, .configure = mlxsw_sp_fid_8021d_configure, .deconfigure = mlxsw_sp_fid_8021d_deconfigure, @@ -1082,6 +1232,36 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload, .vid_to_fid_rif_update = mlxsw_sp_fid_8021d_vid_to_fid_rif_update, + .flood_table_init = mlxsw_sp_fid_flood_table_init_ctl, + .pgt_size = mlxsw_sp_fid_8021d_pgt_size, + .fid_mid = mlxsw_sp_fid_fid_mid_ctl, + .fid_pack = mlxsw_sp_fid_pack_ctl, +}; + +static u16 +mlxsw_sp_fid_fid_mid_cff(const struct mlxsw_sp_fid *fid, + const struct mlxsw_sp_flood_table *flood_table) +{ + return mlxsw_sp_fid_pgt_base_cff(fid) + flood_table->table_index; +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_cff = { + .setup = mlxsw_sp_fid_8021d_setup, + .configure = mlxsw_sp_fid_8021d_configure, + .deconfigure = mlxsw_sp_fid_8021d_deconfigure, + .index_alloc = mlxsw_sp_fid_8021d_index_alloc, + .compare = mlxsw_sp_fid_8021d_compare, + .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap, + .vni_set = mlxsw_sp_fid_8021d_vni_set, + .vni_clear = mlxsw_sp_fid_8021d_vni_clear, + .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set, + .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, + .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload, + .vid_to_fid_rif_update = mlxsw_sp_fid_8021d_vid_to_fid_rif_update, + .pgt_size = mlxsw_sp_fid_8021d_pgt_size, + .fid_mid = mlxsw_sp_fid_fid_mid_cff, + .fid_pack = mlxsw_sp_fid_fid_pack_cff, }; #define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2) @@ -1105,6 +1285,31 @@ static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = { }, }; +static const +struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_8021d_flood_profile = { + .flood_tables = mlxsw_sp_fid_8021d_flood_tables, + .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), + .profile_id = MLXSW_SP_FID_FLOOD_PROFILE_ID_BRIDGE, +}; + +static const struct mlxsw_sp_flood_table mlxsw_sp_fid_rsp_flood_tables_cff[] = { + { + .packet_type = MLXSW_SP_FLOOD_TYPE_UC, + .table_index = 0, + }, + { + .packet_type = MLXSW_SP_FLOOD_TYPE_NOT_UC, + .table_index = 1, + }, +}; + +static const +struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_rsp_flood_profile_cff = { + .flood_tables = mlxsw_sp_fid_rsp_flood_tables_cff, + .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_rsp_flood_tables_cff), + .profile_id = MLXSW_SP_FID_FLOOD_PROFILE_ID_RSP, +}; + static bool mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg) { @@ -1120,9 +1325,35 @@ mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid, br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid)); } -static void mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid *fid, const void *arg) +static int mlxsw_sp_fid_rfid_setup_ctl(struct mlxsw_sp_fid *fid, + const void *arg) { + /* In controlled mode, the FW takes care of FID placement. */ fid->fid_offset = 0; + return 0; +} + +static int mlxsw_sp_fid_rfid_setup_cff(struct mlxsw_sp_fid *fid, + const void *arg) +{ + struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + u16 rif_index = *(const u16 *)arg; + struct mlxsw_sp_rif *rif; + bool is_lag; + u16 port; + int err; + + rif = mlxsw_sp_rif_by_index(mlxsw_sp, rif_index); + if (!rif) + return -ENOENT; + + err = mlxsw_sp_rif_subport_port(rif, &port, &is_lag); + if (err) + return err; + + fid->fid_offset = mlxsw_sp_fid_rfid_fid_offset_cff(mlxsw_sp, port, + is_lag); + return 0; } static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid) @@ -1248,8 +1479,8 @@ mlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid, return 0; } -static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = { - .setup = mlxsw_sp_fid_rfid_setup, +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops_ctl = { + .setup = mlxsw_sp_fid_rfid_setup_ctl, .configure = mlxsw_sp_fid_rfid_configure, .deconfigure = mlxsw_sp_fid_rfid_deconfigure, .index_alloc = mlxsw_sp_fid_rfid_index_alloc, @@ -1261,11 +1492,146 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = { .nve_flood_index_set = mlxsw_sp_fid_rfid_nve_flood_index_set, .nve_flood_index_clear = mlxsw_sp_fid_rfid_nve_flood_index_clear, .vid_to_fid_rif_update = mlxsw_sp_fid_rfid_vid_to_fid_rif_update, + .fid_pack = mlxsw_sp_fid_pack_ctl, +}; + +static int +mlxsw_sp_fid_rfid_port_add_cff(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_flood_table *flood_table, + u16 pgt_addr, u16 smpe, unsigned int local_port) +{ + int err; + + err = mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, + local_port, true); + if (err) + return err; + + if (flood_table->packet_type == MLXSW_SP_FLOOD_TYPE_NOT_UC) { + u16 router_port = mlxsw_sp_router_port(mlxsw_sp); + + err = mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, + router_port, true); + if (err) + goto err_entry_port_set; + } + + return 0; + +err_entry_port_set: + mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, local_port, + false); + return err; +} + +static void +mlxsw_sp_fid_rfid_port_del_cff(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_flood_table *flood_table, + u16 pgt_addr, u16 smpe, u16 local_port) +{ + if (flood_table->packet_type == MLXSW_SP_FLOOD_TYPE_NOT_UC) { + u16 router_port = mlxsw_sp_router_port(mlxsw_sp); + + mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, + router_port, false); + } + mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, local_port, + false); +} + +static int +mlxsw_sp_fid_rfid_port_memb_ft_cff(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_flood_table *flood_table, + const struct mlxsw_sp_port *mlxsw_sp_port, + bool member) +{ + struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; + u16 local_port = mlxsw_sp_port->local_port; + u16 fid_pgt_base; + u16 fid_offset; + u16 pgt_addr; + u16 smpe; + u16 port; + + /* In-PGT SMPE is only valid on Spectrum-1, CFF only on Spectrum>1. */ + smpe = 0; + + port = mlxsw_sp_port->lagged ? mlxsw_sp_port->lag_id : local_port; + fid_offset = mlxsw_sp_fid_rfid_fid_offset_cff(mlxsw_sp, port, + mlxsw_sp_port->lagged); + fid_pgt_base = mlxsw_sp_fid_off_pgt_base_cff(fid_family, fid_offset); + pgt_addr = fid_pgt_base + flood_table->table_index; + + if (member) + return mlxsw_sp_fid_rfid_port_add_cff(mlxsw_sp, flood_table, + pgt_addr, smpe, + local_port); + + mlxsw_sp_fid_rfid_port_del_cff(mlxsw_sp, flood_table, pgt_addr, smpe, + local_port); + return 0; +} + +static int +mlxsw_sp_fid_rfid_port_memb_cff(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_port *mlxsw_sp_port, + bool member) +{ + int i; + + for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) { + const struct mlxsw_sp_flood_table *flood_table = + &fid_family->flood_profile->flood_tables[i]; + int err; + + err = mlxsw_sp_fid_rfid_port_memb_ft_cff(fid_family, + flood_table, + mlxsw_sp_port, member); + if (err) + return err; + } + + return 0; +} + +static int +mlxsw_sp_fid_rfid_port_init_cff(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_port *mlxsw_sp_port) +{ + return mlxsw_sp_fid_rfid_port_memb_cff(fid_family, mlxsw_sp_port, true); +} + +static void +mlxsw_sp_fid_rfid_port_fini_cff(const struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_port *mlxsw_sp_port) +{ + mlxsw_sp_fid_rfid_port_memb_cff(fid_family, mlxsw_sp_port, false); +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops_cff = { + .setup = mlxsw_sp_fid_rfid_setup_cff, + .configure = mlxsw_sp_fid_rfid_configure, + .deconfigure = mlxsw_sp_fid_rfid_deconfigure, + .index_alloc = mlxsw_sp_fid_rfid_index_alloc, + .compare = mlxsw_sp_fid_rfid_compare, + .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap, + .vni_set = mlxsw_sp_fid_rfid_vni_set, + .vni_clear = mlxsw_sp_fid_rfid_vni_clear, + .nve_flood_index_set = mlxsw_sp_fid_rfid_nve_flood_index_set, + .nve_flood_index_clear = mlxsw_sp_fid_rfid_nve_flood_index_clear, + .vid_to_fid_rif_update = mlxsw_sp_fid_rfid_vid_to_fid_rif_update, + .pgt_size = mlxsw_sp_fid_rfid_pgt_size_cff, + .fid_port_init = mlxsw_sp_fid_rfid_port_init_cff, + .fid_port_fini = mlxsw_sp_fid_rfid_port_fini_cff, + .fid_mid = mlxsw_sp_fid_fid_mid_cff, + .fid_pack = mlxsw_sp_fid_fid_pack_cff, }; -static void mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg) +static int mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg) { fid->fid_offset = 0; + return 0; } static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid) @@ -1322,6 +1688,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = { .vni_clear = mlxsw_sp_fid_dummy_vni_clear, .nve_flood_index_set = mlxsw_sp_fid_dummy_nve_flood_index_set, .nve_flood_index_clear = mlxsw_sp_fid_dummy_nve_flood_index_clear, + .fid_pack = mlxsw_sp_fid_pack, }; static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid) @@ -1405,7 +1772,7 @@ mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid, __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false); } -static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = { +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_ctl = { .setup = mlxsw_sp_fid_8021q_setup, .configure = mlxsw_sp_fid_8021q_configure, .deconfigure = mlxsw_sp_fid_8021q_deconfigure, @@ -1419,6 +1786,29 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = { .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, .fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload, .vid_to_fid_rif_update = mlxsw_sp_fid_8021q_vid_to_fid_rif_update, + .flood_table_init = mlxsw_sp_fid_flood_table_init_ctl, + .pgt_size = mlxsw_sp_fid_8021d_pgt_size, + .fid_mid = mlxsw_sp_fid_fid_mid_ctl, + .fid_pack = mlxsw_sp_fid_pack_ctl, +}; + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_cff = { + .setup = mlxsw_sp_fid_8021q_setup, + .configure = mlxsw_sp_fid_8021q_configure, + .deconfigure = mlxsw_sp_fid_8021q_deconfigure, + .index_alloc = mlxsw_sp_fid_8021d_index_alloc, + .compare = mlxsw_sp_fid_8021q_compare, + .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap, + .vni_set = mlxsw_sp_fid_8021d_vni_set, + .vni_clear = mlxsw_sp_fid_8021d_vni_clear, + .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set, + .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, + .fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload, + .vid_to_fid_rif_update = mlxsw_sp_fid_8021q_vid_to_fid_rif_update, + .pgt_size = mlxsw_sp_fid_8021d_pgt_size, + .fid_mid = mlxsw_sp_fid_fid_mid_cff, + .fid_pack = mlxsw_sp_fid_fid_pack_cff, }; /* There are 4K-2 802.1Q FIDs */ @@ -1444,10 +1834,9 @@ static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021q_family = { .fid_size = sizeof(struct mlxsw_sp_fid_8021q), .start_index = MLXSW_SP_FID_8021Q_START, .end_index = MLXSW_SP_FID_8021Q_END, - .flood_tables = mlxsw_sp_fid_8021d_flood_tables, - .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), + .flood_profile = &mlxsw_sp_fid_8021d_flood_profile, .rif_type = MLXSW_SP_RIF_TYPE_VLAN, - .ops = &mlxsw_sp_fid_8021q_ops, + .ops = &mlxsw_sp_fid_8021q_ops_ctl, .flood_rsp = false, .bridge_type = MLXSW_REG_BRIDGE_TYPE_0, .smpe_index_valid = false, @@ -1458,10 +1847,9 @@ static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021d_family = { .fid_size = sizeof(struct mlxsw_sp_fid_8021d), .start_index = MLXSW_SP_FID_8021D_START, .end_index = MLXSW_SP_FID_8021D_END, - .flood_tables = mlxsw_sp_fid_8021d_flood_tables, - .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), + .flood_profile = &mlxsw_sp_fid_8021d_flood_profile, .rif_type = MLXSW_SP_RIF_TYPE_FID, - .ops = &mlxsw_sp_fid_8021d_ops, + .ops = &mlxsw_sp_fid_8021d_ops_ctl, .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, .smpe_index_valid = false, }; @@ -1475,47 +1863,45 @@ static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_dummy_family = { .smpe_index_valid = false, }; -static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = { +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family_ctl = { .type = MLXSW_SP_FID_TYPE_RFID, .fid_size = sizeof(struct mlxsw_sp_fid), .start_index = MLXSW_SP_RFID_START, .end_index = MLXSW_SP_RFID_END, .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT, - .ops = &mlxsw_sp_fid_rfid_ops, + .ops = &mlxsw_sp_fid_rfid_ops_ctl, .flood_rsp = true, .smpe_index_valid = false, }; -const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = { +static const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = { [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp1_fid_8021q_family, [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp1_fid_8021d_family, [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp1_fid_dummy_family, - [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family, + [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family_ctl, }; -static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family = { +static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family_ctl = { .type = MLXSW_SP_FID_TYPE_8021Q, .fid_size = sizeof(struct mlxsw_sp_fid_8021q), .start_index = MLXSW_SP_FID_8021Q_START, .end_index = MLXSW_SP_FID_8021Q_END, - .flood_tables = mlxsw_sp_fid_8021d_flood_tables, - .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), + .flood_profile = &mlxsw_sp_fid_8021d_flood_profile, .rif_type = MLXSW_SP_RIF_TYPE_VLAN, - .ops = &mlxsw_sp_fid_8021q_ops, + .ops = &mlxsw_sp_fid_8021q_ops_ctl, .flood_rsp = false, .bridge_type = MLXSW_REG_BRIDGE_TYPE_0, .smpe_index_valid = true, }; -static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family = { +static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family_ctl = { .type = MLXSW_SP_FID_TYPE_8021D, .fid_size = sizeof(struct mlxsw_sp_fid_8021d), .start_index = MLXSW_SP_FID_8021D_START, .end_index = MLXSW_SP_FID_8021D_END, - .flood_tables = mlxsw_sp_fid_8021d_flood_tables, - .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), + .flood_profile = &mlxsw_sp_fid_8021d_flood_profile, .rif_type = MLXSW_SP_RIF_TYPE_FID, - .ops = &mlxsw_sp_fid_8021d_ops, + .ops = &mlxsw_sp_fid_8021d_ops_ctl, .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, .smpe_index_valid = true, }; @@ -1529,11 +1915,51 @@ static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_dummy_family = { .smpe_index_valid = false, }; -const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[] = { - [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family, - [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family, +static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr_ctl[] = { + [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family_ctl, + [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family_ctl, + [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp2_fid_dummy_family, + [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family_ctl, +}; + +static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family_cff = { + .type = MLXSW_SP_FID_TYPE_8021Q, + .fid_size = sizeof(struct mlxsw_sp_fid_8021q), + .start_index = MLXSW_SP_FID_8021Q_START, + .end_index = MLXSW_SP_FID_8021Q_END, + .flood_profile = &mlxsw_sp_fid_8021d_flood_profile, + .rif_type = MLXSW_SP_RIF_TYPE_VLAN, + .ops = &mlxsw_sp_fid_8021q_ops_cff, + .smpe_index_valid = true, +}; + +static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family_cff = { + .type = MLXSW_SP_FID_TYPE_8021D, + .fid_size = sizeof(struct mlxsw_sp_fid_8021d), + .start_index = MLXSW_SP_FID_8021D_START, + .end_index = MLXSW_SP_FID_8021D_END, + .flood_profile = &mlxsw_sp_fid_8021d_flood_profile, + .rif_type = MLXSW_SP_RIF_TYPE_FID, + .ops = &mlxsw_sp_fid_8021d_ops_cff, + .smpe_index_valid = true, +}; + +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family_cff = { + .type = MLXSW_SP_FID_TYPE_RFID, + .fid_size = sizeof(struct mlxsw_sp_fid), + .start_index = MLXSW_SP_RFID_START, + .end_index = MLXSW_SP_RFID_END, + .flood_profile = &mlxsw_sp_fid_rsp_flood_profile_cff, + .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT, + .ops = &mlxsw_sp_fid_rfid_ops_cff, + .smpe_index_valid = false, +}; + +static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr_cff[] = { + [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family_cff, + [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family_cff, [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp2_fid_dummy_family, - [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family, + [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family_cff, }; static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp, @@ -1581,7 +2007,9 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, fid->fid_index = fid_index; __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap); - fid->fid_family->ops->setup(fid, arg); + err = fid->fid_family->ops->setup(fid, arg); + if (err) + goto err_setup; err = fid->fid_family->ops->configure(fid); if (err) @@ -1599,6 +2027,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, err_rhashtable_insert: fid->fid_family->ops->deconfigure(fid); err_configure: +err_setup: __clear_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap); err_index_alloc: @@ -1659,36 +2088,6 @@ struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp) return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL); } -static int -mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, - const struct mlxsw_sp_flood_table *flood_table) -{ - enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; - struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; - const int *sfgc_packet_types; - u16 mid_base; - int err, i; - - mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0); - - sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; - for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { - char sfgc_pl[MLXSW_REG_SFGC_LEN]; - - if (!sfgc_packet_types[i]) - continue; - - mlxsw_reg_sfgc_pack(sfgc_pl, i, fid_family->bridge_type, - flood_table->table_type, 0, mid_base); - - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl); - if (err) - return err; - } - - return 0; -} - static int mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) { @@ -1697,19 +2096,28 @@ mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) int err; int i; - pgt_size = mlxsw_sp_fid_family_pgt_size(fid_family); + err = fid_family->ops->pgt_size(fid_family, &pgt_size); + if (err) + return err; + err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, &fid_family->pgt_base, pgt_size); if (err) return err; - for (i = 0; i < fid_family->nr_flood_tables; i++) { + if (!fid_family->flood_profile) + return 0; + + for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) { const struct mlxsw_sp_flood_table *flood_table; - flood_table = &fid_family->flood_tables[i]; - err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table); - if (err) - goto err_flood_table_init; + flood_table = &fid_family->flood_profile->flood_tables[i]; + if (fid_family->ops->flood_table_init) { + err = fid_family->ops->flood_table_init(fid_family, + flood_table); + if (err) + goto err_flood_table_init; + } } return 0; @@ -1724,8 +2132,12 @@ mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family *fid_family) { struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; u16 pgt_size; + int err; + + err = fid_family->ops->pgt_size(fid_family, &pgt_size); + if (WARN_ON_ONCE(err)) + return; - pgt_size = mlxsw_sp_fid_family_pgt_size(fid_family); mlxsw_sp_pgt_mid_free_range(mlxsw_sp, fid_family->pgt_base, pgt_size); } @@ -1748,7 +2160,7 @@ static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp, goto err_alloc_fids_bitmap; } - if (fid_family->flood_tables) { + if (fid_family->flood_profile) { err = mlxsw_sp_fid_flood_tables_init(fid_family); if (err) goto err_fid_flood_tables_init; @@ -1771,7 +2183,7 @@ mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp, { mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL; - if (fid_family->flood_tables) + if (fid_family->flood_profile) mlxsw_sp_fid_flood_tables_fini(fid_family); bitmap_free(fid_family->fids_bitmap); @@ -1779,9 +2191,34 @@ mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp, kfree(fid_family); } +static int mlxsw_sp_fid_port_init(const struct mlxsw_sp_port *mlxsw_sp_port) +{ + const enum mlxsw_sp_fid_type type_rfid = MLXSW_SP_FID_TYPE_RFID; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_fid_family *rfid_family; + + rfid_family = mlxsw_sp->fid_core->fid_family_arr[type_rfid]; + if (rfid_family->ops->fid_port_init) + return rfid_family->ops->fid_port_init(rfid_family, + mlxsw_sp_port); + return 0; +} + +static void mlxsw_sp_fid_port_fini(const struct mlxsw_sp_port *mlxsw_sp_port) +{ + const enum mlxsw_sp_fid_type type_rfid = MLXSW_SP_FID_TYPE_RFID; + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_fid_family *rfid_family; + + rfid_family = mlxsw_sp->fid_core->fid_family_arr[type_rfid]; + if (rfid_family->ops->fid_port_fini) + rfid_family->ops->fid_port_fini(rfid_family, mlxsw_sp_port); +} + int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + int err; /* Track number of FIDs configured on the port with mapping type * PORT_VID_TO_FID, so that we know when to transition the port @@ -1789,17 +2226,42 @@ int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port) */ mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; - return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); + err = mlxsw_sp_fid_port_init(mlxsw_sp_port); + if (err) + return err; + + err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); + if (err) + goto err_vp_mode_set; + + return 0; + +err_vp_mode_set: + mlxsw_sp_fid_port_fini(mlxsw_sp_port); + return err; } void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + mlxsw_sp_fid_port_fini(mlxsw_sp_port); mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; } -int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp) +int mlxsw_sp_fid_port_join_lag(const struct mlxsw_sp_port *mlxsw_sp_port) +{ + return mlxsw_sp_fid_port_init(mlxsw_sp_port); +} + +void mlxsw_sp_fid_port_leave_lag(const struct mlxsw_sp_port *mlxsw_sp_port) +{ + mlxsw_sp_fid_port_fini(mlxsw_sp_port); +} + +static int +mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_fid_family *fid_family_arr[]) { unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); struct mlxsw_sp_fid_core *fid_core; @@ -1826,8 +2288,7 @@ int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp) } for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) { - err = mlxsw_sp_fid_family_register(mlxsw_sp, - mlxsw_sp->fid_family_arr[i]); + err = mlxsw_sp_fid_family_register(mlxsw_sp, fid_family_arr[i]); if (err) goto err_fid_ops_register; @@ -1852,7 +2313,7 @@ int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp) return err; } -void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp) +static void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp) { struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; int i; @@ -1865,3 +2326,142 @@ void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp) rhashtable_destroy(&fid_core->fid_ht); kfree(fid_core); } + +static int mlxsw_sp1_fids_init(struct mlxsw_sp *mlxsw_sp) +{ + return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp1_fid_family_arr); +} + +const struct mlxsw_sp_fid_core_ops mlxsw_sp1_fid_core_ops = { + .init = mlxsw_sp1_fids_init, + .fini = mlxsw_sp_fids_fini, +}; + +static int mlxsw_sp_fid_check_flood_profile_id(struct mlxsw_sp *mlxsw_sp, + int profile_id) +{ + u32 max_profiles; + + if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_NVE_FLOOD_PRF)) + return -EIO; + + max_profiles = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_NVE_FLOOD_PRF); + if (WARN_ON_ONCE(!profile_id) || + WARN_ON_ONCE(profile_id >= max_profiles)) + return -EINVAL; + + return 0; +} + +static int +mlxsw_sp2_fids_init_flood_table(struct mlxsw_sp *mlxsw_sp, + enum mlxsw_sp_fid_flood_profile_id profile_id, + const struct mlxsw_sp_flood_table *flood_table) +{ + enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; + const int *sfgc_packet_types; + int err; + int i; + + sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; + for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { + char sffp_pl[MLXSW_REG_SFFP_LEN]; + + if (!sfgc_packet_types[i]) + continue; + + mlxsw_reg_sffp_pack(sffp_pl, profile_id, i, + flood_table->table_index); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sffp), sffp_pl); + if (err) + return err; + } + + return 0; +} + +static int +mlxsw_sp2_fids_init_flood_profile(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_fid_flood_profile * + flood_profile) +{ + int err; + int i; + + err = mlxsw_sp_fid_check_flood_profile_id(mlxsw_sp, + flood_profile->profile_id); + if (err) + return err; + + for (i = 0; i < flood_profile->nr_flood_tables; i++) { + const struct mlxsw_sp_flood_table *flood_table; + + flood_table = &flood_profile->flood_tables[i]; + err = mlxsw_sp2_fids_init_flood_table(mlxsw_sp, + flood_profile->profile_id, + flood_table); + if (err) + return err; + } + + return 0; +} + +static const +struct mlxsw_sp_fid_flood_profile *mlxsw_sp_fid_flood_profiles[] = { + &mlxsw_sp_fid_8021d_flood_profile, + &mlxsw_sp_fid_rsp_flood_profile_cff, +}; + +static int +mlxsw_sp2_fids_init_flood_profiles(struct mlxsw_sp *mlxsw_sp) +{ + int err; + int i; + + for (i = 0; i < ARRAY_SIZE(mlxsw_sp_fid_flood_profiles); i++) { + const struct mlxsw_sp_fid_flood_profile *flood_profile; + + flood_profile = mlxsw_sp_fid_flood_profiles[i]; + err = mlxsw_sp2_fids_init_flood_profile(mlxsw_sp, + flood_profile); + if (err) + return err; + } + + return 0; +} + +static int mlxsw_sp2_fids_init_ctl(struct mlxsw_sp *mlxsw_sp) +{ + return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp2_fid_family_arr_ctl); +} + +static int mlxsw_sp2_fids_init_cff(struct mlxsw_sp *mlxsw_sp) +{ + int err; + + err = mlxsw_sp2_fids_init_flood_profiles(mlxsw_sp); + if (err) + return err; + + return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp2_fid_family_arr_cff); +} + +static int mlxsw_sp2_fids_init(struct mlxsw_sp *mlxsw_sp) +{ + switch (mlxsw_core_flood_mode(mlxsw_sp->core)) { + case MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED: + return mlxsw_sp2_fids_init_ctl(mlxsw_sp); + case MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CFF: + return mlxsw_sp2_fids_init_cff(mlxsw_sp); + default: + WARN_ON_ONCE(1); + return -EINVAL; + } +} + +const struct mlxsw_sp_fid_core_ops mlxsw_sp2_fid_core_ops = { + .init = mlxsw_sp2_fids_init, + .fini = mlxsw_sp_fids_fini, +};