kfree(mlxsw_sp->trap);
}
+static int mlxsw_sp_lag_pgt_init(struct mlxsw_sp *mlxsw_sp)
+{
+ char sgcr_pl[MLXSW_REG_SGCR_LEN];
+ u16 max_lag;
+ int err;
+
+ if (mlxsw_core_lag_mode(mlxsw_sp->core) !=
+ MLXSW_CMD_MBOX_CONFIG_PROFILE_LAG_MODE_SW)
+ return 0;
+
+ err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag);
+ if (err)
+ return err;
+
+ /* In DDD mode, which we by default use, each LAG entry is 8 PGT
+ * entries. The LAG table address needs to be 8-aligned, but that ought
+ * to be the case, since the LAG table is allocated first.
+ */
+ err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, &mlxsw_sp->lag_pgt_base,
+ max_lag * 8);
+ if (err)
+ return err;
+ if (WARN_ON_ONCE(mlxsw_sp->lag_pgt_base % 8)) {
+ err = -EINVAL;
+ goto err_mid_alloc_range;
+ }
+
+ mlxsw_reg_sgcr_pack(sgcr_pl, mlxsw_sp->lag_pgt_base);
+ err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sgcr), sgcr_pl);
+ if (err)
+ goto err_mid_alloc_range;
+
+ return 0;
+
+err_mid_alloc_range:
+ mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mlxsw_sp->lag_pgt_base,
+ max_lag * 8);
+ return err;
+}
+
+static void mlxsw_sp_lag_pgt_fini(struct mlxsw_sp *mlxsw_sp)
+{
+ u16 max_lag;
+ int err;
+
+ if (mlxsw_core_lag_mode(mlxsw_sp->core) !=
+ MLXSW_CMD_MBOX_CONFIG_PROFILE_LAG_MODE_SW)
+ return;
+
+ err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag);
+ if (err)
+ return;
+
+ mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mlxsw_sp->lag_pgt_base,
+ max_lag * 8);
+}
+
#define MLXSW_SP_LAG_SEED_INIT 0xcafecafe
static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp)
if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LAG_MEMBERS))
return -EIO;
+ err = mlxsw_sp_lag_pgt_init(mlxsw_sp);
+ if (err)
+ return err;
+
mlxsw_sp->lags = kcalloc(max_lag, sizeof(struct mlxsw_sp_upper),
GFP_KERNEL);
- if (!mlxsw_sp->lags)
- return -ENOMEM;
+ if (!mlxsw_sp->lags) {
+ err = -ENOMEM;
+ goto err_kcalloc;
+ }
return 0;
+
+err_kcalloc:
+ mlxsw_sp_lag_pgt_fini(mlxsw_sp);
+ return err;
}
static void mlxsw_sp_lag_fini(struct mlxsw_sp *mlxsw_sp)
{
+ mlxsw_sp_lag_pgt_fini(mlxsw_sp);
kfree(mlxsw_sp->lags);
}
goto err_pgt_init;
}
+ /* Initialize before FIDs so that the LAG table is at the start of PGT
+ * and 8-aligned without overallocation.
+ */
+ err = mlxsw_sp_lag_init(mlxsw_sp);
+ if (err) {
+ dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize LAG\n");
+ goto err_lag_init;
+ }
+
err = mlxsw_sp_fids_init(mlxsw_sp);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n");
goto err_buffers_init;
}
- err = mlxsw_sp_lag_init(mlxsw_sp);
- if (err) {
- dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize LAG\n");
- goto err_lag_init;
- }
-
/* Initialize SPAN before router and switchdev, so that those components
* can call mlxsw_sp_span_respin().
*/
err_switchdev_init:
mlxsw_sp_span_fini(mlxsw_sp);
err_span_init:
- mlxsw_sp_lag_fini(mlxsw_sp);
-err_lag_init:
mlxsw_sp_buffers_fini(mlxsw_sp);
err_buffers_init:
mlxsw_sp_devlink_traps_fini(mlxsw_sp);
err_policers_init:
mlxsw_sp_fids_fini(mlxsw_sp);
err_fids_init:
+ mlxsw_sp_lag_fini(mlxsw_sp);
+err_lag_init:
mlxsw_sp_pgt_fini(mlxsw_sp);
err_pgt_init:
mlxsw_sp_kvdl_fini(mlxsw_sp);
mlxsw_sp_counter_pool_fini(mlxsw_sp);
mlxsw_sp_switchdev_fini(mlxsw_sp);
mlxsw_sp_span_fini(mlxsw_sp);
- mlxsw_sp_lag_fini(mlxsw_sp);
mlxsw_sp_buffers_fini(mlxsw_sp);
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_lag_fini(mlxsw_sp);
mlxsw_sp_pgt_fini(mlxsw_sp);
mlxsw_sp_kvdl_fini(mlxsw_sp);
mlxsw_sp_parsing_fini(mlxsw_sp);