root/drivers/cpufreq/ia64-acpi-cpufreq.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. processor_set_pstate
  2. processor_get_pstate
  3. extract_clock
  4. processor_get_freq
  5. processor_set_freq
  6. acpi_cpufreq_get
  7. acpi_cpufreq_target
  8. acpi_cpufreq_cpu_init
  9. acpi_cpufreq_cpu_exit
  10. acpi_cpufreq_init
  11. acpi_cpufreq_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * This file provides the ACPI based P-state support. This
   4  * module works with generic cpufreq infrastructure. Most of
   5  * the code is based on i386 version
   6  * (arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c)
   7  *
   8  * Copyright (C) 2005 Intel Corp
   9  *      Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
  10  */
  11 
  12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  13 
  14 #include <linux/kernel.h>
  15 #include <linux/slab.h>
  16 #include <linux/module.h>
  17 #include <linux/init.h>
  18 #include <linux/cpufreq.h>
  19 #include <linux/proc_fs.h>
  20 #include <asm/io.h>
  21 #include <linux/uaccess.h>
  22 #include <asm/pal.h>
  23 
  24 #include <linux/acpi.h>
  25 #include <acpi/processor.h>
  26 
  27 MODULE_AUTHOR("Venkatesh Pallipadi");
  28 MODULE_DESCRIPTION("ACPI Processor P-States Driver");
  29 MODULE_LICENSE("GPL");
  30 
  31 struct cpufreq_acpi_io {
  32         struct acpi_processor_performance       acpi_data;
  33         unsigned int                            resume;
  34 };
  35 
  36 struct cpufreq_acpi_req {
  37         unsigned int            cpu;
  38         unsigned int            state;
  39 };
  40 
  41 static struct cpufreq_acpi_io   *acpi_io_data[NR_CPUS];
  42 
  43 static struct cpufreq_driver acpi_cpufreq_driver;
  44 
  45 
  46 static int
  47 processor_set_pstate (
  48         u32     value)
  49 {
  50         s64 retval;
  51 
  52         pr_debug("processor_set_pstate\n");
  53 
  54         retval = ia64_pal_set_pstate((u64)value);
  55 
  56         if (retval) {
  57                 pr_debug("Failed to set freq to 0x%x, with error 0x%lx\n",
  58                         value, retval);
  59                 return -ENODEV;
  60         }
  61         return (int)retval;
  62 }
  63 
  64 
  65 static int
  66 processor_get_pstate (
  67         u32     *value)
  68 {
  69         u64     pstate_index = 0;
  70         s64     retval;
  71 
  72         pr_debug("processor_get_pstate\n");
  73 
  74         retval = ia64_pal_get_pstate(&pstate_index,
  75                                      PAL_GET_PSTATE_TYPE_INSTANT);
  76         *value = (u32) pstate_index;
  77 
  78         if (retval)
  79                 pr_debug("Failed to get current freq with "
  80                         "error 0x%lx, idx 0x%x\n", retval, *value);
  81 
  82         return (int)retval;
  83 }
  84 
  85 
  86 /* To be used only after data->acpi_data is initialized */
  87 static unsigned
  88 extract_clock (
  89         struct cpufreq_acpi_io *data,
  90         unsigned value)
  91 {
  92         unsigned long i;
  93 
  94         pr_debug("extract_clock\n");
  95 
  96         for (i = 0; i < data->acpi_data.state_count; i++) {
  97                 if (value == data->acpi_data.states[i].status)
  98                         return data->acpi_data.states[i].core_frequency;
  99         }
 100         return data->acpi_data.states[i-1].core_frequency;
 101 }
 102 
 103 
 104 static long
 105 processor_get_freq (
 106         void *arg)
 107 {
 108         struct cpufreq_acpi_req *req = arg;
 109         unsigned int            cpu = req->cpu;
 110         struct cpufreq_acpi_io  *data = acpi_io_data[cpu];
 111         u32                     value;
 112         int                     ret;
 113 
 114         pr_debug("processor_get_freq\n");
 115         if (smp_processor_id() != cpu)
 116                 return -EAGAIN;
 117 
 118         /* processor_get_pstate gets the instantaneous frequency */
 119         ret = processor_get_pstate(&value);
 120         if (ret) {
 121                 pr_warn("get performance failed with error %d\n", ret);
 122                 return ret;
 123         }
 124         return 1000 * extract_clock(data, value);
 125 }
 126 
 127 
 128 static long
 129 processor_set_freq (
 130         void *arg)
 131 {
 132         struct cpufreq_acpi_req *req = arg;
 133         unsigned int            cpu = req->cpu;
 134         struct cpufreq_acpi_io  *data = acpi_io_data[cpu];
 135         int                     ret, state = req->state;
 136         u32                     value;
 137 
 138         pr_debug("processor_set_freq\n");
 139         if (smp_processor_id() != cpu)
 140                 return -EAGAIN;
 141 
 142         if (state == data->acpi_data.state) {
 143                 if (unlikely(data->resume)) {
 144                         pr_debug("Called after resume, resetting to P%d\n", state);
 145                         data->resume = 0;
 146                 } else {
 147                         pr_debug("Already at target state (P%d)\n", state);
 148                         return 0;
 149                 }
 150         }
 151 
 152         pr_debug("Transitioning from P%d to P%d\n",
 153                 data->acpi_data.state, state);
 154 
 155         /*
 156          * First we write the target state's 'control' value to the
 157          * control_register.
 158          */
 159         value = (u32) data->acpi_data.states[state].control;
 160 
 161         pr_debug("Transitioning to state: 0x%08x\n", value);
 162 
 163         ret = processor_set_pstate(value);
 164         if (ret) {
 165                 pr_warn("Transition failed with error %d\n", ret);
 166                 return -ENODEV;
 167         }
 168 
 169         data->acpi_data.state = state;
 170         return 0;
 171 }
 172 
 173 
 174 static unsigned int
 175 acpi_cpufreq_get (
 176         unsigned int            cpu)
 177 {
 178         struct cpufreq_acpi_req req;
 179         long ret;
 180 
 181         req.cpu = cpu;
 182         ret = work_on_cpu(cpu, processor_get_freq, &req);
 183 
 184         return ret > 0 ? (unsigned int) ret : 0;
 185 }
 186 
 187 
 188 static int
 189 acpi_cpufreq_target (
 190         struct cpufreq_policy   *policy,
 191         unsigned int index)
 192 {
 193         struct cpufreq_acpi_req req;
 194 
 195         req.cpu = policy->cpu;
 196         req.state = index;
 197 
 198         return work_on_cpu(req.cpu, processor_set_freq, &req);
 199 }
 200 
 201 static int
 202 acpi_cpufreq_cpu_init (
 203         struct cpufreq_policy   *policy)
 204 {
 205         unsigned int            i;
 206         unsigned int            cpu = policy->cpu;
 207         struct cpufreq_acpi_io  *data;
 208         unsigned int            result = 0;
 209         struct cpufreq_frequency_table *freq_table;
 210 
 211         pr_debug("acpi_cpufreq_cpu_init\n");
 212 
 213         data = kzalloc(sizeof(*data), GFP_KERNEL);
 214         if (!data)
 215                 return (-ENOMEM);
 216 
 217         acpi_io_data[cpu] = data;
 218 
 219         result = acpi_processor_register_performance(&data->acpi_data, cpu);
 220 
 221         if (result)
 222                 goto err_free;
 223 
 224         /* capability check */
 225         if (data->acpi_data.state_count <= 1) {
 226                 pr_debug("No P-States\n");
 227                 result = -ENODEV;
 228                 goto err_unreg;
 229         }
 230 
 231         if ((data->acpi_data.control_register.space_id !=
 232                                         ACPI_ADR_SPACE_FIXED_HARDWARE) ||
 233             (data->acpi_data.status_register.space_id !=
 234                                         ACPI_ADR_SPACE_FIXED_HARDWARE)) {
 235                 pr_debug("Unsupported address space [%d, %d]\n",
 236                         (u32) (data->acpi_data.control_register.space_id),
 237                         (u32) (data->acpi_data.status_register.space_id));
 238                 result = -ENODEV;
 239                 goto err_unreg;
 240         }
 241 
 242         /* alloc freq_table */
 243         freq_table = kcalloc(data->acpi_data.state_count + 1,
 244                                    sizeof(*freq_table),
 245                                    GFP_KERNEL);
 246         if (!freq_table) {
 247                 result = -ENOMEM;
 248                 goto err_unreg;
 249         }
 250 
 251         /* detect transition latency */
 252         policy->cpuinfo.transition_latency = 0;
 253         for (i=0; i<data->acpi_data.state_count; i++) {
 254                 if ((data->acpi_data.states[i].transition_latency * 1000) >
 255                     policy->cpuinfo.transition_latency) {
 256                         policy->cpuinfo.transition_latency =
 257                             data->acpi_data.states[i].transition_latency * 1000;
 258                 }
 259         }
 260 
 261         /* table init */
 262         for (i = 0; i <= data->acpi_data.state_count; i++)
 263         {
 264                 if (i < data->acpi_data.state_count) {
 265                         freq_table[i].frequency =
 266                               data->acpi_data.states[i].core_frequency * 1000;
 267                 } else {
 268                         freq_table[i].frequency = CPUFREQ_TABLE_END;
 269                 }
 270         }
 271 
 272         policy->freq_table = freq_table;
 273 
 274         /* notify BIOS that we exist */
 275         acpi_processor_notify_smm(THIS_MODULE);
 276 
 277         pr_info("CPU%u - ACPI performance management activated\n", cpu);
 278 
 279         for (i = 0; i < data->acpi_data.state_count; i++)
 280                 pr_debug("     %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n",
 281                         (i == data->acpi_data.state?'*':' '), i,
 282                         (u32) data->acpi_data.states[i].core_frequency,
 283                         (u32) data->acpi_data.states[i].power,
 284                         (u32) data->acpi_data.states[i].transition_latency,
 285                         (u32) data->acpi_data.states[i].bus_master_latency,
 286                         (u32) data->acpi_data.states[i].status,
 287                         (u32) data->acpi_data.states[i].control);
 288 
 289         /* the first call to ->target() should result in us actually
 290          * writing something to the appropriate registers. */
 291         data->resume = 1;
 292 
 293         return (result);
 294 
 295  err_unreg:
 296         acpi_processor_unregister_performance(cpu);
 297  err_free:
 298         kfree(data);
 299         acpi_io_data[cpu] = NULL;
 300 
 301         return (result);
 302 }
 303 
 304 
 305 static int
 306 acpi_cpufreq_cpu_exit (
 307         struct cpufreq_policy   *policy)
 308 {
 309         struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
 310 
 311         pr_debug("acpi_cpufreq_cpu_exit\n");
 312 
 313         if (data) {
 314                 acpi_io_data[policy->cpu] = NULL;
 315                 acpi_processor_unregister_performance(policy->cpu);
 316                 kfree(policy->freq_table);
 317                 kfree(data);
 318         }
 319 
 320         return (0);
 321 }
 322 
 323 
 324 static struct cpufreq_driver acpi_cpufreq_driver = {
 325         .verify         = cpufreq_generic_frequency_table_verify,
 326         .target_index   = acpi_cpufreq_target,
 327         .get            = acpi_cpufreq_get,
 328         .init           = acpi_cpufreq_cpu_init,
 329         .exit           = acpi_cpufreq_cpu_exit,
 330         .name           = "acpi-cpufreq",
 331         .attr           = cpufreq_generic_attr,
 332 };
 333 
 334 
 335 static int __init
 336 acpi_cpufreq_init (void)
 337 {
 338         pr_debug("acpi_cpufreq_init\n");
 339 
 340         return cpufreq_register_driver(&acpi_cpufreq_driver);
 341 }
 342 
 343 
 344 static void __exit
 345 acpi_cpufreq_exit (void)
 346 {
 347         pr_debug("acpi_cpufreq_exit\n");
 348 
 349         cpufreq_unregister_driver(&acpi_cpufreq_driver);
 350 }
 351 
 352 late_initcall(acpi_cpufreq_init);
 353 module_exit(acpi_cpufreq_exit);

/* [<][>][^][v][top][bottom][index][help] */