@@ -159,6 +159,7 @@ struct hfi_cpu_info {
159159static DEFINE_PER_CPU (struct hfi_cpu_info , hfi_cpu_info ) = { .index = -1 };
160160
161161static int max_hfi_instances ;
162+ static int hfi_clients_nr ;
162163static struct hfi_instance * hfi_instances ;
163164
164165static struct hfi_features hfi_features ;
@@ -477,8 +478,11 @@ void intel_hfi_online(unsigned int cpu)
477478enable :
478479 cpumask_set_cpu (cpu , hfi_instance -> cpus );
479480
480- /* Enable this HFI instance if this is its first online CPU. */
481- if (cpumask_weight (hfi_instance -> cpus ) == 1 ) {
481+ /*
482+ * Enable this HFI instance if this is its first online CPU and
483+ * there are user-space clients of thermal events.
484+ */
485+ if (cpumask_weight (hfi_instance -> cpus ) == 1 && hfi_clients_nr > 0 ) {
482486 hfi_set_hw_table (hfi_instance );
483487 hfi_enable ();
484488 }
@@ -573,18 +577,33 @@ static __init int hfi_parse_features(void)
573577 return 0 ;
574578}
575579
576- static void hfi_do_enable (void )
580+ /*
581+ * If concurrency is not prevented by other means, the HFI enable/disable
582+ * routines must be called under hfi_instance_lock."
583+ */
584+ static void hfi_enable_instance (void * ptr )
585+ {
586+ hfi_set_hw_table (ptr );
587+ hfi_enable ();
588+ }
589+
590+ static void hfi_disable_instance (void * ptr )
591+ {
592+ hfi_disable ();
593+ }
594+
595+ static void hfi_syscore_resume (void )
577596{
578597 /* This code runs only on the boot CPU. */
579598 struct hfi_cpu_info * info = & per_cpu (hfi_cpu_info , 0 );
580599 struct hfi_instance * hfi_instance = info -> hfi_instance ;
581600
582601 /* No locking needed. There is no concurrency with CPU online. */
583- hfi_set_hw_table ( hfi_instance );
584- hfi_enable ( );
602+ if ( hfi_clients_nr > 0 )
603+ hfi_enable_instance ( hfi_instance );
585604}
586605
587- static int hfi_do_disable (void )
606+ static int hfi_syscore_suspend (void )
588607{
589608 /* No locking needed. There is no concurrency with CPU offline. */
590609 hfi_disable ();
@@ -593,8 +612,58 @@ static int hfi_do_disable(void)
593612}
594613
595614static struct syscore_ops hfi_pm_ops = {
596- .resume = hfi_do_enable ,
597- .suspend = hfi_do_disable ,
615+ .resume = hfi_syscore_resume ,
616+ .suspend = hfi_syscore_suspend ,
617+ };
618+
619+ static int hfi_thermal_notify (struct notifier_block * nb , unsigned long state ,
620+ void * _notify )
621+ {
622+ struct thermal_genl_notify * notify = _notify ;
623+ struct hfi_instance * hfi_instance ;
624+ smp_call_func_t func = NULL ;
625+ unsigned int cpu ;
626+ int i ;
627+
628+ if (notify -> mcgrp != THERMAL_GENL_EVENT_GROUP )
629+ return NOTIFY_DONE ;
630+
631+ if (state != THERMAL_NOTIFY_BIND && state != THERMAL_NOTIFY_UNBIND )
632+ return NOTIFY_DONE ;
633+
634+ mutex_lock (& hfi_instance_lock );
635+
636+ switch (state ) {
637+ case THERMAL_NOTIFY_BIND :
638+ if (++ hfi_clients_nr == 1 )
639+ func = hfi_enable_instance ;
640+ break ;
641+ case THERMAL_NOTIFY_UNBIND :
642+ if (-- hfi_clients_nr == 0 )
643+ func = hfi_disable_instance ;
644+ break ;
645+ }
646+
647+ if (!func )
648+ goto out ;
649+
650+ for (i = 0 ; i < max_hfi_instances ; i ++ ) {
651+ hfi_instance = & hfi_instances [i ];
652+ if (cpumask_empty (hfi_instance -> cpus ))
653+ continue ;
654+
655+ cpu = cpumask_any (hfi_instance -> cpus );
656+ smp_call_function_single (cpu , func , hfi_instance , true);
657+ }
658+
659+ out :
660+ mutex_unlock (& hfi_instance_lock );
661+
662+ return NOTIFY_OK ;
663+ }
664+
665+ static struct notifier_block hfi_thermal_nb = {
666+ .notifier_call = hfi_thermal_notify ,
598667};
599668
600669void __init intel_hfi_init (void )
@@ -628,10 +697,22 @@ void __init intel_hfi_init(void)
628697 if (!hfi_updates_wq )
629698 goto err_nomem ;
630699
700+ /*
701+ * Both thermal core and Intel HFI can not be build as modules.
702+ * As kernel build-in drivers they are initialized before user-space
703+ * starts, hence we can not miss BIND/UNBIND events when applications
704+ * add/remove thermal multicast group to/from a netlink socket.
705+ */
706+ if (thermal_genl_register_notifier (& hfi_thermal_nb ))
707+ goto err_nl_notif ;
708+
631709 register_syscore_ops (& hfi_pm_ops );
632710
633711 return ;
634712
713+ err_nl_notif :
714+ destroy_workqueue (hfi_updates_wq );
715+
635716err_nomem :
636717 for (j = 0 ; j < i ; ++ j ) {
637718 hfi_instance = & hfi_instances [j ];
0 commit comments