Commit 3d6d7549 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'mlxsw-support-cff-flood-mode'

Petr Machata says:

====================
mlxsw: Support CFF flood mode

The registers to configure to initialize a flood table differ between the
controlled and CFF flood modes. In therefore needs to be an op. Add it,
hook up the current init to the existing families, and invoke the op.

PGT is an in-HW table that maps addresses to sets of ports. Then when some
HW process needs a set of ports as an argument, instead of embedding the
actual set in the dynamic configuration, what gets configured is the
address referencing the set. The HW then works with the appropriate PGT
entry.

Among other allocations, the PGT currently contains two large blocks for
bridge flooding: one for 802.1q and one for 802.1d. Within each of these
blocks are three tables, for unknown-unicast, multicast and broadcast
flooding:

      . . . |    802.1q    |    802.1d    | . . .
            | UC | MC | BC | UC | MC | BC |
             \______ _____/ \_____ ______/
                    v             v
                   FID flood vectors

Thus each FID (which corresponds to an 802.1d bridge or one VLAN in an
802.1q bridge) uses three flood vectors spread across a fairly large region
of PGT.

This way of organizing the flood table (called "controlled") is not very
flexible. E.g. to decrease a bridge scale and store more IP MC vectors, one
would need to completely rewrite the bridge PGT blocks, or resort to hacks
such as storing individual MC flood vectors into unused part of the bridge
table.

In order to address these shortcomings, Spectrum-2 and above support what
is called CFF flood mode, for Compressed FID Flooding. In CFF flood mode,
each FID has a little table of its own, with three entries adjacent to each
other, one for unknown-UC, one for MC, one for BC. This allows for a much
more fine-grained approach to PGT management, where bits of it are
allocated on demand.

      . . . | FID | FID | FID | FID | FID | . . .
            |U|M|B|U|M|B|U|M|B|U|M|B|U|M|B|
             \_____________ _____________/
                           v
                   FID flood vectors

Besides the FID table organization, the CFF flood mode also impacts Router
Subport (RSP) table. This table contains flood vectors for rFIDs, which are
FIDs that reference front panel ports or LAGs. The RSP table contains two
entries per front panel port and LAG, one for unknown-UC traffic, and one
for everything else. Currently, the FW allocates and manages the table in
its own part of PGT. rFIDs are marked with flood_rsp bit and managed
specially. In CFF mode, rFIDs are managed as all other FIDs. The driver
therefore has to allocate and maintain the flood vectors. Like with bridge
FIDs, this is more work, but increases flexibility of the system.

The FW currently supports both the controlled and CFF flood modes. To shed
complexity, in the future it should only support CFF flood mode. Hence this
patchset, which adds CFF flood mode support to mlxsw.

Since mlxsw needs to maintain both the controlled mode as well as CFF mode
support, we will keep the layout as compatible as possible. The bridge
tables will stay in the same overall shape, just their inner organization
will change from flood mode -> FID to FID -> flood mode. Likewise will RSP
be kept as a contiguous block of PGT memory, as was the case when the FW
maintained it.

- The way FIDs get configured under the CFF flood mode differs from the
  currently used controlled mode. The simple approach of having several
  globally visible arrays for spectrum.c to statically choose from no
  longer works.

  Patch #1 thus privatizes all FID initialization and finalization logic,
  and exposes it as ops instead.

- Patch #2 renames the ops that are specific to the controlled mode, to
  make room in the namespace for the CFF variants.

  Patch #3 extracts a helper to compute flood table base out of
  mlxsw_sp_fid_flood_table_mid().

- The op fid_setup configured fid_offset, i.e. the number of this FID
  within its family. For rFIDs in CFF mode, to determine this number, the
  driver will need to do fallible queries.

  Thus in patch #4, make the FID setup operation fallible as well.

- Flood mode initialization routine differs between the controlled and CFF
  flood modes. The controlled mode needs to configure flood table layout,
  which the CFF mode does not need to do.

  In patch #5, move mlxsw_sp_fid_flood_table_init() up so that the
  following patch can make use of it.

  In patch #6, add an op to be invoked per table (if defined).

- The current way of determining PGT allocation size depends on the number
  of FIDs and number of flood tables. RFIDs however have PGT footprint
  depending not on number of FIDs, but on number of ports and LAGs, because
  which ports an rFID should flood to does not depend on the FID itself,
  but on the port or LAG that it references.

  Therefore in patch #7, add FID family ops for determining PGT allocation
  size.

- As elaborated above, layout of PGT will differ between controlled and CFF
  flood modes. In CFF mode, it will further differ between rFIDs and other
  FIDs (as described at previous patch). The way to pack the SFMR register
  to configure a FID will likewise differ from controlled to CFF.

  Thus in patches #8 and #9 add FID family ops to determine PGT base
  address for a FID and to pack SFMR.

- Patches #10 and #11 add more bits for RSP support. In patch #10, add a
  new traffic type enumerator, for non-UC traffic. This is a combination of
  BC and MC traffic, but the way that mlxsw maps these mnemonic names to
  actual traffic type configurations requires that we have a new name to
  describe this class of traffic.

  Patch #11 then adds hooks necessary for RSP table maintenance. As ports
  come and go, and join and leave LAGs, it is necessary to update flood
  vectors that the rFIDs use. These new hooks will make that possible.

- Patches #12, #13 and #14 introduce flood profiles. These have been
  implicit so far, but the way that CFF flood mode works with profile IDs
  requires that we make them explicit.

  Thus in patch #12, introduce flood profile objects as a set of flood
  tables that FID families then refer to. The FID code currently only
  uses a single flood profile.

  In patch #13, add a flood profile ID to flood profile objects.

  In patch #14, when in CFF mode, configure SFFP according to the existing
  flood profiles (or the one that exists as of that point).

- Patches #15 and #16 add code to implement, respectively, bridge FIDs and
  RSP FIDs in CFF mode.

- In patch #17, toggle flood_mode_prefer_cff on Spectrum-2 and above, which
  makes the newly-added code live.
====================

Link: https://lore.kernel.org/r/cover.1701183891.git.petrm@nvidia.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 7edce370 69f289e9
......@@ -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);
......
......@@ -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 {
......
......@@ -11,6 +11,7 @@
#include <linux/refcount.h>
#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,64 @@ 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,
.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,
.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,
......@@ -1082,6 +1259,9 @@ 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,
.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,137 @@ 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,
.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,
.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,
......@@ -1261,11 +1621,17 @@ 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,
.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,27 @@ 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,
.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,
.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,
......@@ -1419,6 +1806,9 @@ 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,
.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,20 +2096,29 @@ 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);
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,
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment