diff options
Diffstat (limited to 'drivers/acpi')
35 files changed, 1919 insertions, 580 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index a34a228..3f5f745 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -42,6 +42,12 @@ menuconfig ACPI if ACPI +config ACPI_LEGACY_TABLES_LOOKUP + bool + +config ARCH_MIGHT_HAVE_ACPI_PDC + bool + config ACPI_SLEEP bool depends on SUSPEND || HIBERNATION diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index ea55e01..505d4d7 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -36,6 +36,7 @@ acpi-y += scan.o acpi-y += resource.o acpi-y += acpi_processor.o acpi-y += processor_core.o +acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-y += pci_root.o pci_link.o pci_irq.o diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index 1853341..340d095 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -69,11 +69,11 @@ static u32 l1_percpu_entry; #define ELOG_ENTRY_ADDR(phyaddr) \ (phyaddr - elog_base + (u8 *)elog_addr) -static struct acpi_generic_status *extlog_elog_entry_check(int cpu, int bank) +static struct acpi_hest_generic_status *extlog_elog_entry_check(int cpu, int bank) { int idx; u64 data; - struct acpi_generic_status *estatus; + struct acpi_hest_generic_status *estatus; WARN_ON(cpu < 0); idx = ELOG_IDX(cpu, bank); @@ -82,7 +82,7 @@ static struct acpi_generic_status *extlog_elog_entry_check(int cpu, int bank) return NULL; data &= EXT_ELOG_ENTRY_MASK; - estatus = (struct acpi_generic_status *)ELOG_ENTRY_ADDR(data); + estatus = (struct acpi_hest_generic_status *)ELOG_ENTRY_ADDR(data); /* if no valid data in elog entry, just return */ if (estatus->block_status == 0) @@ -92,7 +92,7 @@ static struct acpi_generic_status *extlog_elog_entry_check(int cpu, int bank) } static void __print_extlog_rcd(const char *pfx, - struct acpi_generic_status *estatus, int cpu) + struct acpi_hest_generic_status *estatus, int cpu) { static atomic_t seqno; unsigned int curr_seqno; @@ -111,7 +111,7 @@ static void __print_extlog_rcd(const char *pfx, } static int print_extlog_rcd(const char *pfx, - struct acpi_generic_status *estatus, int cpu) + struct acpi_hest_generic_status *estatus, int cpu) { /* Not more than 2 messages every 5 seconds */ static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5*HZ, 2); @@ -137,7 +137,7 @@ static int extlog_print(struct notifier_block *nb, unsigned long val, struct mce *mce = (struct mce *)data; int bank = mce->bank; int cpu = mce->extcpu; - struct acpi_generic_status *estatus; + struct acpi_hest_generic_status *estatus; int rc; estatus = extlog_elog_entry_check(cpu, bank); @@ -148,7 +148,7 @@ static int extlog_print(struct notifier_block *nb, unsigned long val, /* clear record status to enable BIOS to update it again */ estatus->block_status = 0; - rc = print_extlog_rcd(NULL, (struct acpi_generic_status *)elog_buf, cpu); + rc = print_extlog_rcd(NULL, (struct acpi_hest_generic_status *)elog_buf, cpu); return NOTIFY_STOP; } diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 1c08574..1fdf5e0 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -268,7 +268,7 @@ static int acpi_processor_get_info(struct acpi_device *device) pr->apic_id = apic_id; cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id); - if (!cpu0_initialized && !acpi_lapic) { + if (!cpu0_initialized && !acpi_has_cpu_in_madt()) { cpu0_initialized = 1; /* Handle UP system running SMP kernel, with no LAPIC in MADT */ if ((cpu_index == -1) && (num_online_cpus() == 1)) diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index 8bb43f0..4be4cc94 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -2,7 +2,7 @@ # Makefile for ACPICA Core interpreter # -ccflags-y := -Os +ccflags-y := -Os -DBUILDING_ACPICA ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT # use acpi.o to put all files here into acpi.o modparam namespace @@ -175,5 +175,5 @@ acpi-y += \ utxferror.o \ utxfmutex.o -acpi-$(ACPI_FUTURE_USAGE) += uttrack.o utcache.o +acpi-$(ACPI_FUTURE_USAGE) += utfileio.o utprint.o uttrack.o utcache.o diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index 8698ffb..3d2c882 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -79,10 +79,13 @@ /* Macros for usage messages */ #define ACPI_USAGE_HEADER(usage) \ - printf ("Usage: %s\nOptions:\n", usage); + acpi_os_printf ("Usage: %s\nOptions:\n", usage); + +#define ACPI_USAGE_TEXT(description) \ + acpi_os_printf (description); #define ACPI_OPTION(name, description) \ - printf (" %-18s%s\n", name, description); + acpi_os_printf (" %-18s%s\n", name, description); #define FILE_SUFFIX_DISASSEMBLY "dsl" #define ACPI_TABLE_FILE_SUFFIX ".dat" @@ -102,7 +105,7 @@ extern char *acpi_gbl_optarg; /* * cmfsize - Common get file size function */ -u32 cm_get_file_size(FILE * file); +u32 cm_get_file_size(ACPI_FILE file); #ifndef ACPI_DUMP_APP /* diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 68a91eb..1d026ff 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -233,9 +233,6 @@ acpi_status acpi_db_load_acpi_table(char *filename); acpi_status acpi_db_get_table_from_file(char *filename, struct acpi_table_header **table); -acpi_status -acpi_db_read_table_from_file(char *filename, struct acpi_table_header **table); - /* * dbhistry - debugger HISTORY command */ diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 115eedc..ebf02cc 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -297,7 +297,7 @@ ACPI_GLOBAL(u32, acpi_gbl_trace_dbg_layer); * ****************************************************************************/ -ACPI_GLOBAL(u8, acpi_gbl_db_output_flags); +ACPI_INIT_GLOBAL(u8, acpi_gbl_db_output_flags, ACPI_DB_CONSOLE_OUTPUT); #ifdef ACPI_DISASSEMBLER @@ -362,6 +362,12 @@ ACPI_GLOBAL(u32, acpi_gbl_num_objects); #ifdef ACPI_APPLICATION ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_debug_file, NULL); +ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_output_file, NULL); + +/* Print buffer */ + +ACPI_GLOBAL(acpi_spinlock, acpi_gbl_print_lock); /* For print buffer */ +ACPI_GLOBAL(char, acpi_gbl_print_buffer[1024]); #endif /* ACPI_APPLICATION */ diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 1e256c5..ed614f4 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -95,7 +95,6 @@ extern const char *acpi_gbl_pt_decode[]; #ifdef ACPI_ASL_COMPILER #include <stdio.h> -extern FILE *acpi_gbl_output_file; #define ACPI_MSG_REDIRECT_BEGIN \ FILE *output_file = acpi_gbl_output_file; \ @@ -211,6 +210,8 @@ void acpi_ut_subsystem_shutdown(void); acpi_size acpi_ut_strlen(const char *string); +char *acpi_ut_strchr(const char *string, int ch); + char *acpi_ut_strcpy(char *dst_string, const char *src_string); char *acpi_ut_strncpy(char *dst_string, @@ -257,7 +258,7 @@ extern const u8 _acpi_ctype[]; #define ACPI_IS_XDIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_XD)) #define ACPI_IS_UPPER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_UP)) #define ACPI_IS_LOWER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO)) -#define ACPI_IS_PRINT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP | _ACPI_DI | _ACPI_SP | _ACPI_PU)) +#define ACPI_IS_PRINT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP | _ACPI_DI | _ACPI_XS | _ACPI_PU)) #define ACPI_IS_ALPHA(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP)) #endif /* !ACPI_USE_SYSTEM_CLIBRARY */ @@ -352,6 +353,13 @@ acpi_ut_debug_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id); void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 offset); +#ifdef ACPI_APPLICATION +void +acpi_ut_dump_buffer_to_file(ACPI_FILE file, + u8 *buffer, + u32 count, u32 display, u32 base_offset); +#endif + void acpi_ut_report_error(char *module_name, u32 line_number); void acpi_ut_report_info(char *module_name, u32 line_number); @@ -394,6 +402,14 @@ acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node, u8 method_count, u8 *out_values); /* + * utfileio - file operations + */ +#ifdef ACPI_APPLICATION +acpi_status +acpi_ut_read_table_from_file(char *filename, struct acpi_table_header **table); +#endif + +/* * utids - device ID support */ acpi_status @@ -743,4 +759,23 @@ const struct ah_predefined_name *acpi_ah_match_predefined_name(char *nameseg); const struct ah_device_id *acpi_ah_match_hardware_id(char *hid); +/* + * utprint - printf/vprintf output functions + */ +const char *acpi_ut_scan_number(const char *string, u64 *number_ptr); + +const char *acpi_ut_print_number(char *string, u64 number); + +int +acpi_ut_vsnprintf(char *string, + acpi_size size, const char *format, va_list args); + +int acpi_ut_snprintf(char *string, acpi_size size, const char *format, ...); + +#ifdef ACPI_APPLICATION +int acpi_ut_file_vprintf(ACPI_FILE file, const char *format, va_list args); + +int acpi_ut_file_printf(ACPI_FILE file, const char *format, ...); +#endif + #endif /* _ACUTILS_H */ diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 48f7001..e4ba4de 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -698,21 +698,6 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, } /* - * If edge-triggered, clear the GPE status bit now. Note that - * level-triggered events are cleared after the GPE is serviced. - */ - if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == - ACPI_GPE_EDGE_TRIGGERED) { - status = acpi_hw_clear_gpe(gpe_event_info); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Unable to clear GPE %02X", - gpe_number)); - return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); - } - } - - /* * Always disable the GPE so that it does not keep firing before * any asynchronous activity completes (either from the execution * of a GPE method or an asynchronous GPE handler.) @@ -729,6 +714,23 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, } /* + * If edge-triggered, clear the GPE status bit now. Note that + * level-triggered events are cleared after the GPE is serviced. + */ + if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == + ACPI_GPE_EDGE_TRIGGERED) { + status = acpi_hw_clear_gpe(gpe_event_info); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "Unable to clear GPE %02X", + gpe_number)); + (void)acpi_hw_low_set_gpe(gpe_event_info, + ACPI_GPE_CONDITIONAL_ENABLE); + return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); + } + } + + /* * Dispatch the GPE to either an installed handler or the control * method associated with this GPE (_Lxx or _Exx). If a handler * exists, we invoke it and do not attempt to run the method. diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index cb534fa..0cf159c 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -126,11 +126,19 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); - /* Ensure that we have a valid GPE number */ - + /* + * Ensure that we have a valid GPE number and that there is some way + * of handling the GPE (handler or a GPE method). In other words, we + * won't allow a valid GPE to be enabled if there is no way to handle it. + */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (gpe_event_info) { - status = acpi_ev_add_gpe_reference(gpe_event_info); + if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != + ACPI_GPE_DISPATCH_NONE) { + status = acpi_ev_add_gpe_reference(gpe_event_info); + } else { + status = AE_NO_HANDLER; + } } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); @@ -179,6 +187,53 @@ ACPI_EXPORT_SYMBOL(acpi_disable_gpe) /******************************************************************************* * + * FUNCTION: acpi_mark_gpe_for_wake + * + * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 + * gpe_number - GPE level within the GPE block + * + * RETURN: Status + * + * DESCRIPTION: Mark a GPE as having the ability to wake the system. Simply + * sets the ACPI_GPE_CAN_WAKE flag. + * + * Some potential callers of acpi_setup_gpe_for_wake may know in advance that + * there won't be any notify handlers installed for device wake notifications + * from the given GPE (one example is a button GPE in Linux). For these cases, + * acpi_mark_gpe_for_wake should be used instead of acpi_setup_gpe_for_wake. + * This will set the ACPI_GPE_CAN_WAKE flag for the GPE without trying to + * setup implicit wake notification for it (since there's no handler method). + * + ******************************************************************************/ +acpi_status acpi_mark_gpe_for_wake(acpi_handle gpe_device, u32 gpe_number) +{ + struct acpi_gpe_event_info *gpe_event_info; + acpi_status status = AE_BAD_PARAMETER; + acpi_cpu_flags flags; + + ACPI_FUNCTION_TRACE(acpi_mark_gpe_for_wake); + + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); + if (gpe_event_info) { + + /* Mark the GPE as a possible wake event */ + + gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; + status = AE_OK; + } + + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_mark_gpe_for_wake) + +/******************************************************************************* + * * FUNCTION: acpi_setup_gpe_for_wake * * PARAMETERS: wake_device - Device associated with the GPE (via _PRW) diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index 12878e1..1ff42c0 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -56,7 +56,7 @@ acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length); /******************************************************************************* * - * FUNCTION: acpi_get_serial_access_bytes + * FUNCTION: acpi_ex_get_serial_access_length * * PARAMETERS: accessor_type - The type of the protocol indicated by region * field access attributes @@ -103,7 +103,7 @@ acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length) case AML_FIELD_ATTRIB_BLOCK_CALL: default: - length = ACPI_GSBUS_BUFFER_SIZE; + length = ACPI_GSBUS_BUFFER_SIZE - 2; break; } diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index e0fd9b4..a4c34d2 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -278,8 +278,9 @@ acpi_status acpi_hw_clear_acpi_status(void) acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { goto exit; + } /* Clear the GPE Bits in all GPE registers in all GPE blocks */ diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index fe54a8c..a42ee9d 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -237,6 +237,16 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node) (node->object->common.type != ACPI_TYPE_LOCAL_DATA)) { node->object = node->object->common.next_object; } + + /* + * Detach the object from any data objects (which are still held by + * the namespace node) + */ + if (obj_desc->common.next_object && + ((obj_desc->common.next_object)->common.type == + ACPI_TYPE_LOCAL_DATA)) { + obj_desc->common.next_object = NULL; + } } /* Reset the node type to untyped */ diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c index 3c16997..038ea88 100644 --- a/drivers/acpi/acpica/utbuffer.c +++ b/drivers/acpi/acpica/utbuffer.c @@ -199,3 +199,131 @@ acpi_ut_debug_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id) acpi_ut_dump_buffer(buffer, count, display, 0); } + +#ifdef ACPI_APPLICATION +/******************************************************************************* + * + * FUNCTION: acpi_ut_dump_buffer_to_file + * + * PARAMETERS: file - File descriptor + * buffer - Buffer to dump + * count - Amount to dump, in bytes + * display - BYTE, WORD, DWORD, or QWORD display: + * DB_BYTE_DISPLAY + * DB_WORD_DISPLAY + * DB_DWORD_DISPLAY + * DB_QWORD_DISPLAY + * base_offset - Beginning buffer offset (display only) + * + * RETURN: None + * + * DESCRIPTION: Generic dump buffer in both hex and ascii to a file. + * + ******************************************************************************/ + +void +acpi_ut_dump_buffer_to_file(ACPI_FILE file, + u8 *buffer, u32 count, u32 display, u32 base_offset) +{ + u32 i = 0; + u32 j; + u32 temp32; + u8 buf_char; + + if (!buffer) { + acpi_ut_file_printf(file, + "Null Buffer Pointer in DumpBuffer!\n"); + return; + } + + if ((count < 4) || (count & 0x01)) { + display = DB_BYTE_DISPLAY; + } + + /* Nasty little dump buffer routine! */ + + while (i < count) { + + /* Print current offset */ + + acpi_ut_file_printf(file, "%6.4X: ", (base_offset + i)); + + /* Print 16 hex chars */ + + for (j = 0; j < 16;) { + if (i + j >= count) { + + /* Dump fill spaces */ + + acpi_ut_file_printf(file, "%*s", + ((display * 2) + 1), " "); + j += display; + continue; + } + + switch (display) { + case DB_BYTE_DISPLAY: + default: /* Default is BYTE display */ + + acpi_ut_file_printf(file, "%02X ", + buffer[(acpi_size) i + j]); + break; + + case DB_WORD_DISPLAY: + + ACPI_MOVE_16_TO_32(&temp32, + &buffer[(acpi_size) i + j]); + acpi_ut_file_printf(file, "%04X ", temp32); + break; + + case DB_DWORD_DISPLAY: + + ACPI_MOVE_32_TO_32(&temp32, + &buffer[(acpi_size) i + j]); + acpi_ut_file_printf(file, "%08X ", temp32); + break; + + case DB_QWORD_DISPLAY: + + ACPI_MOVE_32_TO_32(&temp32, + &buffer[(acpi_size) i + j]); + acpi_ut_file_printf(file, "%08X", temp32); + + ACPI_MOVE_32_TO_32(&temp32, + &buffer[(acpi_size) i + j + + 4]); + acpi_ut_file_printf(file, "%08X ", temp32); + break; + } + + j += display; + } + + /* + * Print the ASCII equivalent characters but watch out for the bad + * unprintable ones (printable chars are 0x20 through 0x7E) + */ + acpi_ut_file_printf(file, " "); + for (j = 0; j < 16; j++) { + if (i + j >= count) { + acpi_ut_file_printf(file, "\n"); + return; + } + + buf_char = buffer[(acpi_size) i + j]; + if (ACPI_IS_PRINT(buf_char)) { + acpi_ut_file_printf(file, "%c", buf_char); + } else { + acpi_ut_file_printf(file, "."); + } + } + + /* Done with that line. */ + + acpi_ut_file_printf(file, "\n"); + i += 16; + } + + return; +} +#endif diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index 270c164..ff601c0 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -1001,5 +1001,11 @@ acpi_ut_copy_iobject_to_iobject(union acpi_operand_object *source_desc, status = acpi_ut_copy_simple_object(source_desc, *dest_desc); } + /* Delete the allocated object if copy failed */ + + if (ACPI_FAILURE(status)) { + acpi_ut_remove_reference(*dest_desc); + } + return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 21a20ac..e516254 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -561,3 +561,29 @@ acpi_ut_ptr_exit(u32 line_number, } #endif + +#ifdef ACPI_APPLICATION +/******************************************************************************* + * + * FUNCTION: acpi_log_error + * + * PARAMETERS: format - Printf format field + * ... - Optional printf arguments + * + * RETURN: None + * + * DESCRIPTION: Print error message to the console, used by applications. + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE acpi_log_error(const char *format, ...) +{ + va_list args; + + va_start(args, format); + (void)acpi_ut_file_vprintf(ACPI_FILE_ERR, format, args); + va_end(args); +} + +ACPI_EXPORT_SYMBOL(acpi_log_error) +#endif diff --git a/drivers/acpi/acpica/utfileio.c b/drivers/acpi/acpica/utfileio.c new file mode 100644 index 0000000..bdf9914 --- /dev/null +++ b/drivers/acpi/acpica/utfileio.c @@ -0,0 +1,332 @@ +/******************************************************************************* + * + * Module Name: utfileio - simple file I/O routines + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2014, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <acpi/acpi.h> +#include "accommon.h" +#include "actables.h" +#include "acapps.h" + +#ifdef ACPI_ASL_COMPILER +#include "aslcompiler.h" +#endif + +#define _COMPONENT ACPI_CA_DEBUGGER +ACPI_MODULE_NAME("utfileio") + +#ifdef ACPI_APPLICATION +/* Local prototypes */ +static acpi_status +acpi_ut_check_text_mode_corruption(u8 *table, + u32 table_length, u32 file_length); + +static acpi_status +acpi_ut_read_table(FILE * fp, + struct acpi_table_header **table, u32 *table_length); + +/******************************************************************************* + * + * FUNCTION: acpi_ut_check_text_mode_corruption + * + * PARAMETERS: table - Table buffer + * table_length - Length of table from the table header + * file_length - Length of the file that contains the table + * + * RETURN: Status + * + * DESCRIPTION: Check table for text mode file corruption where all linefeed + * characters (LF) have been replaced by carriage return linefeed + * pairs (CR/LF). + * + ******************************************************************************/ + +static acpi_status +acpi_ut_check_text_mode_corruption(u8 *table, u32 table_length, u32 file_length) +{ + u32 i; + u32 pairs = 0; + + if (table_length != file_length) { + ACPI_WARNING((AE_INFO, + "File length (0x%X) is not the same as the table length (0x%X)", + file_length, table_length)); + } + + /* Scan entire table to determine if each LF has been prefixed with a CR */ + + for (i = 1; i < file_length; i++) { + if (table[i] == 0x0A) { + if (table[i - 1] != 0x0D) { + + /* The LF does not have a preceding CR, table not corrupted */ + + return (AE_OK); + } else { + /* Found a CR/LF pair */ + + pairs++; + } + i++; + } + } + + if (!pairs) { + return (AE_OK); + } + + /* + * Entire table scanned, each CR is part of a CR/LF pair -- + * meaning that the table was treated as a text file somewhere. + * + * NOTE: We can't "fix" the table, because any existing CR/LF pairs in the + * original table are left untouched by the text conversion process -- + * meaning that we cannot simply replace CR/LF pairs with LFs. + */ + acpi_os_printf("Table has been corrupted by text mode conversion\n"); + acpi_os_printf("All LFs (%u) were changed to CR/LF pairs\n", pairs); + acpi_os_printf("Table cannot be repaired!\n"); + return (AE_BAD_VALUE); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_read_table + * + * PARAMETERS: fp - File that contains table + * table - Return value, buffer with table + * table_length - Return value, length of table + * + * RETURN: Status + * + * DESCRIPTION: Load the DSDT from the file pointer + * + ******************************************************************************/ + +static acpi_status +acpi_ut_read_table(FILE * fp, + struct acpi_table_header **table, u32 *table_length) +{ + struct acpi_table_header table_header; + u32 actual; + acpi_status status; + u32 file_size; + u8 standard_header = TRUE; + s32 count; + + /* Get the file size */ + + file_size = cm_get_file_size(fp); + if (file_size == ACPI_UINT32_MAX) { + return (AE_ERROR); + } + + if (file_size < 4) { + return (AE_BAD_HEADER); + } + + /* Read the signature */ + + fseek(fp, 0, SEEK_SET); + + count = fread(&table_header, 1, sizeof(struct acpi_table_header), fp); + if (count != sizeof(struct acpi_table_header)) { + acpi_os_printf("Could not read the table header\n"); + return (AE_BAD_HEADER); + } + + /* The RSDP table does not have standard ACPI header */ + + if (ACPI_VALIDATE_RSDP_SIG(table_header.signature)) { + *table_length = file_size; + standard_header = FALSE; + } else { + +#if 0 + /* Validate the table header/length */ + + status = acpi_tb_validate_table_header(&table_header); + if (ACPI_FAILURE(status)) { + acpi_os_printf("Table header is invalid!\n"); + return (status); + } +#endif + + /* File size must be at least as long as the Header-specified length */ + + if (table_header.length > file_size) { + acpi_os_printf + ("TableHeader length [0x%X] greater than the input file size [0x%X]\n", + table_header.length, file_size); + +#ifdef ACPI_ASL_COMPILER + status = fl_check_for_ascii(fp, NULL, FALSE); + if (ACPI_SUCCESS(status)) { + acpi_os_printf + ("File appears to be ASCII only, must be binary\n", + table_header.length, file_size); + } +#endif + return (AE_BAD_HEADER); + } +#ifdef ACPI_OBSOLETE_CODE + /* We only support a limited number of table types */ + + if (!ACPI_COMPARE_NAME + ((char *)table_header.signature, ACPI_SIG_DSDT) + && !ACPI_COMPARE_NAME((char *)table_header.signature, + ACPI_SIG_PSDT) + && !ACPI_COMPARE_NAME((char *)table_header.signature, + ACPI_SIG_SSDT)) { + acpi_os_printf + ("Table signature [%4.4s] is invalid or not supported\n", + (char *)table_header.signature); + ACPI_DUMP_BUFFER(&table_header, + sizeof(struct acpi_table_header)); + return (AE_ERROR); + } +#endif + + *table_length = table_header.length; + } + + /* Allocate a buffer for the table */ + + *table = acpi_os_allocate((size_t) file_size); + if (!*table) { + acpi_os_printf + ("Could not allocate memory for ACPI table %4.4s (size=0x%X)\n", + table_header.signature, *table_length); + return (AE_NO_MEMORY); + } + + /* Get the rest of the table */ + + fseek(fp, 0, SEEK_SET); + actual = fread(*table, 1, (size_t) file_size, fp); + if (actual == file_size) { + if (standard_header) { + + /* Now validate the checksum */ + + status = acpi_tb_verify_checksum((void *)*table, + ACPI_CAST_PTR(struct + acpi_table_header, + *table)-> + length); + + if (status == AE_BAD_CHECKSUM) { + status = + acpi_ut_check_text_mode_corruption((u8 *) + *table, + file_size, + (*table)-> + length); + return (status); + } + } + return (AE_OK); + } + + if (actual > 0) { + acpi_os_printf("Warning - reading table, asked for %X got %X\n", + file_size, actual); + return (AE_OK); + } + + acpi_os_printf("Error - could not read the table file\n"); + acpi_os_free(*table); + *table = NULL; + *table_length = 0; + return (AE_ERROR); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_read_table_from_file + * + * PARAMETERS: filename - File where table is located + * table - Where a pointer to the table is returned + * + * RETURN: Status + * + * DESCRIPTION: Get an ACPI table from a file + * + ******************************************************************************/ + +acpi_status +acpi_ut_read_table_from_file(char *filename, struct acpi_table_header ** table) +{ + FILE *file; + u32 file_size; + u32 table_length; + acpi_status status = AE_ERROR; + + /* Open the file, get current size */ + + file = fopen(filename, "rb"); + if (!file) { + perror("Could not open input file"); + return (status); + } + + file_size = cm_get_file_size(file); + if (file_size == ACPI_UINT32_MAX) { + goto exit; + } + + /* Get the entire file */ + + fprintf(stderr, + "Loading Acpi table from file %10s - Length %.8u (%06X)\n", + filename, file_size, file_size); + + status = acpi_ut_read_table(file, table, &table_length); + if (ACPI_FAILURE(status)) { + acpi_os_printf("Could not get table from the file\n"); + } + +exit: + fclose(file); + return (status); +} + +#endif diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index d69be3c..77ceac7 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -214,152 +214,6 @@ struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS] = }; #endif /* !ACPI_REDUCED_HARDWARE */ -/******************************************************************************* - * - * FUNCTION: acpi_ut_init_globals - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Initialize ACPICA globals. All globals that require specific - * initialization should be initialized here. This allows for - * a warm restart. - * - ******************************************************************************/ - -acpi_status acpi_ut_init_globals(void) -{ - acpi_status status; - u32 i; - - ACPI_FUNCTION_TRACE(ut_init_globals); - - /* Create all memory caches */ - - status = acpi_ut_create_caches(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Address Range lists */ - - for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) { - acpi_gbl_address_range_list[i] = NULL; - } - - /* Mutex locked flags */ - - for (i = 0; i < ACPI_NUM_MUTEX; i++) { - acpi_gbl_mutex_info[i].mutex = NULL; - acpi_gbl_mutex_info[i].thread_id = ACPI_MUTEX_NOT_ACQUIRED; - acpi_gbl_mutex_info[i].use_count = 0; - } - - for (i = 0; i < ACPI_NUM_OWNERID_MASKS; i++) { - acpi_gbl_owner_id_mask[i] = 0; - } - - /* Last owner_ID is never valid */ - - acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS - 1] = 0x80000000; - - /* Event counters */ - - acpi_method_count = 0; - acpi_sci_count = 0; - acpi_gpe_count = 0; - - for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { - acpi_fixed_event_count[i] = 0; - } - -#if (!ACPI_REDUCED_HARDWARE) - - /* GPE/SCI support */ - - acpi_gbl_all_gpes_initialized = FALSE; - acpi_gbl_gpe_xrupt_list_head = NULL; - acpi_gbl_gpe_fadt_blocks[0] = NULL; - acpi_gbl_gpe_fadt_blocks[1] = NULL; - acpi_current_gpe_count = 0; - - acpi_gbl_global_event_handler = NULL; - acpi_gbl_sci_handler_list = NULL; - -#endif /* !ACPI_REDUCED_HARDWARE */ - - /* Global handlers */ - - acpi_gbl_global_notify[0].handler = NULL; - acpi_gbl_global_notify[1].handler = NULL; - acpi_gbl_exception_handler = NULL; - acpi_gbl_init_handler = NULL; - acpi_gbl_table_handler = NULL; - acpi_gbl_interface_handler = NULL; - - /* Global Lock support */ - - acpi_gbl_global_lock_semaphore = NULL; - acpi_gbl_global_lock_mutex = NULL; - acpi_gbl_global_lock_acquired = FALSE; - acpi_gbl_global_lock_handle = 0; - acpi_gbl_global_lock_present = FALSE; - - /* Miscellaneous variables */ - - acpi_gbl_DSDT = NULL; - acpi_gbl_cm_single_step = FALSE; - acpi_gbl_shutdown = FALSE; - acpi_gbl_ns_lookup_count = 0; - acpi_gbl_ps_find_count = 0; - acpi_gbl_acpi_hardware_present = TRUE; - acpi_gbl_last_owner_id_index = 0; - acpi_gbl_next_owner_id_offset = 0; - acpi_gbl_trace_dbg_level = 0; - acpi_gbl_trace_dbg_layer = 0; - acpi_gbl_debugger_configuration = DEBUGGER_THREADING; - acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT; - acpi_gbl_osi_mutex = NULL; - acpi_gbl_reg_methods_executed = FALSE; - - /* Hardware oriented */ - - acpi_gbl_events_initialized = FALSE; - acpi_gbl_system_awake_and_running = TRUE; - - /* Namespace */ - - acpi_gbl_module_code_list = NULL; - acpi_gbl_root_node = NULL; - acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME; - acpi_gbl_root_node_struct.descriptor_type = ACPI_DESC_TYPE_NAMED; - acpi_gbl_root_node_struct.type = ACPI_TYPE_DEVICE; - acpi_gbl_root_node_struct.parent = NULL; - acpi_gbl_root_node_struct.child = NULL; - acpi_gbl_root_node_struct.peer = NULL; - acpi_gbl_root_node_struct.object = NULL; - -#ifdef ACPI_DISASSEMBLER - acpi_gbl_external_list = NULL; - acpi_gbl_num_external_methods = 0; - acpi_gbl_resolved_external_methods = 0; -#endif - -#ifdef ACPI_DEBUG_OUTPUT - acpi_gbl_lowest_stack_pointer = ACPI_CAST_PTR(acpi_size, ACPI_SIZE_MAX); -#endif - -#ifdef ACPI_DBG_TRACK_ALLOCATIONS - acpi_gbl_display_final_mem_stats = FALSE; - acpi_gbl_disable_mem_tracking = FALSE; -#endif - - ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = FALSE); - - return_ACPI_STATUS(AE_OK); -} - /* Public globals */ ACPI_EXPORT_SYMBOL(acpi_gbl_FADT) diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index 5f56fc4..77120ec 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -102,6 +102,151 @@ static void acpi_ut_free_gpe_lists(void) } #endif /* !ACPI_REDUCED_HARDWARE */ +/******************************************************************************* + * + * FUNCTION: acpi_ut_init_globals + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initialize ACPICA globals. All globals that require specific + * initialization should be initialized here. This allows for + * a warm restart. + * + ******************************************************************************/ + +acpi_status acpi_ut_init_globals(void) +{ + acpi_status status; + u32 i; + + ACPI_FUNCTION_TRACE(ut_init_globals); + + /* Create all memory caches */ + + status = acpi_ut_create_caches(); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Address Range lists */ + + for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) { + acpi_gbl_address_range_list[i] = NULL; + } + + /* Mutex locked flags */ + + for (i = 0; i < ACPI_NUM_MUTEX; i++) { + acpi_gbl_mutex_info[i].mutex = NULL; + acpi_gbl_mutex_info[i].thread_id = ACPI_MUTEX_NOT_ACQUIRED; + acpi_gbl_mutex_info[i].use_count = 0; + } + + for (i = 0; i < ACPI_NUM_OWNERID_MASKS; i++) { + acpi_gbl_owner_id_mask[i] = 0; + } + + /* Last owner_ID is never valid */ + + acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS - 1] = 0x80000000; + + /* Event counters */ + + acpi_method_count = 0; + acpi_sci_count = 0; + acpi_gpe_count = 0; + + for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { + acpi_fixed_event_count[i] = 0; + } + +#if (!ACPI_REDUCED_HARDWARE) + + /* GPE/SCI support */ + + acpi_gbl_all_gpes_initialized = FALSE; + acpi_gbl_gpe_xrupt_list_head = NULL; + acpi_gbl_gpe_fadt_blocks[0] = NULL; + acpi_gbl_gpe_fadt_blocks[1] = NULL; + acpi_current_gpe_count = 0; + + acpi_gbl_global_event_handler = NULL; + acpi_gbl_sci_handler_list = NULL; + +#endif /* !ACPI_REDUCED_HARDWARE */ + + /* Global handlers */ + + acpi_gbl_global_notify[0].handler = NULL; + acpi_gbl_global_notify[1].handler = NULL; + acpi_gbl_exception_handler = NULL; + acpi_gbl_init_handler = NULL; + acpi_gbl_table_handler = NULL; + acpi_gbl_interface_handler = NULL; + + /* Global Lock support */ + + acpi_gbl_global_lock_semaphore = NULL; + acpi_gbl_global_lock_mutex = NULL; + acpi_gbl_global_lock_acquired = FALSE; + acpi_gbl_global_lock_handle = 0; + acpi_gbl_global_lock_present = FALSE; + + /* Miscellaneous variables */ + + acpi_gbl_DSDT = NULL; + acpi_gbl_cm_single_step = FALSE; + acpi_gbl_shutdown = FALSE; + acpi_gbl_ns_lookup_count = 0; + acpi_gbl_ps_find_count = 0; + acpi_gbl_acpi_hardware_present = TRUE; + acpi_gbl_last_owner_id_index = 0; + acpi_gbl_next_owner_id_offset = 0; + acpi_gbl_trace_dbg_level = 0; + acpi_gbl_trace_dbg_layer = 0; + acpi_gbl_debugger_configuration = DEBUGGER_THREADING; + acpi_gbl_osi_mutex = NULL; + acpi_gbl_reg_methods_executed = FALSE; + + /* Hardware oriented */ + + acpi_gbl_events_initialized = FALSE; + acpi_gbl_system_awake_and_running = TRUE; + + /* Namespace */ + + acpi_gbl_module_code_list = NULL; + acpi_gbl_root_node = NULL; + acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME; + acpi_gbl_root_node_struct.descriptor_type = ACPI_DESC_TYPE_NAMED; + acpi_gbl_root_node_struct.type = ACPI_TYPE_DEVICE; + acpi_gbl_root_node_struct.parent = NULL; + acpi_gbl_root_node_struct.child = NULL; + acpi_gbl_root_node_struct.peer = NULL; + acpi_gbl_root_node_struct.object = NULL; + +#ifdef ACPI_DISASSEMBLER + acpi_gbl_external_list = NULL; + acpi_gbl_num_external_methods = 0; + acpi_gbl_resolved_external_methods = 0; +#endif + +#ifdef ACPI_DEBUG_OUTPUT + acpi_gbl_lowest_stack_pointer = ACPI_CAST_PTR(acpi_size, ACPI_SIZE_MAX); +#endif + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + acpi_gbl_display_final_mem_stats = FALSE; + acpi_gbl_disable_mem_tracking = FALSE; +#endif + + ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = FALSE); + + return_ACPI_STATUS(AE_OK); +} + /****************************************************************************** * * FUNCTION: acpi_ut_terminate diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c new file mode 100644 index 0000000..1031164 --- /dev/null +++ b/drivers/acpi/acpica/utprint.c @@ -0,0 +1,661 @@ +/****************************************************************************** + * + * Module Name: utprint - Formatted printing routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2014, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <acpi/acpi.h> +#include "accommon.h" + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("utprint") + +#define ACPI_FORMAT_SIGN 0x01 +#define ACPI_FORMAT_SIGN_PLUS 0x02 +#define ACPI_FORMAT_SIGN_PLUS_SPACE 0x04 +#define ACPI_FORMAT_ZERO 0x08 +#define ACPI_FORMAT_LEFT 0x10 +#define ACPI_FORMAT_UPPER 0x20 +#define ACPI_FORMAT_PREFIX 0x40 +/* Local prototypes */ +static acpi_size +acpi_ut_bound_string_length(const char *string, acpi_size count); + +static char *acpi_ut_bound_string_output(char *string, const char *end, char c); + +static char *acpi_ut_format_number(char *string, + char *end, + u64 number, + u8 base, s32 width, s32 precision, u8 type); + +static char *acpi_ut_put_number(char *string, u64 number, u8 base, u8 upper); + +/* Module globals */ + +static const char acpi_gbl_lower_hex_digits[] = "0123456789abcdef"; +static const char acpi_gbl_upper_hex_digits[] = "0123456789ABCDEF"; + +/******************************************************************************* + * + * FUNCTION: acpi_ut_bound_string_length + * + * PARAMETERS: string - String with boundary + * count - Boundary of the string + * + * RETURN: Length of the string. Less than or equal to Count. + * + * DESCRIPTION: Calculate the length of a string with boundary. + * + ******************************************************************************/ + +static acpi_size +acpi_ut_bound_string_length(const char *string, acpi_size count) +{ + u32 length = 0; + + while (*string && count) { + length++; + string++; + count--; + } + + return (length); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_bound_string_output + * + * PARAMETERS: string - String with boundary + * end - Boundary of the string + * c - Character to be output to the string + * + * RETURN: Updated position for next valid character + * + * DESCRIPTION: Output a character into a string with boundary check. + * + ******************************************************************************/ + +static char *acpi_ut_bound_string_output(char *string, const char *end, char c) +{ + + if (string < end) { + *string = c; + } + + ++string; + return (string); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_put_number + * + * PARAMETERS: string - Buffer to hold reverse-ordered string + * number - Integer to be converted + * base - Base of the integer + * upper - Whether or not using upper cased digits + * + * RETURN: Updated position for next valid character + * + * DESCRIPTION: Convert an integer into a string, note that, the string holds a + * reversed ordered number without the trailing zero. + * + ******************************************************************************/ + +static char *acpi_ut_put_number(char *string, u64 number, u8 base, u8 upper) +{ + const char *digits; + u64 digit_index; + char *pos; + + pos = string; + digits = upper ? acpi_gbl_upper_hex_digits : acpi_gbl_lower_hex_digits; + + if (number == 0) { + *(pos++) = '0'; + } else { + while (number) { + (void)acpi_ut_divide(number, base, &number, + &digit_index); + *(pos++) = digits[digit_index]; + } + } + + /* *(Pos++) = '0'; */ + return (pos); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_scan_number + * + * PARAMETERS: string - String buffer + * number_ptr - Where the number is returned + * + * RETURN: Updated position for next valid character + * + * DESCRIPTION: Scan a string for a decimal integer. + * + ******************************************************************************/ + +const char *acpi_ut_scan_number(const char *string, u64 *number_ptr) +{ + u64 number = 0; + + while (ACPI_IS_DIGIT(*string)) { + number *= 10; + number += *(string++) - '0'; + } + + *number_ptr = number; + return (string); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_print_number + * + * PARAMETERS: string - String buffer + * number - The number to be converted + * + * RETURN: Updated position for next valid character + * + * DESCRIPTION: Print a decimal integer into a string. + * + ******************************************************************************/ + +const char *acpi_ut_print_number(char *string, u64 number) +{ + char ascii_string[20]; + const char *pos1; + char *pos2; + + pos1 = acpi_ut_put_number(ascii_string, number, 10, FALSE); + pos2 = string; + + while (pos1 != ascii_string) { + *(pos2++) = *(--pos1); + } + + *pos2 = 0; + return (string); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_format_number + * + * PARAMETERS: string - String buffer with boundary + * end - Boundary of the string + * number - The number to be converted + * base - Base of the integer + * width - Field width + * precision - Precision of the integer + * type - Special printing flags + * + * RETURN: Updated position for next valid character + * + * DESCRIPTION: Print an integer into a string with any base and any precision. + * + ******************************************************************************/ + +static char *acpi_ut_format_number(char *string, + char *end, + u64 number, + u8 base, s32 width, s32 precision, u8 type) +{ + char sign; + char zero; + u8 need_prefix; + u8 upper; + s32 i; + char reversed_string[66]; + + /* Parameter validation */ + + if (base < 2 || base > 16) { + return (NULL); + } + + if (type & ACPI_FORMAT_LEFT) { + type &= ~ACPI_FORMAT_ZERO; + } + + need_prefix = ((type & ACPI_FORMAT_PREFIX) + && base != 10) ? TRUE : FALSE; + upper = (type & ACPI_FORMAT_UPPER) ? TRUE : FALSE; + zero = (type & ACPI_FORMAT_ZERO) ? '0' : ' '; + + /* Calculate size according to sign and prefix */ + + sign = '\0'; + if (type & ACPI_FORMAT_SIGN) { + if ((s64) number < 0) { + sign = '-'; + number = -(s64) number; + width--; + } else if (type & ACPI_FORMAT_SIGN_PLUS) { + sign = '+'; + width--; + } else if (type & ACPI_FORMAT_SIGN_PLUS_SPACE) { + sign = ' '; + width--; + } + } + if (need_prefix) { + width--; + if (base == 16) { + width--; + } + } + + /* Generate full string in reverse order */ + + i = ACPI_PTR_DIFF(acpi_ut_put_number + (reversed_string, number, base, upper), + reversed_string); + + /* Printing 100 using %2d gives "100", not "00" */ + + if (i > precision) { + precision = i; + } + + width -= precision; + + /* Output the string */ + + if (!(type & (ACPI_FORMAT_ZERO | ACPI_FORMAT_LEFT))) { + while (--width >= 0) { + string = acpi_ut_bound_string_output(string, end, ' '); + } + } + if (sign) { + string = acpi_ut_bound_string_output(string, end, sign); + } + if (need_prefix) { + string = acpi_ut_bound_string_output(string, end, '0'); + if (base == 16) { + string = acpi_ut_bound_string_output(string, end, + upper ? 'X' : 'x'); + } + } + if (!(type & ACPI_FORMAT_LEFT)) { + while (--width >= 0) { + string = acpi_ut_bound_string_output(string, end, zero); + } + } + + while (i <= --precision) { + string = acpi_ut_bound_string_output(string, end, '0'); + } + while (--i >= 0) { + string = acpi_ut_bound_string_output(string, end, + reversed_string[i]); + } + while (--width >= 0) { + string = acpi_ut_bound_string_output(string, end, ' '); + } + + return (string); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_vsnprintf + * + * PARAMETERS: string - String with boundary + * size - Boundary of the string + * format - Standard printf format + * args - Argument list + * + * RETURN: Number of bytes actually written. + * + * DESCRIPTION: Formatted output to a string using argument list pointer. + * + ******************************************************************************/ + +int +acpi_ut_vsnprintf(char *string, + acpi_size size, const char *format, va_list args) +{ + u8 base = 10; + u8 type = 0; + s32 width = -1; + s32 precision = -1; + char qualifier = 0; + u64 number; + char *pos; + char *end; + char c; + const char *s; + const void *p; + s32 length; + int i; + + pos = string; + end = string + size; + + for (; *format; ++format) { + if (*format != '%') { + pos = acpi_ut_bound_string_output(pos, end, *format); + continue; + } + + /* Process sign */ + + do { + ++format; + if (*format == '#') { + type |= ACPI_FORMAT_PREFIX; + } else if (*format == '0') { + type |= ACPI_FORMAT_ZERO; + } else if (*format == '+') { + type |= ACPI_FORMAT_SIGN_PLUS; + } else if (*format == ' ') { + type |= ACPI_FORMAT_SIGN_PLUS_SPACE; + } else if (*format == '-') { + type |= ACPI_FORMAT_LEFT; + } else { + break; + } + } while (1); + + /* Process width */ + + if (ACPI_IS_DIGIT(*format)) { + format = acpi_ut_scan_number(format, &number); + width = (s32) number; + } else if (*format == '*') { + ++format; + width = va_arg(args, int); + if (width < 0) { + width = -width; + type |= ACPI_FORMAT_LEFT; + } + } + + /* Process precision */ + + if (*format == '.') { + ++format; + if (ACPI_IS_DIGIT(*format)) { + format = acpi_ut_scan_number(format, &number); + precision = (s32) number; + } else if (*format == '*') { + ++format; + precision = va_arg(args, int); + } + if (precision < 0) { + precision = 0; + } + } + + /* Process qualifier */ + + if (*format == 'h' || *format == 'l' || *format == 'L') { + qualifier = *format; + ++format; + + if (qualifier == 'l' && *format == 'l') { + qualifier = 'L'; + ++format; + } + } + + switch (*format) { + case '%': + + pos = acpi_ut_bound_string_output(pos, end, '%'); + continue; + + case 'c': + + if (!(type & ACPI_FORMAT_LEFT)) { + while (--width > 0) { + pos = + acpi_ut_bound_string_output(pos, + end, + ' '); + } + } + + c = (char)va_arg(args, int); + pos = acpi_ut_bound_string_output(pos, end, c); + + while (--width > 0) { + pos = + acpi_ut_bound_string_output(pos, end, ' '); + } + continue; + + case 's': + + s = va_arg(args, char *); + if (!s) { + s = "<NULL>"; + } + length = acpi_ut_bound_string_length(s, precision); + if (!(type & ACPI_FORMAT_LEFT)) { + while (length < width--) { + pos = + acpi_ut_bound_string_output(pos, + end, + ' '); + } + } + for (i = 0; i < length; ++i) { + pos = acpi_ut_bound_string_output(pos, end, *s); + ++s; + } + while (length < width--) { + pos = + acpi_ut_bound_string_output(pos, end, ' '); + } + continue; + + case 'o': + + base = 8; + break; + + case 'X': + + type |= ACPI_FORMAT_UPPER; + + case 'x': + + base = 16; + break; + + case 'd': + case 'i': + + type |= ACPI_FORMAT_SIGN; + + case 'u': + + break; + + case 'p': + + if (width == -1) { + width = 2 * sizeof(void *); + type |= ACPI_FORMAT_ZERO; + } + + p = va_arg(args, void *); + pos = acpi_ut_format_number(pos, end, + ACPI_TO_INTEGER(p), 16, + width, precision, type); + continue; + + default: + + pos = acpi_ut_bound_string_output(pos, end, '%'); + if (*format) { + pos = + acpi_ut_bound_string_output(pos, end, + *format); + } else { + --format; + } + continue; + } + + if (qualifier == 'L') { + number = va_arg(args, u64); + if (type & ACPI_FORMAT_SIGN) { + number = (s64) number; + } + } else if (qualifier == 'l') { + number = va_arg(args, unsigned long); + if (type & ACPI_FORMAT_SIGN) { + number = (s32) number; + } + } else if (qualifier == 'h') { + number = (u16)va_arg(args, int); + if (type & ACPI_FORMAT_SIGN) { + number = (s16) number; + } + } else { + number = va_arg(args, unsigned int); + if (type & ACPI_FORMAT_SIGN) { + number = (signed int)number; + } + } + + pos = acpi_ut_format_number(pos, end, number, base, + width, precision, type); + } + + if (size > 0) { + if (pos < end) { + *pos = '\0'; + } else { + end[-1] = '\0'; + } + } + + return (ACPI_PTR_DIFF(pos, string)); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_snprintf + * + * PARAMETERS: string - String with boundary + * size - Boundary of the string + * Format, ... - Standard printf format + * + * RETURN: Number of bytes actually written. + * + * DESCRIPTION: Formatted output to a string. + * + ******************************************************************************/ + +int acpi_ut_snprintf(char *string, acpi_size size, const char *format, ...) +{ + va_list args; + int length; + + va_start(args, format); + length = acpi_ut_vsnprintf(string, size, format, args); + va_end(args); + + return (length); +} + +#ifdef ACPI_APPLICATION +/******************************************************************************* + * + * FUNCTION: acpi_ut_file_vprintf + * + * PARAMETERS: file - File descriptor + * format - Standard printf format + * args - Argument list + * + * RETURN: Number of bytes actually written. + * + * DESCRIPTION: Formatted output to a file using argument list pointer. + * + ******************************************************************************/ + +int acpi_ut_file_vprintf(ACPI_FILE file, const char *format, va_list args) +{ + acpi_cpu_flags flags; + int length; + + flags = acpi_os_acquire_lock(acpi_gbl_print_lock); + length = acpi_ut_vsnprintf(acpi_gbl_print_buffer, + sizeof(acpi_gbl_print_buffer), format, args); + + (void)acpi_os_write_file(file, acpi_gbl_print_buffer, length, 1); + acpi_os_release_lock(acpi_gbl_print_lock, flags); + + return (length); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_file_printf + * + * PARAMETERS: file - File descriptor + * Format, ... - Standard printf format + * + * RETURN: Number of bytes actually written. + * + * DESCRIPTION: Formatted output to a file. + * + ******************************************************************************/ + +int acpi_ut_file_printf(ACPI_FILE file, const char *format, ...) +{ + va_list args; + int length; + + va_start(args, format); + length = acpi_ut_file_vprintf(file, format, args); + va_end(args); + + return (length); +} +#endif diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index e5bcd91..16129c7 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -121,11 +121,11 @@ struct dentry; struct dentry *apei_get_debugfs_dir(void); #define apei_estatus_for_each_section(estatus, section) \ - for (section = (struct acpi_generic_data *)(estatus + 1); \ + for (section = (struct acpi_hest_generic_data *)(estatus + 1); \ (void *)section - (void *)estatus < estatus->data_length; \ section = (void *)(section+1) + section->error_data_length) -static inline u32 cper_estatus_len(struct acpi_generic_status *estatus) +static inline u32 cper_estatus_len(struct acpi_hest_generic_status *estatus) { if (estatus->raw_data_length) return estatus->raw_data_offset + \ @@ -135,9 +135,9 @@ static inline u32 cper_estatus_len(struct acpi_generic_status *estatus) } void cper_estatus_print(const char *pfx, - const struct acpi_generic_status *estatus); -int cper_estatus_check_header(const struct acpi_generic_status *estatus); -int cper_estatus_check(const struct acpi_generic_status *estatus); + const struct acpi_hest_generic_status *estatus); +int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus); +int cper_estatus_check(const struct acpi_hest_generic_status *estatus); int apei_osc_setup(void); #endif diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index dab7cb7..7a38d14 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -74,13 +74,13 @@ #define GHES_ESTATUS_CACHE_LEN(estatus_len) \ (sizeof(struct ghes_estatus_cache) + (estatus_len)) #define GHES_ESTATUS_FROM_CACHE(estatus_cache) \ - ((struct acpi_generic_status *) \ + ((struct acpi_hest_generic_status *) \ ((struct ghes_estatus_cache *)(estatus_cache) + 1)) #define GHES_ESTATUS_NODE_LEN(estatus_len) \ (sizeof(struct ghes_estatus_node) + (estatus_len)) #define GHES_ESTATUS_FROM_NODE(estatus_node) \ - ((struct acpi_generic_status *) \ + ((struct acpi_hest_generic_status *) \ ((struct ghes_estatus_node *)(estatus_node) + 1)) bool ghes_disable; @@ -408,7 +408,7 @@ static void ghes_clear_estatus(struct ghes *ghes) ghes->flags &= ~GHES_TO_CLEAR; } -static void ghes_handle_memory_failure(struct acpi_generic_data *gdata, int sev) +static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int sev) { #ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE unsigned long pfn; @@ -441,10 +441,10 @@ static void ghes_handle_memory_failure(struct acpi_generic_data *gdata, int sev) } static void ghes_do_proc(struct ghes *ghes, - const struct acpi_generic_status *estatus) + const struct acpi_hest_generic_status *estatus) { int sev, sec_sev; - struct acpi_generic_data *gdata; + struct acpi_hest_generic_data *gdata; sev = ghes_severity(estatus->error_severity); apei_estatus_for_each_section(estatus, gdata) { @@ -498,7 +498,7 @@ static void ghes_do_proc(struct ghes *ghes, static void __ghes_print_estatus(const char *pfx, const struct acpi_hest_generic *generic, - const struct acpi_generic_status *estatus) + const struct acpi_hest_generic_status *estatus) { static atomic_t seqno; unsigned int curr_seqno; @@ -520,7 +520,7 @@ static void __ghes_print_estatus(const char *pfx, static int ghes_print_estatus(const char *pfx, const struct acpi_hest_generic *generic, - const struct acpi_generic_status *estatus) + const struct acpi_hest_generic_status *estatus) { /* Not more than 2 messages every 5 seconds */ static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5*HZ, 2); @@ -542,13 +542,13 @@ static int ghes_print_estatus(const char *pfx, * GHES error status reporting throttle, to report more kinds of * errors, instead of just most frequently occurred errors. */ -static int ghes_estatus_cached(struct acpi_generic_status *estatus) +static int ghes_estatus_cached(struct acpi_hest_generic_status *estatus) { u32 len; int i, cached = 0; unsigned long long now; struct ghes_estatus_cache *cache; - struct acpi_generic_status *cache_estatus; + struct acpi_hest_generic_status *cache_estatus; len = cper_estatus_len(estatus); rcu_read_lock(); @@ -573,12 +573,12 @@ static int ghes_estatus_cached(struct acpi_generic_status *estatus) static struct ghes_estatus_cache *ghes_estatus_cache_alloc( struct acpi_hest_generic *generic, - struct acpi_generic_status *estatus) + struct acpi_hest_generic_status *estatus) { int alloced; u32 len, cache_len; struct ghes_estatus_cache *cache; - struct acpi_generic_status *cache_estatus; + struct acpi_hest_generic_status *cache_estatus; alloced = atomic_add_return(1, &ghes_estatus_cache_alloced); if (alloced > GHES_ESTATUS_CACHE_ALLOCED_MAX) { @@ -621,7 +621,7 @@ static void ghes_estatus_cache_rcu_free(struct rcu_head *head) static void ghes_estatus_cache_add( struct acpi_hest_generic *generic, - struct acpi_generic_status *estatus) + struct acpi_hest_generic_status *estatus) { int i, slot = -1, count; unsigned long long now, duration, period, max_period = 0; @@ -753,7 +753,7 @@ static void ghes_proc_in_irq(struct irq_work *irq_work) struct llist_node *llnode, *next; struct ghes_estatus_node *estatus_node; struct acpi_hest_generic *generic; - struct acpi_generic_status *estatus; + struct acpi_hest_generic_status *estatus; u32 len, node_len; llnode = llist_del_all(&ghes_estatus_llist); @@ -786,7 +786,7 @@ static void ghes_print_queued_estatus(void) struct llist_node *llnode; struct ghes_estatus_node *estatus_node; struct acpi_hest_generic *generic; - struct acpi_generic_status *estatus; + struct acpi_hest_generic_status *estatus; u32 len, node_len; llnode = llist_del_all(&ghes_estatus_llist); @@ -845,7 +845,7 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) #ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG u32 len, node_len; struct ghes_estatus_node *estatus_node; - struct acpi_generic_status *estatus; + struct acpi_hest_generic_status *estatus; #endif if (!(ghes->flags & GHES_TO_CLEAR)) continue; @@ -925,7 +925,7 @@ static int ghes_probe(struct platform_device *ghes_dev) rc = -EIO; if (generic->error_block_length < - sizeof(struct acpi_generic_status)) { + sizeof(struct acpi_hest_generic_status)) { pr_warning(FW_BUG GHES_PFX "Invalid error block length: %u for generic hardware error source: %d\n", generic->error_block_length, generic->header.source_id); diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 3d8413d..36eb42e 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -247,75 +247,11 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { }, /* - * The following machines have broken backlight support when reporting - * the Windows 2012 OSI, so disable it until their support is fixed. + * These machines will power on immediately after shutdown when + * reporting the Windows 2012 OSI. */ { .callback = dmi_disable_osi_win8, - .ident = "ASUS Zenbook Prime UX31A", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "UX31A"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "ThinkPad Edge E530", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "3259A2G"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "ThinkPad Edge E530", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "3259CTO"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "ThinkPad Edge E530", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "3259HJG"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "Acer Aspire V5-573G", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer Aspire"), - DMI_MATCH(DMI_PRODUCT_VERSION, "V5-573G/Dazzle_HW"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "Acer Aspire V5-572G", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer Aspire"), - DMI_MATCH(DMI_PRODUCT_VERSION, "V5-572G/Dazzle_CX"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "ThinkPad T431s", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "20AACTO1WW"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "ThinkPad T430", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "2349D15"), - }, - }, - { - .callback = dmi_disable_osi_win8, .ident = "Dell Inspiron 7737", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index c5bc8cf..8581f5b 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -477,9 +477,6 @@ static int __init acpi_bus_init_irq(void) return 0; } -u8 acpi_gbl_permanent_mmap; - - void __init acpi_early_init(void) { acpi_status status; diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index db35594..6d5d183 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -79,11 +79,13 @@ static int acpi_button_remove(struct acpi_device *device); static void acpi_button_notify(struct acpi_device *device, u32 event); #ifdef CONFIG_PM_SLEEP +static int acpi_button_suspend(struct device *dev); static int acpi_button_resume(struct device *dev); #else +#define acpi_button_suspend NULL #define acpi_button_resume NULL #endif -static SIMPLE_DEV_PM_OPS(acpi_button_pm, NULL, acpi_button_resume); +static SIMPLE_DEV_PM_OPS(acpi_button_pm, acpi_button_suspend, acpi_button_resume); static struct acpi_driver acpi_button_driver = { .name = "button", @@ -102,6 +104,7 @@ struct acpi_button { struct input_dev *input; char phys[32]; /* for input device */ unsigned long pushed; + bool suspended; }; static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); @@ -293,15 +296,19 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) if (button->type == ACPI_BUTTON_TYPE_LID) { acpi_lid_send_state(device); } else { - int keycode = test_bit(KEY_SLEEP, input->keybit) ? - KEY_SLEEP : KEY_POWER; + int keycode; + + pm_wakeup_event(&device->dev, 0); + if (button->suspended) + break; + keycode = test_bit(KEY_SLEEP, input->keybit) ? + KEY_SLEEP : KEY_POWER; input_report_key(input, keycode, 1); input_sync(input); input_report_key(input, keycode, 0); input_sync(input); - pm_wakeup_event(&device->dev, 0); acpi_bus_generate_netlink_event( device->pnp.device_class, dev_name(&device->dev), @@ -316,11 +323,21 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) } #ifdef CONFIG_PM_SLEEP +static int acpi_button_suspend(struct device *dev) +{ + struct acpi_device *device = to_acpi_device(dev); + struct acpi_button *button = acpi_driver_data(device); + + button->suspended = true; + return 0; +} + static int acpi_button_resume(struct device *dev) { struct acpi_device *device = to_acpi_device(dev); struct acpi_button *button = acpi_driver_data(device); + button->suspended = false; if (button->type == ACPI_BUTTON_TYPE_LID) return acpi_lid_send_state(device); return 0; diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 49a5127..67075f8 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -367,29 +367,61 @@ EXPORT_SYMBOL(acpi_bus_power_manageable); #ifdef CONFIG_PM static DEFINE_MUTEX(acpi_pm_notifier_lock); +static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) +{ + struct acpi_device *adev; + + if (val != ACPI_NOTIFY_DEVICE_WAKE) + return; + + adev = acpi_bus_get_acpi_device(handle); + if (!adev) + return; + + mutex_lock(&acpi_pm_notifier_lock); + + if (adev->wakeup.flags.notifier_present) { + __pm_wakeup_event(adev->wakeup.ws, 0); + if (adev->wakeup.context.work.func) + queue_pm_work(&adev->wakeup.context.work); + } + + mutex_unlock(&acpi_pm_notifier_lock); + + acpi_bus_put_acpi_device(adev); +} + /** - * acpi_add_pm_notifier - Register PM notifier for given ACPI device. - * @adev: ACPI device to add the notifier for. - * @context: Context information to pass to the notifier routine. + * acpi_add_pm_notifier - Register PM notify handler for given ACPI device. + * @adev: ACPI device to add the notify handler for. + * @dev: Device to generate a wakeup event for while handling the notification. + * @work_func: Work function to execute when handling the notification. * * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of * PM wakeup events. For example, wakeup events may be generated for bridges * if one of the devices below the bridge is signaling wakeup, even if the * bridge itself doesn't have a wakeup GPE associated with it. */ -acpi_status acpi_add_pm_notifier(struct acpi_device *adev, - acpi_notify_handler handler, void *context) +acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, + void (*work_func)(struct work_struct *work)) { acpi_status status = AE_ALREADY_EXISTS; + if (!dev && !work_func) + return AE_BAD_PARAMETER; + mutex_lock(&acpi_pm_notifier_lock); if (adev->wakeup.flags.notifier_present) goto out; - status = acpi_install_notify_handler(adev->handle, - ACPI_SYSTEM_NOTIFY, - handler, context); + adev->wakeup.ws = wakeup_source_register(dev_name(&adev->dev)); + adev->wakeup.context.dev = dev; + if (work_func) + INIT_WORK(&adev->wakeup.context.work, work_func); + + status = acpi_install_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY, + acpi_pm_notify_handler, NULL); if (ACPI_FAILURE(status)) goto out; @@ -404,8 +436,7 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev, * acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device. * @adev: ACPI device to remove the notifier from. */ -acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, - acpi_notify_handler handler) +acpi_status acpi_remove_pm_notifier(struct acpi_device *adev) { acpi_status status = AE_BAD_PARAMETER; @@ -416,10 +447,17 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, status = acpi_remove_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY, - handler); + acpi_pm_notify_handler); if (ACPI_FAILURE(status)) goto out; + if (adev->wakeup.context.work.func) { + cancel_work_sync(&adev->wakeup.context.work); + adev->wakeup.context.work.func = NULL; + } + adev->wakeup.context.dev = NULL; + wakeup_source_unregister(adev->wakeup.ws); + adev->wakeup.flags.notifier_present = false; out: @@ -558,7 +596,6 @@ static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev, */ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) { - acpi_handle handle = ACPI_HANDLE(dev); struct acpi_device *adev; int ret, d_min, d_max; @@ -573,8 +610,9 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) d_max_in = ACPI_STATE_D3_HOT; } - if (!handle || acpi_bus_get_device(handle, &adev)) { - dev_dbg(dev, "ACPI handle without context in %s!\n", __func__); + adev = ACPI_COMPANION(dev); + if (!adev) { + dev_dbg(dev, "ACPI companion missing in %s!\n", __func__); return -ENODEV; } @@ -600,26 +638,25 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) } EXPORT_SYMBOL(acpi_pm_device_sleep_state); -#ifdef CONFIG_PM_RUNTIME /** - * acpi_wakeup_device - Wakeup notification handler for ACPI devices. - * @handle: ACPI handle of the device the notification is for. - * @event: Type of the signaled event. - * @context: Device corresponding to @handle. + * acpi_pm_notify_work_func - ACPI devices wakeup notification work function. + * @work: Work item to handle. */ -static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context) +static void acpi_pm_notify_work_func(struct work_struct *work) { - struct device *dev = context; + struct device *dev; - if (event == ACPI_NOTIFY_DEVICE_WAKE && dev) { + dev = container_of(work, struct acpi_device_wakeup_context, work)->dev; + if (dev) { pm_wakeup_event(dev, 0); pm_runtime_resume(dev); } } /** - * __acpi_device_run_wake - Enable/disable runtime remote wakeup for device. - * @adev: ACPI device to enable/disable the remote wakeup for. + * acpi_device_wakeup - Enable/disable wakeup functionality for device. + * @adev: ACPI device to enable/disable wakeup functionality for. + * @target_state: State the system is transitioning into. * @enable: Whether to enable or disable the wakeup functionality. * * Enable/disable the GPE associated with @adev so that it can generate @@ -629,7 +666,8 @@ static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context) * Callers must ensure that @adev is a valid ACPI device node before executing * this function. */ -int __acpi_device_run_wake(struct acpi_device *adev, bool enable) +static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state, + bool enable) { struct acpi_device_wakeup *wakeup = &adev->wakeup; @@ -637,7 +675,7 @@ int __acpi_device_run_wake(struct acpi_device *adev, bool enable) acpi_status res; int error; - error = acpi_enable_wakeup_device_power(adev, ACPI_STATE_S0); + error = acpi_enable_wakeup_device_power(adev, target_state); if (error) return error; @@ -653,6 +691,7 @@ int __acpi_device_run_wake(struct acpi_device *adev, bool enable) return 0; } +#ifdef CONFIG_PM_RUNTIME /** * acpi_pm_device_run_wake - Enable/disable remote wakeup for given device. * @dev: Device to enable/disable the platform to wake up. @@ -661,63 +700,42 @@ int __acpi_device_run_wake(struct acpi_device *adev, bool enable) int acpi_pm_device_run_wake(struct device *phys_dev, bool enable) { struct acpi_device *adev; - acpi_handle handle; if (!device_run_wake(phys_dev)) return -EINVAL; - handle = ACPI_HANDLE(phys_dev); - if (!handle || acpi_bus_get_device(handle, &adev)) { - dev_dbg(phys_dev, "ACPI handle without context in %s!\n", - __func__); + adev = ACPI_COMPANION(phys_dev); + if (!adev) { + dev_dbg(phys_dev, "ACPI companion missing in %s!\n", __func__); return -ENODEV; } - return __acpi_device_run_wake(adev, enable); + return acpi_device_wakeup(adev, enable, ACPI_STATE_S0); } EXPORT_SYMBOL(acpi_pm_device_run_wake); -#else -static inline void acpi_wakeup_device(acpi_handle handle, u32 event, - void *context) {} #endif /* CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_SLEEP /** - * __acpi_device_sleep_wake - Enable or disable device to wake up the system. - * @dev: Device to enable/desible to wake up the system. - * @target_state: System state the device is supposed to wake up from. - * @enable: Whether to enable or disable @dev to wake up the system. - */ -int __acpi_device_sleep_wake(struct acpi_device *adev, u32 target_state, - bool enable) -{ - return enable ? - acpi_enable_wakeup_device_power(adev, target_state) : - acpi_disable_wakeup_device_power(adev); -} - -/** * acpi_pm_device_sleep_wake - Enable or disable device to wake up the system. * @dev: Device to enable/desible to wake up the system from sleep states. * @enable: Whether to enable or disable @dev to wake up the system. */ int acpi_pm_device_sleep_wake(struct device *dev, bool enable) { - acpi_handle handle; struct acpi_device *adev; int error; if (!device_can_wakeup(dev)) return -EINVAL; - handle = ACPI_HANDLE(dev); - if (!handle || acpi_bus_get_device(handle, &adev)) { - dev_dbg(dev, "ACPI handle without context in %s!\n", __func__); + adev = ACPI_COMPANION(dev); + if (!adev) { + dev_dbg(dev, "ACPI companion missing in %s!\n", __func__); return -ENODEV; } - error = __acpi_device_sleep_wake(adev, acpi_target_system_state(), - enable); + error = acpi_device_wakeup(adev, acpi_target_system_state(), enable); if (!error) dev_info(dev, "System wakeup %s by ACPI\n", enable ? "enabled" : "disabled"); @@ -775,13 +793,13 @@ int acpi_dev_runtime_suspend(struct device *dev) remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) > PM_QOS_FLAGS_NONE; - error = __acpi_device_run_wake(adev, remote_wakeup); + error = acpi_device_wakeup(adev, ACPI_STATE_S0, remote_wakeup); if (remote_wakeup && error) return -EAGAIN; error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0); if (error) - __acpi_device_run_wake(adev, false); + acpi_device_wakeup(adev, ACPI_STATE_S0, false); return error; } @@ -804,7 +822,7 @@ int acpi_dev_runtime_resume(struct device *dev) return 0; error = acpi_dev_pm_full_power(adev); - __acpi_device_run_wake(adev, false); + acpi_device_wakeup(adev, ACPI_STATE_S0, false); return error; } EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume); @@ -860,13 +878,13 @@ int acpi_dev_suspend_late(struct device *dev) target_state = acpi_target_system_state(); wakeup = device_may_wakeup(dev); - error = __acpi_device_sleep_wake(adev, target_state, wakeup); + error = acpi_device_wakeup(adev, target_state, wakeup); if (wakeup && error) return error; error = acpi_dev_pm_low_power(dev, adev, target_state); if (error) - __acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false); + acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false); return error; } @@ -889,7 +907,7 @@ int acpi_dev_resume_early(struct device *dev) return 0; error = acpi_dev_pm_full_power(adev); - __acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false); + acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false); return error; } EXPORT_SYMBOL_GPL(acpi_dev_resume_early); @@ -1048,11 +1066,11 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) if (dev->pm_domain) return -EEXIST; - acpi_add_pm_notifier(adev, acpi_wakeup_device, dev); + acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func); dev->pm_domain = &acpi_general_pm_domain; if (power_on) { acpi_dev_pm_full_power(adev); - __acpi_device_run_wake(adev, false); + acpi_device_wakeup(adev, ACPI_STATE_S0, false); } return 0; } @@ -1076,7 +1094,7 @@ void acpi_dev_pm_detach(struct device *dev, bool power_off) if (adev && dev->pm_domain == &acpi_general_pm_domain) { dev->pm_domain = NULL; - acpi_remove_pm_notifier(adev, acpi_wakeup_device); + acpi_remove_pm_notifier(adev); if (power_off) { /* * If the device's PM QoS resume latency limit or flags @@ -1086,7 +1104,7 @@ void acpi_dev_pm_detach(struct device *dev, bool power_off) */ dev_pm_qos_hide_latency_limit(dev); dev_pm_qos_hide_flags(dev); - __acpi_device_run_wake(adev, false); + acpi_device_wakeup(adev, ACPI_STATE_S0, false); acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0); } } diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 7de5b60..4c5cf77 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -84,8 +84,6 @@ 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, struct acpi_device *adev); -int acpi_unbind_one(struct device *dev); bool acpi_device_is_present(struct acpi_device *adev); bool acpi_device_is_battery(struct acpi_device *adev); @@ -108,7 +106,12 @@ 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); + +#ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC void acpi_early_processor_set_pdc(void); +#else +static inline void acpi_early_processor_set_pdc(void) {} +#endif /* -------------------------------------------------------------------------- Embedded Controller diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index bad25b0..3abe9b2 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -259,12 +259,14 @@ acpi_physical_address __init acpi_os_get_root_pointer(void) "System description tables not found\n"); return 0; } - } else { + } else if (IS_ENABLED(CONFIG_ACPI_LEGACY_TABLES_LOOKUP)) { acpi_physical_address pa = 0; acpi_find_root_pointer(&pa); return pa; } + + return 0; } /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index d388f13..e6ae603 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -593,7 +593,7 @@ static int acpi_pci_root_add(struct acpi_device *device, if (no_aspm) pcie_no_aspm(); - pci_acpi_add_bus_pm_notifier(device, root->bus); + pci_acpi_add_bus_pm_notifier(device); if (device->wakeup.flags.run_wake) device_set_run_wake(root->bus->bridge, true); diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 71e2065..00f48d1 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -4,17 +4,11 @@ * * Alex Chiang <achiang@hp.com> * - Unified x86/ia64 implementations - * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> - * - Added _PDC for platforms with Intel CPUs */ #include <linux/export.h> -#include <linux/dmi.h> -#include <linux/slab.h> #include <linux/acpi.h> #include <acpi/processor.h> -#include "internal.h" - #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME("processor_core"); @@ -208,195 +202,3 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) return acpi_map_cpuid(apic_id, acpi_id); } EXPORT_SYMBOL_GPL(acpi_get_cpuid); - -static bool __init processor_physically_present(acpi_handle handle) -{ - int cpuid, type; - u32 acpi_id; - acpi_status status; - acpi_object_type acpi_type; - unsigned long long tmp; - union acpi_object object = { 0 }; - struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; - - status = acpi_get_type(handle, &acpi_type); - if (ACPI_FAILURE(status)) - return false; - - switch (acpi_type) { - case ACPI_TYPE_PROCESSOR: - status = acpi_evaluate_object(handle, NULL, NULL, &buffer); - if (ACPI_FAILURE(status)) - return false; - acpi_id = object.processor.proc_id; - break; - case ACPI_TYPE_DEVICE: - status = acpi_evaluate_integer(handle, "_UID", NULL, &tmp); - if (ACPI_FAILURE(status)) - return false; - acpi_id = tmp; - break; - default: - return false; - } - - type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0; - cpuid = acpi_get_cpuid(handle, type, acpi_id); - - if (cpuid == -1) - return false; - - return true; -} - -static void acpi_set_pdc_bits(u32 *buf) -{ - buf[0] = ACPI_PDC_REVISION_ID; - buf[1] = 1; - - /* Enable coordination with firmware's _TSD info */ - buf[2] = ACPI_PDC_SMP_T_SWCOORD; - - /* Twiddle arch-specific bits needed for _PDC */ - arch_acpi_set_pdc_bits(buf); -} - -static struct acpi_object_list *acpi_processor_alloc_pdc(void) -{ - struct acpi_object_list *obj_list; - union acpi_object *obj; - u32 *buf; - - /* allocate and initialize pdc. It will be used later. */ - obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); - if (!obj_list) { - printk(KERN_ERR "Memory allocation error\n"); - return NULL; - } - - obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); - if (!obj) { - printk(KERN_ERR "Memory allocation error\n"); - kfree(obj_list); - return NULL; - } - - buf = kmalloc(12, GFP_KERNEL); - if (!buf) { - printk(KERN_ERR "Memory allocation error\n"); - kfree(obj); - kfree(obj_list); - return NULL; - } - - acpi_set_pdc_bits(buf); - - obj->type = ACPI_TYPE_BUFFER; - obj->buffer.length = 12; - obj->buffer.pointer = (u8 *) buf; - obj_list->count = 1; - obj_list->pointer = obj; - - return obj_list; -} - -/* - * _PDC is required for a BIOS-OS handshake for most of the newer - * ACPI processor features. - */ -static acpi_status -acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in) -{ - acpi_status status = AE_OK; - - if (boot_option_idle_override == IDLE_NOMWAIT) { - /* - * If mwait is disabled for CPU C-states, the C2C3_FFH access - * mode will be disabled in the parameter of _PDC object. - * Of course C1_FFH access mode will also be disabled. - */ - union acpi_object *obj; - u32 *buffer = NULL; - - obj = pdc_in->pointer; - buffer = (u32 *)(obj->buffer.pointer); - buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH); - - } - status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL); - - if (ACPI_FAILURE(status)) - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Could not evaluate _PDC, using legacy perf. control.\n")); - - return status; -} - -void acpi_processor_set_pdc(acpi_handle handle) -{ - struct acpi_object_list *obj_list; - - if (arch_has_acpi_pdc() == false) - return; - - obj_list = acpi_processor_alloc_pdc(); - if (!obj_list) - return; - - acpi_processor_eval_pdc(handle, obj_list); - - kfree(obj_list->pointer->buffer.pointer); - kfree(obj_list->pointer); - kfree(obj_list); -} - -static acpi_status __init -early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - if (processor_physically_present(handle) == false) - return AE_OK; - - acpi_processor_set_pdc(handle); - return AE_OK; -} - -#if defined(CONFIG_X86) || defined(CONFIG_IA64) -static int __init set_no_mwait(const struct dmi_system_id *id) -{ - pr_notice(PREFIX "%s detected - disabling mwait for CPU C-states\n", - id->ident); - boot_option_idle_override = IDLE_NOMWAIT; - return 0; -} - -static struct dmi_system_id processor_idle_dmi_table[] __initdata = { - { - set_no_mwait, "Extensa 5220", { - DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), - DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL}, - {}, -}; - -static void __init processor_dmi_check(void) -{ - /* - * Check whether the system is DMI table. If yes, OSPM - * should not use mwait for CPU-states. - */ - dmi_check_system(processor_idle_dmi_table); -} -#else -static inline void processor_dmi_check(void) {} -#endif - -void __init acpi_early_processor_set_pdc(void) -{ - processor_dmi_check(); - - acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, - early_init_pdc, NULL, NULL, NULL); - acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, early_init_pdc, NULL, NULL); -} diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c new file mode 100644 index 0000000..e5dd808 --- /dev/null +++ b/drivers/acpi/processor_pdc.c @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2005 Intel Corporation + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. + * + * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> + * - Added _PDC for platforms with Intel CPUs + */ + +#define pr_fmt(fmt) "ACPI: " fmt + +#include <linux/dmi.h> +#include <linux/slab.h> +#include <linux/acpi.h> +#include <acpi/processor.h> + +#include "internal.h" + +#define _COMPONENT ACPI_PROCESSOR_COMPONENT +ACPI_MODULE_NAME("processor_pdc"); + +static bool __init processor_physically_present(acpi_handle handle) +{ + int cpuid, type; + u32 acpi_id; + acpi_status status; + acpi_object_type acpi_type; + unsigned long long tmp; + union acpi_object object = { 0 }; + struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; + + status = acpi_get_type(handle, &acpi_type); + if (ACPI_FAILURE(status)) + return false; + + switch (acpi_type) { + case ACPI_TYPE_PROCESSOR: + status = acpi_evaluate_object(handle, NULL, NULL, &buffer); + if (ACPI_FAILURE(status)) + return false; + acpi_id = object.processor.proc_id; + break; + case ACPI_TYPE_DEVICE: + status = acpi_evaluate_integer(handle, "_UID", NULL, &tmp); + if (ACPI_FAILURE(status)) + return false; + acpi_id = tmp; + break; + default: + return false; + } + + type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0; + cpuid = acpi_get_cpuid(handle, type, acpi_id); + + if (cpuid == -1) + return false; + + return true; +} + +static void acpi_set_pdc_bits(u32 *buf) +{ + buf[0] = ACPI_PDC_REVISION_ID; + buf[1] = 1; + + /* Enable coordination with firmware's _TSD info */ + buf[2] = ACPI_PDC_SMP_T_SWCOORD; + + /* Twiddle arch-specific bits needed for _PDC */ + arch_acpi_set_pdc_bits(buf); +} + +static struct acpi_object_list *acpi_processor_alloc_pdc(void) +{ + struct acpi_object_list *obj_list; + union acpi_object *obj; + u32 *buf; + + /* allocate and initialize pdc. It will be used later. */ + obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); + if (!obj_list) + goto out; + + obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); + if (!obj) { + kfree(obj_list); + goto out; + } + + buf = kmalloc(12, GFP_KERNEL); + if (!buf) { + kfree(obj); + kfree(obj_list); + goto out; + } + + acpi_set_pdc_bits(buf); + + obj->type = ACPI_TYPE_BUFFER; + obj->buffer.length = 12; + obj->buffer.pointer = (u8 *) buf; + obj_list->count = 1; + obj_list->pointer = obj; + + return obj_list; +out: + pr_err("Memory allocation error\n"); + return NULL; +} + +/* + * _PDC is required for a BIOS-OS handshake for most of the newer + * ACPI processor features. + */ +static acpi_status +acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in) +{ + acpi_status status = AE_OK; + + if (boot_option_idle_override == IDLE_NOMWAIT) { + /* + * If mwait is disabled for CPU C-states, the C2C3_FFH access + * mode will be disabled in the parameter of _PDC object. + * Of course C1_FFH access mode will also be disabled. + */ + union acpi_object *obj; + u32 *buffer = NULL; + + obj = pdc_in->pointer; + buffer = (u32 *)(obj->buffer.pointer); + buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH); + + } + status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL); + + if (ACPI_FAILURE(status)) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Could not evaluate _PDC, using legacy perf. control.\n")); + + return status; +} + +void acpi_processor_set_pdc(acpi_handle handle) +{ + struct acpi_object_list *obj_list; + + if (arch_has_acpi_pdc() == false) + return; + + obj_list = acpi_processor_alloc_pdc(); + if (!obj_list) + return; + + acpi_processor_eval_pdc(handle, obj_list); + + kfree(obj_list->pointer->buffer.pointer); + kfree(obj_list->pointer); + kfree(obj_list); +} + +static acpi_status __init +early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + if (processor_physically_present(handle) == false) + return AE_OK; + + acpi_processor_set_pdc(handle); + return AE_OK; +} + +static int __init set_no_mwait(const struct dmi_system_id *id) +{ + pr_notice("%s detected - disabling mwait for CPU C-states\n", + id->ident); + boot_option_idle_override = IDLE_NOMWAIT; + return 0; +} + +static struct dmi_system_id processor_idle_dmi_table[] __initdata = { + { + set_no_mwait, "Extensa 5220", { + DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), + DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL}, + {}, +}; + +static void __init processor_dmi_check(void) +{ + /* + * Check whether the system is DMI table. If yes, OSPM + * should not use mwait for CPU-states. + */ + dmi_check_system(processor_idle_dmi_table); +} + +void __init acpi_early_processor_set_pdc(void) +{ + processor_dmi_check(); + + acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, + early_init_pdc, NULL, NULL, NULL); + acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, early_init_pdc, NULL, NULL); +} diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 3ffc930..5d592e1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1423,14 +1423,13 @@ static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, wakeup->sleep_state = sleep_state; } } - acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number); out: kfree(buffer.pointer); return err; } -static void acpi_bus_set_run_wake_flags(struct acpi_device *device) +static void acpi_wakeup_gpe_init(struct acpi_device *device) { struct acpi_device_id button_device_ids[] = { {"PNP0C0C", 0}, @@ -1438,29 +1437,33 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) {"PNP0C0E", 0}, {"", 0}, }; + struct acpi_device_wakeup *wakeup = &device->wakeup; acpi_status status; acpi_event_status event_status; - device->wakeup.flags.notifier_present = 0; + wakeup->flags.notifier_present = 0; /* Power button, Lid switch always enable wakeup */ if (!acpi_match_device_ids(device, button_device_ids)) { - device->wakeup.flags.run_wake = 1; + wakeup->flags.run_wake = 1; if (!acpi_match_device_ids(device, &button_device_ids[1])) { /* Do not use Lid/sleep button for S5 wakeup */ - if (device->wakeup.sleep_state == ACPI_STATE_S5) - device->wakeup.sleep_state = ACPI_STATE_S4; + if (wakeup->sleep_state == ACPI_STATE_S5) + wakeup->sleep_state = ACPI_STATE_S4; } + acpi_mark_gpe_for_wake(wakeup->gpe_device, wakeup->gpe_number); device_set_wakeup_capable(&device->dev, true); return; } - status = acpi_get_gpe_status(device->wakeup.gpe_device, - device->wakeup.gpe_number, - &event_status); - if (status == AE_OK) - device->wakeup.flags.run_wake = - !!(event_status & ACPI_EVENT_FLAG_HANDLE); + acpi_setup_gpe_for_wake(device->handle, wakeup->gpe_device, + wakeup->gpe_number); + status = acpi_get_gpe_status(wakeup->gpe_device, wakeup->gpe_number, + &event_status); + if (ACPI_FAILURE(status)) + return; + + wakeup->flags.run_wake = !!(event_status & ACPI_EVENT_FLAG_HANDLE); } static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) @@ -1480,7 +1483,7 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) device->wakeup.flags.valid = 1; device->wakeup.prepare_count = 0; - acpi_bus_set_run_wake_flags(device); + acpi_wakeup_gpe_init(device); /* Call _PSW/_DSW object to disable its ability to wake the sleeping * system for the ACPI device with the _PRW object. * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW. diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index b3e3cc7..54da4a3 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -322,6 +322,11 @@ static struct dmi_system_id acpisleep_dmi_table[] __initdata = { static void acpi_sleep_dmi_check(void) { + int year; + + if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year >= 2012) + acpi_nvs_nosave_s3(); + dmi_check_system(acpisleep_dmi_table); } diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 071c1df..18c0e69 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -68,7 +68,7 @@ MODULE_AUTHOR("Bruno Ducrot"); MODULE_DESCRIPTION("ACPI Video Driver"); MODULE_LICENSE("GPL"); -static bool brightness_switch_enabled; +static bool brightness_switch_enabled = 1; module_param(brightness_switch_enabled, bool, 0644); /* @@ -204,6 +204,8 @@ struct acpi_video_device { struct acpi_video_device_flags flags; struct acpi_video_device_cap cap; struct list_head entry; + struct delayed_work switch_brightness_work; + int switch_brightness_event; struct acpi_video_bus *video; struct acpi_device *dev; struct acpi_video_device_brightness *brightness; @@ -230,8 +232,7 @@ static int acpi_video_device_lcd_get_level_current( unsigned long long *level, bool raw); static int acpi_video_get_next_level(struct acpi_video_device *device, u32 level_current, u32 event); -static int acpi_video_switch_brightness(struct acpi_video_device *device, - int event); +static void acpi_video_switch_brightness(struct work_struct *work); static bool acpi_video_use_native_backlight(void) { @@ -275,6 +276,7 @@ static int acpi_video_set_brightness(struct backlight_device *bd) int request_level = bd->props.brightness + 2; struct acpi_video_device *vd = bl_get_data(bd); + cancel_delayed_work(&vd->switch_brightness_work); return acpi_video_device_lcd_set_level(vd, vd->brightness->levels[request_level]); } @@ -461,6 +463,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { }, { .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 T430 and T430s", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), @@ -469,10 +479,42 @@ static struct dmi_system_id video_dmi_table[] __initdata = { }, { .callback = video_set_use_native_backlight, - .ident = "ThinkPad X230", + .ident = "ThinkPad T430", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"), + DMI_MATCH(DMI_PRODUCT_VERSION, "2349D15"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad T431s", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "20AACTO1WW"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad Edge E530", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "3259A2G"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad Edge E530", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "3259CTO"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad Edge E530", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "3259HJG"), }, }, { @@ -572,6 +614,30 @@ static struct dmi_system_id video_dmi_table[] __initdata = { }, }, { + .callback = video_set_use_native_backlight, + .ident = "Acer Aspire V5-572G", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer Aspire"), + DMI_MATCH(DMI_PRODUCT_VERSION, "V5-572G/Dazzle_CX"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "Acer Aspire V5-573G", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer Aspire"), + DMI_MATCH(DMI_PRODUCT_VERSION, "V5-573G/Dazzle_HW"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "ASUS Zenbook Prime UX31A", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX31A"), + }, + }, + { .callback = video_set_use_native_backlight, .ident = "HP ProBook 4340s", .matches = { @@ -581,6 +647,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { }, { .callback = video_set_use_native_backlight, + .ident = "HP ProBook 4540s", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_VERSION, "HP ProBook 4540s"), + }, + }, + { + .callback = video_set_use_native_backlight, .ident = "HP ProBook 2013 models", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), @@ -1180,6 +1254,8 @@ acpi_video_bus_get_one_device(struct acpi_device *device, data->device_id = device_id; data->video = video; data->dev = device; + INIT_DELAYED_WORK(&data->switch_brightness_work, + acpi_video_switch_brightness); attribute = acpi_video_get_device_attr(video, device_id); @@ -1402,15 +1478,18 @@ acpi_video_get_next_level(struct acpi_video_device *device, } } -static int -acpi_video_switch_brightness(struct acpi_video_device *device, int event) +static void +acpi_video_switch_brightness(struct work_struct *work) { + struct acpi_video_device *device = container_of(to_delayed_work(work), + struct acpi_video_device, switch_brightness_work); unsigned long long level_current, level_next; + int event = device->switch_brightness_event; int result = -EINVAL; /* no warning message if acpi_backlight=vendor or a quirk is used */ if (!acpi_video_verify_backlight_support()) - return 0; + return; if (!device->brightness) goto out; @@ -1432,8 +1511,6 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event) out: if (result) printk(KERN_ERR PREFIX "Failed to switch the brightness\n"); - - return result; } int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, @@ -1601,6 +1678,16 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) return; } +static void brightness_switch_event(struct acpi_video_device *video_device, + u32 event) +{ + if (!brightness_switch_enabled) + return; + + video_device->switch_brightness_event = event; + schedule_delayed_work(&video_device->switch_brightness_work, HZ / 10); +} + static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) { struct acpi_video_device *video_device = data; @@ -1618,28 +1705,23 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) switch (event) { case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ - if (brightness_switch_enabled) - acpi_video_switch_brightness(video_device, event); + brightness_switch_event(video_device, event); keycode = KEY_BRIGHTNESS_CYCLE; break; case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ - if (brightness_switch_enabled) - acpi_video_switch_brightness(video_device, event); + brightness_switch_event(video_device, event); keycode = KEY_BRIGHTNESSUP; break; case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ - if (brightness_switch_enabled) - acpi_video_switch_brightness(video_device, event); + brightness_switch_event(video_device, event); keycode = KEY_BRIGHTNESSDOWN; break; case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightness */ - if (brightness_switch_enabled) - acpi_video_switch_brightness(video_device, event); + brightness_switch_event(video_device, event); keycode = KEY_BRIGHTNESS_ZERO; break; case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */ - if (brightness_switch_enabled) - acpi_video_switch_brightness(video_device, event); + brightness_switch_event(video_device, event); keycode = KEY_DISPLAY_OFF; break; default: |