Commit e2f74f355e9e2914483db10c05d70e69e0b7ae04

Authored by Thomas Renninger
Committed by Dave Jones
1 parent cf3289d0e7

[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: Thomas Renninger <trenn@suse.de>
Signed-off-by: Dave Jones <davej@redhat.com>

Showing 8 changed files with 81 additions and 24 deletions Side-by-side Diff

Documentation/cpu-freq/user-guide.txt
... ... @@ -203,6 +203,17 @@
203 203 the frequency the kernel thinks the CPU runs
204 204 at.
205 205  
  206 +bios_limit : If the BIOS tells the OS to limit a CPU to
  207 + lower frequencies, the user can read out the
  208 + maximum available frequency from this file.
  209 + This typically can happen through (often not
  210 + intended) BIOS settings, restrictions
  211 + triggered through a service processor or other
  212 + BIOS/HW based implementations.
  213 + This does not cover thermal ACPI limitations
  214 + which can be detected through the generic
  215 + thermal driver.
  216 +
206 217 If you have selected the "userspace" governor which allows you to
207 218 set the CPU operating frequency to a specific value, you can read out
208 219 the current frequency in
arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
... ... @@ -764,14 +764,15 @@
764 764 };
765 765  
766 766 static struct cpufreq_driver acpi_cpufreq_driver = {
767   - .verify = acpi_cpufreq_verify,
768   - .target = acpi_cpufreq_target,
769   - .init = acpi_cpufreq_cpu_init,
770   - .exit = acpi_cpufreq_cpu_exit,
771   - .resume = acpi_cpufreq_resume,
772   - .name = "acpi-cpufreq",
773   - .owner = THIS_MODULE,
774   - .attr = acpi_cpufreq_attr,
  767 + .verify = acpi_cpufreq_verify,
  768 + .target = acpi_cpufreq_target,
  769 + .bios_limit = acpi_processor_get_bios_limit,
  770 + .init = acpi_cpufreq_cpu_init,
  771 + .exit = acpi_cpufreq_cpu_exit,
  772 + .resume = acpi_cpufreq_resume,
  773 + .name = "acpi-cpufreq",
  774 + .owner = THIS_MODULE,
  775 + .attr = acpi_cpufreq_attr,
775 776 };
776 777  
777 778 static int __init acpi_cpufreq_init(void)
arch/x86/kernel/cpu/cpufreq/powernow-k7.c
... ... @@ -714,14 +714,17 @@
714 714 };
715 715  
716 716 static struct cpufreq_driver powernow_driver = {
717   - .verify = powernow_verify,
718   - .target = powernow_target,
719   - .get = powernow_get,
720   - .init = powernow_cpu_init,
721   - .exit = powernow_cpu_exit,
722   - .name = "powernow-k7",
723   - .owner = THIS_MODULE,
724   - .attr = powernow_table_attr,
  717 + .verify = powernow_verify,
  718 + .target = powernow_target,
  719 + .get = powernow_get,
  720 +#ifdef CONFIG_X86_POWERNOW_K7_ACPI
  721 + .bios_limit = acpi_processor_get_bios_limit,
  722 +#endif
  723 + .init = powernow_cpu_init,
  724 + .exit = powernow_cpu_exit,
  725 + .name = "powernow-k7",
  726 + .owner = THIS_MODULE,
  727 + .attr = powernow_table_attr,
725 728 };
726 729  
727 730 static int __init powernow_init(void)
arch/x86/kernel/cpu/cpufreq/powernow-k8.c
... ... @@ -1398,14 +1398,15 @@
1398 1398 };
1399 1399  
1400 1400 static struct cpufreq_driver cpufreq_amd64_driver = {
1401   - .verify = powernowk8_verify,
1402   - .target = powernowk8_target,
1403   - .init = powernowk8_cpu_init,
1404   - .exit = __devexit_p(powernowk8_cpu_exit),
1405   - .get = powernowk8_get,
1406   - .name = "powernow-k8",
1407   - .owner = THIS_MODULE,
1408   - .attr = powernow_k8_attr,
  1401 + .verify = powernowk8_verify,
  1402 + .target = powernowk8_target,
  1403 + .bios_limit = acpi_processor_get_bios_limit,
  1404 + .init = powernowk8_cpu_init,
  1405 + .exit = __devexit_p(powernowk8_cpu_exit),
  1406 + .get = powernowk8_get,
  1407 + .name = "powernow-k8",
  1408 + .owner = THIS_MODULE,
  1409 + .attr = powernow_k8_attr,
1409 1410 };
1410 1411  
1411 1412 /* driver entry point for init */
drivers/acpi/processor_perflib.c
... ... @@ -167,6 +167,19 @@
167 167 return cpufreq_update_policy(pr->id);
168 168 }
169 169  
  170 +int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
  171 +{
  172 + struct acpi_processor *pr;
  173 +
  174 + pr = per_cpu(processors, cpu);
  175 + if (!pr || !pr->performance || !pr->performance->state_count)
  176 + return -ENODEV;
  177 + *limit = pr->performance->states[pr->performance_platform_limit].
  178 + core_frequency * 1000;
  179 + return 0;
  180 +}
  181 +EXPORT_SYMBOL(acpi_processor_get_bios_limit);
  182 +
170 183 void acpi_processor_ppc_init(void)
171 184 {
172 185 if (!cpufreq_register_notifier
drivers/cpufreq/cpufreq.c
... ... @@ -647,6 +647,21 @@
647 647 return policy->governor->show_setspeed(policy, buf);
648 648 }
649 649  
  650 +/**
  651 + * show_scaling_driver - show the current cpufreq HW/BIOS limitation
  652 + */
  653 +static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf)
  654 +{
  655 + unsigned int limit;
  656 + int ret;
  657 + if (cpufreq_driver->bios_limit) {
  658 + ret = cpufreq_driver->bios_limit(policy->cpu, &limit);
  659 + if (!ret)
  660 + return sprintf(buf, "%u\n", limit);
  661 + }
  662 + return sprintf(buf, "%u\n", policy->cpuinfo.max_freq);
  663 +}
  664 +
650 665 #define define_one_ro(_name) \
651 666 static struct freq_attr _name = \
652 667 __ATTR(_name, 0444, show_##_name, NULL)
... ... @@ -666,6 +681,7 @@
666 681 define_one_ro(scaling_available_governors);
667 682 define_one_ro(scaling_driver);
668 683 define_one_ro(scaling_cur_freq);
  684 +define_one_ro(bios_limit);
669 685 define_one_ro(related_cpus);
670 686 define_one_ro(affected_cpus);
671 687 define_one_rw(scaling_min_freq);
... ... @@ -902,6 +918,11 @@
902 918 }
903 919 if (cpufreq_driver->target) {
904 920 ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
  921 + if (ret)
  922 + goto err_out_kobj_put;
  923 + }
  924 + if (cpufreq_driver->bios_limit) {
  925 + ret = sysfs_create_file(&policy->kobj, &bios_limit.attr);
905 926 if (ret)
906 927 goto err_out_kobj_put;
907 928 }
include/acpi/processor.h
... ... @@ -295,6 +295,7 @@
295 295 void acpi_processor_ppc_init(void);
296 296 void acpi_processor_ppc_exit(void);
297 297 int acpi_processor_ppc_has_changed(struct acpi_processor *pr);
  298 +extern int acpi_processor_get_bios_limit(int cpu, unsigned int *limit);
298 299 #else
299 300 static inline void acpi_processor_ppc_init(void)
300 301 {
... ... @@ -316,6 +317,11 @@
316 317 }
317 318 return 0;
318 319 }
  320 +static inline int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
  321 +{
  322 + return -ENODEV;
  323 +}
  324 +
319 325 #endif /* CONFIG_CPU_FREQ */
320 326  
321 327 /* in processor_throttling.c */
include/linux/cpufreq.h
... ... @@ -232,6 +232,7 @@
232 232 /* optional */
233 233 unsigned int (*getavg) (struct cpufreq_policy *policy,
234 234 unsigned int cpu);
  235 + int (*bios_limit) (int cpu, unsigned int *limit);
235 236  
236 237 int (*exit) (struct cpufreq_policy *policy);
237 238 int (*suspend) (struct cpufreq_policy *policy, pm_message_t pmsg);