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 { ...@@ -21,20 +21,36 @@ struct mlxsw_env_module_info {
enum mlxsw_reg_pmtm_module_type type; enum mlxsw_reg_pmtm_module_type type;
}; };
struct mlxsw_env { struct mlxsw_env_line_card {
struct mlxsw_core *core;
u8 module_count; u8 module_count;
struct mutex module_info_lock; /* Protects 'module_info'. */
struct mlxsw_env_module_info 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, static int __mlxsw_env_validate_module_type(struct mlxsw_core *core,
u8 slot_index, u8 module) u8 slot_index, u8 module)
{ {
struct mlxsw_env *mlxsw_env = mlxsw_core_env(core); struct mlxsw_env_module_info *module_info;
int err; 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: case MLXSW_REG_PMTM_MODULE_TYPE_TWISTED_PAIR:
err = -EINVAL; err = -EINVAL;
break; break;
...@@ -51,9 +67,9 @@ static int mlxsw_env_validate_module_type(struct mlxsw_core *core, ...@@ -51,9 +67,9 @@ static int mlxsw_env_validate_module_type(struct mlxsw_core *core,
struct mlxsw_env *mlxsw_env = mlxsw_core_env(core); struct mlxsw_env *mlxsw_env = mlxsw_core_env(core);
int err; 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); 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; return err;
} }
...@@ -472,6 +488,7 @@ int mlxsw_env_reset_module(struct net_device *netdev, ...@@ -472,6 +488,7 @@ int mlxsw_env_reset_module(struct net_device *netdev,
u8 module, u32 *flags) u8 module, u32 *flags)
{ {
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
struct mlxsw_env_module_info *module_info;
u32 req = *flags; u32 req = *flags;
int err; int err;
...@@ -479,7 +496,7 @@ int mlxsw_env_reset_module(struct net_device *netdev, ...@@ -479,7 +496,7 @@ int mlxsw_env_reset_module(struct net_device *netdev,
!(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)))
return 0; 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); err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
if (err) { if (err) {
...@@ -487,13 +504,14 @@ int mlxsw_env_reset_module(struct net_device *netdev, ...@@ -487,13 +504,14 @@ int mlxsw_env_reset_module(struct net_device *netdev,
goto out; 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"); netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n");
err = -EINVAL; err = -EINVAL;
goto out; 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))) { !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) {
netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n"); netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n");
err = -EINVAL; err = -EINVAL;
...@@ -509,7 +527,7 @@ int mlxsw_env_reset_module(struct net_device *netdev, ...@@ -509,7 +527,7 @@ int mlxsw_env_reset_module(struct net_device *netdev,
*flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)); *flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT));
out: out:
mutex_unlock(&mlxsw_env->module_info_lock); mutex_unlock(&mlxsw_env->line_cards_lock);
return err; return err;
} }
EXPORT_SYMBOL(mlxsw_env_reset_module); EXPORT_SYMBOL(mlxsw_env_reset_module);
...@@ -521,11 +539,12 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, ...@@ -521,11 +539,12 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
struct mlxsw_env_module_info *module_info;
char mcion_pl[MLXSW_REG_MCION_LEN]; char mcion_pl[MLXSW_REG_MCION_LEN];
u32 status_bits; u32 status_bits;
int err; 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); err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
if (err) { if (err) {
...@@ -533,7 +552,8 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, ...@@ -533,7 +552,8 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
goto out; 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); mlxsw_reg_mcion_pack(mcion_pl, slot_index, module);
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl); 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, ...@@ -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; params->mode = ETHTOOL_MODULE_POWER_MODE_HIGH;
out: out:
mutex_unlock(&mlxsw_env->module_info_lock); mutex_unlock(&mlxsw_env->line_cards_lock);
return err; return err;
} }
EXPORT_SYMBOL(mlxsw_env_get_module_power_mode); 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, ...@@ -634,6 +654,7 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
struct mlxsw_env_module_info *module_info;
bool low_power; bool low_power;
int err = 0; int err = 0;
...@@ -643,7 +664,7 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, ...@@ -643,7 +664,7 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
return -EOPNOTSUPP; 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); err = __mlxsw_env_validate_module_type(mlxsw_core, slot_index, module);
if (err) { if (err) {
...@@ -652,11 +673,12 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, ...@@ -652,11 +673,12 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
goto out; 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; goto out;
/* If any ports are up, we are already in high power mode. */ /* 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; goto out_set_policy;
low_power = policy == ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO; 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, ...@@ -666,9 +688,9 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index,
goto out; goto out;
out_set_policy: out_set_policy:
mlxsw_env->module_info[module].power_mode_policy = policy; module_info->power_mode_policy = policy;
out: out:
mutex_unlock(&mlxsw_env->module_info_lock); mutex_unlock(&mlxsw_env->line_cards_lock);
return err; return err;
} }
EXPORT_SYMBOL(mlxsw_env_set_module_power_mode); 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, ...@@ -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, static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core,
u8 slot_index) u8 slot_index)
{ {
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
int i, err, sensor_index; int i, err, sensor_index;
bool has_temp_sensor; 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, err = mlxsw_env_module_has_temp_sensor(mlxsw_core, slot_index,
i, &has_temp_sensor); i, &has_temp_sensor);
if (err) if (err)
...@@ -779,6 +802,7 @@ struct mlxsw_env_module_temp_warn_event { ...@@ -779,6 +802,7 @@ struct mlxsw_env_module_temp_warn_event {
static void mlxsw_env_mtwe_event_work(struct work_struct *work) static void mlxsw_env_mtwe_event_work(struct work_struct *work)
{ {
struct mlxsw_env_module_temp_warn_event *event; struct mlxsw_env_module_temp_warn_event *event;
struct mlxsw_env_module_info *module_info;
struct mlxsw_env *mlxsw_env; struct mlxsw_env *mlxsw_env;
int i, sensor_warning; int i, sensor_warning;
bool is_overheat; bool is_overheat;
...@@ -787,7 +811,7 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work) ...@@ -787,7 +811,7 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work)
work); work);
mlxsw_env = event->mlxsw_env; 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 /* 64-127 of sensor_index are mapped to the port modules
* sequentially (module 0 is mapped to sensor_index 64, * sequentially (module 0 is mapped to sensor_index 64,
* module 1 to sensor_index 65 and so on) * module 1 to sensor_index 65 and so on)
...@@ -795,9 +819,10 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work) ...@@ -795,9 +819,10 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work)
sensor_warning = sensor_warning =
mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl, mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl,
i + MLXSW_REG_MTMP_MODULE_INDEX_MIN); i + MLXSW_REG_MTMP_MODULE_INDEX_MIN);
mutex_lock(&mlxsw_env->module_info_lock); mutex_lock(&mlxsw_env->line_cards_lock);
is_overheat = /* MTWE only supports main board. */
mlxsw_env->module_info[i].is_overheat; module_info = mlxsw_env_module_info_get(mlxsw_env->core, 0, i);
is_overheat = module_info->is_overheat;
if ((is_overheat && sensor_warning) || if ((is_overheat && sensor_warning) ||
(!is_overheat && !sensor_warning)) { (!is_overheat && !sensor_warning)) {
...@@ -805,21 +830,21 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work) ...@@ -805,21 +830,21 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work)
* warning OR current state in "no warning" and MTWE * warning OR current state in "no warning" and MTWE
* does not report warning. * does not report warning.
*/ */
mutex_unlock(&mlxsw_env->module_info_lock); mutex_unlock(&mlxsw_env->line_cards_lock);
continue; continue;
} else if (is_overheat && !sensor_warning) { } else if (is_overheat && !sensor_warning) {
/* MTWE reports "no warning", turn is_overheat off. /* MTWE reports "no warning", turn is_overheat off.
*/ */
mlxsw_env->module_info[i].is_overheat = false; module_info->is_overheat = false;
mutex_unlock(&mlxsw_env->module_info_lock); mutex_unlock(&mlxsw_env->line_cards_lock);
} else { } else {
/* Current state is "no warning" and MTWE reports /* Current state is "no warning" and MTWE reports
* "warning", increase the counter and turn is_overheat * "warning", increase the counter and turn is_overheat
* on. * on.
*/ */
mlxsw_env->module_info[i].is_overheat = true; module_info->is_overheat = true;
mlxsw_env->module_info[i].module_overheat_counter++; module_info->module_overheat_counter++;
mutex_unlock(&mlxsw_env->module_info_lock); mutex_unlock(&mlxsw_env->line_cards_lock);
} }
} }
...@@ -871,6 +896,7 @@ struct mlxsw_env_module_plug_unplug_event { ...@@ -871,6 +896,7 @@ struct mlxsw_env_module_plug_unplug_event {
static void mlxsw_env_pmpe_event_work(struct work_struct *work) static void mlxsw_env_pmpe_event_work(struct work_struct *work)
{ {
struct mlxsw_env_module_plug_unplug_event *event; struct mlxsw_env_module_plug_unplug_event *event;
struct mlxsw_env_module_info *module_info;
struct mlxsw_env *mlxsw_env; struct mlxsw_env *mlxsw_env;
bool has_temp_sensor; bool has_temp_sensor;
u16 sensor_index; u16 sensor_index;
...@@ -880,9 +906,12 @@ static void mlxsw_env_pmpe_event_work(struct work_struct *work) ...@@ -880,9 +906,12 @@ static void mlxsw_env_pmpe_event_work(struct work_struct *work)
work); work);
mlxsw_env = event->mlxsw_env; mlxsw_env = event->mlxsw_env;
mutex_lock(&mlxsw_env->module_info_lock); mutex_lock(&mlxsw_env->line_cards_lock);
mlxsw_env->module_info[event->module].is_overheat = false; module_info = mlxsw_env_module_info_get(mlxsw_env->core,
mutex_unlock(&mlxsw_env->module_info_lock); 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, err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core,
event->slot_index, event->slot_index,
...@@ -909,12 +938,14 @@ static void ...@@ -909,12 +938,14 @@ static void
mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl, mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl,
void *priv) void *priv)
{ {
u8 slot_index = mlxsw_reg_pmpe_slot_index_get(pmpe_pl);
struct mlxsw_env_module_plug_unplug_event *event; struct mlxsw_env_module_plug_unplug_event *event;
enum mlxsw_reg_pmpe_module_status module_status; enum mlxsw_reg_pmpe_module_status module_status;
u8 module = mlxsw_reg_pmpe_module_get(pmpe_pl); u8 module = mlxsw_reg_pmpe_module_get(pmpe_pl);
struct mlxsw_env *mlxsw_env = priv; 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; return;
module_status = mlxsw_reg_pmpe_module_status_get(pmpe_pl); 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, ...@@ -926,7 +957,7 @@ mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl,
return; return;
event->mlxsw_env = mlxsw_env; event->mlxsw_env = mlxsw_env;
event->slot_index = 0; event->slot_index = slot_index;
event->module = module; event->module = module;
INIT_WORK(&event->work, mlxsw_env_pmpe_event_work); INIT_WORK(&event->work, mlxsw_env_pmpe_event_work);
mlxsw_core_schedule_work(&event->work); mlxsw_core_schedule_work(&event->work);
...@@ -957,9 +988,10 @@ static int ...@@ -957,9 +988,10 @@ static int
mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core, mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core,
u8 slot_index) u8 slot_index)
{ {
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
int i, err; 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]; char pmaos_pl[MLXSW_REG_PMAOS_LEN];
mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, i); 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 ...@@ -978,10 +1010,12 @@ mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 slot_ind
u8 module, u64 *p_counter) u8 module, u64 *p_counter)
{ {
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 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);
*p_counter = mlxsw_env->module_info[module].module_overheat_counter; module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
mutex_unlock(&mlxsw_env->module_info_lock); *p_counter = module_info->module_overheat_counter;
mutex_unlock(&mlxsw_env->line_cards_lock);
return 0; return 0;
} }
...@@ -991,10 +1025,12 @@ void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 slot_index, ...@@ -991,10 +1025,12 @@ void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 slot_index,
u8 module) u8 module)
{ {
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 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_mapped++; module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
mutex_unlock(&mlxsw_env->module_info_lock); module_info->num_ports_mapped++;
mutex_unlock(&mlxsw_env->line_cards_lock);
} }
EXPORT_SYMBOL(mlxsw_env_module_port_map); 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, ...@@ -1002,10 +1038,12 @@ void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 slot_index,
u8 module) u8 module)
{ {
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 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_mapped--; module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module);
mutex_unlock(&mlxsw_env->module_info_lock); module_info->num_ports_mapped--;
mutex_unlock(&mlxsw_env->line_cards_lock);
} }
EXPORT_SYMBOL(mlxsw_env_module_port_unmap); 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, ...@@ -1013,15 +1051,17 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index,
u8 module) u8 module)
{ {
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
struct mlxsw_env_module_info *module_info;
int err = 0; 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) ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
goto out_inc; goto out_inc;
if (mlxsw_env->module_info[module].num_ports_up != 0) if (module_info->num_ports_up != 0)
goto out_inc; goto out_inc;
/* Transition to high power mode following first port using the module /* 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, ...@@ -1033,9 +1073,9 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index,
goto out_unlock; goto out_unlock;
out_inc: out_inc:
mlxsw_env->module_info[module].num_ports_up++; module_info->num_ports_up++;
out_unlock: out_unlock:
mutex_unlock(&mlxsw_env->module_info_lock); mutex_unlock(&mlxsw_env->line_cards_lock);
return err; return err;
} }
EXPORT_SYMBOL(mlxsw_env_module_port_up); 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, ...@@ -1044,16 +1084,18 @@ void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index,
u8 module) u8 module)
{ {
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); 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) ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO)
goto out_unlock; goto out_unlock;
if (mlxsw_env->module_info[module].num_ports_up != 0) if (module_info->num_ports_up != 0)
goto out_unlock; goto out_unlock;
/* Transition to low power mode following last port using the module /* 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, ...@@ -1063,17 +1105,57 @@ void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index,
NULL); NULL);
out_unlock: out_unlock:
mutex_unlock(&mlxsw_env->module_info_lock); mutex_unlock(&mlxsw_env->line_cards_lock);
} }
EXPORT_SYMBOL(mlxsw_env_module_port_down); 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 static int
mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core, u8 slot_index) mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core, u8 slot_index)
{ {
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
int i; 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]; char pmtm_pl[MLXSW_REG_PMTM_LEN];
int err; int err;
...@@ -1082,8 +1164,9 @@ mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core, u8 slot_index) ...@@ -1082,8 +1164,9 @@ mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core, u8 slot_index)
if (err) if (err)
return err; return err;
mlxsw_env->module_info[i].type = module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index,
mlxsw_reg_pmtm_module_type_get(pmtm_pl); i);
module_info->type = mlxsw_reg_pmtm_module_type_get(pmtm_pl);
} }
return 0; return 0;
...@@ -1091,32 +1174,38 @@ mlxsw_env_module_type_set(struct mlxsw_core *mlxsw_core, u8 slot_index) ...@@ -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) 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]; char mgpir_pl[MLXSW_REG_MGPIR_LEN];
struct mlxsw_env *env; struct mlxsw_env *env;
u8 module_count; int err;
int i, err;
mlxsw_reg_mgpir_pack(mgpir_pl, 0); mlxsw_reg_mgpir_pack(mgpir_pl, 0);
err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl); err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl);
if (err) if (err)
return 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) if (!env)
return -ENOMEM; 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->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; *p_env = env;
err = mlxsw_env_temp_warn_event_register(mlxsw_core); 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) ...@@ -1127,6 +1216,10 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
if (err) if (err)
goto err_module_plug_event_register; 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); err = mlxsw_env_module_oper_state_event_enable(mlxsw_core, 0);
if (err) if (err)
goto err_oper_state_event_enable; goto err_oper_state_event_enable;
...@@ -1148,7 +1241,9 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) ...@@ -1148,7 +1241,9 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
err_module_plug_event_register: err_module_plug_event_register:
mlxsw_env_temp_warn_event_unregister(env); mlxsw_env_temp_warn_event_unregister(env);
err_temp_warn_event_register: 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); kfree(env);
return err; return err;
} }
...@@ -1159,6 +1254,7 @@ void mlxsw_env_fini(struct mlxsw_env *env) ...@@ -1159,6 +1254,7 @@ void mlxsw_env_fini(struct mlxsw_env *env)
/* Make sure there is no more event work scheduled. */ /* Make sure there is no more event work scheduled. */
mlxsw_core_flush_owq(); mlxsw_core_flush_owq();
mlxsw_env_temp_warn_event_unregister(env); 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); 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