mlxsw: spectrum: Use PMTM register to get max module width
Currently the max module width is hard-coded according to ASIC type. That is not entirely correct, as the max module width might differ per-board. Use PMTM register to query FW for maximal width of a module. Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a513b1a591
commit
25911e1b97
|
@ -2017,6 +2017,35 @@ mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core,
|
|||
}
|
||||
EXPORT_SYMBOL(mlxsw_core_port_devlink_port_get);
|
||||
|
||||
int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module)
|
||||
{
|
||||
enum mlxsw_reg_pmtm_module_type module_type;
|
||||
char pmtm_pl[MLXSW_REG_PMTM_LEN];
|
||||
int err;
|
||||
|
||||
mlxsw_reg_pmtm_pack(pmtm_pl, module);
|
||||
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl);
|
||||
if (err)
|
||||
return err;
|
||||
mlxsw_reg_pmtm_unpack(pmtm_pl, &module_type);
|
||||
|
||||
/* Here we need to get the module width according to the module type. */
|
||||
|
||||
switch (module_type) {
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_BP_4X: /* fall through */
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_BP_QSFP:
|
||||
return 4;
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_BP_2X:
|
||||
return 2;
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_BP_SFP: /* fall through */
|
||||
case MLXSW_REG_PMTM_MODULE_TYPE_BP_1X:
|
||||
return 1;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(mlxsw_core_module_max_width);
|
||||
|
||||
static void mlxsw_core_buf_dump_dbg(struct mlxsw_core *mlxsw_core,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
|
|
|
@ -200,6 +200,7 @@ enum devlink_port_type mlxsw_core_port_type_get(struct mlxsw_core *mlxsw_core,
|
|||
struct devlink_port *
|
||||
mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core,
|
||||
u8 local_port);
|
||||
int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module);
|
||||
|
||||
int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay);
|
||||
bool mlxsw_core_schedule_work(struct work_struct *work);
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
|
||||
#define MLXSW_PORT_DONT_CARE 0xFF
|
||||
|
||||
#define MLXSW_PORT_MODULE_MAX_WIDTH 4
|
||||
|
||||
enum mlxsw_port_admin_status {
|
||||
MLXSW_PORT_ADMIN_STATUS_UP = 1,
|
||||
MLXSW_PORT_ADMIN_STATUS_DOWN = 2,
|
||||
|
|
|
@ -4038,17 +4038,18 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
|
|||
return err;
|
||||
}
|
||||
|
||||
static u8 mlxsw_sp_cluster_base_port_get(u8 local_port)
|
||||
static u8 mlxsw_sp_cluster_base_port_get(u8 local_port, unsigned int max_width)
|
||||
{
|
||||
u8 offset = (local_port - 1) % MLXSW_SP_PORTS_PER_CLUSTER_MAX;
|
||||
u8 offset = (local_port - 1) % max_width;
|
||||
|
||||
return local_port - offset;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port,
|
||||
u8 module, unsigned int count, u8 offset)
|
||||
u8 module, unsigned int count, u8 offset,
|
||||
unsigned int max_width)
|
||||
{
|
||||
u8 width = MLXSW_PORT_MODULE_MAX_WIDTH / count;
|
||||
u8 width = max_width / count;
|
||||
int err, i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
|
@ -4068,9 +4069,10 @@ static int mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port,
|
|||
}
|
||||
|
||||
static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp,
|
||||
u8 base_port, unsigned int count)
|
||||
u8 base_port, unsigned int count,
|
||||
unsigned int max_width)
|
||||
{
|
||||
u8 local_port, module, width = MLXSW_PORT_MODULE_MAX_WIDTH;
|
||||
u8 local_port, module, width = max_width;
|
||||
int i;
|
||||
|
||||
/* Split by four means we need to re-create two ports, otherwise
|
||||
|
@ -4096,7 +4098,8 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
|
|||
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
|
||||
u8 local_ports_in_1x, local_ports_in_2x, offset;
|
||||
struct mlxsw_sp_port *mlxsw_sp_port;
|
||||
u8 module, cur_width, base_port;
|
||||
u8 module, base_port;
|
||||
int max_width;
|
||||
int i;
|
||||
int err;
|
||||
|
||||
|
@ -4116,7 +4119,14 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
|
|||
}
|
||||
|
||||
module = mlxsw_sp_port->mapping.module;
|
||||
cur_width = mlxsw_sp_port->mapping.width;
|
||||
|
||||
max_width = mlxsw_core_module_max_width(mlxsw_core,
|
||||
mlxsw_sp_port->mapping.module);
|
||||
if (max_width < 0) {
|
||||
netdev_err(mlxsw_sp_port->dev, "Cannot get max width of port module\n");
|
||||
NL_SET_ERR_MSG_MOD(extack, "Cannot get max width of port module");
|
||||
return max_width;
|
||||
}
|
||||
|
||||
if (count != 2 && count != 4) {
|
||||
netdev_err(mlxsw_sp_port->dev, "Port can only be split into 2 or 4 ports\n");
|
||||
|
@ -4124,7 +4134,8 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cur_width != MLXSW_PORT_MODULE_MAX_WIDTH) {
|
||||
/* Split port with non-max module width cannot be split. */
|
||||
if (mlxsw_sp_port->mapping.width != max_width) {
|
||||
netdev_err(mlxsw_sp_port->dev, "Port cannot be split further\n");
|
||||
NL_SET_ERR_MSG_MOD(extack, "Port cannot be split further");
|
||||
return -EINVAL;
|
||||
|
@ -4141,7 +4152,8 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
|
|||
}
|
||||
} else {
|
||||
offset = local_ports_in_1x;
|
||||
base_port = mlxsw_sp_cluster_base_port_get(local_port);
|
||||
base_port = mlxsw_sp_cluster_base_port_get(local_port,
|
||||
max_width);
|
||||
if (mlxsw_sp->ports[base_port + 1] ||
|
||||
mlxsw_sp->ports[base_port + 3]) {
|
||||
netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n");
|
||||
|
@ -4155,7 +4167,7 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
|
|||
mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset);
|
||||
|
||||
err = mlxsw_sp_port_split_create(mlxsw_sp, base_port, module, count,
|
||||
offset);
|
||||
offset, max_width);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Failed to create split ports\n");
|
||||
goto err_port_split_create;
|
||||
|
@ -4164,7 +4176,7 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
|
|||
return 0;
|
||||
|
||||
err_port_split_create:
|
||||
mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count);
|
||||
mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, max_width);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -4174,8 +4186,9 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port,
|
|||
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
|
||||
u8 local_ports_in_1x, local_ports_in_2x, offset;
|
||||
struct mlxsw_sp_port *mlxsw_sp_port;
|
||||
u8 cur_width, base_port;
|
||||
unsigned int count;
|
||||
int max_width;
|
||||
u8 base_port;
|
||||
int i;
|
||||
|
||||
if (!MLXSW_CORE_RES_VALID(mlxsw_core, LOCAL_PORTS_IN_1X) ||
|
||||
|
@ -4199,15 +4212,22 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
cur_width = mlxsw_sp_port->mapping.width;
|
||||
count = cur_width == 1 ? 4 : 2;
|
||||
max_width = mlxsw_core_module_max_width(mlxsw_core,
|
||||
mlxsw_sp_port->mapping.module);
|
||||
if (max_width < 0) {
|
||||
netdev_err(mlxsw_sp_port->dev, "Cannot get max width of port module\n");
|
||||
NL_SET_ERR_MSG_MOD(extack, "Cannot get max width of port module");
|
||||
return max_width;
|
||||
}
|
||||
|
||||
count = max_width / mlxsw_sp_port->mapping.width;
|
||||
|
||||
if (count == 2)
|
||||
offset = local_ports_in_2x;
|
||||
else
|
||||
offset = local_ports_in_1x;
|
||||
|
||||
base_port = mlxsw_sp_cluster_base_port_get(local_port);
|
||||
base_port = mlxsw_sp_cluster_base_port_get(local_port, max_width);
|
||||
|
||||
/* Determine which ports to remove. */
|
||||
if (count == 2 && local_port >= base_port + 2)
|
||||
|
@ -4217,7 +4237,7 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port,
|
|||
if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset))
|
||||
mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset);
|
||||
|
||||
mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count);
|
||||
mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, max_width);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user