Skip to content

Commit

Permalink
Merge branch 'mlxsw-fixes'
Browse files Browse the repository at this point in the history
Jiri Pirko says:

====================
mlxsw: couple of fixes

Couple of fixes from Ido.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 9, 2016
2 parents 9b15350 + d664b41 commit 60d6f36
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 91 deletions.
203 changes: 112 additions & 91 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,15 +247,23 @@ static int mlxsw_sp_port_mtu_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mtu)
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl);
}

static int mlxsw_sp_port_swid_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 swid)
static int __mlxsw_sp_port_swid_set(struct mlxsw_sp *mlxsw_sp, u8 local_port,
u8 swid)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
char pspa_pl[MLXSW_REG_PSPA_LEN];

mlxsw_reg_pspa_pack(pspa_pl, swid, mlxsw_sp_port->local_port);
mlxsw_reg_pspa_pack(pspa_pl, swid, local_port);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pspa), pspa_pl);
}

static int mlxsw_sp_port_swid_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 swid)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;

return __mlxsw_sp_port_swid_set(mlxsw_sp, mlxsw_sp_port->local_port,
swid);
}

static int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port,
bool enable)
{
Expand Down Expand Up @@ -305,9 +313,9 @@ mlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port)
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sspr), sspr_pl);
}

static int __mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp,
u8 local_port, u8 *p_module,
u8 *p_width, u8 *p_lane)
static int mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp,
u8 local_port, u8 *p_module,
u8 *p_width, u8 *p_lane)
{
char pmlp_pl[MLXSW_REG_PMLP_LEN];
int err;
Expand All @@ -322,16 +330,6 @@ static int __mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp,
return 0;
}

static int mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp,
u8 local_port, u8 *p_module,
u8 *p_width)
{
u8 lane;

return __mlxsw_sp_port_module_info_get(mlxsw_sp, local_port, p_module,
p_width, &lane);
}

static int mlxsw_sp_port_module_map(struct mlxsw_sp *mlxsw_sp, u8 local_port,
u8 module, u8 width, u8 lane)
{
Expand Down Expand Up @@ -949,17 +947,11 @@ static int mlxsw_sp_port_get_phys_port_name(struct net_device *dev, char *name,
size_t len)
{
struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
u8 module, width, lane;
u8 module = mlxsw_sp_port->mapping.module;
u8 width = mlxsw_sp_port->mapping.width;
u8 lane = mlxsw_sp_port->mapping.lane;
int err;

err = __mlxsw_sp_port_module_info_get(mlxsw_sp_port->mlxsw_sp,
mlxsw_sp_port->local_port,
&module, &width, &lane);
if (err) {
netdev_err(dev, "Failed to retrieve module information\n");
return err;
}

if (!mlxsw_sp_port->split)
err = snprintf(name, len, "p%d", module + 1);
else
Expand Down Expand Up @@ -1681,8 +1673,8 @@ static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port)
return 0;
}

static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
bool split, u8 module, u8 width)
static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
bool split, u8 module, u8 width, u8 lane)
{
struct mlxsw_sp_port *mlxsw_sp_port;
struct net_device *dev;
Expand All @@ -1697,6 +1689,9 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
mlxsw_sp_port->mlxsw_sp = mlxsw_sp;
mlxsw_sp_port->local_port = local_port;
mlxsw_sp_port->split = split;
mlxsw_sp_port->mapping.module = module;
mlxsw_sp_port->mapping.width = width;
mlxsw_sp_port->mapping.lane = lane;
bytes = DIV_ROUND_UP(VLAN_N_VID, BITS_PER_BYTE);
mlxsw_sp_port->active_vlans = kzalloc(bytes, GFP_KERNEL);
if (!mlxsw_sp_port->active_vlans) {
Expand Down Expand Up @@ -1839,28 +1834,6 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
return err;
}

static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
bool split, u8 module, u8 width, u8 lane)
{
int err;

err = mlxsw_sp_port_module_map(mlxsw_sp, local_port, module, width,
lane);
if (err)
return err;

err = __mlxsw_sp_port_create(mlxsw_sp, local_port, split, module,
width);
if (err)
goto err_port_create;

return 0;

err_port_create:
mlxsw_sp_port_module_unmap(mlxsw_sp, local_port);
return err;
}

static void mlxsw_sp_port_vports_fini(struct mlxsw_sp_port *mlxsw_sp_port)
{
struct net_device *dev = mlxsw_sp_port->dev;
Expand Down Expand Up @@ -1909,8 +1882,8 @@ static void mlxsw_sp_ports_remove(struct mlxsw_sp *mlxsw_sp)

static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
{
u8 module, width, lane;
size_t alloc_size;
u8 module, width;
int i;
int err;

Expand All @@ -1921,13 +1894,14 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)

for (i = 1; i < MLXSW_PORT_MAX_PORTS; i++) {
err = mlxsw_sp_port_module_info_get(mlxsw_sp, i, &module,
&width);
&width, &lane);
if (err)
goto err_port_module_info_get;
if (!width)
continue;
mlxsw_sp->port_to_module[i] = module;
err = __mlxsw_sp_port_create(mlxsw_sp, i, false, module, width);
err = mlxsw_sp_port_create(mlxsw_sp, i, false, module, width,
lane);
if (err)
goto err_port_create;
}
Expand All @@ -1948,12 +1922,85 @@ static u8 mlxsw_sp_cluster_base_port_get(u8 local_port)
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 width = MLXSW_PORT_MODULE_MAX_WIDTH / count;
int err, i;

for (i = 0; i < count; i++) {
err = mlxsw_sp_port_module_map(mlxsw_sp, base_port + i, module,
width, i * width);
if (err)
goto err_port_module_map;
}

for (i = 0; i < count; i++) {
err = __mlxsw_sp_port_swid_set(mlxsw_sp, base_port + i, 0);
if (err)
goto err_port_swid_set;
}

for (i = 0; i < count; i++) {
err = mlxsw_sp_port_create(mlxsw_sp, base_port + i, true,
module, width, i * width);
if (err)
goto err_port_create;
}

return 0;

err_port_create:
for (i--; i >= 0; i--)
mlxsw_sp_port_remove(mlxsw_sp, base_port + i);
i = count;
err_port_swid_set:
for (i--; i >= 0; i--)
__mlxsw_sp_port_swid_set(mlxsw_sp, base_port + i,
MLXSW_PORT_SWID_DISABLED_PORT);
i = count;
err_port_module_map:
for (i--; i >= 0; i--)
mlxsw_sp_port_module_unmap(mlxsw_sp, base_port + i);
return err;
}

static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp,
u8 base_port, unsigned int count)
{
u8 local_port, module, width = MLXSW_PORT_MODULE_MAX_WIDTH;
int i;

/* Split by four means we need to re-create two ports, otherwise
* only one.
*/
count = count / 2;

for (i = 0; i < count; i++) {
local_port = base_port + i * 2;
module = mlxsw_sp->port_to_module[local_port];

mlxsw_sp_port_module_map(mlxsw_sp, local_port, module, width,
0);
}

for (i = 0; i < count; i++)
__mlxsw_sp_port_swid_set(mlxsw_sp, base_port + i * 2, 0);

for (i = 0; i < count; i++) {
local_port = base_port + i * 2;
module = mlxsw_sp->port_to_module[local_port];

mlxsw_sp_port_create(mlxsw_sp, local_port, false, module,
width, 0);
}
}

static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
unsigned int count)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
struct mlxsw_sp_port *mlxsw_sp_port;
u8 width = MLXSW_PORT_MODULE_MAX_WIDTH / count;
u8 module, cur_width, base_port;
int i;
int err;
Expand All @@ -1965,18 +2012,14 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
return -EINVAL;
}

module = mlxsw_sp_port->mapping.module;
cur_width = mlxsw_sp_port->mapping.width;

if (count != 2 && count != 4) {
netdev_err(mlxsw_sp_port->dev, "Port can only be split into 2 or 4 ports\n");
return -EINVAL;
}

err = mlxsw_sp_port_module_info_get(mlxsw_sp, local_port, &module,
&cur_width);
if (err) {
netdev_err(mlxsw_sp_port->dev, "Failed to get port's width\n");
return err;
}

if (cur_width != MLXSW_PORT_MODULE_MAX_WIDTH) {
netdev_err(mlxsw_sp_port->dev, "Port cannot be split further\n");
return -EINVAL;
Expand All @@ -2001,36 +2044,26 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
for (i = 0; i < count; i++)
mlxsw_sp_port_remove(mlxsw_sp, base_port + i);

for (i = 0; i < count; i++) {
err = mlxsw_sp_port_create(mlxsw_sp, base_port + i, true,
module, width, i * width);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to create split port\n");
goto err_port_create;
}
err = mlxsw_sp_port_split_create(mlxsw_sp, base_port, module, count);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to create split ports\n");
goto err_port_split_create;
}

return 0;

err_port_create:
for (i--; i >= 0; i--)
mlxsw_sp_port_remove(mlxsw_sp, base_port + i);
for (i = 0; i < count / 2; i++) {
module = mlxsw_sp->port_to_module[base_port + i * 2];
mlxsw_sp_port_create(mlxsw_sp, base_port + i * 2, false,
module, MLXSW_PORT_MODULE_MAX_WIDTH, 0);
}
err_port_split_create:
mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count);
return err;
}

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);
struct mlxsw_sp_port *mlxsw_sp_port;
u8 module, cur_width, base_port;
u8 cur_width, base_port;
unsigned int count;
int i;
int err;

mlxsw_sp_port = mlxsw_sp->ports[local_port];
if (!mlxsw_sp_port) {
Expand All @@ -2044,12 +2077,7 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port)
return -EINVAL;
}

err = mlxsw_sp_port_module_info_get(mlxsw_sp, local_port, &module,
&cur_width);
if (err) {
netdev_err(mlxsw_sp_port->dev, "Failed to get port's width\n");
return err;
}
cur_width = mlxsw_sp_port->mapping.width;
count = cur_width == 1 ? 4 : 2;

base_port = mlxsw_sp_cluster_base_port_get(local_port);
Expand All @@ -2061,14 +2089,7 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port)
for (i = 0; i < count; i++)
mlxsw_sp_port_remove(mlxsw_sp, base_port + i);

for (i = 0; i < count / 2; i++) {
module = mlxsw_sp->port_to_module[base_port + i * 2];
err = mlxsw_sp_port_create(mlxsw_sp, base_port + i * 2, false,
module, MLXSW_PORT_MODULE_MAX_WIDTH,
0);
if (err)
dev_err(mlxsw_sp->bus_info->dev, "Failed to reinstantiate port\n");
}
mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count);

return 0;
}
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@ struct mlxsw_sp_port {
struct ieee_maxrate *maxrate;
struct ieee_pfc *pfc;
} dcb;
struct {
u8 module;
u8 width;
u8 lane;
} mapping;
/* 802.1Q bridge VLANs */
unsigned long *active_vlans;
unsigned long *untagged_vlans;
Expand Down

0 comments on commit 60d6f36

Please sign in to comment.