0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0013
0014 #include <linux/kernel.h>
0015 #include <linux/slab.h>
0016 #include <linux/module.h>
0017 #include <linux/init.h>
0018 #include <linux/cpufreq.h>
0019 #include <linux/proc_fs.h>
0020 #include <asm/io.h>
0021 #include <linux/uaccess.h>
0022 #include <asm/pal.h>
0023
0024 #include <linux/acpi.h>
0025 #include <acpi/processor.h>
0026
0027 MODULE_AUTHOR("Venkatesh Pallipadi");
0028 MODULE_DESCRIPTION("ACPI Processor P-States Driver");
0029 MODULE_LICENSE("GPL");
0030
0031 struct cpufreq_acpi_io {
0032 struct acpi_processor_performance acpi_data;
0033 unsigned int resume;
0034 };
0035
0036 struct cpufreq_acpi_req {
0037 unsigned int cpu;
0038 unsigned int state;
0039 };
0040
0041 static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS];
0042
0043 static struct cpufreq_driver acpi_cpufreq_driver;
0044
0045
0046 static int
0047 processor_set_pstate (
0048 u32 value)
0049 {
0050 s64 retval;
0051
0052 pr_debug("processor_set_pstate\n");
0053
0054 retval = ia64_pal_set_pstate((u64)value);
0055
0056 if (retval) {
0057 pr_debug("Failed to set freq to 0x%x, with error 0x%llx\n",
0058 value, retval);
0059 return -ENODEV;
0060 }
0061 return (int)retval;
0062 }
0063
0064
0065 static int
0066 processor_get_pstate (
0067 u32 *value)
0068 {
0069 u64 pstate_index = 0;
0070 s64 retval;
0071
0072 pr_debug("processor_get_pstate\n");
0073
0074 retval = ia64_pal_get_pstate(&pstate_index,
0075 PAL_GET_PSTATE_TYPE_INSTANT);
0076 *value = (u32) pstate_index;
0077
0078 if (retval)
0079 pr_debug("Failed to get current freq with "
0080 "error 0x%llx, idx 0x%x\n", retval, *value);
0081
0082 return (int)retval;
0083 }
0084
0085
0086
0087 static unsigned
0088 extract_clock (
0089 struct cpufreq_acpi_io *data,
0090 unsigned value)
0091 {
0092 unsigned long i;
0093
0094 pr_debug("extract_clock\n");
0095
0096 for (i = 0; i < data->acpi_data.state_count; i++) {
0097 if (value == data->acpi_data.states[i].status)
0098 return data->acpi_data.states[i].core_frequency;
0099 }
0100 return data->acpi_data.states[i-1].core_frequency;
0101 }
0102
0103
0104 static long
0105 processor_get_freq (
0106 void *arg)
0107 {
0108 struct cpufreq_acpi_req *req = arg;
0109 unsigned int cpu = req->cpu;
0110 struct cpufreq_acpi_io *data = acpi_io_data[cpu];
0111 u32 value;
0112 int ret;
0113
0114 pr_debug("processor_get_freq\n");
0115 if (smp_processor_id() != cpu)
0116 return -EAGAIN;
0117
0118
0119 ret = processor_get_pstate(&value);
0120 if (ret) {
0121 pr_warn("get performance failed with error %d\n", ret);
0122 return ret;
0123 }
0124 return 1000 * extract_clock(data, value);
0125 }
0126
0127
0128 static long
0129 processor_set_freq (
0130 void *arg)
0131 {
0132 struct cpufreq_acpi_req *req = arg;
0133 unsigned int cpu = req->cpu;
0134 struct cpufreq_acpi_io *data = acpi_io_data[cpu];
0135 int ret, state = req->state;
0136 u32 value;
0137
0138 pr_debug("processor_set_freq\n");
0139 if (smp_processor_id() != cpu)
0140 return -EAGAIN;
0141
0142 if (state == data->acpi_data.state) {
0143 if (unlikely(data->resume)) {
0144 pr_debug("Called after resume, resetting to P%d\n", state);
0145 data->resume = 0;
0146 } else {
0147 pr_debug("Already at target state (P%d)\n", state);
0148 return 0;
0149 }
0150 }
0151
0152 pr_debug("Transitioning from P%d to P%d\n",
0153 data->acpi_data.state, state);
0154
0155
0156
0157
0158
0159 value = (u32) data->acpi_data.states[state].control;
0160
0161 pr_debug("Transitioning to state: 0x%08x\n", value);
0162
0163 ret = processor_set_pstate(value);
0164 if (ret) {
0165 pr_warn("Transition failed with error %d\n", ret);
0166 return -ENODEV;
0167 }
0168
0169 data->acpi_data.state = state;
0170 return 0;
0171 }
0172
0173
0174 static unsigned int
0175 acpi_cpufreq_get (
0176 unsigned int cpu)
0177 {
0178 struct cpufreq_acpi_req req;
0179 long ret;
0180
0181 req.cpu = cpu;
0182 ret = work_on_cpu(cpu, processor_get_freq, &req);
0183
0184 return ret > 0 ? (unsigned int) ret : 0;
0185 }
0186
0187
0188 static int
0189 acpi_cpufreq_target (
0190 struct cpufreq_policy *policy,
0191 unsigned int index)
0192 {
0193 struct cpufreq_acpi_req req;
0194
0195 req.cpu = policy->cpu;
0196 req.state = index;
0197
0198 return work_on_cpu(req.cpu, processor_set_freq, &req);
0199 }
0200
0201 static int
0202 acpi_cpufreq_cpu_init (
0203 struct cpufreq_policy *policy)
0204 {
0205 unsigned int i;
0206 unsigned int cpu = policy->cpu;
0207 struct cpufreq_acpi_io *data;
0208 unsigned int result = 0;
0209 struct cpufreq_frequency_table *freq_table;
0210
0211 pr_debug("acpi_cpufreq_cpu_init\n");
0212
0213 data = kzalloc(sizeof(*data), GFP_KERNEL);
0214 if (!data)
0215 return (-ENOMEM);
0216
0217 acpi_io_data[cpu] = data;
0218
0219 result = acpi_processor_register_performance(&data->acpi_data, cpu);
0220
0221 if (result)
0222 goto err_free;
0223
0224
0225 if (data->acpi_data.state_count <= 1) {
0226 pr_debug("No P-States\n");
0227 result = -ENODEV;
0228 goto err_unreg;
0229 }
0230
0231 if ((data->acpi_data.control_register.space_id !=
0232 ACPI_ADR_SPACE_FIXED_HARDWARE) ||
0233 (data->acpi_data.status_register.space_id !=
0234 ACPI_ADR_SPACE_FIXED_HARDWARE)) {
0235 pr_debug("Unsupported address space [%d, %d]\n",
0236 (u32) (data->acpi_data.control_register.space_id),
0237 (u32) (data->acpi_data.status_register.space_id));
0238 result = -ENODEV;
0239 goto err_unreg;
0240 }
0241
0242
0243 freq_table = kcalloc(data->acpi_data.state_count + 1,
0244 sizeof(*freq_table),
0245 GFP_KERNEL);
0246 if (!freq_table) {
0247 result = -ENOMEM;
0248 goto err_unreg;
0249 }
0250
0251
0252 policy->cpuinfo.transition_latency = 0;
0253 for (i=0; i<data->acpi_data.state_count; i++) {
0254 if ((data->acpi_data.states[i].transition_latency * 1000) >
0255 policy->cpuinfo.transition_latency) {
0256 policy->cpuinfo.transition_latency =
0257 data->acpi_data.states[i].transition_latency * 1000;
0258 }
0259 }
0260
0261
0262 for (i = 0; i <= data->acpi_data.state_count; i++)
0263 {
0264 if (i < data->acpi_data.state_count) {
0265 freq_table[i].frequency =
0266 data->acpi_data.states[i].core_frequency * 1000;
0267 } else {
0268 freq_table[i].frequency = CPUFREQ_TABLE_END;
0269 }
0270 }
0271
0272 policy->freq_table = freq_table;
0273
0274
0275 acpi_processor_notify_smm(THIS_MODULE);
0276
0277 pr_info("CPU%u - ACPI performance management activated\n", cpu);
0278
0279 for (i = 0; i < data->acpi_data.state_count; i++)
0280 pr_debug(" %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n",
0281 (i == data->acpi_data.state?'*':' '), i,
0282 (u32) data->acpi_data.states[i].core_frequency,
0283 (u32) data->acpi_data.states[i].power,
0284 (u32) data->acpi_data.states[i].transition_latency,
0285 (u32) data->acpi_data.states[i].bus_master_latency,
0286 (u32) data->acpi_data.states[i].status,
0287 (u32) data->acpi_data.states[i].control);
0288
0289
0290
0291 data->resume = 1;
0292
0293 return (result);
0294
0295 err_unreg:
0296 acpi_processor_unregister_performance(cpu);
0297 err_free:
0298 kfree(data);
0299 acpi_io_data[cpu] = NULL;
0300
0301 return (result);
0302 }
0303
0304
0305 static int
0306 acpi_cpufreq_cpu_exit (
0307 struct cpufreq_policy *policy)
0308 {
0309 struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
0310
0311 pr_debug("acpi_cpufreq_cpu_exit\n");
0312
0313 if (data) {
0314 acpi_io_data[policy->cpu] = NULL;
0315 acpi_processor_unregister_performance(policy->cpu);
0316 kfree(policy->freq_table);
0317 kfree(data);
0318 }
0319
0320 return (0);
0321 }
0322
0323
0324 static struct cpufreq_driver acpi_cpufreq_driver = {
0325 .verify = cpufreq_generic_frequency_table_verify,
0326 .target_index = acpi_cpufreq_target,
0327 .get = acpi_cpufreq_get,
0328 .init = acpi_cpufreq_cpu_init,
0329 .exit = acpi_cpufreq_cpu_exit,
0330 .name = "acpi-cpufreq",
0331 .attr = cpufreq_generic_attr,
0332 };
0333
0334
0335 static int __init
0336 acpi_cpufreq_init (void)
0337 {
0338 pr_debug("acpi_cpufreq_init\n");
0339
0340 return cpufreq_register_driver(&acpi_cpufreq_driver);
0341 }
0342
0343
0344 static void __exit
0345 acpi_cpufreq_exit (void)
0346 {
0347 pr_debug("acpi_cpufreq_exit\n");
0348
0349 cpufreq_unregister_driver(&acpi_cpufreq_driver);
0350 }
0351
0352 late_initcall(acpi_cpufreq_init);
0353 module_exit(acpi_cpufreq_exit);