mlxsw: spectrum_fid: Add hooks for RSP table maintenance
authorPetr Machata <petrm@nvidia.com>
Tue, 28 Nov 2023 15:50:44 +0000 (16:50 +0100)
committerJakub Kicinski <kuba@kernel.org>
Thu, 30 Nov 2023 04:03:24 +0000 (20:03 -0800)
In the CFF flood mode, the driver has to allocate a table within PGT, which
holds flood vectors for router subport FIDs. For LAGs, these flood vectors
have to obviously be maintained dynamically as port membership in a LAG
changes. But even for physical ports, the flood vectors have to be kept
valid, and may not contain enabled bits corresponding to non-existent
ports. It is therefore not possible to precompute the port part of the RSP
table, it has to be maintained as ports come and go due to splits.

To support the RSP table maintenance, add to FID ops two new ops:
fid_port_init and fid_port_fini, for when a port comes to existence, or
joins a lag, and vice versa. Invoke these ops from
mlxsw_sp_port_fids_init() and mlxsw_sp_port_fids_fini(), which are called
when port is added and removed, respectively. Also add two new hooks for
LAG maintenance, mlxsw_sp_fid_port_join_lag() / _leave_lag() which
transitively call into the same ops.

Later patches will actually add the op implementations themselves, this
just adds the scaffolding.

Signed-off-by: Petr Machata <petrm@nvidia.com>
Reviewed-by: Amit Cohen <amcohen@nvidia.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://lore.kernel.org/r/234398a23540317abb25f74f920a5c8121faecf0.1701183892.git.petrm@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c

index 6726447ce100e4d437b44e4ac8204942a8cf61b9..e3ef63e265d2d4ee17b0fe141ec9723f0b5905d3 100644 (file)
@@ -4515,6 +4515,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 +4538,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 +4575,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);
 
index 8bd1083cfd9e2315299a8329a0c684888769101d..61612c413310233df4511426b5a67d1c8af3393d 100644 (file)
@@ -1328,6 +1328,8 @@ 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_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_core_ops mlxsw_sp1_fid_core_ops;
 extern const struct mlxsw_sp_fid_core_ops mlxsw_sp2_fid_core_ops;
index a718bdfa4c3b03c7bc2e0b5f1a4aa45e367cf900..76b0df7370b3a34cd98e0d8bb3d7077f49026168 100644 (file)
@@ -103,6 +103,14 @@ struct mlxsw_sp_fid_ops {
                       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);
 };
 
 struct mlxsw_sp_fid_family {
@@ -1836,9 +1844,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
@@ -1846,16 +1879,39 @@ 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_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[])