diff options
Diffstat (limited to 'drivers/acpi')
75 files changed, 1687 insertions, 1277 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 5d9248526d78..4770de5707b9 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -348,7 +348,6 @@ source "drivers/acpi/apei/Kconfig" config ACPI_EXTLOG tristate "Extended Error Log support" depends on X86_MCE && X86_LOCAL_APIC - select EFI select UEFI_CPER default n help diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 8711e3797165..6f190bc2b8b7 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -32,8 +32,7 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/power_supply.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> #define PREFIX "ACPI: " @@ -207,7 +206,7 @@ static int acpi_ac_probe(struct platform_device *pdev) goto end; result = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev), - ACPI_DEVICE_NOTIFY, acpi_ac_notify_handler, ac); + ACPI_ALL_NOTIFY, acpi_ac_notify_handler, ac); if (result) { power_supply_unregister(&ac->charger); goto end; @@ -244,6 +243,8 @@ static int acpi_ac_resume(struct device *dev) kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE); return 0; } +#else +#define acpi_ac_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_ac_pm_ops, NULL, acpi_ac_resume); @@ -255,7 +256,7 @@ static int acpi_ac_remove(struct platform_device *pdev) return -EINVAL; acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), - ACPI_DEVICE_NOTIFY, acpi_ac_notify_handler); + ACPI_ALL_NOTIFY, acpi_ac_notify_handler); ac = platform_get_drvdata(pdev); if (ac->charger.dev) diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index a6869e110ce5..c4a5d87ede7e 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -9,9 +9,9 @@ #include <linux/module.h> #include <linux/acpi.h> -#include <acpi/acpi_bus.h> #include <linux/cper.h> #include <linux/ratelimit.h> +#include <linux/edac.h> #include <asm/cpu.h> #include <asm/mce.h> @@ -20,11 +20,9 @@ #define EXT_ELOG_ENTRY_MASK GENMASK_ULL(51, 0) /* elog entry address mask */ #define EXTLOG_DSM_REV 0x0 -#define EXTLOG_FN_QUERY 0x0 #define EXTLOG_FN_ADDR 0x1 #define FLAG_OS_OPTIN BIT(0) -#define EXTLOG_QUERY_L1_EXIST BIT(1) #define ELOG_ENTRY_VALID (1ULL<<63) #define ELOG_ENTRY_LEN 0x1000 @@ -43,7 +41,9 @@ struct extlog_l1_head { u8 rev1[12]; }; -static u8 extlog_dsm_uuid[] = "663E35AF-CC10-41A4-88EA-5470AF055295"; +static int old_edac_report_status; + +static u8 extlog_dsm_uuid[] __initdata = "663E35AF-CC10-41A4-88EA-5470AF055295"; /* L1 table related physical address */ static u64 elog_base; @@ -150,65 +150,30 @@ static int extlog_print(struct notifier_block *nb, unsigned long val, rc = print_extlog_rcd(NULL, (struct acpi_generic_status *)elog_buf, cpu); - return NOTIFY_DONE; + return NOTIFY_STOP; } -static int extlog_get_dsm(acpi_handle handle, int rev, int func, u64 *ret) +static bool __init extlog_get_l1addr(void) { - struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; - struct acpi_object_list input; - union acpi_object params[4], *obj; u8 uuid[16]; - int i; + acpi_handle handle; + union acpi_object *obj; acpi_str_to_uuid(extlog_dsm_uuid, uuid); - input.count = 4; - input.pointer = params; - params[0].type = ACPI_TYPE_BUFFER; - params[0].buffer.length = 16; - params[0].buffer.pointer = uuid; - params[1].type = ACPI_TYPE_INTEGER; - params[1].integer.value = rev; - params[2].type = ACPI_TYPE_INTEGER; - params[2].integer.value = func; - params[3].type = ACPI_TYPE_PACKAGE; - params[3].package.count = 0; - params[3].package.elements = NULL; - - if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DSM", &input, &buf))) - return -1; - - *ret = 0; - obj = (union acpi_object *)buf.pointer; - if (obj->type == ACPI_TYPE_INTEGER) { - *ret = obj->integer.value; - } else if (obj->type == ACPI_TYPE_BUFFER) { - if (obj->buffer.length <= 8) { - for (i = 0; i < obj->buffer.length; i++) - *ret |= (obj->buffer.pointer[i] << (i * 8)); - } - } - kfree(buf.pointer); - - return 0; -} - -static bool extlog_get_l1addr(void) -{ - acpi_handle handle; - u64 ret; if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) return false; - - if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_QUERY, &ret) || - !(ret & EXTLOG_QUERY_L1_EXIST)) + if (!acpi_check_dsm(handle, uuid, EXTLOG_DSM_REV, 1 << EXTLOG_FN_ADDR)) return false; - - if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_ADDR, &ret)) + obj = acpi_evaluate_dsm_typed(handle, uuid, EXTLOG_DSM_REV, + EXTLOG_FN_ADDR, NULL, ACPI_TYPE_INTEGER); + if (!obj) { return false; + } else { + l1_dirbase = obj->integer.value; + ACPI_FREE(obj); + } - l1_dirbase = ret; /* Spec says L1 directory must be 4K aligned, bail out if it isn't */ if (l1_dirbase & ((1 << 12) - 1)) { pr_warn(FW_BUG "L1 Directory is invalid at physical %llx\n", @@ -231,8 +196,12 @@ static int __init extlog_init(void) u64 cap; int rc; - rc = -ENODEV; + if (get_edac_report_status() == EDAC_REPORTING_FORCE) { + pr_warn("Not loading eMCA, error reporting force-enabled through EDAC.\n"); + return -EPERM; + } + rc = -ENODEV; rdmsrl(MSR_IA32_MCG_CAP, cap); if (!(cap & MCG_ELOG_P)) return rc; @@ -287,6 +256,12 @@ static int __init extlog_init(void) if (elog_buf == NULL) goto err_release_elog; + /* + * eMCA event report method has higher priority than EDAC method, + * unless EDAC event report method is mandatory. + */ + old_edac_report_status = get_edac_report_status(); + set_edac_report_status(EDAC_REPORTING_DISABLED); mce_register_decode_chain(&extlog_mce_dec); /* enable OS to be involved to take over management from BIOS */ ((struct extlog_l1_head *)extlog_l1_addr)->flags |= FLAG_OS_OPTIN; @@ -308,6 +283,7 @@ err: static void __exit extlog_exit(void) { + set_edac_report_status(old_edac_report_status); mce_unregister_decode_chain(&extlog_mce_dec); ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN; if (extlog_l1_addr) diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 551dad712ffe..b67be85ff0fc 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -180,14 +180,14 @@ static unsigned long acpi_meminfo_end_pfn(struct acpi_memory_info *info) static int acpi_bind_memblk(struct memory_block *mem, void *arg) { - return acpi_bind_one(&mem->dev, (acpi_handle)arg); + return acpi_bind_one(&mem->dev, arg); } static int acpi_bind_memory_blocks(struct acpi_memory_info *info, - acpi_handle handle) + struct acpi_device *adev) { return walk_memory_range(acpi_meminfo_start_pfn(info), - acpi_meminfo_end_pfn(info), (void *)handle, + acpi_meminfo_end_pfn(info), adev, acpi_bind_memblk); } @@ -197,8 +197,7 @@ static int acpi_unbind_memblk(struct memory_block *mem, void *arg) return 0; } -static void acpi_unbind_memory_blocks(struct acpi_memory_info *info, - acpi_handle handle) +static void acpi_unbind_memory_blocks(struct acpi_memory_info *info) { walk_memory_range(acpi_meminfo_start_pfn(info), acpi_meminfo_end_pfn(info), NULL, acpi_unbind_memblk); @@ -242,9 +241,9 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) if (result && result != -EEXIST) continue; - result = acpi_bind_memory_blocks(info, handle); + result = acpi_bind_memory_blocks(info, mem_device->device); if (result) { - acpi_unbind_memory_blocks(info, handle); + acpi_unbind_memory_blocks(info); return -ENODEV; } @@ -285,7 +284,7 @@ static void acpi_memory_remove_memory(struct acpi_memory_device *mem_device) if (nid == NUMA_NO_NODE) nid = memory_add_physaddr_to_nid(info->start_addr); - acpi_unbind_memory_blocks(info, handle); + acpi_unbind_memory_blocks(info); remove_memory(nid, info->start_addr, info->length); list_del(&info->list); kfree(info); @@ -361,7 +360,19 @@ static void acpi_memory_device_remove(struct acpi_device *device) acpi_memory_device_free(mem_device); } +static bool __initdata acpi_no_memhotplug; + void __init acpi_memory_hotplug_init(void) { + if (acpi_no_memhotplug) + return; + acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory"); } + +static int __init disable_acpi_memory_hotplug(char *str) +{ + acpi_no_memhotplug = true; + return 1; +} +__setup("acpi_no_memhotplug", disable_acpi_memory_hotplug); diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index fc6008fbce35..df96a0fe4890 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -28,8 +28,7 @@ #include <linux/cpu.h> #include <linux/clockchips.h> #include <linux/slab.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> #include <asm/mwait.h> #define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad" @@ -193,10 +192,7 @@ static int power_saving_thread(void *data) CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); stop_critical_timings(); - __monitor((void *)¤t_thread_info()->flags, 0, 0); - smp_mb(); - if (!need_resched()) - __mwait(power_saving_mwait_eax, 1); + mwait_idle_with_hints(power_saving_mwait_eax, 1); start_critical_timings(); if (lapic_marked_unstable) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 3c1d6b0c09a4..c29c2c3ec0ad 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -212,7 +212,7 @@ static int acpi_processor_get_info(struct acpi_device *device) union acpi_object object = { 0 }; struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; struct acpi_processor *pr = acpi_driver_data(device); - int cpu_index, device_declaration = 0; + int apic_id, cpu_index, device_declaration = 0; acpi_status status = AE_OK; static int cpu0_initialized; unsigned long long value; @@ -258,18 +258,21 @@ static int acpi_processor_get_info(struct acpi_device *device) device_declaration = 1; pr->acpi_id = value; } - pr->apic_id = acpi_get_apicid(pr->handle, device_declaration, - pr->acpi_id); - cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id); - /* Handle UP system running SMP kernel, with no LAPIC in MADT */ - if (!cpu0_initialized && (cpu_index == -1) && - (num_online_cpus() == 1)) { - cpu_index = 0; + apic_id = acpi_get_apicid(pr->handle, device_declaration, pr->acpi_id); + if (apic_id < 0) { + acpi_handle_debug(pr->handle, "failed to get CPU APIC ID.\n"); + return -ENODEV; } + pr->apic_id = apic_id; - cpu0_initialized = 1; - + cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id); + if (!cpu0_initialized) { + cpu0_initialized = 1; + /* Handle UP system running SMP kernel, with no LAPIC in MADT */ + if ((cpu_index == -1) && (num_online_cpus() == 1)) + cpu_index = 0; + } pr->id = cpu_index; /* @@ -282,6 +285,7 @@ static int acpi_processor_get_info(struct acpi_device *device) if (ret) return ret; } + /* * On some boxes several processors use the same processor bus id. * But they are located in different scope. For example: @@ -395,7 +399,7 @@ static int acpi_processor_add(struct acpi_device *device, goto err; } - result = acpi_bind_one(dev, pr->handle); + result = acpi_bind_one(dev, device); if (result) goto err; diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index a9fd0b872062..2bf3ca2b8a7a 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -113,7 +113,6 @@ void acpi_db_display_handlers(void); ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_generate_gpe(char *gpe_arg, char *block_arg)) - ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_generate_sci(void)) /* diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 41abe552c7a3..0fb0adf435d6 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -71,9 +71,8 @@ acpi_status acpi_ev_init_global_lock_handler(void); ACPI_HW_DEPENDENT_RETURN_OK(acpi_status acpi_ev_acquire_global_lock(u16 timeout)) - ACPI_HW_DEPENDENT_RETURN_OK(acpi_status acpi_ev_release_global_lock(void)) - acpi_status acpi_ev_remove_global_lock_handler(void); +acpi_status acpi_ev_remove_global_lock_handler(void); /* * evgpe - Low-level GPE support @@ -133,7 +132,7 @@ acpi_status acpi_ev_gpe_initialize(void); ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_ev_update_gpes(acpi_owner_id table_owner_id)) - acpi_status +acpi_status acpi_ev_match_gpe_method(acpi_handle obj_handle, u32 level, void *context, void **return_value); @@ -149,7 +148,9 @@ acpi_status acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, void *context); -struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number); +acpi_status +acpi_ev_get_gpe_xrupt_block(u32 interrupt_number, + struct acpi_gpe_xrupt_info **gpe_xrupt_block); acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt); diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index e9f1fc7f99c7..4ed1aa384df2 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -108,7 +108,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE); /* * Optionally enable output from the AML Debug Object. */ -bool ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE); +u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE); /* * Optionally copy the entire DSDT to local memory (instead of simply @@ -119,6 +119,24 @@ bool ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE); u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE); /* + * Optionally ignore an XSDT if present and use the RSDT instead. + * Although the ACPI specification requires that an XSDT be used instead + * of the RSDT, the XSDT has been found to be corrupt or ill-formed on + * some machines. Default behavior is to use the XSDT if present. + */ +u8 ACPI_INIT_GLOBAL(acpi_gbl_do_not_use_xsdt, FALSE); + +/* + * Optionally use 32-bit FADT addresses if and when there is a conflict + * (address mismatch) between the 32-bit and 64-bit versions of the + * address. Although ACPICA adheres to the ACPI specification which + * requires the use of the corresponding 64-bit address if it is non-zero, + * some machines have been found to have a corrupted non-zero 64-bit + * address. Default is FALSE, do not favor the 32-bit addresses. + */ +u8 ACPI_INIT_GLOBAL(acpi_gbl_use32_bit_fadt_addresses, FALSE); + +/* * Optionally truncate I/O addresses to 16 bits. Provides compatibility * with other ACPI implementations. NOTE: During ACPICA initialization, * this value is set to TRUE if any Windows OSI strings have been @@ -484,6 +502,18 @@ ACPI_EXTERN u32 acpi_gbl_size_of_acpi_objects; /***************************************************************************** * + * Application globals + * + ****************************************************************************/ + +#ifdef ACPI_APPLICATION + +ACPI_FILE ACPI_INIT_GLOBAL(acpi_gbl_debug_file, NULL); + +#endif /* ACPI_APPLICATION */ + +/***************************************************************************** + * * Info/help support * ****************************************************************************/ diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 53ed1a8ba4f0..d95ca5449ace 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -1038,15 +1038,16 @@ struct acpi_external_list { struct acpi_external_list *next; u32 value; u16 length; + u16 flags; u8 type; - u8 flags; - u8 resolved; - u8 emitted; }; /* Values for Flags field above */ -#define ACPI_IPATH_ALLOCATED 0x01 +#define ACPI_EXT_RESOLVED_REFERENCE 0x01 /* Object was resolved during cross ref */ +#define ACPI_EXT_ORIGIN_FROM_FILE 0x02 /* External came from a file */ +#define ACPI_EXT_INTERNAL_PATH_ALLOCATED 0x04 /* Deallocate internal path on completion */ +#define ACPI_EXT_EXTERNAL_EMITTED 0x08 /* External() statement has been emitted */ struct acpi_external_file { char *path; diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 2d4c07322576..e7a57c554e84 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -105,7 +105,7 @@ acpi_ds_create_external_region(acpi_status lookup_status, * operation_region not found. Generate an External for it, and * insert the name into the namespace. */ - acpi_dm_add_to_external_list(op, path, ACPI_TYPE_REGION, 0); + acpi_dm_add_op_to_external_list(op, path, ACPI_TYPE_REGION, 0, 0); status = acpi_ns_lookup(walk_state->scope_info, path, ACPI_TYPE_REGION, ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, walk_state, node); diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index ade44e49deb4..d7f53fb2979a 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -727,27 +727,26 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state, index++; } - index--; + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "NumOperands %d, ArgCount %d, Index %d\n", + walk_state->num_operands, arg_count, index)); - /* It is the appropriate order to get objects from the Result stack */ + /* Create the interpreter arguments, in reverse order */ + index--; for (i = 0; i < arg_count; i++) { arg = arguments[index]; - - /* Force the filling of the operand stack in inverse order */ - - walk_state->operand_index = (u8) index; + walk_state->operand_index = (u8)index; status = acpi_ds_create_operand(walk_state, arg, index); if (ACPI_FAILURE(status)) { goto cleanup; } - index--; - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Arg #%u (%p) done, Arg1=%p\n", index, arg, - first_arg)); + "Created Arg #%u (%p) %u args total\n", + index, arg, arg_count)); + index--; } return_ACPI_STATUS(status); diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 95e681a36f9c..2dbe109727c8 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -181,8 +181,8 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, * Target of Scope() not found. Generate an External for it, and * insert the name into the namespace. */ - acpi_dm_add_to_external_list(op, path, ACPI_TYPE_DEVICE, - 0); + acpi_dm_add_op_to_external_list(op, path, + ACPI_TYPE_DEVICE, 0, 0); status = acpi_ns_lookup(walk_state->scope_info, path, object_type, ACPI_IMODE_LOAD_PASS1, diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index a9e76bc4ad97..a31e549e64cc 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -87,9 +87,9 @@ acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, return_ACPI_STATUS(status); } - gpe_xrupt_block = acpi_ev_get_gpe_xrupt_block(interrupt_number); - if (!gpe_xrupt_block) { - status = AE_NO_MEMORY; + status = + acpi_ev_get_gpe_xrupt_block(interrupt_number, &gpe_xrupt_block); + if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -112,7 +112,7 @@ acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, acpi_os_release_lock(acpi_gbl_gpe_lock, flags); unlock_and_exit: - status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index d3f5e1e2a2b1..4d764e847a08 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -197,8 +197,9 @@ acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, * FUNCTION: acpi_ev_get_gpe_xrupt_block * * PARAMETERS: interrupt_number - Interrupt for a GPE block + * gpe_xrupt_block - Where the block is returned * - * RETURN: A GPE interrupt block + * RETURN: Status * * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt * block per unique interrupt level used for GPEs. Should be @@ -207,7 +208,9 @@ acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, * ******************************************************************************/ -struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number) +acpi_status +acpi_ev_get_gpe_xrupt_block(u32 interrupt_number, + struct acpi_gpe_xrupt_info ** gpe_xrupt_block) { struct acpi_gpe_xrupt_info *next_gpe_xrupt; struct acpi_gpe_xrupt_info *gpe_xrupt; @@ -221,7 +224,8 @@ struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number) next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; while (next_gpe_xrupt) { if (next_gpe_xrupt->interrupt_number == interrupt_number) { - return_PTR(next_gpe_xrupt); + *gpe_xrupt_block = next_gpe_xrupt; + return_ACPI_STATUS(AE_OK); } next_gpe_xrupt = next_gpe_xrupt->next; @@ -231,7 +235,7 @@ struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number) gpe_xrupt = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_xrupt_info)); if (!gpe_xrupt) { - return_PTR(NULL); + return_ACPI_STATUS(AE_NO_MEMORY); } gpe_xrupt->interrupt_number = interrupt_number; @@ -250,6 +254,7 @@ struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number) } else { acpi_gbl_gpe_xrupt_list_head = gpe_xrupt; } + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); /* Install new interrupt handler if not SCI_INT */ @@ -259,14 +264,15 @@ struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number) acpi_ev_gpe_xrupt_handler, gpe_xrupt); if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not install GPE interrupt handler at level 0x%X", - interrupt_number)); - return_PTR(NULL); + ACPI_EXCEPTION((AE_INFO, status, + "Could not install GPE interrupt handler at level 0x%X", + interrupt_number)); + return_ACPI_STATUS(status); } } - return_PTR(gpe_xrupt); + *gpe_xrupt_block = gpe_xrupt; + return_ACPI_STATUS(AE_OK); } /******************************************************************************* diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index acd34f599313..7ca6925a87ca 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -124,7 +124,8 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, } if (!source_desc) { - ACPI_ERROR((AE_INFO, "No object attached to node %p", node)); + ACPI_ERROR((AE_INFO, "No object attached to node [%4.4s] %p", + node->name.ascii, node)); return_ACPI_STATUS(AE_AML_NO_OPERAND); } diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index e973e311f856..1f0c28ba50df 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -84,7 +84,7 @@ acpi_evaluate_object_typed(acpi_handle handle, acpi_object_type return_type) { acpi_status status; - u8 must_free = FALSE; + u8 free_buffer_on_error = FALSE; ACPI_FUNCTION_TRACE(acpi_evaluate_object_typed); @@ -95,14 +95,13 @@ acpi_evaluate_object_typed(acpi_handle handle, } if (return_buffer->length == ACPI_ALLOCATE_BUFFER) { - must_free = TRUE; + free_buffer_on_error = TRUE; } /* Evaluate the object */ - status = - acpi_evaluate_object(handle, pathname, external_params, - return_buffer); + status = acpi_evaluate_object(handle, pathname, + external_params, return_buffer); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -135,11 +134,15 @@ acpi_evaluate_object_typed(acpi_handle handle, pointer)->type), acpi_ut_get_type_name(return_type))); - if (must_free) { - - /* Caller used ACPI_ALLOCATE_BUFFER, free the return buffer */ - - ACPI_FREE_BUFFER(*return_buffer); + if (free_buffer_on_error) { + /* + * Free a buffer created via ACPI_ALLOCATE_BUFFER. + * Note: We use acpi_os_free here because acpi_os_allocate was used + * to allocate the buffer. This purposefully bypasses the + * (optionally enabled) allocation tracking mechanism since we + * only want to track internal allocations. + */ + acpi_os_free(return_buffer->pointer); return_buffer->pointer = NULL; } diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c index 9ba5301e5751..b0c9787dbe61 100644 --- a/drivers/acpi/acpica/psopinfo.c +++ b/drivers/acpi/acpica/psopinfo.c @@ -71,6 +71,10 @@ static const u8 acpi_gbl_argument_count[] = const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode) { +#ifdef ACPI_DEBUG_OUTPUT + const char *opcode_name = "Unknown AML opcode"; +#endif + ACPI_FUNCTION_NAME(ps_get_opcode_info); /* @@ -92,11 +96,54 @@ const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode) return (&acpi_gbl_aml_op_info [acpi_gbl_long_op_index[(u8)opcode]]); } +#if defined ACPI_ASL_COMPILER && defined ACPI_DEBUG_OUTPUT +#include "asldefine.h" + + switch (opcode) { + case AML_RAW_DATA_BYTE: + opcode_name = "-Raw Data Byte-"; + break; + + case AML_RAW_DATA_WORD: + opcode_name = "-Raw Data Word-"; + break; + + case AML_RAW_DATA_DWORD: + opcode_name = "-Raw Data Dword-"; + break; + + case AML_RAW_DATA_QWORD: + opcode_name = "-Raw Data Qword-"; + break; + + case AML_RAW_DATA_BUFFER: + opcode_name = "-Raw Data Buffer-"; + break; + + case AML_RAW_DATA_CHAIN: + opcode_name = "-Raw Data Buffer Chain-"; + break; + + case AML_PACKAGE_LENGTH: + opcode_name = "-Package Length-"; + break; + + case AML_UNASSIGNED_OPCODE: + opcode_name = "-Unassigned Opcode-"; + break; + + case AML_DEFAULT_ARG_OP: + opcode_name = "-Default Arg-"; + break; + + default: + break; + } +#endif /* Unknown AML opcode */ - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Unknown AML opcode [%4.4X]\n", opcode)); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%4.4X]\n", opcode_name, opcode)); return (&acpi_gbl_aml_op_info[_UNK]); } diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 9d99f2189693..8f89263ac47e 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -56,10 +56,11 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, static void acpi_tb_convert_fadt(void); -static void acpi_tb_validate_fadt(void); - static void acpi_tb_setup_fadt_registers(void); +static u64 +acpi_tb_select_address(char *register_name, u32 address32, u64 address64); + /* Table for conversion of FADT to common internal format and FADT validation */ typedef struct acpi_fadt_info { @@ -175,6 +176,7 @@ static struct acpi_fadt_pm_info fadt_pm_info_table[] = { * space_id - ACPI Space ID for this register * byte_width - Width of this register * address - Address of the register + * register_name - ASCII name of the ACPI register * * RETURN: None * @@ -220,6 +222,68 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, /******************************************************************************* * + * FUNCTION: acpi_tb_select_address + * + * PARAMETERS: register_name - ASCII name of the ACPI register + * address32 - 32-bit address of the register + * address64 - 64-bit address of the register + * + * RETURN: The resolved 64-bit address + * + * DESCRIPTION: Select between 32-bit and 64-bit versions of addresses within + * the FADT. Used for the FACS and DSDT addresses. + * + * NOTES: + * + * Check for FACS and DSDT address mismatches. An address mismatch between + * the 32-bit and 64-bit address fields (FIRMWARE_CTRL/X_FIRMWARE_CTRL and + * DSDT/X_DSDT) could be a corrupted address field or it might indicate + * the presence of two FACS or two DSDT tables. + * + * November 2013: + * By default, as per the ACPICA specification, a valid 64-bit address is + * used regardless of the value of the 32-bit address. However, this + * behavior can be overridden via the acpi_gbl_use32_bit_fadt_addresses flag. + * + ******************************************************************************/ + +static u64 +acpi_tb_select_address(char *register_name, u32 address32, u64 address64) +{ + + if (!address64) { + + /* 64-bit address is zero, use 32-bit address */ + + return ((u64)address32); + } + + if (address32 && (address64 != (u64)address32)) { + + /* Address mismatch between 32-bit and 64-bit versions */ + + ACPI_BIOS_WARNING((AE_INFO, + "32/64X %s address mismatch in FADT: " + "0x%8.8X/0x%8.8X%8.8X, using %u-bit address", + register_name, address32, + ACPI_FORMAT_UINT64(address64), + acpi_gbl_use32_bit_fadt_addresses ? 32 : + 64)); + + /* 32-bit address override */ + + if (acpi_gbl_use32_bit_fadt_addresses) { + return ((u64)address32); + } + } + + /* Default is to use the 64-bit address */ + + return (address64); +} + +/******************************************************************************* + * * FUNCTION: acpi_tb_parse_fadt * * PARAMETERS: table_index - Index for the FADT @@ -331,10 +395,6 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) acpi_tb_convert_fadt(); - /* Validate FADT values now, before we make any changes */ - - acpi_tb_validate_fadt(); - /* Initialize the global ACPI register structures */ acpi_tb_setup_fadt_registers(); @@ -344,66 +404,55 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) * * FUNCTION: acpi_tb_convert_fadt * - * PARAMETERS: None, uses acpi_gbl_FADT + * PARAMETERS: none - acpi_gbl_FADT is used. * * RETURN: None * * DESCRIPTION: Converts all versions of the FADT to a common internal format. - * Expand 32-bit addresses to 64-bit as necessary. + * Expand 32-bit addresses to 64-bit as necessary. Also validate + * important fields within the FADT. * - * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), - * and must contain a copy of the actual FADT. + * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), and must + * contain a copy of the actual BIOS-provided FADT. * * Notes on 64-bit register addresses: * * After this FADT conversion, later ACPICA code will only use the 64-bit "X" * fields of the FADT for all ACPI register addresses. * - * The 64-bit "X" fields are optional extensions to the original 32-bit FADT + * The 64-bit X fields are optional extensions to the original 32-bit FADT * V1.0 fields. Even if they are present in the FADT, they are optional and * are unused if the BIOS sets them to zero. Therefore, we must copy/expand - * 32-bit V1.0 fields if the corresponding X field is zero. + * 32-bit V1.0 fields to the 64-bit X fields if the the 64-bit X field is + * originally zero. * - * For ACPI 1.0 FADTs, all 32-bit address fields are expanded to the - * corresponding "X" fields in the internal FADT. + * For ACPI 1.0 FADTs (that contain no 64-bit addresses), all 32-bit address + * fields are expanded to the corresponding 64-bit X fields in the internal + * common FADT. * * For ACPI 2.0+ FADTs, all valid (non-zero) 32-bit address fields are expanded - * to the corresponding 64-bit X fields. For compatibility with other ACPI - * implementations, we ignore the 64-bit field if the 32-bit field is valid, - * regardless of whether the host OS is 32-bit or 64-bit. + * to the corresponding 64-bit X fields, if the 64-bit field is originally + * zero. Adhering to the ACPI specification, we completely ignore the 32-bit + * field if the 64-bit field is valid, regardless of whether the host OS is + * 32-bit or 64-bit. + * + * Possible additional checks: + * (acpi_gbl_FADT.pm1_event_length >= 4) + * (acpi_gbl_FADT.pm1_control_length >= 2) + * (acpi_gbl_FADT.pm_timer_length >= 4) + * Gpe block lengths must be multiple of 2 * ******************************************************************************/ static void acpi_tb_convert_fadt(void) { + char *name; struct acpi_generic_address *address64; u32 address32; + u8 length; u32 i; /* - * Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary. - * Later code will always use the X 64-bit field. Also, check for an - * address mismatch between the 32-bit and 64-bit address fields - * (FIRMWARE_CTRL/X_FIRMWARE_CTRL, DSDT/X_DSDT) which would indicate - * the presence of two FACS or two DSDT tables. - */ - if (!acpi_gbl_FADT.Xfacs) { - acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs; - } else if (acpi_gbl_FADT.facs && - (acpi_gbl_FADT.Xfacs != (u64) acpi_gbl_FADT.facs)) { - ACPI_WARNING((AE_INFO, - "32/64 FACS address mismatch in FADT - two FACS tables!")); - } - - if (!acpi_gbl_FADT.Xdsdt) { - acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt; - } else if (acpi_gbl_FADT.dsdt && - (acpi_gbl_FADT.Xdsdt != (u64) acpi_gbl_FADT.dsdt)) { - ACPI_WARNING((AE_INFO, - "32/64 DSDT address mismatch in FADT - two DSDT tables!")); - } - - /* * For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which * should be zero are indeed zero. This will workaround BIOSs that * inadvertently place values in these fields. @@ -421,119 +470,24 @@ static void acpi_tb_convert_fadt(void) acpi_gbl_FADT.boot_flags = 0; } - /* Update the local FADT table header length */ - - acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); - /* - * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" - * generic address structures as necessary. Later code will always use - * the 64-bit address structures. - * - * March 2009: - * We now always use the 32-bit address if it is valid (non-null). This - * is not in accordance with the ACPI specification which states that - * the 64-bit address supersedes the 32-bit version, but we do this for - * compatibility with other ACPI implementations. Most notably, in the - * case where both the 32 and 64 versions are non-null, we use the 32-bit - * version. This is the only address that is guaranteed to have been - * tested by the BIOS manufacturer. + * Now we can update the local FADT length to the length of the + * current FADT version as defined by the ACPI specification. + * Thus, we will have a common FADT internally. */ - for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { - address32 = *ACPI_ADD_PTR(u32, - &acpi_gbl_FADT, - fadt_info_table[i].address32); - - address64 = ACPI_ADD_PTR(struct acpi_generic_address, - &acpi_gbl_FADT, - fadt_info_table[i].address64); - - /* - * If both 32- and 64-bit addresses are valid (non-zero), - * they must match. - */ - if (address64->address && address32 && - (address64->address != (u64)address32)) { - ACPI_BIOS_ERROR((AE_INFO, - "32/64X address mismatch in FADT/%s: " - "0x%8.8X/0x%8.8X%8.8X, using 32", - fadt_info_table[i].name, address32, - ACPI_FORMAT_UINT64(address64-> - address))); - } - - /* Always use 32-bit address if it is valid (non-null) */ - - if (address32) { - /* - * Copy the 32-bit address to the 64-bit GAS structure. The - * Space ID is always I/O for 32-bit legacy address fields - */ - acpi_tb_init_generic_address(address64, - ACPI_ADR_SPACE_SYSTEM_IO, - *ACPI_ADD_PTR(u8, - &acpi_gbl_FADT, - fadt_info_table - [i].length), - (u64) address32, - fadt_info_table[i].name); - } - } -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_validate_fadt - * - * PARAMETERS: table - Pointer to the FADT to be validated - * - * RETURN: None - * - * DESCRIPTION: Validate various important fields within the FADT. If a problem - * is found, issue a message, but no status is returned. - * Used by both the table manager and the disassembler. - * - * Possible additional checks: - * (acpi_gbl_FADT.pm1_event_length >= 4) - * (acpi_gbl_FADT.pm1_control_length >= 2) - * (acpi_gbl_FADT.pm_timer_length >= 4) - * Gpe block lengths must be multiple of 2 - * - ******************************************************************************/ - -static void acpi_tb_validate_fadt(void) -{ - char *name; - struct acpi_generic_address *address64; - u8 length; - u32 i; + acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); /* - * Check for FACS and DSDT address mismatches. An address mismatch between - * the 32-bit and 64-bit address fields (FIRMWARE_CTRL/X_FIRMWARE_CTRL and - * DSDT/X_DSDT) would indicate the presence of two FACS or two DSDT tables. + * Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary. + * Later ACPICA code will always use the X 64-bit field. */ - if (acpi_gbl_FADT.facs && - (acpi_gbl_FADT.Xfacs != (u64)acpi_gbl_FADT.facs)) { - ACPI_BIOS_WARNING((AE_INFO, - "32/64X FACS address mismatch in FADT - " - "0x%8.8X/0x%8.8X%8.8X, using 32", - acpi_gbl_FADT.facs, - ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xfacs))); - - acpi_gbl_FADT.Xfacs = (u64)acpi_gbl_FADT.facs; - } - - if (acpi_gbl_FADT.dsdt && - (acpi_gbl_FADT.Xdsdt != (u64)acpi_gbl_FADT.dsdt)) { - ACPI_BIOS_WARNING((AE_INFO, - "32/64X DSDT address mismatch in FADT - " - "0x%8.8X/0x%8.8X%8.8X, using 32", - acpi_gbl_FADT.dsdt, - ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xdsdt))); + acpi_gbl_FADT.Xfacs = acpi_tb_select_address("FACS", + acpi_gbl_FADT.facs, + acpi_gbl_FADT.Xfacs); - acpi_gbl_FADT.Xdsdt = (u64)acpi_gbl_FADT.dsdt; - } + acpi_gbl_FADT.Xdsdt = acpi_tb_select_address("DSDT", + acpi_gbl_FADT.dsdt, + acpi_gbl_FADT.Xdsdt); /* If Hardware Reduced flag is set, we are all done */ @@ -545,18 +499,95 @@ static void acpi_tb_validate_fadt(void) for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { /* - * Generate pointer to the 64-bit address, get the register - * length (width) and the register name + * Get the 32-bit and 64-bit addresses, as well as the register + * length and register name. */ + address32 = *ACPI_ADD_PTR(u32, + &acpi_gbl_FADT, + fadt_info_table[i].address32); + address64 = ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, fadt_info_table[i].address64); - length = - *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, - fadt_info_table[i].length); + + length = *ACPI_ADD_PTR(u8, + &acpi_gbl_FADT, + fadt_info_table[i].length); + name = fadt_info_table[i].name; /* + * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" + * generic address structures as necessary. Later code will always use + * the 64-bit address structures. + * + * November 2013: + * Now always use the 64-bit address if it is valid (non-zero), in + * accordance with the ACPI specification which states that a 64-bit + * address supersedes the 32-bit version. This behavior can be + * overridden by the acpi_gbl_use32_bit_fadt_addresses flag. + * + * During 64-bit address construction and verification, + * these cases are handled: + * + * Address32 zero, Address64 [don't care] - Use Address64 + * + * Address32 non-zero, Address64 zero - Copy/use Address32 + * Address32 non-zero == Address64 non-zero - Use Address64 + * Address32 non-zero != Address64 non-zero - Warning, use Address64 + * + * Override: if acpi_gbl_use32_bit_fadt_addresses is TRUE, and: + * Address32 non-zero != Address64 non-zero - Warning, copy/use Address32 + * + * Note: space_id is always I/O for 32-bit legacy address fields + */ + if (address32) { + if (!address64->address) { + + /* 64-bit address is zero, use 32-bit address */ + + acpi_tb_init_generic_address(address64, + ACPI_ADR_SPACE_SYSTEM_IO, + *ACPI_ADD_PTR(u8, + &acpi_gbl_FADT, + fadt_info_table + [i]. + length), + (u64)address32, + name); + } else if (address64->address != (u64)address32) { + + /* Address mismatch */ + + ACPI_BIOS_WARNING((AE_INFO, + "32/64X address mismatch in FADT/%s: " + "0x%8.8X/0x%8.8X%8.8X, using %u-bit address", + name, address32, + ACPI_FORMAT_UINT64 + (address64->address), + acpi_gbl_use32_bit_fadt_addresses + ? 32 : 64)); + + if (acpi_gbl_use32_bit_fadt_addresses) { + + /* 32-bit address override */ + + acpi_tb_init_generic_address(address64, + ACPI_ADR_SPACE_SYSTEM_IO, + *ACPI_ADD_PTR + (u8, + &acpi_gbl_FADT, + fadt_info_table + [i]. + length), + (u64) + address32, + name); + } + } + } + + /* * For each extended field, check for length mismatch between the * legacy length field and the corresponding 64-bit X length field. * Note: If the legacy length field is > 0xFF bits, ignore this diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 3d6bb83aa7e7..6412d3c301cb 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -49,69 +49,11 @@ ACPI_MODULE_NAME("tbutils") /* Local prototypes */ +static acpi_status acpi_tb_validate_xsdt(acpi_physical_address address); + static acpi_physical_address acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); -/******************************************************************************* - * - * FUNCTION: acpi_tb_check_xsdt - * - * PARAMETERS: address - Pointer to the XSDT - * - * RETURN: status - * AE_OK - XSDT is okay - * AE_NO_MEMORY - can't map XSDT - * AE_INVALID_TABLE_LENGTH - invalid table length - * AE_NULL_ENTRY - XSDT has NULL entry - * - * DESCRIPTION: validate XSDT -******************************************************************************/ - -static acpi_status -acpi_tb_check_xsdt(acpi_physical_address address) -{ - struct acpi_table_header *table; - u32 length; - u64 xsdt_entry_address; - u8 *table_entry; - u32 table_count; - int i; - - table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); - if (!table) - return AE_NO_MEMORY; - - length = table->length; - acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); - if (length < sizeof(struct acpi_table_header)) - return AE_INVALID_TABLE_LENGTH; - - table = acpi_os_map_memory(address, length); - if (!table) - return AE_NO_MEMORY; - - /* Calculate the number of tables described in XSDT */ - table_count = - (u32) ((table->length - - sizeof(struct acpi_table_header)) / sizeof(u64)); - table_entry = - ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header); - for (i = 0; i < table_count; i++) { - ACPI_MOVE_64_TO_64(&xsdt_entry_address, table_entry); - if (!xsdt_entry_address) { - /* XSDT has NULL entry */ - break; - } - table_entry += sizeof(u64); - } - acpi_os_unmap_memory(table, length); - - if (i < table_count) - return AE_NULL_ENTRY; - else - return AE_OK; -} - #if (!ACPI_REDUCED_HARDWARE) /******************************************************************************* * @@ -383,7 +325,7 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size) * Get the table physical address (32-bit for RSDT, 64-bit for XSDT): * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT */ - if (table_entry_size == sizeof(u32)) { + if (table_entry_size == ACPI_RSDT_ENTRY_SIZE) { /* * 32-bit platform, RSDT: Return 32-bit table entry * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return @@ -415,6 +357,87 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size) /******************************************************************************* * + * FUNCTION: acpi_tb_validate_xsdt + * + * PARAMETERS: address - Physical address of the XSDT (from RSDP) + * + * RETURN: Status. AE_OK if the table appears to be valid. + * + * DESCRIPTION: Validate an XSDT to ensure that it is of minimum size and does + * not contain any NULL entries. A problem that is seen in the + * field is that the XSDT exists, but is actually useless because + * of one or more (or all) NULL entries. + * + ******************************************************************************/ + +static acpi_status acpi_tb_validate_xsdt(acpi_physical_address xsdt_address) +{ + struct acpi_table_header *table; + u8 *next_entry; + acpi_physical_address address; + u32 length; + u32 entry_count; + acpi_status status; + u32 i; + + /* Get the XSDT length */ + + table = + acpi_os_map_memory(xsdt_address, sizeof(struct acpi_table_header)); + if (!table) { + return (AE_NO_MEMORY); + } + + length = table->length; + acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); + + /* + * Minimum XSDT length is the size of the standard ACPI header + * plus one physical address entry + */ + if (length < (sizeof(struct acpi_table_header) + ACPI_XSDT_ENTRY_SIZE)) { + return (AE_INVALID_TABLE_LENGTH); + } + + /* Map the entire XSDT */ + + table = acpi_os_map_memory(xsdt_address, length); + if (!table) { + return (AE_NO_MEMORY); + } + + /* Get the number of entries and pointer to first entry */ + + status = AE_OK; + next_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header)); + entry_count = (u32)((table->length - sizeof(struct acpi_table_header)) / + ACPI_XSDT_ENTRY_SIZE); + + /* Validate each entry (physical address) within the XSDT */ + + for (i = 0; i < entry_count; i++) { + address = + acpi_tb_get_root_table_entry(next_entry, + ACPI_XSDT_ENTRY_SIZE); + if (!address) { + + /* Detected a NULL entry, XSDT is invalid */ + + status = AE_NULL_ENTRY; + break; + } + + next_entry += ACPI_XSDT_ENTRY_SIZE; + } + + /* Unmap table */ + + acpi_os_unmap_memory(table, length); + return (status); +} + +/******************************************************************************* + * * FUNCTION: acpi_tb_parse_root_table * * PARAMETERS: rsdp - Pointer to the RSDP @@ -438,16 +461,14 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) u32 table_count; struct acpi_table_header *table; acpi_physical_address address; - acpi_physical_address uninitialized_var(rsdt_address); u32 length; u8 *table_entry; acpi_status status; ACPI_FUNCTION_TRACE(tb_parse_root_table); - /* - * Map the entire RSDP and extract the address of the RSDT or XSDT - */ + /* Map the entire RSDP and extract the address of the RSDT or XSDT */ + rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp)); if (!rsdp) { return_ACPI_STATUS(AE_NO_MEMORY); @@ -457,24 +478,22 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) ACPI_CAST_PTR(struct acpi_table_header, rsdp)); - /* Differentiate between RSDT and XSDT root tables */ + /* Use XSDT if present and not overridden. Otherwise, use RSDT */ - if (rsdp->revision > 1 && rsdp->xsdt_physical_address - && !acpi_rsdt_forced) { + if ((rsdp->revision > 1) && + rsdp->xsdt_physical_address && !acpi_gbl_do_not_use_xsdt) { /* - * Root table is an XSDT (64-bit physical addresses). We must use the - * XSDT if the revision is > 1 and the XSDT pointer is present, as per - * the ACPI specification. + * RSDP contains an XSDT (64-bit physical addresses). We must use + * the XSDT if the revision is > 1 and the XSDT pointer is present, + * as per the ACPI specification. */ address = (acpi_physical_address) rsdp->xsdt_physical_address; - table_entry_size = sizeof(u64); - rsdt_address = (acpi_physical_address) - rsdp->rsdt_physical_address; + table_entry_size = ACPI_XSDT_ENTRY_SIZE; } else { /* Root table is an RSDT (32-bit physical addresses) */ address = (acpi_physical_address) rsdp->rsdt_physical_address; - table_entry_size = sizeof(u32); + table_entry_size = ACPI_RSDT_ENTRY_SIZE; } /* @@ -483,15 +502,25 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) */ acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp)); - if (table_entry_size == sizeof(u64)) { - if (acpi_tb_check_xsdt(address) == AE_NULL_ENTRY) { - /* XSDT has NULL entry, RSDT is used */ - address = rsdt_address; - table_entry_size = sizeof(u32); - ACPI_WARNING((AE_INFO, "BIOS XSDT has NULL entry, " - "using RSDT")); + /* + * If it is present and used, validate the XSDT for access/size + * and ensure that all table entries are at least non-NULL + */ + if (table_entry_size == ACPI_XSDT_ENTRY_SIZE) { + status = acpi_tb_validate_xsdt(address); + if (ACPI_FAILURE(status)) { + ACPI_BIOS_WARNING((AE_INFO, + "XSDT is invalid (%s), using RSDT", + acpi_format_exception(status))); + + /* Fall back to the RSDT */ + + address = + (acpi_physical_address) rsdp->rsdt_physical_address; + table_entry_size = ACPI_RSDT_ENTRY_SIZE; } } + /* Map the RSDT/XSDT table header to get the full table length */ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); @@ -501,12 +530,14 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) acpi_tb_print_table_header(address, table); - /* Get the length of the full table, verify length and map entire table */ - + /* + * Validate length of the table, and map entire table. + * Minimum length table must contain at least one entry. + */ length = table->length; acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); - if (length < sizeof(struct acpi_table_header)) { + if (length < (sizeof(struct acpi_table_header) + table_entry_size)) { ACPI_BIOS_ERROR((AE_INFO, "Invalid table length 0x%X in RSDT/XSDT", length)); @@ -526,22 +557,21 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) return_ACPI_STATUS(status); } - /* Calculate the number of tables described in the root table */ + /* Get the number of entries and pointer to first entry */ table_count = (u32)((table->length - sizeof(struct acpi_table_header)) / table_entry_size); + table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header)); + /* * First two entries in the table array are reserved for the DSDT * and FACS, which are not actually present in the RSDT/XSDT - they * come from the FADT */ - table_entry = - ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header); acpi_gbl_root_table_list.current_table_count = 2; - /* - * Initialize the root table array from the RSDT/XSDT - */ + /* Initialize the root table array from the RSDT/XSDT */ + for (i = 0; i < table_count; i++) { if (acpi_gbl_root_table_list.current_table_count >= acpi_gbl_root_table_list.max_table_count) { @@ -584,7 +614,7 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) acpi_tb_install_table(acpi_gbl_root_table_list.tables[i]. address, NULL, i); - /* Special case for FADT - get the DSDT and FACS */ + /* Special case for FADT - validate it then get the DSDT and FACS */ if (ACPI_COMPARE_NAME (&acpi_gbl_root_table_list.tables[i].signature, diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c index e0a2e2779c2e..2c2b6ae5dfc4 100644 --- a/drivers/acpi/acpica/utaddress.c +++ b/drivers/acpi/acpica/utaddress.c @@ -224,10 +224,11 @@ acpi_ut_check_address_range(acpi_adr_space_type space_id, while (range_info) { /* - * Check if the requested Address/Length overlaps this address_range. - * Four cases to consider: + * Check if the requested address/length overlaps this + * address range. There are four cases to consider: * - * 1) Input address/length is contained completely in the address range + * 1) Input address/length is contained completely in the + * address range * 2) Input address/length overlaps range at the range start * 3) Input address/length overlaps range at the range end * 4) Input address/length completely encompasses the range @@ -244,11 +245,17 @@ acpi_ut_check_address_range(acpi_adr_space_type space_id, region_node); ACPI_WARNING((AE_INFO, - "0x%p-0x%p %s conflicts with Region %s %d", + "%s range 0x%p-0x%p conflicts with OpRegion 0x%p-0x%p (%s)", + acpi_ut_get_region_name(space_id), ACPI_CAST_PTR(void, address), ACPI_CAST_PTR(void, end_address), - acpi_ut_get_region_name(space_id), - pathname, overlap_count)); + ACPI_CAST_PTR(void, + range_info-> + start_address), + ACPI_CAST_PTR(void, + range_info-> + end_address), + pathname)); ACPI_FREE(pathname); } } diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c index 814267f52715..1851762fc5b5 100644 --- a/drivers/acpi/acpica/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -302,9 +302,13 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer, return (AE_BUFFER_OVERFLOW); case ACPI_ALLOCATE_BUFFER: - - /* Allocate a new buffer */ - + /* + * Allocate a new buffer. We directectly call acpi_os_allocate here to + * purposefully bypass the (optionally enabled) internal allocation + * tracking mechanism since we only want to track internal + * allocations. Note: The caller should use acpi_os_free to free this + * buffer created via ACPI_ALLOCATE_BUFFER. + */ buffer->pointer = acpi_os_allocate(required_length); break; diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c index 366bfec4b770..cacd2fd9e665 100644 --- a/drivers/acpi/acpica/utcache.c +++ b/drivers/acpi/acpica/utcache.c @@ -248,12 +248,12 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache) ACPI_FUNCTION_NAME(os_acquire_object); if (!cache) { - return (NULL); + return_PTR(NULL); } status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); if (ACPI_FAILURE(status)) { - return (NULL); + return_PTR(NULL); } ACPI_MEM_TRACKING(cache->requests++); @@ -276,7 +276,7 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache) status = acpi_ut_release_mutex(ACPI_MTX_CACHES); if (ACPI_FAILURE(status)) { - return (NULL); + return_PTR(NULL); } /* Clear (zero) the previously used Object */ @@ -299,15 +299,15 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache) status = acpi_ut_release_mutex(ACPI_MTX_CACHES); if (ACPI_FAILURE(status)) { - return (NULL); + return_PTR(NULL); } object = ACPI_ALLOCATE_ZEROED(cache->object_size); if (!object) { - return (NULL); + return_PTR(NULL); } } - return (object); + return_PTR(object); } #endif /* ACPI_USE_LOCAL_CACHE */ diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 03ae8affe48f..d971c8631263 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -194,9 +194,9 @@ acpi_debug_print(u32 requested_debug_level, */ acpi_os_printf("%9s-%04ld ", module_name, line_number); -#ifdef ACPI_EXEC_APP +#ifdef ACPI_APPLICATION /* - * For acpi_exec only, emit the thread ID and nesting level. + * For acpi_exec/iASL only, emit the thread ID and nesting level. * Note: nesting level is really only useful during a single-thread * execution. Otherwise, multiple threads will keep resetting the * level. diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 81f9a9584451..030cb0dc673c 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -388,11 +388,7 @@ acpi_status acpi_ut_init_globals(void) /* Public globals */ ACPI_EXPORT_SYMBOL(acpi_gbl_FADT) - ACPI_EXPORT_SYMBOL(acpi_dbg_level) - ACPI_EXPORT_SYMBOL(acpi_dbg_layer) - ACPI_EXPORT_SYMBOL(acpi_gpe_count) - ACPI_EXPORT_SYMBOL(acpi_current_gpe_count) diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index 75efea0539c1..246ef68681f4 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -122,8 +122,16 @@ acpi_status __init acpi_initialize_subsystem(void) /* If configured, initialize the AML debugger */ - ACPI_DEBUGGER_EXEC(status = acpi_db_initialize()); - return_ACPI_STATUS(status); +#ifdef ACPI_DEBUGGER + status = acpi_db_initialize(); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "During Debugger initialization")); + return_ACPI_STATUS(status); + } +#endif + + return_ACPI_STATUS(AE_OK); } ACPI_EXPORT_SYMBOL_INIT(acpi_initialize_subsystem) diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index 786294bb682c..3650b2183227 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig @@ -2,7 +2,6 @@ config ACPI_APEI bool "ACPI Platform Error Interface (APEI)" select MISC_FILESYSTEMS select PSTORE - select EFI select UEFI_CPER depends on X86 help diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index 6d2c49b86b7f..8678dfe5366b 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -34,13 +34,13 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/acpi.h> -#include <linux/acpi_io.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/kref.h> #include <linux/rculist.h> #include <linux/interrupt.h> #include <linux/debugfs.h> +#include <asm/unaligned.h> #include "apei-internal.h" @@ -567,8 +567,7 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr, bit_offset = reg->bit_offset; access_size_code = reg->access_width; space_id = reg->space_id; - /* Handle possible alignment issues */ - memcpy(paddr, ®->address, sizeof(*paddr)); + *paddr = get_unaligned(®->address); if (!*paddr) { pr_warning(FW_BUG APEI_PFX "Invalid physical address in GAR [0x%llx/%u/%u/%u/%u]\n", diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index 21ba34a73883..e5bcd919d4e6 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -8,7 +8,6 @@ #include <linux/cper.h> #include <linux/acpi.h> -#include <linux/acpi_io.h> struct apei_exec_context; diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index fb57d03e698b..1be6f5564485 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -33,7 +33,7 @@ #include <linux/nmi.h> #include <linux/delay.h> #include <linux/mm.h> -#include <acpi/acpi.h> +#include <asm/unaligned.h> #include "apei-internal.h" @@ -216,7 +216,7 @@ static void check_vendor_extension(u64 paddr, static void *einj_get_parameter_address(void) { int i; - u64 paddrv4 = 0, paddrv5 = 0; + u64 pa_v4 = 0, pa_v5 = 0; struct acpi_whea_header *entry; entry = EINJ_TAB_ENTRY(einj_tab); @@ -225,30 +225,28 @@ static void *einj_get_parameter_address(void) entry->instruction == ACPI_EINJ_WRITE_REGISTER && entry->register_region.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) - memcpy(&paddrv4, &entry->register_region.address, - sizeof(paddrv4)); + pa_v4 = get_unaligned(&entry->register_region.address); if (entry->action == ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS && entry->instruction == ACPI_EINJ_WRITE_REGISTER && entry->register_region.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) - memcpy(&paddrv5, &entry->register_region.address, - sizeof(paddrv5)); + pa_v5 = get_unaligned(&entry->register_region.address); entry++; } - if (paddrv5) { + if (pa_v5) { struct set_error_type_with_address *v5param; - v5param = acpi_os_map_memory(paddrv5, sizeof(*v5param)); + v5param = acpi_os_map_memory(pa_v5, sizeof(*v5param)); if (v5param) { acpi5 = 1; - check_vendor_extension(paddrv5, v5param); + check_vendor_extension(pa_v5, v5param); return v5param; } } - if (param_extension && paddrv4) { + if (param_extension && pa_v4) { struct einj_parameter *v4param; - v4param = acpi_os_map_memory(paddrv4, sizeof(*v4param)); + v4param = acpi_os_map_memory(pa_v4, sizeof(*v4param)); if (!v4param) return NULL; if (v4param->reserved1 || v4param->reserved2) { @@ -416,7 +414,8 @@ out: return rc; } -static int __einj_error_inject(u32 type, u64 param1, u64 param2) +static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, + u64 param3, u64 param4) { struct apei_exec_context ctx; u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT; @@ -446,6 +445,12 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) break; } v5param->flags = vendor_flags; + } else if (flags) { + v5param->flags = flags; + v5param->memory_address = param1; + v5param->memory_address_range = param2; + v5param->apicid = param3; + v5param->pcie_sbdf = param4; } else { switch (type) { case ACPI_EINJ_PROCESSOR_CORRECTABLE: @@ -514,11 +519,17 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) } /* Inject the specified hardware error */ -static int einj_error_inject(u32 type, u64 param1, u64 param2) +static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, + u64 param3, u64 param4) { int rc; unsigned long pfn; + /* If user manually set "flags", make sure it is legal */ + if (flags && (flags & + ~(SETWA_FLAGS_APICID|SETWA_FLAGS_MEM|SETWA_FLAGS_PCIE_SBDF))) + return -EINVAL; + /* * We need extra sanity checks for memory errors. * Other types leap directly to injection. @@ -532,7 +543,7 @@ static int einj_error_inject(u32 type, u64 param1, u64 param2) if (type & ACPI5_VENDOR_BIT) { if (vendor_flags != SETWA_FLAGS_MEM) goto inject; - } else if (!(type & MEM_ERROR_MASK)) + } else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) goto inject; /* @@ -546,15 +557,18 @@ static int einj_error_inject(u32 type, u64 param1, u64 param2) inject: mutex_lock(&einj_mutex); - rc = __einj_error_inject(type, param1, param2); + rc = __einj_error_inject(type, flags, param1, param2, param3, param4); mutex_unlock(&einj_mutex); return rc; } static u32 error_type; +static u32 error_flags; static u64 error_param1; static u64 error_param2; +static u64 error_param3; +static u64 error_param4; static struct dentry *einj_debug_dir; static int available_error_type_show(struct seq_file *m, void *v) @@ -648,7 +662,8 @@ static int error_inject_set(void *data, u64 val) if (!error_type) return -EINVAL; - return einj_error_inject(error_type, error_param1, error_param2); + return einj_error_inject(error_type, error_flags, error_param1, error_param2, + error_param3, error_param4); } DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL, @@ -729,6 +744,10 @@ static int __init einj_init(void) rc = -ENOMEM; einj_param = einj_get_parameter_address(); if ((param_extension || acpi5) && einj_param) { + fentry = debugfs_create_x32("flags", S_IRUSR | S_IWUSR, + einj_debug_dir, &error_flags); + if (!fentry) + goto err_unmap; fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, einj_debug_dir, &error_param1); if (!fentry) @@ -737,6 +756,14 @@ static int __init einj_init(void) einj_debug_dir, &error_param2); if (!fentry) goto err_unmap; + fentry = debugfs_create_x64("param3", S_IRUSR | S_IWUSR, + einj_debug_dir, &error_param3); + if (!fentry) + goto err_unmap; + fentry = debugfs_create_x64("param4", S_IRUSR | S_IWUSR, + einj_debug_dir, &error_param4); + if (!fentry) + goto err_unmap; fentry = debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR, einj_debug_dir, ¬rigger); diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 26311f23c824..ed65e9c4b5b0 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -611,7 +611,7 @@ static void __erst_record_id_cache_compact(void) if (entries[i] == APEI_ERST_INVALID_RECORD_ID) continue; if (wpos != i) - memcpy(&entries[wpos], &entries[i], sizeof(entries[i])); + entries[wpos] = entries[i]; wpos++; } erst_record_id_cache.len = wpos; @@ -942,6 +942,7 @@ static int erst_clearer(enum pstore_type_id type, u64 id, int count, static struct pstore_info erst_info = { .owner = THIS_MODULE, .name = "erst", + .flags = PSTORE_FLAGS_FRAGILE, .open = erst_open_pstore, .close = erst_close_pstore, .read = erst_reader, diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index a30bc313787b..dab7cb7349df 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -33,7 +33,6 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/acpi.h> -#include <linux/acpi_io.h> #include <linux/io.h> #include <linux/interrupt.h> #include <linux/timer.h> @@ -413,27 +412,31 @@ static void ghes_handle_memory_failure(struct acpi_generic_data *gdata, int sev) { #ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE unsigned long pfn; + int flags = -1; int sec_sev = ghes_severity(gdata->error_severity); struct cper_sec_mem_err *mem_err; mem_err = (struct cper_sec_mem_err *)(gdata + 1); - if (sec_sev == GHES_SEV_CORRECTED && - (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED) && - (mem_err->validation_bits & CPER_MEM_VALID_PA)) { - pfn = mem_err->physical_addr >> PAGE_SHIFT; - if (pfn_valid(pfn)) - memory_failure_queue(pfn, 0, MF_SOFT_OFFLINE); - else if (printk_ratelimit()) - pr_warn(FW_WARN GHES_PFX - "Invalid address in generic error data: %#llx\n", - mem_err->physical_addr); - } - if (sev == GHES_SEV_RECOVERABLE && - sec_sev == GHES_SEV_RECOVERABLE && - mem_err->validation_bits & CPER_MEM_VALID_PA) { - pfn = mem_err->physical_addr >> PAGE_SHIFT; - memory_failure_queue(pfn, 0, 0); + if (!(mem_err->validation_bits & CPER_MEM_VALID_PA)) + return; + + pfn = mem_err->physical_addr >> PAGE_SHIFT; + if (!pfn_valid(pfn)) { + pr_warn_ratelimited(FW_WARN GHES_PFX + "Invalid address in generic error data: %#llx\n", + mem_err->physical_addr); + return; } + + /* iff following two events can be handled properly by now */ + if (sec_sev == GHES_SEV_CORRECTED && + (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED)) + flags = MF_SOFT_OFFLINE; + if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE) + flags = 0; + + if (flags != -1) + memory_failure_queue(pfn, 0, flags); #endif } @@ -453,8 +456,7 @@ static void ghes_do_proc(struct ghes *ghes, ghes_edac_report_mem_error(ghes, sev, mem_err); #ifdef CONFIG_X86_MCE - apei_mce_report_mem_error(sev == GHES_SEV_CORRECTED, - mem_err); + apei_mce_report_mem_error(sev, mem_err); #endif ghes_handle_memory_failure(gdata, sev); } diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index fbf1aceda8b8..797a6938d051 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -36,8 +36,7 @@ #include <linux/suspend.h> #include <asm/unaligned.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> #include <linux/power_supply.h> #define PREFIX "ACPI: " @@ -62,6 +61,7 @@ MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>"); MODULE_DESCRIPTION("ACPI Battery Driver"); MODULE_LICENSE("GPL"); +static int battery_bix_broken_package; static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); @@ -416,7 +416,12 @@ static int acpi_battery_get_info(struct acpi_battery *battery) ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s", name)); return -ENODEV; } - if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags)) + + if (battery_bix_broken_package) + result = extract_package(battery, buffer.pointer, + extended_info_offsets + 1, + ARRAY_SIZE(extended_info_offsets) - 1); + else if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags)) result = extract_package(battery, buffer.pointer, extended_info_offsets, ARRAY_SIZE(extended_info_offsets)); @@ -544,7 +549,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev, { unsigned long x; struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); - if (sscanf(buf, "%ld\n", &x) == 1) + if (sscanf(buf, "%lu\n", &x) == 1) battery->alarm = x/1000; if (acpi_battery_present(battery)) acpi_battery_set_alarm(battery); @@ -754,6 +759,17 @@ static int battery_notify(struct notifier_block *nb, return 0; } +static struct dmi_system_id bat_dmi_table[] = { + { + .ident = "NEC LZ750/LS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "NEC"), + DMI_MATCH(DMI_PRODUCT_NAME, "PC-LZ750LS"), + }, + }, + {}, +}; + static int acpi_battery_add(struct acpi_device *device) { int result = 0; @@ -825,6 +841,8 @@ static int acpi_battery_resume(struct device *dev) acpi_battery_update(battery); return 0; } +#else +#define acpi_battery_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume); @@ -846,6 +864,9 @@ static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie) { if (acpi_disabled) return; + + if (dmi_check_system(bat_dmi_table)) + battery_bix_broken_package = 1; acpi_bus_register_driver(&acpi_battery_driver); } diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 078c4f7fe2dd..afec4526c48a 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -30,7 +30,6 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/acpi.h> -#include <acpi/acpi_bus.h> #include <linux/dmi.h> #include "internal.h" @@ -261,14 +260,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { }, { .callback = dmi_disable_osi_win8, - .ident = "Dell Inspiron 15R SE", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7520"), - }, - }, - { - .callback = dmi_disable_osi_win8, .ident = "ThinkPad Edge E530", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index bba9b72e25f8..fcb59c21c68d 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -33,12 +33,11 @@ #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 <linux/pci.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> #include <acpi/apei.h> #include <linux/dmi.h> #include <linux/suspend.h> @@ -52,9 +51,6 @@ 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 static int set_copy_dsdt(const struct dmi_system_id *id) { @@ -115,18 +111,16 @@ int acpi_bus_get_status(struct acpi_device *device) if (ACPI_FAILURE(status)) return -ENODEV; - STRUCT_TO_INT(device->status) = (int) sta; + acpi_set_device_status(device, sta); if (device->status.functional && !device->status.present) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: " "functional but not present;\n", - device->pnp.bus_id, - (u32) STRUCT_TO_INT(device->status))); + 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); @@ -156,6 +150,16 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data) } EXPORT_SYMBOL(acpi_bus_get_private_data); +void acpi_bus_no_hotplug(acpi_handle handle) +{ + 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); + static void acpi_print_osc_error(acpi_handle handle, struct acpi_osc_context *context, char *error) { @@ -329,58 +333,6 @@ static void acpi_bus_osc_support(void) Notification Handling -------------------------------------------------------------------------- */ -static void acpi_bus_check_device(acpi_handle handle) -{ - struct acpi_device *device; - acpi_status status; - struct acpi_device_status old_status; - - if (acpi_bus_get_device(handle, &device)) - return; - if (!device) - return; - - 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; - return; - } - - status = acpi_bus_get_status(device); - if (ACPI_FAILURE(status)) - return; - - if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status)) - return; - - /* - * 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 */ - } -} - -static void acpi_bus_check_scope(acpi_handle handle) -{ - /* Status Change? */ - acpi_bus_check_device(handle); - - /* - * TBD: Enumerate child devices within this device's scope and - * run acpi_bus_check_device()'s on them. - */ -} - /** * acpi_bus_notify * --------------- @@ -397,19 +349,11 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) switch (type) { case ACPI_NOTIFY_BUS_CHECK: - acpi_bus_check_scope(handle); - /* - * TBD: We'll need to outsource certain events to non-ACPI - * drivers via the device manager (device.c). - */ + /* TBD */ break; case ACPI_NOTIFY_DEVICE_CHECK: - acpi_bus_check_device(handle); - /* - * TBD: We'll need to outsource certain events to non-ACPI - * drivers via the device manager (device.c). - */ + /* TBD */ break; case ACPI_NOTIFY_DEVICE_WAKE: @@ -566,6 +510,14 @@ void __init acpi_early_init(void) 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: diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index c971929d75c2..714e957a871a 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -31,8 +31,7 @@ #include <linux/seq_file.h> #include <linux/input.h> #include <linux/slab.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> #include <acpi/button.h> #define PREFIX "ACPI: " @@ -81,6 +80,8 @@ static void acpi_button_notify(struct acpi_device *device, u32 event); #ifdef CONFIG_PM_SLEEP static int acpi_button_resume(struct device *dev); +#else +#define acpi_button_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_button_pm, NULL, acpi_button_resume); @@ -101,7 +102,6 @@ struct acpi_button { struct input_dev *input; char phys[32]; /* for input device */ unsigned long pushed; - bool wakeup_enabled; }; static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); @@ -407,16 +407,6 @@ static int acpi_button_add(struct acpi_device *device) lid_device = device; } - if (device->wakeup.flags.valid) { - /* Button's GPE is run-wake GPE */ - acpi_enable_gpe(device->wakeup.gpe_device, - device->wakeup.gpe_number); - if (!device_may_wakeup(&device->dev)) { - device_set_wakeup_enable(&device->dev, true); - button->wakeup_enabled = true; - } - } - printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device)); return 0; @@ -433,13 +423,6 @@ static int acpi_button_remove(struct acpi_device *device) { struct acpi_button *button = acpi_driver_data(device); - if (device->wakeup.flags.valid) { - acpi_disable_gpe(device->wakeup.gpe_device, - device->wakeup.gpe_number); - if (button->wakeup_enabled) - device_set_wakeup_enable(&device->dev, false); - } - acpi_button_remove_fs(device); input_unregister_device(button->input); kfree(button); diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index e23151667655..368f9ddb8480 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -27,8 +27,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include <linux/acpi.h> - -#include "internal.h" +#include <linux/container.h> #include "internal.h" @@ -44,19 +43,66 @@ static const struct acpi_device_id container_device_ids[] = { {"", 0}, }; -static int container_device_attach(struct acpi_device *device, +static int acpi_container_offline(struct container_dev *cdev) +{ + struct acpi_device *adev = ACPI_COMPANION(&cdev->dev); + struct acpi_device *child; + + /* Check all of the dependent devices' physical companions. */ + list_for_each_entry(child, &adev->children, node) + if (!acpi_scan_is_offline(child, false)) + return -EBUSY; + + return 0; +} + +static void acpi_container_release(struct device *dev) +{ + kfree(to_container_dev(dev)); +} + +static int container_device_attach(struct acpi_device *adev, const struct acpi_device_id *not_used) { - /* This is necessary for container hotplug to work. */ + struct container_dev *cdev; + struct device *dev; + int ret; + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return -ENOMEM; + + cdev->offline = acpi_container_offline; + dev = &cdev->dev; + dev->bus = &container_subsys; + dev_set_name(dev, "%s", dev_name(&adev->dev)); + ACPI_COMPANION_SET(dev, adev); + dev->release = acpi_container_release; + ret = device_register(dev); + if (ret) { + put_device(dev); + return ret; + } + adev->driver_data = dev; return 1; } +static void container_device_detach(struct acpi_device *adev) +{ + struct device *dev = acpi_driver_data(adev); + + adev->driver_data = NULL; + if (dev) + device_unregister(dev); +} + static struct acpi_scan_handler container_handler = { .ids = container_device_ids, .attach = container_device_attach, + .detach = container_device_detach, .hotplug = { .enabled = true, - .mode = AHM_CONTAINER, + .demand_offline = true, }, }; diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c index 12b62f2cdb3f..c68e72414a67 100644 --- a/drivers/acpi/custom_method.c +++ b/drivers/acpi/custom_method.c @@ -7,7 +7,7 @@ #include <linux/kernel.h> #include <linux/uaccess.h> #include <linux/debugfs.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> #include "internal.h" diff --git a/drivers/acpi/debugfs.c b/drivers/acpi/debugfs.c index b55d6a20dc0e..6b1919f6bd82 100644 --- a/drivers/acpi/debugfs.c +++ b/drivers/acpi/debugfs.c @@ -5,7 +5,7 @@ #include <linux/export.h> #include <linux/init.h> #include <linux/debugfs.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("debugfs"); diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index b3480cf7db1a..c14a00d3dca6 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -256,6 +256,8 @@ int acpi_bus_init_power(struct acpi_device *device) return -EINVAL; device->power.state = ACPI_STATE_UNKNOWN; + if (!acpi_device_is_present(device)) + return 0; result = acpi_device_get_power(device, &state); if (result) @@ -302,15 +304,18 @@ int acpi_device_fix_up_power(struct acpi_device *device) return ret; } -int acpi_bus_update_power(acpi_handle handle, int *state_p) +int acpi_device_update_power(struct acpi_device *device, int *state_p) { - struct acpi_device *device; int state; int result; - result = acpi_bus_get_device(handle, &device); - if (result) + if (device->power.state == ACPI_STATE_UNKNOWN) { + result = acpi_bus_init_power(device); + if (!result && state_p) + *state_p = device->power.state; + return result; + } result = acpi_device_get_power(device, &state); if (result) @@ -338,6 +343,15 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p) return 0; } + +int acpi_bus_update_power(acpi_handle handle, int *state_p) +{ + struct acpi_device *device; + int result; + + result = acpi_bus_get_device(handle, &device); + return result ? result : acpi_device_update_power(device, state_p); +} EXPORT_SYMBOL_GPL(acpi_bus_update_power); bool acpi_bus_power_manageable(acpi_handle handle) @@ -713,18 +727,6 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable) #endif /* CONFIG_PM_SLEEP */ /** - * acpi_dev_pm_get_node - Get ACPI device node for the given physical device. - * @dev: Device to get the ACPI node for. - */ -struct acpi_device *acpi_dev_pm_get_node(struct device *dev) -{ - acpi_handle handle = ACPI_HANDLE(dev); - struct acpi_device *adev; - - return handle && !acpi_bus_get_device(handle, &adev) ? adev : NULL; -} - -/** * acpi_dev_pm_low_power - Put ACPI device into a low-power state. * @dev: Device to put into a low-power state. * @adev: ACPI device node corresponding to @dev. @@ -764,7 +766,7 @@ static int acpi_dev_pm_full_power(struct acpi_device *adev) */ int acpi_dev_runtime_suspend(struct device *dev) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); bool remote_wakeup; int error; @@ -795,7 +797,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_runtime_suspend); */ int acpi_dev_runtime_resume(struct device *dev) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); int error; if (!adev) @@ -848,7 +850,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_runtime_resume); */ int acpi_dev_suspend_late(struct device *dev) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); u32 target_state; bool wakeup; int error; @@ -880,7 +882,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_suspend_late); */ int acpi_dev_resume_early(struct device *dev) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); int error; if (!adev) @@ -971,7 +973,7 @@ static struct dev_pm_domain acpi_general_pm_domain = { */ int acpi_dev_pm_attach(struct device *dev, bool power_on) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); if (!adev) return -ENODEV; @@ -1003,7 +1005,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); */ void acpi_dev_pm_detach(struct device *dev, bool power_off) { - struct acpi_device *adev = acpi_dev_pm_get_node(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); if (adev && dev->pm_domain == &acpi_general_pm_domain) { dev->pm_domain = NULL; diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index dcd73ccb514c..5bfd769fc91f 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -32,8 +32,8 @@ #include <linux/jiffies.h> #include <linux/stddef.h> #include <linux/acpi.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> + +#include "internal.h" #define PREFIX "ACPI: " @@ -323,14 +323,11 @@ static int dock_present(struct dock_station *ds) */ static void dock_create_acpi_device(acpi_handle handle) { - struct acpi_device *device; + struct acpi_device *device = NULL; int ret; - if (acpi_bus_get_device(handle, &device)) { - /* - * no device created for this object, - * so we should create one. - */ + acpi_bus_get_device(handle, &device); + if (!acpi_device_enumerated(device)) { ret = acpi_bus_scan(handle); if (ret) pr_debug("error adding bus, %x\n", -ret); @@ -612,7 +609,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event) static void dock_notify(struct dock_station *ds, u32 event) { acpi_handle handle = ds->handle; - struct acpi_device *ad; + struct acpi_device *adev = NULL; int surprise_removal = 0; /* @@ -635,7 +632,8 @@ static void dock_notify(struct dock_station *ds, u32 event) switch (event) { case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: - if (!dock_in_progress(ds) && acpi_bus_get_device(handle, &ad)) { + acpi_bus_get_device(handle, &adev); + if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) { begin_dock(ds); dock(ds); if (!dock_present(ds)) { @@ -715,13 +713,11 @@ static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl, static ssize_t show_docked(struct device *dev, struct device_attribute *attr, char *buf) { - struct acpi_device *tmp; - struct dock_station *dock_station = dev->platform_data; + struct acpi_device *adev = NULL; - if (!acpi_bus_get_device(dock_station->handle, &tmp)) - return snprintf(buf, PAGE_SIZE, "1\n"); - return snprintf(buf, PAGE_SIZE, "0\n"); + acpi_bus_get_device(dock_station->handle, &adev); + return snprintf(buf, PAGE_SIZE, "%u\n", acpi_device_enumerated(adev)); } static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); @@ -898,9 +894,6 @@ find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv) void __init acpi_dock_init(void) { - if (acpi_disabled) - return; - /* look for dock stations and bays */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index ba5b56db9d27..d7d32c28829b 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -39,10 +39,9 @@ #include <linux/list.h> #include <linux/spinlock.h> #include <linux/slab.h> -#include <asm/io.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> #include <linux/dmi.h> +#include <asm/io.h> #include "internal.h" @@ -68,6 +67,8 @@ enum ec_command { #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ #define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */ +#define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query + * when trying to clear the EC */ enum { EC_FLAGS_QUERY_PENDING, /* Query is pending */ @@ -91,10 +92,6 @@ static unsigned int ec_storm_threshold __read_mostly = 8; module_param(ec_storm_threshold, uint, 0644); MODULE_PARM_DESC(ec_storm_threshold, "Maxim false GPE numbers not considered as GPE storm"); -/* If we find an EC via the ECDT, we need to keep a ptr to its context */ -/* External interfaces use first EC only, so remember */ -typedef int (*acpi_ec_query_func) (void *data); - struct acpi_ec_query_handler { struct list_head node; acpi_ec_query_func func; @@ -121,6 +118,7 @@ EXPORT_SYMBOL(first_ec); static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */ static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */ static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */ +static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ /* -------------------------------------------------------------------------- Transaction Management @@ -387,27 +385,6 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) return acpi_ec_transaction(ec, &t); } -/* - * Externally callable EC access functions. For now, assume 1 EC only - */ -int ec_burst_enable(void) -{ - if (!first_ec) - return -ENODEV; - return acpi_ec_burst_enable(first_ec); -} - -EXPORT_SYMBOL(ec_burst_enable); - -int ec_burst_disable(void) -{ - if (!first_ec) - return -ENODEV; - return acpi_ec_burst_disable(first_ec); -} - -EXPORT_SYMBOL(ec_burst_disable); - int ec_read(u8 addr, u8 *val) { int err; @@ -466,6 +443,29 @@ acpi_handle ec_get_handle(void) EXPORT_SYMBOL(ec_get_handle); +static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data); + +/* + * Clears stale _Q events that might have accumulated in the EC. + * Run with locked ec mutex. + */ +static void acpi_ec_clear(struct acpi_ec *ec) +{ + int i, status; + u8 value = 0; + + for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { + status = acpi_ec_query_unlocked(ec, &value); + if (status || !value) + break; + } + + if (unlikely(i == ACPI_EC_CLEAR_MAX)) + pr_warn("Warning: Maximum of %d stale EC events cleared\n", i); + else + pr_info("%d stale EC events cleared\n", i); +} + void acpi_ec_block_transactions(void) { struct acpi_ec *ec = first_ec; @@ -489,6 +489,10 @@ void acpi_ec_unblock_transactions(void) mutex_lock(&ec->mutex); /* Allow transactions to be carried out again */ clear_bit(EC_FLAGS_BLOCKED, &ec->flags); + + if (EC_FLAGS_CLEAR_ON_RESUME) + acpi_ec_clear(ec); + mutex_unlock(&ec->mutex); } @@ -779,9 +783,9 @@ static int ec_install_handlers(struct acpi_ec *ec) pr_err("Fail in evaluating the _REG object" " of EC device. Broken bios is suspected.\n"); } else { + acpi_disable_gpe(NULL, ec->gpe); acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); - acpi_disable_gpe(NULL, ec->gpe); return -ENODEV; } } @@ -847,6 +851,13 @@ static int acpi_ec_add(struct acpi_device *device) /* EC is fully operational, allow queries */ clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); + + /* Clear stale _Q events if hardware might require that */ + if (EC_FLAGS_CLEAR_ON_RESUME) { + mutex_lock(&ec->mutex); + acpi_ec_clear(ec); + mutex_unlock(&ec->mutex); + } return ret; } @@ -948,6 +959,30 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id) return 0; } +/* + * On some hardware it is necessary to clear events accumulated by the EC during + * sleep. These ECs stop reporting GPEs until they are manually polled, if too + * many events are accumulated. (e.g. Samsung Series 5/9 notebooks) + * + * https://bugzilla.kernel.org/show_bug.cgi?id=44161 + * + * Ideally, the EC should also be instructed NOT to accumulate events during + * sleep (which Windows seems to do somehow), but the interface to control this + * behaviour is not known at this time. + * + * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx, + * however it is very likely that other Samsung models are affected. + * + * On systems which don't accumulate _Q events during sleep, this extra check + * should be harmless. + */ +static int ec_clear_on_resume(const struct dmi_system_id *id) +{ + pr_debug("Detected system needing EC poll on resume.\n"); + EC_FLAGS_CLEAR_ON_RESUME = 1; + return 0; +} + static struct dmi_system_id ec_dmi_table[] __initdata = { { ec_skip_dsdt_scan, "Compal JFL92", { @@ -991,6 +1026,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = { ec_validate_ecdt, "ASUS hardware", { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL}, + { + ec_clear_on_resume, "Samsung hardware", { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL}, {}, }; diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index 4e7b798900f2..b4c216bab22b 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -105,7 +105,7 @@ static const struct file_operations acpi_ec_io_ops = { .llseek = default_llseek, }; -int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count) +static int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count) { struct dentry *dev_dir; char name[64]; diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index cae3b387b867..ef2d730734dc 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -12,7 +12,7 @@ #include <linux/init.h> #include <linux/poll.h> #include <linux/gfp.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> #include <net/netlink.h> #include <net/genetlink.h> diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index ba3da88cee45..09e423f3d8ad 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -29,8 +29,7 @@ #include <linux/types.h> #include <asm/uaccess.h> #include <linux/thermal.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> #define PREFIX "ACPI: " @@ -56,6 +55,9 @@ MODULE_DEVICE_TABLE(acpi, fan_device_ids); #ifdef CONFIG_PM_SLEEP static int acpi_fan_suspend(struct device *dev); static int acpi_fan_resume(struct device *dev); +#else +#define acpi_fan_suspend NULL +#define acpi_fan_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_fan_pm, acpi_fan_suspend, acpi_fan_resume); diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index a22a295edb69..0c789224d40d 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -37,7 +37,7 @@ int register_acpi_bus_type(struct acpi_bus_type *type) { if (acpi_disabled) return -ENODEV; - if (type && type->match && type->find_device) { + if (type && type->match && type->find_companion) { down_write(&bus_type_sem); list_add_tail(&type->list, &bus_type_list); up_write(&bus_type_sem); @@ -82,109 +82,74 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev) #define FIND_CHILD_MIN_SCORE 1 #define FIND_CHILD_MAX_SCORE 2 -static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used, - void *not_used, void **ret_p) -{ - struct acpi_device *adev = NULL; - - acpi_bus_get_device(handle, &adev); - if (adev) { - *ret_p = handle; - return AE_CTRL_TERMINATE; - } - return AE_OK; -} - -static int do_find_child_checks(acpi_handle handle, bool is_bridge) +static int find_child_checks(struct acpi_device *adev, bool check_children) { bool sta_present = true; unsigned long long sta; acpi_status status; - status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); if (status == AE_NOT_FOUND) sta_present = false; else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED)) return -ENODEV; - if (is_bridge) { - void *test = NULL; + if (check_children && list_empty(&adev->children)) + return -ENODEV; - /* Check if this object has at least one child device. */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, - acpi_dev_present, NULL, NULL, &test); - if (!test) - return -ENODEV; - } return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE; } -struct find_child_context { - u64 addr; - bool is_bridge; - acpi_handle ret; - int ret_score; -}; - -static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used, - void *data, void **not_used) -{ - struct find_child_context *context = data; - unsigned long long addr; - acpi_status status; - int score; - - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr); - if (ACPI_FAILURE(status) || addr != context->addr) - return AE_OK; - - if (!context->ret) { - /* This is the first matching object. Save its handle. */ - context->ret = handle; - return AE_OK; - } - /* - * There is more than one matching object with the same _ADR value. - * That really is unexpected, so we are kind of beyond the scope of the - * spec here. We have to choose which one to return, though. - * - * First, check if the previously found object is good enough and return - * its handle if so. Second, check the same for the object that we've - * just found. - */ - if (!context->ret_score) { - score = do_find_child_checks(context->ret, context->is_bridge); - if (score == FIND_CHILD_MAX_SCORE) - return AE_CTRL_TERMINATE; - else - context->ret_score = score; - } - score = do_find_child_checks(handle, context->is_bridge); - if (score == FIND_CHILD_MAX_SCORE) { - context->ret = handle; - return AE_CTRL_TERMINATE; - } else if (score > context->ret_score) { - context->ret = handle; - context->ret_score = score; - } - return AE_OK; -} - -acpi_handle acpi_find_child(acpi_handle parent, u64 addr, bool is_bridge) +struct acpi_device *acpi_find_child_device(struct acpi_device *parent, + u64 address, bool check_children) { - if (parent) { - struct find_child_context context = { - .addr = addr, - .is_bridge = is_bridge, - }; - - acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, do_find_child, - NULL, &context, NULL); - return context.ret; + struct acpi_device *adev, *ret = NULL; + int ret_score = 0; + + if (!parent) + return NULL; + + list_for_each_entry(adev, &parent->children, node) { + unsigned long long addr; + acpi_status status; + int score; + + status = acpi_evaluate_integer(adev->handle, METHOD_NAME__ADR, + NULL, &addr); + if (ACPI_FAILURE(status) || addr != address) + continue; + + if (!ret) { + /* This is the first matching object. Save it. */ + ret = adev; + continue; + } + /* + * There is more than one matching device object with the same + * _ADR value. That really is unexpected, so we are kind of + * beyond the scope of the spec here. We have to choose which + * one to return, though. + * + * First, check if the previously found object is good enough + * and return it if so. Second, do the same for the object that + * we've just found. + */ + if (!ret_score) { + ret_score = find_child_checks(ret, check_children); + if (ret_score == FIND_CHILD_MAX_SCORE) + return ret; + } + score = find_child_checks(adev, check_children); + if (score == FIND_CHILD_MAX_SCORE) { + return adev; + } else if (score > ret_score) { + ret = adev; + ret_score = score; + } } - return NULL; + return ret; } -EXPORT_SYMBOL_GPL(acpi_find_child); +EXPORT_SYMBOL_GPL(acpi_find_child_device); static void acpi_physnode_link_name(char *buf, unsigned int node_id) { @@ -195,9 +160,8 @@ static void acpi_physnode_link_name(char *buf, unsigned int node_id) strcpy(buf, PHYSICAL_NODE_STRING); } -int acpi_bind_one(struct device *dev, acpi_handle handle) +int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) { - struct acpi_device *acpi_dev = NULL; struct acpi_device_physical_node *physical_node, *pn; char physical_node_name[PHYSICAL_NODE_NAME_SIZE]; struct list_head *physnode_list; @@ -205,14 +169,12 @@ int acpi_bind_one(struct device *dev, acpi_handle handle) int retval = -EINVAL; if (ACPI_COMPANION(dev)) { - if (handle) { + if (acpi_dev) { dev_warn(dev, "ACPI companion already set\n"); return -EINVAL; } else { acpi_dev = ACPI_COMPANION(dev); } - } else { - acpi_bus_get_device(handle, &acpi_dev); } if (!acpi_dev) return -EINVAL; @@ -322,29 +284,22 @@ int acpi_unbind_one(struct device *dev) } EXPORT_SYMBOL_GPL(acpi_unbind_one); -void acpi_preset_companion(struct device *dev, acpi_handle parent, u64 addr) -{ - struct acpi_device *adev; - - if (!acpi_bus_get_device(acpi_get_child(parent, addr), &adev)) - ACPI_COMPANION_SET(dev, adev); -} -EXPORT_SYMBOL_GPL(acpi_preset_companion); - static int acpi_platform_notify(struct device *dev) { struct acpi_bus_type *type = acpi_get_bus_type(dev); - acpi_handle handle; int ret; ret = acpi_bind_one(dev, NULL); if (ret && type) { - ret = type->find_device(dev, &handle); - if (ret) { + struct acpi_device *adev; + + adev = type->find_companion(dev); + if (!adev) { DBG("Unable to get handle for %s\n", dev_name(dev)); + ret = -ENODEV; goto out; } - ret = acpi_bind_one(dev, handle); + ret = acpi_bind_one(dev, adev); if (ret) goto out; } diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c index 13b1d39d7cdf..aafe3ca829c2 100644 --- a/drivers/acpi/hed.c +++ b/drivers/acpi/hed.c @@ -25,8 +25,6 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/acpi.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> #include <acpi/hed.h> static struct acpi_device_id acpi_hed_ids[] = { diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index a29739c0ba79..dedbb2d802f1 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -28,7 +28,6 @@ int init_acpi_device_notify(void); int acpi_scan_init(void); void acpi_pci_root_init(void); void acpi_pci_link_init(void); -void acpi_pci_root_hp_init(void); void acpi_processor_init(void); void acpi_platform_init(void); int acpi_sysfs_init(void); @@ -73,6 +72,9 @@ void acpi_lpss_init(void); static inline void acpi_lpss_init(void) {} #endif +bool acpi_queue_hotplug_work(struct work_struct *work); +bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); + /* -------------------------------------------------------------------------- Device Node Initialization / Removal -------------------------------------------------------------------------- */ @@ -85,9 +87,9 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, int type, unsigned long long sta); void acpi_device_add_finalize(struct acpi_device *device); void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); -int acpi_bind_one(struct device *dev, acpi_handle handle); +int acpi_bind_one(struct device *dev, struct acpi_device *adev); int acpi_unbind_one(struct device *dev); -void acpi_bus_device_eject(void *data, u32 ost_src); +bool acpi_device_is_present(struct acpi_device *adev); /* -------------------------------------------------------------------------- Power Resource @@ -105,6 +107,8 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state); int acpi_power_on_resources(struct acpi_device *device, int state); int acpi_power_transition(struct acpi_device *device, int state); +int acpi_device_update_power(struct acpi_device *device, int *state_p); + int acpi_wakeup_device_init(void); void acpi_early_processor_set_pdc(void); @@ -127,12 +131,21 @@ struct acpi_ec { extern struct acpi_ec *first_ec; +/* If we find an EC via the ECDT, we need to keep a ptr to its context */ +/* External interfaces use first EC only, so remember */ +typedef int (*acpi_ec_query_func) (void *data); + int acpi_ec_init(void); int acpi_ec_ecdt_probe(void); int acpi_boot_ec_enable(void); void acpi_ec_block_transactions(void); void acpi_ec_unblock_transactions(void); void acpi_ec_unblock_transactions_early(void); +int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, + acpi_handle handle, acpi_ec_query_func func, + void *data); +void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit); + /*-------------------------------------------------------------------------- Suspend/Resume diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index a2343a1d9e0b..9e6816ef280a 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -29,7 +29,6 @@ #include <linux/errno.h> #include <linux/acpi.h> #include <linux/numa.h> -#include <acpi/acpi_bus.h> #define PREFIX "ACPI: " diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index 386a9fe497b4..de4fe03873c5 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -12,7 +12,8 @@ #include <linux/mm.h> #include <linux/slab.h> #include <linux/acpi.h> -#include <linux/acpi_io.h> + +#include "internal.h" /* ACPI NVS regions, APEI may use it */ diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 54a20ff4b864..fc1aa7909690 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -39,7 +39,6 @@ #include <linux/workqueue.h> #include <linux/nmi.h> #include <linux/acpi.h> -#include <linux/acpi_io.h> #include <linux/efi.h> #include <linux/ioport.h> #include <linux/list.h> @@ -49,9 +48,6 @@ #include <asm/io.h> #include <asm/uaccess.h> -#include <acpi/acpi.h> -#include <acpi/acpi_bus.h> -#include <acpi/processor.h> #include "internal.h" #define _COMPONENT ACPI_OS_SERVICES @@ -544,7 +540,7 @@ static u64 acpi_tables_addr; static int all_tables_size; /* Copied from acpica/tbutils.c:acpi_tb_checksum() */ -u8 __init acpi_table_checksum(u8 *buffer, u32 length) +static u8 __init acpi_table_checksum(u8 *buffer, u32 length) { u8 sum = 0; u8 *end = buffer + length; @@ -1215,6 +1211,10 @@ acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src) return AE_OK; } +bool acpi_queue_hotplug_work(struct work_struct *work) +{ + return queue_work(kacpi_hotplug_wq, work); +} acpi_status acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) @@ -1282,7 +1282,7 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) jiffies = MAX_SCHEDULE_TIMEOUT; else jiffies = msecs_to_jiffies(timeout); - + ret = down_timeout(sem, jiffies); if (ret) status = AE_TIME; @@ -1794,7 +1794,7 @@ acpi_status __init acpi_os_initialize1(void) { kacpid_wq = alloc_workqueue("kacpid", 0, 1); kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); - kacpi_hotplug_wq = alloc_workqueue("kacpi_hotplug", 0, 1); + kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0); BUG_ON(!kacpid_wq); BUG_ON(!kacpi_notify_wq); BUG_ON(!kacpi_hotplug_wq); diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 41c5e1b799ef..361b40c10c3f 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -37,8 +37,6 @@ #include <linux/pci.h> #include <linux/acpi.h> #include <linux/slab.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> #define PREFIX "ACPI: " @@ -432,6 +430,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) pin_name(pin)); } + kfree(entry); return 0; } diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 2652a614deeb..9418c7a1f786 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -39,9 +39,9 @@ #include <linux/pci.h> #include <linux/mutex.h> #include <linux/slab.h> +#include <linux/acpi.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> +#include "internal.h" #define PREFIX "ACPI: " diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 20360e480bd8..c1c4102e6478 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -35,9 +35,7 @@ #include <linux/pci-aspm.h> #include <linux/acpi.h> #include <linux/slab.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> -#include <acpi/apei.h> +#include <acpi/apei.h> /* for acpi_hest_init() */ #include "internal.h" @@ -51,6 +49,12 @@ static int acpi_pci_root_add(struct acpi_device *device, const struct acpi_device_id *not_used); static void acpi_pci_root_remove(struct acpi_device *device); +static int acpi_pci_root_scan_dependent(struct acpi_device *adev) +{ + acpiphp_check_host_bridge(adev->handle); + return 0; +} + #define ACPI_PCIE_REQ_SUPPORT (OSC_PCI_EXT_CONFIG_SUPPORT \ | OSC_PCI_ASPM_SUPPORT \ | OSC_PCI_CLOCK_PM_SUPPORT \ @@ -66,7 +70,8 @@ static struct acpi_scan_handler pci_root_handler = { .attach = acpi_pci_root_add, .detach = acpi_pci_root_remove, .hotplug = { - .ignore = true, + .enabled = true, + .scan_dependent = acpi_pci_root_scan_dependent, }, }; @@ -599,7 +604,9 @@ static int acpi_pci_root_add(struct acpi_device *device, pci_assign_unassigned_root_bus_resources(root->bus); } + pci_lock_rescan_remove(); pci_bus_add_devices(root->bus); + pci_unlock_rescan_remove(); return 1; end: @@ -611,6 +618,8 @@ static void acpi_pci_root_remove(struct acpi_device *device) { struct acpi_pci_root *root = acpi_driver_data(device); + pci_lock_rescan_remove(); + pci_stop_root_bus(root->bus); device_set_run_wake(root->bus->bridge, false); @@ -618,122 +627,17 @@ static void acpi_pci_root_remove(struct acpi_device *device) pci_remove_root_bus(root->bus); + pci_unlock_rescan_remove(); + kfree(root); } void __init acpi_pci_root_init(void) { acpi_hest_init(); - - if (!acpi_pci_disabled) { - pci_acpi_crs_quirks(); - acpi_scan_add_handler(&pci_root_handler); - } -} -/* Support root bridge hotplug */ - -static void handle_root_bridge_insertion(acpi_handle handle) -{ - struct acpi_device *device; - - if (!acpi_bus_get_device(handle, &device)) { - dev_printk(KERN_DEBUG, &device->dev, - "acpi device already exists; ignoring notify\n"); + if (acpi_pci_disabled) return; - } - - if (acpi_bus_scan(handle)) - acpi_handle_err(handle, "cannot add bridge to acpi list\n"); -} - -static void hotplug_event_root(void *data, u32 type) -{ - acpi_handle handle = data; - struct acpi_pci_root *root; - - acpi_scan_lock_acquire(); - - root = acpi_pci_find_root(handle); - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* bus enumerate */ - acpi_handle_printk(KERN_DEBUG, handle, - "Bus check notify on %s\n", __func__); - if (root) - acpiphp_check_host_bridge(handle); - else - handle_root_bridge_insertion(handle); - - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - /* device check */ - acpi_handle_printk(KERN_DEBUG, handle, - "Device check notify on %s\n", __func__); - if (!root) - handle_root_bridge_insertion(handle); - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - /* request device eject */ - acpi_handle_printk(KERN_DEBUG, handle, - "Device eject notify on %s\n", __func__); - if (!root) - break; - - get_device(&root->device->dev); - - acpi_scan_lock_release(); - - acpi_bus_device_eject(root->device, ACPI_NOTIFY_EJECT_REQUEST); - return; - default: - acpi_handle_warn(handle, - "notify_handler: unknown event type 0x%x\n", - type); - break; - } - - acpi_scan_lock_release(); -} - -static void handle_hotplug_event_root(acpi_handle handle, u32 type, - void *context) -{ - acpi_hotplug_execute(hotplug_event_root, handle, type); -} - -static acpi_status __init -find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - acpi_status status; - int *count = (int *)context; - - if (!acpi_is_root_bridge(handle)) - return AE_OK; - - (*count)++; - - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_root, NULL); - if (ACPI_FAILURE(status)) - acpi_handle_printk(KERN_DEBUG, handle, - "notify handler is not installed, exit status: %u\n", - (unsigned int)status); - else - acpi_handle_printk(KERN_DEBUG, handle, - "notify handler is installed\n"); - - return AE_OK; -} - -void __init acpi_pci_root_hp_init(void) -{ - int num = 0; - - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL); - printk(KERN_DEBUG "Found %d acpi root devices\n", num); + pci_acpi_crs_quirks(); + acpi_scan_add_handler_with_hotplug(&pci_root_handler, "pci_root"); } diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index d678a180ca2a..139d9e479370 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -35,6 +35,7 @@ #include <linux/pci.h> #include <linux/acpi.h> #include <linux/dmi.h> +#include <linux/pci-acpi.h> static bool debug; static int check_sta_before_sun; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index c2ad391d8041..ad7da686e6e6 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -42,8 +42,7 @@ #include <linux/slab.h> #include <linux/pm_runtime.h> #include <linux/sysfs.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> #include "sleep.h" #include "internal.h" diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index 6a5b152ad4d0..75c28eae8860 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -3,12 +3,11 @@ #include <linux/export.h> #include <linux/suspend.h> #include <linux/bcd.h> +#include <linux/acpi.h> #include <asm/uaccess.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> - #include "sleep.h" +#include "internal.h" #define _COMPONENT ACPI_SYSTEM_COMPONENT @@ -61,7 +60,7 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) seq_printf(seq, "%c%-8s %s:%s\n", dev->wakeup.flags.run_wake ? '*' : ' ', (device_may_wakeup(&dev->dev) || - (ldev && device_may_wakeup(ldev))) ? + device_may_wakeup(ldev)) ? "enabled" : "disabled", ldev->bus ? ldev->bus->name : "no-bus", dev_name(ldev)); diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index b3171f30b319..a4eea9a508d3 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -10,8 +10,7 @@ #include <linux/export.h> #include <linux/dmi.h> #include <linux/slab.h> - -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> #include <acpi/processor.h> #include "internal.h" @@ -45,13 +44,13 @@ static int map_lapic_id(struct acpi_subtable_header *entry, (struct acpi_madt_local_apic *)entry; if (!(lapic->lapic_flags & ACPI_MADT_ENABLED)) - return 0; + return -ENODEV; if (lapic->processor_id != acpi_id) - return 0; + return -EINVAL; *apic_id = lapic->id; - return 1; + return 0; } static int map_x2apic_id(struct acpi_subtable_header *entry, @@ -61,14 +60,14 @@ static int map_x2apic_id(struct acpi_subtable_header *entry, (struct acpi_madt_local_x2apic *)entry; if (!(apic->lapic_flags & ACPI_MADT_ENABLED)) - return 0; + return -ENODEV; if (device_declaration && (apic->uid == acpi_id)) { *apic_id = apic->local_apic_id; - return 1; + return 0; } - return 0; + return -EINVAL; } static int map_lsapic_id(struct acpi_subtable_header *entry, @@ -78,16 +77,16 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, (struct acpi_madt_local_sapic *)entry; if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED)) - return 0; + return -ENODEV; if (device_declaration) { if ((entry->length < 16) || (lsapic->uid != acpi_id)) - return 0; + return -EINVAL; } else if (lsapic->processor_id != acpi_id) - return 0; + return -EINVAL; *apic_id = (lsapic->id << 8) | lsapic->eid; - return 1; + return 0; } static int map_madt_entry(int type, u32 acpi_id) @@ -117,13 +116,13 @@ static int map_madt_entry(int type, u32 acpi_id) struct acpi_subtable_header *header = (struct acpi_subtable_header *)entry; if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) { - if (map_lapic_id(header, acpi_id, &apic_id)) + if (!map_lapic_id(header, acpi_id, &apic_id)) break; } else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) { - if (map_x2apic_id(header, type, acpi_id, &apic_id)) + if (!map_x2apic_id(header, type, acpi_id, &apic_id)) break; } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) { - if (map_lsapic_id(header, type, acpi_id, &apic_id)) + if (!map_lsapic_id(header, type, acpi_id, &apic_id)) break; } entry += header->length; diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 146ab7e2b81d..c1c35623550f 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -224,9 +224,9 @@ static int __acpi_processor_start(struct acpi_device *device) static int acpi_processor_start(struct device *dev) { - struct acpi_device *device; + struct acpi_device *device = ACPI_COMPANION(dev); - if (acpi_bus_get_device(ACPI_HANDLE(dev), &device)) + if (!device) return -ENODEV; return __acpi_processor_start(device); @@ -234,10 +234,10 @@ static int acpi_processor_start(struct device *dev) static int acpi_processor_stop(struct device *dev) { - struct acpi_device *device; + struct acpi_device *device = ACPI_COMPANION(dev); struct acpi_processor *pr; - if (acpi_bus_get_device(ACPI_HANDLE(dev), &device)) + if (!device) return 0; acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 644516d9bde6..3dca36d4ad26 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -35,6 +35,7 @@ #include <linux/clockchips.h> #include <linux/cpuidle.h> #include <linux/syscore_ops.h> +#include <acpi/processor.h> /* * Include the apic definitions for x86 to have the APIC timer related defines @@ -46,9 +47,6 @@ #include <asm/apic.h> #endif -#include <acpi/acpi_bus.h> -#include <acpi/processor.h> - #define PREFIX "ACPI: " #define ACPI_PROCESSOR_CLASS "processor" @@ -213,7 +211,7 @@ static int acpi_processor_suspend(void) static void acpi_processor_resume(void) { - u32 resumed_bm_rld; + u32 resumed_bm_rld = 0; acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &resumed_bm_rld); if (resumed_bm_rld == saved_bm_rld) @@ -598,7 +596,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) case ACPI_STATE_C2: if (!cx->address) break; - cx->valid = 1; + cx->valid = 1; break; case ACPI_STATE_C3: @@ -727,11 +725,6 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, if (unlikely(!pr)) return -EINVAL; - if (cx->entry_method == ACPI_CSTATE_FFH) { - if (current_set_polling_and_test()) - return -EINVAL; - } - lapic_timer_state_broadcast(pr, cx, 1); acpi_idle_do_entry(cx); @@ -785,10 +778,12 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (unlikely(!pr)) return -EINVAL; - if (cx->entry_method == ACPI_CSTATE_FFH) { - if (current_set_polling_and_test()) - return -EINVAL; - } +#ifdef CONFIG_HOTPLUG_CPU + if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && + !pr->flags.has_cst && + !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) + return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START); +#endif /* * Must be done before busmaster disable as we might need to @@ -831,6 +826,13 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, if (unlikely(!pr)) return -EINVAL; +#ifdef CONFIG_HOTPLUG_CPU + if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && + !pr->flags.has_cst && + !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) + return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START); +#endif + if (!cx->bm_sts_skip && acpi_idle_bm_check()) { if (drv->safe_state_index >= 0) { return drv->states[drv->safe_state_index].enter(dev, @@ -841,11 +843,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, } } - if (cx->entry_method == ACPI_CSTATE_FFH) { - if (current_set_polling_and_test()) - return -EINVAL; - } - acpi_unlazy_tlb(smp_processor_id()); /* Tell the scheduler that we are going deep-idle: */ @@ -932,12 +929,6 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr, if (!cx->valid) continue; -#ifdef CONFIG_HOTPLUG_CPU - if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && - !pr->flags.has_cst && - !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) - continue; -#endif per_cpu(acpi_cstate[count], dev->cpu) = cx; count++; @@ -945,8 +936,6 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr, break; } - dev->state_count = count; - if (!count) return -EINVAL; @@ -987,13 +976,6 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) if (!cx->valid) continue; -#ifdef CONFIG_HOTPLUG_CPU - if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && - !pr->flags.has_cst && - !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) - continue; -#endif - state = &drv->states[count]; snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 60a7c28fc167..ff90054f04fd 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -31,15 +31,12 @@ #include <linux/init.h> #include <linux/cpufreq.h> #include <linux/slab.h> - +#include <linux/acpi.h> +#include <acpi/processor.h> #ifdef CONFIG_X86 #include <asm/cpufeature.h> #endif -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> -#include <acpi/processor.h> - #define PREFIX "ACPI: " #define ACPI_PROCESSOR_CLASS "processor" diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index d1d2e7fb5b30..e003663b2f8e 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -30,12 +30,9 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/cpufreq.h> - -#include <asm/uaccess.h> - -#include <acpi/acpi_bus.h> +#include <linux/acpi.h> #include <acpi/processor.h> -#include <acpi/acpi_drivers.h> +#include <asm/uaccess.h> #define PREFIX "ACPI: " @@ -186,14 +183,14 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state) #endif -/* thermal coolign device callbacks */ +/* thermal cooling device callbacks */ static int acpi_processor_max_state(struct acpi_processor *pr) { int max_state = 0; /* * There exists four states according to - * cpufreq_thermal_reduction_ptg. 0, 1, 2, 3 + * cpufreq_thermal_reduction_pctg. 0, 1, 2, 3 */ max_state += cpufreq_get_max_state(pr->id); if (pr->flags.throttling) diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index e7dd2c1fee79..84243c32e29c 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -32,14 +32,11 @@ #include <linux/init.h> #include <linux/sched.h> #include <linux/cpufreq.h> - +#include <linux/acpi.h> +#include <acpi/processor.h> #include <asm/io.h> #include <asm/uaccess.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> -#include <acpi/processor.h> - #define PREFIX "ACPI: " #define ACPI_PROCESSOR_CLASS "processor" @@ -59,6 +56,12 @@ struct throttling_tstate { int target_state; /* target T-state */ }; +struct acpi_processor_throttling_arg { + struct acpi_processor *pr; + int target_state; + bool force; +}; + #define THROTTLING_PRECHANGE (1) #define THROTTLING_POSTCHANGE (2) @@ -1063,16 +1066,24 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr, return 0; } +static long acpi_processor_throttling_fn(void *data) +{ + struct acpi_processor_throttling_arg *arg = data; + struct acpi_processor *pr = arg->pr; + + return pr->throttling.acpi_processor_set_throttling(pr, + arg->target_state, arg->force); +} + int acpi_processor_set_throttling(struct acpi_processor *pr, int state, bool force) { - cpumask_var_t saved_mask; int ret = 0; unsigned int i; struct acpi_processor *match_pr; struct acpi_processor_throttling *p_throttling; + struct acpi_processor_throttling_arg arg; struct throttling_tstate t_state; - cpumask_var_t online_throttling_cpus; if (!pr) return -EINVAL; @@ -1083,14 +1094,6 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, if ((state < 0) || (state > (pr->throttling.state_count - 1))) return -EINVAL; - if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL)) - return -ENOMEM; - - if (!alloc_cpumask_var(&online_throttling_cpus, GFP_KERNEL)) { - free_cpumask_var(saved_mask); - return -ENOMEM; - } - if (cpu_is_offline(pr->id)) { /* * the cpu pointed by pr->id is offline. Unnecessary to change @@ -1099,17 +1102,15 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, return -ENODEV; } - cpumask_copy(saved_mask, ¤t->cpus_allowed); t_state.target_state = state; p_throttling = &(pr->throttling); - cpumask_and(online_throttling_cpus, cpu_online_mask, - p_throttling->shared_cpu_map); + /* * The throttling notifier will be called for every * affected cpu in order to get one proper T-state. * The notifier event is THROTTLING_PRECHANGE. */ - for_each_cpu(i, online_throttling_cpus) { + for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) { t_state.cpu = i; acpi_processor_throttling_notifier(THROTTLING_PRECHANGE, &t_state); @@ -1121,21 +1122,18 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, * it can be called only for the cpu pointed by pr. */ if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { - /* FIXME: use work_on_cpu() */ - if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { - /* Can't migrate to the pr->id CPU. Exit */ - ret = -ENODEV; - goto exit; - } - ret = p_throttling->acpi_processor_set_throttling(pr, - t_state.target_state, force); + arg.pr = pr; + arg.target_state = state; + arg.force = force; + ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg); } else { /* * When the T-state coordination is SW_ALL or HW_ALL, * it is necessary to set T-state for every affected * cpus. */ - for_each_cpu(i, online_throttling_cpus) { + for_each_cpu_and(i, cpu_online_mask, + p_throttling->shared_cpu_map) { match_pr = per_cpu(processors, i); /* * If the pointer is invalid, we will report the @@ -1156,13 +1154,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, "on CPU %d\n", i)); continue; } - t_state.cpu = i; - /* FIXME: use work_on_cpu() */ - if (set_cpus_allowed_ptr(current, cpumask_of(i))) - continue; - ret = match_pr->throttling. - acpi_processor_set_throttling( - match_pr, t_state.target_state, force); + + arg.pr = match_pr; + arg.target_state = state; + arg.force = force; + ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, + &arg); } } /* @@ -1171,17 +1168,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, * affected cpu to update the T-states. * The notifier event is THROTTLING_POSTCHANGE */ - for_each_cpu(i, online_throttling_cpus) { + for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) { t_state.cpu = i; acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE, &t_state); } - /* restore the previous state */ - /* FIXME: use work_on_cpu() */ - set_cpus_allowed_ptr(current, saved_mask); -exit: - free_cpumask_var(online_throttling_cpus); - free_cpumask_var(saved_mask); + return ret; } diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index b7201fc6f1e1..0bdacc5e26a3 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -77,18 +77,24 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) switch (ares->type) { case ACPI_RESOURCE_TYPE_MEMORY24: memory24 = &ares->data.memory24; + if (!memory24->address_length) + return false; acpi_dev_get_memresource(res, memory24->minimum, memory24->address_length, memory24->write_protect); break; case ACPI_RESOURCE_TYPE_MEMORY32: memory32 = &ares->data.memory32; + if (!memory32->address_length) + return false; acpi_dev_get_memresource(res, memory32->minimum, memory32->address_length, memory32->write_protect); break; case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: fixed_memory32 = &ares->data.fixed_memory32; + if (!fixed_memory32->address_length) + return false; acpi_dev_get_memresource(res, fixed_memory32->address, fixed_memory32->address_length, fixed_memory32->write_protect); @@ -144,12 +150,16 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) switch (ares->type) { case ACPI_RESOURCE_TYPE_IO: io = &ares->data.io; + if (!io->address_length) + return false; acpi_dev_get_ioresource(res, io->minimum, io->address_length, io->io_decode); break; case ACPI_RESOURCE_TYPE_FIXED_IO: fixed_io = &ares->data.fixed_io; + if (!fixed_io->address_length) + return false; acpi_dev_get_ioresource(res, fixed_io->address, fixed_io->address_length, ACPI_DECODE_10); diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index d465ae6cdd00..dbd48498b938 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -450,7 +450,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev, { unsigned long x; struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); - if (sscanf(buf, "%ld\n", &x) == 1) + if (sscanf(buf, "%lu\n", &x) == 1) battery->alarm_capacity = x / (1000 * acpi_battery_scale(battery)); if (battery->present) @@ -668,6 +668,8 @@ static int acpi_sbs_resume(struct device *dev) acpi_sbs_callback(sbs); return 0; } +#else +#define acpi_sbs_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_sbs_pm, NULL, acpi_sbs_resume); diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index b78bc605837e..26e5b5060523 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -8,8 +8,7 @@ * the Free Software Foundation version 2. */ -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> #include <linux/wait.h> #include <linux/slab.h> #include <linux/delay.h> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fd39459926b1..57b053f424d1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -12,13 +12,12 @@ #include <linux/dmi.h> #include <linux/nls.h> -#include <acpi/acpi_drivers.h> +#include <asm/pgtable.h> #include "internal.h" #define _COMPONENT ACPI_BUS_COMPONENT ACPI_MODULE_NAME("scan"); -#define STRUCT_TO_INT(s) (*((int*)&s)) extern struct acpi_device *acpi_root; #define ACPI_BUS_CLASS "system_bus" @@ -27,6 +26,8 @@ extern struct acpi_device *acpi_root; #define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent) +#define INVALID_ACPI_HANDLE ((acpi_handle)empty_zero_page) + /* * If set, devices will be hot-removed even if they cannot be put offline * gracefully (from the kernel's standpoint). @@ -85,6 +86,9 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, * Creates hid/cid(s) string needed for modalias and uevent * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: * char *modalias: "acpi:IBM0001:ACPI0001" + * Return: 0: no _HID and no _CID + * -EINVAL: output error + * -ENOMEM: output is truncated */ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, int size) @@ -101,8 +105,10 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, list_for_each_entry(id, &acpi_dev->pnp.ids, list) { count = snprintf(&modalias[len], size, "%s:", id->id); - if (count < 0 || count >= size) - return -EINVAL; + if (count < 0) + return EINVAL; + if (count >= size) + return -ENOMEM; len += count; size -= count; } @@ -111,20 +117,96 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, return len; } +/* + * Creates uevent modalias field for ACPI enumerated devices. + * Because the other buses does not support ACPI HIDs & CIDs. + * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get: + * "acpi:IBM0001:ACPI0001" + */ +int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) +{ + struct acpi_device *acpi_dev; + int len; + + acpi_dev = ACPI_COMPANION(dev); + if (!acpi_dev) + return -ENODEV; + + /* Fall back to bus specific way of modalias exporting */ + if (list_empty(&acpi_dev->pnp.ids)) + return -ENODEV; + + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len <= 0) + return len; + env->buflen += len; + return 0; +} +EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias); + +/* + * Creates modalias sysfs attribute for ACPI enumerated devices. + * Because the other buses does not support ACPI HIDs & CIDs. + * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get: + * "acpi:IBM0001:ACPI0001" + */ +int acpi_device_modalias(struct device *dev, char *buf, int size) +{ + struct acpi_device *acpi_dev; + int len; + + acpi_dev = ACPI_COMPANION(dev); + if (!acpi_dev) + return -ENODEV; + + /* Fall back to bus specific way of modalias exporting */ + if (list_empty(&acpi_dev->pnp.ids)) + return -ENODEV; + + len = create_modalias(acpi_dev, buf, size -1); + if (len <= 0) + return len; + buf[len++] = '\n'; + return len; +} +EXPORT_SYMBOL_GPL(acpi_device_modalias); + static ssize_t acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { struct acpi_device *acpi_dev = to_acpi_device(dev); int len; - /* Device has no HID and no CID or string is >1024 */ len = create_modalias(acpi_dev, buf, 1024); if (len <= 0) - return 0; + return len; buf[len++] = '\n'; return len; } static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); +bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent) +{ + struct acpi_device_physical_node *pn; + bool offline = true; + + mutex_lock(&adev->physical_node_lock); + + list_for_each_entry(pn, &adev->physical_node_list, node) + if (device_supports_offline(pn->dev) && !pn->dev->offline) { + if (uevent) + kobject_uevent(&pn->dev->kobj, KOBJ_CHANGE); + + offline = false; + break; + } + + mutex_unlock(&adev->physical_node_lock); + return offline; +} + static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data, void **ret_p) { @@ -195,19 +277,11 @@ static acpi_status acpi_bus_online(acpi_handle handle, u32 lvl, void *data, return AE_OK; } -static int acpi_scan_hot_remove(struct acpi_device *device) +static int acpi_scan_try_to_offline(struct acpi_device *device) { acpi_handle handle = device->handle; - struct device *errdev; + struct device *errdev = NULL; acpi_status status; - unsigned long long sta; - - /* If there is no handle, the device node has been unregistered. */ - if (!handle) { - dev_dbg(&device->dev, "ACPI handle missing\n"); - put_device(&device->dev); - return -EINVAL; - } /* * Carry out two passes here and ignore errors in the first pass, @@ -218,7 +292,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) * * If the first pass is successful, the second one isn't needed, though. */ - errdev = NULL; status = acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, NULL, acpi_bus_offline, (void *)false, (void **)&errdev); @@ -226,7 +299,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) dev_warn(errdev, "Offline disabled.\n"); acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, acpi_bus_online, NULL, NULL, NULL); - put_device(&device->dev); return -EPERM; } acpi_bus_offline(handle, 0, (void *)false, (void **)&errdev); @@ -245,20 +317,32 @@ static int acpi_scan_hot_remove(struct acpi_device *device) acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, acpi_bus_online, NULL, NULL, NULL); - put_device(&device->dev); return -EBUSY; } } + return 0; +} + +static int acpi_scan_hot_remove(struct acpi_device *device) +{ + acpi_handle handle = device->handle; + unsigned long long sta; + acpi_status status; + + if (device->handler->hotplug.demand_offline && !acpi_force_hot_remove) { + if (!acpi_scan_is_offline(device, true)) + return -EBUSY; + } else { + int error = acpi_scan_try_to_offline(device); + if (error) + return error; + } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Hot-removing device %s...\n", dev_name(&device->dev))); acpi_bus_trim(device); - /* Device node has been unregistered. */ - put_device(&device->dev); - device = NULL; - acpi_evaluate_lck(handle, 0); /* * TBD: _EJD support. @@ -285,115 +369,126 @@ static int acpi_scan_hot_remove(struct acpi_device *device) return 0; } -void acpi_bus_device_eject(void *data, u32 ost_src) +static int acpi_scan_device_not_present(struct acpi_device *adev) { - struct acpi_device *device = data; - acpi_handle handle = device->handle; - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - int error; + if (!acpi_device_enumerated(adev)) { + dev_warn(&adev->dev, "Still not present\n"); + return -EALREADY; + } + acpi_bus_trim(adev); + return 0; +} - lock_device_hotplug(); - mutex_lock(&acpi_scan_lock); +static int acpi_scan_device_check(struct acpi_device *adev) +{ + int error; - if (ost_src == ACPI_NOTIFY_EJECT_REQUEST) - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); + acpi_bus_get_status(adev); + if (adev->status.present || adev->status.functional) { + /* + * This function is only called for device objects for which + * matching scan handlers exist. The only situation in which + * the scan handler is not attached to this device object yet + * is when the device has just appeared (either it wasn't + * present at all before or it was removed and then added + * again). + */ + if (adev->handler) { + dev_warn(&adev->dev, "Already enumerated\n"); + return -EALREADY; + } + error = acpi_bus_scan(adev->handle); + if (error) { + dev_warn(&adev->dev, "Namespace scan failure\n"); + return error; + } + if (!adev->handler) { + dev_warn(&adev->dev, "Enumeration failure\n"); + error = -ENODEV; + } + } else { + error = acpi_scan_device_not_present(adev); + } + return error; +} - if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER) - kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); +static int acpi_scan_bus_check(struct acpi_device *adev) +{ + struct acpi_scan_handler *handler = adev->handler; + struct acpi_device *child; + int error; - error = acpi_scan_hot_remove(device); - if (error == -EPERM) { - goto err_support; - } else if (error) { - goto err_out; + acpi_bus_get_status(adev); + if (!(adev->status.present || adev->status.functional)) { + acpi_scan_device_not_present(adev); + return 0; } + if (handler && handler->hotplug.scan_dependent) + return handler->hotplug.scan_dependent(adev); - out: - mutex_unlock(&acpi_scan_lock); - unlock_device_hotplug(); - return; - - err_support: - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - err_out: - acpi_evaluate_hotplug_ost(handle, ost_src, ost_code, NULL); - goto out; + error = acpi_bus_scan(adev->handle); + if (error) { + dev_warn(&adev->dev, "Namespace scan failure\n"); + return error; + } + list_for_each_entry(child, &adev->children, node) { + error = acpi_scan_bus_check(child); + if (error) + return error; + } + return 0; } -static void acpi_scan_bus_device_check(void *data, u32 ost_source) +static void acpi_device_hotplug(void *data, u32 src) { - acpi_handle handle = data; - struct acpi_device *device = NULL; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; + struct acpi_device *adev = data; int error; lock_device_hotplug(); mutex_lock(&acpi_scan_lock); - if (ost_source != ACPI_NOTIFY_BUS_CHECK) { - acpi_bus_get_device(handle, &device); - if (device) { - dev_warn(&device->dev, "Attempt to re-insert\n"); - goto out; - } - } - error = acpi_bus_scan(handle); - if (error) { - acpi_handle_warn(handle, "Namespace scan failure\n"); - goto out; - } - error = acpi_bus_get_device(handle, &device); - if (error) { - acpi_handle_warn(handle, "Missing device node object\n"); + /* + * The device object's ACPI handle cannot become invalid as long as we + * are holding acpi_scan_lock, but it may have become invalid before + * that lock was acquired. + */ + if (adev->handle == INVALID_ACPI_HANDLE) goto out; - } - ost_code = ACPI_OST_SC_SUCCESS; - if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER) - kobject_uevent(&device->dev.kobj, KOBJ_ONLINE); - out: - acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL); - mutex_unlock(&acpi_scan_lock); - unlock_device_hotplug(); -} - -static void acpi_hotplug_unsupported(acpi_handle handle, u32 type) -{ - u32 ost_status; - - switch (type) { + switch (src) { case ACPI_NOTIFY_BUS_CHECK: - acpi_handle_debug(handle, - "ACPI_NOTIFY_BUS_CHECK event: unsupported\n"); - ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED; + error = acpi_scan_bus_check(adev); break; case ACPI_NOTIFY_DEVICE_CHECK: - acpi_handle_debug(handle, - "ACPI_NOTIFY_DEVICE_CHECK event: unsupported\n"); - ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED; + error = acpi_scan_device_check(adev); break; case ACPI_NOTIFY_EJECT_REQUEST: - acpi_handle_debug(handle, - "ACPI_NOTIFY_EJECT_REQUEST event: unsupported\n"); - ost_status = ACPI_OST_SC_EJECT_NOT_SUPPORTED; + case ACPI_OST_EC_OSPM_EJECT: + error = acpi_scan_hot_remove(adev); break; default: - /* non-hotplug event; possibly handled by other handler */ - return; + error = -EINVAL; + break; } + if (!error) + ost_code = ACPI_OST_SC_SUCCESS; - acpi_evaluate_hotplug_ost(handle, type, ost_status, NULL); + out: + acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL); + put_device(&adev->dev); + mutex_unlock(&acpi_scan_lock); + unlock_device_hotplug(); } static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) { - struct acpi_scan_handler *handler = data; + u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_device *adev; acpi_status status; - if (!handler->hotplug.enabled) - return acpi_hotplug_unsupported(handle, type); + if (acpi_bus_get_device(handle, &adev)) + goto err_out; switch (type) { case ACPI_NOTIFY_BUS_CHECK: @@ -404,27 +499,30 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data) break; case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - if (acpi_bus_get_device(handle, &adev)) + if (!adev->handler) goto err_out; - get_device(&adev->dev); - status = acpi_hotplug_execute(acpi_bus_device_eject, adev, type); - if (ACPI_SUCCESS(status)) - return; - - put_device(&adev->dev); - goto err_out; + if (!adev->handler->hotplug.enabled) { + acpi_handle_err(handle, "Eject disabled\n"); + ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; + goto err_out; + } + acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, + ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); + break; default: /* non-hotplug event; possibly handled by other handler */ return; } - status = acpi_hotplug_execute(acpi_scan_bus_device_check, handle, type); + get_device(&adev->dev); + status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); if (ACPI_SUCCESS(status)) return; + put_device(&adev->dev); + err_out: - acpi_evaluate_hotplug_ost(handle, type, - ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); + acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); } static ssize_t real_power_state_show(struct device *dev, @@ -475,7 +573,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); get_device(&acpi_device->dev); - status = acpi_hotplug_execute(acpi_bus_device_eject, acpi_device, + status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device, ACPI_OST_EC_OSPM_EJECT); if (ACPI_SUCCESS(status)) return count; @@ -567,6 +665,20 @@ acpi_device_sun_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL); +static ssize_t status_show(struct device *dev, struct device_attribute *attr, + char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + acpi_status status; + unsigned long long sta; + + status = acpi_evaluate_integer(acpi_dev->handle, "_STA", NULL, &sta); + if (ACPI_FAILURE(status)) + return -ENODEV; + + return sprintf(buf, "%llu\n", sta); +} +static DEVICE_ATTR_RO(status); + static int acpi_device_setup_files(struct acpi_device *dev) { struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; @@ -622,6 +734,12 @@ static int acpi_device_setup_files(struct acpi_device *dev) dev->pnp.sun = (unsigned long)-1; } + if (acpi_has_method(dev->handle, "_STA")) { + result = device_create_file(&dev->dev, &dev_attr_status); + if (result) + goto end; + } + /* * If device has _EJ0, 'eject' file is created that is used to trigger * hot-removal function from userland. @@ -677,6 +795,8 @@ static void acpi_device_remove_files(struct acpi_device *dev) device_remove_file(&dev->dev, &dev_attr_adr); device_remove_file(&dev->dev, &dev_attr_modalias); device_remove_file(&dev->dev, &dev_attr_hid); + if (acpi_has_method(dev->handle, "_STA")) + device_remove_file(&dev->dev, &dev_attr_status); if (dev->handle) device_remove_file(&dev->dev, &dev_attr_path); } @@ -782,8 +902,8 @@ static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) return -ENOMEM; len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], sizeof(env->buf) - env->buflen); - if (len >= (sizeof(env->buf) - env->buflen)) - return -ENOMEM; + if (len <= 0) + return len; env->buflen += len; return 0; } @@ -907,9 +1027,91 @@ struct bus_type acpi_bus_type = { .uevent = acpi_device_uevent, }; -static void acpi_bus_data_handler(acpi_handle handle, void *context) +static void acpi_device_del(struct acpi_device *device) +{ + mutex_lock(&acpi_device_lock); + if (device->parent) + list_del(&device->node); + + list_del(&device->wakeup_list); + mutex_unlock(&acpi_device_lock); + + acpi_power_add_remove_device(device, false); + acpi_device_remove_files(device); + if (device->remove) + device->remove(device); + + device_del(&device->dev); +} + +static LIST_HEAD(acpi_device_del_list); +static DEFINE_MUTEX(acpi_device_del_lock); + +static void acpi_device_del_work_fn(struct work_struct *work_not_used) +{ + for (;;) { + struct acpi_device *adev; + + mutex_lock(&acpi_device_del_lock); + + if (list_empty(&acpi_device_del_list)) { + mutex_unlock(&acpi_device_del_lock); + break; + } + adev = list_first_entry(&acpi_device_del_list, + struct acpi_device, del_list); + list_del(&adev->del_list); + + mutex_unlock(&acpi_device_del_lock); + + acpi_device_del(adev); + /* + * Drop references to all power resources that might have been + * used by the device. + */ + acpi_power_transition(adev, ACPI_STATE_D3_COLD); + put_device(&adev->dev); + } +} + +/** + * acpi_scan_drop_device - Drop an ACPI device object. + * @handle: Handle of an ACPI namespace node, not used. + * @context: Address of the ACPI device object to drop. + * + * This is invoked by acpi_ns_delete_node() during the removal of the ACPI + * namespace node the device object pointed to by @context is attached to. + * + * The unregistration is carried out asynchronously to avoid running + * acpi_device_del() under the ACPICA's namespace mutex and the list is used to + * ensure the correct ordering (the device objects must be unregistered in the + * same order in which the corresponding namespace nodes are deleted). + */ +static void acpi_scan_drop_device(acpi_handle handle, void *context) { - /* Intentionally empty. */ + static DECLARE_WORK(work, acpi_device_del_work_fn); + struct acpi_device *adev = context; + + mutex_lock(&acpi_device_del_lock); + + /* + * Use the ACPI hotplug workqueue which is ordered, so this work item + * won't run after any hotplug work items submitted subsequently. That + * prevents attempts to register device objects identical to those being + * deleted from happening concurrently (such attempts result from + * hotplug events handled via the ACPI hotplug workqueue). It also will + * run after all of the work items submitted previosuly, which helps + * those work items to ensure that they are not accessing stale device + * objects. + */ + if (list_empty(&acpi_device_del_list)) + acpi_queue_hotplug_work(&work); + + list_add_tail(&adev->del_list, &acpi_device_del_list); + /* Make acpi_ns_validate_handle() return NULL for this handle. */ + adev->handle = INVALID_ACPI_HANDLE; + + mutex_unlock(&acpi_device_del_lock); } int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) @@ -919,7 +1121,7 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) if (!device) return -EINVAL; - status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device); + status = acpi_get_data(handle, acpi_scan_drop_device, (void **)device); if (ACPI_FAILURE(status) || !*device) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", handle)); @@ -939,7 +1141,7 @@ int acpi_device_add(struct acpi_device *device, if (device->handle) { acpi_status status; - status = acpi_attach_data(device->handle, acpi_bus_data_handler, + status = acpi_attach_data(device->handle, acpi_scan_drop_device, device); if (ACPI_FAILURE(status)) { acpi_handle_err(device->handle, @@ -957,6 +1159,7 @@ int acpi_device_add(struct acpi_device *device, INIT_LIST_HEAD(&device->node); INIT_LIST_HEAD(&device->wakeup_list); INIT_LIST_HEAD(&device->physical_node_list); + INIT_LIST_HEAD(&device->del_list); mutex_init(&device->physical_node_lock); new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); @@ -1020,37 +1223,10 @@ int acpi_device_add(struct acpi_device *device, mutex_unlock(&acpi_device_lock); err_detach: - acpi_detach_data(device->handle, acpi_bus_data_handler); + acpi_detach_data(device->handle, acpi_scan_drop_device); return result; } -static void acpi_device_unregister(struct acpi_device *device) -{ - mutex_lock(&acpi_device_lock); - if (device->parent) - list_del(&device->node); - - list_del(&device->wakeup_list); - mutex_unlock(&acpi_device_lock); - - acpi_detach_data(device->handle, acpi_bus_data_handler); - - acpi_power_add_remove_device(device, false); - acpi_device_remove_files(device); - if (device->remove) - device->remove(device); - - device_del(&device->dev); - /* - * Transition the device to D3cold to drop the reference counts of all - * power resources the device depends on and turn off the ones that have - * no more references. - */ - acpi_device_set_power(device, ACPI_STATE_D3_COLD); - device->handle = NULL; - put_device(&device->dev); -} - /* -------------------------------------------------------------------------- Driver Management -------------------------------------------------------------------------- */ @@ -1624,11 +1800,13 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, device->device_type = type; device->handle = handle; device->parent = acpi_bus_get_parent(handle); - STRUCT_TO_INT(device->status) = sta; + acpi_set_device_status(device, sta); acpi_device_get_busid(device); acpi_set_pnp_ids(handle, &device->pnp, type); acpi_bus_get_flags(device); device->flags.match_driver = false; + device->flags.initialized = true; + device->flags.visited = false; device_initialize(&device->dev); dev_set_uevent_suppress(&device->dev, true); } @@ -1713,6 +1891,15 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, return 0; } +bool acpi_device_is_present(struct acpi_device *adev) +{ + if (adev->status.present || adev->status.functional) + return true; + + adev->flags.initialized = false; + return false; +} + static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler, char *idstr, const struct acpi_device_id **matchid) @@ -1772,7 +1959,7 @@ static void acpi_scan_init_hotplug(acpi_handle handle, int type) */ list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); - if (handler && !handler->hotplug.ignore) { + if (handler) { acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, acpi_hotplug_notify_cb, handler); break; @@ -1806,18 +1993,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, acpi_scan_init_hotplug(handle, type); - if (!(sta & ACPI_STA_DEVICE_PRESENT) && - !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { - struct acpi_device_wakeup wakeup; - - if (acpi_has_method(handle, "_PRW")) { - acpi_bus_extract_wakeup_device_power_package(handle, - &wakeup); - acpi_power_resources_list_free(&wakeup.resources); - } - return AE_CTRL_DEPTH; - } - acpi_add_single_object(&device, handle, type, sta); if (!device) return AE_CTRL_DEPTH; @@ -1852,36 +2027,40 @@ static int acpi_scan_attach_handler(struct acpi_device *device) return ret; } -static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, - void *not_used, void **ret_not_used) +static void acpi_bus_attach(struct acpi_device *device) { - struct acpi_device *device; - unsigned long long sta_not_used; + struct acpi_device *child; int ret; - /* - * Ignore errors ignored by acpi_bus_check_add() to avoid terminating - * namespace walks prematurely. - */ - if (acpi_bus_type_and_status(handle, &ret, &sta_not_used)) - return AE_OK; - - if (acpi_bus_get_device(handle, &device)) - return AE_CTRL_DEPTH; - + acpi_bus_get_status(device); + /* Skip devices that are not present. */ + if (!acpi_device_is_present(device)) { + device->flags.visited = false; + return; + } if (device->handler) - return AE_OK; + goto ok; + if (!device->flags.initialized) { + acpi_bus_update_power(device, NULL); + device->flags.initialized = true; + } + device->flags.visited = false; ret = acpi_scan_attach_handler(device); if (ret < 0) - return AE_CTRL_DEPTH; + return; device->flags.match_driver = true; - if (ret > 0) - return AE_OK; + if (!ret) { + ret = device_attach(&device->dev); + if (ret < 0) + return; + } + device->flags.visited = true; - ret = device_attach(&device->dev); - return ret >= 0 ? AE_OK : AE_CTRL_DEPTH; + ok: + list_for_each_entry(child, &device->children, node) + acpi_bus_attach(child); } /** @@ -1901,75 +2080,49 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, int acpi_bus_scan(acpi_handle handle) { void *device = NULL; - int error = 0; if (ACPI_SUCCESS(acpi_bus_check_add(handle, 0, NULL, &device))) acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, acpi_bus_check_add, NULL, NULL, &device); - if (!device) - error = -ENODEV; - else if (ACPI_SUCCESS(acpi_bus_device_attach(handle, 0, NULL, NULL))) - acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, - acpi_bus_device_attach, NULL, NULL, NULL); - - return error; -} -EXPORT_SYMBOL(acpi_bus_scan); - -static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used, - void *not_used, void **ret_not_used) -{ - struct acpi_device *device = NULL; - - if (!acpi_bus_get_device(handle, &device)) { - struct acpi_scan_handler *dev_handler = device->handler; - - if (dev_handler) { - if (dev_handler->detach) - dev_handler->detach(device); - - device->handler = NULL; - } else { - device_release_driver(&device->dev); - } + if (device) { + acpi_bus_attach(device); + return 0; } - return AE_OK; -} - -static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used, - void *not_used, void **ret_not_used) -{ - struct acpi_device *device = NULL; - - if (!acpi_bus_get_device(handle, &device)) - acpi_device_unregister(device); - - return AE_OK; + return -ENODEV; } +EXPORT_SYMBOL(acpi_bus_scan); /** - * acpi_bus_trim - Remove ACPI device node and all of its descendants - * @start: Root of the ACPI device nodes subtree to remove. + * acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects. + * @adev: Root of the ACPI namespace scope to walk. * * Must be called under acpi_scan_lock. */ -void acpi_bus_trim(struct acpi_device *start) +void acpi_bus_trim(struct acpi_device *adev) { + struct acpi_scan_handler *handler = adev->handler; + struct acpi_device *child; + + list_for_each_entry_reverse(child, &adev->children, node) + acpi_bus_trim(child); + + adev->flags.match_driver = false; + if (handler) { + if (handler->detach) + handler->detach(adev); + + adev->handler = NULL; + } else { + device_release_driver(&adev->dev); + } /* - * Execute acpi_bus_device_detach() as a post-order callback to detach - * all ACPI drivers from the device nodes being removed. - */ - acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL, - acpi_bus_device_detach, NULL, NULL); - acpi_bus_device_detach(start->handle, 0, NULL, NULL); - /* - * Execute acpi_bus_remove() as a post-order callback to remove device - * nodes in the given namespace scope. + * Most likely, the device is going away, so put it into D3cold before + * that. */ - acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL, - acpi_bus_remove, NULL, NULL); - acpi_bus_remove(start->handle, 0, NULL, NULL); + acpi_device_set_power(adev, ACPI_STATE_D3_COLD); + adev->flags.initialized = false; + adev->flags.visited = false; } EXPORT_SYMBOL_GPL(acpi_bus_trim); @@ -2047,14 +2200,14 @@ int __init acpi_scan_init(void) result = acpi_bus_scan_fixed(); if (result) { - acpi_device_unregister(acpi_root); + acpi_detach_data(acpi_root->handle, acpi_scan_drop_device); + acpi_device_del(acpi_root); + put_device(&acpi_root->dev); goto out; } acpi_update_all_gpes(); - acpi_pci_root_hp_init(); - out: mutex_unlock(&acpi_scan_lock); return result; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 721e949e606e..c40fb2e81bbc 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -18,12 +18,8 @@ #include <linux/reboot.h> #include <linux/acpi.h> #include <linux/module.h> - #include <asm/io.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> - #include "internal.h" #include "sleep.h" @@ -75,6 +71,17 @@ static int acpi_sleep_prepare(u32 acpi_state) return 0; } +static bool acpi_sleep_state_supported(u8 sleep_state) +{ + acpi_status status; + u8 type_a, type_b; + + status = acpi_get_sleep_type_data(sleep_state, &type_a, &type_b); + return ACPI_SUCCESS(status) && (!acpi_gbl_reduced_hardware + || (acpi_gbl_FADT.sleep_control.address + && acpi_gbl_FADT.sleep_status.address)); +} + #ifdef CONFIG_ACPI_SLEEP static u32 acpi_target_sleep_state = ACPI_STATE_S0; @@ -608,15 +615,9 @@ static void acpi_sleep_suspend_setup(void) { int i; - for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) { - acpi_status status; - u8 type_a, type_b; - - status = acpi_get_sleep_type_data(i, &type_a, &type_b); - if (ACPI_SUCCESS(status)) { + for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) + if (acpi_sleep_state_supported(i)) sleep_states[i] = 1; - } - } suspend_set_ops(old_suspend_ordering ? &acpi_suspend_ops_old : &acpi_suspend_ops); @@ -670,11 +671,8 @@ static void acpi_hibernation_leave(void) /* Reprogram control registers */ acpi_leave_sleep_state_prep(ACPI_STATE_S4); /* Check the hardware signature */ - if (facs && s4_hardware_signature != facs->hardware_signature) { - printk(KERN_EMERG "ACPI: Hardware changed while hibernated, " - "cannot resume!\n"); - panic("ACPI S4 hardware signature mismatch"); - } + if (facs && s4_hardware_signature != facs->hardware_signature) + pr_crit("ACPI: Hardware changed while hibernated, success doubtful!\n"); /* Restore the NVS memory area */ suspend_nvs_restore(); /* Allow EC transactions to happen. */ @@ -747,11 +745,7 @@ static const struct platform_hibernation_ops acpi_hibernation_ops_old = { static void acpi_sleep_hibernate_setup(void) { - acpi_status status; - u8 type_a, type_b; - - status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b); - if (ACPI_FAILURE(status)) + if (!acpi_sleep_state_supported(ACPI_STATE_S4)) return; hibernation_set_ops(old_suspend_ordering ? @@ -800,15 +794,10 @@ static void acpi_power_off(void) int __init acpi_sleep_init(void) { - acpi_status status; - u8 type_a, type_b; char supported[ACPI_S_STATE_COUNT * 3 + 1]; char *pos = supported; int i; - if (acpi_disabled) - return 0; - acpi_sleep_dmi_check(); sleep_states[ACPI_STATE_S0] = 1; @@ -816,8 +805,7 @@ int __init acpi_sleep_init(void) acpi_sleep_suspend_setup(); acpi_sleep_hibernate_setup(); - status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); - if (ACPI_SUCCESS(status)) { + if (acpi_sleep_state_supported(ACPI_STATE_S5)) { sleep_states[ACPI_STATE_S5] = 1; pm_power_off_prepare = acpi_power_off_prepare; pm_power_off = acpi_power_off; diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 6dbc3ca45223..91a32cefb11f 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -5,7 +5,7 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/moduleparam.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> #include "internal.h" @@ -226,7 +226,7 @@ module_param_call(trace_state, param_set_trace_state, param_get_trace_state, /* /sys/modules/acpi/parameters/aml_debug_output */ module_param_named(aml_debug_output, acpi_gbl_enable_aml_debug_object, - bool, 0644); + byte, 0644); MODULE_PARM_DESC(aml_debug_output, "To enable/disable the ACPI Debug Object output."); diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index d67a1fe07f0e..5837f857ac2e 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -278,12 +278,13 @@ acpi_table_parse_madt(enum acpi_madt_type id, /** * acpi_table_parse - find table with @id, run @handler on it - * * @id: table id to find * @handler: handler to run * * Scan the ACPI System Descriptor Table (STD) for a table matching @id, - * run @handler on it. Return 0 if table found, return on if not. + * run @handler on it. + * + * Return 0 if table found, -errno if not. */ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) { @@ -293,7 +294,7 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) if (acpi_disabled) return -ENODEV; - if (!handler) + if (!id || !handler) return -EINVAL; if (strncmp(id, ACPI_SIG_MADT, 4) == 0) @@ -306,7 +307,7 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) early_acpi_os_unmap_memory(table, tbl_size); return 0; } else - return 1; + return -ENODEV; } /* @@ -351,7 +352,7 @@ int __init acpi_table_init(void) status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); if (ACPI_FAILURE(status)) - return 1; + return -EINVAL; check_multiple_madt(); return 0; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 0d9f46b5ae6d..08626c851be7 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -41,10 +41,9 @@ #include <linux/kmod.h> #include <linux/reboot.h> #include <linux/device.h> -#include <asm/uaccess.h> #include <linux/thermal.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> +#include <asm/uaccess.h> #define PREFIX "ACPI: " @@ -103,6 +102,8 @@ MODULE_DEVICE_TABLE(acpi, thermal_device_ids); #ifdef CONFIG_PM_SLEEP static int acpi_thermal_resume(struct device *dev); +#else +#define acpi_thermal_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume); @@ -862,7 +863,7 @@ acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal, return acpi_thermal_cooling_device_cb(thermal, cdev, false); } -static const struct thermal_zone_device_ops acpi_thermal_zone_ops = { +static struct thermal_zone_device_ops acpi_thermal_zone_ops = { .bind = acpi_thermal_bind_cooling_device, .unbind = acpi_thermal_unbind_cooling_device, .get_temp = thermal_get_temp, diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 6d408bfbbb1d..85e3b612bdc0 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -30,8 +30,6 @@ #include <linux/types.h> #include <linux/hardirq.h> #include <linux/acpi.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> #include "internal.h" @@ -101,10 +99,6 @@ acpi_extract_package(union acpi_object *package, union acpi_object *element = &(package->package.elements[i]); - if (!element) { - return AE_BAD_DATA; - } - switch (element->type) { case ACPI_TYPE_INTEGER: @@ -574,3 +568,100 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock) return status; } + +/** + * acpi_evaluate_dsm - evaluate device's _DSM method + * @handle: ACPI device handle + * @uuid: UUID of requested functions, should be 16 bytes + * @rev: revision number of requested function + * @func: requested function number + * @argv4: the function specific parameter + * + * Evaluate device's _DSM method with specified UUID, revision id and + * function number. Caller needs to free the returned object. + * + * Though ACPI defines the fourth parameter for _DSM should be a package, + * some old BIOSes do expect a buffer or an integer etc. + */ +union acpi_object * +acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, int rev, int func, + union acpi_object *argv4) +{ + acpi_status ret; + struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object params[4]; + struct acpi_object_list input = { + .count = 4, + .pointer = params, + }; + + params[0].type = ACPI_TYPE_BUFFER; + params[0].buffer.length = 16; + params[0].buffer.pointer = (char *)uuid; + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = rev; + params[2].type = ACPI_TYPE_INTEGER; + params[2].integer.value = func; + if (argv4) { + params[3] = *argv4; + } else { + params[3].type = ACPI_TYPE_PACKAGE; + params[3].package.count = 0; + params[3].package.elements = NULL; + } + + ret = acpi_evaluate_object(handle, "_DSM", &input, &buf); + if (ACPI_SUCCESS(ret)) + return (union acpi_object *)buf.pointer; + + if (ret != AE_NOT_FOUND) + acpi_handle_warn(handle, + "failed to evaluate _DSM (0x%x)\n", ret); + + return NULL; +} +EXPORT_SYMBOL(acpi_evaluate_dsm); + +/** + * acpi_check_dsm - check if _DSM method supports requested functions. + * @handle: ACPI device handle + * @uuid: UUID of requested functions, should be 16 bytes at least + * @rev: revision number of requested functions + * @funcs: bitmap of requested functions + * @exclude: excluding special value, used to support i915 and nouveau + * + * Evaluate device's _DSM method to check whether it supports requested + * functions. Currently only support 64 functions at maximum, should be + * enough for now. + */ +bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs) +{ + int i; + u64 mask = 0; + union acpi_object *obj; + + if (funcs == 0) + return false; + + obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL); + if (!obj) + return false; + + /* For compatibility, old BIOSes may return an integer */ + if (obj->type == ACPI_TYPE_INTEGER) + mask = obj->integer.value; + else if (obj->type == ACPI_TYPE_BUFFER) + for (i = 0; i < obj->buffer.length && i < 8; i++) + mask |= (((u8)obj->buffer.pointer[i]) << (i * 8)); + ACPI_FREE(obj); + + /* + * Bit 0 indicates whether there's support for any functions other than + * function 0 for the specified UUID and revision. + */ + if ((mask & 0x1) && (mask & funcs) == funcs) + return true; + + return false; +} +EXPORT_SYMBOL(acpi_check_dsm); diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 995e91bcb97b..b6ba88ed31ae 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -37,12 +37,11 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> -#include <asm/uaccess.h> #include <linux/dmi.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> #include <linux/suspend.h> +#include <linux/acpi.h> #include <acpi/video.h> +#include <asm/uaccess.h> #include "internal.h" @@ -82,11 +81,12 @@ static bool allow_duplicates; module_param(allow_duplicates, bool, 0644); /* - * For Windows 8 systems: if set ture and the GPU driver has - * registered a backlight interface, skip registering ACPI video's. + * For Windows 8 systems: used to decide if video module + * should skip registering backlight interface of its own. */ -static bool use_native_backlight = false; -module_param(use_native_backlight, bool, 0644); +static int use_native_backlight_param = -1; +module_param_named(use_native_backlight, use_native_backlight_param, int, 0444); +static bool use_native_backlight_dmi = false; static int register_count; static struct mutex video_list_lock; @@ -232,9 +232,17 @@ static int acpi_video_get_next_level(struct acpi_video_device *device, static int acpi_video_switch_brightness(struct acpi_video_device *device, int event); +static bool acpi_video_use_native_backlight(void) +{ + if (use_native_backlight_param != -1) + return use_native_backlight_param; + else + return use_native_backlight_dmi; +} + static bool acpi_video_verify_backlight_support(void) { - if (acpi_osi_is_win8() && use_native_backlight && + if (acpi_osi_is_win8() && acpi_video_use_native_backlight() && backlight_device_registered(BACKLIGHT_RAW)) return false; return acpi_video_backlight_support(); @@ -399,6 +407,12 @@ static int __init video_set_bqc_offset(const struct dmi_system_id *d) return 0; } +static int __init video_set_use_native_backlight(const struct dmi_system_id *d) +{ + use_native_backlight_dmi = true; + return 0; +} + static struct dmi_system_id video_dmi_table[] __initdata = { /* * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121 @@ -443,6 +457,120 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"), }, }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad T430s", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T430s"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad X230", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad X1 Carbon", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X1 Carbon"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "Lenovo Yoga 13", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "Dell Inspiron 7520", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_VERSION, "Inspiron 7520"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "Acer Aspire 5733Z", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5733Z"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "Acer Aspire V5-431", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-431"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ProBook 4340s", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_VERSION, "HP ProBook 4340s"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ProBook 2013 models", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "), + DMI_MATCH(DMI_PRODUCT_NAME, " G1"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP EliteBook 2013 models", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "), + DMI_MATCH(DMI_PRODUCT_NAME, " G1"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ZBook 14", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ZBook 15", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ZBook 17", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP EliteBook 8780w", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"), + }, + }, {} }; @@ -686,6 +814,7 @@ acpi_video_init_brightness(struct acpi_video_device *device) union acpi_object *o; struct acpi_video_device_brightness *br = NULL; int result = -EINVAL; + u32 value; if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " @@ -716,7 +845,12 @@ acpi_video_init_brightness(struct acpi_video_device *device) printk(KERN_ERR PREFIX "Invalid data\n"); continue; } - br->levels[count] = (u32) o->integer.value; + value = (u32) o->integer.value; + /* Skip duplicate entries */ + if (count > 2 && br->levels[count - 1] == value) + continue; + + br->levels[count] = value; if (br->levels[count] > max_level) max_level = br->levels[count]; diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 84875fd4c74f..19080c8e2f2a 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -50,7 +50,7 @@ static bool acpi_video_caps_checked; static acpi_status acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, - void **retyurn_value) + void **return_value) { long *cap = context; @@ -168,14 +168,6 @@ static struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"), }, }, - { - .callback = video_detect_force_vendor, - .ident = "Lenovo Yoga 13", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"), - }, - }, { }, }; diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c index 7bfbe40bc43b..1638401ab282 100644 --- a/drivers/acpi/wakeup.c +++ b/drivers/acpi/wakeup.c @@ -5,7 +5,6 @@ #include <linux/init.h> #include <linux/acpi.h> -#include <acpi/acpi_drivers.h> #include <linux/kernel.h> #include <linux/types.h> |