linux/drivers/cpufreq/freq_table.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/cpufreq/freq_table.c
   3 *
   4 * Copyright (C) 2002 - 2003 Dominik Brodowski
   5 */
   6
   7#include <linux/kernel.h>
   8#include <linux/module.h>
   9#include <linux/init.h>
  10#include <linux/cpufreq.h>
  11
  12#define dprintk(msg...) \
  13        cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg)
  14
  15/*********************************************************************
  16 *                     FREQUENCY TABLE HELPERS                       *
  17 *********************************************************************/
  18
  19int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
  20                                    struct cpufreq_frequency_table *table)
  21{
  22        unsigned int min_freq = ~0;
  23        unsigned int max_freq = 0;
  24        unsigned int i;
  25
  26        for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
  27                unsigned int freq = table[i].frequency;
  28                if (freq == CPUFREQ_ENTRY_INVALID) {
  29                        dprintk("table entry %u is invalid, skipping\n", i);
  30
  31                        continue;
  32                }
  33                dprintk("table entry %u: %u kHz, %u index\n",
  34                                        i, freq, table[i].index);
  35                if (freq < min_freq)
  36                        min_freq = freq;
  37                if (freq > max_freq)
  38                        max_freq = freq;
  39        }
  40
  41        policy->min = policy->cpuinfo.min_freq = min_freq;
  42        policy->max = policy->cpuinfo.max_freq = max_freq;
  43
  44        if (policy->min == ~0)
  45                return -EINVAL;
  46        else
  47                return 0;
  48}
  49EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
  50
  51
  52int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
  53                                   struct cpufreq_frequency_table *table)
  54{
  55        unsigned int next_larger = ~0;
  56        unsigned int i;
  57        unsigned int count = 0;
  58
  59        dprintk("request for verification of policy (%u - %u kHz) for cpu %u\n",
  60                                        policy->min, policy->max, policy->cpu);
  61
  62        if (!cpu_online(policy->cpu))
  63                return -EINVAL;
  64
  65        cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
  66                                     policy->cpuinfo.max_freq);
  67
  68        for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
  69                unsigned int freq = table[i].frequency;
  70                if (freq == CPUFREQ_ENTRY_INVALID)
  71                        continue;
  72                if ((freq >= policy->min) && (freq <= policy->max))
  73                        count++;
  74                else if ((next_larger > freq) && (freq > policy->max))
  75                        next_larger = freq;
  76        }
  77
  78        if (!count)
  79                policy->max = next_larger;
  80
  81        cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
  82                                     policy->cpuinfo.max_freq);
  83
  84        dprintk("verification lead to (%u - %u kHz) for cpu %u\n",
  85                                policy->min, policy->max, policy->cpu);
  86
  87        return 0;
  88}
  89EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
  90
  91
  92int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
  93                                   struct cpufreq_frequency_table *table,
  94                                   unsigned int target_freq,
  95                                   unsigned int relation,
  96                                   unsigned int *index)
  97{
  98        struct cpufreq_frequency_table optimal = {
  99                .index = ~0,
 100                .frequency = 0,
 101        };
 102        struct cpufreq_frequency_table suboptimal = {
 103                .index = ~0,
 104                .frequency = 0,
 105        };
 106        unsigned int i;
 107
 108        dprintk("request for target %u kHz (relation: %u) for cpu %u\n",
 109                                        target_freq, relation, policy->cpu);
 110
 111        switch (relation) {
 112        case CPUFREQ_RELATION_H:
 113                suboptimal.frequency = ~0;
 114                break;
 115        case CPUFREQ_RELATION_L:
 116                optimal.frequency = ~0;
 117                break;
 118        }
 119
 120        if (!cpu_online(policy->cpu))
 121                return -EINVAL;
 122
 123        for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
 124                unsigned int freq = table[i].frequency;
 125                if (freq == CPUFREQ_ENTRY_INVALID)
 126                        continue;
 127                if ((freq < policy->min) || (freq > policy->max))
 128                        continue;
 129                switch(relation) {
 130                case CPUFREQ_RELATION_H:
 131                        if (freq <= target_freq) {
 132                                if (freq >= optimal.frequency) {
 133                                        optimal.frequency = freq;
 134                                        optimal.index = i;
 135                                }
 136                        } else {
 137                                if (freq <= suboptimal.frequency) {
 138                                        suboptimal.frequency = freq;
 139                                        suboptimal.index = i;
 140                                }
 141                        }
 142                        break;
 143                case CPUFREQ_RELATION_L:
 144                        if (freq >= target_freq) {
 145                                if (freq <= optimal.frequency) {
 146                                        optimal.frequency = freq;
 147                                        optimal.index = i;
 148                                }
 149                        } else {
 150                                if (freq >= suboptimal.frequency) {
 151                                        suboptimal.frequency = freq;
 152                                        suboptimal.index = i;
 153                                }
 154                        }
 155                        break;
 156                }
 157        }
 158        if (optimal.index > i) {
 159                if (suboptimal.index > i)
 160                        return -EINVAL;
 161                *index = suboptimal.index;
 162        } else
 163                *index = optimal.index;
 164
 165        dprintk("target is %u (%u kHz, %u)\n", *index, table[*index].frequency,
 166                table[*index].index);
 167
 168        return 0;
 169}
 170EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
 171
 172static struct cpufreq_frequency_table *show_table[NR_CPUS];
 173/**
 174 * show_scaling_governor - show the current policy for the specified CPU
 175 */
 176static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)
 177{
 178        unsigned int i = 0;
 179        unsigned int cpu = policy->cpu;
 180        ssize_t count = 0;
 181        struct cpufreq_frequency_table *table;
 182
 183        if (!show_table[cpu])
 184                return -ENODEV;
 185
 186        table = show_table[cpu];
 187
 188        for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
 189                if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
 190                        continue;
 191                count += sprintf(&buf[count], "%d ", table[i].frequency);
 192        }
 193        count += sprintf(&buf[count], "\n");
 194
 195        return count;
 196
 197}
 198
 199struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
 200        .attr = { .name = "scaling_available_frequencies",
 201                  .mode = 0444,
 202                },
 203        .show = show_available_freqs,
 204};
 205EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
 206
 207/*
 208 * if you use these, you must assure that the frequency table is valid
 209 * all the time between get_attr and put_attr!
 210 */
 211void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
 212                                      unsigned int cpu)
 213{
 214        dprintk("setting show_table for cpu %u to %p\n", cpu, table);
 215        show_table[cpu] = table;
 216}
 217EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr);
 218
 219void cpufreq_frequency_table_put_attr(unsigned int cpu)
 220{
 221        dprintk("clearing show_table for cpu %u\n", cpu);
 222        show_table[cpu] = NULL;
 223}
 224EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
 225
 226struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
 227{
 228        return show_table[cpu];
 229}
 230EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
 231
 232MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
 233MODULE_DESCRIPTION ("CPUfreq frequency table helpers");
 234MODULE_LICENSE ("GPL");
 235