aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2016-06-27 06:34:07 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-07-06 18:13:20 -0400
commitda0c6dc00c69d0adaae99c3b3d2ea0c869a3fb35 (patch)
tree857ed9f41fafe743720003520ecc94d4e53114d8
parent8d540ea79211dd272403ed79b2033bbded19ac42 (diff)
cpufreq: Handle sorted frequency tables more efficiently
cpufreq drivers aren't required to provide a sorted frequency table today, and even the ones which provide a sorted table aren't handled efficiently by cpufreq core. This patch adds infrastructure to verify if the freq-table provided by the drivers is sorted or not, and use efficient helpers if they are sorted. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/cpufreq/freq_table.c73
-rw-r--r--include/linux/cpufreq.h234
2 files changed, 296 insertions, 11 deletions
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index eac8bcbdaad1..3bbbf9e6960c 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -113,9 +113,9 @@ int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy)
113} 113}
114EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify); 114EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify);
115 115
116int cpufreq_frequency_table_target(struct cpufreq_policy *policy, 116int cpufreq_table_index_unsorted(struct cpufreq_policy *policy,
117 unsigned int target_freq, 117 unsigned int target_freq,
118 unsigned int relation) 118 unsigned int relation)
119{ 119{
120 struct cpufreq_frequency_table optimal = { 120 struct cpufreq_frequency_table optimal = {
121 .driver_data = ~0, 121 .driver_data = ~0,
@@ -205,7 +205,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
205 table[index].frequency); 205 table[index].frequency);
206 return index; 206 return index;
207} 207}
208EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); 208EXPORT_SYMBOL_GPL(cpufreq_table_index_unsorted);
209 209
210int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, 210int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
211 unsigned int freq) 211 unsigned int freq)
@@ -297,15 +297,72 @@ struct freq_attr *cpufreq_generic_attr[] = {
297}; 297};
298EXPORT_SYMBOL_GPL(cpufreq_generic_attr); 298EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
299 299
300static int set_freq_table_sorted(struct cpufreq_policy *policy)
301{
302 struct cpufreq_frequency_table *pos, *table = policy->freq_table;
303 struct cpufreq_frequency_table *prev = NULL;
304 int ascending = 0;
305
306 policy->freq_table_sorted = CPUFREQ_TABLE_UNSORTED;
307
308 cpufreq_for_each_valid_entry(pos, table) {
309 if (!prev) {
310 prev = pos;
311 continue;
312 }
313
314 if (pos->frequency == prev->frequency) {
315 pr_warn("Duplicate freq-table entries: %u\n",
316 pos->frequency);
317 return -EINVAL;
318 }
319
320 /* Frequency increased from prev to pos */
321 if (pos->frequency > prev->frequency) {
322 /* But frequency was decreasing earlier */
323 if (ascending < 0) {
324 pr_debug("Freq table is unsorted\n");
325 return 0;
326 }
327
328 ascending++;
329 } else {
330 /* Frequency decreased from prev to pos */
331
332 /* But frequency was increasing earlier */
333 if (ascending > 0) {
334 pr_debug("Freq table is unsorted\n");
335 return 0;
336 }
337
338 ascending--;
339 }
340
341 prev = pos;
342 }
343
344 if (ascending > 0)
345 policy->freq_table_sorted = CPUFREQ_TABLE_SORTED_ASCENDING;
346 else
347 policy->freq_table_sorted = CPUFREQ_TABLE_SORTED_DESCENDING;
348
349 pr_debug("Freq table is sorted in %s order\n",
350 ascending > 0 ? "ascending" : "descending");
351
352 return 0;
353}
354
300int cpufreq_table_validate_and_show(struct cpufreq_policy *policy, 355int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
301 struct cpufreq_frequency_table *table) 356 struct cpufreq_frequency_table *table)
302{ 357{
303 int ret = cpufreq_frequency_table_cpuinfo(policy, table); 358 int ret;
304 359
305 if (!ret) 360 ret = cpufreq_frequency_table_cpuinfo(policy, table);
306 policy->freq_table = table; 361 if (ret)
362 return ret;
307 363
308 return ret; 364 policy->freq_table = table;
365 return set_freq_table_sorted(policy);
309} 366}
310EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show); 367EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);
311 368
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index c378776628b4..c6410b1b2490 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -36,6 +36,12 @@
36 36
37struct cpufreq_governor; 37struct cpufreq_governor;
38 38
39enum cpufreq_table_sorting {
40 CPUFREQ_TABLE_UNSORTED,
41 CPUFREQ_TABLE_SORTED_ASCENDING,
42 CPUFREQ_TABLE_SORTED_DESCENDING
43};
44
39struct cpufreq_freqs { 45struct cpufreq_freqs {
40 unsigned int cpu; /* cpu nr */ 46 unsigned int cpu; /* cpu nr */
41 unsigned int old; 47 unsigned int old;
@@ -87,6 +93,7 @@ struct cpufreq_policy {
87 93
88 struct cpufreq_user_policy user_policy; 94 struct cpufreq_user_policy user_policy;
89 struct cpufreq_frequency_table *freq_table; 95 struct cpufreq_frequency_table *freq_table;
96 enum cpufreq_table_sorting freq_table_sorted;
90 97
91 struct list_head policy_list; 98 struct list_head policy_list;
92 struct kobject kobj; 99 struct kobject kobj;
@@ -597,9 +604,9 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
597 struct cpufreq_frequency_table *table); 604 struct cpufreq_frequency_table *table);
598int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy); 605int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy);
599 606
600int cpufreq_frequency_table_target(struct cpufreq_policy *policy, 607int cpufreq_table_index_unsorted(struct cpufreq_policy *policy,
601 unsigned int target_freq, 608 unsigned int target_freq,
602 unsigned int relation); 609 unsigned int relation);
603int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, 610int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
604 unsigned int freq); 611 unsigned int freq);
605 612
@@ -610,6 +617,227 @@ int cpufreq_boost_trigger_state(int state);
610int cpufreq_boost_enabled(void); 617int cpufreq_boost_enabled(void);
611int cpufreq_enable_boost_support(void); 618int cpufreq_enable_boost_support(void);
612bool policy_has_boost_freq(struct cpufreq_policy *policy); 619bool policy_has_boost_freq(struct cpufreq_policy *policy);
620
621/* Find lowest freq at or above target in a table in ascending order */
622static inline int cpufreq_table_find_index_al(struct cpufreq_policy *policy,
623 unsigned int target_freq)
624{
625 struct cpufreq_frequency_table *table = policy->freq_table;
626 unsigned int freq;
627 int i, best = -1;
628
629 for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
630 freq = table[i].frequency;
631
632 if (freq >= target_freq)
633 return i;
634
635 best = i;
636 }
637
638 return best;
639}
640
641/* Find lowest freq at or above target in a table in descending order */
642static inline int cpufreq_table_find_index_dl(struct cpufreq_policy *policy,
643 unsigned int target_freq)
644{
645 struct cpufreq_frequency_table *table = policy->freq_table;
646 unsigned int freq;
647 int i, best = -1;
648
649 for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
650 freq = table[i].frequency;
651
652 if (freq == target_freq)
653 return i;
654
655 if (freq > target_freq) {
656 best = i;
657 continue;
658 }
659
660 /* No freq found above target_freq */
661 if (best == -1)
662 return i;
663
664 return best;
665 }
666
667 return best;
668}
669
670/* Works only on sorted freq-tables */
671static inline int cpufreq_table_find_index_l(struct cpufreq_policy *policy,
672 unsigned int target_freq)
673{
674 target_freq = clamp_val(target_freq, policy->min, policy->max);
675
676 if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING)
677 return cpufreq_table_find_index_al(policy, target_freq);
678 else
679 return cpufreq_table_find_index_dl(policy, target_freq);
680}
681
682/* Find highest freq at or below target in a table in ascending order */
683static inline int cpufreq_table_find_index_ah(struct cpufreq_policy *policy,
684 unsigned int target_freq)
685{
686 struct cpufreq_frequency_table *table = policy->freq_table;
687 unsigned int freq;
688 int i, best = -1;
689
690 for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
691 freq = table[i].frequency;
692
693 if (freq == target_freq)
694 return i;
695
696 if (freq < target_freq) {
697 best = i;
698 continue;
699 }
700
701 /* No freq found below target_freq */
702 if (best == -1)
703 return i;
704
705 return best;
706 }
707
708 return best;
709}
710
711/* Find highest freq at or below target in a table in descending order */
712static inline int cpufreq_table_find_index_dh(struct cpufreq_policy *policy,
713 unsigned int target_freq)
714{
715 struct cpufreq_frequency_table *table = policy->freq_table;
716 unsigned int freq;
717 int i, best = -1;
718
719 for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
720 freq = table[i].frequency;
721
722 if (freq <= target_freq)
723 return i;
724
725 best = i;
726 }
727
728 return best;
729}
730
731/* Works only on sorted freq-tables */
732static inline int cpufreq_table_find_index_h(struct cpufreq_policy *policy,
733 unsigned int target_freq)
734{
735 target_freq = clamp_val(target_freq, policy->min, policy->max);
736
737 if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING)
738 return cpufreq_table_find_index_ah(policy, target_freq);
739 else
740 return cpufreq_table_find_index_dh(policy, target_freq);
741}
742
743/* Find closest freq to target in a table in ascending order */
744static inline int cpufreq_table_find_index_ac(struct cpufreq_policy *policy,
745 unsigned int target_freq)
746{
747 struct cpufreq_frequency_table *table = policy->freq_table;
748 unsigned int freq;
749 int i, best = -1;
750
751 for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
752 freq = table[i].frequency;
753
754 if (freq == target_freq)
755 return i;
756
757 if (freq < target_freq) {
758 best = i;
759 continue;
760 }
761
762 /* No freq found below target_freq */
763 if (best == -1)
764 return i;
765
766 /* Choose the closest freq */
767 if (target_freq - table[best].frequency > freq - target_freq)
768 return i;
769
770 return best;
771 }
772
773 return best;
774}
775
776/* Find closest freq to target in a table in descending order */
777static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy,
778 unsigned int target_freq)
779{
780 struct cpufreq_frequency_table *table = policy->freq_table;
781 unsigned int freq;
782 int i, best = -1;
783
784 for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
785 freq = table[i].frequency;
786
787 if (freq == target_freq)
788 return i;
789
790 if (freq > target_freq) {
791 best = i;
792 continue;
793 }
794
795 /* No freq found above target_freq */
796 if (best == -1)
797 return i;
798
799 /* Choose the closest freq */
800 if (table[best].frequency - target_freq > target_freq - freq)
801 return i;
802
803 return best;
804 }
805
806 return best;
807}
808
809/* Works only on sorted freq-tables */
810static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy,
811 unsigned int target_freq)
812{
813 target_freq = clamp_val(target_freq, policy->min, policy->max);
814
815 if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING)
816 return cpufreq_table_find_index_ac(policy, target_freq);
817 else
818 return cpufreq_table_find_index_dc(policy, target_freq);
819}
820
821static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
822 unsigned int target_freq,
823 unsigned int relation)
824{
825 if (unlikely(policy->freq_table_sorted == CPUFREQ_TABLE_UNSORTED))
826 return cpufreq_table_index_unsorted(policy, target_freq,
827 relation);
828
829 switch (relation) {
830 case CPUFREQ_RELATION_L:
831 return cpufreq_table_find_index_l(policy, target_freq);
832 case CPUFREQ_RELATION_H:
833 return cpufreq_table_find_index_h(policy, target_freq);
834 case CPUFREQ_RELATION_C:
835 return cpufreq_table_find_index_c(policy, target_freq);
836 default:
837 pr_err("%s: Invalid relation: %d\n", __func__, relation);
838 return -EINVAL;
839 }
840}
613#else 841#else
614static inline int cpufreq_boost_trigger_state(int state) 842static inline int cpufreq_boost_trigger_state(int state)
615{ 843{