Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq:
[CPUFREQ] Fix cast warning in pcc driver.
[CPUFREQ] Processor Clocking Control interface driver

+844
+207
Documentation/cpu-freq/pcc-cpufreq.txt
···
··· 1 + /* 2 + * pcc-cpufreq.txt - PCC interface documentation 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 + 27 + Processor Clocking Control Driver 28 + --------------------------------- 29 + 30 + Contents: 31 + --------- 32 + 1. Introduction 33 + 1.1 PCC interface 34 + 1.1.1 Get Average Frequency 35 + 1.1.2 Set Desired Frequency 36 + 1.2 Platforms affected 37 + 2. Driver and /sys details 38 + 2.1 scaling_available_frequencies 39 + 2.2 cpuinfo_transition_latency 40 + 2.3 cpuinfo_cur_freq 41 + 2.4 related_cpus 42 + 3. Caveats 43 + 44 + 1. Introduction: 45 + ---------------- 46 + Processor Clocking Control (PCC) is an interface between the platform 47 + firmware and OSPM. It is a mechanism for coordinating processor 48 + performance (ie: frequency) between the platform firmware and the OS. 49 + 50 + The PCC driver (pcc-cpufreq) allows OSPM to take advantage of the PCC 51 + interface. 52 + 53 + OS utilizes the PCC interface to inform platform firmware what frequency the 54 + OS wants for a logical processor. The platform firmware attempts to achieve 55 + the requested frequency. If the request for the target frequency could not be 56 + satisfied by platform firmware, then it usually means that power budget 57 + conditions are in place, and "power capping" is taking place. 58 + 59 + 1.1 PCC interface: 60 + ------------------ 61 + The complete PCC specification is available here: 62 + http://www.acpica.org/download/Processor-Clocking-Control-v1p0.pdf 63 + 64 + PCC relies on a shared memory region that provides a channel for communication 65 + between the OS and platform firmware. PCC also implements a "doorbell" that 66 + is used by the OS to inform the platform firmware that a command has been 67 + sent. 68 + 69 + The ACPI PCCH() method is used to discover the location of the PCC shared 70 + memory region. The shared memory region header contains the "command" and 71 + "status" interface. PCCH() also contains details on how to access the platform 72 + doorbell. 73 + 74 + The following commands are supported by the PCC interface: 75 + * Get Average Frequency 76 + * Set Desired Frequency 77 + 78 + The ACPI PCCP() method is implemented for each logical processor and is 79 + used to discover the offsets for the input and output buffers in the shared 80 + memory region. 81 + 82 + When PCC mode is enabled, the platform will not expose processor performance 83 + or throttle states (_PSS, _TSS and related ACPI objects) to OSPM. Therefore, 84 + the native P-state driver (such as acpi-cpufreq for Intel, powernow-k8 for 85 + AMD) will not load. 86 + 87 + However, OSPM remains in control of policy. The governor (eg: "ondemand") 88 + computes the required performance for each processor based on server workload. 89 + The PCC driver fills in the command interface, and the input buffer and 90 + communicates the request to the platform firmware. The platform firmware is 91 + responsible for delivering the requested performance. 92 + 93 + Each PCC command is "global" in scope and can affect all the logical CPUs in 94 + the system. Therefore, PCC is capable of performing "group" updates. With PCC 95 + the OS is capable of getting/setting the frequency of all the logical CPUs in 96 + the system with a single call to the BIOS. 97 + 98 + 1.1.1 Get Average Frequency: 99 + ---------------------------- 100 + This command is used by the OSPM to query the running frequency of the 101 + processor since the last time this command was completed. The output buffer 102 + indicates the average unhalted frequency of the logical processor expressed as 103 + a percentage of the nominal (ie: maximum) CPU frequency. The output buffer 104 + also signifies if the CPU frequency is limited by a power budget condition. 105 + 106 + 1.1.2 Set Desired Frequency: 107 + ---------------------------- 108 + This command is used by the OSPM to communicate to the platform firmware the 109 + desired frequency for a logical processor. The output buffer is currently 110 + ignored by OSPM. The next invocation of "Get Average Frequency" will inform 111 + OSPM if the desired frequency was achieved or not. 112 + 113 + 1.2 Platforms affected: 114 + ----------------------- 115 + The PCC driver will load on any system where the platform firmware: 116 + * supports the PCC interface, and the associated PCCH() and PCCP() methods 117 + * assumes responsibility for managing the hardware clocking controls in order 118 + to deliver the requested processor performance 119 + 120 + Currently, certain HP ProLiant platforms implement the PCC interface. On those 121 + platforms PCC is the "default" choice. 122 + 123 + However, it is possible to disable this interface via a BIOS setting. In 124 + such an instance, as is also the case on platforms where the PCC interface 125 + is not implemented, the PCC driver will fail to load silently. 126 + 127 + 2. Driver and /sys details: 128 + --------------------------- 129 + When the driver loads, it merely prints the lowest and the highest CPU 130 + frequencies supported by the platform firmware. 131 + 132 + The PCC driver loads with a message such as: 133 + pcc-cpufreq: (v1.00.00) driver loaded with frequency limits: 1600 MHz, 2933 134 + MHz 135 + 136 + This means that the OPSM can request the CPU to run at any frequency in 137 + between the limits (1600 MHz, and 2933 MHz) specified in the message. 138 + 139 + Internally, there is no need for the driver to convert the "target" frequency 140 + to a corresponding P-state. 141 + 142 + The VERSION number for the driver will be of the format v.xy.ab. 143 + eg: 1.00.02 144 + ----- -- 145 + | | 146 + | -- this will increase with bug fixes/enhancements to the driver 147 + |-- this is the version of the PCC specification the driver adheres to 148 + 149 + 150 + The following is a brief discussion on some of the fields exported via the 151 + /sys filesystem and how their values are affected by the PCC driver: 152 + 153 + 2.1 scaling_available_frequencies: 154 + ---------------------------------- 155 + scaling_available_frequencies is not created in /sys. No intermediate 156 + frequencies need to be listed because the BIOS will try to achieve any 157 + frequency, within limits, requested by the governor. A frequency does not have 158 + to be strictly associated with a P-state. 159 + 160 + 2.2 cpuinfo_transition_latency: 161 + ------------------------------- 162 + The cpuinfo_transition_latency field is 0. The PCC specification does 163 + not include a field to expose this value currently. 164 + 165 + 2.3 cpuinfo_cur_freq: 166 + --------------------- 167 + A) Often cpuinfo_cur_freq will show a value different than what is declared 168 + in the scaling_available_frequencies or scaling_cur_freq, or scaling_max_freq. 169 + This is due to "turbo boost" available on recent Intel processors. If certain 170 + conditions are met the BIOS can achieve a slightly higher speed than requested 171 + by OSPM. An example: 172 + 173 + scaling_cur_freq : 2933000 174 + cpuinfo_cur_freq : 3196000 175 + 176 + B) There is a round-off error associated with the cpuinfo_cur_freq value. 177 + Since the driver obtains the current frequency as a "percentage" (%) of the 178 + nominal frequency from the BIOS, sometimes, the values displayed by 179 + scaling_cur_freq and cpuinfo_cur_freq may not match. An example: 180 + 181 + scaling_cur_freq : 1600000 182 + cpuinfo_cur_freq : 1583000 183 + 184 + In this example, the nominal frequency is 2933 MHz. The driver obtains the 185 + current frequency, cpuinfo_cur_freq, as 54% of the nominal frequency: 186 + 187 + 54% of 2933 MHz = 1583 MHz 188 + 189 + Nominal frequency is the maximum frequency of the processor, and it usually 190 + corresponds to the frequency of the P0 P-state. 191 + 192 + 2.4 related_cpus: 193 + ----------------- 194 + The related_cpus field is identical to affected_cpus. 195 + 196 + affected_cpus : 4 197 + related_cpus : 4 198 + 199 + Currently, the PCC driver does not evaluate _PSD. The platforms that support 200 + PCC do not implement SW_ALL. So OSPM doesn't need to perform any coordination 201 + to ensure that the same frequency is requested of all dependent CPUs. 202 + 203 + 3. Caveats: 204 + ----------- 205 + The "cpufreq_stats" module in its present form cannot be loaded and 206 + expected to work with the PCC driver. Since the "cpufreq_stats" module 207 + provides information wrt each P-state, it is not applicable to the PCC driver.
+14
arch/x86/kernel/cpu/cpufreq/Kconfig
··· 10 11 comment "CPUFreq processor drivers" 12 13 config X86_ACPI_CPUFREQ 14 tristate "ACPI Processor P-States driver" 15 select CPU_FREQ_TABLE
··· 10 11 comment "CPUFreq processor drivers" 12 13 + config X86_PCC_CPUFREQ 14 + tristate "Processor Clocking Control interface driver" 15 + depends on ACPI && ACPI_PROCESSOR 16 + help 17 + This driver adds support for the PCC interface. 18 + 19 + For details, take a look at: 20 + <file:Documentation/cpu-freq/pcc-cpufreq.txt>. 21 + 22 + To compile this driver as a module, choose M here: the 23 + module will be called pcc-cpufreq. 24 + 25 + If in doubt, say N. 26 + 27 config X86_ACPI_CPUFREQ 28 tristate "ACPI Processor P-States driver" 29 select CPU_FREQ_TABLE
+1
arch/x86/kernel/cpu/cpufreq/Makefile
··· 4 5 obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o 6 obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o 7 obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o 8 obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o 9 obj-$(CONFIG_X86_LONGHAUL) += longhaul.o
··· 4 5 obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o 6 obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o 7 + obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o 8 obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o 9 obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o 10 obj-$(CONFIG_X86_LONGHAUL) += longhaul.o
+620
arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c
···
··· 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 + 34 + #include <linux/acpi.h> 35 + #include <linux/io.h> 36 + #include <linux/spinlock.h> 37 + #include <linux/uaccess.h> 38 + 39 + #include <acpi/processor.h> 40 + 41 + #define PCC_VERSION "1.00.00" 42 + #define POLL_LOOPS 300 43 + 44 + #define CMD_COMPLETE 0x1 45 + #define CMD_GET_FREQ 0x0 46 + #define CMD_SET_FREQ 0x1 47 + 48 + #define BUF_SZ 4 49 + 50 + #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ 51 + "pcc-cpufreq", msg) 52 + 53 + struct pcc_register_resource { 54 + u8 descriptor; 55 + u16 length; 56 + u8 space_id; 57 + u8 bit_width; 58 + u8 bit_offset; 59 + u8 access_size; 60 + u64 address; 61 + } __attribute__ ((packed)); 62 + 63 + struct pcc_memory_resource { 64 + u8 descriptor; 65 + u16 length; 66 + u8 space_id; 67 + u8 resource_usage; 68 + u8 type_specific; 69 + u64 granularity; 70 + u64 minimum; 71 + u64 maximum; 72 + u64 translation_offset; 73 + u64 address_length; 74 + } __attribute__ ((packed)); 75 + 76 + static struct cpufreq_driver pcc_cpufreq_driver; 77 + 78 + struct pcc_header { 79 + u32 signature; 80 + u16 length; 81 + u8 major; 82 + u8 minor; 83 + u32 features; 84 + u16 command; 85 + u16 status; 86 + u32 latency; 87 + u32 minimum_time; 88 + u32 maximum_time; 89 + u32 nominal; 90 + u32 throttled_frequency; 91 + u32 minimum_frequency; 92 + }; 93 + 94 + static void __iomem *pcch_virt_addr; 95 + static struct pcc_header __iomem *pcch_hdr; 96 + 97 + static DEFINE_SPINLOCK(pcc_lock); 98 + 99 + static struct acpi_generic_address doorbell; 100 + 101 + static u64 doorbell_preserve; 102 + static u64 doorbell_write; 103 + 104 + static u8 OSC_UUID[16] = {0x63, 0x9B, 0x2C, 0x9F, 0x70, 0x91, 0x49, 0x1f, 105 + 0xBB, 0x4F, 0xA5, 0x98, 0x2F, 0xA1, 0xB5, 0x46}; 106 + 107 + struct pcc_cpu { 108 + u32 input_offset; 109 + u32 output_offset; 110 + }; 111 + 112 + static struct pcc_cpu *pcc_cpu_info; 113 + 114 + static int pcc_cpufreq_verify(struct cpufreq_policy *policy) 115 + { 116 + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, 117 + policy->cpuinfo.max_freq); 118 + return 0; 119 + } 120 + 121 + static inline void pcc_cmd(void) 122 + { 123 + u64 doorbell_value; 124 + int i; 125 + 126 + acpi_read(&doorbell_value, &doorbell); 127 + acpi_write((doorbell_value & doorbell_preserve) | doorbell_write, 128 + &doorbell); 129 + 130 + for (i = 0; i < POLL_LOOPS; i++) { 131 + if (ioread16(&pcch_hdr->status) & CMD_COMPLETE) 132 + break; 133 + } 134 + } 135 + 136 + static inline void pcc_clear_mapping(void) 137 + { 138 + if (pcch_virt_addr) 139 + iounmap(pcch_virt_addr); 140 + pcch_virt_addr = NULL; 141 + } 142 + 143 + static unsigned int pcc_get_freq(unsigned int cpu) 144 + { 145 + struct pcc_cpu *pcc_cpu_data; 146 + unsigned int curr_freq; 147 + unsigned int freq_limit; 148 + u16 status; 149 + u32 input_buffer; 150 + u32 output_buffer; 151 + 152 + spin_lock(&pcc_lock); 153 + 154 + dprintk("get: get_freq for CPU %d\n", cpu); 155 + pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); 156 + 157 + input_buffer = 0x1; 158 + iowrite32(input_buffer, 159 + (pcch_virt_addr + pcc_cpu_data->input_offset)); 160 + iowrite16(CMD_GET_FREQ, &pcch_hdr->command); 161 + 162 + pcc_cmd(); 163 + 164 + output_buffer = 165 + ioread32(pcch_virt_addr + pcc_cpu_data->output_offset); 166 + 167 + /* Clear the input buffer - we are done with the current command */ 168 + memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); 169 + 170 + status = ioread16(&pcch_hdr->status); 171 + if (status != CMD_COMPLETE) { 172 + dprintk("get: FAILED: for CPU %d, status is %d\n", 173 + cpu, status); 174 + goto cmd_incomplete; 175 + } 176 + iowrite16(0, &pcch_hdr->status); 177 + curr_freq = (((ioread32(&pcch_hdr->nominal) * (output_buffer & 0xff)) 178 + / 100) * 1000); 179 + 180 + dprintk("get: SUCCESS: (virtual) output_offset for cpu %d is " 181 + "0x%x, contains a value of: 0x%x. Speed is: %d MHz\n", 182 + cpu, (pcch_virt_addr + pcc_cpu_data->output_offset), 183 + output_buffer, curr_freq); 184 + 185 + freq_limit = (output_buffer >> 8) & 0xff; 186 + if (freq_limit != 0xff) { 187 + dprintk("get: frequency for cpu %d is being temporarily" 188 + " capped at %d\n", cpu, curr_freq); 189 + } 190 + 191 + spin_unlock(&pcc_lock); 192 + return curr_freq; 193 + 194 + cmd_incomplete: 195 + iowrite16(0, &pcch_hdr->status); 196 + spin_unlock(&pcc_lock); 197 + return -EINVAL; 198 + } 199 + 200 + static int pcc_cpufreq_target(struct cpufreq_policy *policy, 201 + unsigned int target_freq, 202 + unsigned int relation) 203 + { 204 + struct pcc_cpu *pcc_cpu_data; 205 + struct cpufreq_freqs freqs; 206 + u16 status; 207 + u32 input_buffer; 208 + int cpu; 209 + 210 + spin_lock(&pcc_lock); 211 + cpu = policy->cpu; 212 + pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); 213 + 214 + dprintk("target: CPU %d should go to target freq: %d " 215 + "(virtual) input_offset is 0x%x\n", 216 + cpu, target_freq, 217 + (pcch_virt_addr + pcc_cpu_data->input_offset)); 218 + 219 + freqs.new = target_freq; 220 + freqs.cpu = cpu; 221 + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 222 + 223 + input_buffer = 0x1 | (((target_freq * 100) 224 + / (ioread32(&pcch_hdr->nominal) * 1000)) << 8); 225 + iowrite32(input_buffer, 226 + (pcch_virt_addr + pcc_cpu_data->input_offset)); 227 + iowrite16(CMD_SET_FREQ, &pcch_hdr->command); 228 + 229 + pcc_cmd(); 230 + 231 + /* Clear the input buffer - we are done with the current command */ 232 + memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); 233 + 234 + status = ioread16(&pcch_hdr->status); 235 + if (status != CMD_COMPLETE) { 236 + dprintk("target: FAILED for cpu %d, with status: 0x%x\n", 237 + cpu, status); 238 + goto cmd_incomplete; 239 + } 240 + iowrite16(0, &pcch_hdr->status); 241 + 242 + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 243 + dprintk("target: was SUCCESSFUL for cpu %d\n", cpu); 244 + spin_unlock(&pcc_lock); 245 + 246 + return 0; 247 + 248 + cmd_incomplete: 249 + iowrite16(0, &pcch_hdr->status); 250 + spin_unlock(&pcc_lock); 251 + return -EINVAL; 252 + } 253 + 254 + static int pcc_get_offset(int cpu) 255 + { 256 + acpi_status status; 257 + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 258 + union acpi_object *pccp, *offset; 259 + struct pcc_cpu *pcc_cpu_data; 260 + struct acpi_processor *pr; 261 + int ret = 0; 262 + 263 + pr = per_cpu(processors, cpu); 264 + pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); 265 + 266 + status = acpi_evaluate_object(pr->handle, "PCCP", NULL, &buffer); 267 + if (ACPI_FAILURE(status)) 268 + return -ENODEV; 269 + 270 + pccp = buffer.pointer; 271 + if (!pccp || pccp->type != ACPI_TYPE_PACKAGE) { 272 + ret = -ENODEV; 273 + goto out_free; 274 + }; 275 + 276 + offset = &(pccp->package.elements[0]); 277 + if (!offset || offset->type != ACPI_TYPE_INTEGER) { 278 + ret = -ENODEV; 279 + goto out_free; 280 + } 281 + 282 + pcc_cpu_data->input_offset = offset->integer.value; 283 + 284 + offset = &(pccp->package.elements[1]); 285 + if (!offset || offset->type != ACPI_TYPE_INTEGER) { 286 + ret = -ENODEV; 287 + goto out_free; 288 + } 289 + 290 + pcc_cpu_data->output_offset = offset->integer.value; 291 + 292 + memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); 293 + memset_io((pcch_virt_addr + pcc_cpu_data->output_offset), 0, BUF_SZ); 294 + 295 + dprintk("pcc_get_offset: for CPU %d: pcc_cpu_data " 296 + "input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n", 297 + cpu, pcc_cpu_data->input_offset, pcc_cpu_data->output_offset); 298 + out_free: 299 + kfree(buffer.pointer); 300 + return ret; 301 + } 302 + 303 + static int __init pcc_cpufreq_do_osc(acpi_handle *handle) 304 + { 305 + acpi_status status; 306 + struct acpi_object_list input; 307 + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; 308 + union acpi_object in_params[4]; 309 + union acpi_object *out_obj; 310 + u32 capabilities[2]; 311 + u32 errors; 312 + u32 supported; 313 + int ret = 0; 314 + 315 + input.count = 4; 316 + input.pointer = in_params; 317 + input.count = 4; 318 + input.pointer = in_params; 319 + in_params[0].type = ACPI_TYPE_BUFFER; 320 + in_params[0].buffer.length = 16; 321 + in_params[0].buffer.pointer = OSC_UUID; 322 + in_params[1].type = ACPI_TYPE_INTEGER; 323 + in_params[1].integer.value = 1; 324 + in_params[2].type = ACPI_TYPE_INTEGER; 325 + in_params[2].integer.value = 2; 326 + in_params[3].type = ACPI_TYPE_BUFFER; 327 + in_params[3].buffer.length = 8; 328 + in_params[3].buffer.pointer = (u8 *)&capabilities; 329 + 330 + capabilities[0] = OSC_QUERY_ENABLE; 331 + capabilities[1] = 0x1; 332 + 333 + status = acpi_evaluate_object(*handle, "_OSC", &input, &output); 334 + if (ACPI_FAILURE(status)) 335 + return -ENODEV; 336 + 337 + if (!output.length) 338 + return -ENODEV; 339 + 340 + out_obj = output.pointer; 341 + if (out_obj->type != ACPI_TYPE_BUFFER) { 342 + ret = -ENODEV; 343 + goto out_free; 344 + } 345 + 346 + errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); 347 + if (errors) { 348 + ret = -ENODEV; 349 + goto out_free; 350 + } 351 + 352 + supported = *((u32 *)(out_obj->buffer.pointer + 4)); 353 + if (!(supported & 0x1)) { 354 + ret = -ENODEV; 355 + goto out_free; 356 + } 357 + 358 + kfree(output.pointer); 359 + capabilities[0] = 0x0; 360 + capabilities[1] = 0x1; 361 + 362 + status = acpi_evaluate_object(*handle, "_OSC", &input, &output); 363 + if (ACPI_FAILURE(status)) 364 + return -ENODEV; 365 + 366 + if (!output.length) 367 + return -ENODEV; 368 + 369 + out_obj = output.pointer; 370 + if (out_obj->type != ACPI_TYPE_BUFFER) { 371 + ret = -ENODEV; 372 + goto out_free; 373 + } 374 + 375 + errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); 376 + if (errors) { 377 + ret = -ENODEV; 378 + goto out_free; 379 + } 380 + 381 + supported = *((u32 *)(out_obj->buffer.pointer + 4)); 382 + if (!(supported & 0x1)) { 383 + ret = -ENODEV; 384 + goto out_free; 385 + } 386 + 387 + out_free: 388 + kfree(output.pointer); 389 + return ret; 390 + } 391 + 392 + static int __init pcc_cpufreq_probe(void) 393 + { 394 + acpi_status status; 395 + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; 396 + struct pcc_memory_resource *mem_resource; 397 + struct pcc_register_resource *reg_resource; 398 + union acpi_object *out_obj, *member; 399 + acpi_handle handle, osc_handle; 400 + int ret = 0; 401 + 402 + status = acpi_get_handle(NULL, "\\_SB", &handle); 403 + if (ACPI_FAILURE(status)) 404 + return -ENODEV; 405 + 406 + status = acpi_get_handle(handle, "_OSC", &osc_handle); 407 + if (ACPI_SUCCESS(status)) { 408 + ret = pcc_cpufreq_do_osc(&osc_handle); 409 + if (ret) 410 + dprintk("probe: _OSC evaluation did not succeed\n"); 411 + /* Firmware's use of _OSC is optional */ 412 + ret = 0; 413 + } 414 + 415 + status = acpi_evaluate_object(handle, "PCCH", NULL, &output); 416 + if (ACPI_FAILURE(status)) 417 + return -ENODEV; 418 + 419 + out_obj = output.pointer; 420 + if (out_obj->type != ACPI_TYPE_PACKAGE) { 421 + ret = -ENODEV; 422 + goto out_free; 423 + } 424 + 425 + member = &out_obj->package.elements[0]; 426 + if (member->type != ACPI_TYPE_BUFFER) { 427 + ret = -ENODEV; 428 + goto out_free; 429 + } 430 + 431 + mem_resource = (struct pcc_memory_resource *)member->buffer.pointer; 432 + 433 + dprintk("probe: mem_resource descriptor: 0x%x," 434 + " length: %d, space_id: %d, resource_usage: %d," 435 + " type_specific: %d, granularity: 0x%llx," 436 + " minimum: 0x%llx, maximum: 0x%llx," 437 + " translation_offset: 0x%llx, address_length: 0x%llx\n", 438 + mem_resource->descriptor, mem_resource->length, 439 + mem_resource->space_id, mem_resource->resource_usage, 440 + mem_resource->type_specific, mem_resource->granularity, 441 + mem_resource->minimum, mem_resource->maximum, 442 + mem_resource->translation_offset, 443 + mem_resource->address_length); 444 + 445 + if (mem_resource->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) { 446 + ret = -ENODEV; 447 + goto out_free; 448 + } 449 + 450 + pcch_virt_addr = ioremap_nocache(mem_resource->minimum, 451 + mem_resource->address_length); 452 + if (pcch_virt_addr == NULL) { 453 + dprintk("probe: could not map shared mem region\n"); 454 + goto out_free; 455 + } 456 + pcch_hdr = pcch_virt_addr; 457 + 458 + dprintk("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr); 459 + dprintk("probe: PCCH header is at physical address: 0x%llx," 460 + " signature: 0x%x, length: %d bytes, major: %d, minor: %d," 461 + " supported features: 0x%x, command field: 0x%x," 462 + " status field: 0x%x, nominal latency: %d us\n", 463 + mem_resource->minimum, ioread32(&pcch_hdr->signature), 464 + ioread16(&pcch_hdr->length), ioread8(&pcch_hdr->major), 465 + ioread8(&pcch_hdr->minor), ioread32(&pcch_hdr->features), 466 + ioread16(&pcch_hdr->command), ioread16(&pcch_hdr->status), 467 + ioread32(&pcch_hdr->latency)); 468 + 469 + dprintk("probe: min time between commands: %d us," 470 + " max time between commands: %d us," 471 + " nominal CPU frequency: %d MHz," 472 + " minimum CPU frequency: %d MHz," 473 + " minimum CPU frequency without throttling: %d MHz\n", 474 + ioread32(&pcch_hdr->minimum_time), 475 + ioread32(&pcch_hdr->maximum_time), 476 + ioread32(&pcch_hdr->nominal), 477 + ioread32(&pcch_hdr->throttled_frequency), 478 + ioread32(&pcch_hdr->minimum_frequency)); 479 + 480 + member = &out_obj->package.elements[1]; 481 + if (member->type != ACPI_TYPE_BUFFER) { 482 + ret = -ENODEV; 483 + goto pcch_free; 484 + } 485 + 486 + reg_resource = (struct pcc_register_resource *)member->buffer.pointer; 487 + 488 + doorbell.space_id = reg_resource->space_id; 489 + doorbell.bit_width = reg_resource->bit_width; 490 + doorbell.bit_offset = reg_resource->bit_offset; 491 + doorbell.access_width = 64; 492 + doorbell.address = reg_resource->address; 493 + 494 + dprintk("probe: doorbell: space_id is %d, bit_width is %d, " 495 + "bit_offset is %d, access_width is %d, address is 0x%llx\n", 496 + doorbell.space_id, doorbell.bit_width, doorbell.bit_offset, 497 + doorbell.access_width, reg_resource->address); 498 + 499 + member = &out_obj->package.elements[2]; 500 + if (member->type != ACPI_TYPE_INTEGER) { 501 + ret = -ENODEV; 502 + goto pcch_free; 503 + } 504 + 505 + doorbell_preserve = member->integer.value; 506 + 507 + member = &out_obj->package.elements[3]; 508 + if (member->type != ACPI_TYPE_INTEGER) { 509 + ret = -ENODEV; 510 + goto pcch_free; 511 + } 512 + 513 + doorbell_write = member->integer.value; 514 + 515 + dprintk("probe: doorbell_preserve: 0x%llx," 516 + " doorbell_write: 0x%llx\n", 517 + doorbell_preserve, doorbell_write); 518 + 519 + pcc_cpu_info = alloc_percpu(struct pcc_cpu); 520 + if (!pcc_cpu_info) { 521 + ret = -ENOMEM; 522 + goto pcch_free; 523 + } 524 + 525 + printk(KERN_DEBUG "pcc-cpufreq: (v%s) driver loaded with frequency" 526 + " limits: %d MHz, %d MHz\n", PCC_VERSION, 527 + ioread32(&pcch_hdr->minimum_frequency), 528 + ioread32(&pcch_hdr->nominal)); 529 + kfree(output.pointer); 530 + return ret; 531 + pcch_free: 532 + pcc_clear_mapping(); 533 + out_free: 534 + kfree(output.pointer); 535 + return ret; 536 + } 537 + 538 + static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) 539 + { 540 + unsigned int cpu = policy->cpu; 541 + unsigned int result = 0; 542 + 543 + if (!pcch_virt_addr) { 544 + result = -1; 545 + goto pcch_null; 546 + } 547 + 548 + result = pcc_get_offset(cpu); 549 + if (result) { 550 + dprintk("init: PCCP evaluation failed\n"); 551 + goto free; 552 + } 553 + 554 + policy->max = policy->cpuinfo.max_freq = 555 + ioread32(&pcch_hdr->nominal) * 1000; 556 + policy->min = policy->cpuinfo.min_freq = 557 + ioread32(&pcch_hdr->minimum_frequency) * 1000; 558 + policy->cur = pcc_get_freq(cpu); 559 + 560 + dprintk("init: policy->max is %d, policy->min is %d\n", 561 + policy->max, policy->min); 562 + 563 + return 0; 564 + free: 565 + pcc_clear_mapping(); 566 + free_percpu(pcc_cpu_info); 567 + pcch_null: 568 + return result; 569 + } 570 + 571 + static int pcc_cpufreq_cpu_exit(struct cpufreq_policy *policy) 572 + { 573 + return 0; 574 + } 575 + 576 + static struct cpufreq_driver pcc_cpufreq_driver = { 577 + .flags = CPUFREQ_CONST_LOOPS, 578 + .get = pcc_get_freq, 579 + .verify = pcc_cpufreq_verify, 580 + .target = pcc_cpufreq_target, 581 + .init = pcc_cpufreq_cpu_init, 582 + .exit = pcc_cpufreq_cpu_exit, 583 + .name = "pcc-cpufreq", 584 + .owner = THIS_MODULE, 585 + }; 586 + 587 + static int __init pcc_cpufreq_init(void) 588 + { 589 + int ret; 590 + 591 + if (acpi_disabled) 592 + return 0; 593 + 594 + ret = pcc_cpufreq_probe(); 595 + if (ret) { 596 + dprintk("pcc_cpufreq_init: PCCH evaluation failed\n"); 597 + return ret; 598 + } 599 + 600 + ret = cpufreq_register_driver(&pcc_cpufreq_driver); 601 + 602 + return ret; 603 + } 604 + 605 + static void __exit pcc_cpufreq_exit(void) 606 + { 607 + cpufreq_unregister_driver(&pcc_cpufreq_driver); 608 + 609 + pcc_clear_mapping(); 610 + 611 + free_percpu(pcc_cpu_info); 612 + } 613 + 614 + MODULE_AUTHOR("Matthew Garrett, Naga Chumbalkar"); 615 + MODULE_VERSION(PCC_VERSION); 616 + MODULE_DESCRIPTION("Processor Clocking Control interface driver"); 617 + MODULE_LICENSE("GPL"); 618 + 619 + late_initcall(pcc_cpufreq_init); 620 + module_exit(pcc_cpufreq_exit);
+2
drivers/acpi/processor_core.c
··· 123 #endif 124 125 DEFINE_PER_CPU(struct acpi_processor *, processors); 126 struct acpi_processor_errata errata __read_mostly; 127 128 /* --------------------------------------------------------------------------
··· 123 #endif 124 125 DEFINE_PER_CPU(struct acpi_processor *, processors); 126 + EXPORT_PER_CPU_SYMBOL(processors); 127 + 128 struct acpi_processor_errata errata __read_mostly; 129 130 /* --------------------------------------------------------------------------