mlxsw: minimal: Extend to support line card dynamic operations

Implement line card operation callbacks got_active() / got_inactive().
The purpose of these callback to create / remove line card ports after
line card is getting active / inactive.

Implement line ports_remove_selected() callback to support line card
un-provisioning flow through 'devlink'.

Add line card operation registration and de-registration APIs.

Add module offset for line card. Offset for main board iz zero.
For line card in slot #n offset is calculated as (#n - 1) multiplied by
maximum modules number.

Signed-off-by: Vadim Pasternak <vadimp@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Vadim Pasternak 2022-08-21 18:20:18 +02:00 committed by Jakub Kicinski
parent 01328e23a4
commit 706ddb7821

View File

@ -48,6 +48,7 @@ struct mlxsw_m_port {
u16 local_port;
u8 slot_index;
u8 module;
u8 module_offset;
};
static int mlxsw_m_base_mac_get(struct mlxsw_m *mlxsw_m)
@ -227,7 +228,8 @@ mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port)
if (err)
return err;
mlxsw_reg_ppad_mac_memcpy_from(ppad_pl, addr);
eth_hw_addr_gen(mlxsw_m_port->dev, addr, mlxsw_m_port->module + 1);
eth_hw_addr_gen(mlxsw_m_port->dev, addr, mlxsw_m_port->module + 1 +
mlxsw_m_port->module_offset);
return 0;
}
@ -268,6 +270,14 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u16 local_port, u8 slot_index,
mlxsw_m_port->local_port = local_port;
mlxsw_m_port->module = module;
mlxsw_m_port->slot_index = slot_index;
/* Add module offset for line card. Offset for main board iz zero.
* For line card in slot #n offset is calculated as (#n - 1)
* multiplied by maximum modules number, which could be found on a line
* card.
*/
mlxsw_m_port->module_offset = mlxsw_m_port->slot_index ?
(mlxsw_m_port->slot_index - 1) *
mlxsw_m->max_modules_per_slot : 0;
dev->netdev_ops = &mlxsw_m_port_netdev_ops;
dev->ethtool_ops = &mlxsw_m_port_ethtool_ops;
@ -333,6 +343,9 @@ static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u16 local_port,
if (err)
return err;
/* Skip if line card has been already configured */
if (mlxsw_m->line_cards[slot_index]->active)
return 0;
if (!width)
return 0;
/* Skip, if port belongs to the cluster */
@ -536,6 +549,24 @@ static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m)
mlxsw_m_linecard_ports_remove(mlxsw_m, 0);
}
static void
mlxsw_m_ports_remove_selected(struct mlxsw_core *mlxsw_core,
bool (*selector)(void *priv, u16 local_port),
void *priv)
{
struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
struct mlxsw_linecard *linecard_priv = priv;
struct mlxsw_m_line_card *linecard;
linecard = mlxsw_m->line_cards[linecard_priv->slot_index];
if (WARN_ON(!linecard->active))
return;
mlxsw_m_linecard_ports_remove(mlxsw_m, linecard_priv->slot_index);
linecard->active = false;
}
static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m)
{
const struct mlxsw_fw_rev *rev = &mlxsw_m->bus_info->fw_rev;
@ -554,6 +585,60 @@ static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m)
return -EINVAL;
}
static void
mlxsw_m_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, void *priv)
{
struct mlxsw_m_line_card *linecard;
struct mlxsw_m *mlxsw_m = priv;
int err;
linecard = mlxsw_m->line_cards[slot_index];
/* Skip if line card has been already configured during init */
if (linecard->active)
return;
/* Fill out module to local port mapping array */
err = mlxsw_m_ports_module_map(mlxsw_m);
if (err)
goto err_ports_module_map;
/* Create port objects for each valid entry */
err = mlxsw_m_linecard_ports_create(mlxsw_m, slot_index);
if (err) {
dev_err(mlxsw_m->bus_info->dev, "Failed to create port for line card at slot %d\n",
slot_index);
goto err_linecard_ports_create;
}
linecard->active = true;
return;
err_linecard_ports_create:
err_ports_module_map:
mlxsw_m_linecard_port_module_unmap(mlxsw_m, slot_index);
}
static void
mlxsw_m_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index, void *priv)
{
struct mlxsw_m_line_card *linecard;
struct mlxsw_m *mlxsw_m = priv;
linecard = mlxsw_m->line_cards[slot_index];
if (WARN_ON(!linecard->active))
return;
mlxsw_m_linecard_ports_remove(mlxsw_m, slot_index);
linecard->active = false;
}
static struct mlxsw_linecards_event_ops mlxsw_m_event_ops = {
.got_active = mlxsw_m_got_active,
.got_inactive = mlxsw_m_got_inactive,
};
static int mlxsw_m_init(struct mlxsw_core *mlxsw_core,
const struct mlxsw_bus_info *mlxsw_bus_info,
struct netlink_ext_ack *extack)
@ -580,6 +665,13 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core,
return err;
}
err = mlxsw_linecards_event_ops_register(mlxsw_core,
&mlxsw_m_event_ops, mlxsw_m);
if (err) {
dev_err(mlxsw_m->bus_info->dev, "Failed to register line cards operations\n");
goto linecards_event_ops_register;
}
err = mlxsw_m_ports_create(mlxsw_m);
if (err) {
dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n");
@ -589,6 +681,9 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core,
return 0;
err_ports_create:
mlxsw_linecards_event_ops_unregister(mlxsw_core,
&mlxsw_m_event_ops, mlxsw_m);
linecards_event_ops_register:
mlxsw_m_linecards_fini(mlxsw_m);
return err;
}
@ -598,6 +693,8 @@ static void mlxsw_m_fini(struct mlxsw_core *mlxsw_core)
struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
mlxsw_m_ports_remove(mlxsw_m);
mlxsw_linecards_event_ops_unregister(mlxsw_core,
&mlxsw_m_event_ops, mlxsw_m);
mlxsw_m_linecards_fini(mlxsw_m);
}
@ -608,6 +705,7 @@ static struct mlxsw_driver mlxsw_m_driver = {
.priv_size = sizeof(struct mlxsw_m),
.init = mlxsw_m_init,
.fini = mlxsw_m_fini,
.ports_remove_selected = mlxsw_m_ports_remove_selected,
.profile = &mlxsw_m_config_profile,
};