Skip to content

Commit 5706383

Browse files
committed
Merge branch 'mlxsw-Add-support-for-transceiver-modules-reset'
Ido Schimmel says: ==================== mlxsw: Add support for transceiver modules reset This patchset prepares mlxsw for future transceiver modules related [1] changes and adds reset support via the existing 'ETHTOOL_RESET' interface. Patches #1-#6 are relatively straightforward preparations. Patch #7 tracks the number of logical ports that are mapped to the transceiver module and the number of logical ports using it that are administratively up. Needed for both reset support and power mode policy support. Patches #8-#9 add required fields in device registers. Patch #10 implements support for ethtool_ops::reset in order to reset transceiver modules. [1] https://lore.kernel.org/netdev/[email protected]/ ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 0013522 + 49fd3b6 commit 5706383

File tree

8 files changed

+281
-58
lines changed

8 files changed

+281
-58
lines changed

drivers/net/ethernet/mellanox/mlxsw/core.c

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ struct mlxsw_core {
9090
struct devlink_health_reporter *fw_fatal;
9191
} health;
9292
struct mlxsw_env *env;
93-
bool is_initialized; /* Denotes if core was already initialized. */
9493
unsigned long driver_priv[];
9594
/* driver_priv has to be always the last item */
9695
};
@@ -1995,12 +1994,6 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
19951994
if (err)
19961995
goto err_health_init;
19971996

1998-
if (mlxsw_driver->init) {
1999-
err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info, extack);
2000-
if (err)
2001-
goto err_driver_init;
2002-
}
2003-
20041997
err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon);
20051998
if (err)
20061999
goto err_hwmon_init;
@@ -2014,22 +2007,26 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
20142007
if (err)
20152008
goto err_env_init;
20162009

2017-
mlxsw_core->is_initialized = true;
2010+
if (mlxsw_driver->init) {
2011+
err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info, extack);
2012+
if (err)
2013+
goto err_driver_init;
2014+
}
2015+
20182016
devlink_params_publish(devlink);
20192017

20202018
if (!reload)
20212019
devlink_reload_enable(devlink);
20222020

20232021
return 0;
20242022

2023+
err_driver_init:
2024+
mlxsw_env_fini(mlxsw_core->env);
20252025
err_env_init:
20262026
mlxsw_thermal_fini(mlxsw_core->thermal);
20272027
err_thermal_init:
20282028
mlxsw_hwmon_fini(mlxsw_core->hwmon);
20292029
err_hwmon_init:
2030-
if (mlxsw_core->driver->fini)
2031-
mlxsw_core->driver->fini(mlxsw_core);
2032-
err_driver_init:
20332030
mlxsw_core_health_fini(mlxsw_core);
20342031
err_health_init:
20352032
err_fw_rev_validate:
@@ -2100,12 +2097,11 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
21002097
}
21012098

21022099
devlink_params_unpublish(devlink);
2103-
mlxsw_core->is_initialized = false;
2100+
if (mlxsw_core->driver->fini)
2101+
mlxsw_core->driver->fini(mlxsw_core);
21042102
mlxsw_env_fini(mlxsw_core->env);
21052103
mlxsw_thermal_fini(mlxsw_core->thermal);
21062104
mlxsw_hwmon_fini(mlxsw_core->hwmon);
2107-
if (mlxsw_core->driver->fini)
2108-
mlxsw_core->driver->fini(mlxsw_core);
21092105
mlxsw_core_health_fini(mlxsw_core);
21102106
if (!reload)
21112107
mlxsw_core_params_unregister(mlxsw_core);
@@ -2939,11 +2935,6 @@ struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core)
29392935
return mlxsw_core->env;
29402936
}
29412937

2942-
bool mlxsw_core_is_initialized(const struct mlxsw_core *mlxsw_core)
2943-
{
2944-
return mlxsw_core->is_initialized;
2945-
}
2946-
29472938
static void mlxsw_core_buf_dump_dbg(struct mlxsw_core *mlxsw_core,
29482939
const char *buf, size_t size)
29492940
{

drivers/net/ethernet/mellanox/mlxsw/core.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,6 @@ mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core,
249249
u8 local_port);
250250
bool mlxsw_core_port_is_xm(const struct mlxsw_core *mlxsw_core, u8 local_port);
251251
struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core);
252-
bool mlxsw_core_is_initialized(const struct mlxsw_core *mlxsw_core);
253252

254253
int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay);
255254
bool mlxsw_core_schedule_work(struct work_struct *work);

drivers/net/ethernet/mellanox/mlxsw/core_env.c

Lines changed: 160 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <linux/err.h>
66
#include <linux/ethtool.h>
77
#include <linux/sfp.h>
8+
#include <linux/mutex.h>
89

910
#include "core.h"
1011
#include "core_env.h"
@@ -14,12 +15,14 @@
1415
struct mlxsw_env_module_info {
1516
u64 module_overheat_counter;
1617
bool is_overheat;
18+
int num_ports_mapped;
19+
int num_ports_up;
1720
};
1821

1922
struct mlxsw_env {
2023
struct mlxsw_core *core;
2124
u8 module_count;
22-
spinlock_t module_info_lock; /* Protects 'module_info'. */
25+
struct mutex module_info_lock; /* Protects 'module_info'. */
2326
struct mlxsw_env_module_info module_info[];
2427
};
2528

@@ -389,6 +392,59 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
389392
}
390393
EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page);
391394

395+
static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 module)
396+
{
397+
char pmaos_pl[MLXSW_REG_PMAOS_LEN];
398+
399+
mlxsw_reg_pmaos_pack(pmaos_pl, module);
400+
mlxsw_reg_pmaos_rst_set(pmaos_pl, true);
401+
402+
return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
403+
}
404+
405+
int mlxsw_env_reset_module(struct net_device *netdev,
406+
struct mlxsw_core *mlxsw_core, u8 module, u32 *flags)
407+
{
408+
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
409+
u32 req = *flags;
410+
int err;
411+
412+
if (!(req & ETH_RESET_PHY) &&
413+
!(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)))
414+
return 0;
415+
416+
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
417+
return -EINVAL;
418+
419+
mutex_lock(&mlxsw_env->module_info_lock);
420+
421+
if (mlxsw_env->module_info[module].num_ports_up) {
422+
netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n");
423+
err = -EINVAL;
424+
goto out;
425+
}
426+
427+
if (mlxsw_env->module_info[module].num_ports_mapped > 1 &&
428+
!(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) {
429+
netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n");
430+
err = -EINVAL;
431+
goto out;
432+
}
433+
434+
err = mlxsw_env_module_reset(mlxsw_core, module);
435+
if (err) {
436+
netdev_err(netdev, "Failed to reset module\n");
437+
goto out;
438+
}
439+
440+
*flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT));
441+
442+
out:
443+
mutex_unlock(&mlxsw_env->module_info_lock);
444+
return err;
445+
}
446+
EXPORT_SYMBOL(mlxsw_env_reset_module);
447+
392448
static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core,
393449
u8 module,
394450
bool *p_has_temp_sensor)
@@ -482,22 +538,32 @@ static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core,
482538
return 0;
483539
}
484540

485-
static void mlxsw_env_mtwe_event_func(const struct mlxsw_reg_info *reg,
486-
char *mtwe_pl, void *priv)
541+
struct mlxsw_env_module_temp_warn_event {
542+
struct mlxsw_env *mlxsw_env;
543+
char mtwe_pl[MLXSW_REG_MTWE_LEN];
544+
struct work_struct work;
545+
};
546+
547+
static void mlxsw_env_mtwe_event_work(struct work_struct *work)
487548
{
488-
struct mlxsw_env *mlxsw_env = priv;
549+
struct mlxsw_env_module_temp_warn_event *event;
550+
struct mlxsw_env *mlxsw_env;
489551
int i, sensor_warning;
490552
bool is_overheat;
491553

554+
event = container_of(work, struct mlxsw_env_module_temp_warn_event,
555+
work);
556+
mlxsw_env = event->mlxsw_env;
557+
492558
for (i = 0; i < mlxsw_env->module_count; i++) {
493559
/* 64-127 of sensor_index are mapped to the port modules
494560
* sequentially (module 0 is mapped to sensor_index 64,
495561
* module 1 to sensor_index 65 and so on)
496562
*/
497563
sensor_warning =
498-
mlxsw_reg_mtwe_sensor_warning_get(mtwe_pl,
564+
mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl,
499565
i + MLXSW_REG_MTMP_MODULE_INDEX_MIN);
500-
spin_lock(&mlxsw_env->module_info_lock);
566+
mutex_lock(&mlxsw_env->module_info_lock);
501567
is_overheat =
502568
mlxsw_env->module_info[i].is_overheat;
503569

@@ -507,27 +573,46 @@ static void mlxsw_env_mtwe_event_func(const struct mlxsw_reg_info *reg,
507573
* warning OR current state in "no warning" and MTWE
508574
* does not report warning.
509575
*/
510-
spin_unlock(&mlxsw_env->module_info_lock);
576+
mutex_unlock(&mlxsw_env->module_info_lock);
511577
continue;
512578
} else if (is_overheat && !sensor_warning) {
513579
/* MTWE reports "no warning", turn is_overheat off.
514580
*/
515581
mlxsw_env->module_info[i].is_overheat = false;
516-
spin_unlock(&mlxsw_env->module_info_lock);
582+
mutex_unlock(&mlxsw_env->module_info_lock);
517583
} else {
518584
/* Current state is "no warning" and MTWE reports
519585
* "warning", increase the counter and turn is_overheat
520586
* on.
521587
*/
522588
mlxsw_env->module_info[i].is_overheat = true;
523589
mlxsw_env->module_info[i].module_overheat_counter++;
524-
spin_unlock(&mlxsw_env->module_info_lock);
590+
mutex_unlock(&mlxsw_env->module_info_lock);
525591
}
526592
}
593+
594+
kfree(event);
595+
}
596+
597+
static void
598+
mlxsw_env_mtwe_listener_func(const struct mlxsw_reg_info *reg, char *mtwe_pl,
599+
void *priv)
600+
{
601+
struct mlxsw_env_module_temp_warn_event *event;
602+
struct mlxsw_env *mlxsw_env = priv;
603+
604+
event = kmalloc(sizeof(*event), GFP_ATOMIC);
605+
if (!event)
606+
return;
607+
608+
event->mlxsw_env = mlxsw_env;
609+
memcpy(event->mtwe_pl, mtwe_pl, MLXSW_REG_MTWE_LEN);
610+
INIT_WORK(&event->work, mlxsw_env_mtwe_event_work);
611+
mlxsw_core_schedule_work(&event->work);
527612
}
528613

529614
static const struct mlxsw_listener mlxsw_env_temp_warn_listener =
530-
MLXSW_EVENTL(mlxsw_env_mtwe_event_func, MTWE, MTWE);
615+
MLXSW_EVENTL(mlxsw_env_mtwe_listener_func, MTWE, MTWE);
531616

532617
static int mlxsw_env_temp_warn_event_register(struct mlxsw_core *mlxsw_core)
533618
{
@@ -568,9 +653,9 @@ static void mlxsw_env_pmpe_event_work(struct work_struct *work)
568653
work);
569654
mlxsw_env = event->mlxsw_env;
570655

571-
spin_lock_bh(&mlxsw_env->module_info_lock);
656+
mutex_lock(&mlxsw_env->module_info_lock);
572657
mlxsw_env->module_info[event->module].is_overheat = false;
573-
spin_unlock_bh(&mlxsw_env->module_info_lock);
658+
mutex_unlock(&mlxsw_env->module_info_lock);
574659

575660
err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, event->module,
576661
&has_temp_sensor);
@@ -652,8 +737,10 @@ mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core,
652737
for (i = 0; i < module_count; i++) {
653738
char pmaos_pl[MLXSW_REG_PMAOS_LEN];
654739

655-
mlxsw_reg_pmaos_pack(pmaos_pl, i,
656-
MLXSW_REG_PMAOS_E_GENERATE_EVENT);
740+
mlxsw_reg_pmaos_pack(pmaos_pl, i);
741+
mlxsw_reg_pmaos_e_set(pmaos_pl,
742+
MLXSW_REG_PMAOS_E_GENERATE_EVENT);
743+
mlxsw_reg_pmaos_ee_set(pmaos_pl, true);
657744
err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl);
658745
if (err)
659746
return err;
@@ -667,23 +754,71 @@ mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module,
667754
{
668755
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
669756

670-
/* Prevent switch driver from accessing uninitialized data. */
671-
if (!mlxsw_core_is_initialized(mlxsw_core)) {
672-
*p_counter = 0;
673-
return 0;
674-
}
675-
676757
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
677758
return -EINVAL;
678759

679-
spin_lock_bh(&mlxsw_env->module_info_lock);
760+
mutex_lock(&mlxsw_env->module_info_lock);
680761
*p_counter = mlxsw_env->module_info[module].module_overheat_counter;
681-
spin_unlock_bh(&mlxsw_env->module_info_lock);
762+
mutex_unlock(&mlxsw_env->module_info_lock);
682763

683764
return 0;
684765
}
685766
EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get);
686767

768+
void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module)
769+
{
770+
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
771+
772+
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
773+
return;
774+
775+
mutex_lock(&mlxsw_env->module_info_lock);
776+
mlxsw_env->module_info[module].num_ports_mapped++;
777+
mutex_unlock(&mlxsw_env->module_info_lock);
778+
}
779+
EXPORT_SYMBOL(mlxsw_env_module_port_map);
780+
781+
void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module)
782+
{
783+
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
784+
785+
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
786+
return;
787+
788+
mutex_lock(&mlxsw_env->module_info_lock);
789+
mlxsw_env->module_info[module].num_ports_mapped--;
790+
mutex_unlock(&mlxsw_env->module_info_lock);
791+
}
792+
EXPORT_SYMBOL(mlxsw_env_module_port_unmap);
793+
794+
int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module)
795+
{
796+
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
797+
798+
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
799+
return -EINVAL;
800+
801+
mutex_lock(&mlxsw_env->module_info_lock);
802+
mlxsw_env->module_info[module].num_ports_up++;
803+
mutex_unlock(&mlxsw_env->module_info_lock);
804+
805+
return 0;
806+
}
807+
EXPORT_SYMBOL(mlxsw_env_module_port_up);
808+
809+
void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module)
810+
{
811+
struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
812+
813+
if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
814+
return;
815+
816+
mutex_lock(&mlxsw_env->module_info_lock);
817+
mlxsw_env->module_info[module].num_ports_up--;
818+
mutex_unlock(&mlxsw_env->module_info_lock);
819+
}
820+
EXPORT_SYMBOL(mlxsw_env_module_port_down);
821+
687822
int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
688823
{
689824
char mgpir_pl[MLXSW_REG_MGPIR_LEN];
@@ -702,7 +837,7 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
702837
if (!env)
703838
return -ENOMEM;
704839

705-
spin_lock_init(&env->module_info_lock);
840+
mutex_init(&env->module_info_lock);
706841
env->core = mlxsw_core;
707842
env->module_count = module_count;
708843
*p_env = env;
@@ -732,6 +867,7 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
732867
err_module_plug_event_register:
733868
mlxsw_env_temp_warn_event_unregister(env);
734869
err_temp_warn_event_register:
870+
mutex_destroy(&env->module_info_lock);
735871
kfree(env);
736872
return err;
737873
}
@@ -742,5 +878,6 @@ void mlxsw_env_fini(struct mlxsw_env *env)
742878
/* Make sure there is no more event work scheduled. */
743879
mlxsw_core_flush_owq();
744880
mlxsw_env_temp_warn_event_unregister(env);
881+
mutex_destroy(&env->module_info_lock);
745882
kfree(env);
746883
}

0 commit comments

Comments
 (0)