Skip to content

Commit

Permalink
Merge branch 'pm-cpufreq-qos'
Browse files Browse the repository at this point in the history
* pm-cpufreq-qos:
  Documentation: cpufreq: Update policy notifier documentation
  cpufreq: Remove CPUFREQ_ADJUST and CPUFREQ_NOTIFY policy notifier events
  ACPI: cpufreq: Switch to QoS requests instead of cpufreq notifier
  video: pxafb: Remove cpufreq policy notifier
  video: sa1100fb: Remove cpufreq policy notifier
  arch_topology: Use CPUFREQ_CREATE_POLICY instead of CPUFREQ_NOTIFY
  cpufreq: powerpc_cbe: Switch to QoS requests for freq limits
  cpufreq: powerpc: macintosh: Switch to QoS requests for freq limits
  thermal: cpu_cooling: Switch to QoS requests for freq limits
  cpufreq: Add policy create/remove notifiers back
  • Loading branch information
rafaeljw committed Sep 5, 2019
2 parents 77c84dd + c27c38a commit beb4e08
Show file tree
Hide file tree
Showing 17 changed files with 322 additions and 360 deletions.
16 changes: 4 additions & 12 deletions Documentation/cpu-freq/core.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,11 @@ transition notifiers.
2.1 CPUFreq policy notifiers
----------------------------

These are notified when a new policy is intended to be set. Each
CPUFreq policy notifier is called twice for a policy transition:
These are notified when a new policy is created or removed.

1.) During CPUFREQ_ADJUST all CPUFreq notifiers may change the limit if
they see a need for this - may it be thermal considerations or
hardware limitations.

2.) And during CPUFREQ_NOTIFY all notifiers are informed of the new policy
- if two hardware drivers failed to agree on a new policy before this
stage, the incompatible hardware shall be shut down, and the user
informed of this.

The phase is specified in the second argument to the notifier.
The phase is specified in the second argument to the notifier. The phase is
CPUFREQ_CREATE_POLICY when the policy is first created and it is
CPUFREQ_REMOVE_POLICY when the policy is removed.

The third argument, a void *pointer, points to a struct cpufreq_policy
consisting of several values, including min, max (the lower and upper
Expand Down
39 changes: 35 additions & 4 deletions drivers/acpi/processor_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,29 @@ static int acpi_processor_stop(struct device *dev)
return 0;
}

bool acpi_processor_cpufreq_init;

static int acpi_processor_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
struct cpufreq_policy *policy = data;
int cpu = policy->cpu;

if (event == CPUFREQ_CREATE_POLICY) {
acpi_thermal_cpufreq_init(cpu);
acpi_processor_ppc_init(cpu);
} else if (event == CPUFREQ_REMOVE_POLICY) {
acpi_processor_ppc_exit(cpu);
acpi_thermal_cpufreq_exit(cpu);
}

return 0;
}

static struct notifier_block acpi_processor_notifier_block = {
.notifier_call = acpi_processor_notifier,
};

/*
* We keep the driver loaded even when ACPI is not running.
* This is needed for the powernow-k8 driver, that works even without
Expand All @@ -310,8 +333,12 @@ static int __init acpi_processor_driver_init(void)
cpuhp_setup_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD, "acpi/cpu-drv:dead",
NULL, acpi_soft_cpu_dead);

acpi_thermal_cpufreq_init();
acpi_processor_ppc_init();
if (!cpufreq_register_notifier(&acpi_processor_notifier_block,
CPUFREQ_POLICY_NOTIFIER)) {
acpi_processor_cpufreq_init = true;
acpi_processor_ignore_ppc_init();
}

acpi_processor_throttling_init();
return 0;
err:
Expand All @@ -324,8 +351,12 @@ static void __exit acpi_processor_driver_exit(void)
if (acpi_disabled)
return;

acpi_processor_ppc_exit();
acpi_thermal_cpufreq_exit();
if (acpi_processor_cpufreq_init) {
cpufreq_unregister_notifier(&acpi_processor_notifier_block,
CPUFREQ_POLICY_NOTIFIER);
acpi_processor_cpufreq_init = false;
}

cpuhp_remove_state_nocalls(hp_online);
cpuhp_remove_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD);
driver_unregister(&acpi_processor_driver);
Expand Down
100 changes: 38 additions & 62 deletions drivers/acpi/processor_perflib.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,57 +50,13 @@ module_param(ignore_ppc, int, 0644);
MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \
"limited by BIOS, this should help");

#define PPC_REGISTERED 1
#define PPC_IN_USE 2

static int acpi_processor_ppc_status;

static int acpi_processor_ppc_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
struct cpufreq_policy *policy = data;
struct acpi_processor *pr;
unsigned int ppc = 0;

if (ignore_ppc < 0)
ignore_ppc = 0;

if (ignore_ppc)
return 0;

if (event != CPUFREQ_ADJUST)
return 0;

mutex_lock(&performance_mutex);

pr = per_cpu(processors, policy->cpu);
if (!pr || !pr->performance)
goto out;

ppc = (unsigned int)pr->performance_platform_limit;

if (ppc >= pr->performance->state_count)
goto out;

cpufreq_verify_within_limits(policy, 0,
pr->performance->states[ppc].
core_frequency * 1000);

out:
mutex_unlock(&performance_mutex);

return 0;
}

static struct notifier_block acpi_ppc_notifier_block = {
.notifier_call = acpi_processor_ppc_notifier,
};
static bool acpi_processor_ppc_in_use;

static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
{
acpi_status status = 0;
unsigned long long ppc = 0;

int ret;

if (!pr)
return -EINVAL;
Expand All @@ -112,7 +68,7 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc);

if (status != AE_NOT_FOUND)
acpi_processor_ppc_status |= PPC_IN_USE;
acpi_processor_ppc_in_use = true;

if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PPC"));
Expand All @@ -124,6 +80,17 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)

pr->performance_platform_limit = (int)ppc;

if (ppc >= pr->performance->state_count ||
unlikely(!dev_pm_qos_request_active(&pr->perflib_req)))
return 0;

ret = dev_pm_qos_update_request(&pr->perflib_req,
pr->performance->states[ppc].core_frequency * 1000);
if (ret < 0) {
pr_warn("Failed to update perflib freq constraint: CPU%d (%d)\n",
pr->id, ret);
}

return 0;
}

Expand Down Expand Up @@ -184,23 +151,32 @@ int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
}
EXPORT_SYMBOL(acpi_processor_get_bios_limit);

void acpi_processor_ppc_init(void)
void acpi_processor_ignore_ppc_init(void)
{
if (!cpufreq_register_notifier
(&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER))
acpi_processor_ppc_status |= PPC_REGISTERED;
else
printk(KERN_DEBUG
"Warning: Processor Platform Limit not supported.\n");
if (ignore_ppc < 0)
ignore_ppc = 0;
}

void acpi_processor_ppc_init(int cpu)
{
struct acpi_processor *pr = per_cpu(processors, cpu);
int ret;

ret = dev_pm_qos_add_request(get_cpu_device(cpu),
&pr->perflib_req, DEV_PM_QOS_MAX_FREQUENCY,
INT_MAX);
if (ret < 0) {
pr_err("Failed to add freq constraint for CPU%d (%d)\n", cpu,
ret);
return;
}
}

void acpi_processor_ppc_exit(void)
void acpi_processor_ppc_exit(int cpu)
{
if (acpi_processor_ppc_status & PPC_REGISTERED)
cpufreq_unregister_notifier(&acpi_ppc_notifier_block,
CPUFREQ_POLICY_NOTIFIER);
struct acpi_processor *pr = per_cpu(processors, cpu);

acpi_processor_ppc_status &= ~PPC_REGISTERED;
dev_pm_qos_remove_request(&pr->perflib_req);
}

static int acpi_processor_get_performance_control(struct acpi_processor *pr)
Expand Down Expand Up @@ -477,7 +453,7 @@ int acpi_processor_notify_smm(struct module *calling_module)
static int is_done = 0;
int result;

if (!(acpi_processor_ppc_status & PPC_REGISTERED))
if (!acpi_processor_cpufreq_init)
return -EBUSY;

if (!try_module_get(calling_module))
Expand Down Expand Up @@ -513,7 +489,7 @@ int acpi_processor_notify_smm(struct module *calling_module)
* we can allow the cpufreq driver to be rmmod'ed. */
is_done = 1;

if (!(acpi_processor_ppc_status & PPC_IN_USE))
if (!acpi_processor_ppc_in_use)
module_put(calling_module);

return 0;
Expand Down Expand Up @@ -742,7 +718,7 @@ acpi_processor_register_performance(struct acpi_processor_performance
{
struct acpi_processor *pr;

if (!(acpi_processor_ppc_status & PPC_REGISTERED))
if (!acpi_processor_cpufreq_init)
return -EINVAL;

mutex_lock(&performance_mutex);
Expand Down
84 changes: 41 additions & 43 deletions drivers/acpi/processor_thermal.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ ACPI_MODULE_NAME("processor_thermal");
#define CPUFREQ_THERMAL_MAX_STEP 3

static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg);
static unsigned int acpi_thermal_cpufreq_is_init = 0;

#define reduction_pctg(cpu) \
per_cpu(cpufreq_thermal_reduction_pctg, phys_package_first_cpu(cpu))
Expand All @@ -61,35 +60,11 @@ static int phys_package_first_cpu(int cpu)
static int cpu_has_cpufreq(unsigned int cpu)
{
struct cpufreq_policy policy;
if (!acpi_thermal_cpufreq_is_init || cpufreq_get_policy(&policy, cpu))
if (!acpi_processor_cpufreq_init || cpufreq_get_policy(&policy, cpu))
return 0;
return 1;
}

static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
struct cpufreq_policy *policy = data;
unsigned long max_freq = 0;

if (event != CPUFREQ_ADJUST)
goto out;

max_freq = (
policy->cpuinfo.max_freq *
(100 - reduction_pctg(policy->cpu) * 20)
) / 100;

cpufreq_verify_within_limits(policy, 0, max_freq);

out:
return 0;
}

static struct notifier_block acpi_thermal_cpufreq_notifier_block = {
.notifier_call = acpi_thermal_cpufreq_notifier,
};

static int cpufreq_get_max_state(unsigned int cpu)
{
if (!cpu_has_cpufreq(cpu))
Expand All @@ -108,7 +83,10 @@ static int cpufreq_get_cur_state(unsigned int cpu)

static int cpufreq_set_cur_state(unsigned int cpu, int state)
{
int i;
struct cpufreq_policy *policy;
struct acpi_processor *pr;
unsigned long max_freq;
int i, ret;

if (!cpu_has_cpufreq(cpu))
return 0;
Expand All @@ -121,33 +99,53 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state)
* frequency.
*/
for_each_online_cpu(i) {
if (topology_physical_package_id(i) ==
if (topology_physical_package_id(i) !=
topology_physical_package_id(cpu))
cpufreq_update_policy(i);
continue;

pr = per_cpu(processors, i);

if (unlikely(!dev_pm_qos_request_active(&pr->thermal_req)))
continue;

policy = cpufreq_cpu_get(i);
if (!policy)
return -EINVAL;

max_freq = (policy->cpuinfo.max_freq * (100 - reduction_pctg(i) * 20)) / 100;

cpufreq_cpu_put(policy);

ret = dev_pm_qos_update_request(&pr->thermal_req, max_freq);
if (ret < 0) {
pr_warn("Failed to update thermal freq constraint: CPU%d (%d)\n",
pr->id, ret);
}
}
return 0;
}

void acpi_thermal_cpufreq_init(void)
void acpi_thermal_cpufreq_init(int cpu)
{
int i;

i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block,
CPUFREQ_POLICY_NOTIFIER);
if (!i)
acpi_thermal_cpufreq_is_init = 1;
struct acpi_processor *pr = per_cpu(processors, cpu);
int ret;

ret = dev_pm_qos_add_request(get_cpu_device(cpu),
&pr->thermal_req, DEV_PM_QOS_MAX_FREQUENCY,
INT_MAX);
if (ret < 0) {
pr_err("Failed to add freq constraint for CPU%d (%d)\n", cpu,
ret);
return;
}
}

void acpi_thermal_cpufreq_exit(void)
void acpi_thermal_cpufreq_exit(int cpu)
{
if (acpi_thermal_cpufreq_is_init)
cpufreq_unregister_notifier
(&acpi_thermal_cpufreq_notifier_block,
CPUFREQ_POLICY_NOTIFIER);
struct acpi_processor *pr = per_cpu(processors, cpu);

acpi_thermal_cpufreq_is_init = 0;
dev_pm_qos_remove_request(&pr->thermal_req);
}

#else /* ! CONFIG_CPU_FREQ */
static int cpufreq_get_max_state(unsigned int cpu)
{
Expand Down
2 changes: 1 addition & 1 deletion drivers/base/arch_topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ init_cpu_capacity_callback(struct notifier_block *nb,
if (!raw_capacity)
return 0;

if (val != CPUFREQ_NOTIFY)
if (val != CPUFREQ_CREATE_POLICY)
return 0;

pr_debug("cpu_capacity: init cpu capacity for CPUs [%*pbl] (to_visit=%*pbl)\n",
Expand Down
Loading

0 comments on commit beb4e08

Please sign in to comment.