aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Renninger <trenn@suse.de>2009-11-19 06:31:01 -0500
committerDave Jones <davej@redhat.com>2009-11-24 13:33:34 -0500
commite2f74f355e9e2914483db10c05d70e69e0b7ae04 (patch)
treee17cae217151627c2c95aeeb2a43baf96d49ac91
parentcf3289d0e701b2f59123bf653c12722a7e32aedb (diff)
[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>
-rw-r--r--Documentation/cpu-freq/user-guide.txt11
-rw-r--r--arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c17
-rw-r--r--arch/x86/kernel/cpu/cpufreq/powernow-k7.c19
-rw-r--r--arch/x86/kernel/cpu/cpufreq/powernow-k8.c17
-rw-r--r--drivers/acpi/processor_perflib.c13
-rw-r--r--drivers/cpufreq/cpufreq.c21
-rw-r--r--include/acpi/processor.h6
-rw-r--r--include/linux/cpufreq.h1
8 files changed, 81 insertions, 24 deletions
diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt
index 2a5b850847c0..04f6b32993e6 100644
--- a/Documentation/cpu-freq/user-guide.txt
+++ b/Documentation/cpu-freq/user-guide.txt
@@ -203,6 +203,17 @@ scaling_cur_freq : Current frequency of the CPU as determined by
203 the frequency the kernel thinks the CPU runs 203 the frequency the kernel thinks the CPU runs
204 at. 204 at.
205 205
206bios_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
206If you have selected the "userspace" governor which allows you to 217If you have selected the "userspace" governor which allows you to
207set the CPU operating frequency to a specific value, you can read out 218set the CPU operating frequency to a specific value, you can read out
208the current frequency in 219the current frequency in
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index 8b581d3905cb..d2e7c77c1ea4 100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -764,14 +764,15 @@ static struct freq_attr *acpi_cpufreq_attr[] = {
764}; 764};
765 765
766static struct cpufreq_driver acpi_cpufreq_driver = { 766static struct cpufreq_driver acpi_cpufreq_driver = {
767 .verify = acpi_cpufreq_verify, 767 .verify = acpi_cpufreq_verify,
768 .target = acpi_cpufreq_target, 768 .target = acpi_cpufreq_target,
769 .init = acpi_cpufreq_cpu_init, 769 .bios_limit = acpi_processor_get_bios_limit,
770 .exit = acpi_cpufreq_cpu_exit, 770 .init = acpi_cpufreq_cpu_init,
771 .resume = acpi_cpufreq_resume, 771 .exit = acpi_cpufreq_cpu_exit,
772 .name = "acpi-cpufreq", 772 .resume = acpi_cpufreq_resume,
773 .owner = THIS_MODULE, 773 .name = "acpi-cpufreq",
774 .attr = acpi_cpufreq_attr, 774 .owner = THIS_MODULE,
775 .attr = acpi_cpufreq_attr,
775}; 776};
776 777
777static int __init acpi_cpufreq_init(void) 778static int __init acpi_cpufreq_init(void)
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
index d47c775eb0ab..9a97116f89e5 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
@@ -714,14 +714,17 @@ static struct freq_attr *powernow_table_attr[] = {
714}; 714};
715 715
716static struct cpufreq_driver powernow_driver = { 716static struct cpufreq_driver powernow_driver = {
717 .verify = powernow_verify, 717 .verify = powernow_verify,
718 .target = powernow_target, 718 .target = powernow_target,
719 .get = powernow_get, 719 .get = powernow_get,
720 .init = powernow_cpu_init, 720#ifdef CONFIG_X86_POWERNOW_K7_ACPI
721 .exit = powernow_cpu_exit, 721 .bios_limit = acpi_processor_get_bios_limit,
722 .name = "powernow-k7", 722#endif
723 .owner = THIS_MODULE, 723 .init = powernow_cpu_init,
724 .attr = powernow_table_attr, 724 .exit = powernow_cpu_exit,
725 .name = "powernow-k7",
726 .owner = THIS_MODULE,
727 .attr = powernow_table_attr,
725}; 728};
726 729
727static int __init powernow_init(void) 730static int __init powernow_init(void)
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
index f30d25383940..a9df9441a9a2 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
@@ -1398,14 +1398,15 @@ static struct freq_attr *powernow_k8_attr[] = {
1398}; 1398};
1399 1399
1400static struct cpufreq_driver cpufreq_amd64_driver = { 1400static struct cpufreq_driver cpufreq_amd64_driver = {
1401 .verify = powernowk8_verify, 1401 .verify = powernowk8_verify,
1402 .target = powernowk8_target, 1402 .target = powernowk8_target,
1403 .init = powernowk8_cpu_init, 1403 .bios_limit = acpi_processor_get_bios_limit,
1404 .exit = __devexit_p(powernowk8_cpu_exit), 1404 .init = powernowk8_cpu_init,
1405 .get = powernowk8_get, 1405 .exit = __devexit_p(powernowk8_cpu_exit),
1406 .name = "powernow-k8", 1406 .get = powernowk8_get,
1407 .owner = THIS_MODULE, 1407 .name = "powernow-k8",
1408 .attr = powernow_k8_attr, 1408 .owner = THIS_MODULE,
1409 .attr = powernow_k8_attr,
1409}; 1410};
1410 1411
1411/* driver entry point for init */ 1412/* driver entry point for init */
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 8ba0ed0b9ddb..01e366d2b6fb 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -167,6 +167,19 @@ int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
167 return cpufreq_update_policy(pr->id); 167 return cpufreq_update_policy(pr->id);
168} 168}
169 169
170int 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}
181EXPORT_SYMBOL(acpi_processor_get_bios_limit);
182
170void acpi_processor_ppc_init(void) 183void acpi_processor_ppc_init(void)
171{ 184{
172 if (!cpufreq_register_notifier 185 if (!cpufreq_register_notifier
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 5b9b1c8c4950..f20668c09ce0 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -647,6 +647,21 @@ static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf)
647 return policy->governor->show_setspeed(policy, buf); 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 */
653static 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#define define_one_ro(_name) \ 665#define define_one_ro(_name) \
651static struct freq_attr _name = \ 666static struct freq_attr _name = \
652__ATTR(_name, 0444, show_##_name, NULL) 667__ATTR(_name, 0444, show_##_name, NULL)
@@ -666,6 +681,7 @@ define_one_ro(cpuinfo_transition_latency);
666define_one_ro(scaling_available_governors); 681define_one_ro(scaling_available_governors);
667define_one_ro(scaling_driver); 682define_one_ro(scaling_driver);
668define_one_ro(scaling_cur_freq); 683define_one_ro(scaling_cur_freq);
684define_one_ro(bios_limit);
669define_one_ro(related_cpus); 685define_one_ro(related_cpus);
670define_one_ro(affected_cpus); 686define_one_ro(affected_cpus);
671define_one_rw(scaling_min_freq); 687define_one_rw(scaling_min_freq);
@@ -905,6 +921,11 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
905 if (ret) 921 if (ret)
906 goto err_out_kobj_put; 922 goto err_out_kobj_put;
907 } 923 }
924 if (cpufreq_driver->bios_limit) {
925 ret = sysfs_create_file(&policy->kobj, &bios_limit.attr);
926 if (ret)
927 goto err_out_kobj_put;
928 }
908 929
909 spin_lock_irqsave(&cpufreq_driver_lock, flags); 930 spin_lock_irqsave(&cpufreq_driver_lock, flags);
910 for_each_cpu(j, policy->cpus) { 931 for_each_cpu(j, policy->cpus) {
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 740ac3ad8fd0..8b668ead6d6e 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -295,6 +295,7 @@ static inline void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx
295void acpi_processor_ppc_init(void); 295void acpi_processor_ppc_init(void);
296void acpi_processor_ppc_exit(void); 296void acpi_processor_ppc_exit(void);
297int acpi_processor_ppc_has_changed(struct acpi_processor *pr); 297int acpi_processor_ppc_has_changed(struct acpi_processor *pr);
298extern int acpi_processor_get_bios_limit(int cpu, unsigned int *limit);
298#else 299#else
299static inline void acpi_processor_ppc_init(void) 300static inline void acpi_processor_ppc_init(void)
300{ 301{
@@ -316,6 +317,11 @@ static inline int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
316 } 317 }
317 return 0; 318 return 0;
318} 319}
320static inline int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
321{
322 return -ENODEV;
323}
324
319#endif /* CONFIG_CPU_FREQ */ 325#endif /* CONFIG_CPU_FREQ */
320 326
321/* in processor_throttling.c */ 327/* in processor_throttling.c */
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 79a2340d83cd..4de02b10007f 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -232,6 +232,7 @@ struct cpufreq_driver {
232 /* optional */ 232 /* optional */
233 unsigned int (*getavg) (struct cpufreq_policy *policy, 233 unsigned int (*getavg) (struct cpufreq_policy *policy,
234 unsigned int cpu); 234 unsigned int cpu);
235 int (*bios_limit) (int cpu, unsigned int *limit);
235 236
236 int (*exit) (struct cpufreq_policy *policy); 237 int (*exit) (struct cpufreq_policy *policy);
237 int (*suspend) (struct cpufreq_policy *policy, pm_message_t pmsg); 238 int (*suspend) (struct cpufreq_policy *policy, pm_message_t pmsg);