Commit e5b6a5ba authored by Vadim Pasternak's avatar Vadim Pasternak Committed by David S. Miller

mlxsw: core: Extend port module data structures for line cards

The port module core is tasked with module operations such as setting
power mode policy and reset. The per-module information is currently
stored in one large array suited for non-modular systems where only the
main board is present (i.e., slot index 0).

As a preparation for line cards support, allocate a per line card array
according to the queried number of slots in the system. For each line
card, allocate a module array according to the queried maximum number of
modules per-slot.
Signed-off-by: default avatarVadim Pasternak <vadimp@nvidia.com>
Signed-off-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 34945452
......@@ -21,20 +21,36 @@ struct mlxsw_env_module_info {
enum mlxsw_reg_pmtm_module_type type;
};
struct mlxsw_env {
struct mlxsw_core *core;
struct mlxsw_env_line_card {
u8 module_count;
struct mutex module_info_lock; /* Protects 'module_info'. */
struct mlxsw_env_module_info module_info[];
};
struct mlxsw_env {
struct mlxsw_core *core;
u8 max_module_count; /* Maximum number of modules per-slot. */
u8 num_of_slots; /* Including the main board. */
struct mutex line_cards_lock; /* Protects line cards. */
struct mlxsw_env_line_card *line_cards[];
};
static struct
mlxsw_env_module_info *mlxsw_env_module_info_get(struct mlxsw_core *mlxsw_core,
u8 slot_index, u8 module)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
return &mlxsw_env->line_cards[slot_index]->module_info[module];
}
static int __mlxsw_env_validate_module_type(struct mlxsw_core *core,
u8 slot_index, u8 module)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(core);
struct mlxsw_env_module_info *module_info;
int err;
switch (mlxsw_env->module_info[module].type) {
module_info = mlxsw_env_module_info_get(core, slot_index, module);
switch (module_info->type) {
case MLXSW_REG_PMTM_MODULE_TYPE_TWISTED_PAIR:
err = -EINVAL;
break;
......@@ -51,9 +67,9 @@ static int mlxsw_env_validate_module_type(struct mlxsw_core *core,
struct mlxsw_env *mlxsw_env = mlxsw_core_env(core);
int err;
mutex_lock(&mlxsw_env->module_info_lock);
mutex_lock(&mlxsw_env->line_cards_lock);
err = __mlxsw_env_validate_module_type(core, slot_index, module);
mutex_unlock(&mlxsw_env->module_info_lock);
mutex_unlock(&mlxsw_env->line_cards_lock);
return err;
}
......@@ -472,6 +488,7 @@ int mlxsw_env_reset_module(struct net_device *netdev,
u8 module, u32 *flags)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
struct mlxsw_env_module_info *module_info;
u32 req = *flags;
int err;
......@@ -479,7 +496,7 @@ int mlxsw_env_reset_module(struct net_device *netdev,
!(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)))
return 0;
mutex_lock(&mlxsw_env->module_info_lock);
mutex_lock(&mlxsw_env->line_cards_lock);
err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
if (err) {
......@@ -487,13 +504,14 @@ int mlxsw_env_reset_module(struct net_device *netdev,
goto out;
}
if (mlxsw_env->module_info[module].num_ports_up) {
module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
if (module_info->num_ports_up) {
netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n");
err = -EINVAL;
goto out;
}
if (mlxsw_env->module_info[module].num_ports_mapped > 1 &&
if (module_info->num_ports_mapped > 1 &&
!(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) {
netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n");
err = -EINVAL;
......@@ -509,7 +527,7 @@ int mlxsw_env_reset_module(struct net_device *netdev,
*flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT));
out:
mutex_unlock(&mlxsw_env->module_info_lock);
mutex_unlock(&mlxsw_env->line_cards_lock);
return err;
}
EXPORT_SYMBOL(mlxsw_env_reset_module);
......@@ -521,11 +539,12 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
struct netlink_ext_ack *extack)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
struct mlxsw_env_module_info *module_info;
char mcion_pl[MLXSW_REG_MCION_LEN];
u32 status_bits;
int err;
mutex_lock(&mlxsw_env->module_info_lock);
mutex_lock(&mlxsw_env->line_cards_lock);
err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
if (err) {
......@@ -533,7 +552,8 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
goto out;
}
params->policy = mlxsw_env->module_info[module].power_mode_policy;
module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
params->policy = module_info->power_mode_policy;
mlxsw_reg_mcion_pack(mcion_pl, slot_index, module);
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl);
......@@ -552,7 +572,7 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
params->mode = ETHTOOL_MODULE_POWER_MODE_HIGH;
out:
mutex_unlock(&mlxsw_env->module_info_lock);
mutex_unlock(&mlxsw_env->line_cards_lock);
return err;
}
EXPORT_SYMBOL(mlxsw_env_get_module_power_mode);
......@@ -634,6 +654,7 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
struct netlink_ext_ack *extack)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
struct mlxsw_env_module_info *module_info;
bool low_power;
int err = 0;
......@@ -643,7 +664,7 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
return -EOPNOTSUPP;
}
mutex_lock(&mlxsw_env->module_info_lock);
mutex_lock(&mlxsw_env->line_cards_lock);
err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
if (err) {
......@@ -652,11 +673,12 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
goto out;
}
if (mlxsw_env->module_info[module].power_mode_policy == policy)
module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
if (module_info->power_mode_policy == policy)
goto out;
/* If any ports are up, we are already in high power mode. */
if (mlxsw_env->module_info[module].num_ports_up)
if (module_info->num_ports_up)
goto out_set_policy;
low_power = policy == ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO;
......@@ -666,9 +688,9 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
goto out;
out_set_policy:
mlxsw_env->module_info[module].power_mode_policy = policy;
module_info->power_mode_policy = policy;
out:
mutex_unlock(&mlxsw_env->module_info_lock);
mutex_unlock(&mlxsw_env->line_cards_lock);
return err;
}
EXPORT_SYMBOL(mlxsw_env_set_module_power_mode);
......@@ -748,10 +770,11 @@ mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core, u8 slot_index,
static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core,
u8 slot_index)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
int i, err, sensor_index;
bool has_temp_sensor;
for (i = 0; i < mlxsw_core_env(mlxsw_core)->module_count; i++) {
for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) {
err = mlxsw_env_module_has_temp_sensor(mlxsw_core, slot_index,
i, &has_temp_sensor);
if (err)
......@@ -779,6 +802,7 @@ struct mlxsw_env_module_temp_warn_event {
static void mlxsw_env_mtwe_event_work(struct work_struct *work)
{
struct mlxsw_env_module_temp_warn_event *event;
struct mlxsw_env_module_info *module_info;
struct mlxsw_env *mlxsw_env;
int i, sensor_warning;
bool is_overheat;
......@@ -787,7 +811,7 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work)
work);
mlxsw_env = event->mlxsw_env;
for (i = 0; i < mlxsw_env->module_count; i++) {
for (i = 0; i < mlxsw_env->max_module_count; i++) {
/* 64-127 of sensor_index are mapped to the port modules
* sequentially (module 0 is mapped to sensor_index 64,
* module 1 to sensor_index 65 and so on)
......@@ -795,9 +819,10 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work)
sensor_warning =
mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl,
i + MLXSW_REG_MTMP_MODULE_INDEX_MIN);
mutex_lock(&mlxsw_env->module_info_lock);
is_overheat =
mlxsw_env->module_info[i].is_overheat;
mutex_lock(&mlxsw_env->line_cards_lock);
/* MTWE only supports main board. */
module_info = mlxsw_env_module_info_get(mlxsw_env->core, 0, i);
is_overheat = module_info->is_overheat;
if ((is_overheat && sensor_warning) ||
(!is_overheat && !sensor_warning)) {
......@@ -805,21 +830,21 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work)
* warning OR current state in "no warning" and MTWE
* does not report warning.
*/
mutex_unlock(&mlxsw_env->module_info_lock);
mutex_unlock(&mlxsw_env->line_cards_lock);
continue;
} else if (is_overheat && !sensor_warning) {
/* MTWE reports "no warning", turn is_overheat off.
*/
mlxsw_env->module_info[i].is_overheat = false;
mutex_unlock(&mlxsw_env->module_info_lock);
module_info->is_overheat = false;
mutex_unlock(&mlxsw_env->line_cards_lock);
} else {
/* Current state is "no warning" and MTWE reports
* "warning", increase the counter and turn is_overheat
* on.
*/
mlxsw_env->module_info[i].is_overheat = true;
mlxsw_env->module_info[i].module_overheat_counter++;
mutex_unlock(&mlxsw_env->module_info_lock);
module_info->is_overheat = true;
module_info->module_overheat_counter++;
mutex_unlock(&mlxsw_env->line_cards_lock);
}
}
......@@ -871,6 +896,7 @@ struct mlxsw_env_module_plug_unplug_event {
static void mlxsw_env_pmpe_event_work(struct work_struct *work)
{
struct mlxsw_env_module_plug_unplug_event *event;
struct mlxsw_env_module_info *module_info;
struct mlxsw_env *mlxsw_env;
bool has_temp_sensor;
u16 sensor_index;
......@@ -880,9 +906,12 @@ static void mlxsw_env_pmpe_event_work(struct work_struct *work)
work);
mlxsw_env = event->mlxsw_env;
mutex_lock(&mlxsw_env->module_info_lock);
mlxsw_env->module_info[event->module].is_overheat = false;
mutex_unlock(&mlxsw_env->module_info_lock);
mutex_lock(&mlxsw_env->line_cards_lock);
module_info = mlxsw_env_module_info_get(mlxsw_env->core,
event->slot_index,
event->module);
module_info->is_overheat = false;
mutex_unlock(&mlxsw_env->line_cards_lock);
err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core,
event->slot_index,
......@@ -909,12 +938,14 @@ static void
mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl,
void *priv)
{
u8 slot_index = mlxsw_reg_pmpe_slot_index_get(pmpe_pl);
struct mlxsw_env_module_plug_unplug_event *event;
enum mlxsw_reg_pmpe_module_status module_status;
u8 module = mlxsw_reg_pmpe_module_get(pmpe_pl);
struct mlxsw_env *mlxsw_env = priv;
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
if (WARN_ON_ONCE(module >= mlxsw_env->max_module_count ||
slot_index >= mlxsw_env->num_of_slots))
return;
module_status = mlxsw_reg_pmpe_module_status_get(pmpe_pl);
......@@ -926,7 +957,7 @@ mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl,
return;
event->mlxsw_env = mlxsw_env;
event->slot_index = 0;
event->slot_index = slot_index;
event->module = module;
INIT_WORK(&event->work, mlxsw_env_pmpe_event_work);
mlxsw_core_schedule_work(&event->work);
......@@ -957,9 +988,10 @@ static int
mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core,
u8 slot_index)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
int i, err;
for (i = 0; i < mlxsw_core_env(mlxsw_core)->module_count; i++) {
for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) {
char pmaos_pl[MLXSW_REG_PMAOS_LEN];
mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, i);
......@@ -978,10 +1010,12 @@ mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 slot_ind
u8 module, u64 *p_counter)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
struct mlxsw_env_module_info *module_info;
mutex_lock(&mlxsw_env->module_info_lock);
*p_counter = mlxsw_env->module_info[module].module_overheat_counter;
mutex_unlock(&mlxsw_env->module_info_lock);
mutex_lock(&mlxsw_env->line_cards_lock);
module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
*p_counter = module_info->module_overheat_counter;
mutex_unlock(&mlxsw_env->line_cards_lock);
return 0;
}
......@@ -991,10 +1025,12 @@ void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 slot_index,
u8 module)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
struct mlxsw_env_module_info *module_info;
mutex_lock(&mlxsw_env->module_info_lock);
mlxsw_env->module_info[module].num_ports_mapped++;
mutex_unlock(&mlxsw_env->module_info_lock);
mutex_lock(&mlxsw_env->line_cards_lock);
module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
module_info->num_ports_mapped++;
mutex_unlock(&mlxsw_env->line_cards_lock);
}
EXPORT_SYMBOL(mlxsw_env_module_port_map);
......@@ -1002,10 +1038,12 @@ void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 slot_index,
u8 module)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
struct mlxsw_env_module_info *module_info;
mutex_lock(&mlxsw_env->module_info_lock);
mlxsw_env->module_info[module].num_ports_mapped--;
mutex_unlock(&mlxsw_env->module_info_lock);
mutex_lock(&mlxsw_env->line_cards_lock);
module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
module_info->num_ports_mapped--;
mutex_unlock(&mlxsw_env->line_cards_lock);
}
EXPORT_SYMBOL(mlxsw_env_module_port_unmap);
......@@ -1013,15 +1051,17 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index,
u8 module)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
struct mlxsw_env_module_info *module_info;
int err = 0;
mutex_lock(&mlxsw_env->module_info_lock);
mutex_lock(&mlxsw_env->line_cards_lock);
if (mlxsw_env->module_info[module].power_mode_policy !=
module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
if (module_info->power_mode_policy !=
ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
goto out_inc;
if (mlxsw_env->module_info[module].num_ports_up != 0)
if (module_info->num_ports_up != 0)
goto out_inc;
/* Transition to high power mode following first port using the module
......@@ -1033,9 +1073,9 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index,
goto out_unlock;
out_inc:
mlxsw_env->module_info[module].num_ports_up++;
module_info->num_ports_up++;
out_unlock:
mutex_unlock(&mlxsw_env->module_info_lock);
mutex_unlock(&mlxsw_env->line_cards_lock);
return err;
}
EXPORT_SYMBOL(mlxsw_env_module_port_up);
......@@ -1044,16 +1084,18 @@ void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index,
u8 module)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
struct mlxsw_env_module_info *module_info;
mutex_lock(&mlxsw_env->module_info_lock);
mutex_lock(&mlxsw_env->line_cards_lock);
mlxsw_env->module_info[module].num_ports_up--;
module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
module_info->num_ports_up--;
if (mlxsw_env->module_info[module].power_mode_policy !=
if (module_info->power_mode_policy !=
ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
goto out_unlock;
if (mlxsw_env->module_info[module].num_ports_up != 0)
if (module_info->num_ports_up != 0)
goto out_unlock;
/* Transition to low power mode following last port using the module
......@@ -1063,17 +1105,57 @@ void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index,
NULL);
out_unlock:
mutex_unlock(&mlxsw_env->module_info_lock);
mutex_unlock(&mlxsw_env->line_cards_lock);
}
EXPORT_SYMBOL(mlxsw_env_module_port_down);
static int mlxsw_env_line_cards_alloc(struct mlxsw_env *env)
{
struct mlxsw_env_module_info *module_info;
int i, j;
for (i = 0; i < env->num_of_slots; i++) {
env->line_cards[i] = kzalloc(struct_size(env->line_cards[i],
module_info,
env->max_module_count),
GFP_KERNEL);
if (!env->line_cards[i])
goto kzalloc_err;
/* Firmware defaults to high power mode policy where modules
* are transitioned to high power mode following plug-in.
*/
for (j = 0; j < env->max_module_count; j++) {
module_info = &env->line_cards[i]->module_info[j];
module_info->power_mode_policy =
ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH;
}
}
return 0;
kzalloc_err:
for (i--; i >= 0; i--)
kfree(env->line_cards[i]);
return -ENOMEM;
}
static void mlxsw_env_line_cards_free(struct mlxsw_env *env)
{
int i = env->num_of_slots;
for (i--; i >= 0; i--)
kfree(env->line_cards[i]);
}
static int
mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core, u8 slot_index)
{
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
int i;
for (i = 0; i < mlxsw_env->module_count; i++) {
for (i = 0; i < mlxsw_env->line_cards[slot_index]->module_count; i++) {
struct mlxsw_env_module_info *module_info;
char pmtm_pl[MLXSW_REG_PMTM_LEN];
int err;
......@@ -1082,8 +1164,9 @@ mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core, u8 slot_index)
if (err)
return err;
mlxsw_env->module_info[i].type =
mlxsw_reg_pmtm_module_type_get(pmtm_pl);
module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index,
i);
module_info->type = mlxsw_reg_pmtm_module_type_get(pmtm_pl);
}
return 0;
......@@ -1091,32 +1174,38 @@ mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core, u8 slot_index)
int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
{
u8 module_count, num_of_slots, max_module_count;
char mgpir_pl[MLXSW_REG_MGPIR_LEN];
struct mlxsw_env *env;
u8 module_count;
int i, err;
int err;
mlxsw_reg_mgpir_pack(mgpir_pl, 0);
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl);
if (err)
return err;
mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count, NULL);
mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count,
&num_of_slots);
/* If the system is modular, get the maximum number of modules per-slot.
* Otherwise, get the maximum number of modules on the main board.
*/
max_module_count = num_of_slots ?
mlxsw_reg_mgpir_max_modules_per_slot_get(mgpir_pl) :
module_count;
env = kzalloc(struct_size(env, module_info, module_count), GFP_KERNEL);
env = kzalloc(struct_size(env, line_cards, num_of_slots + 1),
GFP_KERNEL);
if (!env)
return -ENOMEM;
/* Firmware defaults to high power mode policy where modules are
* transitioned to high power mode following plug-in.
*/
for (i = 0; i < module_count; i++)
env->module_info[i].power_mode_policy =
ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH;
mutex_init(&env->module_info_lock);
env->core = mlxsw_core;
env->module_count = module_count;
env->num_of_slots = num_of_slots + 1;
env->max_module_count = max_module_count;
err = mlxsw_env_line_cards_alloc(env);
if (err)
goto err_mlxsw_env_line_cards_alloc;
mutex_init(&env->line_cards_lock);
*p_env = env;
err = mlxsw_env_temp_warn_event_register(mlxsw_core);
......@@ -1127,6 +1216,10 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
if (err)
goto err_module_plug_event_register;
/* Set 'module_count' only for main board. Actual count for line card
* is to be set after line card is activated.
*/
env->line_cards[0]->module_count = num_of_slots ? 0 : module_count;
err = mlxsw_env_module_oper_state_event_enable(mlxsw_core, 0);
if (err)
goto err_oper_state_event_enable;
......@@ -1148,7 +1241,9 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
err_module_plug_event_register:
mlxsw_env_temp_warn_event_unregister(env);
err_temp_warn_event_register:
mutex_destroy(&env->module_info_lock);
mutex_destroy(&env->line_cards_lock);
mlxsw_env_line_cards_free(env);
err_mlxsw_env_line_cards_alloc:
kfree(env);
return err;
}
......@@ -1159,6 +1254,7 @@ void mlxsw_env_fini(struct mlxsw_env *env)
/* Make sure there is no more event work scheduled. */
mlxsw_core_flush_owq();
mlxsw_env_temp_warn_event_unregister(env);
mutex_destroy(&env->module_info_lock);
mutex_destroy(&env->line_cards_lock);
mlxsw_env_line_cards_free(env);
kfree(env);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment