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