root/drivers/cpufreq/pcc-cpufreq.c

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

DEFINITIONS

This source file includes following definitions.
  1. pcc_cpufreq_verify
  2. pcc_cmd
  3. pcc_clear_mapping
  4. pcc_get_freq
  5. pcc_cpufreq_target
  6. pcc_get_offset
  7. pcc_cpufreq_do_osc
  8. pcc_cpufreq_probe
  9. pcc_cpufreq_cpu_init
  10. pcc_cpufreq_cpu_exit
  11. pcc_cpufreq_init
  12. pcc_cpufreq_exit

   1 /*
   2  *  pcc-cpufreq.c - Processor Clocking Control firmware cpufreq interface
   3  *
   4  *  Copyright (C) 2009 Red Hat, Matthew Garrett <mjg@redhat.com>
   5  *  Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
   6  *      Nagananda Chumbalkar <nagananda.chumbalkar@hp.com>
   7  *
   8  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   9  *
  10  *  This program is free software; you can redistribute it and/or modify
  11  *  it under the terms of the GNU General Public License as published by
  12  *  the Free Software Foundation; version 2 of the License.
  13  *
  14  *  This program is distributed in the hope that it will be useful, but
  15  *  WITHOUT ANY WARRANTY; without even the implied warranty of
  16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or NON
  17  *  INFRINGEMENT. See the GNU General Public License for more details.
  18  *
  19  *  You should have received a copy of the GNU General Public License along
  20  *  with this program; if not, write to the Free Software Foundation, Inc.,
  21  *  675 Mass Ave, Cambridge, MA 02139, USA.
  22  *
  23  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  24  */
  25 
  26 #include <linux/kernel.h>
  27 #include <linux/module.h>
  28 #include <linux/init.h>
  29 #include <linux/smp.h>
  30 #include <linux/sched.h>
  31 #include <linux/cpufreq.h>
  32 #include <linux/compiler.h>
  33 #include <linux/slab.h>
  34 
  35 #include <linux/acpi.h>
  36 #include <linux/io.h>
  37 #include <linux/spinlock.h>
  38 #include <linux/uaccess.h>
  39 
  40 #include <acpi/processor.h>
  41 
  42 #define PCC_VERSION     "1.10.00"
  43 #define POLL_LOOPS      300
  44 
  45 #define CMD_COMPLETE    0x1
  46 #define CMD_GET_FREQ    0x0
  47 #define CMD_SET_FREQ    0x1
  48 
  49 #define BUF_SZ          4
  50 
  51 struct pcc_register_resource {
  52         u8 descriptor;
  53         u16 length;
  54         u8 space_id;
  55         u8 bit_width;
  56         u8 bit_offset;
  57         u8 access_size;
  58         u64 address;
  59 } __attribute__ ((packed));
  60 
  61 struct pcc_memory_resource {
  62         u8 descriptor;
  63         u16 length;
  64         u8 space_id;
  65         u8 resource_usage;
  66         u8 type_specific;
  67         u64 granularity;
  68         u64 minimum;
  69         u64 maximum;
  70         u64 translation_offset;
  71         u64 address_length;
  72 } __attribute__ ((packed));
  73 
  74 static struct cpufreq_driver pcc_cpufreq_driver;
  75 
  76 struct pcc_header {
  77         u32 signature;
  78         u16 length;
  79         u8 major;
  80         u8 minor;
  81         u32 features;
  82         u16 command;
  83         u16 status;
  84         u32 latency;
  85         u32 minimum_time;
  86         u32 maximum_time;
  87         u32 nominal;
  88         u32 throttled_frequency;
  89         u32 minimum_frequency;
  90 };
  91 
  92 static void __iomem *pcch_virt_addr;
  93 static struct pcc_header __iomem *pcch_hdr;
  94 
  95 static DEFINE_SPINLOCK(pcc_lock);
  96 
  97 static struct acpi_generic_address doorbell;
  98 
  99 static u64 doorbell_preserve;
 100 static u64 doorbell_write;
 101 
 102 static u8 OSC_UUID[16] = {0x9F, 0x2C, 0x9B, 0x63, 0x91, 0x70, 0x1f, 0x49,
 103                           0xBB, 0x4F, 0xA5, 0x98, 0x2F, 0xA1, 0xB5, 0x46};
 104 
 105 struct pcc_cpu {
 106         u32 input_offset;
 107         u32 output_offset;
 108 };
 109 
 110 static struct pcc_cpu __percpu *pcc_cpu_info;
 111 
 112 static int pcc_cpufreq_verify(struct cpufreq_policy_data *policy)
 113 {
 114         cpufreq_verify_within_cpu_limits(policy);
 115         return 0;
 116 }
 117 
 118 static inline void pcc_cmd(void)
 119 {
 120         u64 doorbell_value;
 121         int i;
 122 
 123         acpi_read(&doorbell_value, &doorbell);
 124         acpi_write((doorbell_value & doorbell_preserve) | doorbell_write,
 125                    &doorbell);
 126 
 127         for (i = 0; i < POLL_LOOPS; i++) {
 128                 if (ioread16(&pcch_hdr->status) & CMD_COMPLETE)
 129                         break;
 130         }
 131 }
 132 
 133 static inline void pcc_clear_mapping(void)
 134 {
 135         if (pcch_virt_addr)
 136                 iounmap(pcch_virt_addr);
 137         pcch_virt_addr = NULL;
 138 }
 139 
 140 static unsigned int pcc_get_freq(unsigned int cpu)
 141 {
 142         struct pcc_cpu *pcc_cpu_data;
 143         unsigned int curr_freq;
 144         unsigned int freq_limit;
 145         u16 status;
 146         u32 input_buffer;
 147         u32 output_buffer;
 148 
 149         spin_lock(&pcc_lock);
 150 
 151         pr_debug("get: get_freq for CPU %d\n", cpu);
 152         pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
 153 
 154         input_buffer = 0x1;
 155         iowrite32(input_buffer,
 156                         (pcch_virt_addr + pcc_cpu_data->input_offset));
 157         iowrite16(CMD_GET_FREQ, &pcch_hdr->command);
 158 
 159         pcc_cmd();
 160 
 161         output_buffer =
 162                 ioread32(pcch_virt_addr + pcc_cpu_data->output_offset);
 163 
 164         /* Clear the input buffer - we are done with the current command */
 165         memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ);
 166 
 167         status = ioread16(&pcch_hdr->status);
 168         if (status != CMD_COMPLETE) {
 169                 pr_debug("get: FAILED: for CPU %d, status is %d\n",
 170                         cpu, status);
 171                 goto cmd_incomplete;
 172         }
 173         iowrite16(0, &pcch_hdr->status);
 174         curr_freq = (((ioread32(&pcch_hdr->nominal) * (output_buffer & 0xff))
 175                         / 100) * 1000);
 176 
 177         pr_debug("get: SUCCESS: (virtual) output_offset for cpu %d is "
 178                 "0x%p, contains a value of: 0x%x. Speed is: %d MHz\n",
 179                 cpu, (pcch_virt_addr + pcc_cpu_data->output_offset),
 180                 output_buffer, curr_freq);
 181 
 182         freq_limit = (output_buffer >> 8) & 0xff;
 183         if (freq_limit != 0xff) {
 184                 pr_debug("get: frequency for cpu %d is being temporarily"
 185                         " capped at %d\n", cpu, curr_freq);
 186         }
 187 
 188         spin_unlock(&pcc_lock);
 189         return curr_freq;
 190 
 191 cmd_incomplete:
 192         iowrite16(0, &pcch_hdr->status);
 193         spin_unlock(&pcc_lock);
 194         return 0;
 195 }
 196 
 197 static int pcc_cpufreq_target(struct cpufreq_policy *policy,
 198                               unsigned int target_freq,
 199                               unsigned int relation)
 200 {
 201         struct pcc_cpu *pcc_cpu_data;
 202         struct cpufreq_freqs freqs;
 203         u16 status;
 204         u32 input_buffer;
 205         int cpu;
 206 
 207         cpu = policy->cpu;
 208         pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
 209 
 210         pr_debug("target: CPU %d should go to target freq: %d "
 211                 "(virtual) input_offset is 0x%p\n",
 212                 cpu, target_freq,
 213                 (pcch_virt_addr + pcc_cpu_data->input_offset));
 214 
 215         freqs.old = policy->cur;
 216         freqs.new = target_freq;
 217         cpufreq_freq_transition_begin(policy, &freqs);
 218         spin_lock(&pcc_lock);
 219 
 220         input_buffer = 0x1 | (((target_freq * 100)
 221                                / (ioread32(&pcch_hdr->nominal) * 1000)) << 8);
 222         iowrite32(input_buffer,
 223                         (pcch_virt_addr + pcc_cpu_data->input_offset));
 224         iowrite16(CMD_SET_FREQ, &pcch_hdr->command);
 225 
 226         pcc_cmd();
 227 
 228         /* Clear the input buffer - we are done with the current command */
 229         memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ);
 230 
 231         status = ioread16(&pcch_hdr->status);
 232         iowrite16(0, &pcch_hdr->status);
 233 
 234         cpufreq_freq_transition_end(policy, &freqs, status != CMD_COMPLETE);
 235         spin_unlock(&pcc_lock);
 236 
 237         if (status != CMD_COMPLETE) {
 238                 pr_debug("target: FAILED for cpu %d, with status: 0x%x\n",
 239                         cpu, status);
 240                 return -EINVAL;
 241         }
 242 
 243         pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu);
 244 
 245         return 0;
 246 }
 247 
 248 static int pcc_get_offset(int cpu)
 249 {
 250         acpi_status status;
 251         struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
 252         union acpi_object *pccp, *offset;
 253         struct pcc_cpu *pcc_cpu_data;
 254         struct acpi_processor *pr;
 255         int ret = 0;
 256 
 257         pr = per_cpu(processors, cpu);
 258         pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
 259 
 260         if (!pr)
 261                 return -ENODEV;
 262 
 263         status = acpi_evaluate_object(pr->handle, "PCCP", NULL, &buffer);
 264         if (ACPI_FAILURE(status))
 265                 return -ENODEV;
 266 
 267         pccp = buffer.pointer;
 268         if (!pccp || pccp->type != ACPI_TYPE_PACKAGE) {
 269                 ret = -ENODEV;
 270                 goto out_free;
 271         }
 272 
 273         offset = &(pccp->package.elements[0]);
 274         if (!offset || offset->type != ACPI_TYPE_INTEGER) {
 275                 ret = -ENODEV;
 276                 goto out_free;
 277         }
 278 
 279         pcc_cpu_data->input_offset = offset->integer.value;
 280 
 281         offset = &(pccp->package.elements[1]);
 282         if (!offset || offset->type != ACPI_TYPE_INTEGER) {
 283                 ret = -ENODEV;
 284                 goto out_free;
 285         }
 286 
 287         pcc_cpu_data->output_offset = offset->integer.value;
 288 
 289         memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ);
 290         memset_io((pcch_virt_addr + pcc_cpu_data->output_offset), 0, BUF_SZ);
 291 
 292         pr_debug("pcc_get_offset: for CPU %d: pcc_cpu_data "
 293                 "input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n",
 294                 cpu, pcc_cpu_data->input_offset, pcc_cpu_data->output_offset);
 295 out_free:
 296         kfree(buffer.pointer);
 297         return ret;
 298 }
 299 
 300 static int __init pcc_cpufreq_do_osc(acpi_handle *handle)
 301 {
 302         acpi_status status;
 303         struct acpi_object_list input;
 304         struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
 305         union acpi_object in_params[4];
 306         union acpi_object *out_obj;
 307         u32 capabilities[2];
 308         u32 errors;
 309         u32 supported;
 310         int ret = 0;
 311 
 312         input.count = 4;
 313         input.pointer = in_params;
 314         in_params[0].type               = ACPI_TYPE_BUFFER;
 315         in_params[0].buffer.length      = 16;
 316         in_params[0].buffer.pointer     = OSC_UUID;
 317         in_params[1].type               = ACPI_TYPE_INTEGER;
 318         in_params[1].integer.value      = 1;
 319         in_params[2].type               = ACPI_TYPE_INTEGER;
 320         in_params[2].integer.value      = 2;
 321         in_params[3].type               = ACPI_TYPE_BUFFER;
 322         in_params[3].buffer.length      = 8;
 323         in_params[3].buffer.pointer     = (u8 *)&capabilities;
 324 
 325         capabilities[0] = OSC_QUERY_ENABLE;
 326         capabilities[1] = 0x1;
 327 
 328         status = acpi_evaluate_object(*handle, "_OSC", &input, &output);
 329         if (ACPI_FAILURE(status))
 330                 return -ENODEV;
 331 
 332         if (!output.length)
 333                 return -ENODEV;
 334 
 335         out_obj = output.pointer;
 336         if (out_obj->type != ACPI_TYPE_BUFFER) {
 337                 ret = -ENODEV;
 338                 goto out_free;
 339         }
 340 
 341         errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
 342         if (errors) {
 343                 ret = -ENODEV;
 344                 goto out_free;
 345         }
 346 
 347         supported = *((u32 *)(out_obj->buffer.pointer + 4));
 348         if (!(supported & 0x1)) {
 349                 ret = -ENODEV;
 350                 goto out_free;
 351         }
 352 
 353         kfree(output.pointer);
 354         capabilities[0] = 0x0;
 355         capabilities[1] = 0x1;
 356 
 357         status = acpi_evaluate_object(*handle, "_OSC", &input, &output);
 358         if (ACPI_FAILURE(status))
 359                 return -ENODEV;
 360 
 361         if (!output.length)
 362                 return -ENODEV;
 363 
 364         out_obj = output.pointer;
 365         if (out_obj->type != ACPI_TYPE_BUFFER) {
 366                 ret = -ENODEV;
 367                 goto out_free;
 368         }
 369 
 370         errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
 371         if (errors) {
 372                 ret = -ENODEV;
 373                 goto out_free;
 374         }
 375 
 376         supported = *((u32 *)(out_obj->buffer.pointer + 4));
 377         if (!(supported & 0x1)) {
 378                 ret = -ENODEV;
 379                 goto out_free;
 380         }
 381 
 382 out_free:
 383         kfree(output.pointer);
 384         return ret;
 385 }
 386 
 387 static int __init pcc_cpufreq_probe(void)
 388 {
 389         acpi_status status;
 390         struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
 391         struct pcc_memory_resource *mem_resource;
 392         struct pcc_register_resource *reg_resource;
 393         union acpi_object *out_obj, *member;
 394         acpi_handle handle, osc_handle;
 395         int ret = 0;
 396 
 397         status = acpi_get_handle(NULL, "\\_SB", &handle);
 398         if (ACPI_FAILURE(status))
 399                 return -ENODEV;
 400 
 401         if (!acpi_has_method(handle, "PCCH"))
 402                 return -ENODEV;
 403 
 404         status = acpi_get_handle(handle, "_OSC", &osc_handle);
 405         if (ACPI_SUCCESS(status)) {
 406                 ret = pcc_cpufreq_do_osc(&osc_handle);
 407                 if (ret)
 408                         pr_debug("probe: _OSC evaluation did not succeed\n");
 409                 /* Firmware's use of _OSC is optional */
 410                 ret = 0;
 411         }
 412 
 413         status = acpi_evaluate_object(handle, "PCCH", NULL, &output);
 414         if (ACPI_FAILURE(status))
 415                 return -ENODEV;
 416 
 417         out_obj = output.pointer;
 418         if (out_obj->type != ACPI_TYPE_PACKAGE) {
 419                 ret = -ENODEV;
 420                 goto out_free;
 421         }
 422 
 423         member = &out_obj->package.elements[0];
 424         if (member->type != ACPI_TYPE_BUFFER) {
 425                 ret = -ENODEV;
 426                 goto out_free;
 427         }
 428 
 429         mem_resource = (struct pcc_memory_resource *)member->buffer.pointer;
 430 
 431         pr_debug("probe: mem_resource descriptor: 0x%x,"
 432                 " length: %d, space_id: %d, resource_usage: %d,"
 433                 " type_specific: %d, granularity: 0x%llx,"
 434                 " minimum: 0x%llx, maximum: 0x%llx,"
 435                 " translation_offset: 0x%llx, address_length: 0x%llx\n",
 436                 mem_resource->descriptor, mem_resource->length,
 437                 mem_resource->space_id, mem_resource->resource_usage,
 438                 mem_resource->type_specific, mem_resource->granularity,
 439                 mem_resource->minimum, mem_resource->maximum,
 440                 mem_resource->translation_offset,
 441                 mem_resource->address_length);
 442 
 443         if (mem_resource->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
 444                 ret = -ENODEV;
 445                 goto out_free;
 446         }
 447 
 448         pcch_virt_addr = ioremap_nocache(mem_resource->minimum,
 449                                         mem_resource->address_length);
 450         if (pcch_virt_addr == NULL) {
 451                 pr_debug("probe: could not map shared mem region\n");
 452                 ret = -ENOMEM;
 453                 goto out_free;
 454         }
 455         pcch_hdr = pcch_virt_addr;
 456 
 457         pr_debug("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr);
 458         pr_debug("probe: PCCH header is at physical address: 0x%llx,"
 459                 " signature: 0x%x, length: %d bytes, major: %d, minor: %d,"
 460                 " supported features: 0x%x, command field: 0x%x,"
 461                 " status field: 0x%x, nominal latency: %d us\n",
 462                 mem_resource->minimum, ioread32(&pcch_hdr->signature),
 463                 ioread16(&pcch_hdr->length), ioread8(&pcch_hdr->major),
 464                 ioread8(&pcch_hdr->minor), ioread32(&pcch_hdr->features),
 465                 ioread16(&pcch_hdr->command), ioread16(&pcch_hdr->status),
 466                 ioread32(&pcch_hdr->latency));
 467 
 468         pr_debug("probe: min time between commands: %d us,"
 469                 " max time between commands: %d us,"
 470                 " nominal CPU frequency: %d MHz,"
 471                 " minimum CPU frequency: %d MHz,"
 472                 " minimum CPU frequency without throttling: %d MHz\n",
 473                 ioread32(&pcch_hdr->minimum_time),
 474                 ioread32(&pcch_hdr->maximum_time),
 475                 ioread32(&pcch_hdr->nominal),
 476                 ioread32(&pcch_hdr->throttled_frequency),
 477                 ioread32(&pcch_hdr->minimum_frequency));
 478 
 479         member = &out_obj->package.elements[1];
 480         if (member->type != ACPI_TYPE_BUFFER) {
 481                 ret = -ENODEV;
 482                 goto pcch_free;
 483         }
 484 
 485         reg_resource = (struct pcc_register_resource *)member->buffer.pointer;
 486 
 487         doorbell.space_id = reg_resource->space_id;
 488         doorbell.bit_width = reg_resource->bit_width;
 489         doorbell.bit_offset = reg_resource->bit_offset;
 490         doorbell.access_width = 4;
 491         doorbell.address = reg_resource->address;
 492 
 493         pr_debug("probe: doorbell: space_id is %d, bit_width is %d, "
 494                 "bit_offset is %d, access_width is %d, address is 0x%llx\n",
 495                 doorbell.space_id, doorbell.bit_width, doorbell.bit_offset,
 496                 doorbell.access_width, reg_resource->address);
 497 
 498         member = &out_obj->package.elements[2];
 499         if (member->type != ACPI_TYPE_INTEGER) {
 500                 ret = -ENODEV;
 501                 goto pcch_free;
 502         }
 503 
 504         doorbell_preserve = member->integer.value;
 505 
 506         member = &out_obj->package.elements[3];
 507         if (member->type != ACPI_TYPE_INTEGER) {
 508                 ret = -ENODEV;
 509                 goto pcch_free;
 510         }
 511 
 512         doorbell_write = member->integer.value;
 513 
 514         pr_debug("probe: doorbell_preserve: 0x%llx,"
 515                 " doorbell_write: 0x%llx\n",
 516                 doorbell_preserve, doorbell_write);
 517 
 518         pcc_cpu_info = alloc_percpu(struct pcc_cpu);
 519         if (!pcc_cpu_info) {
 520                 ret = -ENOMEM;
 521                 goto pcch_free;
 522         }
 523 
 524         printk(KERN_DEBUG "pcc-cpufreq: (v%s) driver loaded with frequency"
 525                " limits: %d MHz, %d MHz\n", PCC_VERSION,
 526                ioread32(&pcch_hdr->minimum_frequency),
 527                ioread32(&pcch_hdr->nominal));
 528         kfree(output.pointer);
 529         return ret;
 530 pcch_free:
 531         pcc_clear_mapping();
 532 out_free:
 533         kfree(output.pointer);
 534         return ret;
 535 }
 536 
 537 static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy)
 538 {
 539         unsigned int cpu = policy->cpu;
 540         unsigned int result = 0;
 541 
 542         if (!pcch_virt_addr) {
 543                 result = -1;
 544                 goto out;
 545         }
 546 
 547         result = pcc_get_offset(cpu);
 548         if (result) {
 549                 pr_debug("init: PCCP evaluation failed\n");
 550                 goto out;
 551         }
 552 
 553         policy->max = policy->cpuinfo.max_freq =
 554                 ioread32(&pcch_hdr->nominal) * 1000;
 555         policy->min = policy->cpuinfo.min_freq =
 556                 ioread32(&pcch_hdr->minimum_frequency) * 1000;
 557 
 558         pr_debug("init: policy->max is %d, policy->min is %d\n",
 559                 policy->max, policy->min);
 560 out:
 561         return result;
 562 }
 563 
 564 static int pcc_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 565 {
 566         return 0;
 567 }
 568 
 569 static struct cpufreq_driver pcc_cpufreq_driver = {
 570         .flags = CPUFREQ_CONST_LOOPS,
 571         .get = pcc_get_freq,
 572         .verify = pcc_cpufreq_verify,
 573         .target = pcc_cpufreq_target,
 574         .init = pcc_cpufreq_cpu_init,
 575         .exit = pcc_cpufreq_cpu_exit,
 576         .name = "pcc-cpufreq",
 577 };
 578 
 579 static int __init pcc_cpufreq_init(void)
 580 {
 581         int ret;
 582 
 583         /* Skip initialization if another cpufreq driver is there. */
 584         if (cpufreq_get_current_driver())
 585                 return -EEXIST;
 586 
 587         if (acpi_disabled)
 588                 return -ENODEV;
 589 
 590         ret = pcc_cpufreq_probe();
 591         if (ret) {
 592                 pr_debug("pcc_cpufreq_init: PCCH evaluation failed\n");
 593                 return ret;
 594         }
 595 
 596         if (num_present_cpus() > 4) {
 597                 pcc_cpufreq_driver.flags |= CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING;
 598                 pr_err("%s: Too many CPUs, dynamic performance scaling disabled\n",
 599                        __func__);
 600                 pr_err("%s: Try to enable another scaling driver through BIOS settings\n",
 601                        __func__);
 602                 pr_err("%s: and complain to the system vendor\n", __func__);
 603         }
 604 
 605         ret = cpufreq_register_driver(&pcc_cpufreq_driver);
 606 
 607         return ret;
 608 }
 609 
 610 static void __exit pcc_cpufreq_exit(void)
 611 {
 612         cpufreq_unregister_driver(&pcc_cpufreq_driver);
 613 
 614         pcc_clear_mapping();
 615 
 616         free_percpu(pcc_cpu_info);
 617 }
 618 
 619 static const struct acpi_device_id processor_device_ids[] = {
 620         {ACPI_PROCESSOR_OBJECT_HID, },
 621         {ACPI_PROCESSOR_DEVICE_HID, },
 622         {},
 623 };
 624 MODULE_DEVICE_TABLE(acpi, processor_device_ids);
 625 
 626 MODULE_AUTHOR("Matthew Garrett, Naga Chumbalkar");
 627 MODULE_VERSION(PCC_VERSION);
 628 MODULE_DESCRIPTION("Processor Clocking Control interface driver");
 629 MODULE_LICENSE("GPL");
 630 
 631 late_initcall(pcc_cpufreq_init);
 632 module_exit(pcc_cpufreq_exit);

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