Blame view

drivers/acpi/processor_perflib.c 19.3 KB
c942fddf8   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
  /*
   * processor_perflib.c - ACPI Processor P-States Library ($Revision: 71 $)
   *
   *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
   *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
   *  Copyright (C) 2004       Dominik Brodowski <linux@brodo.de>
   *  Copyright (C) 2004  Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
   *  			- Added processor hotplug support
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/cpufreq.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
15
  #include <linux/slab.h>
8b48463f8   Lv Zheng   ACPI: Clean up in...
16
17
  #include <linux/acpi.h>
  #include <acpi/processor.h>
16be87ea1   Miao Xie   ACPI: cpufreq, pr...
18
  #ifdef CONFIG_X86
910dfae29   Thomas Renninger   ACPI: cpufreq, pr...
19
  #include <asm/cpufeature.h>
16be87ea1   Miao Xie   ACPI: cpufreq, pr...
20
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21

a192a9580   Len Brown   ACPI: Move defini...
22
  #define PREFIX "ACPI: "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  #define ACPI_PROCESSOR_CLASS		"processor"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  #define ACPI_PROCESSOR_FILE_PERFORMANCE	"performance"
  #define _COMPONENT		ACPI_PROCESSOR_COMPONENT
f52fd66d2   Len Brown   ACPI: clean up AC...
26
  ACPI_MODULE_NAME("processor_perflib");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27

65c19bbd2   Arjan van de Ven   sem2mutex: driver...
28
  static DEFINE_MUTEX(performance_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
34
35
36
37
38
  
  /*
   * _PPC support is implemented as a CPUfreq policy notifier:
   * This means each time a CPUfreq driver registered also with
   * the ACPI core is asked to change the speed policy, the maximum
   * value is adjusted so that it is within the platform limit.
   *
   * Also, when a new platform limit value is detected, the CPUfreq
   * policy is adjusted accordingly.
   */
a1531acd4   Thomas Renninger   cpufreq acpi: onl...
39
40
41
42
43
44
  /* ignore_ppc:
   * -1 -> cpufreq low level drivers not initialized -> _PSS, etc. not called yet
   *       ignore _PPC
   *  0 -> cpufreq low level drivers initialized -> consider _PPC values
   *  1 -> ignore _PPC totally -> forced by user through boot param
   */
9f497bcc6   Milan Broz   ACPI: Fix thermal...
45
  static int ignore_ppc = -1;
613e5f337   Milan Broz   ACPI: Fix now sig...
46
  module_param(ignore_ppc, int, 0644);
623b78c39   Thomas Renninger   ACPI: add "proces...
47
48
  MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \
  		 "limited by BIOS, this should help");
d15ce4127   Viresh Kumar   ACPI: cpufreq: Sw...
49
  static bool acpi_processor_ppc_in_use;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50

4be44fcd3   Len Brown   [ACPI] Lindent al...
51
  static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
53
  	acpi_status status = 0;
27663c585   Matthew Wilcox   ACPI: Change acpi...
54
  	unsigned long long ppc = 0;
d15ce4127   Viresh Kumar   ACPI: cpufreq: Sw...
55
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
  
  	if (!pr)
d550d98d3   Patrick Mochel   ACPI: delete trac...
58
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
61
62
63
64
65
66
  
  	/*
  	 * _PPC indicates the maximum state currently supported by the platform
  	 * (e.g. 0 = states 0..n; 1 = states 1..n; etc.
  	 */
  	status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc);
  
  	if (status != AE_NOT_FOUND)
d15ce4127   Viresh Kumar   ACPI: cpufreq: Sw...
67
  		acpi_processor_ppc_in_use = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68

4be44fcd3   Len Brown   [ACPI] Lindent al...
69
  	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
70
  		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PPC"));
d550d98d3   Patrick Mochel   ACPI: delete trac...
71
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
  	}
2d06d8c49   Dominik Brodowski   [CPUFREQ] use dyn...
73
74
  	pr_debug("CPU %d: _PPC is %d - frequency %s limited
  ", pr->id,
919158d17   Thomas Renninger   ACPI: cpufreq: Pr...
75
  		       (int)ppc, ppc ? "" : "not");
4be44fcd3   Len Brown   [ACPI] Lindent al...
76
  	pr->performance_platform_limit = (int)ppc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77

d15ce4127   Viresh Kumar   ACPI: cpufreq: Sw...
78
  	if (ppc >= pr->performance->state_count ||
3000ce3c5   Rafael J. Wysocki   cpufreq: Use per-...
79
  	    unlikely(!freq_qos_request_active(&pr->perflib_req)))
d15ce4127   Viresh Kumar   ACPI: cpufreq: Sw...
80
  		return 0;
3000ce3c5   Rafael J. Wysocki   cpufreq: Use per-...
81
  	ret = freq_qos_update_request(&pr->perflib_req,
d15ce4127   Viresh Kumar   ACPI: cpufreq: Sw...
82
83
84
85
86
87
  			pr->performance->states[ppc].core_frequency * 1000);
  	if (ret < 0) {
  		pr_warn("Failed to update perflib freq constraint: CPU%d (%d)
  ",
  			pr->id, ret);
  	}
d550d98d3   Patrick Mochel   ACPI: delete trac...
88
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  }
d81c45e1c   Zhao Yakui   ACPI: Notify the ...
90
91
92
93
94
95
96
97
98
99
  #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE	0x80
  /*
   * acpi_processor_ppc_ost: Notify firmware the _PPC evaluation status
   * @handle: ACPI processor handle
   * @status: the status code of _PPC evaluation
   *	0: success. OSPM is now using the performance state specificed.
   *	1: failure. OSPM has not changed the number of P-states in use
   */
  static void acpi_processor_ppc_ost(acpi_handle handle, int status)
  {
4a6172a4e   Jiang Liu   ACPI / processor:...
100
101
102
  	if (acpi_has_method(handle, "_OST"))
  		acpi_evaluate_ost(handle, ACPI_PROCESSOR_NOTIFY_PERFORMANCE,
  				  status, NULL);
d81c45e1c   Zhao Yakui   ACPI: Notify the ...
103
  }
bca5f557d   Rafael J. Wysocki   ACPI / processor:...
104
  void acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  {
623b78c39   Thomas Renninger   ACPI: add "proces...
106
  	int ret;
ba1edb9a5   Chen Yu   ACPI: processor_p...
107
  	if (ignore_ppc || !pr->performance) {
d81c45e1c   Zhao Yakui   ACPI: Notify the ...
108
109
110
111
112
113
  		/*
  		 * Only when it is notification event, the _OST object
  		 * will be evaluated. Otherwise it is skipped.
  		 */
  		if (event_flag)
  			acpi_processor_ppc_ost(pr->handle, 1);
bca5f557d   Rafael J. Wysocki   ACPI / processor:...
114
  		return;
d81c45e1c   Zhao Yakui   ACPI: Notify the ...
115
  	}
623b78c39   Thomas Renninger   ACPI: add "proces...
116
117
  
  	ret = acpi_processor_get_platform_limit(pr);
d81c45e1c   Zhao Yakui   ACPI: Notify the ...
118
119
120
121
122
123
124
125
126
127
  	/*
  	 * Only when it is notification event, the _OST object
  	 * will be evaluated. Otherwise it is skipped.
  	 */
  	if (event_flag) {
  		if (ret < 0)
  			acpi_processor_ppc_ost(pr->handle, 1);
  		else
  			acpi_processor_ppc_ost(pr->handle, 0);
  	}
bca5f557d   Rafael J. Wysocki   ACPI / processor:...
128
  	if (ret >= 0)
5a25e3f7c   Rafael J. Wysocki   cpufreq: intel_ps...
129
  		cpufreq_update_limits(pr->id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  }
e2f74f355   Thomas Renninger   [ACPI/CPUFREQ] In...
131
132
133
134
135
136
137
138
139
140
141
142
  int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
  {
  	struct acpi_processor *pr;
  
  	pr = per_cpu(processors, cpu);
  	if (!pr || !pr->performance || !pr->performance->state_count)
  		return -ENODEV;
  	*limit = pr->performance->states[pr->performance_platform_limit].
  		core_frequency * 1000;
  	return 0;
  }
  EXPORT_SYMBOL(acpi_processor_get_bios_limit);
d15ce4127   Viresh Kumar   ACPI: cpufreq: Sw...
143
  void acpi_processor_ignore_ppc_init(void)
4be44fcd3   Len Brown   [ACPI] Lindent al...
144
  {
d15ce4127   Viresh Kumar   ACPI: cpufreq: Sw...
145
146
147
  	if (ignore_ppc < 0)
  		ignore_ppc = 0;
  }
3000ce3c5   Rafael J. Wysocki   cpufreq: Use per-...
148
  void acpi_processor_ppc_init(struct cpufreq_policy *policy)
d15ce4127   Viresh Kumar   ACPI: cpufreq: Sw...
149
  {
a1bb46c36   Rafael J. Wysocki   ACPI: processor: ...
150
  	unsigned int cpu;
d15ce4127   Viresh Kumar   ACPI: cpufreq: Sw...
151

a1bb46c36   Rafael J. Wysocki   ACPI: processor: ...
152
153
154
155
156
157
  	for_each_cpu(cpu, policy->related_cpus) {
  		struct acpi_processor *pr = per_cpu(processors, cpu);
  		int ret;
  
  		if (!pr)
  			continue;
2d8b39a62   Rafael J. Wysocki   ACPI: processor: ...
158

a1bb46c36   Rafael J. Wysocki   ACPI: processor: ...
159
160
161
162
163
164
165
166
  		ret = freq_qos_add_request(&policy->constraints,
  					   &pr->perflib_req,
  					   FREQ_QOS_MAX, INT_MAX);
  		if (ret < 0)
  			pr_err("Failed to add freq constraint for CPU%d (%d)
  ",
  			       cpu, ret);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  }
3000ce3c5   Rafael J. Wysocki   cpufreq: Use per-...
168
  void acpi_processor_ppc_exit(struct cpufreq_policy *policy)
4be44fcd3   Len Brown   [ACPI] Lindent al...
169
  {
a1bb46c36   Rafael J. Wysocki   ACPI: processor: ...
170
  	unsigned int cpu;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171

a1bb46c36   Rafael J. Wysocki   ACPI: processor: ...
172
173
174
175
176
177
  	for_each_cpu(cpu, policy->related_cpus) {
  		struct acpi_processor *pr = per_cpu(processors, cpu);
  
  		if (pr)
  			freq_qos_remove_request(&pr->perflib_req);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
179
  static int acpi_processor_get_performance_control(struct acpi_processor *pr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
181
182
183
184
185
  	int result = 0;
  	acpi_status status = 0;
  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
  	union acpi_object *pct = NULL;
  	union acpi_object obj = { 0 };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
  
  	status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer);
4be44fcd3   Len Brown   [ACPI] Lindent al...
189
  	if (ACPI_FAILURE(status)) {
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
190
  		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PCT"));
d550d98d3   Patrick Mochel   ACPI: delete trac...
191
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
193
  	pct = (union acpi_object *)buffer.pointer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  	if (!pct || (pct->type != ACPI_TYPE_PACKAGE)
4be44fcd3   Len Brown   [ACPI] Lindent al...
195
  	    || (pct->package.count != 2)) {
6468463ab   Len Brown   ACPI: un-export A...
196
197
  		printk(KERN_ERR PREFIX "Invalid _PCT data
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
202
203
204
205
206
207
208
  		result = -EFAULT;
  		goto end;
  	}
  
  	/*
  	 * control_register
  	 */
  
  	obj = pct->package.elements[0];
  
  	if ((obj.type != ACPI_TYPE_BUFFER)
4be44fcd3   Len Brown   [ACPI] Lindent al...
209
210
  	    || (obj.buffer.length < sizeof(struct acpi_pct_register))
  	    || (obj.buffer.pointer == NULL)) {
6468463ab   Len Brown   ACPI: un-export A...
211
212
  		printk(KERN_ERR PREFIX "Invalid _PCT data (control_register)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
  		result = -EFAULT;
  		goto end;
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
216
217
  	memcpy(&pr->performance->control_register, obj.buffer.pointer,
  	       sizeof(struct acpi_pct_register));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
221
222
223
224
225
  
  	/*
  	 * status_register
  	 */
  
  	obj = pct->package.elements[1];
  
  	if ((obj.type != ACPI_TYPE_BUFFER)
4be44fcd3   Len Brown   [ACPI] Lindent al...
226
227
  	    || (obj.buffer.length < sizeof(struct acpi_pct_register))
  	    || (obj.buffer.pointer == NULL)) {
6468463ab   Len Brown   ACPI: un-export A...
228
229
  		printk(KERN_ERR PREFIX "Invalid _PCT data (status_register)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
232
  		result = -EFAULT;
  		goto end;
  	}
4be44fcd3   Len Brown   [ACPI] Lindent al...
233
234
  	memcpy(&pr->performance->status_register, obj.buffer.pointer,
  	       sizeof(struct acpi_pct_register));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235

4be44fcd3   Len Brown   [ACPI] Lindent al...
236
        end:
02438d877   Len Brown   ACPI: delete acpi...
237
  	kfree(buffer.pointer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238

d550d98d3   Patrick Mochel   ACPI: delete trac...
239
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  }
f594065fa   Matthew Garrett   ACPI: Add fixups ...
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
  #ifdef CONFIG_X86
  /*
   * Some AMDs have 50MHz frequency multiples, but only provide 100MHz rounding
   * in their ACPI data. Calculate the real values and fix up the _PSS data.
   */
  static void amd_fixup_frequency(struct acpi_processor_px *px, int i)
  {
  	u32 hi, lo, fid, did;
  	int index = px->control & 0x00000007;
  
  	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
  		return;
  
  	if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10)
  	    || boot_cpu_data.x86 == 0x11) {
  		rdmsr(MSR_AMD_PSTATE_DEF_BASE + index, lo, hi);
9855d8ce4   Stefan Bader   ACPI: Check MSR v...
257
258
259
260
261
262
  		/*
  		 * MSR C001_0064+:
  		 * Bit 63: PstateEn. Read-write. If set, the P-state is valid.
  		 */
  		if (!(hi & BIT(31)))
  			return;
f594065fa   Matthew Garrett   ACPI: Add fixups ...
263
264
265
266
267
268
269
270
271
272
273
  		fid = lo & 0x3f;
  		did = (lo >> 6) & 7;
  		if (boot_cpu_data.x86 == 0x10)
  			px->core_frequency = (100 * (fid + 0x10)) >> did;
  		else
  			px->core_frequency = (100 * (fid + 8)) >> did;
  	}
  }
  #else
  static void amd_fixup_frequency(struct acpi_processor_px *px, int i) {};
  #endif
4be44fcd3   Len Brown   [ACPI] Lindent al...
274
  static int acpi_processor_get_performance_states(struct acpi_processor *pr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
276
277
278
279
280
281
282
  	int result = 0;
  	acpi_status status = AE_OK;
  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
  	struct acpi_buffer format = { sizeof("NNNNNN"), "NNNNNN" };
  	struct acpi_buffer state = { 0, NULL };
  	union acpi_object *pss = NULL;
  	int i;
d8e725f35   Marco Aurelio da Costa   ACPI: Ignore inva...
283
  	int last_invalid = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
  
  	status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer);
4be44fcd3   Len Brown   [ACPI] Lindent al...
287
  	if (ACPI_FAILURE(status)) {
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
288
  		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PSS"));
d550d98d3   Patrick Mochel   ACPI: delete trac...
289
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  	}
50dd09697   Jan Engelhardt   ACPI: Remove unne...
291
  	pss = buffer.pointer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
  	if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) {
6468463ab   Len Brown   ACPI: un-export A...
293
294
  		printk(KERN_ERR PREFIX "Invalid _PSS data
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
298
299
300
  		result = -EFAULT;
  		goto end;
  	}
  
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states
  ",
4be44fcd3   Len Brown   [ACPI] Lindent al...
301
  			  pss->package.count));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
  
  	pr->performance->state_count = pss->package.count;
4be44fcd3   Len Brown   [ACPI] Lindent al...
304
  	pr->performance->states =
6da2ec560   Kees Cook   treewide: kmalloc...
305
306
307
  	    kmalloc_array(pss->package.count,
  			  sizeof(struct acpi_processor_px),
  			  GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
  	if (!pr->performance->states) {
  		result = -ENOMEM;
  		goto end;
  	}
  
  	for (i = 0; i < pr->performance->state_count; i++) {
  
  		struct acpi_processor_px *px = &(pr->performance->states[i]);
  
  		state.length = sizeof(struct acpi_processor_px);
  		state.pointer = px;
  
  		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d
  ", i));
  
  		status = acpi_extract_package(&(pss->package.elements[i]),
4be44fcd3   Len Brown   [ACPI] Lindent al...
324
  					      &format, &state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  		if (ACPI_FAILURE(status)) {
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
326
  			ACPI_EXCEPTION((AE_INFO, status, "Invalid _PSS data"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
330
  			result = -EFAULT;
  			kfree(pr->performance->states);
  			goto end;
  		}
f594065fa   Matthew Garrett   ACPI: Add fixups ...
331
  		amd_fixup_frequency(px, i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd3   Len Brown   [ACPI] Lindent al...
333
334
335
336
337
338
339
340
  				  "State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]
  ",
  				  i,
  				  (u32) px->core_frequency,
  				  (u32) px->power,
  				  (u32) px->transition_latency,
  				  (u32) px->bus_master_latency,
  				  (u32) px->control, (u32) px->status));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341

34d531e64   Len Brown   ACPI: sanity chec...
342
  		/*
c6237b210   Maximilian Luz   ACPI: Fix whitesp...
343
  		 * Check that ACPI's u64 MHz will be valid as u32 KHz in cpufreq
34d531e64   Len Brown   ACPI: sanity chec...
344
345
346
347
348
  		 */
  		if (!px->core_frequency ||
  		    ((u32)(px->core_frequency * 1000) !=
  		     (px->core_frequency * 1000))) {
  			printk(KERN_ERR FW_BUG PREFIX
d8e725f35   Marco Aurelio da Costa   ACPI: Ignore inva...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
  			       "Invalid BIOS _PSS frequency found for processor %d: 0x%llx MHz
  ",
  			       pr->id, px->core_frequency);
  			if (last_invalid == -1)
  				last_invalid = i;
  		} else {
  			if (last_invalid != -1) {
  				/*
  				 * Copy this valid entry over last_invalid entry
  				 */
  				memcpy(&(pr->performance->states[last_invalid]),
  				       px, sizeof(struct acpi_processor_px));
  				++last_invalid;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
  		}
  	}
d8e725f35   Marco Aurelio da Costa   ACPI: Ignore inva...
365
366
367
368
369
370
371
372
373
374
375
  	if (last_invalid == 0) {
  		printk(KERN_ERR FW_BUG PREFIX
  		       "No valid BIOS _PSS frequency found for processor %d
  ", pr->id);
  		result = -EFAULT;
  		kfree(pr->performance->states);
  		pr->performance->states = NULL;
  	}
  
  	if (last_invalid > 0)
  		pr->performance->state_count = last_invalid;
4be44fcd3   Len Brown   [ACPI] Lindent al...
376
        end:
02438d877   Len Brown   ACPI: delete acpi...
377
  	kfree(buffer.pointer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378

d550d98d3   Patrick Mochel   ACPI: delete trac...
379
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  }
c705c78c0   Konrad Rzeszutek Wilk   acpi: Export the ...
381
  int acpi_processor_get_performance_info(struct acpi_processor *pr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
383
  	int result = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
  	if (!pr || !pr->performance || !pr->handle)
d550d98d3   Patrick Mochel   ACPI: delete trac...
386
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387

952c63e95   Jiang Liu   ACPI: introduce h...
388
  	if (!acpi_has_method(pr->handle, "_PCT")) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd3   Len Brown   [ACPI] Lindent al...
390
391
  				  "ACPI-based processor performance control unavailable
  "));
d550d98d3   Patrick Mochel   ACPI: delete trac...
392
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
396
  	}
  
  	result = acpi_processor_get_performance_control(pr);
  	if (result)
910dfae29   Thomas Renninger   ACPI: cpufreq, pr...
397
  		goto update_bios;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
400
  
  	result = acpi_processor_get_performance_states(pr);
  	if (result)
910dfae29   Thomas Renninger   ACPI: cpufreq, pr...
401
  		goto update_bios;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402

455c0d71d   Darrick J. Wong   ACPI: Fix regress...
403
404
405
406
407
  	/* We need to call _PPC once when cpufreq starts */
  	if (ignore_ppc != 1)
  		result = acpi_processor_get_platform_limit(pr);
  
  	return result;
910dfae29   Thomas Renninger   ACPI: cpufreq, pr...
408
409
410
411
412
413
  
  	/*
  	 * Having _PPC but missing frequencies (_PSS, _PCT) is a very good hint that
  	 * the BIOS is older than the CPU and does not know its frequencies
  	 */
   update_bios:
16be87ea1   Miao Xie   ACPI: cpufreq, pr...
414
  #ifdef CONFIG_X86
952c63e95   Jiang Liu   ACPI: introduce h...
415
  	if (acpi_has_method(pr->handle, "_PPC")) {
910dfae29   Thomas Renninger   ACPI: cpufreq, pr...
416
417
418
419
420
  		if(boot_cpu_has(X86_FEATURE_EST))
  			printk(KERN_WARNING FW_BUG "BIOS needs update for CPU "
  			       "frequency support
  ");
  	}
16be87ea1   Miao Xie   ACPI: cpufreq, pr...
421
  #endif
910dfae29   Thomas Renninger   ACPI: cpufreq, pr...
422
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  }
c705c78c0   Konrad Rzeszutek Wilk   acpi: Export the ...
424
  EXPORT_SYMBOL_GPL(acpi_processor_get_performance_info);
d0ea59e18   Rafael J. Wysocki   cpufreq: intel_ps...
425
426
  
  int acpi_processor_pstate_control(void)
4be44fcd3   Len Brown   [ACPI] Lindent al...
427
428
  {
  	acpi_status status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429

d0ea59e18   Rafael J. Wysocki   cpufreq: intel_ps...
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
  	if (!acpi_gbl_FADT.smi_command || !acpi_gbl_FADT.pstate_control)
  		return 0;
  
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
  			  "Writing pstate_control [0x%x] to smi_command [0x%x]
  ",
  			  acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
  
  	status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
  				    (u32)acpi_gbl_FADT.pstate_control, 8);
  	if (ACPI_SUCCESS(status))
  		return 1;
  
  	ACPI_EXCEPTION((AE_INFO, status,
  			"Failed to write pstate_control [0x%x] to smi_command [0x%x]",
  			acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
  	return -EIO;
  }
  
  int acpi_processor_notify_smm(struct module *calling_module)
  {
  	static int is_done = 0;
  	int result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453

d15ce4127   Viresh Kumar   ACPI: cpufreq: Sw...
454
  	if (!acpi_processor_cpufreq_init)
d550d98d3   Patrick Mochel   ACPI: delete trac...
455
  		return -EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
  
  	if (!try_module_get(calling_module))
d550d98d3   Patrick Mochel   ACPI: delete trac...
458
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459

58f87ed0d   Lucas De Marchi   ACPI: Fix typos
460
461
  	/* is_done is set to negative if an error occurred,
  	 * and to postitive if _no_ error occurred, but SMM
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
465
466
  	 * was already notified. This avoids double notification
  	 * which might lead to unexpected results...
  	 */
  	if (is_done > 0) {
  		module_put(calling_module);
d550d98d3   Patrick Mochel   ACPI: delete trac...
467
  		return 0;
4be44fcd3   Len Brown   [ACPI] Lindent al...
468
  	} else if (is_done < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  		module_put(calling_module);
d550d98d3   Patrick Mochel   ACPI: delete trac...
470
  		return is_done;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
  	}
  
  	is_done = -EIO;
d0ea59e18   Rafael J. Wysocki   cpufreq: intel_ps...
474
475
  	result = acpi_processor_pstate_control();
  	if (!result) {
ad71860a1   Alexey Starikovskiy   ACPICA: minimal p...
476
477
  		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control
  "));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
  		module_put(calling_module);
d550d98d3   Patrick Mochel   ACPI: delete trac...
479
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
  	}
d0ea59e18   Rafael J. Wysocki   cpufreq: intel_ps...
481
  	if (result < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  		module_put(calling_module);
d0ea59e18   Rafael J. Wysocki   cpufreq: intel_ps...
483
  		return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
487
488
  	}
  
  	/* Success. If there's no _PPC, we need to fear nothing, so
  	 * we can allow the cpufreq driver to be rmmod'ed. */
  	is_done = 1;
d15ce4127   Viresh Kumar   ACPI: cpufreq: Sw...
489
  	if (!acpi_processor_ppc_in_use)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
  		module_put(calling_module);
d550d98d3   Patrick Mochel   ACPI: delete trac...
491
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493

4be44fcd3   Len Brown   [ACPI] Lindent al...
494
  EXPORT_SYMBOL(acpi_processor_notify_smm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495

4d0f1ce69   Joao Martins   xen/acpi: upload ...
496
  int acpi_processor_get_psd(acpi_handle handle, struct acpi_psd_package *pdomain)
3b2d99429   Venkatesh Pallipadi   P-state software ...
497
498
499
500
501
502
503
  {
  	int result = 0;
  	acpi_status status = AE_OK;
  	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
  	struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"};
  	struct acpi_buffer state = {0, NULL};
  	union acpi_object  *psd = NULL;
3b2d99429   Venkatesh Pallipadi   P-state software ...
504

4d0f1ce69   Joao Martins   xen/acpi: upload ...
505
  	status = acpi_evaluate_object(handle, "_PSD", NULL, &buffer);
3b2d99429   Venkatesh Pallipadi   P-state software ...
506
  	if (ACPI_FAILURE(status)) {
9011bff4b   Len Brown   ACPI: delete newl...
507
  		return -ENODEV;
3b2d99429   Venkatesh Pallipadi   P-state software ...
508
  	}
50dd09697   Jan Engelhardt   ACPI: Remove unne...
509
  	psd = buffer.pointer;
3b2d99429   Venkatesh Pallipadi   P-state software ...
510
  	if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) {
55ac9a018   Lin Ming   ACPI: replace ACP...
511
512
  		printk(KERN_ERR PREFIX "Invalid _PSD data
  ");
3b2d99429   Venkatesh Pallipadi   P-state software ...
513
514
515
516
517
  		result = -EFAULT;
  		goto end;
  	}
  
  	if (psd->package.count != 1) {
55ac9a018   Lin Ming   ACPI: replace ACP...
518
519
  		printk(KERN_ERR PREFIX "Invalid _PSD data
  ");
3b2d99429   Venkatesh Pallipadi   P-state software ...
520
521
522
  		result = -EFAULT;
  		goto end;
  	}
3b2d99429   Venkatesh Pallipadi   P-state software ...
523
524
525
526
527
528
  	state.length = sizeof(struct acpi_psd_package);
  	state.pointer = pdomain;
  
  	status = acpi_extract_package(&(psd->package.elements[0]),
  		&format, &state);
  	if (ACPI_FAILURE(status)) {
55ac9a018   Lin Ming   ACPI: replace ACP...
529
530
  		printk(KERN_ERR PREFIX "Invalid _PSD data
  ");
3b2d99429   Venkatesh Pallipadi   P-state software ...
531
532
533
534
535
  		result = -EFAULT;
  		goto end;
  	}
  
  	if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) {
55ac9a018   Lin Ming   ACPI: replace ACP...
536
537
  		printk(KERN_ERR PREFIX "Unknown _PSD:num_entries
  ");
3b2d99429   Venkatesh Pallipadi   P-state software ...
538
539
540
541
542
  		result = -EFAULT;
  		goto end;
  	}
  
  	if (pdomain->revision != ACPI_PSD_REV0_REVISION) {
55ac9a018   Lin Ming   ACPI: replace ACP...
543
544
  		printk(KERN_ERR PREFIX "Unknown _PSD:revision
  ");
3b2d99429   Venkatesh Pallipadi   P-state software ...
545
546
547
  		result = -EFAULT;
  		goto end;
  	}
e1eb47797   Stanislaw Gruszka   ACPI: Avoid wipin...
548
549
550
551
552
553
554
555
  	if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
  	    pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
  	    pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
  		printk(KERN_ERR PREFIX "Invalid _PSD:coord_type
  ");
  		result = -EFAULT;
  		goto end;
  	}
3b2d99429   Venkatesh Pallipadi   P-state software ...
556
  end:
02438d877   Len Brown   ACPI: delete acpi...
557
  	kfree(buffer.pointer);
9011bff4b   Len Brown   ACPI: delete newl...
558
  	return result;
3b2d99429   Venkatesh Pallipadi   P-state software ...
559
  }
4d0f1ce69   Joao Martins   xen/acpi: upload ...
560
  EXPORT_SYMBOL(acpi_processor_get_psd);
3b2d99429   Venkatesh Pallipadi   P-state software ...
561
562
  
  int acpi_processor_preregister_performance(
a29d8b8e2   Tejun Heo   percpu: add __per...
563
  		struct acpi_processor_performance __percpu *performance)
3b2d99429   Venkatesh Pallipadi   P-state software ...
564
  {
09d5ca804   Lan Tianyu   ACPI / processor:...
565
  	int count_target;
3b2d99429   Venkatesh Pallipadi   P-state software ...
566
567
  	int retval = 0;
  	unsigned int i, j;
2fdf66b49   Rusty Russell   cpumask: convert ...
568
  	cpumask_var_t covered_cpus;
3b2d99429   Venkatesh Pallipadi   P-state software ...
569
570
571
572
  	struct acpi_processor *pr;
  	struct acpi_psd_package *pdomain;
  	struct acpi_processor *match_pr;
  	struct acpi_psd_package *match_pdomain;
79f559977   Li Zefan   cpumask: use zall...
573
  	if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))
2fdf66b49   Rusty Russell   cpumask: convert ...
574
  		return -ENOMEM;
785fcccd6   Len Brown   ACPI: resolve mer...
575
  	mutex_lock(&performance_mutex);
3b2d99429   Venkatesh Pallipadi   P-state software ...
576

e1eb47797   Stanislaw Gruszka   ACPI: Avoid wipin...
577
578
579
580
  	/*
  	 * Check if another driver has already registered, and abort before
  	 * changing pr->performance if it has. Check input data as well.
  	 */
193de0c79   KAMEZAWA Hiroyuki   ACPI: use for_eac...
581
  	for_each_possible_cpu(i) {
706546d02   Mike Travis   ACPI: change proc...
582
  		pr = per_cpu(processors, i);
3b2d99429   Venkatesh Pallipadi   P-state software ...
583
584
585
586
587
588
589
  		if (!pr) {
  			/* Look only at processors in ACPI namespace */
  			continue;
  		}
  
  		if (pr->performance) {
  			retval = -EBUSY;
e1eb47797   Stanislaw Gruszka   ACPI: Avoid wipin...
590
  			goto err_out;
3b2d99429   Venkatesh Pallipadi   P-state software ...
591
  		}
b36128c83   Rusty Russell   alloc_percpu: cha...
592
  		if (!performance || !per_cpu_ptr(performance, i)) {
3b2d99429   Venkatesh Pallipadi   P-state software ...
593
  			retval = -EINVAL;
e1eb47797   Stanislaw Gruszka   ACPI: Avoid wipin...
594
  			goto err_out;
3b2d99429   Venkatesh Pallipadi   P-state software ...
595
  		}
e1eb47797   Stanislaw Gruszka   ACPI: Avoid wipin...
596
597
598
599
600
601
602
  	}
  
  	/* Call _PSD for all CPUs */
  	for_each_possible_cpu(i) {
  		pr = per_cpu(processors, i);
  		if (!pr)
  			continue;
3b2d99429   Venkatesh Pallipadi   P-state software ...
603

b36128c83   Rusty Russell   alloc_percpu: cha...
604
  		pr->performance = per_cpu_ptr(performance, i);
2fdf66b49   Rusty Russell   cpumask: convert ...
605
  		cpumask_set_cpu(i, pr->performance->shared_cpu_map);
4d0f1ce69   Joao Martins   xen/acpi: upload ...
606
607
  		pdomain = &(pr->performance->domain_info);
  		if (acpi_processor_get_psd(pr->handle, pdomain)) {
3b2d99429   Venkatesh Pallipadi   P-state software ...
608
609
610
611
612
613
614
615
  			retval = -EINVAL;
  			continue;
  		}
  	}
  	if (retval)
  		goto err_ret;
  
  	/*
c6237b210   Maximilian Luz   ACPI: Fix whitesp...
616
  	 * Now that we have _PSD data from all CPUs, lets setup P-state
3b2d99429   Venkatesh Pallipadi   P-state software ...
617
618
  	 * domain info.
  	 */
193de0c79   KAMEZAWA Hiroyuki   ACPI: use for_eac...
619
  	for_each_possible_cpu(i) {
706546d02   Mike Travis   ACPI: change proc...
620
  		pr = per_cpu(processors, i);
3b2d99429   Venkatesh Pallipadi   P-state software ...
621
622
  		if (!pr)
  			continue;
2fdf66b49   Rusty Russell   cpumask: convert ...
623
  		if (cpumask_test_cpu(i, covered_cpus))
3b2d99429   Venkatesh Pallipadi   P-state software ...
624
625
626
  			continue;
  
  		pdomain = &(pr->performance->domain_info);
2fdf66b49   Rusty Russell   cpumask: convert ...
627
628
  		cpumask_set_cpu(i, pr->performance->shared_cpu_map);
  		cpumask_set_cpu(i, covered_cpus);
3b2d99429   Venkatesh Pallipadi   P-state software ...
629
630
631
632
633
  		if (pdomain->num_processors <= 1)
  			continue;
  
  		/* Validate the Domain info */
  		count_target = pdomain->num_processors;
46f18e3a2   Venkatesh Pallipadi   ACPI: HW P-state ...
634
  		if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL)
3b2d99429   Venkatesh Pallipadi   P-state software ...
635
  			pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
46f18e3a2   Venkatesh Pallipadi   ACPI: HW P-state ...
636
637
638
  		else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL)
  			pr->performance->shared_type = CPUFREQ_SHARED_TYPE_HW;
  		else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
3b2d99429   Venkatesh Pallipadi   P-state software ...
639
  			pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY;
3b2d99429   Venkatesh Pallipadi   P-state software ...
640

193de0c79   KAMEZAWA Hiroyuki   ACPI: use for_eac...
641
  		for_each_possible_cpu(j) {
3b2d99429   Venkatesh Pallipadi   P-state software ...
642
643
  			if (i == j)
  				continue;
706546d02   Mike Travis   ACPI: change proc...
644
  			match_pr = per_cpu(processors, j);
3b2d99429   Venkatesh Pallipadi   P-state software ...
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
  			if (!match_pr)
  				continue;
  
  			match_pdomain = &(match_pr->performance->domain_info);
  			if (match_pdomain->domain != pdomain->domain)
  				continue;
  
  			/* Here i and j are in the same domain */
  
  			if (match_pdomain->num_processors != count_target) {
  				retval = -EINVAL;
  				goto err_ret;
  			}
  
  			if (pdomain->coord_type != match_pdomain->coord_type) {
  				retval = -EINVAL;
  				goto err_ret;
  			}
2fdf66b49   Rusty Russell   cpumask: convert ...
663
664
  			cpumask_set_cpu(j, covered_cpus);
  			cpumask_set_cpu(j, pr->performance->shared_cpu_map);
3b2d99429   Venkatesh Pallipadi   P-state software ...
665
  		}
193de0c79   KAMEZAWA Hiroyuki   ACPI: use for_eac...
666
  		for_each_possible_cpu(j) {
3b2d99429   Venkatesh Pallipadi   P-state software ...
667
668
  			if (i == j)
  				continue;
706546d02   Mike Travis   ACPI: change proc...
669
  			match_pr = per_cpu(processors, j);
3b2d99429   Venkatesh Pallipadi   P-state software ...
670
671
672
673
674
675
  			if (!match_pr)
  				continue;
  
  			match_pdomain = &(match_pr->performance->domain_info);
  			if (match_pdomain->domain != pdomain->domain)
  				continue;
c6237b210   Maximilian Luz   ACPI: Fix whitesp...
676
  			match_pr->performance->shared_type =
3b2d99429   Venkatesh Pallipadi   P-state software ...
677
  					pr->performance->shared_type;
2fdf66b49   Rusty Russell   cpumask: convert ...
678
679
  			cpumask_copy(match_pr->performance->shared_cpu_map,
  				     pr->performance->shared_cpu_map);
3b2d99429   Venkatesh Pallipadi   P-state software ...
680
681
682
683
  		}
  	}
  
  err_ret:
193de0c79   KAMEZAWA Hiroyuki   ACPI: use for_eac...
684
  	for_each_possible_cpu(i) {
706546d02   Mike Travis   ACPI: change proc...
685
  		pr = per_cpu(processors, i);
3b2d99429   Venkatesh Pallipadi   P-state software ...
686
687
688
689
690
  		if (!pr || !pr->performance)
  			continue;
  
  		/* Assume no coordination on any error parsing domain info */
  		if (retval) {
2fdf66b49   Rusty Russell   cpumask: convert ...
691
692
  			cpumask_clear(pr->performance->shared_cpu_map);
  			cpumask_set_cpu(i, pr->performance->shared_cpu_map);
3b2d99429   Venkatesh Pallipadi   P-state software ...
693
694
695
696
  			pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
  		}
  		pr->performance = NULL; /* Will be set for real in register */
  	}
e1eb47797   Stanislaw Gruszka   ACPI: Avoid wipin...
697
  err_out:
785fcccd6   Len Brown   ACPI: resolve mer...
698
  	mutex_unlock(&performance_mutex);
2fdf66b49   Rusty Russell   cpumask: convert ...
699
  	free_cpumask_var(covered_cpus);
9011bff4b   Len Brown   ACPI: delete newl...
700
  	return retval;
3b2d99429   Venkatesh Pallipadi   P-state software ...
701
702
  }
  EXPORT_SYMBOL(acpi_processor_preregister_performance);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
  int
4be44fcd3   Len Brown   [ACPI] Lindent al...
704
705
  acpi_processor_register_performance(struct acpi_processor_performance
  				    *performance, unsigned int cpu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
  {
  	struct acpi_processor *pr;
d15ce4127   Viresh Kumar   ACPI: cpufreq: Sw...
708
  	if (!acpi_processor_cpufreq_init)
d550d98d3   Patrick Mochel   ACPI: delete trac...
709
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710

65c19bbd2   Arjan van de Ven   sem2mutex: driver...
711
  	mutex_lock(&performance_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712

706546d02   Mike Travis   ACPI: change proc...
713
  	pr = per_cpu(processors, cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
  	if (!pr) {
65c19bbd2   Arjan van de Ven   sem2mutex: driver...
715
  		mutex_unlock(&performance_mutex);
d550d98d3   Patrick Mochel   ACPI: delete trac...
716
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
718
719
  	}
  
  	if (pr->performance) {
65c19bbd2   Arjan van de Ven   sem2mutex: driver...
720
  		mutex_unlock(&performance_mutex);
d550d98d3   Patrick Mochel   ACPI: delete trac...
721
  		return -EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
  	}
a913f5070   Andrew Morton   [PATCH] powernow-...
723
  	WARN_ON(!performance);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
725
726
727
  	pr->performance = performance;
  
  	if (acpi_processor_get_performance_info(pr)) {
  		pr->performance = NULL;
65c19bbd2   Arjan van de Ven   sem2mutex: driver...
728
  		mutex_unlock(&performance_mutex);
d550d98d3   Patrick Mochel   ACPI: delete trac...
729
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  	}
65c19bbd2   Arjan van de Ven   sem2mutex: driver...
731
  	mutex_unlock(&performance_mutex);
d550d98d3   Patrick Mochel   ACPI: delete trac...
732
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734

4be44fcd3   Len Brown   [ACPI] Lindent al...
735
  EXPORT_SYMBOL(acpi_processor_register_performance);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736

b2f8dc4ce   Rafael J. Wysocki   ACPI / processor:...
737
  void acpi_processor_unregister_performance(unsigned int cpu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
739
  {
  	struct acpi_processor *pr;
65c19bbd2   Arjan van de Ven   sem2mutex: driver...
740
  	mutex_lock(&performance_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741

706546d02   Mike Travis   ACPI: change proc...
742
  	pr = per_cpu(processors, cpu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
  	if (!pr) {
65c19bbd2   Arjan van de Ven   sem2mutex: driver...
744
  		mutex_unlock(&performance_mutex);
d550d98d3   Patrick Mochel   ACPI: delete trac...
745
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
  	}
a913f5070   Andrew Morton   [PATCH] powernow-...
747
748
  	if (pr->performance)
  		kfree(pr->performance->states);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
  	pr->performance = NULL;
65c19bbd2   Arjan van de Ven   sem2mutex: driver...
750
  	mutex_unlock(&performance_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751

d550d98d3   Patrick Mochel   ACPI: delete trac...
752
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
754

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
  EXPORT_SYMBOL(acpi_processor_unregister_performance);