blob: 0bf5ec2d5818eee53156f94b3ae5120964d11975 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * acpi_bus.c - ACPI Bus Driver ($Revision: 80 $)
3 *
4 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
5 *
6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 */
24
25#include <linux/module.h>
26#include <linux/init.h>
27#include <linux/ioport.h>
Randy Dunlapd568df82006-07-12 01:47:00 -040028#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/list.h>
30#include <linux/sched.h>
31#include <linux/pm.h>
32#include <linux/device.h>
33#include <linux/proc_fs.h>
Harvey Harrison6697c052008-02-09 23:24:08 +010034#include <linux/acpi.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090035#include <linux/slab.h>
Mark Brown31119432014-01-27 00:32:14 +000036#include <linux/regulator/machine.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#ifdef CONFIG_X86
38#include <asm/mpspec.h>
39#endif
Robert Hancock7752d5c2008-02-15 01:27:20 -080040#include <linux/pci.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <acpi/acpi_bus.h>
42#include <acpi/acpi_drivers.h>
Huang Yingeccddd32011-07-13 13:14:20 +080043#include <acpi/apei.h>
Len Browneb27cae2009-07-06 23:40:19 -040044#include <linux/dmi.h>
Rafael J. Wysockicd51e612011-02-11 00:04:52 +010045#include <linux/suspend.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
Bjorn Helgaase60cc7a2009-03-13 12:08:26 -060047#include "internal.h"
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#define _COMPONENT ACPI_BUS_COMPONENT
Len Brownf52fd662007-02-12 22:42:12 -050050ACPI_MODULE_NAME("bus");
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
Len Brown4be44fc2005-08-05 00:44:28 -040052struct acpi_device *acpi_root;
53struct proc_dir_entry *acpi_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054EXPORT_SYMBOL(acpi_root_dir);
55
56#define STRUCT_TO_INT(s) (*((int*)&s))
57
Zhao Yakui6415e122008-08-11 14:59:59 +080058
Lin Mingcce4f632010-05-12 09:26:48 +080059#ifdef CONFIG_X86
Lin Mingaa2110c2010-04-08 14:34:27 +080060static int set_copy_dsdt(const struct dmi_system_id *id)
61{
62 printk(KERN_NOTICE "%s detected - "
63 "force copy of DSDT to local memory\n", id->ident);
64 acpi_gbl_copy_dsdt_locally = 1;
65 return 0;
66}
67
68static struct dmi_system_id dsdt_dmi_table[] __initdata = {
69 /*
Len Brown100cf872010-09-28 22:57:02 -040070 * Invoke DSDT corruption work-around on all Toshiba Satellite.
Lin Mingaa2110c2010-04-08 14:34:27 +080071 * https://bugzilla.kernel.org/show_bug.cgi?id=14679
72 */
73 {
74 .callback = set_copy_dsdt,
Len Brown100cf872010-09-28 22:57:02 -040075 .ident = "TOSHIBA Satellite",
Lin Mingaa2110c2010-04-08 14:34:27 +080076 .matches = {
77 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
Len Brown100cf872010-09-28 22:57:02 -040078 DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"),
Lin Mingaa2110c2010-04-08 14:34:27 +080079 },
Lin Mingcce4f632010-05-12 09:26:48 +080080 },
81 {}
Lin Mingaa2110c2010-04-08 14:34:27 +080082};
Lin Mingcce4f632010-05-12 09:26:48 +080083#else
84static struct dmi_system_id dsdt_dmi_table[] __initdata = {
85 {}
86};
87#endif
Lin Mingaa2110c2010-04-08 14:34:27 +080088
Linus Torvalds1da177e2005-04-16 15:20:36 -070089/* --------------------------------------------------------------------------
90 Device Management
91 -------------------------------------------------------------------------- */
92
Len Brown4be44fc2005-08-05 00:44:28 -040093int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
Len Brown4be44fc2005-08-05 00:44:28 -040095 acpi_status status = AE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98 if (!device)
Patrick Mocheld550d982006-06-27 00:41:40 -040099 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
101 /* TBD: Support fixed-feature devices */
102
Len Brown4be44fc2005-08-05 00:44:28 -0400103 status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 if (ACPI_FAILURE(status) || !*device) {
Len Brown9805cb72006-07-25 13:30:57 -0400105 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
106 handle));
Patrick Mocheld550d982006-06-27 00:41:40 -0400107 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 }
109
Patrick Mocheld550d982006-06-27 00:41:40 -0400110 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111}
Len Brown4be44fc2005-08-05 00:44:28 -0400112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113EXPORT_SYMBOL(acpi_bus_get_device);
114
Bjorn Helgaas402ac532009-09-21 19:30:01 +0000115acpi_status acpi_bus_get_status_handle(acpi_handle handle,
116 unsigned long long *sta)
117{
118 acpi_status status;
119
120 status = acpi_evaluate_integer(handle, "_STA", NULL, sta);
121 if (ACPI_SUCCESS(status))
122 return AE_OK;
123
124 if (status == AE_NOT_FOUND) {
125 *sta = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
126 ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
127 return AE_OK;
128 }
129 return status;
130}
131
Len Brown4be44fc2005-08-05 00:44:28 -0400132int acpi_bus_get_status(struct acpi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133{
Bjorn Helgaas402ac532009-09-21 19:30:01 +0000134 acpi_status status;
135 unsigned long long sta;
Len Brown4be44fc2005-08-05 00:44:28 -0400136
Bjorn Helgaas402ac532009-09-21 19:30:01 +0000137 status = acpi_bus_get_status_handle(device->handle, &sta);
138 if (ACPI_FAILURE(status))
139 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
Bjorn Helgaas402ac532009-09-21 19:30:01 +0000141 STRUCT_TO_INT(device->status) = (int) sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143 if (device->status.functional && !device->status.present) {
Zhao Yakui39a0ad82008-08-11 13:40:22 +0800144 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: "
145 "functional but not present;\n",
146 device->pnp.bus_id,
147 (u32) STRUCT_TO_INT(device->status)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 }
149
Len Brown4be44fc2005-08-05 00:44:28 -0400150 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
151 device->pnp.bus_id,
152 (u32) STRUCT_TO_INT(device->status)));
Patrick Mocheld550d982006-06-27 00:41:40 -0400153 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154}
Len Brown4be44fc2005-08-05 00:44:28 -0400155EXPORT_SYMBOL(acpi_bus_get_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
Zhang Rui20733932008-01-17 15:51:21 +0800157void acpi_bus_private_data_handler(acpi_handle handle,
Bob Moore8e4319c2009-06-29 13:43:27 +0800158 void *context)
Zhang Rui20733932008-01-17 15:51:21 +0800159{
160 return;
161}
162EXPORT_SYMBOL(acpi_bus_private_data_handler);
163
164int acpi_bus_get_private_data(acpi_handle handle, void **data)
165{
166 acpi_status status = AE_OK;
167
168 if (!*data)
169 return -EINVAL;
170
171 status = acpi_get_data(handle, acpi_bus_private_data_handler, data);
172 if (ACPI_FAILURE(status) || !*data) {
173 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
174 handle));
175 return -ENODEV;
176 }
177
178 return 0;
179}
180EXPORT_SYMBOL(acpi_bus_get_private_data);
181
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182/* --------------------------------------------------------------------------
183 Power Management
184 -------------------------------------------------------------------------- */
185
Rafael J. Wysocki5e6d4fe2010-11-25 00:07:56 +0100186static int __acpi_bus_get_power(struct acpi_device *device, int *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187{
Len Brown4be44fc2005-08-05 00:44:28 -0400188 int result = 0;
189 acpi_status status = 0;
Matthew Wilcox27663c52008-10-10 02:22:59 -0400190 unsigned long long psc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
Rafael J. Wysocki5e6d4fe2010-11-25 00:07:56 +0100192 if (!device || !state)
193 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195 *state = ACPI_STATE_UNKNOWN;
196
Rafael J. Wysocki5e6d4fe2010-11-25 00:07:56 +0100197 if (device->flags.power_manageable) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 /*
Alexey Starikovskiyaafbcd12007-02-10 01:32:16 -0500199 * Get the device's power state either directly (via _PSC) or
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 * indirectly (via power resources).
201 */
Zhang Rui0c99c522009-12-17 16:02:08 +0800202 if (device->power.flags.power_resources) {
Rafael J. Wysocki5e6d4fe2010-11-25 00:07:56 +0100203 result = acpi_power_get_inferred_state(device, state);
Zhang Rui0c99c522009-12-17 16:02:08 +0800204 if (result)
205 return result;
206 } else if (device->power.flags.explicit_get) {
Len Brown4be44fc2005-08-05 00:44:28 -0400207 status = acpi_evaluate_integer(device->handle, "_PSC",
208 NULL, &psc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 if (ACPI_FAILURE(status))
Patrick Mocheld550d982006-06-27 00:41:40 -0400210 return -ENODEV;
Rafael J. Wysocki5e6d4fe2010-11-25 00:07:56 +0100211 *state = (int)psc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 }
Rafael J. Wysocki5e6d4fe2010-11-25 00:07:56 +0100213 } else {
214 /* TBD: Non-recursive algorithm for walking up hierarchy. */
215 *state = device->parent ?
216 device->parent->power.state : ACPI_STATE_D0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 }
218
219 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n",
Rafael J. Wysocki5e6d4fe2010-11-25 00:07:56 +0100220 device->pnp.bus_id, *state));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
Patrick Mocheld550d982006-06-27 00:41:40 -0400222 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223}
Len Brown4be44fc2005-08-05 00:44:28 -0400224
Rafael J. Wysocki5e6d4fe2010-11-25 00:07:56 +0100225
Rafael J. Wysocki25eed402010-11-25 00:09:15 +0100226static int __acpi_bus_set_power(struct acpi_device *device, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227{
Len Brown4be44fc2005-08-05 00:44:28 -0400228 int result = 0;
229 acpi_status status = AE_OK;
Len Brown4be44fc2005-08-05 00:44:28 -0400230 char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
Lin Ming28c21032011-05-04 22:56:43 +0800232 if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
Patrick Mocheld550d982006-06-27 00:41:40 -0400233 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235 /* Make sure this is a valid target state */
236
Rafael J. Wysocki488a76c2010-11-25 00:11:24 +0100237 if (state == device->power.state) {
Konstantin Karasyovb1028c52007-02-16 02:23:07 -0500238 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
239 state));
240 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 }
Konstantin Karasyovb1028c52007-02-16 02:23:07 -0500242
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 if (!device->power.states[state].flags.valid) {
Len Browncece9292006-06-26 23:04:31 -0400244 printk(KERN_WARNING PREFIX "Device does not support D%d\n", state);
Patrick Mocheld550d982006-06-27 00:41:40 -0400245 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 }
247 if (device->parent && (state < device->parent->power.state)) {
Len Browncece9292006-06-26 23:04:31 -0400248 printk(KERN_WARNING PREFIX
Thomas Renningera6fc6722006-06-26 23:58:43 -0400249 "Cannot set device to a higher-powered"
Len Browncece9292006-06-26 23:04:31 -0400250 " state than parent\n");
Patrick Mocheld550d982006-06-27 00:41:40 -0400251 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 }
253
Rafael J. Wysocki5c7dd712012-05-18 00:39:35 +0200254 /* For D3cold we should execute _PS3, not _PS4. */
255 if (state == ACPI_STATE_D3_COLD)
256 object_name[3] = '3';
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 /*
259 * Transition Power
260 * ----------------
261 * On transitions to a high-powered state we first apply power (via
262 * power resources) then evalute _PSx. Conversly for transitions to
263 * a lower-powered state.
David Shaohua Lib9131002005-03-19 00:16:18 -0500264 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 if (state < device->power.state) {
266 if (device->power.flags.power_resources) {
267 result = acpi_power_transition(device, state);
268 if (result)
269 goto end;
270 }
271 if (device->power.states[state].flags.explicit_set) {
Len Brown4be44fc2005-08-05 00:44:28 -0400272 status = acpi_evaluate_object(device->handle,
273 object_name, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 if (ACPI_FAILURE(status)) {
275 result = -ENODEV;
276 goto end;
277 }
278 }
Len Brown4be44fc2005-08-05 00:44:28 -0400279 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 if (device->power.states[state].flags.explicit_set) {
Len Brown4be44fc2005-08-05 00:44:28 -0400281 status = acpi_evaluate_object(device->handle,
282 object_name, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 if (ACPI_FAILURE(status)) {
284 result = -ENODEV;
285 goto end;
286 }
287 }
288 if (device->power.flags.power_resources) {
289 result = acpi_power_transition(device, state);
290 if (result)
291 goto end;
292 }
293 }
294
Len Brown4be44fc2005-08-05 00:44:28 -0400295 end:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 if (result)
Len Browncece9292006-06-26 23:04:31 -0400297 printk(KERN_WARNING PREFIX
Len Brownddc50b62009-05-08 00:07:30 -0400298 "Device [%s] failed to transition to D%d\n",
Len Browncece9292006-06-26 23:04:31 -0400299 device->pnp.bus_id, state);
Shaohua Li5e321322007-10-11 23:53:58 +0200300 else {
301 device->power.state = state;
Len Brown4be44fc2005-08-05 00:44:28 -0400302 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
303 "Device [%s] transitioned to D%d\n",
304 device->pnp.bus_id, state));
Shaohua Li5e321322007-10-11 23:53:58 +0200305 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Patrick Mocheld550d982006-06-27 00:41:40 -0400307 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308}
Len Brown4be44fc2005-08-05 00:44:28 -0400309
Rafael J. Wysocki25eed402010-11-25 00:09:15 +0100310
311int acpi_bus_set_power(acpi_handle handle, int state)
312{
313 struct acpi_device *device;
314 int result;
315
316 result = acpi_bus_get_device(handle, &device);
317 if (result)
318 return result;
319
320 if (!device->flags.power_manageable) {
321 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
322 "Device [%s] is not power manageable\n",
323 dev_name(&device->dev)));
324 return -ENODEV;
325 }
326
Rafael J. Wysocki25eed402010-11-25 00:09:15 +0100327 return __acpi_bus_set_power(device, state);
328}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329EXPORT_SYMBOL(acpi_bus_set_power);
330
Rafael J. Wysockiade3e7f2010-11-25 00:08:36 +0100331
332int acpi_bus_init_power(struct acpi_device *device)
333{
334 int state;
335 int result;
336
337 if (!device)
338 return -EINVAL;
339
340 device->power.state = ACPI_STATE_UNKNOWN;
341
342 result = __acpi_bus_get_power(device, &state);
343 if (result)
344 return result;
345
346 if (device->power.flags.power_resources)
347 result = acpi_power_on_resources(device, state);
348
349 if (!result)
350 device->power.state = state;
351
352 return result;
353}
354
355
Rafael J. Wysocki25eed402010-11-25 00:09:15 +0100356int acpi_bus_update_power(acpi_handle handle, int *state_p)
357{
358 struct acpi_device *device;
359 int state;
360 int result;
361
362 result = acpi_bus_get_device(handle, &device);
363 if (result)
364 return result;
365
366 result = __acpi_bus_get_power(device, &state);
367 if (result)
368 return result;
369
370 result = __acpi_bus_set_power(device, state);
371 if (!result && state_p)
372 *state_p = state;
373
374 return result;
375}
376EXPORT_SYMBOL_GPL(acpi_bus_update_power);
377
378
Rafael J. Wysocki3737b2b2008-07-07 03:30:55 +0200379bool acpi_bus_power_manageable(acpi_handle handle)
380{
381 struct acpi_device *device;
382 int result;
383
384 result = acpi_bus_get_device(handle, &device);
385 return result ? false : device->flags.power_manageable;
386}
387
388EXPORT_SYMBOL(acpi_bus_power_manageable);
389
Rafael J. Wysockieb9d0fe2008-07-07 03:34:48 +0200390bool acpi_bus_can_wakeup(acpi_handle handle)
391{
392 struct acpi_device *device;
393 int result;
394
395 result = acpi_bus_get_device(handle, &device);
396 return result ? false : device->wakeup.flags.valid;
397}
398
399EXPORT_SYMBOL(acpi_bus_can_wakeup);
400
Shaohua Li70023de2009-10-29 11:04:28 +0800401static void acpi_print_osc_error(acpi_handle handle,
402 struct acpi_osc_context *context, char *error)
403{
404 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER};
405 int i;
406
407 if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer)))
408 printk(KERN_DEBUG "%s\n", error);
409 else {
410 printk(KERN_DEBUG "%s:%s\n", (char *)buffer.pointer, error);
411 kfree(buffer.pointer);
412 }
413 printk(KERN_DEBUG"_OSC request data:");
414 for (i = 0; i < context->cap.length; i += sizeof(u32))
415 printk("%x ", *((u32 *)(context->cap.pointer + i)));
416 printk("\n");
417}
418
Shaohua Li70023de2009-10-29 11:04:28 +0800419static acpi_status acpi_str_to_uuid(char *str, u8 *uuid)
420{
421 int i;
422 static int opc_map_to_uuid[16] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21,
423 24, 26, 28, 30, 32, 34};
424
425 if (strlen(str) != 36)
426 return AE_BAD_PARAMETER;
427 for (i = 0; i < 36; i++) {
428 if (i == 8 || i == 13 || i == 18 || i == 23) {
429 if (str[i] != '-')
430 return AE_BAD_PARAMETER;
431 } else if (!isxdigit(str[i]))
432 return AE_BAD_PARAMETER;
433 }
434 for (i = 0; i < 16; i++) {
Andy Shevchenko965fd9e2010-05-24 14:33:28 -0700435 uuid[i] = hex_to_bin(str[opc_map_to_uuid[i]]) << 4;
436 uuid[i] |= hex_to_bin(str[opc_map_to_uuid[i] + 1]);
Shaohua Li70023de2009-10-29 11:04:28 +0800437 }
438 return AE_OK;
439}
440
441acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
442{
443 acpi_status status;
444 struct acpi_object_list input;
445 union acpi_object in_params[4];
446 union acpi_object *out_obj;
447 u8 uuid[16];
448 u32 errors;
Shaohua Li9dc130f2009-12-23 17:04:11 +0800449 struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
Shaohua Li70023de2009-10-29 11:04:28 +0800450
451 if (!context)
452 return AE_ERROR;
453 if (ACPI_FAILURE(acpi_str_to_uuid(context->uuid_str, uuid)))
454 return AE_ERROR;
455 context->ret.length = ACPI_ALLOCATE_BUFFER;
456 context->ret.pointer = NULL;
457
458 /* Setting up input parameters */
459 input.count = 4;
460 input.pointer = in_params;
461 in_params[0].type = ACPI_TYPE_BUFFER;
462 in_params[0].buffer.length = 16;
463 in_params[0].buffer.pointer = uuid;
464 in_params[1].type = ACPI_TYPE_INTEGER;
465 in_params[1].integer.value = context->rev;
466 in_params[2].type = ACPI_TYPE_INTEGER;
467 in_params[2].integer.value = context->cap.length/sizeof(u32);
468 in_params[3].type = ACPI_TYPE_BUFFER;
469 in_params[3].buffer.length = context->cap.length;
470 in_params[3].buffer.pointer = context->cap.pointer;
471
Shaohua Li9dc130f2009-12-23 17:04:11 +0800472 status = acpi_evaluate_object(handle, "_OSC", &input, &output);
Shaohua Li70023de2009-10-29 11:04:28 +0800473 if (ACPI_FAILURE(status))
474 return status;
475
Shaohua Li9dc130f2009-12-23 17:04:11 +0800476 if (!output.length)
Shaohua Li70023de2009-10-29 11:04:28 +0800477 return AE_NULL_OBJECT;
478
Shaohua Li9dc130f2009-12-23 17:04:11 +0800479 out_obj = output.pointer;
480 if (out_obj->type != ACPI_TYPE_BUFFER
481 || out_obj->buffer.length != context->cap.length) {
Shaohua Li70023de2009-10-29 11:04:28 +0800482 acpi_print_osc_error(handle, context,
483 "_OSC evaluation returned wrong type");
484 status = AE_TYPE;
485 goto out_kfree;
486 }
487 /* Need to ignore the bit0 in result code */
488 errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
489 if (errors) {
490 if (errors & OSC_REQUEST_ERROR)
491 acpi_print_osc_error(handle, context,
492 "_OSC request failed");
493 if (errors & OSC_INVALID_UUID_ERROR)
494 acpi_print_osc_error(handle, context,
495 "_OSC invalid UUID");
496 if (errors & OSC_INVALID_REVISION_ERROR)
497 acpi_print_osc_error(handle, context,
498 "_OSC invalid revision");
499 if (errors & OSC_CAPABILITIES_MASK_ERROR) {
500 if (((u32 *)context->cap.pointer)[OSC_QUERY_TYPE]
501 & OSC_QUERY_ENABLE)
502 goto out_success;
503 status = AE_SUPPORT;
504 goto out_kfree;
505 }
506 status = AE_ERROR;
507 goto out_kfree;
508 }
509out_success:
Shaohua Li9dc130f2009-12-23 17:04:11 +0800510 context->ret.length = out_obj->buffer.length;
511 context->ret.pointer = kmalloc(context->ret.length, GFP_KERNEL);
512 if (!context->ret.pointer) {
513 status = AE_NO_MEMORY;
514 goto out_kfree;
515 }
516 memcpy(context->ret.pointer, out_obj->buffer.pointer,
517 context->ret.length);
518 status = AE_OK;
Shaohua Li70023de2009-10-29 11:04:28 +0800519
520out_kfree:
Shaohua Li9dc130f2009-12-23 17:04:11 +0800521 kfree(output.pointer);
522 if (status != AE_OK)
523 context->ret.pointer = NULL;
Shaohua Li70023de2009-10-29 11:04:28 +0800524 return status;
525}
526EXPORT_SYMBOL(acpi_run_osc);
527
Huang Yingeccddd32011-07-13 13:14:20 +0800528bool osc_sb_apei_support_acked;
Shaohua Li3563ff92009-10-29 11:05:05 +0800529static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48";
530static void acpi_bus_osc_support(void)
531{
532 u32 capbuf[2];
533 struct acpi_osc_context context = {
534 .uuid_str = sb_uuid_str,
535 .rev = 1,
536 .cap.length = 8,
537 .cap.pointer = capbuf,
538 };
539 acpi_handle handle;
540
541 capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
542 capbuf[OSC_SUPPORT_TYPE] = OSC_SB_PR3_SUPPORT; /* _PR3 is in use */
Zhao Yakui6a4e2b72010-01-08 21:29:58 +0800543#if defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR) ||\
544 defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR_MODULE)
Shaohua Li3563ff92009-10-29 11:05:05 +0800545 capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PAD_SUPPORT;
546#endif
Zhao Yakui6a4e2b72010-01-08 21:29:58 +0800547
548#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
549 capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PPC_OST_SUPPORT;
550#endif
Huang Yingeccddd32011-07-13 13:14:20 +0800551
Huang Yingeccddd32011-07-13 13:14:20 +0800552 if (!ghes_disable)
553 capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_APEI_SUPPORT;
Shaohua Li3563ff92009-10-29 11:05:05 +0800554 if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)))
555 return;
Huang Yingeccddd32011-07-13 13:14:20 +0800556 if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) {
557 u32 *capbuf_ret = context.ret.pointer;
558 if (context.ret.length > OSC_SUPPORT_TYPE)
559 osc_sb_apei_support_acked =
560 capbuf_ret[OSC_SUPPORT_TYPE] & OSC_SB_APEI_SUPPORT;
Shaohua Li3563ff92009-10-29 11:05:05 +0800561 kfree(context.ret.pointer);
Huang Yingeccddd32011-07-13 13:14:20 +0800562 }
563 /* do we need to check other returned cap? Sounds no */
Shaohua Li3563ff92009-10-29 11:05:05 +0800564}
565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566/* --------------------------------------------------------------------------
567 Event Management
568 -------------------------------------------------------------------------- */
569
Len Brown14e04fb2007-08-23 15:20:26 -0400570#ifdef CONFIG_ACPI_PROC_EVENT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571static DEFINE_SPINLOCK(acpi_bus_event_lock);
572
573LIST_HEAD(acpi_bus_event_list);
574DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue);
575
Len Brown4be44fc2005-08-05 00:44:28 -0400576extern int event_is_open;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
Alexey Starikovskiy8db85d42007-09-26 19:43:16 +0400578int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579{
Alexey Starikovskiy8db85d42007-09-26 19:43:16 +0400580 struct acpi_bus_event *event;
Len Brown4be44fc2005-08-05 00:44:28 -0400581 unsigned long flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 /* drop event on the floor if no one's listening */
584 if (!event_is_open)
Patrick Mocheld550d982006-06-27 00:41:40 -0400585 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Dan Carpenter5cc4a0f2010-04-27 00:23:37 +0200587 event = kzalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 if (!event)
Patrick Mocheld550d982006-06-27 00:41:40 -0400589 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Alexey Starikovskiy8db85d42007-09-26 19:43:16 +0400591 strcpy(event->device_class, device_class);
592 strcpy(event->bus_id, bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 event->type = type;
594 event->data = data;
595
596 spin_lock_irqsave(&acpi_bus_event_lock, flags);
597 list_add_tail(&event->node, &acpi_bus_event_list);
598 spin_unlock_irqrestore(&acpi_bus_event_lock, flags);
599
600 wake_up_interruptible(&acpi_bus_event_queue);
601
Patrick Mocheld550d982006-06-27 00:41:40 -0400602 return 0;
Alexey Starikovskiy8db85d42007-09-26 19:43:16 +0400603
604}
605
606EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4);
607
608int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
609{
610 if (!device)
611 return -EINVAL;
612 return acpi_bus_generate_proc_event4(device->pnp.device_class,
613 device->pnp.bus_id, type, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614}
Len Brown4be44fc2005-08-05 00:44:28 -0400615
Len Brown14e04fb2007-08-23 15:20:26 -0400616EXPORT_SYMBOL(acpi_bus_generate_proc_event);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Len Brown4be44fc2005-08-05 00:44:28 -0400618int acpi_bus_receive_event(struct acpi_bus_event *event)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619{
Len Brown4be44fc2005-08-05 00:44:28 -0400620 unsigned long flags = 0;
621 struct acpi_bus_event *entry = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
623 DECLARE_WAITQUEUE(wait, current);
624
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626 if (!event)
Patrick Mocheld550d982006-06-27 00:41:40 -0400627 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629 if (list_empty(&acpi_bus_event_list)) {
630
631 set_current_state(TASK_INTERRUPTIBLE);
632 add_wait_queue(&acpi_bus_event_queue, &wait);
633
634 if (list_empty(&acpi_bus_event_list))
635 schedule();
636
637 remove_wait_queue(&acpi_bus_event_queue, &wait);
638 set_current_state(TASK_RUNNING);
639
640 if (signal_pending(current))
Patrick Mocheld550d982006-06-27 00:41:40 -0400641 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 }
643
644 spin_lock_irqsave(&acpi_bus_event_lock, flags);
Chuck Ebbertf0a37e02008-04-15 14:34:47 -0700645 if (!list_empty(&acpi_bus_event_list)) {
646 entry = list_entry(acpi_bus_event_list.next,
647 struct acpi_bus_event, node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 list_del(&entry->node);
Chuck Ebbertf0a37e02008-04-15 14:34:47 -0700649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 spin_unlock_irqrestore(&acpi_bus_event_lock, flags);
651
652 if (!entry)
Patrick Mocheld550d982006-06-27 00:41:40 -0400653 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655 memcpy(event, entry, sizeof(struct acpi_bus_event));
656
657 kfree(entry);
658
Patrick Mocheld550d982006-06-27 00:41:40 -0400659 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
Len Brown14e04fb2007-08-23 15:20:26 -0400662#endif /* CONFIG_ACPI_PROC_EVENT */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664/* --------------------------------------------------------------------------
665 Notification Handling
666 -------------------------------------------------------------------------- */
667
Bjorn Helgaasff754e22009-05-22 11:43:56 -0600668static void acpi_bus_check_device(acpi_handle handle)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669{
Bjorn Helgaasff754e22009-05-22 11:43:56 -0600670 struct acpi_device *device;
Bjorn Helgaascdd5b8c2009-05-22 11:43:51 -0600671 acpi_status status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 struct acpi_device_status old_status;
673
Bjorn Helgaasff754e22009-05-22 11:43:56 -0600674 if (acpi_bus_get_device(handle, &device))
675 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 if (!device)
Bjorn Helgaascdd5b8c2009-05-22 11:43:51 -0600677 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 old_status = device->status;
680
681 /*
682 * Make sure this device's parent is present before we go about
683 * messing with the device.
684 */
685 if (device->parent && !device->parent->status.present) {
686 device->status = device->parent->status;
Bjorn Helgaascdd5b8c2009-05-22 11:43:51 -0600687 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 }
689
690 status = acpi_bus_get_status(device);
691 if (ACPI_FAILURE(status))
Bjorn Helgaascdd5b8c2009-05-22 11:43:51 -0600692 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694 if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status))
Bjorn Helgaascdd5b8c2009-05-22 11:43:51 -0600695 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 /*
698 * Device Insertion/Removal
699 */
700 if ((device->status.present) && !(old_status.present)) {
701 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device insertion detected\n"));
702 /* TBD: Handle device insertion */
Len Brown4be44fc2005-08-05 00:44:28 -0400703 } else if (!(device->status.present) && (old_status.present)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n"));
705 /* TBD: Handle device removal */
706 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707}
708
Bjorn Helgaasff754e22009-05-22 11:43:56 -0600709static void acpi_bus_check_scope(acpi_handle handle)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 /* Status Change? */
Bjorn Helgaasff754e22009-05-22 11:43:56 -0600712 acpi_bus_check_device(handle);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 /*
715 * TBD: Enumerate child devices within this device's scope and
716 * run acpi_bus_check_device()'s on them.
717 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718}
719
Shaohua Li6bd00a62008-08-28 10:04:29 +0800720static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
721int register_acpi_bus_notifier(struct notifier_block *nb)
722{
723 return blocking_notifier_chain_register(&acpi_bus_notify_list, nb);
724}
725EXPORT_SYMBOL_GPL(register_acpi_bus_notifier);
726
727void unregister_acpi_bus_notifier(struct notifier_block *nb)
728{
729 blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb);
730}
731EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);
732
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733/**
734 * acpi_bus_notify
735 * ---------------
736 * Callback for all 'system-level' device notifications (values 0x00-0x7F).
737 */
Len Brown4be44fc2005-08-05 00:44:28 -0400738static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739{
Len Brown4be44fc2005-08-05 00:44:28 -0400740 struct acpi_device *device = NULL;
Bjorn Helgaas6d278132009-04-30 09:35:37 -0600741 struct acpi_driver *driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
Bjorn Helgaas02c37bd2009-05-22 11:43:41 -0600743 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
744 type, handle));
745
Shaohua Li6bd00a62008-08-28 10:04:29 +0800746 blocking_notifier_call_chain(&acpi_bus_notify_list,
747 type, (void *)handle);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 switch (type) {
750
751 case ACPI_NOTIFY_BUS_CHECK:
Bjorn Helgaasff754e22009-05-22 11:43:56 -0600752 acpi_bus_check_scope(handle);
Alexey Starikovskiyaafbcd12007-02-10 01:32:16 -0500753 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 * TBD: We'll need to outsource certain events to non-ACPI
Len Brown4be44fc2005-08-05 00:44:28 -0400755 * drivers via the device manager (device.c).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 */
757 break;
758
759 case ACPI_NOTIFY_DEVICE_CHECK:
Bjorn Helgaasff754e22009-05-22 11:43:56 -0600760 acpi_bus_check_device(handle);
Alexey Starikovskiyaafbcd12007-02-10 01:32:16 -0500761 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 * TBD: We'll need to outsource certain events to non-ACPI
Len Brown4be44fc2005-08-05 00:44:28 -0400763 * drivers via the device manager (device.c).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 */
765 break;
766
767 case ACPI_NOTIFY_DEVICE_WAKE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 /* TBD */
769 break;
770
771 case ACPI_NOTIFY_EJECT_REQUEST:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 /* TBD */
773 break;
774
775 case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 /* TBD: Exactly what does 'light' mean? */
777 break;
778
779 case ACPI_NOTIFY_FREQUENCY_MISMATCH:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 /* TBD */
781 break;
782
783 case ACPI_NOTIFY_BUS_MODE_MISMATCH:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 /* TBD */
785 break;
786
787 case ACPI_NOTIFY_POWER_FAULT:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 /* TBD */
789 break;
790
791 default:
Len Brown4be44fc2005-08-05 00:44:28 -0400792 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
793 "Received unknown/unsupported notification [%08x]\n",
794 type));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 break;
796 }
797
Bjorn Helgaasff754e22009-05-22 11:43:56 -0600798 acpi_bus_get_device(handle, &device);
799 if (device) {
800 driver = device->driver;
801 if (driver && driver->ops.notify &&
802 (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
803 driver->ops.notify(device, type);
804 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805}
806
807/* --------------------------------------------------------------------------
808 Initialization/Cleanup
809 -------------------------------------------------------------------------- */
810
Len Brown4be44fc2005-08-05 00:44:28 -0400811static int __init acpi_bus_init_irq(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812{
Len Brown4be44fc2005-08-05 00:44:28 -0400813 acpi_status status = AE_OK;
814 union acpi_object arg = { ACPI_TYPE_INTEGER };
815 struct acpi_object_list arg_list = { 1, &arg };
816 char *message = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
Alexey Starikovskiyaafbcd12007-02-10 01:32:16 -0500819 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 * Let the system know what interrupt model we are using by
821 * evaluating the \_PIC object, if exists.
822 */
823
824 switch (acpi_irq_model) {
825 case ACPI_IRQ_MODEL_PIC:
826 message = "PIC";
827 break;
828 case ACPI_IRQ_MODEL_IOAPIC:
829 message = "IOAPIC";
830 break;
831 case ACPI_IRQ_MODEL_IOSAPIC:
832 message = "IOSAPIC";
833 break;
John Keller3948ec92006-12-22 11:50:04 -0600834 case ACPI_IRQ_MODEL_PLATFORM:
835 message = "platform specific model";
836 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 default:
838 printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n");
Patrick Mocheld550d982006-06-27 00:41:40 -0400839 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 }
841
842 printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message);
843
844 arg.integer.value = acpi_irq_model;
845
846 status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL);
847 if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
Thomas Renningera6fc6722006-06-26 23:58:43 -0400848 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
Patrick Mocheld550d982006-06-27 00:41:40 -0400849 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 }
851
Patrick Mocheld550d982006-06-27 00:41:40 -0400852 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853}
854
Bob Moore67a119f2008-06-10 13:42:13 +0800855u8 acpi_gbl_permanent_mmap;
Alexey Starikovskiyad718602007-02-02 19:48:19 +0300856
857
Len Brown4be44fc2005-08-05 00:44:28 -0400858void __init acpi_early_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859{
Len Brown4be44fc2005-08-05 00:44:28 -0400860 acpi_status status = AE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861
862 if (acpi_disabled)
Patrick Mocheld550d982006-06-27 00:41:40 -0400863 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864
Bob Moore61686122006-03-17 16:44:00 -0500865 printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION);
866
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 /* enable workarounds, unless strict ACPI spec. compliance */
868 if (!acpi_strict)
869 acpi_gbl_enable_interpreter_slack = TRUE;
870
Alexey Starikovskiyad718602007-02-02 19:48:19 +0300871 acpi_gbl_permanent_mmap = 1;
872
Lin Mingaa2110c2010-04-08 14:34:27 +0800873 /*
874 * If the machine falls into the DMI check table,
875 * DSDT will be copied to memory
876 */
877 dmi_check_system(dsdt_dmi_table);
878
Alexey Starikovskiyad718602007-02-02 19:48:19 +0300879 status = acpi_reallocate_root_table();
880 if (ACPI_FAILURE(status)) {
881 printk(KERN_ERR PREFIX
882 "Unable to reallocate ACPI tables\n");
883 goto error0;
884 }
885
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 status = acpi_initialize_subsystem();
887 if (ACPI_FAILURE(status)) {
Len Brown4be44fc2005-08-05 00:44:28 -0400888 printk(KERN_ERR PREFIX
889 "Unable to initialize the ACPI Interpreter\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 goto error0;
891 }
892
893 status = acpi_load_tables();
894 if (ACPI_FAILURE(status)) {
Len Brown4be44fc2005-08-05 00:44:28 -0400895 printk(KERN_ERR PREFIX
896 "Unable to load the System Description Tables\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 goto error0;
898 }
899
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900#ifdef CONFIG_X86
901 if (!acpi_ioapic) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 /* compatible (0) means level (3) */
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300903 if (!(acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)) {
904 acpi_sci_flags &= ~ACPI_MADT_TRIGGER_MASK;
905 acpi_sci_flags |= ACPI_MADT_TRIGGER_LEVEL;
906 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 /* Set PIC-mode SCI trigger type */
Alexey Starikovskiycee324b2007-02-02 19:48:22 +0300908 acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt,
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300909 (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 /*
Alexey Starikovskiycee324b2007-02-02 19:48:22 +0300912 * now that acpi_gbl_FADT is initialized,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 * update it with result from INT_SRC_OVR parsing
914 */
Alexey Starikovskiycee324b2007-02-02 19:48:22 +0300915 acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 }
917#endif
918
Rafael J. Wysocki4505a202011-11-06 14:20:42 +0100919 status = acpi_enable_subsystem(~ACPI_NO_ACPI_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 if (ACPI_FAILURE(status)) {
921 printk(KERN_ERR PREFIX "Unable to enable ACPI\n");
922 goto error0;
923 }
924
Mark Brown31119432014-01-27 00:32:14 +0000925 /*
926 * If the system is using ACPI then we can be reasonably
927 * confident that any regulators are managed by the firmware
928 * so tell the regulator core it has everything it needs to
929 * know.
930 */
931 regulator_has_full_constraints();
932
Patrick Mocheld550d982006-06-27 00:41:40 -0400933 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Len Brown4be44fc2005-08-05 00:44:28 -0400935 error0:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 disable_acpi();
Patrick Mocheld550d982006-06-27 00:41:40 -0400937 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938}
939
Len Brown4be44fc2005-08-05 00:44:28 -0400940static int __init acpi_bus_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941{
Len Brown4be44fc2005-08-05 00:44:28 -0400942 int result = 0;
943 acpi_status status = AE_OK;
944 extern acpi_status acpi_os_initialize1(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
Jiri Slaby176f9c12009-03-04 11:55:27 -0800946 acpi_os_initialize1();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Rafael J. Wysocki4505a202011-11-06 14:20:42 +0100948 status = acpi_enable_subsystem(ACPI_NO_ACPI_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 if (ACPI_FAILURE(status)) {
Len Brown4be44fc2005-08-05 00:44:28 -0400950 printk(KERN_ERR PREFIX
951 "Unable to start the ACPI Interpreter\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 goto error1;
953 }
954
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 /*
956 * ACPI 2.0 requires the EC driver to be loaded and work before
957 * the EC device is found in the namespace (i.e. before acpi_initialize_objects()
958 * is called).
959 *
Alexey Starikovskiyaafbcd12007-02-10 01:32:16 -0500960 * This is accomplished by looking for the ECDT table, and getting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 * the EC parameters out of that.
962 */
963 status = acpi_ec_ecdt_probe();
964 /* Ignore result. Not having an ECDT is not fatal. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
966 status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION);
967 if (ACPI_FAILURE(status)) {
968 printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n");
969 goto error1;
970 }
971
Zhang Ruib1d248d2010-10-26 10:06:54 +0800972 /*
Lin Ming2006e6f2012-07-16 16:30:21 +0800973 * _OSC method may exist in module level code,
974 * so it must be run after ACPI_FULL_INITIALIZATION
975 */
976 acpi_bus_osc_support();
977
978 /*
Zhang Ruib1d248d2010-10-26 10:06:54 +0800979 * _PDC control method may load dynamic SSDT tables,
980 * and we need to install the table handler before that.
981 */
982 acpi_sysfs_init();
983
Alex Chiang78f16992009-12-20 12:19:09 -0700984 acpi_early_processor_set_pdc();
985
Zhao Yakui455c8792008-10-06 10:31:36 +0800986 /*
987 * Maybe EC region is required at bus_scan/acpi_get_devices. So it
988 * is necessary to enable it as early as possible.
989 */
990 acpi_boot_ec_enable();
991
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 printk(KERN_INFO PREFIX "Interpreter enabled\n");
993
Alexey Starikovskiyaafbcd12007-02-10 01:32:16 -0500994 /* Initialize sleep structures */
995 acpi_sleep_init();
996
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 /*
998 * Get the system interrupt model and evaluate \_PIC.
999 */
1000 result = acpi_bus_init_irq();
1001 if (result)
1002 goto error1;
1003
1004 /*
1005 * Register the for all standard device notifications.
1006 */
Len Brown4be44fc2005-08-05 00:44:28 -04001007 status =
1008 acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY,
1009 &acpi_bus_notify, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 if (ACPI_FAILURE(status)) {
Len Brown4be44fc2005-08-05 00:44:28 -04001011 printk(KERN_ERR PREFIX
1012 "Unable to register for device notifications\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 goto error1;
1014 }
1015
1016 /*
1017 * Create the top ACPI proc directory
1018 */
1019 acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL);
1020
Patrick Mocheld550d982006-06-27 00:41:40 -04001021 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
1023 /* Mimic structured exception handling */
Len Brown4be44fc2005-08-05 00:44:28 -04001024 error1:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 acpi_terminate();
Patrick Mocheld550d982006-06-27 00:41:40 -04001026 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027}
1028
Greg Kroah-Hartman99e0d2f2007-11-02 16:19:59 -07001029struct kobject *acpi_kobj;
Matthew Garrettf2d47532012-01-31 13:19:19 -05001030EXPORT_SYMBOL_GPL(acpi_kobj);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
Len Brown4be44fc2005-08-05 00:44:28 -04001032static int __init acpi_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033{
Rafael J. Wysocki6831c6e2011-02-15 21:22:24 +01001034 int result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 if (acpi_disabled) {
1037 printk(KERN_INFO PREFIX "Interpreter disabled.\n");
Patrick Mocheld550d982006-06-27 00:41:40 -04001038 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 }
1040
Greg Kroah-Hartmanf62ed9e2007-11-05 13:16:15 -08001041 acpi_kobj = kobject_create_and_add("acpi", firmware_kobj);
Greg Kroah-Hartman99e0d2f2007-11-02 16:19:59 -07001042 if (!acpi_kobj) {
Harvey Harrison96b2dd12008-03-05 18:24:51 -08001043 printk(KERN_WARNING "%s: kset create error\n", __func__);
Greg Kroah-Hartman99e0d2f2007-11-02 16:19:59 -07001044 acpi_kobj = NULL;
1045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
Bjorn Helgaas0e465172009-03-24 16:50:09 -06001047 init_acpi_device_notify();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 result = acpi_bus_init();
Rafael J. Wysocki6831c6e2011-02-15 21:22:24 +01001049 if (result) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 disable_acpi();
Bjorn Helgaas81d02732009-03-24 16:49:38 -06001051 return result;
Rafael J. Wysocki6831c6e2011-02-15 21:22:24 +01001052 }
Bjorn Helgaas81d02732009-03-24 16:49:38 -06001053
Rafael J. Wysocki6831c6e2011-02-15 21:22:24 +01001054 pci_mmcfg_late_init();
Bjorn Helgaase747f272009-03-24 16:49:43 -06001055 acpi_scan_init();
Bjorn Helgaasa5f820f2009-03-24 16:49:48 -06001056 acpi_ec_init();
Zhang Ruia25ee922010-07-15 10:46:15 +08001057 acpi_debugfs_init();
Bjorn Helgaas9cee43e2009-03-24 16:50:14 -06001058 acpi_sleep_proc_init();
Bjorn Helgaas201b8c62009-03-24 16:50:19 -06001059 acpi_wakeup_device_init();
Rafael J. Wysocki6831c6e2011-02-15 21:22:24 +01001060 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061}
1062
1063subsys_initcall(acpi_init);