Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * This file provides the ACPI based P-state support. This
0004  * module works with generic cpufreq infrastructure. Most of
0005  * the code is based on i386 version
0006  * (arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c)
0007  *
0008  * Copyright (C) 2005 Intel Corp
0009  *      Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
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 /* To be used only after data->acpi_data is initialized */
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     /* processor_get_pstate gets the instantaneous frequency */
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      * First we write the target state's 'control' value to the
0157      * control_register.
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     /* capability check */
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     /* alloc freq_table */
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     /* detect transition latency */
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     /* table init */
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     /* notify BIOS that we exist */
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     /* the first call to ->target() should result in us actually
0290      * writing something to the appropriate registers. */
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);