Commit 2cc6ced132f472b2bdb619960a650b9a85cdd34f
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
Merge branch 'pm-cpufreq'
* pm-cpufreq: cpufreq: don't leave stale policy pointer in cdbs->cur_policy acpi-cpufreq: Add new sysfs attribute freqdomain_cpus cpufreq: make sure frequency transitions are serialized
Showing 5 changed files Side-by-side Diff
Documentation/ABI/testing/sysfs-devices-system-cpu
... | ... | @@ -144,6 +144,21 @@ |
144 | 144 | to learn how to control the knobs. |
145 | 145 | |
146 | 146 | |
147 | +What: /sys/devices/system/cpu/cpu#/cpufreq/freqdomain_cpus | |
148 | +Date: June 2013 | |
149 | +Contact: cpufreq@vger.kernel.org | |
150 | +Description: Discover CPUs in the same CPU frequency coordination domain | |
151 | + | |
152 | + freqdomain_cpus is the list of CPUs (online+offline) that share | |
153 | + the same clock/freq domain (possibly at the hardware level). | |
154 | + That information may be hidden from the cpufreq core and the | |
155 | + value of related_cpus may be different from freqdomain_cpus. This | |
156 | + attribute is useful for user space DVFS controllers to get better | |
157 | + power/performance results for platforms using acpi-cpufreq. | |
158 | + | |
159 | + This file is only present if the acpi-cpufreq driver is in use. | |
160 | + | |
161 | + | |
147 | 162 | What: /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1} |
148 | 163 | Date: August 2008 |
149 | 164 | KernelVersion: 2.6.27 |
drivers/cpufreq/acpi-cpufreq.c
... | ... | @@ -70,6 +70,7 @@ |
70 | 70 | struct cpufreq_frequency_table *freq_table; |
71 | 71 | unsigned int resume; |
72 | 72 | unsigned int cpu_feature; |
73 | + cpumask_var_t freqdomain_cpus; | |
73 | 74 | }; |
74 | 75 | |
75 | 76 | static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data); |
... | ... | @@ -176,6 +177,15 @@ |
176 | 177 | show_global_boost, |
177 | 178 | store_global_boost); |
178 | 179 | |
180 | +static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf) | |
181 | +{ | |
182 | + struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); | |
183 | + | |
184 | + return cpufreq_show_cpus(data->freqdomain_cpus, buf); | |
185 | +} | |
186 | + | |
187 | +cpufreq_freq_attr_ro(freqdomain_cpus); | |
188 | + | |
179 | 189 | #ifdef CONFIG_X86_ACPI_CPUFREQ_CPB |
180 | 190 | static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf, |
181 | 191 | size_t count) |
... | ... | @@ -704,6 +714,11 @@ |
704 | 714 | if (!data) |
705 | 715 | return -ENOMEM; |
706 | 716 | |
717 | + if (!zalloc_cpumask_var(&data->freqdomain_cpus, GFP_KERNEL)) { | |
718 | + result = -ENOMEM; | |
719 | + goto err_free; | |
720 | + } | |
721 | + | |
707 | 722 | data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu); |
708 | 723 | per_cpu(acfreq_data, cpu) = data; |
709 | 724 | |
... | ... | @@ -712,7 +727,7 @@ |
712 | 727 | |
713 | 728 | result = acpi_processor_register_performance(data->acpi_data, cpu); |
714 | 729 | if (result) |
715 | - goto err_free; | |
730 | + goto err_free_mask; | |
716 | 731 | |
717 | 732 | perf = data->acpi_data; |
718 | 733 | policy->shared_type = perf->shared_type; |
... | ... | @@ -725,6 +740,7 @@ |
725 | 740 | policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { |
726 | 741 | cpumask_copy(policy->cpus, perf->shared_cpu_map); |
727 | 742 | } |
743 | + cpumask_copy(data->freqdomain_cpus, perf->shared_cpu_map); | |
728 | 744 | |
729 | 745 | #ifdef CONFIG_SMP |
730 | 746 | dmi_check_system(sw_any_bug_dmi_table); |
... | ... | @@ -736,6 +752,7 @@ |
736 | 752 | if (check_amd_hwpstate_cpu(cpu) && !acpi_pstate_strict) { |
737 | 753 | cpumask_clear(policy->cpus); |
738 | 754 | cpumask_set_cpu(cpu, policy->cpus); |
755 | + cpumask_copy(data->freqdomain_cpus, cpu_sibling_mask(cpu)); | |
739 | 756 | policy->shared_type = CPUFREQ_SHARED_TYPE_HW; |
740 | 757 | pr_info_once(PFX "overriding BIOS provided _PSD data\n"); |
741 | 758 | } |
... | ... | @@ -870,6 +887,8 @@ |
870 | 887 | kfree(data->freq_table); |
871 | 888 | err_unreg: |
872 | 889 | acpi_processor_unregister_performance(perf, cpu); |
890 | +err_free_mask: | |
891 | + free_cpumask_var(data->freqdomain_cpus); | |
873 | 892 | err_free: |
874 | 893 | kfree(data); |
875 | 894 | per_cpu(acfreq_data, cpu) = NULL; |
... | ... | @@ -888,6 +907,7 @@ |
888 | 907 | per_cpu(acfreq_data, policy->cpu) = NULL; |
889 | 908 | acpi_processor_unregister_performance(data->acpi_data, |
890 | 909 | policy->cpu); |
910 | + free_cpumask_var(data->freqdomain_cpus); | |
891 | 911 | kfree(data->freq_table); |
892 | 912 | kfree(data); |
893 | 913 | } |
... | ... | @@ -908,6 +928,7 @@ |
908 | 928 | |
909 | 929 | static struct freq_attr *acpi_cpufreq_attr[] = { |
910 | 930 | &cpufreq_freq_attr_scaling_available_freqs, |
931 | + &freqdomain_cpus, | |
911 | 932 | NULL, /* this is a placeholder for cpb, do not remove */ |
912 | 933 | NULL, |
913 | 934 | }; |
drivers/cpufreq/cpufreq.c
... | ... | @@ -312,6 +312,12 @@ |
312 | 312 | switch (state) { |
313 | 313 | |
314 | 314 | case CPUFREQ_PRECHANGE: |
315 | + if (WARN(policy->transition_ongoing, | |
316 | + "In middle of another frequency transition\n")) | |
317 | + return; | |
318 | + | |
319 | + policy->transition_ongoing = true; | |
320 | + | |
315 | 321 | /* detect if the driver reported a value as "old frequency" |
316 | 322 | * which is not equal to what the cpufreq core thinks is |
317 | 323 | * "old frequency". |
... | ... | @@ -331,6 +337,12 @@ |
331 | 337 | break; |
332 | 338 | |
333 | 339 | case CPUFREQ_POSTCHANGE: |
340 | + if (WARN(!policy->transition_ongoing, | |
341 | + "No frequency transition in progress\n")) | |
342 | + return; | |
343 | + | |
344 | + policy->transition_ongoing = false; | |
345 | + | |
334 | 346 | adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); |
335 | 347 | pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new, |
336 | 348 | (unsigned long)freqs->cpu); |
... | ... | @@ -573,7 +585,7 @@ |
573 | 585 | return i; |
574 | 586 | } |
575 | 587 | |
576 | -static ssize_t show_cpus(const struct cpumask *mask, char *buf) | |
588 | +ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf) | |
577 | 589 | { |
578 | 590 | ssize_t i = 0; |
579 | 591 | unsigned int cpu; |
... | ... | @@ -588,6 +600,7 @@ |
588 | 600 | i += sprintf(&buf[i], "\n"); |
589 | 601 | return i; |
590 | 602 | } |
603 | +EXPORT_SYMBOL_GPL(cpufreq_show_cpus); | |
591 | 604 | |
592 | 605 | /** |
593 | 606 | * show_related_cpus - show the CPUs affected by each transition even if |
... | ... | @@ -595,7 +608,7 @@ |
595 | 608 | */ |
596 | 609 | static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf) |
597 | 610 | { |
598 | - return show_cpus(policy->related_cpus, buf); | |
611 | + return cpufreq_show_cpus(policy->related_cpus, buf); | |
599 | 612 | } |
600 | 613 | |
601 | 614 | /** |
... | ... | @@ -603,7 +616,7 @@ |
603 | 616 | */ |
604 | 617 | static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf) |
605 | 618 | { |
606 | - return show_cpus(policy->cpus, buf); | |
619 | + return cpufreq_show_cpus(policy->cpus, buf); | |
607 | 620 | } |
608 | 621 | |
609 | 622 | static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy, |
... | ... | @@ -1539,6 +1552,8 @@ |
1539 | 1552 | |
1540 | 1553 | if (cpufreq_disabled()) |
1541 | 1554 | return -ENODEV; |
1555 | + if (policy->transition_ongoing) | |
1556 | + return -EBUSY; | |
1542 | 1557 | |
1543 | 1558 | /* Make sure that target_freq is within supported range */ |
1544 | 1559 | if (target_freq > policy->max) |
drivers/cpufreq/cpufreq_governor.c
include/linux/cpufreq.h
... | ... | @@ -119,6 +119,7 @@ |
119 | 119 | |
120 | 120 | struct kobject kobj; |
121 | 121 | struct completion kobj_unregister; |
122 | + bool transition_ongoing; /* Tracks transition status */ | |
122 | 123 | }; |
123 | 124 | |
124 | 125 | #define CPUFREQ_ADJUST (0) |
... | ... | @@ -438,5 +439,8 @@ |
438 | 439 | void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy); |
439 | 440 | |
440 | 441 | void cpufreq_frequency_table_put_attr(unsigned int cpu); |
442 | + | |
443 | +ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf); | |
444 | + | |
441 | 445 | #endif /* _LINUX_CPUFREQ_H */ |