1  // SPDX-License-Identifier: GPL-2.0-only
2  /*
3   * linux/drivers/cpufreq/freq_table.c
4   *
5   * Copyright (C) 2002 - 2003 Dominik Brodowski
6   */
7  
8  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9  
10  #include <linux/cpufreq.h>
11  #include <linux/module.h>
12  
13  /*********************************************************************
14   *                     FREQUENCY TABLE HELPERS                       *
15   *********************************************************************/
16  
policy_has_boost_freq(struct cpufreq_policy * policy)17  bool policy_has_boost_freq(struct cpufreq_policy *policy)
18  {
19  	struct cpufreq_frequency_table *pos, *table = policy->freq_table;
20  
21  	if (!table)
22  		return false;
23  
24  	cpufreq_for_each_valid_entry(pos, table)
25  		if (pos->flags & CPUFREQ_BOOST_FREQ)
26  			return true;
27  
28  	return false;
29  }
30  EXPORT_SYMBOL_GPL(policy_has_boost_freq);
31  
cpufreq_frequency_table_cpuinfo(struct cpufreq_policy * policy,struct cpufreq_frequency_table * table)32  int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
33  				    struct cpufreq_frequency_table *table)
34  {
35  	struct cpufreq_frequency_table *pos;
36  	unsigned int min_freq = ~0;
37  	unsigned int max_freq = 0;
38  	unsigned int freq;
39  
40  	cpufreq_for_each_valid_entry(pos, table) {
41  		freq = pos->frequency;
42  
43  		if ((!cpufreq_boost_enabled() || !policy->boost_enabled)
44  		    && (pos->flags & CPUFREQ_BOOST_FREQ))
45  			continue;
46  
47  		pr_debug("table entry %u: %u kHz\n", (int)(pos - table), freq);
48  		if (freq < min_freq)
49  			min_freq = freq;
50  		if (freq > max_freq)
51  			max_freq = freq;
52  	}
53  
54  	policy->min = policy->cpuinfo.min_freq = min_freq;
55  	policy->max = max_freq;
56  	/*
57  	 * If the driver has set its own cpuinfo.max_freq above max_freq, leave
58  	 * it as is.
59  	 */
60  	if (policy->cpuinfo.max_freq < max_freq)
61  		policy->max = policy->cpuinfo.max_freq = max_freq;
62  
63  	if (policy->min == ~0)
64  		return -EINVAL;
65  	else
66  		return 0;
67  }
68  
cpufreq_frequency_table_verify(struct cpufreq_policy_data * policy,struct cpufreq_frequency_table * table)69  int cpufreq_frequency_table_verify(struct cpufreq_policy_data *policy,
70  				   struct cpufreq_frequency_table *table)
71  {
72  	struct cpufreq_frequency_table *pos;
73  	unsigned int freq, prev_smaller = 0;
74  	bool found = false;
75  
76  	pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
77  					policy->min, policy->max, policy->cpu);
78  
79  	cpufreq_verify_within_cpu_limits(policy);
80  
81  	cpufreq_for_each_valid_entry(pos, table) {
82  		freq = pos->frequency;
83  
84  		if ((freq >= policy->min) && (freq <= policy->max)) {
85  			found = true;
86  			break;
87  		}
88  
89  		if ((prev_smaller < freq) && (freq <= policy->max))
90  			prev_smaller = freq;
91  	}
92  
93  	if (!found) {
94  		policy->max = prev_smaller;
95  		cpufreq_verify_within_cpu_limits(policy);
96  	}
97  
98  	pr_debug("verification lead to (%u - %u kHz) for cpu %u\n",
99  				policy->min, policy->max, policy->cpu);
100  
101  	return 0;
102  }
103  EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
104  
105  /*
106   * Generic routine to verify policy & frequency table, requires driver to set
107   * policy->freq_table prior to it.
108   */
cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data * policy)109  int cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data *policy)
110  {
111  	if (!policy->freq_table)
112  		return -ENODEV;
113  
114  	return cpufreq_frequency_table_verify(policy, policy->freq_table);
115  }
116  EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify);
117  
cpufreq_table_index_unsorted(struct cpufreq_policy * policy,unsigned int target_freq,unsigned int relation)118  int cpufreq_table_index_unsorted(struct cpufreq_policy *policy,
119  				 unsigned int target_freq,
120  				 unsigned int relation)
121  {
122  	struct cpufreq_frequency_table optimal = {
123  		.driver_data = ~0,
124  		.frequency = 0,
125  	};
126  	struct cpufreq_frequency_table suboptimal = {
127  		.driver_data = ~0,
128  		.frequency = 0,
129  	};
130  	struct cpufreq_frequency_table *pos;
131  	struct cpufreq_frequency_table *table = policy->freq_table;
132  	unsigned int freq, diff, i = 0;
133  	int index;
134  
135  	pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
136  					target_freq, relation, policy->cpu);
137  
138  	switch (relation) {
139  	case CPUFREQ_RELATION_H:
140  		suboptimal.frequency = ~0;
141  		break;
142  	case CPUFREQ_RELATION_L:
143  	case CPUFREQ_RELATION_C:
144  		optimal.frequency = ~0;
145  		break;
146  	}
147  
148  	cpufreq_for_each_valid_entry_idx(pos, table, i) {
149  		freq = pos->frequency;
150  
151  		if ((freq < policy->min) || (freq > policy->max))
152  			continue;
153  		if (freq == target_freq) {
154  			optimal.driver_data = i;
155  			break;
156  		}
157  		switch (relation) {
158  		case CPUFREQ_RELATION_H:
159  			if (freq < target_freq) {
160  				if (freq >= optimal.frequency) {
161  					optimal.frequency = freq;
162  					optimal.driver_data = i;
163  				}
164  			} else {
165  				if (freq <= suboptimal.frequency) {
166  					suboptimal.frequency = freq;
167  					suboptimal.driver_data = i;
168  				}
169  			}
170  			break;
171  		case CPUFREQ_RELATION_L:
172  			if (freq > target_freq) {
173  				if (freq <= optimal.frequency) {
174  					optimal.frequency = freq;
175  					optimal.driver_data = i;
176  				}
177  			} else {
178  				if (freq >= suboptimal.frequency) {
179  					suboptimal.frequency = freq;
180  					suboptimal.driver_data = i;
181  				}
182  			}
183  			break;
184  		case CPUFREQ_RELATION_C:
185  			diff = abs(freq - target_freq);
186  			if (diff < optimal.frequency ||
187  			    (diff == optimal.frequency &&
188  			     freq > table[optimal.driver_data].frequency)) {
189  				optimal.frequency = diff;
190  				optimal.driver_data = i;
191  			}
192  			break;
193  		}
194  	}
195  	if (optimal.driver_data > i) {
196  		if (suboptimal.driver_data > i) {
197  			WARN(1, "Invalid frequency table: %u\n", policy->cpu);
198  			return 0;
199  		}
200  
201  		index = suboptimal.driver_data;
202  	} else
203  		index = optimal.driver_data;
204  
205  	pr_debug("target index is %u, freq is:%u kHz\n", index,
206  		 table[index].frequency);
207  	return index;
208  }
209  EXPORT_SYMBOL_GPL(cpufreq_table_index_unsorted);
210  
cpufreq_frequency_table_get_index(struct cpufreq_policy * policy,unsigned int freq)211  int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
212  		unsigned int freq)
213  {
214  	struct cpufreq_frequency_table *pos, *table = policy->freq_table;
215  	int idx;
216  
217  	if (unlikely(!table)) {
218  		pr_debug("%s: Unable to find frequency table\n", __func__);
219  		return -ENOENT;
220  	}
221  
222  	cpufreq_for_each_valid_entry_idx(pos, table, idx)
223  		if (pos->frequency == freq)
224  			return idx;
225  
226  	return -EINVAL;
227  }
228  EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
229  
230  /*
231   * show_available_freqs - show available frequencies for the specified CPU
232   */
show_available_freqs(struct cpufreq_policy * policy,char * buf,bool show_boost)233  static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
234  				    bool show_boost)
235  {
236  	ssize_t count = 0;
237  	struct cpufreq_frequency_table *pos, *table = policy->freq_table;
238  
239  	if (!table)
240  		return -ENODEV;
241  
242  	cpufreq_for_each_valid_entry(pos, table) {
243  		/*
244  		 * show_boost = true and driver_data = BOOST freq
245  		 * display BOOST freqs
246  		 *
247  		 * show_boost = false and driver_data = BOOST freq
248  		 * show_boost = true and driver_data != BOOST freq
249  		 * continue - do not display anything
250  		 *
251  		 * show_boost = false and driver_data != BOOST freq
252  		 * display NON BOOST freqs
253  		 */
254  		if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))
255  			continue;
256  
257  		count += sprintf(&buf[count], "%u ", pos->frequency);
258  	}
259  	count += sprintf(&buf[count], "\n");
260  
261  	return count;
262  
263  }
264  
265  #define cpufreq_attr_available_freq(_name)	  \
266  struct freq_attr cpufreq_freq_attr_##_name##_freqs =     \
267  __ATTR_RO(_name##_frequencies)
268  
269  /*
270   * scaling_available_frequencies_show - show available normal frequencies for
271   * the specified CPU
272   */
scaling_available_frequencies_show(struct cpufreq_policy * policy,char * buf)273  static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
274  						  char *buf)
275  {
276  	return show_available_freqs(policy, buf, false);
277  }
278  cpufreq_attr_available_freq(scaling_available);
279  EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
280  
281  /*
282   * scaling_boost_frequencies_show - show available boost frequencies for
283   * the specified CPU
284   */
scaling_boost_frequencies_show(struct cpufreq_policy * policy,char * buf)285  static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
286  					      char *buf)
287  {
288  	return show_available_freqs(policy, buf, true);
289  }
290  cpufreq_attr_available_freq(scaling_boost);
291  EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
292  
293  struct freq_attr *cpufreq_generic_attr[] = {
294  	&cpufreq_freq_attr_scaling_available_freqs,
295  	NULL,
296  };
297  EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
298  
set_freq_table_sorted(struct cpufreq_policy * policy)299  static int set_freq_table_sorted(struct cpufreq_policy *policy)
300  {
301  	struct cpufreq_frequency_table *pos, *table = policy->freq_table;
302  	struct cpufreq_frequency_table *prev = NULL;
303  	int ascending = 0;
304  
305  	policy->freq_table_sorted = CPUFREQ_TABLE_UNSORTED;
306  
307  	cpufreq_for_each_valid_entry(pos, table) {
308  		if (!prev) {
309  			prev = pos;
310  			continue;
311  		}
312  
313  		if (pos->frequency == prev->frequency) {
314  			pr_warn("Duplicate freq-table entries: %u\n",
315  				pos->frequency);
316  			return -EINVAL;
317  		}
318  
319  		/* Frequency increased from prev to pos */
320  		if (pos->frequency > prev->frequency) {
321  			/* But frequency was decreasing earlier */
322  			if (ascending < 0) {
323  				pr_debug("Freq table is unsorted\n");
324  				return 0;
325  			}
326  
327  			ascending++;
328  		} else {
329  			/* Frequency decreased from prev to pos */
330  
331  			/* But frequency was increasing earlier */
332  			if (ascending > 0) {
333  				pr_debug("Freq table is unsorted\n");
334  				return 0;
335  			}
336  
337  			ascending--;
338  		}
339  
340  		prev = pos;
341  	}
342  
343  	if (ascending > 0)
344  		policy->freq_table_sorted = CPUFREQ_TABLE_SORTED_ASCENDING;
345  	else
346  		policy->freq_table_sorted = CPUFREQ_TABLE_SORTED_DESCENDING;
347  
348  	pr_debug("Freq table is sorted in %s order\n",
349  		 ascending > 0 ? "ascending" : "descending");
350  
351  	return 0;
352  }
353  
cpufreq_table_validate_and_sort(struct cpufreq_policy * policy)354  int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy)
355  {
356  	int ret;
357  
358  	if (!policy->freq_table) {
359  		/* Freq table must be passed by drivers with target_index() */
360  		if (has_target_index())
361  			return -EINVAL;
362  
363  		return 0;
364  	}
365  
366  	ret = cpufreq_frequency_table_cpuinfo(policy, policy->freq_table);
367  	if (ret)
368  		return ret;
369  
370  	return set_freq_table_sorted(policy);
371  }
372  
373  MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
374  MODULE_DESCRIPTION("CPUfreq frequency table helpers");
375