diff options
Diffstat (limited to 'drivers/acpi/bus.c')
| -rw-r--r-- | drivers/acpi/bus.c | 780 |
1 files changed, 335 insertions, 445 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 5b6760e0f95..c5bc8cfe09f 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -32,11 +32,17 @@ #include <linux/device.h> #include <linux/proc_fs.h> #include <linux/acpi.h> +#include <linux/slab.h> +#include <linux/regulator/machine.h> #ifdef CONFIG_X86 #include <asm/mpspec.h> #endif -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> +#include <linux/pci.h> +#include <acpi/apei.h> +#include <linux/dmi.h> +#include <linux/suspend.h> + +#include "internal.h" #define _COMPONENT ACPI_BUS_COMPONENT ACPI_MODULE_NAME("bus"); @@ -45,433 +51,313 @@ struct acpi_device *acpi_root; struct proc_dir_entry *acpi_root_dir; EXPORT_SYMBOL(acpi_root_dir); -#define STRUCT_TO_INT(s) (*((int*)&s)) +#ifdef CONFIG_X86 +#ifdef CONFIG_ACPI_CUSTOM_DSDT +static inline int set_copy_dsdt(const struct dmi_system_id *id) +{ + return 0; +} +#else +static int set_copy_dsdt(const struct dmi_system_id *id) +{ + printk(KERN_NOTICE "%s detected - " + "force copy of DSDT to local memory\n", id->ident); + acpi_gbl_copy_dsdt_locally = 1; + return 0; +} +#endif + +static struct dmi_system_id dsdt_dmi_table[] __initdata = { + /* + * Invoke DSDT corruption work-around on all Toshiba Satellite. + * https://bugzilla.kernel.org/show_bug.cgi?id=14679 + */ + { + .callback = set_copy_dsdt, + .ident = "TOSHIBA Satellite", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"), + }, + }, + {} +}; +#else +static struct dmi_system_id dsdt_dmi_table[] __initdata = { + {} +}; +#endif /* -------------------------------------------------------------------------- Device Management -------------------------------------------------------------------------- */ -int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) +acpi_status acpi_bus_get_status_handle(acpi_handle handle, + unsigned long long *sta) { - acpi_status status = AE_OK; + acpi_status status; + status = acpi_evaluate_integer(handle, "_STA", NULL, sta); + if (ACPI_SUCCESS(status)) + return AE_OK; - if (!device) - return -EINVAL; - - /* TBD: Support fixed-feature devices */ - - status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device); - if (ACPI_FAILURE(status) || !*device) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", - handle)); - return -ENODEV; + if (status == AE_NOT_FOUND) { + *sta = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | + ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; + return AE_OK; } - - return 0; + return status; } -EXPORT_SYMBOL(acpi_bus_get_device); - int acpi_bus_get_status(struct acpi_device *device) { - acpi_status status = AE_OK; - unsigned long sta = 0; - + acpi_status status; + unsigned long long sta; - if (!device) - return -EINVAL; - - /* - * Evaluate _STA if present. - */ - if (device->flags.dynamic_status) { - status = - acpi_evaluate_integer(device->handle, "_STA", NULL, &sta); - if (ACPI_FAILURE(status)) - return -ENODEV; - STRUCT_TO_INT(device->status) = (int)sta; - } + status = acpi_bus_get_status_handle(device->handle, &sta); + if (ACPI_FAILURE(status)) + return -ENODEV; - /* - * Otherwise we assume the status of our parent (unless we don't - * have one, in which case status is implied). - */ - else if (device->parent) - device->status = device->parent->status; - else - STRUCT_TO_INT(device->status) = - ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | - ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; + acpi_set_device_status(device, sta); if (device->status.functional && !device->status.present) { - printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: " - "functional but not present; setting present\n", - device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status)); - device->status.present = 1; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: " + "functional but not present;\n", + device->pnp.bus_id, (u32)sta)); } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n", - device->pnp.bus_id, - (u32) STRUCT_TO_INT(device->status))); - + device->pnp.bus_id, (u32)sta)); return 0; } - EXPORT_SYMBOL(acpi_bus_get_status); void acpi_bus_private_data_handler(acpi_handle handle, - u32 function, void *context) + void *context) { return; } EXPORT_SYMBOL(acpi_bus_private_data_handler); -int acpi_bus_get_private_data(acpi_handle handle, void **data) +int acpi_bus_attach_private_data(acpi_handle handle, void *data) { - acpi_status status = AE_OK; - - if (!*data) - return -EINVAL; + acpi_status status; - status = acpi_get_data(handle, acpi_bus_private_data_handler, data); - if (ACPI_FAILURE(status) || !*data) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", - handle)); + status = acpi_attach_data(handle, + acpi_bus_private_data_handler, data); + if (ACPI_FAILURE(status)) { + acpi_handle_debug(handle, "Error attaching device data\n"); return -ENODEV; } return 0; } -EXPORT_SYMBOL(acpi_bus_get_private_data); - -/* -------------------------------------------------------------------------- - Power Management - -------------------------------------------------------------------------- */ +EXPORT_SYMBOL_GPL(acpi_bus_attach_private_data); -int acpi_bus_get_power(acpi_handle handle, int *state) +int acpi_bus_get_private_data(acpi_handle handle, void **data) { - int result = 0; - acpi_status status = 0; - struct acpi_device *device = NULL; - unsigned long psc = 0; - + acpi_status status; - result = acpi_bus_get_device(handle, &device); - if (result) - return result; - - *state = ACPI_STATE_UNKNOWN; - - if (!device->flags.power_manageable) { - /* TBD: Non-recursive algorithm for walking up hierarchy */ - if (device->parent) - *state = device->parent->power.state; - else - *state = ACPI_STATE_D0; - } else { - /* - * Get the device's power state either directly (via _PSC) or - * indirectly (via power resources). - */ - if (device->power.flags.explicit_get) { - status = acpi_evaluate_integer(device->handle, "_PSC", - NULL, &psc); - if (ACPI_FAILURE(status)) - return -ENODEV; - device->power.state = (int)psc; - } else if (device->power.flags.power_resources) { - result = acpi_power_get_inferred_state(device); - if (result) - return result; - } + if (!*data) + return -EINVAL; - *state = device->power.state; + status = acpi_get_data(handle, acpi_bus_private_data_handler, data); + if (ACPI_FAILURE(status)) { + acpi_handle_debug(handle, "No context for object\n"); + return -ENODEV; } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n", - device->pnp.bus_id, device->power.state)); - return 0; } +EXPORT_SYMBOL_GPL(acpi_bus_get_private_data); -EXPORT_SYMBOL(acpi_bus_get_power); - -int acpi_bus_set_power(acpi_handle handle, int state) +void acpi_bus_detach_private_data(acpi_handle handle) { - int result = 0; - acpi_status status = AE_OK; - struct acpi_device *device = NULL; - char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' }; - - - result = acpi_bus_get_device(handle, &device); - if (result) - return result; - - if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) - return -EINVAL; - - /* Make sure this is a valid target state */ - - if (!device->flags.power_manageable) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n", - kobject_name(&device->dev.kobj))); - return -ENODEV; - } - /* - * Get device's current power state - */ - acpi_bus_get_power(device->handle, &device->power.state); - if ((state == device->power.state) && !device->flags.force_power_state) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", - state)); - return 0; - } - - if (!device->power.states[state].flags.valid) { - printk(KERN_WARNING PREFIX "Device does not support D%d\n", state); - return -ENODEV; - } - if (device->parent && (state < device->parent->power.state)) { - printk(KERN_WARNING PREFIX - "Cannot set device to a higher-powered" - " state than parent\n"); - return -ENODEV; - } - - /* - * Transition Power - * ---------------- - * On transitions to a high-powered state we first apply power (via - * power resources) then evalute _PSx. Conversly for transitions to - * a lower-powered state. - */ - if (state < device->power.state) { - if (device->power.flags.power_resources) { - result = acpi_power_transition(device, state); - if (result) - goto end; - } - if (device->power.states[state].flags.explicit_set) { - status = acpi_evaluate_object(device->handle, - object_name, NULL, NULL); - if (ACPI_FAILURE(status)) { - result = -ENODEV; - goto end; - } - } - } else { - if (device->power.states[state].flags.explicit_set) { - status = acpi_evaluate_object(device->handle, - object_name, NULL, NULL); - if (ACPI_FAILURE(status)) { - result = -ENODEV; - goto end; - } - } - if (device->power.flags.power_resources) { - result = acpi_power_transition(device, state); - if (result) - goto end; - } - } - - end: - if (result) - printk(KERN_WARNING PREFIX - "Transitioning device [%s] to D%d\n", - device->pnp.bus_id, state); - else { - device->power.state = state; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Device [%s] transitioned to D%d\n", - device->pnp.bus_id, state)); - } - - return result; + acpi_detach_data(handle, acpi_bus_private_data_handler); } +EXPORT_SYMBOL_GPL(acpi_bus_detach_private_data); -EXPORT_SYMBOL(acpi_bus_set_power); - -/* -------------------------------------------------------------------------- - Event Management - -------------------------------------------------------------------------- */ - -#ifdef CONFIG_ACPI_PROC_EVENT -static DEFINE_SPINLOCK(acpi_bus_event_lock); - -LIST_HEAD(acpi_bus_event_list); -DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue); - -extern int event_is_open; - -int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data) +void acpi_bus_no_hotplug(acpi_handle handle) { - struct acpi_bus_event *event; - unsigned long flags = 0; - - /* drop event on the floor if no one's listening */ - if (!event_is_open) - return 0; - - event = kmalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC); - if (!event) - return -ENOMEM; - - strcpy(event->device_class, device_class); - strcpy(event->bus_id, bus_id); - event->type = type; - event->data = data; - - spin_lock_irqsave(&acpi_bus_event_lock, flags); - list_add_tail(&event->node, &acpi_bus_event_list); - spin_unlock_irqrestore(&acpi_bus_event_lock, flags); - - wake_up_interruptible(&acpi_bus_event_queue); - - return 0; + struct acpi_device *adev = NULL; + acpi_bus_get_device(handle, &adev); + if (adev) + adev->flags.no_hotplug = true; } +EXPORT_SYMBOL_GPL(acpi_bus_no_hotplug); -EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4); - -int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) +static void acpi_print_osc_error(acpi_handle handle, + struct acpi_osc_context *context, char *error) { - if (!device) - return -EINVAL; - return acpi_bus_generate_proc_event4(device->pnp.device_class, - device->pnp.bus_id, type, data); -} + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER}; + int i; -EXPORT_SYMBOL(acpi_bus_generate_proc_event); + if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) + printk(KERN_DEBUG "%s\n", error); + else { + printk(KERN_DEBUG "%s:%s\n", (char *)buffer.pointer, error); + kfree(buffer.pointer); + } + printk(KERN_DEBUG"_OSC request data:"); + for (i = 0; i < context->cap.length; i += sizeof(u32)) + printk("%x ", *((u32 *)(context->cap.pointer + i))); + printk("\n"); +} -int acpi_bus_receive_event(struct acpi_bus_event *event) +acpi_status acpi_str_to_uuid(char *str, u8 *uuid) { - unsigned long flags = 0; - struct acpi_bus_event *entry = NULL; - - DECLARE_WAITQUEUE(wait, current); - - - if (!event) - return -EINVAL; - - if (list_empty(&acpi_bus_event_list)) { - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&acpi_bus_event_queue, &wait); - - if (list_empty(&acpi_bus_event_list)) - schedule(); - - remove_wait_queue(&acpi_bus_event_queue, &wait); - set_current_state(TASK_RUNNING); - - if (signal_pending(current)) - return -ERESTARTSYS; + int i; + static int opc_map_to_uuid[16] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21, + 24, 26, 28, 30, 32, 34}; + + if (strlen(str) != 36) + return AE_BAD_PARAMETER; + for (i = 0; i < 36; i++) { + if (i == 8 || i == 13 || i == 18 || i == 23) { + if (str[i] != '-') + return AE_BAD_PARAMETER; + } else if (!isxdigit(str[i])) + return AE_BAD_PARAMETER; } - - spin_lock_irqsave(&acpi_bus_event_lock, flags); - entry = - list_entry(acpi_bus_event_list.next, struct acpi_bus_event, node); - if (entry) - list_del(&entry->node); - spin_unlock_irqrestore(&acpi_bus_event_lock, flags); - - if (!entry) - return -ENODEV; - - memcpy(event, entry, sizeof(struct acpi_bus_event)); - - kfree(entry); - - return 0; + for (i = 0; i < 16; i++) { + uuid[i] = hex_to_bin(str[opc_map_to_uuid[i]]) << 4; + uuid[i] |= hex_to_bin(str[opc_map_to_uuid[i] + 1]); + } + return AE_OK; } +EXPORT_SYMBOL_GPL(acpi_str_to_uuid); -#endif /* CONFIG_ACPI_PROC_EVENT */ - -/* -------------------------------------------------------------------------- - Notification Handling - -------------------------------------------------------------------------- */ - -static int -acpi_bus_check_device(struct acpi_device *device, int *status_changed) +acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context) { - acpi_status status = 0; - struct acpi_device_status old_status; - - - if (!device) - return -EINVAL; - - if (status_changed) - *status_changed = 0; - - old_status = device->status; - - /* - * Make sure this device's parent is present before we go about - * messing with the device. - */ - if (device->parent && !device->parent->status.present) { - device->status = device->parent->status; - if (STRUCT_TO_INT(old_status) != STRUCT_TO_INT(device->status)) { - if (status_changed) - *status_changed = 1; + acpi_status status; + struct acpi_object_list input; + union acpi_object in_params[4]; + union acpi_object *out_obj; + u8 uuid[16]; + u32 errors; + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; + + if (!context) + return AE_ERROR; + if (ACPI_FAILURE(acpi_str_to_uuid(context->uuid_str, uuid))) + return AE_ERROR; + context->ret.length = ACPI_ALLOCATE_BUFFER; + context->ret.pointer = NULL; + + /* Setting up input parameters */ + input.count = 4; + input.pointer = in_params; + in_params[0].type = ACPI_TYPE_BUFFER; + in_params[0].buffer.length = 16; + in_params[0].buffer.pointer = uuid; + in_params[1].type = ACPI_TYPE_INTEGER; + in_params[1].integer.value = context->rev; + in_params[2].type = ACPI_TYPE_INTEGER; + in_params[2].integer.value = context->cap.length/sizeof(u32); + in_params[3].type = ACPI_TYPE_BUFFER; + in_params[3].buffer.length = context->cap.length; + in_params[3].buffer.pointer = context->cap.pointer; + + status = acpi_evaluate_object(handle, "_OSC", &input, &output); + if (ACPI_FAILURE(status)) + return status; + + if (!output.length) + return AE_NULL_OBJECT; + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER + || out_obj->buffer.length != context->cap.length) { + acpi_print_osc_error(handle, context, + "_OSC evaluation returned wrong type"); + status = AE_TYPE; + goto out_kfree; + } + /* Need to ignore the bit0 in result code */ + errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); + if (errors) { + if (errors & OSC_REQUEST_ERROR) + acpi_print_osc_error(handle, context, + "_OSC request failed"); + if (errors & OSC_INVALID_UUID_ERROR) + acpi_print_osc_error(handle, context, + "_OSC invalid UUID"); + if (errors & OSC_INVALID_REVISION_ERROR) + acpi_print_osc_error(handle, context, + "_OSC invalid revision"); + if (errors & OSC_CAPABILITIES_MASK_ERROR) { + if (((u32 *)context->cap.pointer)[OSC_QUERY_DWORD] + & OSC_QUERY_ENABLE) + goto out_success; + status = AE_SUPPORT; + goto out_kfree; } - return 0; + status = AE_ERROR; + goto out_kfree; } - - status = acpi_bus_get_status(device); - if (ACPI_FAILURE(status)) - return -ENODEV; - - if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status)) - return 0; - - if (status_changed) - *status_changed = 1; - - /* - * Device Insertion/Removal - */ - if ((device->status.present) && !(old_status.present)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device insertion detected\n")); - /* TBD: Handle device insertion */ - } else if (!(device->status.present) && (old_status.present)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n")); - /* TBD: Handle device removal */ +out_success: + context->ret.length = out_obj->buffer.length; + context->ret.pointer = kmemdup(out_obj->buffer.pointer, + context->ret.length, GFP_KERNEL); + if (!context->ret.pointer) { + status = AE_NO_MEMORY; + goto out_kfree; } + status = AE_OK; - return 0; +out_kfree: + kfree(output.pointer); + if (status != AE_OK) + context->ret.pointer = NULL; + return status; } +EXPORT_SYMBOL(acpi_run_osc); -static int acpi_bus_check_scope(struct acpi_device *device) +bool osc_sb_apei_support_acked; +static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48"; +static void acpi_bus_osc_support(void) { - int result = 0; - int status_changed = 0; - - - if (!device) - return -EINVAL; - - /* Status Change? */ - result = acpi_bus_check_device(device, &status_changed); - if (result) - return result; + u32 capbuf[2]; + struct acpi_osc_context context = { + .uuid_str = sb_uuid_str, + .rev = 1, + .cap.length = 8, + .cap.pointer = capbuf, + }; + acpi_handle handle; + + capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE; + capbuf[OSC_SUPPORT_DWORD] = OSC_SB_PR3_SUPPORT; /* _PR3 is in use */ +#if defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR) ||\ + defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR_MODULE) + capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PAD_SUPPORT; +#endif - if (!status_changed) - return 0; +#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) + capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PPC_OST_SUPPORT; +#endif - /* - * TBD: Enumerate child devices within this device's scope and - * run acpi_bus_check_device()'s on them. - */ + capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT; - return 0; + if (!ghes_disable) + capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT; + if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) + return; + if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) { + u32 *capbuf_ret = context.ret.pointer; + if (context.ret.length > OSC_SUPPORT_DWORD) + osc_sb_apei_support_acked = + capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT; + kfree(context.ret.pointer); + } + /* do we need to check other returned cap? Sounds no */ } +/* -------------------------------------------------------------------------- + Notification Handling + -------------------------------------------------------------------------- */ + /** * acpi_bus_notify * --------------- @@ -479,87 +365,72 @@ static int acpi_bus_check_scope(struct acpi_device *device) */ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) { - int result = 0; - struct acpi_device *device = NULL; - - - if (acpi_bus_get_device(handle, &device)) - return; + struct acpi_device *adev; + struct acpi_driver *driver; + u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; + bool hotplug_event = false; switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received BUS CHECK notification for device [%s]\n", - device->pnp.bus_id)); - result = acpi_bus_check_scope(device); - /* - * TBD: We'll need to outsource certain events to non-ACPI - * drivers via the device manager (device.c). - */ + acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); + hotplug_event = true; break; case ACPI_NOTIFY_DEVICE_CHECK: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received DEVICE CHECK notification for device [%s]\n", - device->pnp.bus_id)); - result = acpi_bus_check_device(device, NULL); - /* - * TBD: We'll need to outsource certain events to non-ACPI - * drivers via the device manager (device.c). - */ + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); + hotplug_event = true; break; case ACPI_NOTIFY_DEVICE_WAKE: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received DEVICE WAKE notification for device [%s]\n", - device->pnp.bus_id)); - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n"); break; case ACPI_NOTIFY_EJECT_REQUEST: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received EJECT REQUEST notification for device [%s]\n", - device->pnp.bus_id)); - /* TBD */ + acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); + hotplug_event = true; break; case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received DEVICE CHECK LIGHT notification for device [%s]\n", - device->pnp.bus_id)); + acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n"); /* TBD: Exactly what does 'light' mean? */ break; case ACPI_NOTIFY_FREQUENCY_MISMATCH: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received FREQUENCY MISMATCH notification for device [%s]\n", - device->pnp.bus_id)); - /* TBD */ + acpi_handle_err(handle, "Device cannot be configured due " + "to a frequency mismatch\n"); break; case ACPI_NOTIFY_BUS_MODE_MISMATCH: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received BUS MODE MISMATCH notification for device [%s]\n", - device->pnp.bus_id)); - /* TBD */ + acpi_handle_err(handle, "Device cannot be configured due " + "to a bus mode mismatch\n"); break; case ACPI_NOTIFY_POWER_FAULT: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received POWER FAULT notification for device [%s]\n", - device->pnp.bus_id)); - /* TBD */ + acpi_handle_err(handle, "Device has suffered a power fault\n"); break; default: - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Received unknown/unsupported notification [%08x]\n", - type)); + acpi_handle_debug(handle, "Unknown event type 0x%x\n", type); break; } + adev = acpi_bus_get_acpi_device(handle); + if (!adev) + goto err; + + driver = adev->driver; + if (driver && driver->ops.notify && + (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) + driver->ops.notify(adev, type); + + if (hotplug_event && ACPI_SUCCESS(acpi_hotplug_schedule(adev, type))) + return; + + acpi_bus_put_acpi_device(adev); return; + + err: + acpi_evaluate_ost(handle, type, ost_code, NULL); } /* -------------------------------------------------------------------------- @@ -568,9 +439,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) static int __init acpi_bus_init_irq(void) { - acpi_status status = AE_OK; - union acpi_object arg = { ACPI_TYPE_INTEGER }; - struct acpi_object_list arg_list = { 1, &arg }; + acpi_status status; char *message = NULL; @@ -599,9 +468,7 @@ static int __init acpi_bus_init_irq(void) printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message); - arg.integer.value = acpi_irq_model; - - status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL); + status = acpi_execute_simple_method(NULL, "\\_PIC", acpi_irq_model); if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC")); return -ENODEV; @@ -610,24 +477,33 @@ static int __init acpi_bus_init_irq(void) return 0; } -acpi_native_uint acpi_gbl_permanent_mmap; +u8 acpi_gbl_permanent_mmap; void __init acpi_early_init(void) { - acpi_status status = AE_OK; + acpi_status status; if (acpi_disabled) return; printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION); + /* It's safe to verify table checksums during late stage */ + acpi_gbl_verify_table_checksum = TRUE; + /* enable workarounds, unless strict ACPI spec. compliance */ if (!acpi_strict) acpi_gbl_enable_interpreter_slack = TRUE; acpi_gbl_permanent_mmap = 1; + /* + * If the machine falls into the DMI check table, + * DSDT will be copied to memory + */ + dmi_check_system(dsdt_dmi_table); + status = acpi_reallocate_root_table(); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX @@ -668,15 +544,20 @@ void __init acpi_early_init(void) } #endif - status = - acpi_enable_subsystem(~ - (ACPI_NO_HARDWARE_INIT | - ACPI_NO_ACPI_ENABLE)); + status = acpi_enable_subsystem(~ACPI_NO_ACPI_ENABLE); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to enable ACPI\n"); goto error0; } + /* + * If the system is using ACPI then we can be reasonably + * confident that any regulators are managed by the firmware + * so tell the regulator core it has everything it needs to + * know. + */ + regulator_has_full_constraints(); + return; error0: @@ -686,27 +567,18 @@ void __init acpi_early_init(void) static int __init acpi_bus_init(void) { - int result = 0; - acpi_status status = AE_OK; - extern acpi_status acpi_os_initialize1(void); - + int result; + acpi_status status; - status = acpi_os_initialize1(); + acpi_os_initialize1(); - status = - acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE); + status = acpi_enable_subsystem(ACPI_NO_ACPI_ENABLE); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to start the ACPI Interpreter\n"); goto error1; } - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX - "Unable to initialize ACPI OS objects\n"); - goto error1; - } -#ifdef CONFIG_ACPI_EC /* * ACPI 2.0 requires the EC driver to be loaded and work before * the EC device is found in the namespace (i.e. before acpi_initialize_objects() @@ -717,7 +589,6 @@ static int __init acpi_bus_init(void) */ status = acpi_ec_ecdt_probe(); /* Ignore result. Not having an ECDT is not fatal. */ -#endif status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION); if (ACPI_FAILURE(status)) { @@ -725,6 +596,26 @@ static int __init acpi_bus_init(void) goto error1; } + /* + * _OSC method may exist in module level code, + * so it must be run after ACPI_FULL_INITIALIZATION + */ + acpi_bus_osc_support(); + + /* + * _PDC control method may load dynamic SSDT tables, + * and we need to install the table handler before that. + */ + acpi_sysfs_init(); + + acpi_early_processor_set_pdc(); + + /* + * Maybe EC region is required at bus_scan/acpi_get_devices. So it + * is necessary to enable it as early as possible. + */ + acpi_boot_ec_enable(); + printk(KERN_INFO PREFIX "Interpreter enabled\n"); /* Initialize sleep structures */ @@ -763,11 +654,11 @@ static int __init acpi_bus_init(void) } struct kobject *acpi_kobj; +EXPORT_SYMBOL_GPL(acpi_kobj); static int __init acpi_init(void) { - int result = 0; - + int result; if (acpi_disabled) { printk(KERN_INFO PREFIX "Interpreter disabled.\n"); @@ -780,21 +671,20 @@ static int __init acpi_init(void) acpi_kobj = NULL; } + init_acpi_device_notify(); result = acpi_bus_init(); - - if (!result) { - if (!(pm_flags & PM_APM)) - pm_flags |= PM_ACPI; - else { - printk(KERN_INFO PREFIX - "APM is already active, exiting\n"); - disable_acpi(); - result = -ENODEV; - } - } else + if (result) { disable_acpi(); + return result; + } - return result; + pci_mmcfg_late_init(); + acpi_scan_init(); + acpi_ec_init(); + acpi_debugfs_init(); + acpi_sleep_proc_init(); + acpi_wakeup_device_init(); + return 0; } subsys_initcall(acpi_init); |
