| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 1 | /* | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 2 |  * This file provides the ACPI based P-state support. This | 
 | 3 |  * module works with generic cpufreq infrastructure. Most of | 
 | 4 |  * the code is based on i386 version | 
 | 5 |  * (arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c) | 
 | 6 |  * | 
 | 7 |  * Copyright (C) 2005 Intel Corp | 
 | 8 |  *      Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> | 
 | 9 |  */ | 
 | 10 |  | 
| Joe Perches | 1c5864e | 2016-04-05 13:28:25 -0700 | [diff] [blame] | 11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 
 | 12 |  | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 13 | #include <linux/kernel.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 14 | #include <linux/slab.h> | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 15 | #include <linux/module.h> | 
 | 16 | #include <linux/init.h> | 
 | 17 | #include <linux/cpufreq.h> | 
 | 18 | #include <linux/proc_fs.h> | 
 | 19 | #include <linux/seq_file.h> | 
 | 20 | #include <asm/io.h> | 
| Linus Torvalds | 7c0f6ba | 2016-12-24 11:46:01 -0800 | [diff] [blame] | 21 | #include <linux/uaccess.h> | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 22 | #include <asm/pal.h> | 
 | 23 |  | 
 | 24 | #include <linux/acpi.h> | 
 | 25 | #include <acpi/processor.h> | 
 | 26 |  | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 27 | MODULE_AUTHOR("Venkatesh Pallipadi"); | 
 | 28 | MODULE_DESCRIPTION("ACPI Processor P-States Driver"); | 
 | 29 | MODULE_LICENSE("GPL"); | 
 | 30 |  | 
 | 31 |  | 
 | 32 | struct cpufreq_acpi_io { | 
 | 33 | 	struct acpi_processor_performance	acpi_data; | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 34 | 	unsigned int				resume; | 
 | 35 | }; | 
 | 36 |  | 
 | 37 | static struct cpufreq_acpi_io	*acpi_io_data[NR_CPUS]; | 
 | 38 |  | 
 | 39 | static struct cpufreq_driver acpi_cpufreq_driver; | 
 | 40 |  | 
 | 41 |  | 
 | 42 | static int | 
 | 43 | processor_set_pstate ( | 
 | 44 | 	u32	value) | 
 | 45 | { | 
 | 46 | 	s64 retval; | 
 | 47 |  | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 48 | 	pr_debug("processor_set_pstate\n"); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 49 |  | 
 | 50 | 	retval = ia64_pal_set_pstate((u64)value); | 
 | 51 |  | 
 | 52 | 	if (retval) { | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 53 | 		pr_debug("Failed to set freq to 0x%x, with error 0x%lx\n", | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 54 | 		        value, retval); | 
 | 55 | 		return -ENODEV; | 
 | 56 | 	} | 
 | 57 | 	return (int)retval; | 
 | 58 | } | 
 | 59 |  | 
 | 60 |  | 
 | 61 | static int | 
 | 62 | processor_get_pstate ( | 
 | 63 | 	u32	*value) | 
 | 64 | { | 
 | 65 | 	u64	pstate_index = 0; | 
 | 66 | 	s64 	retval; | 
 | 67 |  | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 68 | 	pr_debug("processor_get_pstate\n"); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 69 |  | 
| Venkatesh Pallipadi | 17e77b1 | 2006-12-01 15:28:14 -0800 | [diff] [blame] | 70 | 	retval = ia64_pal_get_pstate(&pstate_index, | 
 | 71 | 	                             PAL_GET_PSTATE_TYPE_INSTANT); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 72 | 	*value = (u32) pstate_index; | 
 | 73 |  | 
 | 74 | 	if (retval) | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 75 | 		pr_debug("Failed to get current freq with " | 
| Denis V. Lunev | 60192db | 2008-07-17 11:11:17 -0700 | [diff] [blame] | 76 | 			"error 0x%lx, idx 0x%x\n", retval, *value); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 77 |  | 
 | 78 | 	return (int)retval; | 
 | 79 | } | 
 | 80 |  | 
 | 81 |  | 
 | 82 | /* To be used only after data->acpi_data is initialized */ | 
 | 83 | static unsigned | 
 | 84 | extract_clock ( | 
 | 85 | 	struct cpufreq_acpi_io *data, | 
 | 86 | 	unsigned value, | 
 | 87 | 	unsigned int cpu) | 
 | 88 | { | 
 | 89 | 	unsigned long i; | 
 | 90 |  | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 91 | 	pr_debug("extract_clock\n"); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 92 |  | 
 | 93 | 	for (i = 0; i < data->acpi_data.state_count; i++) { | 
| Venkatesh Pallipadi | 17e77b1 | 2006-12-01 15:28:14 -0800 | [diff] [blame] | 94 | 		if (value == data->acpi_data.states[i].status) | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 95 | 			return data->acpi_data.states[i].core_frequency; | 
 | 96 | 	} | 
 | 97 | 	return data->acpi_data.states[i-1].core_frequency; | 
 | 98 | } | 
 | 99 |  | 
 | 100 |  | 
 | 101 | static unsigned int | 
 | 102 | processor_get_freq ( | 
 | 103 | 	struct cpufreq_acpi_io	*data, | 
 | 104 | 	unsigned int		cpu) | 
 | 105 | { | 
 | 106 | 	int			ret = 0; | 
 | 107 | 	u32			value = 0; | 
 | 108 | 	cpumask_t		saved_mask; | 
 | 109 | 	unsigned long 		clock_freq; | 
 | 110 |  | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 111 | 	pr_debug("processor_get_freq\n"); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 112 |  | 
 | 113 | 	saved_mask = current->cpus_allowed; | 
| Julia Lawall | 552dce3 | 2010-03-26 23:02:23 +0100 | [diff] [blame] | 114 | 	set_cpus_allowed_ptr(current, cpumask_of(cpu)); | 
| Alex Williamson | 182fdd2 | 2007-08-13 15:49:46 -0600 | [diff] [blame] | 115 | 	if (smp_processor_id() != cpu) | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 116 | 		goto migrate_end; | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 117 |  | 
| Venkatesh Pallipadi | 17e77b1 | 2006-12-01 15:28:14 -0800 | [diff] [blame] | 118 | 	/* processor_get_pstate gets the instantaneous frequency */ | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 119 | 	ret = processor_get_pstate(&value); | 
 | 120 |  | 
 | 121 | 	if (ret) { | 
| Julia Lawall | 552dce3 | 2010-03-26 23:02:23 +0100 | [diff] [blame] | 122 | 		set_cpus_allowed_ptr(current, &saved_mask); | 
| Joe Perches | b49c22a | 2016-04-05 13:28:24 -0700 | [diff] [blame] | 123 | 		pr_warn("get performance failed with error %d\n", ret); | 
| Alex Williamson | 182fdd2 | 2007-08-13 15:49:46 -0600 | [diff] [blame] | 124 | 		ret = 0; | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 125 | 		goto migrate_end; | 
 | 126 | 	} | 
 | 127 | 	clock_freq = extract_clock(data, value, cpu); | 
 | 128 | 	ret = (clock_freq*1000); | 
 | 129 |  | 
 | 130 | migrate_end: | 
| Julia Lawall | 552dce3 | 2010-03-26 23:02:23 +0100 | [diff] [blame] | 131 | 	set_cpus_allowed_ptr(current, &saved_mask); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 132 | 	return ret; | 
 | 133 | } | 
 | 134 |  | 
 | 135 |  | 
 | 136 | static int | 
 | 137 | processor_set_freq ( | 
 | 138 | 	struct cpufreq_acpi_io	*data, | 
| Viresh Kumar | b43a7ff | 2013-03-24 11:56:43 +0530 | [diff] [blame] | 139 | 	struct cpufreq_policy   *policy, | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 140 | 	int			state) | 
 | 141 | { | 
 | 142 | 	int			ret = 0; | 
 | 143 | 	u32			value = 0; | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 144 | 	cpumask_t		saved_mask; | 
 | 145 | 	int			retval; | 
 | 146 |  | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 147 | 	pr_debug("processor_set_freq\n"); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 148 |  | 
 | 149 | 	saved_mask = current->cpus_allowed; | 
| Viresh Kumar | b43a7ff | 2013-03-24 11:56:43 +0530 | [diff] [blame] | 150 | 	set_cpus_allowed_ptr(current, cpumask_of(policy->cpu)); | 
 | 151 | 	if (smp_processor_id() != policy->cpu) { | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 152 | 		retval = -EAGAIN; | 
 | 153 | 		goto migrate_end; | 
 | 154 | 	} | 
 | 155 |  | 
 | 156 | 	if (state == data->acpi_data.state) { | 
 | 157 | 		if (unlikely(data->resume)) { | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 158 | 			pr_debug("Called after resume, resetting to P%d\n", state); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 159 | 			data->resume = 0; | 
 | 160 | 		} else { | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 161 | 			pr_debug("Already at target state (P%d)\n", state); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 162 | 			retval = 0; | 
 | 163 | 			goto migrate_end; | 
 | 164 | 		} | 
 | 165 | 	} | 
 | 166 |  | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 167 | 	pr_debug("Transitioning from P%d to P%d\n", | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 168 | 		data->acpi_data.state, state); | 
 | 169 |  | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 170 | 	/* | 
 | 171 | 	 * First we write the target state's 'control' value to the | 
 | 172 | 	 * control_register. | 
 | 173 | 	 */ | 
 | 174 |  | 
 | 175 | 	value = (u32) data->acpi_data.states[state].control; | 
 | 176 |  | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 177 | 	pr_debug("Transitioning to state: 0x%08x\n", value); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 178 |  | 
 | 179 | 	ret = processor_set_pstate(value); | 
 | 180 | 	if (ret) { | 
| Joe Perches | b49c22a | 2016-04-05 13:28:24 -0700 | [diff] [blame] | 181 | 		pr_warn("Transition failed with error %d\n", ret); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 182 | 		retval = -ENODEV; | 
 | 183 | 		goto migrate_end; | 
 | 184 | 	} | 
 | 185 |  | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 186 | 	data->acpi_data.state = state; | 
 | 187 |  | 
 | 188 | 	retval = 0; | 
 | 189 |  | 
 | 190 | migrate_end: | 
| Julia Lawall | 552dce3 | 2010-03-26 23:02:23 +0100 | [diff] [blame] | 191 | 	set_cpus_allowed_ptr(current, &saved_mask); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 192 | 	return (retval); | 
 | 193 | } | 
 | 194 |  | 
 | 195 |  | 
 | 196 | static unsigned int | 
 | 197 | acpi_cpufreq_get ( | 
 | 198 | 	unsigned int		cpu) | 
 | 199 | { | 
 | 200 | 	struct cpufreq_acpi_io *data = acpi_io_data[cpu]; | 
 | 201 |  | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 202 | 	pr_debug("acpi_cpufreq_get\n"); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 203 |  | 
 | 204 | 	return processor_get_freq(data, cpu); | 
 | 205 | } | 
 | 206 |  | 
 | 207 |  | 
 | 208 | static int | 
 | 209 | acpi_cpufreq_target ( | 
 | 210 | 	struct cpufreq_policy   *policy, | 
| Viresh Kumar | 9c0ebcf | 2013-10-25 19:45:48 +0530 | [diff] [blame] | 211 | 	unsigned int index) | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 212 | { | 
| Viresh Kumar | 9c0ebcf | 2013-10-25 19:45:48 +0530 | [diff] [blame] | 213 | 	return processor_set_freq(acpi_io_data[policy->cpu], policy, index); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 214 | } | 
 | 215 |  | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 216 | static int | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 217 | acpi_cpufreq_cpu_init ( | 
 | 218 | 	struct cpufreq_policy   *policy) | 
 | 219 | { | 
 | 220 | 	unsigned int		i; | 
 | 221 | 	unsigned int		cpu = policy->cpu; | 
 | 222 | 	struct cpufreq_acpi_io	*data; | 
 | 223 | 	unsigned int		result = 0; | 
| Pan Xinhui | 946c14f | 2015-07-20 14:22:46 +0800 | [diff] [blame] | 224 | 	struct cpufreq_frequency_table *freq_table; | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 225 |  | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 226 | 	pr_debug("acpi_cpufreq_cpu_init\n"); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 227 |  | 
| Viresh Kumar | d5b73cd | 2013-08-06 22:53:06 +0530 | [diff] [blame] | 228 | 	data = kzalloc(sizeof(*data), GFP_KERNEL); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 229 | 	if (!data) | 
 | 230 | 		return (-ENOMEM); | 
 | 231 |  | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 232 | 	acpi_io_data[cpu] = data; | 
 | 233 |  | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 234 | 	result = acpi_processor_register_performance(&data->acpi_data, cpu); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 235 |  | 
 | 236 | 	if (result) | 
 | 237 | 		goto err_free; | 
 | 238 |  | 
 | 239 | 	/* capability check */ | 
 | 240 | 	if (data->acpi_data.state_count <= 1) { | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 241 | 		pr_debug("No P-States\n"); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 242 | 		result = -ENODEV; | 
 | 243 | 		goto err_unreg; | 
 | 244 | 	} | 
 | 245 |  | 
 | 246 | 	if ((data->acpi_data.control_register.space_id != | 
 | 247 | 					ACPI_ADR_SPACE_FIXED_HARDWARE) || | 
 | 248 | 	    (data->acpi_data.status_register.space_id != | 
 | 249 | 					ACPI_ADR_SPACE_FIXED_HARDWARE)) { | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 250 | 		pr_debug("Unsupported address space [%d, %d]\n", | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 251 | 			(u32) (data->acpi_data.control_register.space_id), | 
 | 252 | 			(u32) (data->acpi_data.status_register.space_id)); | 
 | 253 | 		result = -ENODEV; | 
 | 254 | 		goto err_unreg; | 
 | 255 | 	} | 
 | 256 |  | 
 | 257 | 	/* alloc freq_table */ | 
| Pan Xinhui | 946c14f | 2015-07-20 14:22:46 +0800 | [diff] [blame] | 258 | 	freq_table = kzalloc(sizeof(*freq_table) * | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 259 | 	                           (data->acpi_data.state_count + 1), | 
 | 260 | 	                           GFP_KERNEL); | 
| Pan Xinhui | 946c14f | 2015-07-20 14:22:46 +0800 | [diff] [blame] | 261 | 	if (!freq_table) { | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 262 | 		result = -ENOMEM; | 
 | 263 | 		goto err_unreg; | 
 | 264 | 	} | 
 | 265 |  | 
 | 266 | 	/* detect transition latency */ | 
 | 267 | 	policy->cpuinfo.transition_latency = 0; | 
 | 268 | 	for (i=0; i<data->acpi_data.state_count; i++) { | 
 | 269 | 		if ((data->acpi_data.states[i].transition_latency * 1000) > | 
 | 270 | 		    policy->cpuinfo.transition_latency) { | 
 | 271 | 			policy->cpuinfo.transition_latency = | 
 | 272 | 			    data->acpi_data.states[i].transition_latency * 1000; | 
 | 273 | 		} | 
 | 274 | 	} | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 275 |  | 
 | 276 | 	/* table init */ | 
 | 277 | 	for (i = 0; i <= data->acpi_data.state_count; i++) | 
 | 278 | 	{ | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 279 | 		if (i < data->acpi_data.state_count) { | 
| Pan Xinhui | 946c14f | 2015-07-20 14:22:46 +0800 | [diff] [blame] | 280 | 			freq_table[i].frequency = | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 281 | 			      data->acpi_data.states[i].core_frequency * 1000; | 
 | 282 | 		} else { | 
| Pan Xinhui | 946c14f | 2015-07-20 14:22:46 +0800 | [diff] [blame] | 283 | 			freq_table[i].frequency = CPUFREQ_TABLE_END; | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 284 | 		} | 
 | 285 | 	} | 
 | 286 |  | 
| Pan Xinhui | 946c14f | 2015-07-20 14:22:46 +0800 | [diff] [blame] | 287 | 	result = cpufreq_table_validate_and_show(policy, freq_table); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 288 | 	if (result) { | 
 | 289 | 		goto err_freqfree; | 
 | 290 | 	} | 
 | 291 |  | 
 | 292 | 	/* notify BIOS that we exist */ | 
 | 293 | 	acpi_processor_notify_smm(THIS_MODULE); | 
 | 294 |  | 
| Joe Perches | 1c5864e | 2016-04-05 13:28:25 -0700 | [diff] [blame] | 295 | 	pr_info("CPU%u - ACPI performance management activated\n", cpu); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 296 |  | 
 | 297 | 	for (i = 0; i < data->acpi_data.state_count; i++) | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 298 | 		pr_debug("     %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n", | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 299 | 			(i == data->acpi_data.state?'*':' '), i, | 
 | 300 | 			(u32) data->acpi_data.states[i].core_frequency, | 
 | 301 | 			(u32) data->acpi_data.states[i].power, | 
 | 302 | 			(u32) data->acpi_data.states[i].transition_latency, | 
 | 303 | 			(u32) data->acpi_data.states[i].bus_master_latency, | 
 | 304 | 			(u32) data->acpi_data.states[i].status, | 
 | 305 | 			(u32) data->acpi_data.states[i].control); | 
 | 306 |  | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 307 | 	/* the first call to ->target() should result in us actually | 
 | 308 | 	 * writing something to the appropriate registers. */ | 
 | 309 | 	data->resume = 1; | 
 | 310 |  | 
 | 311 | 	return (result); | 
 | 312 |  | 
 | 313 |  err_freqfree: | 
| Pan Xinhui | 946c14f | 2015-07-20 14:22:46 +0800 | [diff] [blame] | 314 | 	kfree(freq_table); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 315 |  err_unreg: | 
| Rafael J. Wysocki | b2f8dc4 | 2015-07-22 22:11:16 +0200 | [diff] [blame] | 316 | 	acpi_processor_unregister_performance(cpu); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 317 |  err_free: | 
 | 318 | 	kfree(data); | 
 | 319 | 	acpi_io_data[cpu] = NULL; | 
 | 320 |  | 
 | 321 | 	return (result); | 
 | 322 | } | 
 | 323 |  | 
 | 324 |  | 
 | 325 | static int | 
 | 326 | acpi_cpufreq_cpu_exit ( | 
 | 327 | 	struct cpufreq_policy   *policy) | 
 | 328 | { | 
 | 329 | 	struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; | 
 | 330 |  | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 331 | 	pr_debug("acpi_cpufreq_cpu_exit\n"); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 332 |  | 
 | 333 | 	if (data) { | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 334 | 		acpi_io_data[policy->cpu] = NULL; | 
| Rafael J. Wysocki | b2f8dc4 | 2015-07-22 22:11:16 +0200 | [diff] [blame] | 335 | 		acpi_processor_unregister_performance(policy->cpu); | 
| Pan Xinhui | 555f3fe | 2015-07-20 14:24:36 +0800 | [diff] [blame] | 336 | 		kfree(policy->freq_table); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 337 | 		kfree(data); | 
 | 338 | 	} | 
 | 339 |  | 
 | 340 | 	return (0); | 
 | 341 | } | 
 | 342 |  | 
 | 343 |  | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 344 | static struct cpufreq_driver acpi_cpufreq_driver = { | 
| Viresh Kumar | 59b2413 | 2013-10-03 20:28:07 +0530 | [diff] [blame] | 345 | 	.verify 	= cpufreq_generic_frequency_table_verify, | 
| Viresh Kumar | 9c0ebcf | 2013-10-25 19:45:48 +0530 | [diff] [blame] | 346 | 	.target_index	= acpi_cpufreq_target, | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 347 | 	.get 		= acpi_cpufreq_get, | 
 | 348 | 	.init		= acpi_cpufreq_cpu_init, | 
 | 349 | 	.exit		= acpi_cpufreq_cpu_exit, | 
 | 350 | 	.name		= "acpi-cpufreq", | 
| Viresh Kumar | 59b2413 | 2013-10-03 20:28:07 +0530 | [diff] [blame] | 351 | 	.attr		= cpufreq_generic_attr, | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 352 | }; | 
 | 353 |  | 
 | 354 |  | 
 | 355 | static int __init | 
 | 356 | acpi_cpufreq_init (void) | 
 | 357 | { | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 358 | 	pr_debug("acpi_cpufreq_init\n"); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 359 |  | 
 | 360 |  	return cpufreq_register_driver(&acpi_cpufreq_driver); | 
 | 361 | } | 
 | 362 |  | 
 | 363 |  | 
 | 364 | static void __exit | 
 | 365 | acpi_cpufreq_exit (void) | 
 | 366 | { | 
| Dominik Brodowski | 2d06d8c | 2011-03-27 15:04:46 +0200 | [diff] [blame] | 367 | 	pr_debug("acpi_cpufreq_exit\n"); | 
| Venkatesh Pallipadi | 4db8699 | 2005-07-29 16:15:00 -0700 | [diff] [blame] | 368 |  | 
 | 369 | 	cpufreq_unregister_driver(&acpi_cpufreq_driver); | 
 | 370 | 	return; | 
 | 371 | } | 
 | 372 |  | 
 | 373 |  | 
 | 374 | late_initcall(acpi_cpufreq_init); | 
 | 375 | module_exit(acpi_cpufreq_exit); | 
 | 376 |  |