Skip to content

Commit b33f3d2

Browse files
sgruszkarafaeljw
authored andcommitted
thermal: intel: hfi: Enable HFI only when required
Enable and disable hardware feedback interface (HFI) when user space handler is present. For example, enable HFI, when intel-speed-select or Intel Low Power daemon is running and subscribing to thermal netlink events. When user space handlers exit or remove subscription for thermal netlink events, disable HFI. Summary of changes: - Register a thermal genetlink notifier - In the notifier, process THERMAL_NOTIFY_BIND and THERMAL_NOTIFY_UNBIND reason codes to count number of thermal event group netlink multicast clients. If thermal netlink group has any listener enable HFI on all packages. If there are no listener disable HFI on all packages. - When CPU is online, instead of blindly enabling HFI, check if the thermal netlink group has any listener. This will make sure that HFI is not enabled by default during boot time. - Actual processing to enable/disable matches what is done in suspend/resume callbacks. Create two functions hfi_enable_instance() and hfi_disable_instance(), which can be called from the netlink notifier callback and suspend/resume callbacks. Signed-off-by: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent afdaff3 commit b33f3d2

File tree

1 file changed

+89
-8
lines changed

1 file changed

+89
-8
lines changed

drivers/thermal/intel/intel_hfi.c

Lines changed: 89 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ struct hfi_cpu_info {
159159
static DEFINE_PER_CPU(struct hfi_cpu_info, hfi_cpu_info) = { .index = -1 };
160160

161161
static int max_hfi_instances;
162+
static int hfi_clients_nr;
162163
static struct hfi_instance *hfi_instances;
163164

164165
static struct hfi_features hfi_features;
@@ -477,8 +478,11 @@ void intel_hfi_online(unsigned int cpu)
477478
enable:
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

595614
static 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

600669
void __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+
635716
err_nomem:
636717
for (j = 0; j < i; ++j) {
637718
hfi_instance = &hfi_instances[j];

0 commit comments

Comments
 (0)