Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e2f74f35 authored by Thomas Renninger's avatar Thomas Renninger Committed by Dave Jones
Browse files

[ACPI/CPUFREQ] Introduce bios_limit per cpu cpufreq sysfs interface



This interface is mainly intended (and implemented) for ACPI _PPC BIOS
frequency limitations, but other cpufreq drivers can also use it for
similar use-cases.

Why is this needed:

Currently it's not obvious why cpufreq got limited.
People see cpufreq/scaling_max_freq reduced, but this could have
happened by:
  - any userspace prog writing to scaling_max_freq
  - thermal limitations
  - hardware (_PPC in ACPI case) limitiations

Therefore export bios_limit (in kHz) to:
  - Point the user that it's the BIOS (broken or intended) which limits
    frequency
  - Export it as a sysfs interface for userspace progs.
    While this was a rarely used feature on laptops, there will appear
    more and more server implemenations providing "Green IT" features like
    allowing the service processor to limit the frequency. People want
    to know about HW/BIOS frequency limitations.

All ACPI P-state driven cpufreq drivers are covered with this patch:
  - powernow-k8
  - powernow-k7
  - acpi-cpufreq

Tested with a patched DSDT which limits the first two cores (_PPC returns 1)
via _PPC, exposed by bios_limit:
# echo 2200000 >cpu2/cpufreq/scaling_max_freq
# cat cpu*/cpufreq/scaling_max_freq
2600000
2600000
2200000
2200000
# #scaling_max_freq shows general user/thermal/BIOS limitations

# cat cpu*/cpufreq/bios_limit
2600000
2600000
2800000
2800000
# #bios_limit only shows the HW/BIOS limitation

CC: Pallipadi Venkatesh <venkatesh.pallipadi@intel.com>
CC: Len Brown <lenb@kernel.org>
CC: davej@codemonkey.org.uk
CC: linux@dominikbrodowski.net

Signed-off-by: default avatarThomas Renninger <trenn@suse.de>
Signed-off-by: default avatarDave Jones <davej@redhat.com>
parent cf3289d0
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -203,6 +203,17 @@ scaling_cur_freq : Current frequency of the CPU as determined by
				the frequency the kernel thinks the CPU runs
				at.

bios_limit :			If the BIOS tells the OS to limit a CPU to
				lower frequencies, the user can read out the
				maximum available frequency from this file.
				This typically can happen through (often not
				intended) BIOS settings, restrictions
				triggered through a service processor or other
				BIOS/HW based implementations.
				This does not cover thermal ACPI limitations
				which can be detected through the generic
				thermal driver.

If you have selected the "userspace" governor which allows you to
set the CPU operating frequency to a specific value, you can read out
the current frequency in
+9 −8
Original line number Diff line number Diff line
@@ -766,6 +766,7 @@ static struct freq_attr *acpi_cpufreq_attr[] = {
static struct cpufreq_driver acpi_cpufreq_driver = {
	.verify		= acpi_cpufreq_verify,
	.target		= acpi_cpufreq_target,
	.bios_limit	= acpi_processor_get_bios_limit,
	.init		= acpi_cpufreq_cpu_init,
	.exit		= acpi_cpufreq_cpu_exit,
	.resume		= acpi_cpufreq_resume,
+11 −8
Original line number Diff line number Diff line
@@ -717,6 +717,9 @@ static struct cpufreq_driver powernow_driver = {
	.verify		= powernow_verify,
	.target		= powernow_target,
	.get		= powernow_get,
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
	.bios_limit	= acpi_processor_get_bios_limit,
#endif
	.init		= powernow_cpu_init,
	.exit		= powernow_cpu_exit,
	.name		= "powernow-k7",
+9 −8
Original line number Diff line number Diff line
@@ -1400,6 +1400,7 @@ static struct freq_attr *powernow_k8_attr[] = {
static struct cpufreq_driver cpufreq_amd64_driver = {
	.verify		= powernowk8_verify,
	.target		= powernowk8_target,
	.bios_limit	= acpi_processor_get_bios_limit,
	.init		= powernowk8_cpu_init,
	.exit		= __devexit_p(powernowk8_cpu_exit),
	.get		= powernowk8_get,
+13 −0
Original line number Diff line number Diff line
@@ -167,6 +167,19 @@ int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
		return cpufreq_update_policy(pr->id);
}

int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
{
	struct acpi_processor *pr;

	pr = per_cpu(processors, cpu);
	if (!pr || !pr->performance || !pr->performance->state_count)
		return -ENODEV;
	*limit = pr->performance->states[pr->performance_platform_limit].
		core_frequency * 1000;
	return 0;
}
EXPORT_SYMBOL(acpi_processor_get_bios_limit);

void acpi_processor_ppc_init(void)
{
	if (!cpufreq_register_notifier
Loading