1 /* 2 * CPPC (Collaborative Processor Performance Control) driver for 3 * interfacing with the CPUfreq layer and governors. See 4 * cppc_acpi.c for CPPC specific methods. 5 * 6 * (C) Copyright 2014, 2015 Linaro Ltd. 7 * Author: Ashwin Chaugule <ashwin.chaugule@linaro.org> 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; version 2 12 * of the License. 13 */ 14 15 #define pr_fmt(fmt) "CPPC Cpufreq:" fmt 16 17 #include <linux/kernel.h> 18 #include <linux/module.h> 19 #include <linux/delay.h> 20 #include <linux/cpu.h> 21 #include <linux/cpufreq.h> 22 #include <linux/vmalloc.h> 23 24 #include <acpi/cppc_acpi.h> 25 26 /* 27 * These structs contain information parsed from per CPU 28 * ACPI _CPC structures. 29 * e.g. For each CPU the highest, lowest supported 30 * performance capabilities, desired performance level 31 * requested etc. 32 */ 33 static struct cpudata **all_cpu_data; 34 35 static int cppc_cpufreq_set_target(struct cpufreq_policy *policy, 36 unsigned int target_freq, 37 unsigned int relation) 38 { 39 struct cpudata *cpu; 40 struct cpufreq_freqs freqs; 41 int ret = 0; 42 43 cpu = all_cpu_data[policy->cpu]; 44 45 cpu->perf_ctrls.desired_perf = target_freq; 46 freqs.old = policy->cur; 47 freqs.new = target_freq; 48 49 cpufreq_freq_transition_begin(policy, &freqs); 50 ret = cppc_set_perf(cpu->cpu, &cpu->perf_ctrls); 51 cpufreq_freq_transition_end(policy, &freqs, ret != 0); 52 53 if (ret) 54 pr_debug("Failed to set target on CPU:%d. ret:%d\n", 55 cpu->cpu, ret); 56 57 return ret; 58 } 59 60 static int cppc_verify_policy(struct cpufreq_policy *policy) 61 { 62 cpufreq_verify_within_cpu_limits(policy); 63 return 0; 64 } 65 66 static void cppc_cpufreq_stop_cpu(struct cpufreq_policy *policy) 67 { 68 int cpu_num = policy->cpu; 69 struct cpudata *cpu = all_cpu_data[cpu_num]; 70 int ret; 71 72 cpu->perf_ctrls.desired_perf = cpu->perf_caps.lowest_perf; 73 74 ret = cppc_set_perf(cpu_num, &cpu->perf_ctrls); 75 if (ret) 76 pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n", 77 cpu->perf_caps.lowest_perf, cpu_num, ret); 78 } 79 80 static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) 81 { 82 struct cpudata *cpu; 83 unsigned int cpu_num = policy->cpu; 84 int ret = 0; 85 86 cpu = all_cpu_data[policy->cpu]; 87 88 cpu->cpu = cpu_num; 89 ret = cppc_get_perf_caps(policy->cpu, &cpu->perf_caps); 90 91 if (ret) { 92 pr_debug("Err reading CPU%d perf capabilities. ret:%d\n", 93 cpu_num, ret); 94 return ret; 95 } 96 97 policy->min = cpu->perf_caps.lowest_perf; 98 policy->max = cpu->perf_caps.highest_perf; 99 policy->cpuinfo.min_freq = policy->min; 100 policy->cpuinfo.max_freq = policy->max; 101 102 if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) 103 cpumask_copy(policy->cpus, cpu->shared_cpu_map); 104 else { 105 /* Support only SW_ANY for now. */ 106 pr_debug("Unsupported CPU co-ord type\n"); 107 return -EFAULT; 108 } 109 110 cpumask_set_cpu(policy->cpu, policy->cpus); 111 cpu->cur_policy = policy; 112 113 /* Set policy->cur to max now. The governors will adjust later. */ 114 policy->cur = cpu->perf_ctrls.desired_perf = cpu->perf_caps.highest_perf; 115 116 ret = cppc_set_perf(cpu_num, &cpu->perf_ctrls); 117 if (ret) 118 pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n", 119 cpu->perf_caps.highest_perf, cpu_num, ret); 120 121 return ret; 122 } 123 124 static struct cpufreq_driver cppc_cpufreq_driver = { 125 .flags = CPUFREQ_CONST_LOOPS, 126 .verify = cppc_verify_policy, 127 .target = cppc_cpufreq_set_target, 128 .init = cppc_cpufreq_cpu_init, 129 .stop_cpu = cppc_cpufreq_stop_cpu, 130 .name = "cppc_cpufreq", 131 }; 132 133 static int __init cppc_cpufreq_init(void) 134 { 135 int i, ret = 0; 136 struct cpudata *cpu; 137 138 if (acpi_disabled) 139 return -ENODEV; 140 141 all_cpu_data = kzalloc(sizeof(void *) * num_possible_cpus(), GFP_KERNEL); 142 if (!all_cpu_data) 143 return -ENOMEM; 144 145 for_each_possible_cpu(i) { 146 all_cpu_data[i] = kzalloc(sizeof(struct cpudata), GFP_KERNEL); 147 if (!all_cpu_data[i]) 148 goto out; 149 150 cpu = all_cpu_data[i]; 151 if (!zalloc_cpumask_var(&cpu->shared_cpu_map, GFP_KERNEL)) 152 goto out; 153 } 154 155 ret = acpi_get_psd_map(all_cpu_data); 156 if (ret) { 157 pr_debug("Error parsing PSD data. Aborting cpufreq registration.\n"); 158 goto out; 159 } 160 161 ret = cpufreq_register_driver(&cppc_cpufreq_driver); 162 if (ret) 163 goto out; 164 165 return ret; 166 167 out: 168 for_each_possible_cpu(i) 169 kfree(all_cpu_data[i]); 170 171 kfree(all_cpu_data); 172 return -ENODEV; 173 } 174 175 late_initcall(cppc_cpufreq_init); 176