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"
1415struct 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
1922struct 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}
390393EXPORT_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+
392448static 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
529614static 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
532617static 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}
685766EXPORT_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+
687822int 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)
732867err_module_plug_event_register :
733868 mlxsw_env_temp_warn_event_unregister (env );
734869err_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