From d6d9026668db8fd9f86b6121e9a7e147539ffaa2 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Mon, 27 Jun 2022 10:06:09 +0300 Subject: mlxsw: spectrum: Add a temporary variable to indicate bridge model As part of transition to unified bridge model, many different firmware configurations are done. Some of the configuration that needs to be done for the unified bridge model is not valid under the legacy model, and would be rejected by the firmware. At the same time, the driver cannot switch to the unified bridge model until all of the code has been converted. To allow breaking the change into patches, and to not break driver behavior during the transition, add a boolean variable to indicate bridge model. Then, forbidden configurations will be skipped using the check - "if (!mlxsw_sp->ubridge)". The new variable is temporary for several sets, it will be removed when firmware will be configured to work with unified bridge model. Signed-off-by: Amit Cohen Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 1 + drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index e58acd397edf..6b17fa9ab9c7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -3155,6 +3155,7 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, goto err_ports_create; } + mlxsw_sp->ubridge = false; return 0; err_ports_create: diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 80006a631333..828d5a265157 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -216,6 +216,7 @@ struct mlxsw_sp { u32 lowest_shaper_bs; struct rhashtable ipv6_addr_ht; struct mutex ipv6_addr_ht_lock; /* Protects ipv6_addr_ht */ + bool ubridge; }; struct mlxsw_sp_ptp_ops { -- cgit v1.2.3 From 93303ff828fd435afef3bf1991defb3e4ae26464 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Mon, 27 Jun 2022 10:06:10 +0300 Subject: mlxsw: spectrum_fid: Configure flooding table type for rFID Using unified bridge model, RITR register no longer configures the rFID used for sub-port RIFs. It needs to be created by software via SFMR. Such FIDs need to be created with a special flood indication using 'SFMR.flood_rsp=1'. It means that for such FIDs, router sub-port flooding table will be used, this table is configured by firmware. Set the above mentioned field as part of FID initialization and FID edition, so then when other fields will be updated in SFMR, this field will store the correct value and will not be overwritten. Add 'flood_rsp' variable to 'struct mlxsw_sp_fid_family', set it to true for rFID and to false for the rest. Signed-off-by: Amit Cohen Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 3 ++- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 7961f0c55fa6..80a02ba788bb 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -1960,7 +1960,7 @@ MLXSW_ITEM32(reg, sfmr, smpe, 0x28, 0, 16); static inline void mlxsw_reg_sfmr_pack(char *payload, enum mlxsw_reg_sfmr_op op, u16 fid, - u16 fid_offset) + u16 fid_offset, bool flood_rsp) { MLXSW_REG_ZERO(sfmr, payload); mlxsw_reg_sfmr_op_set(payload, op); @@ -1968,6 +1968,7 @@ static inline void mlxsw_reg_sfmr_pack(char *payload, mlxsw_reg_sfmr_fid_offset_set(payload, fid_offset); mlxsw_reg_sfmr_vtfp_set(payload, false); mlxsw_reg_sfmr_vv_set(payload, false); + mlxsw_reg_sfmr_flood_rsp_set(payload, flood_rsp); } /* SPVMLR - Switch Port VLAN MAC Learning Register diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index fb04fbec7c82..b67b51addb7d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -109,6 +109,7 @@ struct mlxsw_sp_fid_family { enum mlxsw_sp_rif_type rif_type; const struct mlxsw_sp_fid_ops *ops; struct mlxsw_sp *mlxsw_sp; + bool flood_rsp; }; static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { @@ -422,9 +423,13 @@ 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]; + bool flood_rsp = false; + + if (mlxsw_sp->ubridge) + flood_rsp = fid->fid_family->flood_rsp; mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid->fid_index, - fid->fid_offset); + fid->fid_offset, flood_rsp); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); } @@ -432,9 +437,13 @@ 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]; + bool flood_rsp = false; + + if (mlxsw_sp->ubridge) + flood_rsp = fid->fid_family->flood_rsp; mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, - fid->fid_index, fid->fid_offset); + fid->fid_index, fid->fid_offset, flood_rsp); 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); @@ -898,6 +907,7 @@ static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = { .end_index = MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1, .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT, .ops = &mlxsw_sp_fid_rfid_ops, + .flood_rsp = true, }; static void mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg) -- cgit v1.2.3 From fad8e1b6d52de875a63a64c465be7349958bb561 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Mon, 27 Jun 2022 10:06:11 +0300 Subject: mlxsw: Prepare 'bridge_type' field for SFMR usage Under the legacy bridge model, the field 'bridge_type' is used only in SFGC register, to determine the type of flood table (FID/FID offset). Under the unified bridge model, it will be used also in SFMR register. When a BUM packet needs to be flooded, SFGC is used to provide the 'mid_base' for PGT table. The access to SFGC is by {packet type, bridge type}. Under the unified bridge model, software is responsible for configuring 'bridge_type' as part of SFMR. As preparation for the new required configuration, rename 'enum mlxsw_reg_sfgc_bridge_type' to 'enum mlxsw_reg_bridge_type'. Then it can be used also in SFMR. In addition, align the names of the values to internal documentation. Signed-off-by: Amit Cohen Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 9 +++++---- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 80a02ba788bb..e198ee7365b5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -1054,9 +1054,10 @@ enum mlxsw_reg_sfgc_type { */ MLXSW_ITEM32(reg, sfgc, type, 0x00, 0, 4); -enum mlxsw_reg_sfgc_bridge_type { - MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID = 0, - MLXSW_REG_SFGC_BRIDGE_TYPE_VFID = 1, +/* bridge_type is used in SFGC and SFMR. */ +enum mlxsw_reg_bridge_type { + MLXSW_REG_BRIDGE_TYPE_0 = 0, /* Used for .1q FIDs. */ + MLXSW_REG_BRIDGE_TYPE_1 = 1, /* Used for .1d FIDs. */ }; /* reg_sfgc_bridge_type @@ -1111,7 +1112,7 @@ MLXSW_ITEM32(reg, sfgc, mid_base, 0x10, 0, 16); static inline void mlxsw_reg_sfgc_pack(char *payload, enum mlxsw_reg_sfgc_type type, - enum mlxsw_reg_sfgc_bridge_type bridge_type, + enum mlxsw_reg_bridge_type bridge_type, enum mlxsw_flood_table_type table_type, unsigned int flood_table) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index b67b51addb7d..ef4d8ddb2a12 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -71,7 +71,7 @@ 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_reg_sfgc_bridge_type bridge_type; + enum mlxsw_reg_bridge_type bridge_type; enum mlxsw_flood_table_type table_type; int table_index; }; @@ -709,19 +709,19 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = { { .packet_type = MLXSW_SP_FLOOD_TYPE_UC, - .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, + .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, .table_index = 0, }, { .packet_type = MLXSW_SP_FLOOD_TYPE_MC, - .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, + .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, .table_index = 1, }, { .packet_type = MLXSW_SP_FLOOD_TYPE_BC, - .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, + .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, .table_index = 2, }, -- cgit v1.2.3 From dd8c77d597086cb4aa4d5d0f9f61f98c491bb122 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Mon, 27 Jun 2022 10:06:12 +0300 Subject: mlxsw: spectrum_fid: Store 'bridge_type' as part of FID family Currently, 'bridge_type' is an attribute of 'struct mlxsw_sp_flood_table', which is defined per FID family. Instead, it can be an attribute of 'struct mlxsw_sp_fid_family' as all flood tables in the same family are of the same type. This change will ease the configuration of 'SFMR.flood_bridge_type' which will be added in the next patch. Signed-off-by: Amit Cohen Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index ef4d8ddb2a12..279e65a5fad2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -71,7 +71,6 @@ 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_reg_bridge_type bridge_type; enum mlxsw_flood_table_type table_type; int table_index; }; @@ -110,6 +109,7 @@ struct mlxsw_sp_fid_family { const struct mlxsw_sp_fid_ops *ops; struct mlxsw_sp *mlxsw_sp; bool flood_rsp; + enum mlxsw_reg_bridge_type bridge_type; }; static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { @@ -709,19 +709,16 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = { { .packet_type = MLXSW_SP_FLOOD_TYPE_UC, - .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, .table_index = 0, }, { .packet_type = MLXSW_SP_FLOOD_TYPE_MC, - .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, .table_index = 1, }, { .packet_type = MLXSW_SP_FLOOD_TYPE_BC, - .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, .table_index = 2, }, @@ -737,6 +734,7 @@ static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = { .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), .rif_type = MLXSW_SP_RIF_TYPE_FID, .ops = &mlxsw_sp_fid_8021d_ops, + .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, }; static bool @@ -785,6 +783,7 @@ static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_emu_family = { .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), .rif_type = MLXSW_SP_RIF_TYPE_VLAN_EMU, .ops = &mlxsw_sp_fid_8021q_emu_ops, + .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, }; static void mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid *fid, const void *arg) @@ -1132,7 +1131,7 @@ mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, if (!sfgc_packet_types[i]) continue; - mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type, + mlxsw_reg_sfgc_pack(sfgc_pl, i, fid_family->bridge_type, flood_table->table_type, flood_table->table_index); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl); -- cgit v1.2.3 From aa845e36a069a4cb7a7314d629bc415456e2df0a Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Mon, 27 Jun 2022 10:06:13 +0300 Subject: mlxsw: Set flood bridge type for FIDs In the unified bridge model, the bridge type FID attribute is no longer configured by the firmware, but instead by software when creating and editing a FID via SFMR register. Set this field as part of FID creation and edition flow. Default to 0 (reserved) as long as the driver operates in the legacy bridge model. Signed-off-by: Amit Cohen Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 4 +++- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 15 +++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index e198ee7365b5..d0ebb565b5cd 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -1961,7 +1961,8 @@ MLXSW_ITEM32(reg, sfmr, smpe, 0x28, 0, 16); static inline void mlxsw_reg_sfmr_pack(char *payload, enum mlxsw_reg_sfmr_op op, u16 fid, - u16 fid_offset, bool flood_rsp) + u16 fid_offset, bool flood_rsp, + enum mlxsw_reg_bridge_type bridge_type) { MLXSW_REG_ZERO(sfmr, payload); mlxsw_reg_sfmr_op_set(payload, op); @@ -1970,6 +1971,7 @@ static inline void mlxsw_reg_sfmr_pack(char *payload, mlxsw_reg_sfmr_vtfp_set(payload, false); mlxsw_reg_sfmr_vv_set(payload, false); mlxsw_reg_sfmr_flood_rsp_set(payload, flood_rsp); + mlxsw_reg_sfmr_flood_bridge_type_set(payload, bridge_type); } /* SPVMLR - Switch Port VLAN MAC Learning Register diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 279e65a5fad2..3335d744f870 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -422,28 +422,35 @@ static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid) static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid) { struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + enum mlxsw_reg_bridge_type bridge_type = 0; char sfmr_pl[MLXSW_REG_SFMR_LEN]; bool flood_rsp = false; - if (mlxsw_sp->ubridge) + if (mlxsw_sp->ubridge) { flood_rsp = fid->fid_family->flood_rsp; + bridge_type = fid->fid_family->bridge_type; + } mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid->fid_index, - fid->fid_offset, flood_rsp); + fid->fid_offset, flood_rsp, bridge_type); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); } static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid) { struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + enum mlxsw_reg_bridge_type bridge_type = 0; char sfmr_pl[MLXSW_REG_SFMR_LEN]; bool flood_rsp = false; - if (mlxsw_sp->ubridge) + if (mlxsw_sp->ubridge) { flood_rsp = fid->fid_family->flood_rsp; + bridge_type = fid->fid_family->bridge_type; + } mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, - fid->fid_index, fid->fid_offset, flood_rsp); + fid->fid_index, fid->fid_offset, flood_rsp, + bridge_type); 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); -- cgit v1.2.3 From 8c2da081c8b88216977a3305ce44351475d204ac Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Mon, 27 Jun 2022 10:06:14 +0300 Subject: mlxsw: spectrum_fid: Configure egress VID classification for multicast The device includes two main tables to support layer 2 multicast (i.e., MDB and flooding). These are the PGT (Port Group Table) table and the MPE (Multicast Port Egress) table. - PGT is {MID -> (bitmap of local_port, SPME index)} - MPE is {(Local port, SMPE index) -> eVID} In the legacy model, software did not interact with MPE table as it was completely hidden in firmware. In the new model, software needs to populate the table itself in order to map from {Local port, SMPE} to an egress VID. This is done using the SMPE register. Configure SMPE register when a {Local port, VID} are mapped/unmapped to a 802.1d and 802.1q emulated FIDs. The MPE table is not relevant for rFIDs as firmware handles their flooding. Signed-off-by: Amit Cohen Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 3335d744f870..a82612a894eb 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -622,6 +622,18 @@ mlxsw_sp_fid_port_vid_list_del(struct mlxsw_sp_fid *fid, u16 local_port, } } +static int +mlxsw_sp_fid_mpe_table_map(const struct mlxsw_sp_fid *fid, u16 local_port, + u16 vid, bool valid) +{ + struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + char smpe_pl[MLXSW_REG_SMPE_LEN]; + + mlxsw_reg_smpe_pack(smpe_pl, local_port, fid->fid_index, + valid ? vid : 0); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smpe), smpe_pl); +} + static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid, struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) @@ -635,6 +647,12 @@ static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid, if (err) return err; + if (fid->fid_family->mlxsw_sp->ubridge) { + err = mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, true); + if (err) + goto err_mpe_table_map; + } + err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port, vid); if (err) @@ -652,6 +670,9 @@ err_port_vp_mode_trans: mlxsw_sp->fid_core->port_fid_mappings[local_port]--; mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid); err_port_vid_list_add: + if (fid->fid_family->mlxsw_sp->ubridge) + mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, false); +err_mpe_table_map: __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false); return err; } @@ -667,6 +688,8 @@ mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid, mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); mlxsw_sp->fid_core->port_fid_mappings[local_port]--; mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid); + if (fid->fid_family->mlxsw_sp->ubridge) + mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, false); __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false); } -- cgit v1.2.3 From d8782ec59eb882b3be432a9a5288e81d4efe79dd Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Mon, 27 Jun 2022 10:06:15 +0300 Subject: mlxsw: Add an initial PGT table support The PGT (Port Group Table) table maps an index to a bitmap of local ports to which a packet needs to be replicated. This table is used for layer 2 multicast and flooding. In the legacy model, software did not interact with this table directly. Instead, it was accessed by firmware in response to registers such as SFTR and SMID. In the new model, the SFTR register is deprecated and software has full control over the PGT table using the SMID register. The entire state of the PGT table needs to be maintained in software because member ports in a PGT entry needs to be reference counted to avoid releasing entries which are still in use. Add the following APIs: 1. mlxsw_sp_pgt_{init, fini}() - allocate/free the PGT table. 2. mlxsw_sp_pgt_mid_alloc_range() - allocate a range of MID indexes in PGT. To be used by FID code during initialization to reserve specific PGT indexes for flooding entries. 3. mlxsw_sp_pgt_mid_free_range() - free indexes in a given range. 4. mlxsw_sp_pgt_mid_alloc() - allocate one MID index in the PGT at a non-specific range, just search for free index. To be used by MDB code. 5. mlxsw_sp_pgt_mid_free() - free the given index. Note that alloc() functions do not allocate the entries in software, just allocate IDs using 'idr'. Signed-off-by: Amit Cohen Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/Makefile | 3 +- drivers/net/ethernet/mellanox/mlxsw/resources.h | 2 + drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 12 +++ drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c | 120 +++++++++++++++++++++ 4 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile index c57e293cca25..c2d6d64ffe4b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Makefile +++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile @@ -28,7 +28,8 @@ mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \ spectrum_qdisc.o spectrum_span.o \ spectrum_nve.o spectrum_nve_vxlan.o \ spectrum_dpipe.o spectrum_trap.o \ - spectrum_ethtool.o spectrum_policer.o + spectrum_ethtool.o spectrum_policer.o \ + spectrum_pgt.o mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o mlxsw_spectrum-$(CONFIG_PTP_1588_CLOCK) += spectrum_ptp.o obj-$(CONFIG_MLXSW_MINIMAL) += mlxsw_minimal.o diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h index daacf6291253..826e47fb4586 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/resources.h +++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h @@ -11,6 +11,7 @@ enum mlxsw_res_id { MLXSW_RES_ID_KVD_SIZE, MLXSW_RES_ID_KVD_SINGLE_MIN_SIZE, MLXSW_RES_ID_KVD_DOUBLE_MIN_SIZE, + MLXSW_RES_ID_PGT_SIZE, MLXSW_RES_ID_MAX_KVD_LINEAR_RANGE, MLXSW_RES_ID_MAX_KVD_ACTION_SETS, MLXSW_RES_ID_MAX_TRAP_GROUPS, @@ -69,6 +70,7 @@ static u16 mlxsw_res_ids[] = { [MLXSW_RES_ID_KVD_SIZE] = 0x1001, [MLXSW_RES_ID_KVD_SINGLE_MIN_SIZE] = 0x1002, [MLXSW_RES_ID_KVD_DOUBLE_MIN_SIZE] = 0x1003, + [MLXSW_RES_ID_PGT_SIZE] = 0x1004, [MLXSW_RES_ID_MAX_KVD_LINEAR_RANGE] = 0x1005, [MLXSW_RES_ID_MAX_KVD_ACTION_SETS] = 0x1007, [MLXSW_RES_ID_MAX_TRAP_GROUPS] = 0x2201, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 828d5a265157..b42b23d09ab2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -143,6 +143,7 @@ struct mlxsw_sp_ptp_ops; struct mlxsw_sp_span_ops; struct mlxsw_sp_qdisc_state; struct mlxsw_sp_mall_entry; +struct mlxsw_sp_pgt; struct mlxsw_sp_port_mapping { u8 module; @@ -217,6 +218,7 @@ struct mlxsw_sp { struct rhashtable ipv6_addr_ht; struct mutex ipv6_addr_ht_lock; /* Protects ipv6_addr_ht */ bool ubridge; + struct mlxsw_sp_pgt *pgt; }; struct mlxsw_sp_ptp_ops { @@ -1448,4 +1450,14 @@ int mlxsw_sp_policers_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_policers_fini(struct mlxsw_sp *mlxsw_sp); int mlxsw_sp_policer_resources_register(struct mlxsw_core *mlxsw_core); +/* spectrum_pgt.c */ +int mlxsw_sp_pgt_mid_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_mid); +void mlxsw_sp_pgt_mid_free(struct mlxsw_sp *mlxsw_sp, u16 mid_base); +int mlxsw_sp_pgt_mid_alloc_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, + u16 count); +void mlxsw_sp_pgt_mid_free_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, + u16 count); +int mlxsw_sp_pgt_init(struct mlxsw_sp *mlxsw_sp); +void mlxsw_sp_pgt_fini(struct mlxsw_sp *mlxsw_sp); + #endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c new file mode 100644 index 000000000000..27db277bc906 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ + +#include +#include + +#include "spectrum.h" +#include "reg.h" + +struct mlxsw_sp_pgt { + struct idr pgt_idr; + u16 end_index; /* Exclusive. */ + struct mutex lock; /* Protects PGT. */ +}; + +int mlxsw_sp_pgt_mid_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_mid) +{ + int index, err = 0; + + mutex_lock(&mlxsw_sp->pgt->lock); + index = idr_alloc(&mlxsw_sp->pgt->pgt_idr, NULL, 0, + mlxsw_sp->pgt->end_index, GFP_KERNEL); + + if (index < 0) { + err = index; + goto err_idr_alloc; + } + + *p_mid = index; + mutex_unlock(&mlxsw_sp->pgt->lock); + return 0; + +err_idr_alloc: + mutex_unlock(&mlxsw_sp->pgt->lock); + return err; +} + +void mlxsw_sp_pgt_mid_free(struct mlxsw_sp *mlxsw_sp, u16 mid_base) +{ + mutex_lock(&mlxsw_sp->pgt->lock); + WARN_ON(idr_remove(&mlxsw_sp->pgt->pgt_idr, mid_base)); + mutex_unlock(&mlxsw_sp->pgt->lock); +} + +int +mlxsw_sp_pgt_mid_alloc_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, u16 count) +{ + unsigned int idr_cursor; + int i, err; + + mutex_lock(&mlxsw_sp->pgt->lock); + + /* This function is supposed to be called several times as part of + * driver init, in specific order. Verify that the mid_index is the + * first free index in the idr, to be able to free the indexes in case + * of error. + */ + idr_cursor = idr_get_cursor(&mlxsw_sp->pgt->pgt_idr); + if (WARN_ON(idr_cursor != mid_base)) { + err = -EINVAL; + goto err_idr_cursor; + } + + for (i = 0; i < count; i++) { + err = idr_alloc_cyclic(&mlxsw_sp->pgt->pgt_idr, NULL, + mid_base, mid_base + count, GFP_KERNEL); + if (err < 0) + goto err_idr_alloc_cyclic; + } + + mutex_unlock(&mlxsw_sp->pgt->lock); + return 0; + +err_idr_alloc_cyclic: + for (i--; i >= 0; i--) + idr_remove(&mlxsw_sp->pgt->pgt_idr, mid_base + i); +err_idr_cursor: + mutex_unlock(&mlxsw_sp->pgt->lock); + return err; +} + +void +mlxsw_sp_pgt_mid_free_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, u16 count) +{ + struct idr *pgt_idr = &mlxsw_sp->pgt->pgt_idr; + int i; + + mutex_lock(&mlxsw_sp->pgt->lock); + + for (i = 0; i < count; i++) + WARN_ON_ONCE(idr_remove(pgt_idr, mid_base + i)); + + mutex_unlock(&mlxsw_sp->pgt->lock); +} + +int mlxsw_sp_pgt_init(struct mlxsw_sp *mlxsw_sp) +{ + struct mlxsw_sp_pgt *pgt; + + if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, PGT_SIZE)) + return -EIO; + + pgt = kzalloc(sizeof(*mlxsw_sp->pgt), GFP_KERNEL); + if (!pgt) + return -ENOMEM; + + idr_init(&pgt->pgt_idr); + pgt->end_index = MLXSW_CORE_RES_GET(mlxsw_sp->core, PGT_SIZE); + mutex_init(&pgt->lock); + mlxsw_sp->pgt = pgt; + return 0; +} + +void mlxsw_sp_pgt_fini(struct mlxsw_sp *mlxsw_sp) +{ + mutex_destroy(&mlxsw_sp->pgt->lock); + WARN_ON(!idr_is_empty(&mlxsw_sp->pgt->pgt_idr)); + idr_destroy(&mlxsw_sp->pgt->pgt_idr); + kfree(mlxsw_sp->pgt); +} -- cgit v1.2.3 From a1697d11c945d7c3d46e22fca02299c9cb4b465f Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Mon, 27 Jun 2022 10:06:16 +0300 Subject: mlxsw: Add an indication of SMPE index validity for PGT table In Spectrum-1, the index into the MPE table - called switch multicast to port egress VID (SMPE) - is derived from the PGT entry, whereas in Spectrum-2 and later ASICs it is derived from the FID. Therefore, in Spectrum-1, the SMPE index needs to be programmed as part of the PGT entry via SMID register, while it is reserved for Spectrum-2 and later ASICs. Add 'pgt_smpe_index_valid' boolean as part of 'struct mlxsw_sp' and set it to true for Spectrum-1 and to false for the later ASICs. Add 'smpe_index_valid' as part of 'struct mlxsw_sp_pgt' and set it according to the value in 'struct mlxsw_sp' as part of PGT initialization. Signed-off-by: Amit Cohen Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 4 ++++ drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 + drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c | 2 ++ 3 files changed, 7 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 6b17fa9ab9c7..b128f900d0fe 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -3235,6 +3235,7 @@ static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp1_listener); mlxsw_sp->fid_family_arr = mlxsw_sp1_fid_family_arr; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP1; + mlxsw_sp->pgt_smpe_index_valid = true; return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); } @@ -3268,6 +3269,7 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener); mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP2; + mlxsw_sp->pgt_smpe_index_valid = false; return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); } @@ -3301,6 +3303,7 @@ static int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener); mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3; + mlxsw_sp->pgt_smpe_index_valid = false; return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); } @@ -3334,6 +3337,7 @@ static int mlxsw_sp4_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener); mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr; mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP4; + mlxsw_sp->pgt_smpe_index_valid = false; return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index b42b23d09ab2..600089364575 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -219,6 +219,7 @@ struct mlxsw_sp { struct mutex ipv6_addr_ht_lock; /* Protects ipv6_addr_ht */ bool ubridge; struct mlxsw_sp_pgt *pgt; + bool pgt_smpe_index_valid; }; struct mlxsw_sp_ptp_ops { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c index 27db277bc906..0fc29d486efc 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c @@ -11,6 +11,7 @@ struct mlxsw_sp_pgt { struct idr pgt_idr; u16 end_index; /* Exclusive. */ struct mutex lock; /* Protects PGT. */ + bool smpe_index_valid; }; int mlxsw_sp_pgt_mid_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_mid) @@ -107,6 +108,7 @@ int mlxsw_sp_pgt_init(struct mlxsw_sp *mlxsw_sp) idr_init(&pgt->pgt_idr); pgt->end_index = MLXSW_CORE_RES_GET(mlxsw_sp->core, PGT_SIZE); mutex_init(&pgt->lock); + pgt->smpe_index_valid = mlxsw_sp->pgt_smpe_index_valid; mlxsw_sp->pgt = pgt; return 0; } -- cgit v1.2.3 From d7a7b69787091b7ed78399dc40e8c6c9759b9b90 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Mon, 27 Jun 2022 10:06:17 +0300 Subject: mlxsw: Add a dedicated structure for bitmap of ports Currently when bitmap of ports is needed, 'unsigned long *' type is used. The functions which use the bitmap assume its length according to its name, i.e., each function which gets a bitmap of ports queries the maximum number of ports and uses it as the size. As preparation for the next patch which will use bitmap of ports, add a dedicated structure for it. Refactor the existing code to use the new structure. Signed-off-by: Amit Cohen Signed-off-by: Ido Schimmel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 25 +++++++++++++++ .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 37 +++++++++++----------- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 600089364575..645244ac5dfc 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -395,6 +395,31 @@ struct mlxsw_sp_port_type_speed_ops { u32 (*ptys_proto_cap_masked_get)(u32 eth_proto_cap); }; +struct mlxsw_sp_ports_bitmap { + unsigned long *bitmap; + unsigned int nbits; +}; + +static inline int +mlxsw_sp_port_bitmap_init(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_ports_bitmap *ports_bm) +{ + unsigned int nbits = mlxsw_core_max_ports(mlxsw_sp->core); + + ports_bm->nbits = nbits; + ports_bm->bitmap = bitmap_zalloc(nbits, GFP_KERNEL); + if (!ports_bm->bitmap) + return -ENOMEM; + + return 0; +} + +static inline void +mlxsw_sp_port_bitmap_fini(struct mlxsw_sp_ports_bitmap *ports_bm) +{ + bitmap_free(ports_bm->bitmap); +} + static inline u8 mlxsw_sp_tunnel_ecn_decap(u8 outer_ecn, u8 inner_ecn, bool *trap_en) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 863c8055746b..e153b6f2783a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -1646,9 +1646,10 @@ out: return err; } -static int mlxsw_sp_port_smid_full_entry(struct mlxsw_sp *mlxsw_sp, u16 mid_idx, - long *ports_bitmap, - bool set_router_port) +static int +mlxsw_sp_port_smid_full_entry(struct mlxsw_sp *mlxsw_sp, u16 mid_idx, + const struct mlxsw_sp_ports_bitmap *ports_bm, + bool set_router_port) { char *smid2_pl; int err, i; @@ -1666,7 +1667,7 @@ static int mlxsw_sp_port_smid_full_entry(struct mlxsw_sp *mlxsw_sp, u16 mid_idx, mlxsw_reg_smid2_port_mask_set(smid2_pl, mlxsw_sp_router_port(mlxsw_sp), 1); - for_each_set_bit(i, ports_bitmap, mlxsw_core_max_ports(mlxsw_sp->core)) + for_each_set_bit(i, ports_bm->bitmap, ports_bm->nbits) mlxsw_reg_smid2_port_set(smid2_pl, i, 1); mlxsw_reg_smid2_port_set(smid2_pl, mlxsw_sp_router_port(mlxsw_sp), @@ -1712,14 +1713,14 @@ mlxsw_sp_mid *__mlxsw_sp_mc_get(struct mlxsw_sp_bridge_device *bridge_device, static void mlxsw_sp_bridge_port_get_ports_bitmap(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_bridge_port *bridge_port, - unsigned long *ports_bitmap) + struct mlxsw_sp_ports_bitmap *ports_bm) { struct mlxsw_sp_port *mlxsw_sp_port; u64 max_lag_members, i; int lag_id; if (!bridge_port->lagged) { - set_bit(bridge_port->system_port, ports_bitmap); + set_bit(bridge_port->system_port, ports_bm->bitmap); } else { max_lag_members = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_LAG_MEMBERS); @@ -1729,13 +1730,13 @@ mlxsw_sp_bridge_port_get_ports_bitmap(struct mlxsw_sp *mlxsw_sp, lag_id, i); if (mlxsw_sp_port) set_bit(mlxsw_sp_port->local_port, - ports_bitmap); + ports_bm->bitmap); } } } static void -mlxsw_sp_mc_get_mrouters_bitmap(unsigned long *flood_bitmap, +mlxsw_sp_mc_get_mrouters_bitmap(struct mlxsw_sp_ports_bitmap *flood_bm, struct mlxsw_sp_bridge_device *bridge_device, struct mlxsw_sp *mlxsw_sp) { @@ -1745,7 +1746,7 @@ mlxsw_sp_mc_get_mrouters_bitmap(unsigned long *flood_bitmap, if (bridge_port->mrouter) { mlxsw_sp_bridge_port_get_ports_bitmap(mlxsw_sp, bridge_port, - flood_bitmap); + flood_bm); } } } @@ -1755,8 +1756,7 @@ mlxsw_sp_mc_write_mdb_entry(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_mid *mid, struct mlxsw_sp_bridge_device *bridge_device) { - long *flood_bitmap; - int num_of_ports; + struct mlxsw_sp_ports_bitmap flood_bitmap; u16 mid_idx; int err; @@ -1765,18 +1765,17 @@ mlxsw_sp_mc_write_mdb_entry(struct mlxsw_sp *mlxsw_sp, if (mid_idx == MLXSW_SP_MID_MAX) return -ENOBUFS; - num_of_ports = mlxsw_core_max_ports(mlxsw_sp->core); - flood_bitmap = bitmap_alloc(num_of_ports, GFP_KERNEL); - if (!flood_bitmap) - return -ENOMEM; + err = mlxsw_sp_port_bitmap_init(mlxsw_sp, &flood_bitmap); + if (err) + return err; - bitmap_copy(flood_bitmap, mid->ports_in_mid, num_of_ports); - mlxsw_sp_mc_get_mrouters_bitmap(flood_bitmap, bridge_device, mlxsw_sp); + bitmap_copy(flood_bitmap.bitmap, mid->ports_in_mid, flood_bitmap.nbits); + mlxsw_sp_mc_get_mrouters_bitmap(&flood_bitmap, bridge_device, mlxsw_sp); mid->mid = mid_idx; - err = mlxsw_sp_port_smid_full_entry(mlxsw_sp, mid_idx, flood_bitmap, + err = mlxsw_sp_port_smid_full_entry(mlxsw_sp, mid_idx, &flood_bitmap, bridge_device->mrouter); - bitmap_free(flood_bitmap); + mlxsw_sp_port_bitmap_fini(&flood_bitmap); if (err) return err; -- cgit v1.2.3 From a3a7992bc4e42633c34ab6a7623fd502e76146ed Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Mon, 27 Jun 2022 10:06:18 +0300 Subject: mlxsw: Extend PGT APIs to support maintaining list of ports per entry Add an API to associate a PGT entry with SMPE index and add or remove a port. This API will be used by FID code and MDB code, to add/remove port from specific PGT entry. When the first port is added to PGT entry, allocate the entry in the given MID index, when the last port is removed from PGT entry, free it. Signed-off-by: Amit Cohen Signed-off-by: Ido Schimmel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 2 + drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c | 229 +++++++++++++++++++++ 2 files changed, 231 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 645244ac5dfc..b128692611d9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -1483,6 +1483,8 @@ int mlxsw_sp_pgt_mid_alloc_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, u16 count); void mlxsw_sp_pgt_mid_free_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, u16 count); +int mlxsw_sp_pgt_entry_port_set(struct mlxsw_sp *mlxsw_sp, u16 mid, + u16 smpe, u16 local_port, bool member); int mlxsw_sp_pgt_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_pgt_fini(struct mlxsw_sp *mlxsw_sp); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c index 0fc29d486efc..3b7265b539b2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c @@ -14,6 +14,17 @@ struct mlxsw_sp_pgt { bool smpe_index_valid; }; +struct mlxsw_sp_pgt_entry { + struct list_head ports_list; + u16 index; + u16 smpe_index; +}; + +struct mlxsw_sp_pgt_entry_port { + struct list_head list; /* Member of 'ports_list'. */ + u16 local_port; +}; + int mlxsw_sp_pgt_mid_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_mid) { int index, err = 0; @@ -94,6 +105,224 @@ mlxsw_sp_pgt_mid_free_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, u16 count) mutex_unlock(&mlxsw_sp->pgt->lock); } +static struct mlxsw_sp_pgt_entry_port * +mlxsw_sp_pgt_entry_port_lookup(struct mlxsw_sp_pgt_entry *pgt_entry, + u16 local_port) +{ + struct mlxsw_sp_pgt_entry_port *pgt_entry_port; + + list_for_each_entry(pgt_entry_port, &pgt_entry->ports_list, list) { + if (pgt_entry_port->local_port == local_port) + return pgt_entry_port; + } + + return NULL; +} + +static struct mlxsw_sp_pgt_entry * +mlxsw_sp_pgt_entry_create(struct mlxsw_sp_pgt *pgt, u16 mid, u16 smpe) +{ + struct mlxsw_sp_pgt_entry *pgt_entry; + void *ret; + int err; + + pgt_entry = kzalloc(sizeof(*pgt_entry), GFP_KERNEL); + if (!pgt_entry) + return ERR_PTR(-ENOMEM); + + ret = idr_replace(&pgt->pgt_idr, pgt_entry, mid); + if (IS_ERR(ret)) { + err = PTR_ERR(ret); + goto err_idr_replace; + } + + INIT_LIST_HEAD(&pgt_entry->ports_list); + pgt_entry->index = mid; + pgt_entry->smpe_index = smpe; + return pgt_entry; + +err_idr_replace: + kfree(pgt_entry); + return ERR_PTR(err); +} + +static void mlxsw_sp_pgt_entry_destroy(struct mlxsw_sp_pgt *pgt, + struct mlxsw_sp_pgt_entry *pgt_entry) +{ + WARN_ON(!list_empty(&pgt_entry->ports_list)); + + pgt_entry = idr_replace(&pgt->pgt_idr, NULL, pgt_entry->index); + if (WARN_ON(IS_ERR(pgt_entry))) + return; + + kfree(pgt_entry); +} + +static struct mlxsw_sp_pgt_entry * +mlxsw_sp_pgt_entry_get(struct mlxsw_sp_pgt *pgt, u16 mid, u16 smpe) +{ + struct mlxsw_sp_pgt_entry *pgt_entry; + + pgt_entry = idr_find(&pgt->pgt_idr, mid); + if (pgt_entry) + return pgt_entry; + + return mlxsw_sp_pgt_entry_create(pgt, mid, smpe); +} + +static void mlxsw_sp_pgt_entry_put(struct mlxsw_sp_pgt *pgt, u16 mid) +{ + struct mlxsw_sp_pgt_entry *pgt_entry; + + pgt_entry = idr_find(&pgt->pgt_idr, mid); + if (WARN_ON(!pgt_entry)) + return; + + if (list_empty(&pgt_entry->ports_list)) + mlxsw_sp_pgt_entry_destroy(pgt, pgt_entry); +} + +static void mlxsw_sp_pgt_smid2_port_set(char *smid2_pl, u16 local_port, + bool member) +{ + mlxsw_reg_smid2_port_set(smid2_pl, local_port, member); + mlxsw_reg_smid2_port_mask_set(smid2_pl, local_port, 1); +} + +static int +mlxsw_sp_pgt_entry_port_write(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_pgt_entry *pgt_entry, + u16 local_port, bool member) +{ + bool smpe_index_valid; + char *smid2_pl; + u16 smpe; + int err; + + smid2_pl = kmalloc(MLXSW_REG_SMID2_LEN, GFP_KERNEL); + if (!smid2_pl) + return -ENOMEM; + + smpe_index_valid = mlxsw_sp->ubridge ? mlxsw_sp->pgt->smpe_index_valid : + false; + smpe = mlxsw_sp->ubridge ? pgt_entry->smpe_index : 0; + + mlxsw_reg_smid2_pack(smid2_pl, pgt_entry->index, 0, 0, smpe_index_valid, + smpe); + + mlxsw_sp_pgt_smid2_port_set(smid2_pl, local_port, member); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid2), smid2_pl); + + kfree(smid2_pl); + + return err; +} + +static struct mlxsw_sp_pgt_entry_port * +mlxsw_sp_pgt_entry_port_create(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_pgt_entry *pgt_entry, + u16 local_port) +{ + struct mlxsw_sp_pgt_entry_port *pgt_entry_port; + int err; + + pgt_entry_port = kzalloc(sizeof(*pgt_entry_port), GFP_KERNEL); + if (!pgt_entry_port) + return ERR_PTR(-ENOMEM); + + err = mlxsw_sp_pgt_entry_port_write(mlxsw_sp, pgt_entry, local_port, + true); + if (err) + goto err_pgt_entry_port_write; + + pgt_entry_port->local_port = local_port; + list_add(&pgt_entry_port->list, &pgt_entry->ports_list); + + return pgt_entry_port; + +err_pgt_entry_port_write: + kfree(pgt_entry_port); + return ERR_PTR(err); +} + +static void +mlxsw_sp_pgt_entry_port_destroy(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_pgt_entry *pgt_entry, + struct mlxsw_sp_pgt_entry_port *pgt_entry_port) + +{ + list_del(&pgt_entry_port->list); + mlxsw_sp_pgt_entry_port_write(mlxsw_sp, pgt_entry, + pgt_entry_port->local_port, false); + kfree(pgt_entry_port); +} + +static int mlxsw_sp_pgt_entry_port_add(struct mlxsw_sp *mlxsw_sp, u16 mid, + u16 smpe, u16 local_port) +{ + struct mlxsw_sp_pgt_entry_port *pgt_entry_port; + struct mlxsw_sp_pgt_entry *pgt_entry; + int err; + + mutex_lock(&mlxsw_sp->pgt->lock); + + pgt_entry = mlxsw_sp_pgt_entry_get(mlxsw_sp->pgt, mid, smpe); + if (IS_ERR(pgt_entry)) { + err = PTR_ERR(pgt_entry); + goto err_pgt_entry_get; + } + + pgt_entry_port = mlxsw_sp_pgt_entry_port_create(mlxsw_sp, pgt_entry, + local_port); + if (IS_ERR(pgt_entry_port)) { + err = PTR_ERR(pgt_entry_port); + goto err_pgt_entry_port_get; + } + + mutex_unlock(&mlxsw_sp->pgt->lock); + return 0; + +err_pgt_entry_port_get: + mlxsw_sp_pgt_entry_put(mlxsw_sp->pgt, mid); +err_pgt_entry_get: + mutex_unlock(&mlxsw_sp->pgt->lock); + return err; +} + +static void mlxsw_sp_pgt_entry_port_del(struct mlxsw_sp *mlxsw_sp, + u16 mid, u16 smpe, u16 local_port) +{ + struct mlxsw_sp_pgt_entry_port *pgt_entry_port; + struct mlxsw_sp_pgt_entry *pgt_entry; + + mutex_lock(&mlxsw_sp->pgt->lock); + + pgt_entry = idr_find(&mlxsw_sp->pgt->pgt_idr, mid); + if (!pgt_entry) + goto out; + + pgt_entry_port = mlxsw_sp_pgt_entry_port_lookup(pgt_entry, local_port); + if (!pgt_entry_port) + goto out; + + mlxsw_sp_pgt_entry_port_destroy(mlxsw_sp, pgt_entry, pgt_entry_port); + mlxsw_sp_pgt_entry_put(mlxsw_sp->pgt, mid); + +out: + mutex_unlock(&mlxsw_sp->pgt->lock); +} + +int mlxsw_sp_pgt_entry_port_set(struct mlxsw_sp *mlxsw_sp, u16 mid, + u16 smpe, u16 local_port, bool member) +{ + if (member) + return mlxsw_sp_pgt_entry_port_add(mlxsw_sp, mid, smpe, + local_port); + + mlxsw_sp_pgt_entry_port_del(mlxsw_sp, mid, smpe, local_port); + return 0; +} + int mlxsw_sp_pgt_init(struct mlxsw_sp *mlxsw_sp) { struct mlxsw_sp_pgt *pgt; -- cgit v1.2.3 From bb1bba35f50a4cae858ff4891f4c6698cf5b50b0 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Mon, 27 Jun 2022 10:06:19 +0300 Subject: mlxsw: spectrum: Initialize PGT table Initialize PGT table as part of mlxsw_sp_init(). This table will be used first in the next patch by FID code to set flooding entries, and later by MDB code to add multicast entries. Signed-off-by: Amit Cohen Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index b128f900d0fe..ff94cd9d872f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -3010,6 +3010,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, return err; } + err = mlxsw_sp_pgt_init(mlxsw_sp); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize PGT\n"); + goto err_pgt_init; + } + err = mlxsw_sp_fids_init(mlxsw_sp); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n"); @@ -3202,6 +3208,8 @@ err_traps_init: err_policers_init: mlxsw_sp_fids_fini(mlxsw_sp); err_fids_init: + mlxsw_sp_pgt_fini(mlxsw_sp); +err_pgt_init: mlxsw_sp_kvdl_fini(mlxsw_sp); mlxsw_sp_parsing_fini(mlxsw_sp); return err; @@ -3370,6 +3378,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) mlxsw_sp_traps_fini(mlxsw_sp); mlxsw_sp_policers_fini(mlxsw_sp); mlxsw_sp_fids_fini(mlxsw_sp); + mlxsw_sp_pgt_fini(mlxsw_sp); mlxsw_sp_kvdl_fini(mlxsw_sp); mlxsw_sp_parsing_fini(mlxsw_sp); } -- cgit v1.2.3 From 9f6f467a3cdb1cfcca570af0c8901479b090cb35 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Mon, 27 Jun 2022 10:06:20 +0300 Subject: mlxsw: spectrum_fid: Set 'mid_base' as part of flood tables initialization The PGT (Port Group Table) table maps an index to a bitmap of local ports to which a packet needs to be replicated. This table is used for layer 2 multicast and flooding. The index to PGT table which is called 'mid_index', is a result of 'mid_base' + 'fid_offset'. Using the legacy bridge model, firmware configures 'mid_base'. However, using the new model, software is responsible to configure it via SFGC register. The first 15K entries will be used for flooding and the rest for multicast. The table will look as follows: +----------------------------+ | | | 802.1q, unicast flooding | 4K entries | | +----------------------------+ | | | 802.1q, multicast flooding | 4K entries | | +----------------------------+ | | | 802.1q, broadcast flooding | 4K entries | | +----------------------------+ | 802.1d, unicast flooding | 1K entries +----------------------------+ | 802.1d, multicast flooding | 1K entries +----------------------------+ | 802.1d, broadcast flooding | 1K entries +----------------------------+ | | | | | Multicast entries | The rest of the table | | | | +----------------------------+ Add 'pgt_base' to 'struct mlxsw_sp_fid_family' and use it to calculate MID base, set 'SFGC.mid_base' as part of flood tables initialization. Signed-off-by: Amit Cohen Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 3 +- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 33 ++++++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index d0ebb565b5cd..022b2168f3a5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -1114,13 +1114,14 @@ static inline void mlxsw_reg_sfgc_pack(char *payload, enum mlxsw_reg_sfgc_type type, enum mlxsw_reg_bridge_type bridge_type, enum mlxsw_flood_table_type table_type, - unsigned int flood_table) + unsigned int flood_table, u16 mid_base) { MLXSW_REG_ZERO(sfgc, payload); mlxsw_reg_sfgc_type_set(payload, type); mlxsw_reg_sfgc_bridge_type_set(payload, bridge_type); mlxsw_reg_sfgc_table_type_set(payload, table_type); mlxsw_reg_sfgc_flood_table_set(payload, flood_table); + mlxsw_reg_sfgc_mid_base_set(payload, mid_base); } /* SFDF - Switch Filtering DB Flush diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index a82612a894eb..d168e9f5c62d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -110,6 +110,7 @@ struct mlxsw_sp_fid_family { struct mlxsw_sp *mlxsw_sp; bool flood_rsp; enum mlxsw_reg_bridge_type bridge_type; + u16 pgt_base; }; static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { @@ -321,6 +322,18 @@ mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid, return NULL; } +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) +{ + u16 num_fids; + + num_fids = fid_family->end_index - fid_family->start_index + 1; + return fid_family->pgt_base + num_fids * flood_table->table_index + + fid_offset; +} + int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_flood_type packet_type, u16 local_port, bool member) @@ -736,6 +749,10 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload, }; +#define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2) +#define MLXSW_SP_FID_8021Q_PGT_BASE 0 +#define MLXSW_SP_FID_8021D_PGT_BASE (3 * MLXSW_SP_FID_8021Q_MAX) + static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = { { .packet_type = MLXSW_SP_FLOOD_TYPE_UC, @@ -765,6 +782,7 @@ static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = { .rif_type = MLXSW_SP_RIF_TYPE_FID, .ops = &mlxsw_sp_fid_8021d_ops, .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, + .pgt_base = MLXSW_SP_FID_8021D_PGT_BASE, }; static bool @@ -801,7 +819,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_emu_ops = { /* There are 4K-2 emulated 802.1Q FIDs, starting right after the 802.1D FIDs */ #define MLXSW_SP_FID_8021Q_EMU_START (VLAN_N_VID + MLXSW_SP_FID_8021D_MAX) #define MLXSW_SP_FID_8021Q_EMU_END (MLXSW_SP_FID_8021Q_EMU_START + \ - VLAN_VID_MASK - 2) + MLXSW_SP_FID_8021Q_MAX - 1) /* Range and flood configuration must match mlxsw_config_profile */ static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_emu_family = { @@ -814,6 +832,7 @@ static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_emu_family = { .rif_type = MLXSW_SP_RIF_TYPE_VLAN_EMU, .ops = &mlxsw_sp_fid_8021q_emu_ops, .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, + .pgt_base = MLXSW_SP_FID_8021Q_PGT_BASE, }; static void mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid *fid, const void *arg) @@ -1151,8 +1170,11 @@ mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, { enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; const int *sfgc_packet_types; + u16 mid_base, table_index; int 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++) { struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; @@ -1161,9 +1183,14 @@ mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, if (!sfgc_packet_types[i]) continue; + + mid_base = mlxsw_sp->ubridge ? mid_base : 0; + table_index = mlxsw_sp->ubridge ? 0 : flood_table->table_index; + mlxsw_reg_sfgc_pack(sfgc_pl, i, fid_family->bridge_type, - flood_table->table_type, - flood_table->table_index); + flood_table->table_type, table_index, + mid_base); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl); if (err) return err; -- cgit v1.2.3 From fe94df6dc6225e034cca71a917c2fa3302e7b2c8 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Mon, 27 Jun 2022 10:06:21 +0300 Subject: mlxsw: spectrum_fid: Configure flooding entries using PGT APIs The PGT (Port Group Table) table maps an index to a bitmap of local ports to which a packet needs to be replicated. This table is used for layer 2 multicast and flooding. In the legacy model, software did not interact with PGT table directly. Instead, it was accessed by firmware in response to registers such as SFTR and SMID. In the new model, the SFTR register is deprecated and software has full control over the PGT table using the SMID register. Use the new PGT APIs to allocate entries for flooding as part of flood tables initialization. Add mlxsw_sp_fid_flood_tables_fini() to free the allocated indexes. In addition, use PGT APIs to add/remove ports from PGT table. The existing code which configures the flood entries via SFTR2 will be removed later. Signed-off-by: Amit Cohen Reviewed-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 65 ++++++++++++++++++++-- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index d168e9f5c62d..160c5af5235d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -322,6 +322,12 @@ mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid, return NULL; } +static u16 +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_flood_table_mid(const struct mlxsw_sp_fid_family *fid_family, const struct mlxsw_sp_flood_table *flood_table, @@ -329,7 +335,7 @@ mlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family *fid_family, { u16 num_fids; - num_fids = fid_family->end_index - fid_family->start_index + 1; + num_fids = mlxsw_sp_fid_family_num_fids(fid_family); return fid_family->pgt_base + num_fids * flood_table->table_index + fid_offset; } @@ -342,6 +348,7 @@ int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, const struct mlxsw_sp_fid_ops *ops = fid_family->ops; const struct mlxsw_sp_flood_table *flood_table; char *sftr2_pl; + u16 mid_index; int err; if (WARN_ON(!fid_family->flood_tables || !ops->flood_index)) @@ -351,6 +358,15 @@ int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, if (!flood_table) return -ESRCH; + if (fid_family->mlxsw_sp->ubridge) { + mid_index = mlxsw_sp_fid_flood_table_mid(fid_family, + flood_table, + fid->fid_offset); + return mlxsw_sp_pgt_entry_port_set(fid_family->mlxsw_sp, + mid_index, fid->fid_index, + local_port, member); + } + sftr2_pl = kmalloc(MLXSW_REG_SFTR2_LEN, GFP_KERNEL); if (!sftr2_pl) return -ENOMEM; @@ -1169,17 +1185,20 @@ 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; + u16 mid_base, num_fids, table_index; const int *sfgc_packet_types; - u16 mid_base, table_index; - int i; + int err, i; mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0); + num_fids = mlxsw_sp_fid_family_num_fids(fid_family); + err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, mid_base, num_fids); + if (err) + return err; sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { - struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; char sfgc_pl[MLXSW_REG_SFGC_LEN]; - int err; if (!sfgc_packet_types[i]) continue; @@ -1193,10 +1212,27 @@ mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl); if (err) - return err; + goto err_reg_write; } return 0; + +err_reg_write: + mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0); + mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids); + return err; +} + +static void +mlxsw_sp_fid_flood_table_fini(struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_flood_table *flood_table) +{ + struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; + u16 num_fids, mid_base; + + mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0); + num_fids = mlxsw_sp_fid_family_num_fids(fid_family); + mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids); } static int @@ -1217,6 +1253,19 @@ mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) return 0; } +static void +mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family *fid_family) +{ + int i; + + for (i = 0; i < fid_family->nr_flood_tables; i++) { + const struct mlxsw_sp_flood_table *flood_table; + + flood_table = &fid_family->flood_tables[i]; + mlxsw_sp_fid_flood_table_fini(fid_family, flood_table); + } +} + static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_fid_family *tmpl) { @@ -1258,6 +1307,10 @@ mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid_family *fid_family) { mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL; + + if (fid_family->flood_tables) + mlxsw_sp_fid_flood_tables_fini(fid_family); + bitmap_free(fid_family->fids_bitmap); WARN_ON_ONCE(!list_empty(&fid_family->fids_list)); kfree(fid_family); -- cgit v1.2.3