From 1d44efab14ed537d7c9585c110ce4c103ced336f Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:36:47 +0800 Subject: [PATCH 001/134] ACPICA: Add EXPORT_SYMBOL macros for install/remove SCI handler interfaces. These recently added interfaces did not have these macros, used by some hosts. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/evxface.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index a734b27da061..a41a0e75b1b6 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -457,6 +457,8 @@ acpi_status acpi_install_sci_handler(acpi_sci_handler address, void *context) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_install_sci_handler) + /******************************************************************************* * * FUNCTION: acpi_remove_sci_handler @@ -468,7 +470,6 @@ acpi_status acpi_install_sci_handler(acpi_sci_handler address, void *context) * DESCRIPTION: Remove a handler for a System Control Interrupt. * ******************************************************************************/ - acpi_status acpi_remove_sci_handler(acpi_sci_handler address) { struct acpi_sci_handler_info *prev_sci_handler; @@ -522,6 +523,8 @@ acpi_status acpi_remove_sci_handler(acpi_sci_handler address) return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_remove_sci_handler) + /******************************************************************************* * * FUNCTION: acpi_install_global_event_handler @@ -537,7 +540,6 @@ acpi_status acpi_remove_sci_handler(acpi_sci_handler address) * Can be used to update event counters, etc. * ******************************************************************************/ - acpi_status acpi_install_global_event_handler(acpi_gbl_event_handler handler, void *context) { From 5d42b0fa25df7ef2f575107597c1aaebe2407d10 Mon Sep 17 00:00:00 2001 From: David Binderman Date: Fri, 4 Apr 2014 12:36:55 +0800 Subject: [PATCH 002/134] ACPICA: utstring: Check array index bound before use. ACPICA BZ 1077. David Binderman. References: https://bugs.acpica.org/show_bug.cgi?id=1077 Signed-off-by: David Binderman Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Cc: 3.9+ # 3.9.x: 42f8fb75: ACPICA: Source restructuring Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utstring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index 77219336c7e0..6dc54b3c28b0 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -353,7 +353,7 @@ void acpi_ut_print_string(char *string, u16 max_length) } acpi_os_printf("\""); - for (i = 0; string[i] && (i < max_length); i++) { + for (i = 0; (i < max_length) && string[i]; i++) { /* Escape sequences */ From 6085bb18afa431823a6287a0aa4d13641acb658d Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:37:11 +0800 Subject: [PATCH 003/134] ACPICA: Update comments for ACPICA name - no functional change. Change all comments that contain the string "ACPI CA" to "ACPICA" so that the name is standard across the entire source base. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 4 ++-- drivers/acpi/acpica/evsci.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 49bbc71fad54..11ce629359ef 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -103,8 +103,8 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_auto_serialize_methods, TRUE); /* * Create the predefined _OSI method in the namespace? Default is TRUE - * because ACPI CA is fully compatible with other ACPI implementations. - * Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior. + * because ACPICA is fully compatible with other ACPI implementations. + * Changing this will revert ACPICA (and machine ASL) to pre-OSI behavior. */ ACPI_INIT_GLOBAL(u8, acpi_gbl_create_osi_method, TRUE); diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c index 4d8a709c1fc4..29630e303829 100644 --- a/drivers/acpi/acpica/evsci.c +++ b/drivers/acpi/acpica/evsci.c @@ -117,7 +117,7 @@ static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context) ACPI_FUNCTION_TRACE(ev_sci_xrupt_handler); /* - * We are guaranteed by the ACPI CA initialization/shutdown code that + * We are guaranteed by the ACPICA initialization/shutdown code that * if this interrupt handler is installed, ACPI is enabled. */ From 7ed823264845f7c2f14d3278405e593ddfdc50f6 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:37:19 +0800 Subject: [PATCH 004/134] ACPICA: gcc-specific: Fix possible issue with the strchr function. Some versions of gcc implement strchr via a macro, which either contains bugs or can provoke a bug in the compiler. This change fixes a possible compile-time error when using this function. The problem is usually seen when compiling the getopt.c module. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/platform/acgcc.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h index a476b9118b49..384875da3713 100644 --- a/include/acpi/platform/acgcc.h +++ b/include/acpi/platform/acgcc.h @@ -64,4 +64,15 @@ */ #define ACPI_UNUSED_VAR __attribute__ ((unused)) +/* + * Some versions of gcc implement strchr() with a buggy macro. So, + * undef it here. Prevents error messages of this form (usually from the + * file getopt.c): + * + * error: logical '&&' with non-zero constant will always evaluate as true + */ +#ifdef strchr +#undef strchr +#endif + #endif /* __ACGCC_H__ */ From 43d1a62d651233fe4d28f7d9e8f9c13d2a1ad1bc Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:37:26 +0800 Subject: [PATCH 005/134] ACPICA: Unload operator: Emit a warning if and when it is ever used. We would like to see the ASL for any machine that uses this operator, so emit at least a warning to hopefully draw some attention. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/exconfig.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 8ba1464efd11..1b734eb7c0c0 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -575,6 +575,13 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) ACPI_FUNCTION_TRACE(ex_unload_table); + /* + * Temporarily emit a warning so that the ASL for the machine can be + * hopefully obtained. This is to say that the Unload() operator is + * extremely rare if not completely unused. + */ + ACPI_WARNING((AE_INFO, "Received request to unload an ACPI table")); + /* * Validate the handle * Although the handle is partially validated in acpi_ex_reconfiguration() From b944b29c90a18d6254fca4a018195adc8802cf2e Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:37:35 +0800 Subject: [PATCH 006/134] ACPICA: Disassembler: Add support to decode _HID and _CID values. For _HID and _CID, the disassembler will emit a string that describes the device if the _HID/_CID value is recognized. acpihelp updated also. acpihelp will now search for a specific ID as well as displaying the list of "known" (to ACPICA) IDs. This patch does not affect Linux kernel behavior as the disassembler and the acpihelp are not shipped with it. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 1 + drivers/acpi/acpica/aclocal.h | 8 +++++++- drivers/acpi/acpica/acutils.h | 7 +++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 11ce629359ef..71bb5b50c656 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -509,5 +509,6 @@ ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_debug_file, NULL); ****************************************************************************/ extern const struct ah_predefined_name asl_predefined_info[]; +extern const AH_DEVICE_ID asl_device_ids[]; #endif /* __ACGLOBAL_H__ */ diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 52a21dafb540..f68cb602dc23 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -733,7 +733,8 @@ union acpi_parse_value { #define ACPI_DASM_MATCHOP 0x06 /* Parent opcode is a Match() operator */ #define ACPI_DASM_LNOT_PREFIX 0x07 /* Start of a Lnot_equal (etc.) pair of opcodes */ #define ACPI_DASM_LNOT_SUFFIX 0x08 /* End of a Lnot_equal (etc.) pair of opcodes */ -#define ACPI_DASM_IGNORE 0x09 /* Not used at this time */ +#define ACPI_DASM_HID_STRING 0x09 /* String is a _HID or _CID */ +#define ACPI_DASM_IGNORE 0x0A /* Not used at this time */ /* * Generic operation (for example: If, While, Store) @@ -1147,4 +1148,9 @@ struct ah_predefined_name { #endif }; +struct ah_device_id { + char *name; + char *description; +}; + #endif /* __ACLOCAL_H__ */ diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index ceeec0b7ccb1..532861001e06 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -737,4 +737,11 @@ acpi_ut_method_error(const char *module_name, struct acpi_namespace_node *node, const char *path, acpi_status lookup_status); +/* + * Utility functions for ACPI names and IDs + */ +const struct ah_predefined_name *acpi_ah_match_predefined_name(char *nameseg); + +const AH_DEVICE_ID *acpi_ah_match_hardware_id(char *hid); + #endif /* _ACUTILS_H */ From 06a63e33f32fd6b68cc78fd88f294d0fee6b889a Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:37:44 +0800 Subject: [PATCH 007/134] ACPICA: Disassembler: Add decoding of Notify() values. For Notify operators, displays a comment that describe the meaning of the notify value. This patch updates the debugging information that is enabled for CONFIG_ACPI_DEBUG builds. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acutils.h | 3 +- drivers/acpi/acpica/evmisc.c | 3 +- drivers/acpi/acpica/utdecode.c | 76 ++++++++++++++++++++++++++++------ 3 files changed, 67 insertions(+), 15 deletions(-) diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 532861001e06..2cf8d2c7133b 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -176,8 +176,7 @@ acpi_status acpi_ut_init_globals(void); char *acpi_ut_get_mutex_name(u32 mutex_id); -const char *acpi_ut_get_notify_name(u32 notify_value); - +const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type); #endif char *acpi_ut_get_type_name(acpi_object_type type); diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index 5d594eb2e5ec..24ea3424981b 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -167,7 +167,8 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n", acpi_ut_get_node_name(node), acpi_ut_get_type_name(node->type), notify_value, - acpi_ut_get_notify_name(notify_value), node)); + acpi_ut_get_notify_name(notify_value, ACPI_TYPE_ANY), + node)); status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch, info); diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index fbfa9eca011f..90ec37c473c6 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -462,7 +462,7 @@ char *acpi_ut_get_mutex_name(u32 mutex_id) /* Names for Notify() values, used for debug output */ -static const char *acpi_gbl_notify_value_names[ACPI_NOTIFY_MAX + 1] = { +static const char *acpi_gbl_generic_notify[ACPI_NOTIFY_MAX + 1] = { /* 00 */ "Bus Check", /* 01 */ "Device Check", /* 02 */ "Device Wake", @@ -473,23 +473,75 @@ static const char *acpi_gbl_notify_value_names[ACPI_NOTIFY_MAX + 1] = { /* 07 */ "Power Fault", /* 08 */ "Capabilities Check", /* 09 */ "Device PLD Check", - /* 10 */ "Reserved", - /* 11 */ "System Locality Update", - /* 12 */ "Shutdown Request" + /* 0A */ "Reserved", + /* 0B */ "System Locality Update", + /* 0C */ "Shutdown Request" }; -const char *acpi_ut_get_notify_name(u32 notify_value) +static const char *acpi_gbl_device_notify[4] = { + /* 80 */ "Status Change", + /* 81 */ "Information Change", + /* 82 */ "Device-Specific Change", + /* 83 */ "Device-Specific Change" +}; + +static const char *acpi_gbl_processor_notify[4] = { + /* 80 */ "Performance Capability Change", + /* 81 */ "C-State Change", + /* 82 */ "Throttling Capability Change", + /* 83 */ "Device-Specific Change" +}; + +static const char *acpi_gbl_thermal_notify[4] = { + /* 80 */ "Thermal Status Change", + /* 81 */ "Thermal Trip Point Change", + /* 82 */ "Thermal Device List Change", + /* 83 */ "Thermal Relationship Change" +}; + +const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type) { + /* 00 - 0C are common to all object types */ + if (notify_value <= ACPI_NOTIFY_MAX) { - return (acpi_gbl_notify_value_names[notify_value]); - } else if (notify_value <= ACPI_MAX_SYS_NOTIFY) { - return ("Reserved"); - } else if (notify_value <= ACPI_MAX_DEVICE_SPECIFIC_NOTIFY) { - return ("Device Specific"); - } else { - return ("Hardware Specific"); + return (acpi_gbl_generic_notify[notify_value]); } + + /* 0D - 7F are reserved */ + + if (notify_value <= ACPI_MAX_SYS_NOTIFY) { + return ("Reserved"); + } + + /* 80 - 83 are per-object-type */ + + if (notify_value <= 0x83) { + switch (type) { + case ACPI_TYPE_ANY: + case ACPI_TYPE_DEVICE: + return (acpi_gbl_device_notify[notify_value - 0x80]); + + case ACPI_TYPE_PROCESSOR: + return (acpi_gbl_processor_notify[notify_value - 0x80]); + + case ACPI_TYPE_THERMAL: + return (acpi_gbl_thermal_notify[notify_value - 0x80]); + + default: + return ("Target object type does not support notifies"); + } + } + + /* 84 - BF are device-specific */ + + if (notify_value <= ACPI_MAX_DEVICE_SPECIFIC_NOTIFY) { + return ("Device-Specific"); + } + + /* C0 and above are hardware-specific */ + + return ("Hardware-Specific"); } #endif From 69c841b6dd8313c9a673246cc0e2535174272cab Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:37:51 +0800 Subject: [PATCH 008/134] ACPICA: Update use of acpi_os_wait_events_complete interface. This patch cleans up all of the acpi_os_wait_events_complete() invocations to make it to be invoked inside of ACPICA in the way to accommodate Linux's work queue implementation. According to the report, current Linux kernel code is facing a boot time race issue in the acpi_remove_notify_handler(). This is because: Linux is using work queues to implement a deferred handler call environment while ACPICA expects OSPM to implement acpi_os_wait_events_complete() using wait queues. The position to invoke a "waiter" is not suitable for a "flusher" as new invocations can be scheduled after this position and before the deletion of the handler from its management container. Since the following commit has deleted acpi_os_wait_events_complete() parameters, it thus might not be possible for OSPM to achieve a safe removal using wait queues. This requires ACPICA to be changed accordingly to "flush" handlers rather than "wait" them to be drain up: Commit: 5ff986a2a9db11858247b71fe242fe17617229aa Date: Wed, 16 May 2012 13:36:07 -0700 Subject: Introduce acpi_os_wait_events_complete interface. This interface will block until asynchronous events like notifies and GPEs are complete. Within ACPICA, it is called before a notify or GPE handler is removed. ACPICA BZ 868. This patch fixes this issue by invoking acpi_os_wait_events_complete() in the way to "flush" things - it thus should be put to the position after handler is removed from its management container but before it is destructed. The technical concerns are: 1. MTX_NAMESPACE is used to protect things that acpi_os_wait_events_complete() might be waiting for, thus MTX_NAMESPACE must be unlocked before invoking acpi_os_wait_events_complete(). 2. MTX_NAMESPACE is also used to implement the serialization of acpi_install_notify_handler() and acpi_remove_notify_handler(). This patch changes this logic, thus if there are many acpi_install/remove_notify_handler() invoked in parallel, the acpi_os_wait_events_complete() might face the races which could cause it never running to an end. Normally this will require additional code to implement a separate locking facility which is not implemented due to 3. 3. Given ACPICA users will always invoke acpi_install_notify_handler() once during Linux module/device initialization and invoke acpi_remove_notify_handler() once during module/device finalization, problem stated in 2 will not happen in Linux environment due to the mutual exclusive module/device existence, this fix thus is sufficient. Same concerns can apply to acpi_install/remove_gpe_handler(). Reported and tested: Ronald Vink. Fixed: Lv Zheng. References: https://bugzilla.kernel.org/show_bug.cgi?id=60583 Signed-off-by: Lv Zheng Reported-and-Tested-by: Ronald Vink Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/evxface.c | 55 +++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index a41a0e75b1b6..11e5803b8b41 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -239,7 +239,7 @@ acpi_remove_notify_handler(acpi_handle device, union acpi_operand_object *obj_desc; union acpi_operand_object *handler_obj; union acpi_operand_object *previous_handler_obj; - acpi_status status; + acpi_status status = AE_OK; u32 i; ACPI_FUNCTION_TRACE(acpi_remove_notify_handler); @@ -251,20 +251,17 @@ acpi_remove_notify_handler(acpi_handle device, return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Make sure all deferred notify tasks are completed */ - - acpi_os_wait_events_complete(); - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - /* Root Object. Global handlers are removed here */ if (device == ACPI_ROOT_OBJECT) { for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { if (handler_type & (i + 1)) { + status = + acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + if (!acpi_gbl_global_notify[i].handler || (acpi_gbl_global_notify[i].handler != handler)) { @@ -277,31 +274,40 @@ acpi_remove_notify_handler(acpi_handle device, acpi_gbl_global_notify[i].handler = NULL; acpi_gbl_global_notify[i].context = NULL; + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + + /* Make sure all deferred notify tasks are completed */ + + acpi_os_wait_events_complete(); } } - goto unlock_and_exit; + return_ACPI_STATUS(AE_OK); } /* All other objects: Are Notifies allowed on this object? */ if (!acpi_ev_is_notify_object(node)) { - status = AE_TYPE; - goto unlock_and_exit; + return_ACPI_STATUS(AE_TYPE); } /* Must have an existing internal object */ obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { - status = AE_NOT_EXIST; - goto unlock_and_exit; + return_ACPI_STATUS(AE_NOT_EXIST); } /* Internal object exists. Find the handler and remove it */ for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { if (handler_type & (i + 1)) { + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + handler_obj = obj_desc->common_notify.notify_list[i]; previous_handler_obj = NULL; @@ -329,10 +335,17 @@ acpi_remove_notify_handler(acpi_handle device, handler_obj->notify.next[i]; } + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + + /* Make sure all deferred notify tasks are completed */ + + acpi_os_wait_events_complete(); acpi_ut_remove_reference(handler_obj); } } + return_ACPI_STATUS(status); + unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); @@ -842,10 +855,6 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Make sure all deferred GPE tasks are completed */ - - acpi_os_wait_events_complete(); - status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -897,9 +906,17 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, (void)acpi_ev_add_gpe_reference(gpe_event_info); } + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); + + /* Make sure all deferred GPE tasks are completed */ + + acpi_os_wait_events_complete(); + /* Now we can free the handler object */ ACPI_FREE(handler); + return_ACPI_STATUS(status); unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); From a3a80da3ef396c5c64ade0c834a8145d3f283a24 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:37:59 +0800 Subject: [PATCH 009/134] ACPICA: Clean up comment divergences in aclinux.h When the following commmit is back ported to ACPICA, comments have been updated: Subject: ACPICA: Linux-specific header: Update support for Linux/acpi applications. This patch back ports the differences between the ACPICA upstream and Linux. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore [rjw: Subject] Signed-off-by: Rafael J. Wysocki --- include/acpi/platform/aclinux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 93c55ed7c53d..0d94be8531b5 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -91,7 +91,7 @@ #include #include -/* Disable kernel specific declarators */ +/* Define/disable kernel-specific declarators */ #ifndef __init #define __init From 72bdad969271b713e109fd747111d39a0b41d289 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 4 Apr 2014 12:38:05 +0800 Subject: [PATCH 010/134] ACPICA: Linux-specific header: Add support for PPC64 compilation. Adds PPC64 as a 64-bit architecture. Colin Ian King. Signed-off-by: Colin Ian King Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/platform/aclinux.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 0d94be8531b5..f2429094b9b9 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -106,7 +106,8 @@ #define ACPI_FLUSH_CPU_CACHE() #define ACPI_CAST_PTHREAD_T(pthread) ((acpi_thread_id) (pthread)) -#if defined(__ia64__) || defined(__x86_64__) || defined(__aarch64__) +#if defined(__ia64__) || defined(__x86_64__) ||\ + defined(__aarch64__) || defined(__PPC64__) #define ACPI_MACHINE_WIDTH 64 #define COMPILER_DEPENDENT_INT64 long #define COMPILER_DEPENDENT_UINT64 unsigned long From 0745fb41c3c8ab3c472c8195baed1e5098b44e09 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:38:12 +0800 Subject: [PATCH 011/134] ACPICA: Add a missing field for debug dump of mutex objects. Adds "OriginalSyncLevel" field to the output. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/exdump.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 973fdae00f94..925202acc3e4 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -134,9 +134,11 @@ static struct acpi_exdump_info acpi_ex_dump_method[9] = { {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.aml_start), "Aml Start"} }; -static struct acpi_exdump_info acpi_ex_dump_mutex[5] = { +static struct acpi_exdump_info acpi_ex_dump_mutex[6] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.sync_level), "Sync Level"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.original_sync_level), + "Original Sync Level"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"}, {ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth), "Acquire Depth"}, From 5582982d1acefe37528a3de8b42e81a7b0a75cfb Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:38:18 +0800 Subject: [PATCH 012/134] ACPICA: Remove indent divergences to reduce maintenance overhead. The divergences in the ACPICA files makes it difficult to maintain linuxize ACPICA table commits. This patch reduces such divergences before applying table manager commits so that human interventions of patch rebasing can be reduced. Signed-off-by: Lv Zheng [rjw: Subject] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/tbinstal.c | 6 +++++- drivers/acpi/acpica/tbutils.c | 4 ++-- drivers/acpi/acpica/tbxface.c | 10 +++++----- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index e3040947e9a0..73fffb0f3dd3 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -75,6 +75,7 @@ acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc) acpi_os_map_memory(table_desc->address, table_desc->length); } + if (!table_desc->pointer) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -459,10 +460,13 @@ acpi_tb_store_table(acpi_physical_address address, void acpi_tb_delete_table(struct acpi_table_desc *table_desc) { + /* Table must be mapped or allocated */ + if (!table_desc->pointer) { return; } + switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { case ACPI_TABLE_ORIGIN_MAPPED: @@ -657,7 +661,7 @@ acpi_status acpi_tb_release_owner_id(u32 table_index) * ******************************************************************************/ -acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id) +acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id * owner_id) { acpi_status status = AE_BAD_PARAMETER; diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index a4702eee91a8..3f1afca87aeb 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -582,8 +582,8 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) if (ACPI_FAILURE(status)) { ACPI_WARNING((AE_INFO, "Truncating %u table entries!", - (unsigned) (table_count - - (acpi_gbl_root_table_list. + (unsigned)(table_count - + (acpi_gbl_root_table_list. current_table_count - 2)))); break; diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index a1593159d9ea..4debc1290d0a 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -206,8 +206,8 @@ acpi_status acpi_get_table_header(char *signature, u32 instance, struct acpi_table_header *out_table_header) { - u32 i; - u32 j; + u32 i; + u32 j; struct acpi_table_header *header; /* Parameter validation */ @@ -321,8 +321,8 @@ acpi_get_table_with_size(char *signature, u32 instance, struct acpi_table_header **out_table, acpi_size *tbl_size) { - u32 i; - u32 j; + u32 i; + u32 j; acpi_status status; /* Parameter validation */ @@ -390,7 +390,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table) * ******************************************************************************/ acpi_status -acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table) +acpi_get_table_by_index(u32 table_index, struct acpi_table_header ** table) { acpi_status status; From dc156adf0d1b9d9ea54a86ca803ac5202ab139c7 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:38:26 +0800 Subject: [PATCH 013/134] ACPICA: Tables: Fix the issues in handling virtual addressed tables. When table is overridden or reloaded, acpi_tb_delete_table() is called where struct acpi_table_desc.Pointer will be NULL. It thus is impossible for virtual addressed tables to obtain the .Pointer again in acpi_tb_verify_table(). This patch stores virtual table addresses (ACPI_TABLE_ORIGIN_ALLOCATED, ACPI_TABLE_ORIGIN_UNKNOWN, ACPI_TABLE_ORIGIN_OVERRIDE) in the struct acpi_table_desc.Address field and refills the struct acpi_table_desc.Pointer using these addresses in acpi_tb_verify_table(). Note that if a table with ACPI_TABLE_ORIGIN_ALLOCATED set is actually freed, the .Address field should be invalidated and thus must be replaced with NULL to avoid wrong future validations occuring in acpi_tb_verify_table(). Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/exconfig.c | 4 ++-- drivers/acpi/acpica/tbinstal.c | 20 ++++++++++++++++++-- drivers/acpi/acpica/tbutils.c | 1 + 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 1b734eb7c0c0..649a8efef0f5 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -435,7 +435,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(status); } - table_desc.address = obj_desc->region.address; + table_desc.address = ACPI_PTR_TO_PHYSADDR(table_desc.pointer); break; case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */ @@ -476,7 +476,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, } ACPI_MEMCPY(table_desc.pointer, table, length); - table_desc.address = ACPI_TO_INTEGER(table_desc.pointer); + table_desc.address = ACPI_PTR_TO_PHYSADDR(table_desc.pointer); break; default: diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 73fffb0f3dd3..144076ac21f0 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -69,11 +69,26 @@ acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc) /* Map the table if necessary */ if (!table_desc->pointer) { - if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == - ACPI_TABLE_ORIGIN_MAPPED) { + switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_MAPPED: + table_desc->pointer = acpi_os_map_memory(table_desc->address, table_desc->length); + break; + + case ACPI_TABLE_ORIGIN_ALLOCATED: + case ACPI_TABLE_ORIGIN_UNKNOWN: + case ACPI_TABLE_ORIGIN_OVERRIDE: + + table_desc->pointer = + ACPI_CAST_PTR(struct acpi_table_header, + table_desc->address); + break; + + default: + + break; } if (!table_desc->pointer) { @@ -476,6 +491,7 @@ void acpi_tb_delete_table(struct acpi_table_desc *table_desc) case ACPI_TABLE_ORIGIN_ALLOCATED: ACPI_FREE(table_desc->pointer); + table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL); break; /* Not mapped or allocated, there is nothing we can do */ diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 3f1afca87aeb..9b6992d8578f 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -179,6 +179,7 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) ACPI_MEMCPY(new_table, table_desc->pointer, table_desc->length); acpi_tb_delete_table(table_desc); + table_desc->address = ACPI_PTR_TO_PHYSADDR(new_table); table_desc->pointer = new_table; table_desc->flags = ACPI_TABLE_ORIGIN_ALLOCATED; From 55df23f0d620c5194ecbd3b68ecdb2798778bf93 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:38:35 +0800 Subject: [PATCH 014/134] ACPICA: Tables: Fix multiple ACPI_FREE()s around acpi_tb_add_table(). Currently there are following issues in acpi_tb_add_table(): Following logic is currently correct: 1. When a table is allocated in acpi_ex_load_op(), if a reloading happens, the allocated memory is freed by acpi_tb_add_table() and AE_OK is returned to the caller to avoid the caller to free it again. Following logic is currently incorrect: 1. When a table is allocated in acpi_ex_load_op() or by the acpi_load_table() caller, if the table is already loaded, there will be twice ACPI_FREE() called for the same pointer when acpi_tb_add_table() returns AE_ALREADY_EXISTS. This patch only fixes the above incorrect logic in acpi_tb_add_table(): 1. Only invoke acpi_tb_delete_table() if AE_OK is going to be returned. 2. After doing so, we do not invoke ACPI_FREE() when returning AE_OK; Signed-off-by: Lv Zheng Signed-off-by: Bob Moore [rjw: Subject] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/exconfig.c | 2 +- drivers/acpi/acpica/tbinstal.c | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 649a8efef0f5..11a014ca3935 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -504,7 +504,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, /* Delete allocated table buffer */ - acpi_tb_delete_table(&table_desc); + ACPI_FREE(table_desc.pointer); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 144076ac21f0..0040e19b6d14 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -203,12 +203,6 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) * need to be unregistered when they are unloaded, and slots in the * root table list should be reused when empty. */ - - /* - * Table is already registered. - * We can delete the table that was passed as a parameter. - */ - acpi_tb_delete_table(table_desc); *table_index = i; if (acpi_gbl_root_table_list.tables[i]. @@ -221,6 +215,7 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) } else { /* Table was unloaded, allow it to be reloaded */ + acpi_tb_delete_table(table_desc); table_desc->pointer = acpi_gbl_root_table_list.tables[i].pointer; table_desc->address = From 7f9fc99cde939187c1ee6dac115bdb76655cc798 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:38:42 +0800 Subject: [PATCH 015/134] ACPICA: Tables: Clean up split INSTALLED/VALIDATED table state logics. This patch is mainly a naming cleanup to clarify hidden logics, no functional changes. acpi_initialize_tables() is used by Linux to install table addresses for early boot steps. During this stage, table addresses are mapped by early_ioremap() mechanism which is different from the runtime IO mappings. Thus it is not safe for ACPICA to keep mapped pointers in struct acpi_table_desc structure during this stage. In order to support this in ACPICA, table states are divided into 1. "INSTALLED" (where struct acpi_table_desc.Pointer is always NULL) and 2. "VALIDATED" (where struct acpi_table_desc.Pointer is always not NULL). During acpi_initialize_tables(), table state are ensured to be "INSTALLED" but not "VALIDATED". This logic is ensured by the original code in very ambigious way. For example, currently acpi_tb_delete_table() is invoked in some place to perform an uninstallation while it is invoked in other place to perform an invalidation. They happen to work just because no one enters the penalty where the 2 behaviours are not equivalent. The naming cleanups are made in this patch: A. For installation and validation: There is code setting struct acpi_table_desc.Pointer first and delete it immediately to keep the descriptor's state as "INSTALLED" during the installation. This patch implements this in more direct way. After applying it, struct acpi_table_desc.Pointer will never be set in acpi_tb_install_table() and acpi_tb_override_table() as they are the only functions invoked during acpi_initialize_tables(). This is achieved by: 1. Rename acpi_tb_verify_table() to acpi_tb_validate_table() to clarify this change. 2. Rename acpi_tb_table_override() to acpi_tb_override_table() to keep nameing consistencies as other APIs (verb. Table). 3. Stops setting struct acpi_table_desc.Pointer in acpi_tb_install_table() and acpi_tb_table_override(). 4. Introduce acpi_tb_acquire_table() to acquire the table pointer that is not maintained in the struct acpi_table_desc of the global root table list and rewrite acpi_tb_validate_table() using this new function to reduce redundancies. 5. Replace the table pointer using the overridden table pointer in acpi_tb_add_table(). As acpi_tb_add_table() is not invoked during early boot stage, tables returned from this functions should be "VALIDATED". As acpi_tb_override_table() is modified by this patch to return a "INSTALLED" but not "VALIDATED" descriptor, to keep acpi_tb_add_table() unchanged, struct acpi_table_desc.Pointer is filled in acpi_tb_add_table(). B. For invalidation and uninstallation: The original code invalidate table by invoking acpi_tb_delete_table() here and there, but actually this function should only be used to uninstall tables. This can work just because its invocations are equivalent to invalidation in some cases. This patch splits acpi_tb_delete_table() into acpi_tb_invalidate_table() and acpi_tb_uninstall_table() and cleans up the hidden logic using the new APIs. This is achieved by: 1. Rename acpi_tb_delete_table() to acpi_tb_uninstall_table() as it is mainly called before resetting struct acpi_table_desc.Address. Thus the table descriptor is in "not INSTALLED" state. This patch enforces this by setting struct acpi_table_desc.Address to NULL in this function. 2. Introduce acpi_tb_invalidate_table() to be the reversal of acpi_tb_validate_table() and invoke it in acpi_tb_uninstall_table(). 3. Introduce acpi_tb_release_table() to release the table pointer that is not maintained in acpi_gbl_root_table_list and rewrite acpi_tb_invalidate_table() using this new function to reduce redundancies. After cleaning up, the maintainability of the internal APIs are also improved: 1. acpi_tb_acquire_table: Acquire struct acpi_table_header according to ACPI_TABLE_ORIGIN_xxx flags. 2. acpi_tb_release_table: Release struct acpi_table_header according to ACPI_TABLE_ORIGIN_xxx flags. 3. acpi_tb_install_table: Make struct acpi_table_desc.Address not NULL according to ACPI_TABLE_ORIGIN_xxx flags. 4. acpi_tb_uninstall_table: Make struct acpi_table_desc.Address NULL according to ACPI_TABLE_ORIGIN_xxx flags. 5. acpi_tb_validate_table: Make struct acpi_table_desc.Pointer not NULL according to ACPI_TABLE_ORIGIN_xxx flags. 6. acpi_tb_invalidate_table: Make struct acpi_table_desc.Pointer NULL according to ACPI_TABLE_ORIGIN_xxx flags. 7. acpi_tb_override_table: Replace struct acpi_table_desc.Address and struct acpi_table_desc.Flags. It only happens in "INSTALLED" state. The patch has been unit tested in acpi_exec by: 1. Initializing; 2. Executing exc_tbl ASLTS tests; 3. Executing "Load" command. So that all original acpi_tb_install_table() and acpi_tb_override_table() invocations are covered. Known Issues: 1. Cleanup acpi_tb_add_table() to Kill Code Redundancies Current implementation in acpi_tb_add_table() is not very clean, further patch can rewrite acpi_tb_add_table() with ordered acpi_tb_install_table(), acpi_tb_override_table() and acpi_tb_validate_table(). It is not done in this patch so that it is easy for the reviewers to understand the changes in this patch. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/actables.h | 17 +- drivers/acpi/acpica/tbfind.c | 4 +- drivers/acpi/acpica/tbinstal.c | 305 ++++++++++++++++++++++----------- drivers/acpi/acpica/tbutils.c | 11 +- drivers/acpi/acpica/tbxface.c | 6 +- drivers/acpi/acpica/tbxfload.c | 6 +- 6 files changed, 238 insertions(+), 111 deletions(-) diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 5fa4b2027697..c569eab774b1 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -72,13 +72,24 @@ acpi_tb_find_table(char *signature, */ acpi_status acpi_tb_resize_root_table_list(void); -acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc); +acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc); -struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header +void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc); + +struct acpi_table_header *acpi_tb_override_table(struct acpi_table_header *table_header, struct acpi_table_desc *table_desc); +acpi_status +acpi_tb_acquire_table(struct acpi_table_desc *table_desc, + struct acpi_table_header **table_ptr, + u32 *table_length, u8 *table_flags); + +void +acpi_tb_release_table(struct acpi_table_header *table, + u32 table_length, u8 table_flags); + acpi_status acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index); @@ -87,7 +98,7 @@ acpi_tb_store_table(acpi_physical_address address, struct acpi_table_header *table, u32 length, u8 flags, u32 *table_index); -void acpi_tb_delete_table(struct acpi_table_desc *table_desc); +void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc); void acpi_tb_terminate(void); diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index c12003947bd5..cb947700206c 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -99,8 +99,8 @@ acpi_tb_find_table(char *signature, /* Table is not currently mapped, map it */ status = - acpi_tb_verify_table(&acpi_gbl_root_table_list. - tables[i]); + acpi_tb_validate_table(&acpi_gbl_root_table_list. + tables[i]); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 0040e19b6d14..93a99ef03425 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -49,49 +49,123 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbinstal") -/****************************************************************************** +/******************************************************************************* * - * FUNCTION: acpi_tb_verify_table + * FUNCTION: acpi_tb_acquire_table * - * PARAMETERS: table_desc - table + * PARAMETERS: table_desc - Table descriptor + * table_ptr - Where table is returned + * table_length - Where table length is returned + * table_flags - Where table allocation flags are returned * * RETURN: Status * - * DESCRIPTION: this function is called to verify and map table + * DESCRIPTION: Acquire a table. It can be used for tables not maintained in + * acpi_gbl_root_table_list. + * + ******************************************************************************/ +acpi_status +acpi_tb_acquire_table(struct acpi_table_desc *table_desc, + struct acpi_table_header **table_ptr, + u32 *table_length, u8 *table_flags) +{ + struct acpi_table_header *table = NULL; + + switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_MAPPED: + + table = + acpi_os_map_memory(table_desc->address, table_desc->length); + break; + + case ACPI_TABLE_ORIGIN_ALLOCATED: + case ACPI_TABLE_ORIGIN_UNKNOWN: + case ACPI_TABLE_ORIGIN_OVERRIDE: + + table = + ACPI_CAST_PTR(struct acpi_table_header, + table_desc->address); + break; + + default: + + break; + } + + /* Table is not valid yet */ + + if (!table) { + return (AE_NO_MEMORY); + } + + /* Fill the return values */ + + *table_ptr = table; + *table_length = table_desc->length; + *table_flags = table_desc->flags; + + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_release_table + * + * PARAMETERS: table - Pointer for the table + * table_length - Length for the table + * table_flags - Allocation flags for the table + * + * RETURN: None + * + * DESCRIPTION: Release a table. The reversal of acpi_tb_acquire_table(). + * + ******************************************************************************/ + +void +acpi_tb_release_table(struct acpi_table_header *table, + u32 table_length, u8 table_flags) +{ + switch (table_flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_MAPPED: + + acpi_os_unmap_memory(table, table_length); + break; + + case ACPI_TABLE_ORIGIN_ALLOCATED: + case ACPI_TABLE_ORIGIN_UNKNOWN: + case ACPI_TABLE_ORIGIN_OVERRIDE: + default: + + break; + } +} + +/****************************************************************************** + * + * FUNCTION: acpi_tb_validate_table + * + * PARAMETERS: table_desc - Table descriptor + * + * RETURN: Status + * + * DESCRIPTION: This function is called to validate (ensure Pointer is valid) + * and verify the table. * *****************************************************************************/ -acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc) + +acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc) { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE(tb_verify_table); + ACPI_FUNCTION_TRACE(tb_validate_table); - /* Map the table if necessary */ + /* Validate the table if necessary */ if (!table_desc->pointer) { - switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { - case ACPI_TABLE_ORIGIN_MAPPED: - - table_desc->pointer = - acpi_os_map_memory(table_desc->address, - table_desc->length); - break; - - case ACPI_TABLE_ORIGIN_ALLOCATED: - case ACPI_TABLE_ORIGIN_UNKNOWN: - case ACPI_TABLE_ORIGIN_OVERRIDE: - - table_desc->pointer = - ACPI_CAST_PTR(struct acpi_table_header, - table_desc->address); - break; - - default: - - break; - } - - if (!table_desc->pointer) { + status = acpi_tb_acquire_table(table_desc, &table_desc->pointer, + &table_desc->length, + &table_desc->flags); + if (ACPI_FAILURE(status) || !table_desc->pointer) { return_ACPI_STATUS(AE_NO_MEMORY); } } @@ -104,6 +178,37 @@ acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc) return_ACPI_STATUS(status); } +/******************************************************************************* + * + * FUNCTION: acpi_tb_invalidate_table + * + * PARAMETERS: table_desc - Table descriptor + * + * RETURN: None + * + * DESCRIPTION: Invalidate one internal ACPI table, this is reversal of + * acpi_tb_validate_table(). + * + ******************************************************************************/ + +void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc) +{ + + ACPI_FUNCTION_TRACE(tb_invalidate_table); + + /* Table must be validated */ + + if (!table_desc->pointer) { + return_VOID; + } + + acpi_tb_release_table(table_desc->pointer, table_desc->length, + table_desc->flags); + table_desc->pointer = NULL; + + return_VOID; +} + /******************************************************************************* * * FUNCTION: acpi_tb_add_table @@ -124,11 +229,12 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) { u32 i; acpi_status status = AE_OK; + struct acpi_table_header *final_table; ACPI_FUNCTION_TRACE(tb_add_table); if (!table_desc->pointer) { - status = acpi_tb_verify_table(table_desc); + status = acpi_tb_validate_table(table_desc); if (ACPI_FAILURE(status) || !table_desc->pointer) { return_ACPI_STATUS(status); } @@ -166,8 +272,8 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { if (!acpi_gbl_root_table_list.tables[i].pointer) { status = - acpi_tb_verify_table(&acpi_gbl_root_table_list. - tables[i]); + acpi_tb_validate_table(&acpi_gbl_root_table_list. + tables[i]); if (ACPI_FAILURE(status) || !acpi_gbl_root_table_list.tables[i].pointer) { continue; @@ -215,7 +321,7 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) } else { /* Table was unloaded, allow it to be reloaded */ - acpi_tb_delete_table(table_desc); + acpi_tb_uninstall_table(table_desc); table_desc->pointer = acpi_gbl_root_table_list.tables[i].pointer; table_desc->address = @@ -229,9 +335,15 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) * ACPI Table Override: * Allow the host to override dynamically loaded tables. * NOTE: the table is fully mapped at this point, and the mapping will - * be deleted by tb_table_override if the table is actually overridden. + * be deleted by acpi_tb_override_table if the table is actually overridden. */ - (void)acpi_tb_table_override(table_desc->pointer, table_desc); + final_table = acpi_tb_override_table(table_desc->pointer, table_desc); + if (final_table) { + + /* Ensure table descriptor is in "VALIDATED" state */ + + table_desc->pointer = final_table; + } /* Add the table to the global root table list */ @@ -252,7 +364,7 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) /******************************************************************************* * - * FUNCTION: acpi_tb_table_override + * FUNCTION: acpi_tb_override_table * * PARAMETERS: table_header - Header for the original table * table_desc - Table descriptor initialized for the @@ -264,29 +376,35 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) * * DESCRIPTION: Attempt table override by calling the OSL override functions. * Note: If the table is overridden, then the entire new table - * is mapped and returned by this function. + * is acquired and returned by this function. + * After invocation, the table descriptor is in a state that is + * "INSTALLED" but not "VALIDATED", thus the "Pointer" member is + * kept NULL. * ******************************************************************************/ -struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header +struct acpi_table_header *acpi_tb_override_table(struct acpi_table_header *table_header, struct acpi_table_desc *table_desc) { acpi_status status; - struct acpi_table_header *new_table = NULL; - acpi_physical_address new_address = 0; - u32 new_table_length = 0; + struct acpi_table_header *new_table; + u32 new_table_length; u8 new_flags; char *override_type; + struct acpi_table_desc new_table_desc; + + ACPI_MEMSET(&new_table_desc, 0, sizeof(struct acpi_table_desc)); /* (1) Attempt logical override (returns a logical address) */ - status = acpi_os_table_override(table_header, &new_table); - if (ACPI_SUCCESS(status) && new_table) { - new_address = ACPI_PTR_TO_PHYSADDR(new_table); - new_table_length = new_table->length; - new_flags = ACPI_TABLE_ORIGIN_OVERRIDE; + status = acpi_os_table_override(table_header, &new_table_desc.pointer); + if (ACPI_SUCCESS(status) && new_table_desc.pointer) { + new_table_desc.address = + ACPI_PTR_TO_PHYSADDR(new_table_desc.pointer); + new_table_desc.length = new_table_desc.pointer->length; + new_table_desc.flags = ACPI_TABLE_ORIGIN_OVERRIDE; override_type = "Logical"; goto finish_override; } @@ -294,25 +412,12 @@ struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header /* (2) Attempt physical override (returns a physical address) */ status = acpi_os_physical_table_override(table_header, - &new_address, - &new_table_length); - if (ACPI_SUCCESS(status) && new_address && new_table_length) { - - /* Map the entire new table */ - - new_table = acpi_os_map_memory(new_address, new_table_length); - if (!new_table) { - ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, - "%4.4s " ACPI_PRINTF_UINT - " Attempted physical table override failed", - table_header->signature, - ACPI_FORMAT_TO_UINT(table_desc-> - address))); - return (NULL); - } - + &new_table_desc.address, + &new_table_desc.length); + if (ACPI_SUCCESS(status) && new_table_desc.address + && new_table_desc.length) { override_type = "Physical"; - new_flags = ACPI_TABLE_ORIGIN_MAPPED; + new_table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED; goto finish_override; } @@ -320,22 +425,36 @@ struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header finish_override: + /* + * Acquire the entire new table to indicate overridden. + * Note that this is required by the callers of this function. + */ + status = acpi_tb_acquire_table(&new_table_desc, &new_table, + &new_table_length, &new_flags); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, + "%4.4s " ACPI_PRINTF_UINT + " Attempted table override failed", + table_header->signature, + ACPI_FORMAT_TO_UINT(table_desc->address))); + return (NULL); + } + ACPI_INFO((AE_INFO, "%4.4s " ACPI_PRINTF_UINT " %s table override, new table: " ACPI_PRINTF_UINT, table_header->signature, ACPI_FORMAT_TO_UINT(table_desc->address), - override_type, ACPI_FORMAT_TO_UINT(new_table))); + override_type, ACPI_FORMAT_TO_UINT(new_table_desc.address))); - /* We can now unmap/delete the original table (if fully mapped) */ + /* We can now uninstall the original table (if fully mapped) */ - acpi_tb_delete_table(table_desc); + acpi_tb_uninstall_table(table_desc); - /* Setup descriptor for the new table */ + /* Install the new table */ - table_desc->address = new_address; - table_desc->pointer = new_table; - table_desc->length = new_table_length; - table_desc->flags = new_flags; + table_desc->address = new_table_desc.address; + table_desc->length = new_table_desc.length; + table_desc->flags = new_table_desc.flags; return (new_table); } @@ -458,9 +577,9 @@ acpi_tb_store_table(acpi_physical_address address, /******************************************************************************* * - * FUNCTION: acpi_tb_delete_table + * FUNCTION: acpi_tb_uninstall_table * - * PARAMETERS: table_index - Table index + * PARAMETERS: table_desc - Table descriptor * * RETURN: None * @@ -468,35 +587,27 @@ acpi_tb_store_table(acpi_physical_address address, * ******************************************************************************/ -void acpi_tb_delete_table(struct acpi_table_desc *table_desc) +void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc) { - /* Table must be mapped or allocated */ + ACPI_FUNCTION_TRACE(tb_uninstall_table); - if (!table_desc->pointer) { - return; + /* Table must be installed */ + + if (!table_desc->address) { + return_VOID; } - switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { - case ACPI_TABLE_ORIGIN_MAPPED: + acpi_tb_invalidate_table(table_desc); - acpi_os_unmap_memory(table_desc->pointer, table_desc->length); - break; - - case ACPI_TABLE_ORIGIN_ALLOCATED: - - ACPI_FREE(table_desc->pointer); - table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL); - break; - - /* Not mapped or allocated, there is nothing we can do */ - - default: - - return; + if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == + ACPI_TABLE_ORIGIN_ALLOCATED) { + ACPI_FREE(ACPI_CAST_PTR(void, table_desc->address)); } - table_desc->pointer = NULL; + table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL); + + return_VOID; } /******************************************************************************* @@ -522,7 +633,7 @@ void acpi_tb_terminate(void) /* Delete the individual tables */ for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { - acpi_tb_delete_table(&acpi_gbl_root_table_list.tables[i]); + acpi_tb_uninstall_table(&acpi_gbl_root_table_list.tables[i]); } /* diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 9b6992d8578f..c61432fa4332 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -178,7 +178,7 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) } ACPI_MEMCPY(new_table, table_desc->pointer, table_desc->length); - acpi_tb_delete_table(table_desc); + acpi_tb_uninstall_table(table_desc); table_desc->address = ACPI_PTR_TO_PHYSADDR(new_table); table_desc->pointer = new_table; table_desc->flags = ACPI_TABLE_ORIGIN_ALLOCATED; @@ -268,7 +268,7 @@ acpi_tb_install_table(acpi_physical_address address, * fully mapped later (in verify table). In any case, we must * unmap the header that was mapped above. */ - final_table = acpi_tb_table_override(table, table_desc); + final_table = acpi_tb_override_table(table, table_desc); if (!final_table) { final_table = table; /* There was no override */ } @@ -290,7 +290,12 @@ acpi_tb_install_table(acpi_physical_address address, * flag set and will not be deleted below. */ if (final_table != table) { - acpi_tb_delete_table(table_desc); + /* + * Table is in "INSTALLED" state, the final_table pointer is not + * maintained in the root table list. + */ + acpi_tb_release_table(final_table, table_desc->length, + table_desc->flags); } unmap_and_exit: diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 4debc1290d0a..ae3fe4d41137 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -346,7 +346,7 @@ acpi_get_table_with_size(char *signature, } status = - acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]); + acpi_tb_validate_table(&acpi_gbl_root_table_list.tables[i]); if (ACPI_SUCCESS(status)) { *out_table = acpi_gbl_root_table_list.tables[i].pointer; *tbl_size = acpi_gbl_root_table_list.tables[i].length; @@ -416,8 +416,8 @@ acpi_get_table_by_index(u32 table_index, struct acpi_table_header ** table) /* Table is not mapped, map it */ status = - acpi_tb_verify_table(&acpi_gbl_root_table_list. - tables[table_index]); + acpi_tb_validate_table(&acpi_gbl_root_table_list. + tables[table_index]); if (ACPI_FAILURE(status)) { (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_ACPI_STATUS(status); diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 0909420fc776..a2899b0cab23 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -117,7 +117,7 @@ static acpi_status acpi_tb_load_namespace(void) tables[ACPI_TABLE_INDEX_DSDT].signature), ACPI_SIG_DSDT) || - ACPI_FAILURE(acpi_tb_verify_table + ACPI_FAILURE(acpi_tb_validate_table (&acpi_gbl_root_table_list. tables[ACPI_TABLE_INDEX_DSDT]))) { status = AE_NO_ACPI_TABLES; @@ -128,7 +128,7 @@ static acpi_status acpi_tb_load_namespace(void) * Save the DSDT pointer for simple access. This is the mapped memory * address. We must take care here because the address of the .Tables * array can change dynamically as tables are loaded at run-time. Note: - * .Pointer field is not validated until after call to acpi_tb_verify_table. + * .Pointer field is not validated until after call to acpi_tb_validate_table. */ acpi_gbl_DSDT = acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer; @@ -174,7 +174,7 @@ static acpi_status acpi_tb_load_namespace(void) (acpi_gbl_root_table_list.tables[i]. signature), ACPI_SIG_PSDT)) || - ACPI_FAILURE(acpi_tb_verify_table + ACPI_FAILURE(acpi_tb_validate_table (&acpi_gbl_root_table_list.tables[i]))) { continue; } From eb0c65bd2c276b4b346db545d938d4113e1a4e9c Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:38:50 +0800 Subject: [PATCH 016/134] ACPICA: Tables: Fix unbalanced table validations. As acpi_tb_validate_table() returns failure on checksum verification without doing invalidatation, all its invocations that are not done to a descriptor stored in acpi_gbl_root_table_list are checked and balanced. But this is not a real issue as the descritors that have been passed to acpi_tb_add_table() are all virtual address tables and the validations are in fact no-op. The cleanup can ensure that any future extensions made on acpi_tb_add_table() to allow it to be invoked with physical address tables will not trigger memory leakage regressions. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore [rjw: Subject] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/tbinstal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 93a99ef03425..d3e1db225cb2 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -236,6 +236,7 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) if (!table_desc->pointer) { status = acpi_tb_validate_table(table_desc); if (ACPI_FAILURE(status) || !table_desc->pointer) { + acpi_tb_invalidate_table(table_desc); return_ACPI_STATUS(status); } } From 86dfc6f339886559d80ee0d4bd20fe5ee90450f0 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:38:57 +0800 Subject: [PATCH 017/134] ACPICA: Tables: Fix table checksums verification before installation. The original table handling code does not always verify checksums before installing a table, this is because code to achieve this must be implemented here and there in the redundant code blocks. There are two stages during table initialization: 1. "INSTALLED" after acpi_tb_install_table() and acpi_tb_override_table(), struct acpi_table_desc.Pointer is ensured to be NULL. This can be safely used during OSPM's early boot stage. 2. "VALIDATED" after acpi_tb_validate_table(), struct acpi_table_desc.Pointer is ensured to be not NULL. This must not be used during OSPM's early boot stage. This patch changes acpi_tb_add_table() into an early boot safe API to reduce code redundancies by changing the table state that is returned by this function from "VALIDATED" to "INSTALLED". Then the table verification code can be done in a single place. Originally, the acpi_tb_add_table() can only be used by dynamic table loadings that are executed after early boot stage, it cannot be used by static table loadings that are executed in early boot stage as: 1. The address of the table is a virtual address either maintained by OSPMs who call acpi_load_table() or by ACPICA whenever "Load" or "LoadTable" opcodes are executed, while during early boot stage, physical address of the table should be used for table loading. 2. The API will ensure the state of the loaded table to be "VALIDATED" while during early boot stage, tables maintained by root table list should be kept as "INSTALLED". To achieve this: 1. Rename acpi_tb_install_table() to acpi_tb_install_fixed_table() as it only applies to DSDT/FACS installation. Rename acpi_tb_add_table() to acpi_tb_install_non_fixed_table() as it will be applied to the installation of the rest kinds of tables. 2. Introduce acpi_tb_install_table(), acpi_tb_install_and_override_table to collect redudant code where their invocations actually have slight differences. 1. acpi_tb_install_table() is used to fill an struct acpi_table_desc where the table length is known to the caller. 2. acpi_tb_install_and_override_table() is used to perform necessary overriding before installation. 3. Change a parameter of acpi_tb_install_non_fixed_table() from struct acpi_table_desc to acpi_physical_address to allow it to be invoked by static table loadings. Also cleanup acpi_ex_load_op() and acpi_load_table() to accomodate to the parameter change. 4. Invoke acpi_tb_install_non_fixed_table() for all table loadings other than DSDT/FACS in acpi_tb_parse_root_table() to improve code maintainability (logics are collected in the single function). Also delete useless code from acpi_tb_parse_root_table(). 5. Remove all acpi_tb_validate_table() from acpi_tb_install_non_fixed_table() and acpi_tb_install_fixed_table() so that the table descriptor is kept in the state of "INSTALLED" but not "VALIDATED" after returning from these functions. 6. Introduce temporary struct acpi_table_desc (new_table_desc/old_table_desc) into the functions to indicate a table descriptor that is not maintained by acpi_gbl_root_table_list. Introduce acpi_tb_acquire_temporal_table() and acpi_tb_release_temporal_table() to handle the use cases of such temporal tables. They are only used for verified installation. 7. Introduce acpi_tb_verify_table() to validate table and verify table checksum, also remove table checksum verification from acpi_tb_validate_table(). Invoke acpi_tb_validate_table() in the functions that will convert a table into "LOADED" state or invoke it from acpi_get_table_XXX() APIs. Invoke acpi_tb_verify_table() on temporary struct acpi_table_desc(s) that are going to be "INSTALLED". 8. Change acpi_tb_override_table() logic so that a temporary struct acpi_table_desc will be overridden before installtion, this makes code simpler. After applying the patch, tables are always installed after being overridden and the table checksums are always verified before installation. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore [rjw: Subject] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/actables.h | 24 +- drivers/acpi/acpica/exconfig.c | 75 ++-- drivers/acpi/acpica/tbfadt.c | 10 +- drivers/acpi/acpica/tbinstal.c | 726 ++++++++++++++++++++++++--------- drivers/acpi/acpica/tbutils.c | 173 +------- drivers/acpi/acpica/tbxfload.c | 26 +- 6 files changed, 616 insertions(+), 418 deletions(-) diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index c569eab774b1..32aec48eb2d8 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -76,10 +76,10 @@ acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc); void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc); -struct acpi_table_header *acpi_tb_override_table(struct acpi_table_header - *table_header, - struct acpi_table_desc - *table_desc); +acpi_status +acpi_tb_verify_table(struct acpi_table_desc *table_desc, char *signature); + +void acpi_tb_override_table(struct acpi_table_desc *old_table_desc); acpi_status acpi_tb_acquire_table(struct acpi_table_desc *table_desc, @@ -91,7 +91,8 @@ acpi_tb_release_table(struct acpi_table_header *table, u32 table_length, u8 table_flags); acpi_status -acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index); +acpi_tb_install_non_fixed_table(acpi_physical_address address, + u8 flags, u8 reload, u32 *table_index); acpi_status acpi_tb_store_table(acpi_physical_address address, @@ -135,8 +136,17 @@ void acpi_tb_check_dsdt_header(void); struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index); void -acpi_tb_install_table(acpi_physical_address address, - char *signature, u32 table_index); +acpi_tb_install_table(struct acpi_table_desc *table_desc, + acpi_physical_address address, + u8 flags, struct acpi_table_header *table); + +void +acpi_tb_install_and_override_table(u32 table_index, + struct acpi_table_desc *new_table_desc); + +acpi_status +acpi_tb_install_fixed_table(acpi_physical_address address, + char *signature, u32 table_index); acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address); diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 11a014ca3935..52ea900c41a1 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -343,16 +343,14 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { union acpi_operand_object *ddb_handle; + struct acpi_table_header *table_header; struct acpi_table_header *table; - struct acpi_table_desc table_desc; u32 table_index; acpi_status status; u32 length; ACPI_FUNCTION_TRACE(ex_load_op); - ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc)); - /* Source Object can be either an op_region or a Buffer/Field */ switch (obj_desc->common.type) { @@ -380,17 +378,17 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, /* Get the table header first so we can get the table length */ - table = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); - if (!table) { + table_header = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); + if (!table_header) { return_ACPI_STATUS(AE_NO_MEMORY); } status = acpi_ex_region_read(obj_desc, sizeof(struct acpi_table_header), - ACPI_CAST_PTR(u8, table)); - length = table->length; - ACPI_FREE(table); + ACPI_CAST_PTR(u8, table_header)); + length = table_header->length; + ACPI_FREE(table_header); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -420,22 +418,19 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, /* Allocate a buffer for the table */ - table_desc.pointer = ACPI_ALLOCATE(length); - if (!table_desc.pointer) { + table = ACPI_ALLOCATE(length); + if (!table) { return_ACPI_STATUS(AE_NO_MEMORY); } /* Read the entire table */ status = acpi_ex_region_read(obj_desc, length, - ACPI_CAST_PTR(u8, - table_desc.pointer)); + ACPI_CAST_PTR(u8, table)); if (ACPI_FAILURE(status)) { - ACPI_FREE(table_desc.pointer); + ACPI_FREE(table); return_ACPI_STATUS(status); } - - table_desc.address = ACPI_PTR_TO_PHYSADDR(table_desc.pointer); break; case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */ @@ -452,10 +447,10 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, /* Get the actual table length from the table header */ - table = + table_header = ACPI_CAST_PTR(struct acpi_table_header, obj_desc->buffer.pointer); - length = table->length; + length = table_header->length; /* Table cannot extend beyond the buffer */ @@ -470,13 +465,12 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, * Copy the table from the buffer because the buffer could be modified * or even deleted in the future */ - table_desc.pointer = ACPI_ALLOCATE(length); - if (!table_desc.pointer) { + table = ACPI_ALLOCATE(length); + if (!table) { return_ACPI_STATUS(AE_NO_MEMORY); } - ACPI_MEMCPY(table_desc.pointer, table, length); - table_desc.address = ACPI_PTR_TO_PHYSADDR(table_desc.pointer); + ACPI_MEMCPY(table, table_header, length); break; default: @@ -484,27 +478,30 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } - /* Validate table checksum (will not get validated in tb_add_table) */ - - status = acpi_tb_verify_checksum(table_desc.pointer, length); - if (ACPI_FAILURE(status)) { - ACPI_FREE(table_desc.pointer); - return_ACPI_STATUS(status); - } - - /* Complete the table descriptor */ - - table_desc.length = length; - table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED; - /* Install the new table into the local data structures */ - status = acpi_tb_add_table(&table_desc, &table_index); + ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:")); + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + status = acpi_tb_install_non_fixed_table(ACPI_PTR_TO_PHYSADDR(table), + ACPI_TABLE_ORIGIN_ALLOCATED, + TRUE, &table_index); + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); if (ACPI_FAILURE(status)) { /* Delete allocated table buffer */ - ACPI_FREE(table_desc.pointer); + ACPI_FREE(table); + return_ACPI_STATUS(status); + } + + /* + * Note: Now table is "INSTALLED", it must be validated before + * loading. + */ + status = + acpi_tb_validate_table(&acpi_gbl_root_table_list. + tables[table_index]); + if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -536,9 +533,6 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(status); } - ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:")); - acpi_tb_print_table_header(0, table_desc.pointer); - /* Remove the reference by added by acpi_ex_store above */ acpi_ut_remove_reference(ddb_handle); @@ -546,8 +540,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, /* Invoke table handler if present */ if (acpi_gbl_table_handler) { - (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, - table_desc.pointer, + (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table, acpi_gbl_table_handler_context); } diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index ec14588254d4..a37af164b8c8 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -332,15 +332,15 @@ void acpi_tb_parse_fadt(u32 table_index) /* Obtain the DSDT and FACS tables via their addresses within the FADT */ - acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, - ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); + acpi_tb_install_fixed_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, + ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); /* If Hardware Reduced flag is set, there is no FACS */ if (!acpi_gbl_reduced_hardware) { - acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT. - Xfacs, ACPI_SIG_FACS, - ACPI_TABLE_INDEX_FACS); + acpi_tb_install_fixed_table((acpi_physical_address) + acpi_gbl_FADT.Xfacs, ACPI_SIG_FACS, + ACPI_TABLE_INDEX_FACS); } } diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index d3e1db225cb2..099e678edcb2 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -49,6 +49,19 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbinstal") +/* Local prototypes */ +static acpi_status +acpi_tb_acquire_temporal_table(struct acpi_table_desc *table_desc, + acpi_physical_address address, u8 flags); + +static void acpi_tb_release_temporal_table(struct acpi_table_desc *table_desc); + +static acpi_status acpi_tb_acquire_root_table_entry(u32 *table_index); + +static u8 +acpi_tb_is_equivalent_table(struct acpi_table_desc *table_desc, + u32 table_index); + /******************************************************************************* * * FUNCTION: acpi_tb_acquire_table @@ -64,6 +77,7 @@ ACPI_MODULE_NAME("tbinstal") * acpi_gbl_root_table_list. * ******************************************************************************/ + acpi_status acpi_tb_acquire_table(struct acpi_table_desc *table_desc, struct acpi_table_header **table_ptr, @@ -148,8 +162,8 @@ acpi_tb_release_table(struct acpi_table_header *table, * * RETURN: Status * - * DESCRIPTION: This function is called to validate (ensure Pointer is valid) - * and verify the table. + * DESCRIPTION: This function is called to validate the table, the returned + * table descriptor is in "VALIDATED" state. * *****************************************************************************/ @@ -165,16 +179,11 @@ acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc) status = acpi_tb_acquire_table(table_desc, &table_desc->pointer, &table_desc->length, &table_desc->flags); - if (ACPI_FAILURE(status) || !table_desc->pointer) { - return_ACPI_STATUS(AE_NO_MEMORY); + if (!table_desc->pointer) { + status = AE_NO_MEMORY; } } - /* Always calculate checksum, ignore bad checksum if requested */ - - status = - acpi_tb_verify_checksum(table_desc->pointer, table_desc->length); - return_ACPI_STATUS(status); } @@ -209,157 +218,473 @@ void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc) return_VOID; } -/******************************************************************************* +/****************************************************************************** * - * FUNCTION: acpi_tb_add_table + * FUNCTION: acpi_tb_verify_table * * PARAMETERS: table_desc - Table descriptor - * table_index - Where the table index is returned + * signature - Table signature to verify * * RETURN: Status * - * DESCRIPTION: This function is called to add an ACPI table. It is used to - * dynamically load tables via the Load and load_table AML - * operators. + * DESCRIPTION: This function is called to validate and verify the table, the + * returned table descriptor is in "VALIDATED" state. + * + *****************************************************************************/ + +acpi_status +acpi_tb_verify_table(struct acpi_table_desc *table_desc, char *signature) +{ + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE(tb_verify_table); + + /* Validate the table */ + + status = acpi_tb_validate_table(table_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* If a particular signature is expected (DSDT/FACS), it must match */ + + if (signature && !ACPI_COMPARE_NAME(&table_desc->signature, signature)) { + ACPI_BIOS_ERROR((AE_INFO, + "Invalid signature 0x%X for ACPI table, expected [%s]", + table_desc->signature.integer, signature)); + status = AE_BAD_SIGNATURE; + goto invalidate_and_exit; + } + + /* Verify the checksum */ + + status = + acpi_tb_verify_checksum(table_desc->pointer, table_desc->length); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, + "%4.4s " ACPI_PRINTF_UINT + " Attempted table install failed", + acpi_ut_valid_acpi_name(table_desc->signature. + ascii) ? table_desc-> + signature.ascii : "????", + ACPI_FORMAT_TO_UINT(table_desc->address))); + goto invalidate_and_exit; + } + + return_ACPI_STATUS(AE_OK); + +invalidate_and_exit: + acpi_tb_invalidate_table(table_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_install_table + * + * PARAMETERS: table_desc - Table descriptor + * address - Physical address of the table + * flags - Allocation flags of the table + * table - Pointer to the table + * + * RETURN: None + * + * DESCRIPTION: Install an ACPI table into the global data structure. * ******************************************************************************/ -acpi_status -acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) +void +acpi_tb_install_table(struct acpi_table_desc *table_desc, + acpi_physical_address address, + u8 flags, struct acpi_table_header *table) { - u32 i; - acpi_status status = AE_OK; - struct acpi_table_header *final_table; - - ACPI_FUNCTION_TRACE(tb_add_table); - - if (!table_desc->pointer) { - status = acpi_tb_validate_table(table_desc); - if (ACPI_FAILURE(status) || !table_desc->pointer) { - acpi_tb_invalidate_table(table_desc); - return_ACPI_STATUS(status); - } - } - /* - * Validate the incoming table signature. - * - * 1) Originally, we checked the table signature for "SSDT" or "PSDT". - * 2) We added support for OEMx tables, signature "OEM". - * 3) Valid tables were encountered with a null signature, so we just - * gave up on validating the signature, (05/2008). - * 4) We encountered non-AML tables such as the MADT, which caused - * interpreter errors and kernel faults. So now, we once again allow - * only "SSDT", "OEMx", and now, also a null signature. (05/2011). + * Initialize the table entry. Set the pointer to NULL, since the + * table is not fully mapped at this time. */ - if ((table_desc->pointer->signature[0] != 0x00) && - (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)) - && (ACPI_STRNCMP(table_desc->pointer->signature, "OEM", 3))) { - ACPI_BIOS_ERROR((AE_INFO, - "Table has invalid signature [%4.4s] (0x%8.8X), " - "must be SSDT or OEMx", - acpi_ut_valid_acpi_name(table_desc->pointer-> - signature) ? - table_desc->pointer->signature : "????", - *(u32 *)table_desc->pointer->signature)); + ACPI_MEMSET(table_desc, 0, sizeof(struct acpi_table_desc)); + table_desc->address = address; + table_desc->length = table->length; + table_desc->flags = flags; + ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature); +} - return_ACPI_STATUS(AE_BAD_SIGNATURE); +/******************************************************************************* + * + * FUNCTION: acpi_tb_acquire_temporal_table + * + * PARAMETERS: table_desc - Table descriptor to be acquired + * address - Address of the table + * flags - Allocation flags of the table + * + * RETURN: Status + * + * DESCRIPTION: This function validates the table header to obtain the length + * of a table and fills the table descriptor to make its state as + * "INSTALLED". Such table descriptor is only used for verified + * installation. + * + ******************************************************************************/ + +static acpi_status +acpi_tb_acquire_temporal_table(struct acpi_table_desc *table_desc, + acpi_physical_address address, u8 flags) +{ + struct acpi_table_header *table_header; + + switch (flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_MAPPED: + + /* Try to obtain the length of the table */ + + table_header = + acpi_os_map_memory(address, + sizeof(struct acpi_table_header)); + if (!table_header) { + return (AE_NO_MEMORY); + } + acpi_tb_install_table(table_desc, address, flags, table_header); + acpi_os_unmap_memory(table_header, + sizeof(struct acpi_table_header)); + return (AE_OK); + + case ACPI_TABLE_ORIGIN_ALLOCATED: + case ACPI_TABLE_ORIGIN_UNKNOWN: + case ACPI_TABLE_ORIGIN_OVERRIDE: + + table_header = ACPI_CAST_PTR(struct acpi_table_header, address); + if (!table_header) { + return (AE_NO_MEMORY); + } + acpi_tb_install_table(table_desc, address, flags, table_header); + return (AE_OK); + + default: + + break; } - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + /* Table is not valid yet */ - /* Check if table is already registered */ + return (AE_NO_MEMORY); +} - for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { - if (!acpi_gbl_root_table_list.tables[i].pointer) { - status = - acpi_tb_validate_table(&acpi_gbl_root_table_list. - tables[i]); - if (ACPI_FAILURE(status) - || !acpi_gbl_root_table_list.tables[i].pointer) { - continue; - } - } +/******************************************************************************* + * + * FUNCTION: acpi_tb_release_temporal_table + * + * PARAMETERS: table_desc - Table descriptor to be released + * + * RETURN: Status + * + * DESCRIPTION: The reversal of acpi_tb_acquire_temporal_table(). + * + ******************************************************************************/ - /* - * Check for a table match on the entire table length, - * not just the header. - */ - if (table_desc->length != - acpi_gbl_root_table_list.tables[i].length) { - continue; - } +static void acpi_tb_release_temporal_table(struct acpi_table_desc *table_desc) +{ + /* + * Note that the .Address is maintained by the callers of + * acpi_tb_acquire_temporal_table(), thus do not invoke acpi_tb_uninstall_table() + * where .Address will be freed. + */ + acpi_tb_invalidate_table(table_desc); +} - if (ACPI_MEMCMP(table_desc->pointer, - acpi_gbl_root_table_list.tables[i].pointer, - acpi_gbl_root_table_list.tables[i].length)) { - continue; - } +/******************************************************************************* + * + * FUNCTION: acpi_tb_install_and_override_table + * + * PARAMETERS: table_index - Index into root table array + * new_table_desc - New table descriptor to install + * + * RETURN: None + * + * DESCRIPTION: Install an ACPI table into the global data structure. The + * table override mechanism is called to allow the host + * OS to replace any table before it is installed in the root + * table array. + * + ******************************************************************************/ - /* - * Note: the current mechanism does not unregister a table if it is - * dynamically unloaded. The related namespace entries are deleted, - * but the table remains in the root table list. - * - * The assumption here is that the number of different tables that - * will be loaded is actually small, and there is minimal overhead - * in just keeping the table in case it is needed again. - * - * If this assumption changes in the future (perhaps on large - * machines with many table load/unload operations), tables will - * need to be unregistered when they are unloaded, and slots in the - * root table list should be reused when empty. - */ - *table_index = i; - - if (acpi_gbl_root_table_list.tables[i]. - flags & ACPI_TABLE_IS_LOADED) { - - /* Table is still loaded, this is an error */ - - status = AE_ALREADY_EXISTS; - goto release; - } else { - /* Table was unloaded, allow it to be reloaded */ - - acpi_tb_uninstall_table(table_desc); - table_desc->pointer = - acpi_gbl_root_table_list.tables[i].pointer; - table_desc->address = - acpi_gbl_root_table_list.tables[i].address; - status = AE_OK; - goto print_header; - } +void +acpi_tb_install_and_override_table(u32 table_index, + struct acpi_table_desc *new_table_desc) +{ + if (table_index >= acpi_gbl_root_table_list.current_table_count) { + return; } /* * ACPI Table Override: - * Allow the host to override dynamically loaded tables. - * NOTE: the table is fully mapped at this point, and the mapping will - * be deleted by acpi_tb_override_table if the table is actually overridden. + * + * Before we install the table, let the host OS override it with a new + * one if desired. Any table within the RSDT/XSDT can be replaced, + * including the DSDT which is pointed to by the FADT. */ - final_table = acpi_tb_override_table(table_desc->pointer, table_desc); - if (final_table) { + acpi_tb_override_table(new_table_desc); - /* Ensure table descriptor is in "VALIDATED" state */ + acpi_tb_install_table(&acpi_gbl_root_table_list.tables[table_index], + new_table_desc->address, new_table_desc->flags, + new_table_desc->pointer); - table_desc->pointer = final_table; + acpi_tb_print_table_header(new_table_desc->address, + new_table_desc->pointer); + + /* Set the global integer width (based upon revision of the DSDT) */ + + if (table_index == ACPI_TABLE_INDEX_DSDT) { + acpi_ut_set_integer_width(new_table_desc->pointer->revision); + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_install_fixed_table + * + * PARAMETERS: address - Physical address of DSDT or FACS + * signature - Table signature, NULL if no need to + * match + * table_index - Index into root table array + * + * RETURN: Status + * + * DESCRIPTION: Install a fixed ACPI table (DSDT/FACS) into the global data + * structure. + * + ******************************************************************************/ + +acpi_status +acpi_tb_install_fixed_table(acpi_physical_address address, + char *signature, u32 table_index) +{ + struct acpi_table_desc new_table_desc; + acpi_status status; + + ACPI_FUNCTION_TRACE(tb_install_fixed_table); + + if (!address) { + ACPI_ERROR((AE_INFO, + "Null physical address for ACPI table [%s]", + signature)); + return (AE_NO_MEMORY); + } + + /* Fill a table descriptor for validation */ + + status = acpi_tb_acquire_temporal_table(&new_table_desc, address, + ACPI_TABLE_ORIGIN_MAPPED); + if (ACPI_FAILURE(status)) { + ACPI_ERROR((AE_INFO, "Could not acquire table length at %p", + ACPI_CAST_PTR(void, address))); + return_ACPI_STATUS(status); + } + + /* Validate and verify a table before installation */ + + status = acpi_tb_verify_table(&new_table_desc, signature); + if (ACPI_FAILURE(status)) { + goto release_and_exit; + } + + acpi_tb_install_and_override_table(table_index, &new_table_desc); + +release_and_exit: + + /* Release the temporal table descriptor */ + + acpi_tb_release_temporal_table(&new_table_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_is_equivalent_table + * + * PARAMETERS: table_desc - Table 1 descriptor to be compared + * table_index - Index of table 2 to be compared + * + * RETURN: TRUE if 2 tables are equivalent + * + * DESCRIPTION: This function is called to compare a table with what have + * already been installed in the root table list. + * + ******************************************************************************/ + +static u8 +acpi_tb_is_equivalent_table(struct acpi_table_desc *table_desc, u32 table_index) +{ + acpi_status status = AE_OK; + u8 is_equivalent; + struct acpi_table_header *table; + u32 table_length; + u8 table_flags; + + status = + acpi_tb_acquire_table(&acpi_gbl_root_table_list.tables[table_index], + &table, &table_length, &table_flags); + if (ACPI_FAILURE(status)) { + return (FALSE); + } + + /* + * Check for a table match on the entire table length, + * not just the header. + */ + is_equivalent = (u8)((table_desc->length != table_length || + ACPI_MEMCMP(table_desc->pointer, table, + table_length)) ? FALSE : TRUE); + + /* Release the acquired table */ + + acpi_tb_release_table(table, table_length, table_flags); + + return (is_equivalent); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_install_non_fixed_table + * + * PARAMETERS: address - Address of the table (might be a logical + * address depending on the table_flags) + * flags - Flags for the table + * reload - Whether reload should be performed + * table_index - Where the table index is returned + * + * RETURN: Status + * + * DESCRIPTION: This function is called to install an ACPI table that is + * neither DSDT nor FACS. + * When this function is called by "Load" or "LoadTable" opcodes, + * or by acpi_load_table() API, the "Reload" parameter is set. + * After sucessfully returning from this function, table is + * "INSTALLED" but not "VALIDATED". + * + ******************************************************************************/ + +acpi_status +acpi_tb_install_non_fixed_table(acpi_physical_address address, + u8 flags, u8 reload, u32 *table_index) +{ + u32 i; + acpi_status status = AE_OK; + struct acpi_table_desc new_table_desc; + + ACPI_FUNCTION_TRACE(tb_install_non_fixed_table); + + /* Acquire a temporal table descriptor for validation */ + + status = + acpi_tb_acquire_temporal_table(&new_table_desc, address, flags); + if (ACPI_FAILURE(status)) { + ACPI_ERROR((AE_INFO, "Could not acquire table length at %p", + ACPI_CAST_PTR(void, address))); + return_ACPI_STATUS(status); + } + + /* Validate and verify a table before installation */ + + status = acpi_tb_verify_table(&new_table_desc, NULL); + if (ACPI_FAILURE(status)) { + goto release_and_exit; + } + + if (reload) { + /* + * Validate the incoming table signature. + * + * 1) Originally, we checked the table signature for "SSDT" or "PSDT". + * 2) We added support for OEMx tables, signature "OEM". + * 3) Valid tables were encountered with a null signature, so we just + * gave up on validating the signature, (05/2008). + * 4) We encountered non-AML tables such as the MADT, which caused + * interpreter errors and kernel faults. So now, we once again allow + * only "SSDT", "OEMx", and now, also a null signature. (05/2011). + */ + if ((new_table_desc.signature.ascii[0] != 0x00) && + (!ACPI_COMPARE_NAME + (&new_table_desc.signature, ACPI_SIG_SSDT)) + && (ACPI_STRNCMP(new_table_desc.signature.ascii, "OEM", 3))) + { + ACPI_BIOS_ERROR((AE_INFO, + "Table has invalid signature [%4.4s] (0x%8.8X), " + "must be SSDT or OEMx", + acpi_ut_valid_acpi_name(new_table_desc. + signature. + ascii) ? + new_table_desc.signature. + ascii : "????", + new_table_desc.signature.integer)); + + status = AE_BAD_SIGNATURE; + goto release_and_exit; + } + + /* Check if table is already registered */ + + for (i = 0; i < acpi_gbl_root_table_list.current_table_count; + ++i) { + /* + * Check for a table match on the entire table length, + * not just the header. + */ + if (!acpi_tb_is_equivalent_table(&new_table_desc, i)) { + continue; + } + + /* + * Note: the current mechanism does not unregister a table if it is + * dynamically unloaded. The related namespace entries are deleted, + * but the table remains in the root table list. + * + * The assumption here is that the number of different tables that + * will be loaded is actually small, and there is minimal overhead + * in just keeping the table in case it is needed again. + * + * If this assumption changes in the future (perhaps on large + * machines with many table load/unload operations), tables will + * need to be unregistered when they are unloaded, and slots in the + * root table list should be reused when empty. + */ + if (acpi_gbl_root_table_list.tables[i]. + flags & ACPI_TABLE_IS_LOADED) { + + /* Table is still loaded, this is an error */ + + status = AE_ALREADY_EXISTS; + goto release_and_exit; + } else { + /* + * Table was unloaded, allow it to be reloaded. + * As we are going to return AE_OK to the caller, we should + * take the responsibility of freeing the input descriptor. + * Refill the input descriptor to ensure + * acpi_tb_install_and_override_table() can be called again to + * indicate the re-installation. + */ + acpi_tb_uninstall_table(&new_table_desc); + *table_index = i; + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(AE_OK); + } + } } /* Add the table to the global root table list */ - status = acpi_tb_store_table(table_desc->address, table_desc->pointer, - table_desc->length, table_desc->flags, - table_index); + status = acpi_tb_acquire_root_table_entry(&i); if (ACPI_FAILURE(status)) { - goto release; + goto release_and_exit; } + *table_index = i; + acpi_tb_install_and_override_table(i, &new_table_desc); -print_header: - acpi_tb_print_table_header(table_desc->address, table_desc->pointer); +release_and_exit: -release: - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + /* Release the temporal table descriptor */ + + acpi_tb_release_temporal_table(&new_table_desc); return_ACPI_STATUS(status); } @@ -367,97 +692,82 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) * * FUNCTION: acpi_tb_override_table * - * PARAMETERS: table_header - Header for the original table - * table_desc - Table descriptor initialized for the - * original table. May or may not be mapped. + * PARAMETERS: old_table_desc - Validated table descriptor to be + * overridden * - * RETURN: Pointer to the entire new table. NULL if table not overridden. - * If overridden, installs the new table within the input table - * descriptor. + * RETURN: None * * DESCRIPTION: Attempt table override by calling the OSL override functions. * Note: If the table is overridden, then the entire new table * is acquired and returned by this function. - * After invocation, the table descriptor is in a state that is - * "INSTALLED" but not "VALIDATED", thus the "Pointer" member is - * kept NULL. + * Before/after invocation, the table descriptor is in a state + * that is "VALIDATED". * ******************************************************************************/ -struct acpi_table_header *acpi_tb_override_table(struct acpi_table_header - *table_header, - struct acpi_table_desc - *table_desc) +void acpi_tb_override_table(struct acpi_table_desc *old_table_desc) { acpi_status status; - struct acpi_table_header *new_table; - u32 new_table_length; - u8 new_flags; char *override_type; struct acpi_table_desc new_table_desc; - - ACPI_MEMSET(&new_table_desc, 0, sizeof(struct acpi_table_desc)); + struct acpi_table_header *table; + acpi_physical_address address; + u32 length; /* (1) Attempt logical override (returns a logical address) */ - status = acpi_os_table_override(table_header, &new_table_desc.pointer); - if (ACPI_SUCCESS(status) && new_table_desc.pointer) { - new_table_desc.address = - ACPI_PTR_TO_PHYSADDR(new_table_desc.pointer); - new_table_desc.length = new_table_desc.pointer->length; - new_table_desc.flags = ACPI_TABLE_ORIGIN_OVERRIDE; + status = acpi_os_table_override(old_table_desc->pointer, &table); + if (ACPI_SUCCESS(status) && table) { + acpi_tb_acquire_temporal_table(&new_table_desc, + ACPI_PTR_TO_PHYSADDR(table), + ACPI_TABLE_ORIGIN_OVERRIDE); override_type = "Logical"; goto finish_override; } /* (2) Attempt physical override (returns a physical address) */ - status = acpi_os_physical_table_override(table_header, - &new_table_desc.address, - &new_table_desc.length); - if (ACPI_SUCCESS(status) && new_table_desc.address - && new_table_desc.length) { + status = acpi_os_physical_table_override(old_table_desc->pointer, + &address, &length); + if (ACPI_SUCCESS(status) && address && length) { + acpi_tb_acquire_temporal_table(&new_table_desc, address, + ACPI_TABLE_ORIGIN_MAPPED); override_type = "Physical"; - new_table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED; goto finish_override; } - return (NULL); /* There was no override */ + return; /* There was no override */ finish_override: - /* - * Acquire the entire new table to indicate overridden. - * Note that this is required by the callers of this function. - */ - status = acpi_tb_acquire_table(&new_table_desc, &new_table, - &new_table_length, &new_flags); + /* Validate and verify a table before overriding */ + + status = acpi_tb_verify_table(&new_table_desc, NULL); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, - "%4.4s " ACPI_PRINTF_UINT - " Attempted table override failed", - table_header->signature, - ACPI_FORMAT_TO_UINT(table_desc->address))); - return (NULL); + return; } ACPI_INFO((AE_INFO, "%4.4s " ACPI_PRINTF_UINT " %s table override, new table: " ACPI_PRINTF_UINT, - table_header->signature, - ACPI_FORMAT_TO_UINT(table_desc->address), + old_table_desc->signature.ascii, + ACPI_FORMAT_TO_UINT(old_table_desc->address), override_type, ACPI_FORMAT_TO_UINT(new_table_desc.address))); - /* We can now uninstall the original table (if fully mapped) */ + /* We can now uninstall the original table */ - acpi_tb_uninstall_table(table_desc); + acpi_tb_uninstall_table(old_table_desc); - /* Install the new table */ + /* + * Replace the original table descriptor and keep its state as + * "VALIDATED". + */ + acpi_tb_install_table(old_table_desc, new_table_desc.address, + new_table_desc.flags, new_table_desc.pointer); + acpi_tb_validate_table(old_table_desc); - table_desc->address = new_table_desc.address; - table_desc->length = new_table_desc.length; - table_desc->flags = new_table_desc.flags; + /* Release the temporal table descriptor */ - return (new_table); + acpi_tb_release_temporal_table(&new_table_desc); } /******************************************************************************* @@ -524,6 +834,37 @@ acpi_status acpi_tb_resize_root_table_list(void) return_ACPI_STATUS(AE_OK); } +/******************************************************************************* + * + * FUNCTION: acpi_tb_acquire_root_table_entry + * + * PARAMETERS: table_index - Where table index is returned + * + * RETURN: Status and table index. + * + * DESCRIPTION: Allocate a new ACPI table entry to the global table list + * + ******************************************************************************/ + +static acpi_status acpi_tb_acquire_root_table_entry(u32 *table_index) +{ + acpi_status status; + + /* Ensure that there is room for the table in the Root Table List */ + + if (acpi_gbl_root_table_list.current_table_count >= + acpi_gbl_root_table_list.max_table_count) { + status = acpi_tb_resize_root_table_list(); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + *table_index = acpi_gbl_root_table_list.current_table_count; + acpi_gbl_root_table_list.current_table_count++; + return (AE_OK); +} + /******************************************************************************* * * FUNCTION: acpi_tb_store_table @@ -541,38 +882,23 @@ acpi_status acpi_tb_resize_root_table_list(void) acpi_status acpi_tb_store_table(acpi_physical_address address, - struct acpi_table_header *table, + struct acpi_table_header * table, u32 length, u8 flags, u32 *table_index) { acpi_status status; - struct acpi_table_desc *new_table; + struct acpi_table_desc *table_desc; - /* Ensure that there is room for the table in the Root Table List */ - - if (acpi_gbl_root_table_list.current_table_count >= - acpi_gbl_root_table_list.max_table_count) { - status = acpi_tb_resize_root_table_list(); - if (ACPI_FAILURE(status)) { - return (status); - } + status = acpi_tb_acquire_root_table_entry(table_index); + if (ACPI_FAILURE(status)) { + return (status); } - new_table = - &acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list. - current_table_count]; - /* Initialize added table */ - new_table->address = address; - new_table->pointer = table; - new_table->length = length; - new_table->owner_id = 0; - new_table->flags = flags; + table_desc = &acpi_gbl_root_table_list.tables[*table_index]; + acpi_tb_install_table(table_desc, address, flags, table); + table_desc->pointer = table; - ACPI_MOVE_32_TO_32(&new_table->signature, table->signature); - - *table_index = acpi_gbl_root_table_list.current_table_count; - acpi_gbl_root_table_list.current_table_count++; return (AE_OK); } diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index c61432fa4332..e58dfbf9dd3e 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -179,9 +179,10 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) ACPI_MEMCPY(new_table, table_desc->pointer, table_desc->length); acpi_tb_uninstall_table(table_desc); - table_desc->address = ACPI_PTR_TO_PHYSADDR(new_table); - table_desc->pointer = new_table; - table_desc->flags = ACPI_TABLE_ORIGIN_ALLOCATED; + acpi_tb_install_table(&acpi_gbl_root_table_list. + tables[ACPI_TABLE_INDEX_DSDT], + ACPI_PTR_TO_PHYSADDR(new_table), + ACPI_TABLE_ORIGIN_ALLOCATED, new_table); ACPI_INFO((AE_INFO, "Forced DSDT copy: length 0x%05X copied locally, original unmapped", @@ -190,121 +191,6 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) return (new_table); } -/******************************************************************************* - * - * FUNCTION: acpi_tb_install_table - * - * PARAMETERS: address - Physical address of DSDT or FACS - * signature - Table signature, NULL if no need to - * match - * table_index - Index into root table array - * - * RETURN: None - * - * DESCRIPTION: Install an ACPI table into the global data structure. The - * table override mechanism is called to allow the host - * OS to replace any table before it is installed in the root - * table array. - * - ******************************************************************************/ - -void -acpi_tb_install_table(acpi_physical_address address, - char *signature, u32 table_index) -{ - struct acpi_table_header *table; - struct acpi_table_header *final_table; - struct acpi_table_desc *table_desc; - - if (!address) { - ACPI_ERROR((AE_INFO, - "Null physical address for ACPI table [%s]", - signature)); - return; - } - - /* Map just the table header */ - - table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); - if (!table) { - ACPI_ERROR((AE_INFO, - "Could not map memory for table [%s] at %p", - signature, ACPI_CAST_PTR(void, address))); - return; - } - - /* If a particular signature is expected (DSDT/FACS), it must match */ - - if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) { - ACPI_BIOS_ERROR((AE_INFO, - "Invalid signature 0x%X for ACPI table, expected [%s]", - *ACPI_CAST_PTR(u32, table->signature), - signature)); - goto unmap_and_exit; - } - - /* - * Initialize the table entry. Set the pointer to NULL, since the - * table is not fully mapped at this time. - */ - table_desc = &acpi_gbl_root_table_list.tables[table_index]; - - table_desc->address = address; - table_desc->pointer = NULL; - table_desc->length = table->length; - table_desc->flags = ACPI_TABLE_ORIGIN_MAPPED; - ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature); - - /* - * ACPI Table Override: - * - * Before we install the table, let the host OS override it with a new - * one if desired. Any table within the RSDT/XSDT can be replaced, - * including the DSDT which is pointed to by the FADT. - * - * NOTE: If the table is overridden, then final_table will contain a - * mapped pointer to the full new table. If the table is not overridden, - * or if there has been a physical override, then the table will be - * fully mapped later (in verify table). In any case, we must - * unmap the header that was mapped above. - */ - final_table = acpi_tb_override_table(table, table_desc); - if (!final_table) { - final_table = table; /* There was no override */ - } - - acpi_tb_print_table_header(table_desc->address, final_table); - - /* Set the global integer width (based upon revision of the DSDT) */ - - if (table_index == ACPI_TABLE_INDEX_DSDT) { - acpi_ut_set_integer_width(final_table->revision); - } - - /* - * If we have a physical override during this early loading of the ACPI - * tables, unmap the table for now. It will be mapped again later when - * it is actually used. This supports very early loading of ACPI tables, - * before virtual memory is fully initialized and running within the - * host OS. Note: A logical override has the ACPI_TABLE_ORIGIN_OVERRIDE - * flag set and will not be deleted below. - */ - if (final_table != table) { - /* - * Table is in "INSTALLED" state, the final_table pointer is not - * maintained in the root table list. - */ - acpi_tb_release_table(final_table, table_desc->length, - table_desc->flags); - } - -unmap_and_exit: - - /* Always unmap the table header that we mapped above */ - - acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); -} - /******************************************************************************* * * FUNCTION: acpi_tb_get_root_table_entry @@ -470,6 +356,7 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) u32 length; u8 *table_entry; acpi_status status; + u32 table_index; ACPI_FUNCTION_TRACE(tb_parse_root_table); @@ -579,31 +466,24 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) /* Initialize the root table array from the RSDT/XSDT */ for (i = 0; i < table_count; i++) { - if (acpi_gbl_root_table_list.current_table_count >= - acpi_gbl_root_table_list.max_table_count) { - - /* There is no more room in the root table array, attempt resize */ - - status = acpi_tb_resize_root_table_list(); - if (ACPI_FAILURE(status)) { - ACPI_WARNING((AE_INFO, - "Truncating %u table entries!", - (unsigned)(table_count - - (acpi_gbl_root_table_list. - current_table_count - - 2)))); - break; - } - } /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */ - acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list. - current_table_count].address = - acpi_tb_get_root_table_entry(table_entry, table_entry_size); + status = + acpi_tb_install_non_fixed_table(acpi_tb_get_root_table_entry + (table_entry, + table_entry_size), + ACPI_TABLE_ORIGIN_MAPPED, + FALSE, &table_index); + + if (ACPI_SUCCESS(status) && + ACPI_COMPARE_NAME(&acpi_gbl_root_table_list. + tables[table_index].signature, + ACPI_SIG_FADT)) { + acpi_tb_parse_fadt(table_index); + } table_entry += table_entry_size; - acpi_gbl_root_table_list.current_table_count++; } /* @@ -612,22 +492,5 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) */ acpi_os_unmap_memory(table, length); - /* - * Complete the initialization of the root table array by examining - * the header of each table - */ - for (i = 2; i < acpi_gbl_root_table_list.current_table_count; i++) { - acpi_tb_install_table(acpi_gbl_root_table_list.tables[i]. - address, NULL, i); - - /* Special case for FADT - validate it then get the DSDT and FACS */ - - if (ACPI_COMPARE_NAME - (&acpi_gbl_root_table_list.tables[i].signature, - ACPI_SIG_FADT)) { - acpi_tb_parse_fadt(i); - } - } - return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index a2899b0cab23..77e8d269e491 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -226,7 +226,6 @@ static acpi_status acpi_tb_load_namespace(void) acpi_status acpi_load_table(struct acpi_table_header *table) { acpi_status status; - struct acpi_table_desc table_desc; u32 table_index; ACPI_FUNCTION_TRACE(acpi_load_table); @@ -237,14 +236,6 @@ acpi_status acpi_load_table(struct acpi_table_header *table) return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Init local table descriptor */ - - ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc)); - table_desc.address = ACPI_PTR_TO_PHYSADDR(table); - table_desc.pointer = table; - table_desc.length = table->length; - table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN; - /* Must acquire the interpreter lock during this operation */ status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); @@ -255,7 +246,22 @@ acpi_status acpi_load_table(struct acpi_table_header *table) /* Install the table and load it into the namespace */ ACPI_INFO((AE_INFO, "Host-directed Dynamic ACPI Table Load:")); - status = acpi_tb_add_table(&table_desc, &table_index); + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + status = acpi_tb_install_non_fixed_table(ACPI_PTR_TO_PHYSADDR(table), + ACPI_TABLE_ORIGIN_UNKNOWN, + TRUE, &table_index); + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + if (ACPI_FAILURE(status)) { + goto unlock_and_exit; + } + + /* + * Note: Now table is "INSTALLED", it must be validated before + * using. + */ + status = + acpi_tb_validate_table(&acpi_gbl_root_table_list. + tables[table_index]); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } From 8a216d7f6aa94c3e252bbfdb2c422e2d0380084e Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:39:04 +0800 Subject: [PATCH 018/134] ACPICA: Tables: Cleanup ACPI_TABLE_ORIGIN_xxx flags. This patch refines ACPI_TABLE_ORIGIN_xxx flags. No functional changes. The previous commits have introduced the following internal APIs: 1. acpi_tb_acquire_table: Acquire struct acpi_table_header according to ACPI_TABLE_ORIGIN_xxx flags. 2. acpi_tb_release_table: Release struct acpi_table_header according to ACPI_TABLE_ORIGIN_xxx flags. 3. acpi_tb_install_table: Make struct acpi_table_desc.Address not NULL according to ACPI_TABLE_ORIGIN_xxx flags. 4. acpi_tb_uninstall_table: Make struct acpi_table_desc.Address NULL according to ACPI_TABLE_ORIGIN_xxx flags. 5. acpi_tb_validate_table: Make struct acpi_table_desc.Pointer not NULL according to ACPI_TABLE_ORIGIN_xxx flags. 6. acpi_tb_invalidate_table: Make struct acpi_table_desc.Pointer NULL according to ACPI_TABLE_ORIGIN_xxx flags. It thus detects that the ACPI_TABLE_ORIGIN_UNKNOWN is redundant to ACPI_TABLE_ORIGIN_OVERRIDE. The ACPI_TABLE_ORIGIN_xxTERN_VIRTUAL flags are named as VIRTUAL in order not to confuse with x86 logical address, this patch also renames all "logical override" into "virtual override". Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/exconfig.c | 2 +- drivers/acpi/acpica/tbinstal.c | 31 ++++++++++++++----------------- drivers/acpi/acpica/tbutils.c | 4 ++-- drivers/acpi/acpica/tbxface.c | 2 +- drivers/acpi/acpica/tbxfload.c | 2 +- include/acpi/actbl.h | 11 +++++------ 6 files changed, 24 insertions(+), 28 deletions(-) diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 52ea900c41a1..4dfe6c07b004 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -483,7 +483,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:")); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); status = acpi_tb_install_non_fixed_table(ACPI_PTR_TO_PHYSADDR(table), - ACPI_TABLE_ORIGIN_ALLOCATED, + ACPI_TABLE_ORIGIN_INTERN_VIRTUAL, TRUE, &table_index); (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 099e678edcb2..cf1ccc576629 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -86,15 +86,14 @@ acpi_tb_acquire_table(struct acpi_table_desc *table_desc, struct acpi_table_header *table = NULL; switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { - case ACPI_TABLE_ORIGIN_MAPPED: + case ACPI_TABLE_ORIGIN_INTERN_PHYSICAL: table = acpi_os_map_memory(table_desc->address, table_desc->length); break; - case ACPI_TABLE_ORIGIN_ALLOCATED: - case ACPI_TABLE_ORIGIN_UNKNOWN: - case ACPI_TABLE_ORIGIN_OVERRIDE: + case ACPI_TABLE_ORIGIN_INTERN_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL: table = ACPI_CAST_PTR(struct acpi_table_header, @@ -140,14 +139,13 @@ acpi_tb_release_table(struct acpi_table_header *table, u32 table_length, u8 table_flags) { switch (table_flags & ACPI_TABLE_ORIGIN_MASK) { - case ACPI_TABLE_ORIGIN_MAPPED: + case ACPI_TABLE_ORIGIN_INTERN_PHYSICAL: acpi_os_unmap_memory(table, table_length); break; - case ACPI_TABLE_ORIGIN_ALLOCATED: - case ACPI_TABLE_ORIGIN_UNKNOWN: - case ACPI_TABLE_ORIGIN_OVERRIDE: + case ACPI_TABLE_ORIGIN_INTERN_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL: default: break; @@ -333,7 +331,7 @@ acpi_tb_acquire_temporal_table(struct acpi_table_desc *table_desc, struct acpi_table_header *table_header; switch (flags & ACPI_TABLE_ORIGIN_MASK) { - case ACPI_TABLE_ORIGIN_MAPPED: + case ACPI_TABLE_ORIGIN_INTERN_PHYSICAL: /* Try to obtain the length of the table */ @@ -348,9 +346,8 @@ acpi_tb_acquire_temporal_table(struct acpi_table_desc *table_desc, sizeof(struct acpi_table_header)); return (AE_OK); - case ACPI_TABLE_ORIGIN_ALLOCATED: - case ACPI_TABLE_ORIGIN_UNKNOWN: - case ACPI_TABLE_ORIGIN_OVERRIDE: + case ACPI_TABLE_ORIGIN_INTERN_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL: table_header = ACPI_CAST_PTR(struct acpi_table_header, address); if (!table_header) { @@ -473,7 +470,7 @@ acpi_tb_install_fixed_table(acpi_physical_address address, /* Fill a table descriptor for validation */ status = acpi_tb_acquire_temporal_table(&new_table_desc, address, - ACPI_TABLE_ORIGIN_MAPPED); + ACPI_TABLE_ORIGIN_INTERN_PHYSICAL); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not acquire table length at %p", ACPI_CAST_PTR(void, address))); @@ -546,7 +543,7 @@ acpi_tb_is_equivalent_table(struct acpi_table_desc *table_desc, u32 table_index) * * FUNCTION: acpi_tb_install_non_fixed_table * - * PARAMETERS: address - Address of the table (might be a logical + * PARAMETERS: address - Address of the table (might be a virtual * address depending on the table_flags) * flags - Flags for the table * reload - Whether reload should be performed @@ -720,7 +717,7 @@ void acpi_tb_override_table(struct acpi_table_desc *old_table_desc) if (ACPI_SUCCESS(status) && table) { acpi_tb_acquire_temporal_table(&new_table_desc, ACPI_PTR_TO_PHYSADDR(table), - ACPI_TABLE_ORIGIN_OVERRIDE); + ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL); override_type = "Logical"; goto finish_override; } @@ -731,7 +728,7 @@ void acpi_tb_override_table(struct acpi_table_desc *old_table_desc) &address, &length); if (ACPI_SUCCESS(status) && address && length) { acpi_tb_acquire_temporal_table(&new_table_desc, address, - ACPI_TABLE_ORIGIN_MAPPED); + ACPI_TABLE_ORIGIN_INTERN_PHYSICAL); override_type = "Physical"; goto finish_override; } @@ -928,7 +925,7 @@ void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc) acpi_tb_invalidate_table(table_desc); if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == - ACPI_TABLE_ORIGIN_ALLOCATED) { + ACPI_TABLE_ORIGIN_INTERN_VIRTUAL) { ACPI_FREE(ACPI_CAST_PTR(void, table_desc->address)); } diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index e58dfbf9dd3e..1bf9de7c6636 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -182,7 +182,7 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) acpi_tb_install_table(&acpi_gbl_root_table_list. tables[ACPI_TABLE_INDEX_DSDT], ACPI_PTR_TO_PHYSADDR(new_table), - ACPI_TABLE_ORIGIN_ALLOCATED, new_table); + ACPI_TABLE_ORIGIN_INTERN_VIRTUAL, new_table); ACPI_INFO((AE_INFO, "Forced DSDT copy: length 0x%05X copied locally, original unmapped", @@ -473,7 +473,7 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) acpi_tb_install_non_fixed_table(acpi_tb_get_root_table_entry (table_entry, table_entry_size), - ACPI_TABLE_ORIGIN_MAPPED, + ACPI_TABLE_ORIGIN_INTERN_PHYSICAL, FALSE, &table_index); if (ACPI_SUCCESS(status) && diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index ae3fe4d41137..19c0b13ad4c2 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -233,7 +233,7 @@ acpi_get_table_header(char *signature, if (!acpi_gbl_root_table_list.tables[i].pointer) { if ((acpi_gbl_root_table_list.tables[i].flags & ACPI_TABLE_ORIGIN_MASK) == - ACPI_TABLE_ORIGIN_MAPPED) { + ACPI_TABLE_ORIGIN_INTERN_PHYSICAL) { header = acpi_os_map_memory(acpi_gbl_root_table_list. tables[i].address, diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 77e8d269e491..62bbd384ac49 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -248,7 +248,7 @@ acpi_status acpi_load_table(struct acpi_table_header *table) ACPI_INFO((AE_INFO, "Host-directed Dynamic ACPI Table Load:")); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); status = acpi_tb_install_non_fixed_table(ACPI_PTR_TO_PHYSADDR(table), - ACPI_TABLE_ORIGIN_UNKNOWN, + ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL, TRUE, &table_index); (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); if (ACPI_FAILURE(status)) { diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index 3b30e36b53b5..0cdf4cc10f18 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -367,12 +367,11 @@ struct acpi_table_desc { /* Masks for Flags field above */ -#define ACPI_TABLE_ORIGIN_UNKNOWN (0) -#define ACPI_TABLE_ORIGIN_MAPPED (1) -#define ACPI_TABLE_ORIGIN_ALLOCATED (2) -#define ACPI_TABLE_ORIGIN_OVERRIDE (4) -#define ACPI_TABLE_ORIGIN_MASK (7) -#define ACPI_TABLE_IS_LOADED (8) +#define ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL (0) /* Virtual address, external maintained */ +#define ACPI_TABLE_ORIGIN_INTERN_PHYSICAL (1) /* Physical address, internal mapped */ +#define ACPI_TABLE_ORIGIN_INTERN_VIRTUAL (2) /* Virtual address, internal allocated */ +#define ACPI_TABLE_ORIGIN_MASK (3) +#define ACPI_TABLE_IS_LOADED (8) /* * Get the remaining ACPI tables From a94e88cdd8057fe8ea84bbb6d9a89a823c7bc49b Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:39:11 +0800 Subject: [PATCH 019/134] ACPICA: Tables: Avoid SSDT installation with acpi_gbl_disable_ssdt_table_load. It is reported that when acpi_gbl_disable_ssdt_table_load is specified, user still can see it installed into /sys/firmware/acpi/tables on Linux boxes. This is because the option only stops table "loading", but doesn't stop table "installing", thus it is still in the acpi_gbl_root_table_list. With previous cleanups, it is possible to prevent SSDT installations to make it not such confusing. The global variable is also renamed. Lv Zheng. Signed-off-by: Lv Zheng [rjw: Subject] Signed-off-by: Rafael J. Wysocki --- Documentation/kernel-parameters.txt | 10 +++++++++- drivers/acpi/acpica/acglobal.h | 4 ++-- drivers/acpi/acpica/tbinstal.c | 12 ++++++++++++ drivers/acpi/acpica/tbxfload.c | 13 ------------- drivers/acpi/osl.c | 11 +++++------ include/acpi/acpixf.h | 2 +- 6 files changed, 29 insertions(+), 23 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 03e50b4883a8..fbb58d790ec7 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -237,7 +237,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. This feature is enabled by default. This option allows to turn off the feature. - acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT + acpi_no_static_ssdt [HW,ACPI] + Disable installation of static SSDTs at early boot time + By default, SSDTs contained in the RSDT/XSDT will be + installed automatically and they will appear under + /sys/firmware/acpi/tables. + This option turns off this feature. + Note that specifying this option does not affect + dynamic table installation which will install SSDT + tables to /sys/firmware/acpi/tables/dynamic. acpica_no_return_repair [HW, ACPI] Disable AML predefined validation mechanism diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 71bb5b50c656..0cac564ffe93 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -160,10 +160,10 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_truncate_io_addresses, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_auto_repair, FALSE); /* - * Optionally do not load any SSDTs from the RSDT/XSDT during initialization. + * Optionally do not install any SSDTs from the RSDT/XSDT during initialization. * This can be useful for debugging ACPI problems on some machines. */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_load, FALSE); +ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_install, FALSE); /* * We keep track of the latest version of Windows that has been requested by diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index cf1ccc576629..de10d3245d9c 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -580,6 +580,18 @@ acpi_tb_install_non_fixed_table(acpi_physical_address address, return_ACPI_STATUS(status); } + /* + * Optionally do not load any SSDTs from the RSDT/XSDT. This can + * be useful for debugging ACPI problems on some machines. + */ + if (!reload && acpi_gbl_disable_ssdt_table_install && + ACPI_COMPARE_NAME(&new_table_desc.signature, ACPI_SIG_SSDT)) { + ACPI_INFO((AE_INFO, "Ignoring installation of %4.4s at %p", + new_table_desc.signature.ascii, ACPI_CAST_PTR(void, + address))); + goto release_and_exit; + } + /* Validate and verify a table before installation */ status = acpi_tb_verify_table(&new_table_desc, NULL); diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 62bbd384ac49..3f9eaf5c9fb7 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -179,19 +179,6 @@ static acpi_status acpi_tb_load_namespace(void) continue; } - /* - * Optionally do not load any SSDTs from the RSDT/XSDT. This can - * be useful for debugging ACPI problems on some machines. - */ - if (acpi_gbl_disable_ssdt_table_load) { - ACPI_INFO((AE_INFO, "Ignoring %4.4s at %p", - acpi_gbl_root_table_list.tables[i].signature. - ascii, ACPI_CAST_PTR(void, - acpi_gbl_root_table_list. - tables[i].address))); - continue; - } - /* Ignore errors while loading tables, get as many as possible */ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 6776c599816f..9aeae41e22fb 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1770,16 +1770,15 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) } #endif -static int __init acpi_no_auto_ssdt_setup(char *s) +static int __init acpi_no_static_ssdt_setup(char *s) { - printk(KERN_NOTICE PREFIX "SSDT auto-load disabled\n"); + acpi_gbl_disable_ssdt_table_install = TRUE; + pr_info("ACPI: static SSDT installation disabled\n"); - acpi_gbl_disable_ssdt_table_load = TRUE; - - return 1; + return 0; } -__setup("acpi_no_auto_ssdt", acpi_no_auto_ssdt_setup); +early_param("acpi_no_static_ssdt", acpi_no_static_ssdt_setup); static int __init acpi_disable_return_repair(char *s) { diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 44f5e9749601..2280c190536d 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -75,7 +75,7 @@ extern u8 acpi_gbl_auto_serialize_methods; extern u8 acpi_gbl_copy_dsdt_locally; extern u8 acpi_gbl_create_osi_method; extern u8 acpi_gbl_disable_auto_repair; -extern u8 acpi_gbl_disable_ssdt_table_load; +extern u8 acpi_gbl_disable_ssdt_table_install; extern u8 acpi_gbl_do_not_use_xsdt; extern u8 acpi_gbl_enable_aml_debug_object; extern u8 acpi_gbl_enable_interpreter_slack; From caf4a15c5f930aae41951b4916289e3e59dda8eb Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:39:18 +0800 Subject: [PATCH 020/134] ACPICA: Tables: Add acpi_install_table() API for early table installation. This patch adds a new API - acpi_install_table(). OSPMs can use this API to install tables during early boot stage. Lv Zheng. References: https://lkml.org/lkml/2014/2/28/372 Cc: Thomas Renninger Signed-off-by: Lv Zheng Signed-off-by: Bob Moore [rjw: Subject] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/actables.h | 6 +++-- drivers/acpi/acpica/exconfig.c | 2 +- drivers/acpi/acpica/tbinstal.c | 16 +++++++++---- drivers/acpi/acpica/tbutils.c | 2 +- drivers/acpi/acpica/tbxfload.c | 42 ++++++++++++++++++++++++++++++++-- include/acpi/acpixf.h | 3 +++ 6 files changed, 60 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 32aec48eb2d8..3d20a96f6f09 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -92,7 +92,8 @@ acpi_tb_release_table(struct acpi_table_header *table, acpi_status acpi_tb_install_non_fixed_table(acpi_physical_address address, - u8 flags, u8 reload, u32 *table_index); + u8 flags, + u8 reload, u8 override, u32 *table_index); acpi_status acpi_tb_store_table(acpi_physical_address address, @@ -142,7 +143,8 @@ acpi_tb_install_table(struct acpi_table_desc *table_desc, void acpi_tb_install_and_override_table(u32 table_index, - struct acpi_table_desc *new_table_desc); + struct acpi_table_desc *new_table_desc, + u8 override); acpi_status acpi_tb_install_fixed_table(acpi_physical_address address, diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 4dfe6c07b004..815003d81b5c 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -484,7 +484,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); status = acpi_tb_install_non_fixed_table(ACPI_PTR_TO_PHYSADDR(table), ACPI_TABLE_ORIGIN_INTERN_VIRTUAL, - TRUE, &table_index); + TRUE, TRUE, &table_index); (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index de10d3245d9c..9835213269e6 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -394,6 +394,7 @@ static void acpi_tb_release_temporal_table(struct acpi_table_desc *table_desc) * * PARAMETERS: table_index - Index into root table array * new_table_desc - New table descriptor to install + * override - Whether override should be performed * * RETURN: None * @@ -406,7 +407,8 @@ static void acpi_tb_release_temporal_table(struct acpi_table_desc *table_desc) void acpi_tb_install_and_override_table(u32 table_index, - struct acpi_table_desc *new_table_desc) + struct acpi_table_desc *new_table_desc, + u8 override) { if (table_index >= acpi_gbl_root_table_list.current_table_count) { return; @@ -419,7 +421,9 @@ acpi_tb_install_and_override_table(u32 table_index, * one if desired. Any table within the RSDT/XSDT can be replaced, * including the DSDT which is pointed to by the FADT. */ - acpi_tb_override_table(new_table_desc); + if (override) { + acpi_tb_override_table(new_table_desc); + } acpi_tb_install_table(&acpi_gbl_root_table_list.tables[table_index], new_table_desc->address, new_table_desc->flags, @@ -484,7 +488,7 @@ acpi_tb_install_fixed_table(acpi_physical_address address, goto release_and_exit; } - acpi_tb_install_and_override_table(table_index, &new_table_desc); + acpi_tb_install_and_override_table(table_index, &new_table_desc, TRUE); release_and_exit: @@ -547,6 +551,7 @@ acpi_tb_is_equivalent_table(struct acpi_table_desc *table_desc, u32 table_index) * address depending on the table_flags) * flags - Flags for the table * reload - Whether reload should be performed + * override - Whether override should be performed * table_index - Where the table index is returned * * RETURN: Status @@ -562,7 +567,8 @@ acpi_tb_is_equivalent_table(struct acpi_table_desc *table_desc, u32 table_index) acpi_status acpi_tb_install_non_fixed_table(acpi_physical_address address, - u8 flags, u8 reload, u32 *table_index) + u8 flags, + u8 reload, u8 override, u32 *table_index) { u32 i; acpi_status status = AE_OK; @@ -687,7 +693,7 @@ acpi_tb_install_non_fixed_table(acpi_physical_address address, goto release_and_exit; } *table_index = i; - acpi_tb_install_and_override_table(i, &new_table_desc); + acpi_tb_install_and_override_table(i, &new_table_desc, override); release_and_exit: diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 1bf9de7c6636..aa11949815df 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -474,7 +474,7 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) (table_entry, table_entry_size), ACPI_TABLE_ORIGIN_INTERN_PHYSICAL, - FALSE, &table_index); + FALSE, TRUE, &table_index); if (ACPI_SUCCESS(status) && ACPI_COMPARE_NAME(&acpi_gbl_root_table_list. diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 3f9eaf5c9fb7..529f633efa55 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -193,6 +193,45 @@ static acpi_status acpi_tb_load_namespace(void) return_ACPI_STATUS(status); } +/******************************************************************************* + * + * FUNCTION: acpi_install_table + * + * PARAMETERS: address - Address of the ACPI table to be installed. + * physical - Whether the address is a physical table + * address or not + * + * RETURN: Status + * + * DESCRIPTION: Dynamically install an ACPI table. + * Note: This function should only be invoked after + * acpi_initialize_tables() and before acpi_load_tables(). + * + ******************************************************************************/ + +acpi_status __init +acpi_install_table(acpi_physical_address address, u8 physical) +{ + acpi_status status; + u8 flags; + u32 table_index; + + ACPI_FUNCTION_TRACE(acpi_install_table); + + if (physical) { + flags = ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL; + } else { + flags = ACPI_TABLE_ORIGIN_INTERN_PHYSICAL; + } + + status = acpi_tb_install_non_fixed_table(address, flags, + FALSE, FALSE, &table_index); + + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL_INIT(acpi_install_table) + /******************************************************************************* * * FUNCTION: acpi_load_table @@ -209,7 +248,6 @@ static acpi_status acpi_tb_load_namespace(void) * to ensure that the table is not deleted or unmapped. * ******************************************************************************/ - acpi_status acpi_load_table(struct acpi_table_header *table) { acpi_status status; @@ -236,7 +274,7 @@ acpi_status acpi_load_table(struct acpi_table_header *table) (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); status = acpi_tb_install_non_fixed_table(ACPI_PTR_TO_PHYSADDR(table), ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL, - TRUE, &table_index); + TRUE, FALSE, &table_index); (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); if (ACPI_FAILURE(status)) { goto unlock_and_exit; diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 2280c190536d..8dc934073620 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -164,6 +164,9 @@ acpi_decode_pld_buffer(u8 *in_buffer, /* * ACPI table load/unload interfaces */ +acpi_status __init +acpi_install_table(acpi_physical_address address, u8 physical); + acpi_status acpi_load_table(struct acpi_table_header *table); acpi_status acpi_unload_parent_table(acpi_handle object); From ed6f1d44dae8a4eec42a74acae95cc177ee2e1ad Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:39:26 +0800 Subject: [PATCH 021/134] ACPICA: Table Manager: Misc cleanup and renames, no functional change. Some various cleanups and renames. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/actables.h | 18 ++-- drivers/acpi/acpica/exconfig.c | 8 +- drivers/acpi/acpica/tbinstal.c | 179 +++++++++++++++++---------------- drivers/acpi/acpica/tbutils.c | 20 ++-- drivers/acpi/acpica/tbxface.c | 2 +- drivers/acpi/acpica/tbxfload.c | 16 +-- include/acpi/actbl.h | 6 +- 7 files changed, 133 insertions(+), 116 deletions(-) diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 3d20a96f6f09..ade430c6004f 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -91,9 +91,9 @@ acpi_tb_release_table(struct acpi_table_header *table, u32 table_length, u8 table_flags); acpi_status -acpi_tb_install_non_fixed_table(acpi_physical_address address, - u8 flags, - u8 reload, u8 override, u32 *table_index); +acpi_tb_install_standard_table(acpi_physical_address address, + u8 flags, + u8 reload, u8 override, u32 *table_index); acpi_status acpi_tb_store_table(acpi_physical_address address, @@ -137,14 +137,14 @@ void acpi_tb_check_dsdt_header(void); struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index); void -acpi_tb_install_table(struct acpi_table_desc *table_desc, - acpi_physical_address address, - u8 flags, struct acpi_table_header *table); +acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, + acpi_physical_address address, + u8 flags, struct acpi_table_header *table); void -acpi_tb_install_and_override_table(u32 table_index, - struct acpi_table_desc *new_table_desc, - u8 override); +acpi_tb_install_table_with_override(u32 table_index, + struct acpi_table_desc *new_table_desc, + u8 override); acpi_status acpi_tb_install_fixed_table(acpi_physical_address address, diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 815003d81b5c..7d2949420db7 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -482,9 +482,11 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:")); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - status = acpi_tb_install_non_fixed_table(ACPI_PTR_TO_PHYSADDR(table), - ACPI_TABLE_ORIGIN_INTERN_VIRTUAL, - TRUE, TRUE, &table_index); + + status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table), + ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, + TRUE, TRUE, &table_index); + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 9835213269e6..50a6f229633c 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -51,12 +51,12 @@ ACPI_MODULE_NAME("tbinstal") /* Local prototypes */ static acpi_status -acpi_tb_acquire_temporal_table(struct acpi_table_desc *table_desc, - acpi_physical_address address, u8 flags); +acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, + acpi_physical_address address, u8 flags); -static void acpi_tb_release_temporal_table(struct acpi_table_desc *table_desc); +static void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc); -static acpi_status acpi_tb_acquire_root_table_entry(u32 *table_index); +static acpi_status acpi_tb_get_root_table_entry(u32 *table_index); static u8 acpi_tb_is_equivalent_table(struct acpi_table_desc *table_desc, @@ -73,8 +73,8 @@ acpi_tb_is_equivalent_table(struct acpi_table_desc *table_desc, * * RETURN: Status * - * DESCRIPTION: Acquire a table. It can be used for tables not maintained in - * acpi_gbl_root_table_list. + * DESCRIPTION: Acquire an ACPI table. It can be used for tables not + * maintained in the acpi_gbl_root_table_list. * ******************************************************************************/ @@ -86,14 +86,14 @@ acpi_tb_acquire_table(struct acpi_table_desc *table_desc, struct acpi_table_header *table = NULL; switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { - case ACPI_TABLE_ORIGIN_INTERN_PHYSICAL: + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: table = acpi_os_map_memory(table_desc->address, table_desc->length); break; - case ACPI_TABLE_ORIGIN_INTERN_VIRTUAL: - case ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL: + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: table = ACPI_CAST_PTR(struct acpi_table_header, @@ -116,7 +116,6 @@ acpi_tb_acquire_table(struct acpi_table_desc *table_desc, *table_ptr = table; *table_length = table_desc->length; *table_flags = table_desc->flags; - return (AE_OK); } @@ -130,7 +129,7 @@ acpi_tb_acquire_table(struct acpi_table_desc *table_desc, * * RETURN: None * - * DESCRIPTION: Release a table. The reversal of acpi_tb_acquire_table(). + * DESCRIPTION: Release a table. The inverse of acpi_tb_acquire_table(). * ******************************************************************************/ @@ -138,14 +137,15 @@ void acpi_tb_release_table(struct acpi_table_header *table, u32 table_length, u8 table_flags) { + switch (table_flags & ACPI_TABLE_ORIGIN_MASK) { - case ACPI_TABLE_ORIGIN_INTERN_PHYSICAL: + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: acpi_os_unmap_memory(table, table_length); break; - case ACPI_TABLE_ORIGIN_INTERN_VIRTUAL: - case ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL: + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: default: break; @@ -193,7 +193,7 @@ acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc) * * RETURN: None * - * DESCRIPTION: Invalidate one internal ACPI table, this is reversal of + * DESCRIPTION: Invalidate one internal ACPI table, this is the inverse of * acpi_tb_validate_table(). * ******************************************************************************/ @@ -278,7 +278,7 @@ acpi_tb_verify_table(struct acpi_table_desc *table_desc, char *signature) /******************************************************************************* * - * FUNCTION: acpi_tb_install_table + * FUNCTION: acpi_tb_init_table_descriptor * * PARAMETERS: table_desc - Table descriptor * address - Physical address of the table @@ -287,17 +287,18 @@ acpi_tb_verify_table(struct acpi_table_desc *table_desc, char *signature) * * RETURN: None * - * DESCRIPTION: Install an ACPI table into the global data structure. + * DESCRIPTION: Initialize a new table descriptor * ******************************************************************************/ void -acpi_tb_install_table(struct acpi_table_desc *table_desc, - acpi_physical_address address, - u8 flags, struct acpi_table_header *table) +acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, + acpi_physical_address address, + u8 flags, struct acpi_table_header *table) { + /* - * Initialize the table entry. Set the pointer to NULL, since the + * Initialize the table descriptor. Set the pointer to NULL, since the * table is not fully mapped at this time. */ ACPI_MEMSET(table_desc, 0, sizeof(struct acpi_table_desc)); @@ -309,7 +310,7 @@ acpi_tb_install_table(struct acpi_table_desc *table_desc, /******************************************************************************* * - * FUNCTION: acpi_tb_acquire_temporal_table + * FUNCTION: acpi_tb_acquire_temp_table * * PARAMETERS: table_desc - Table descriptor to be acquired * address - Address of the table @@ -319,21 +320,21 @@ acpi_tb_install_table(struct acpi_table_desc *table_desc, * * DESCRIPTION: This function validates the table header to obtain the length * of a table and fills the table descriptor to make its state as - * "INSTALLED". Such table descriptor is only used for verified + * "INSTALLED". Such a table descriptor is only used for verified * installation. * ******************************************************************************/ static acpi_status -acpi_tb_acquire_temporal_table(struct acpi_table_desc *table_desc, - acpi_physical_address address, u8 flags) +acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, + acpi_physical_address address, u8 flags) { struct acpi_table_header *table_header; switch (flags & ACPI_TABLE_ORIGIN_MASK) { - case ACPI_TABLE_ORIGIN_INTERN_PHYSICAL: + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: - /* Try to obtain the length of the table */ + /* Get the length of the full table from the header */ table_header = acpi_os_map_memory(address, @@ -341,19 +342,23 @@ acpi_tb_acquire_temporal_table(struct acpi_table_desc *table_desc, if (!table_header) { return (AE_NO_MEMORY); } - acpi_tb_install_table(table_desc, address, flags, table_header); + + acpi_tb_init_table_descriptor(table_desc, address, flags, + table_header); acpi_os_unmap_memory(table_header, sizeof(struct acpi_table_header)); return (AE_OK); - case ACPI_TABLE_ORIGIN_INTERN_VIRTUAL: - case ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL: + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: table_header = ACPI_CAST_PTR(struct acpi_table_header, address); if (!table_header) { return (AE_NO_MEMORY); } - acpi_tb_install_table(table_desc, address, flags, table_header); + + acpi_tb_init_table_descriptor(table_desc, address, flags, + table_header); return (AE_OK); default: @@ -368,21 +373,22 @@ acpi_tb_acquire_temporal_table(struct acpi_table_desc *table_desc, /******************************************************************************* * - * FUNCTION: acpi_tb_release_temporal_table + * FUNCTION: acpi_tb_release_temp_table * * PARAMETERS: table_desc - Table descriptor to be released * * RETURN: Status * - * DESCRIPTION: The reversal of acpi_tb_acquire_temporal_table(). + * DESCRIPTION: The inverse of acpi_tb_acquire_temp_table(). * ******************************************************************************/ -static void acpi_tb_release_temporal_table(struct acpi_table_desc *table_desc) +static void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc) { + /* * Note that the .Address is maintained by the callers of - * acpi_tb_acquire_temporal_table(), thus do not invoke acpi_tb_uninstall_table() + * acpi_tb_acquire_temp_table(), thus do not invoke acpi_tb_uninstall_table() * where .Address will be freed. */ acpi_tb_invalidate_table(table_desc); @@ -390,7 +396,7 @@ static void acpi_tb_release_temporal_table(struct acpi_table_desc *table_desc) /******************************************************************************* * - * FUNCTION: acpi_tb_install_and_override_table + * FUNCTION: acpi_tb_install_table_with_override * * PARAMETERS: table_index - Index into root table array * new_table_desc - New table descriptor to install @@ -406,10 +412,11 @@ static void acpi_tb_release_temporal_table(struct acpi_table_desc *table_desc) ******************************************************************************/ void -acpi_tb_install_and_override_table(u32 table_index, - struct acpi_table_desc *new_table_desc, - u8 override) +acpi_tb_install_table_with_override(u32 table_index, + struct acpi_table_desc *new_table_desc, + u8 override) { + if (table_index >= acpi_gbl_root_table_list.current_table_count) { return; } @@ -425,9 +432,11 @@ acpi_tb_install_and_override_table(u32 table_index, acpi_tb_override_table(new_table_desc); } - acpi_tb_install_table(&acpi_gbl_root_table_list.tables[table_index], - new_table_desc->address, new_table_desc->flags, - new_table_desc->pointer); + acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list. + tables[table_index], + new_table_desc->address, + new_table_desc->flags, + new_table_desc->pointer); acpi_tb_print_table_header(new_table_desc->address, new_table_desc->pointer); @@ -473,8 +482,8 @@ acpi_tb_install_fixed_table(acpi_physical_address address, /* Fill a table descriptor for validation */ - status = acpi_tb_acquire_temporal_table(&new_table_desc, address, - ACPI_TABLE_ORIGIN_INTERN_PHYSICAL); + status = acpi_tb_acquire_temp_table(&new_table_desc, address, + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not acquire table length at %p", ACPI_CAST_PTR(void, address))); @@ -488,13 +497,13 @@ acpi_tb_install_fixed_table(acpi_physical_address address, goto release_and_exit; } - acpi_tb_install_and_override_table(table_index, &new_table_desc, TRUE); + acpi_tb_install_table_with_override(table_index, &new_table_desc, TRUE); release_and_exit: - /* Release the temporal table descriptor */ + /* Release the temporary table descriptor */ - acpi_tb_release_temporal_table(&new_table_desc); + acpi_tb_release_temp_table(&new_table_desc); return_ACPI_STATUS(status); } @@ -539,13 +548,12 @@ acpi_tb_is_equivalent_table(struct acpi_table_desc *table_desc, u32 table_index) /* Release the acquired table */ acpi_tb_release_table(table, table_length, table_flags); - return (is_equivalent); } /******************************************************************************* * - * FUNCTION: acpi_tb_install_non_fixed_table + * FUNCTION: acpi_tb_install_standard_table * * PARAMETERS: address - Address of the table (might be a virtual * address depending on the table_flags) @@ -557,7 +565,7 @@ acpi_tb_is_equivalent_table(struct acpi_table_desc *table_desc, u32 table_index) * RETURN: Status * * DESCRIPTION: This function is called to install an ACPI table that is - * neither DSDT nor FACS. + * neither DSDT nor FACS (a "standard" table.) * When this function is called by "Load" or "LoadTable" opcodes, * or by acpi_load_table() API, the "Reload" parameter is set. * After sucessfully returning from this function, table is @@ -566,20 +574,19 @@ acpi_tb_is_equivalent_table(struct acpi_table_desc *table_desc, u32 table_index) ******************************************************************************/ acpi_status -acpi_tb_install_non_fixed_table(acpi_physical_address address, - u8 flags, - u8 reload, u8 override, u32 *table_index) +acpi_tb_install_standard_table(acpi_physical_address address, + u8 flags, + u8 reload, u8 override, u32 *table_index) { u32 i; acpi_status status = AE_OK; struct acpi_table_desc new_table_desc; - ACPI_FUNCTION_TRACE(tb_install_non_fixed_table); + ACPI_FUNCTION_TRACE(tb_install_standard_table); - /* Acquire a temporal table descriptor for validation */ + /* Acquire a temporary table descriptor for validation */ - status = - acpi_tb_acquire_temporal_table(&new_table_desc, address, flags); + status = acpi_tb_acquire_temp_table(&new_table_desc, address, flags); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not acquire table length at %p", ACPI_CAST_PTR(void, address))); @@ -590,7 +597,8 @@ acpi_tb_install_non_fixed_table(acpi_physical_address address, * Optionally do not load any SSDTs from the RSDT/XSDT. This can * be useful for debugging ACPI problems on some machines. */ - if (!reload && acpi_gbl_disable_ssdt_table_install && + if (!reload && + acpi_gbl_disable_ssdt_table_install && ACPI_COMPARE_NAME(&new_table_desc.signature, ACPI_SIG_SSDT)) { ACPI_INFO((AE_INFO, "Ignoring installation of %4.4s at %p", new_table_desc.signature.ascii, ACPI_CAST_PTR(void, @@ -675,7 +683,7 @@ acpi_tb_install_non_fixed_table(acpi_physical_address address, * As we are going to return AE_OK to the caller, we should * take the responsibility of freeing the input descriptor. * Refill the input descriptor to ensure - * acpi_tb_install_and_override_table() can be called again to + * acpi_tb_install_table_with_override() can be called again to * indicate the re-installation. */ acpi_tb_uninstall_table(&new_table_desc); @@ -688,18 +696,19 @@ acpi_tb_install_non_fixed_table(acpi_physical_address address, /* Add the table to the global root table list */ - status = acpi_tb_acquire_root_table_entry(&i); + status = acpi_tb_get_root_table_entry(&i); if (ACPI_FAILURE(status)) { goto release_and_exit; } + *table_index = i; - acpi_tb_install_and_override_table(i, &new_table_desc, override); + acpi_tb_install_table_with_override(i, &new_table_desc, override); release_and_exit: - /* Release the temporal table descriptor */ + /* Release the temporary table descriptor */ - acpi_tb_release_temporal_table(&new_table_desc); + acpi_tb_release_temp_table(&new_table_desc); return_ACPI_STATUS(status); } @@ -733,9 +742,9 @@ void acpi_tb_override_table(struct acpi_table_desc *old_table_desc) status = acpi_os_table_override(old_table_desc->pointer, &table); if (ACPI_SUCCESS(status) && table) { - acpi_tb_acquire_temporal_table(&new_table_desc, - ACPI_PTR_TO_PHYSADDR(table), - ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL); + acpi_tb_acquire_temp_table(&new_table_desc, + ACPI_PTR_TO_PHYSADDR(table), + ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL); override_type = "Logical"; goto finish_override; } @@ -745,8 +754,8 @@ void acpi_tb_override_table(struct acpi_table_desc *old_table_desc) status = acpi_os_physical_table_override(old_table_desc->pointer, &address, &length); if (ACPI_SUCCESS(status) && address && length) { - acpi_tb_acquire_temporal_table(&new_table_desc, address, - ACPI_TABLE_ORIGIN_INTERN_PHYSICAL); + acpi_tb_acquire_temp_table(&new_table_desc, address, + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL); override_type = "Physical"; goto finish_override; } @@ -776,13 +785,14 @@ void acpi_tb_override_table(struct acpi_table_desc *old_table_desc) * Replace the original table descriptor and keep its state as * "VALIDATED". */ - acpi_tb_install_table(old_table_desc, new_table_desc.address, - new_table_desc.flags, new_table_desc.pointer); + acpi_tb_init_table_descriptor(old_table_desc, new_table_desc.address, + new_table_desc.flags, + new_table_desc.pointer); acpi_tb_validate_table(old_table_desc); - /* Release the temporal table descriptor */ + /* Release the temporary table descriptor */ - acpi_tb_release_temporal_table(&new_table_desc); + acpi_tb_release_temp_table(&new_table_desc); } /******************************************************************************* @@ -851,7 +861,7 @@ acpi_status acpi_tb_resize_root_table_list(void) /******************************************************************************* * - * FUNCTION: acpi_tb_acquire_root_table_entry + * FUNCTION: acpi_tb_get_root_table_entry * * PARAMETERS: table_index - Where table index is returned * @@ -861,7 +871,7 @@ acpi_status acpi_tb_resize_root_table_list(void) * ******************************************************************************/ -static acpi_status acpi_tb_acquire_root_table_entry(u32 *table_index) +static acpi_status acpi_tb_get_root_table_entry(u32 *table_index) { acpi_status status; @@ -887,7 +897,8 @@ static acpi_status acpi_tb_acquire_root_table_entry(u32 *table_index) * PARAMETERS: address - Table address * table - Table header * length - Table length - * flags - flags + * flags - Install flags + * table_index - Where the table index is returned * * RETURN: Status and table index. * @@ -903,7 +914,7 @@ acpi_tb_store_table(acpi_physical_address address, acpi_status status; struct acpi_table_desc *table_desc; - status = acpi_tb_acquire_root_table_entry(table_index); + status = acpi_tb_get_root_table_entry(table_index); if (ACPI_FAILURE(status)) { return (status); } @@ -911,9 +922,8 @@ acpi_tb_store_table(acpi_physical_address address, /* Initialize added table */ table_desc = &acpi_gbl_root_table_list.tables[*table_index]; - acpi_tb_install_table(table_desc, address, flags, table); + acpi_tb_init_table_descriptor(table_desc, address, flags, table); table_desc->pointer = table; - return (AE_OK); } @@ -943,12 +953,11 @@ void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc) acpi_tb_invalidate_table(table_desc); if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == - ACPI_TABLE_ORIGIN_INTERN_VIRTUAL) { + ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL) { ACPI_FREE(ACPI_CAST_PTR(void, table_desc->address)); } table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL); - return_VOID; } @@ -991,8 +1000,8 @@ void acpi_tb_terminate(void) acpi_gbl_root_table_list.current_table_count = 0; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n")); - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_VOID; } @@ -1074,8 +1083,10 @@ acpi_status acpi_tb_allocate_owner_id(u32 table_index) (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); if (table_index < acpi_gbl_root_table_list.current_table_count) { - status = acpi_ut_allocate_owner_id - (&(acpi_gbl_root_table_list.tables[table_index].owner_id)); + status = + acpi_ut_allocate_owner_id(& + (acpi_gbl_root_table_list. + tables[table_index].owner_id)); } (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); @@ -1146,7 +1157,7 @@ acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id * owner_id) * * FUNCTION: acpi_tb_is_table_loaded * - * PARAMETERS: table_index - Table index + * PARAMETERS: table_index - Index into the root table * * RETURN: Table Loaded Flag * diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index aa11949815df..6c31d77cece0 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -179,10 +179,12 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) ACPI_MEMCPY(new_table, table_desc->pointer, table_desc->length); acpi_tb_uninstall_table(table_desc); - acpi_tb_install_table(&acpi_gbl_root_table_list. - tables[ACPI_TABLE_INDEX_DSDT], - ACPI_PTR_TO_PHYSADDR(new_table), - ACPI_TABLE_ORIGIN_INTERN_VIRTUAL, new_table); + + acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list. + tables[ACPI_TABLE_INDEX_DSDT], + ACPI_PTR_TO_PHYSADDR(new_table), + ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, + new_table); ACPI_INFO((AE_INFO, "Forced DSDT copy: length 0x%05X copied locally, original unmapped", @@ -470,11 +472,11 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */ status = - acpi_tb_install_non_fixed_table(acpi_tb_get_root_table_entry - (table_entry, - table_entry_size), - ACPI_TABLE_ORIGIN_INTERN_PHYSICAL, - FALSE, TRUE, &table_index); + acpi_tb_install_standard_table(acpi_tb_get_root_table_entry + (table_entry, + table_entry_size), + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, + FALSE, TRUE, &table_index); if (ACPI_SUCCESS(status) && ACPI_COMPARE_NAME(&acpi_gbl_root_table_list. diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 19c0b13ad4c2..6482b0ded652 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -233,7 +233,7 @@ acpi_get_table_header(char *signature, if (!acpi_gbl_root_table_list.tables[i].pointer) { if ((acpi_gbl_root_table_list.tables[i].flags & ACPI_TABLE_ORIGIN_MASK) == - ACPI_TABLE_ORIGIN_INTERN_PHYSICAL) { + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL) { header = acpi_os_map_memory(acpi_gbl_root_table_list. tables[i].address, diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 529f633efa55..ab5308b81aa8 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -219,13 +219,13 @@ acpi_install_table(acpi_physical_address address, u8 physical) ACPI_FUNCTION_TRACE(acpi_install_table); if (physical) { - flags = ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL; + flags = ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL; } else { - flags = ACPI_TABLE_ORIGIN_INTERN_PHYSICAL; + flags = ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL; } - status = acpi_tb_install_non_fixed_table(address, flags, - FALSE, FALSE, &table_index); + status = acpi_tb_install_standard_table(address, flags, + FALSE, FALSE, &table_index); return_ACPI_STATUS(status); } @@ -272,9 +272,11 @@ acpi_status acpi_load_table(struct acpi_table_header *table) ACPI_INFO((AE_INFO, "Host-directed Dynamic ACPI Table Load:")); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - status = acpi_tb_install_non_fixed_table(ACPI_PTR_TO_PHYSADDR(table), - ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL, - TRUE, FALSE, &table_index); + + status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table), + ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, + TRUE, FALSE, &table_index); + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); if (ACPI_FAILURE(status)) { goto unlock_and_exit; diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index 0cdf4cc10f18..1cc7ef13c01a 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -367,9 +367,9 @@ struct acpi_table_desc { /* Masks for Flags field above */ -#define ACPI_TABLE_ORIGIN_EXTERN_VIRTUAL (0) /* Virtual address, external maintained */ -#define ACPI_TABLE_ORIGIN_INTERN_PHYSICAL (1) /* Physical address, internal mapped */ -#define ACPI_TABLE_ORIGIN_INTERN_VIRTUAL (2) /* Virtual address, internal allocated */ +#define ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL (0) /* Virtual address, external maintained */ +#define ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL (1) /* Physical address, internally mapped */ +#define ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL (2) /* Virtual address, internallly allocated */ #define ACPI_TABLE_ORIGIN_MASK (3) #define ACPI_TABLE_IS_LOADED (8) From c418ce19030f8cd9304b4e97c8e0dd580a81ace5 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:39:34 +0800 Subject: [PATCH 022/134] ACPICA: Table Manager: Split tbinstal.c into two files. New file is tbdata.c -- management functions for ACPICA table manager data structures. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/Makefile | 1 + drivers/acpi/acpica/actables.h | 29 +- drivers/acpi/acpica/tbdata.c | 723 +++++++++++++++++++++++++++++++ drivers/acpi/acpica/tbinstal.c | 752 ++------------------------------- 4 files changed, 778 insertions(+), 727 deletions(-) create mode 100644 drivers/acpi/acpica/tbdata.c diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index b7ed86a20427..8bb43f06e11f 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -135,6 +135,7 @@ acpi-y += \ rsxface.o acpi-y += \ + tbdata.o \ tbfadt.o \ tbfind.o \ tbinstal.o \ diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index ade430c6004f..bda9a7eb50c1 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -53,6 +53,26 @@ acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp); u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length); +/* + * tbdata - table data structure management + */ +acpi_status acpi_tb_get_next_root_index(u32 *table_index); + +void +acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, + acpi_physical_address address, + u8 flags, struct acpi_table_header *table); + +acpi_status +acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, + acpi_physical_address address, u8 flags); + +void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc); + +u8 acpi_tb_is_table_loaded(u32 table_index); + +void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded); + /* * tbfadt - FADT parse/convert/validate */ @@ -112,10 +132,6 @@ acpi_status acpi_tb_release_owner_id(u32 table_index); acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id); -u8 acpi_tb_is_table_loaded(u32 table_index); - -void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded); - /* * tbutils - table manager utilities */ @@ -136,11 +152,6 @@ void acpi_tb_check_dsdt_header(void); struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index); -void -acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, - acpi_physical_address address, - u8 flags, struct acpi_table_header *table); - void acpi_tb_install_table_with_override(u32 table_index, struct acpi_table_desc *new_table_desc, diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c new file mode 100644 index 000000000000..cbe29944dc97 --- /dev/null +++ b/drivers/acpi/acpica/tbdata.c @@ -0,0 +1,723 @@ +/****************************************************************************** + * + * Module Name: tbdata - Table manager data structure functions + * + *****************************************************************************/ + +/* + * 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 +#include "accommon.h" +#include "acnamesp.h" +#include "actables.h" + +#define _COMPONENT ACPI_TABLES +ACPI_MODULE_NAME("tbdata") + +/******************************************************************************* + * + * FUNCTION: acpi_tb_init_table_descriptor + * + * PARAMETERS: table_desc - Table descriptor + * address - Physical address of the table + * flags - Allocation flags of the table + * table - Pointer to the table + * + * RETURN: None + * + * DESCRIPTION: Initialize a new table descriptor + * + ******************************************************************************/ +void +acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, + acpi_physical_address address, + u8 flags, struct acpi_table_header *table) +{ + + /* + * Initialize the table descriptor. Set the pointer to NULL, since the + * table is not fully mapped at this time. + */ + ACPI_MEMSET(table_desc, 0, sizeof(struct acpi_table_desc)); + table_desc->address = address; + table_desc->length = table->length; + table_desc->flags = flags; + ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_acquire_table + * + * PARAMETERS: table_desc - Table descriptor + * table_ptr - Where table is returned + * table_length - Where table length is returned + * table_flags - Where table allocation flags are returned + * + * RETURN: Status + * + * DESCRIPTION: Acquire an ACPI table. It can be used for tables not + * maintained in the acpi_gbl_root_table_list. + * + ******************************************************************************/ + +acpi_status +acpi_tb_acquire_table(struct acpi_table_desc *table_desc, + struct acpi_table_header **table_ptr, + u32 *table_length, u8 *table_flags) +{ + struct acpi_table_header *table = NULL; + + switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: + + table = + acpi_os_map_memory(table_desc->address, table_desc->length); + break; + + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: + + table = + ACPI_CAST_PTR(struct acpi_table_header, + table_desc->address); + break; + + default: + + break; + } + + /* Table is not valid yet */ + + if (!table) { + return (AE_NO_MEMORY); + } + + /* Fill the return values */ + + *table_ptr = table; + *table_length = table_desc->length; + *table_flags = table_desc->flags; + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_release_table + * + * PARAMETERS: table - Pointer for the table + * table_length - Length for the table + * table_flags - Allocation flags for the table + * + * RETURN: None + * + * DESCRIPTION: Release a table. The inverse of acpi_tb_acquire_table(). + * + ******************************************************************************/ + +void +acpi_tb_release_table(struct acpi_table_header *table, + u32 table_length, u8 table_flags) +{ + + switch (table_flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: + + acpi_os_unmap_memory(table, table_length); + break; + + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: + default: + + break; + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_acquire_temp_table + * + * PARAMETERS: table_desc - Table descriptor to be acquired + * address - Address of the table + * flags - Allocation flags of the table + * + * RETURN: Status + * + * DESCRIPTION: This function validates the table header to obtain the length + * of a table and fills the table descriptor to make its state as + * "INSTALLED". Such a table descriptor is only used for verified + * installation. + * + ******************************************************************************/ + +acpi_status +acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, + acpi_physical_address address, u8 flags) +{ + struct acpi_table_header *table_header; + + switch (flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: + + /* Get the length of the full table from the header */ + + table_header = + acpi_os_map_memory(address, + sizeof(struct acpi_table_header)); + if (!table_header) { + return (AE_NO_MEMORY); + } + + acpi_tb_init_table_descriptor(table_desc, address, flags, + table_header); + acpi_os_unmap_memory(table_header, + sizeof(struct acpi_table_header)); + return (AE_OK); + + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: + + table_header = ACPI_CAST_PTR(struct acpi_table_header, address); + if (!table_header) { + return (AE_NO_MEMORY); + } + + acpi_tb_init_table_descriptor(table_desc, address, flags, + table_header); + return (AE_OK); + + default: + + break; + } + + /* Table is not valid yet */ + + return (AE_NO_MEMORY); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_release_temp_table + * + * PARAMETERS: table_desc - Table descriptor to be released + * + * RETURN: Status + * + * DESCRIPTION: The inverse of acpi_tb_acquire_temp_table(). + * + *****************************************************************************/ + +void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc) +{ + + /* + * Note that the .Address is maintained by the callers of + * acpi_tb_acquire_temp_table(), thus do not invoke acpi_tb_uninstall_table() + * where .Address will be freed. + */ + acpi_tb_invalidate_table(table_desc); +} + +/****************************************************************************** + * + * FUNCTION: acpi_tb_validate_table + * + * PARAMETERS: table_desc - Table descriptor + * + * RETURN: Status + * + * DESCRIPTION: This function is called to validate the table, the returned + * table descriptor is in "VALIDATED" state. + * + *****************************************************************************/ + +acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc) +{ + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE(tb_validate_table); + + /* Validate the table if necessary */ + + if (!table_desc->pointer) { + status = acpi_tb_acquire_table(table_desc, &table_desc->pointer, + &table_desc->length, + &table_desc->flags); + if (!table_desc->pointer) { + status = AE_NO_MEMORY; + } + } + + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_invalidate_table + * + * PARAMETERS: table_desc - Table descriptor + * + * RETURN: None + * + * DESCRIPTION: Invalidate one internal ACPI table, this is the inverse of + * acpi_tb_validate_table(). + * + ******************************************************************************/ + +void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc) +{ + + ACPI_FUNCTION_TRACE(tb_invalidate_table); + + /* Table must be validated */ + + if (!table_desc->pointer) { + return_VOID; + } + + acpi_tb_release_table(table_desc->pointer, table_desc->length, + table_desc->flags); + table_desc->pointer = NULL; + + return_VOID; +} + +/****************************************************************************** + * + * FUNCTION: acpi_tb_verify_table + * + * PARAMETERS: table_desc - Table descriptor + * signature - Table signature to verify + * + * RETURN: Status + * + * DESCRIPTION: This function is called to validate and verify the table, the + * returned table descriptor is in "VALIDATED" state. + * + *****************************************************************************/ + +acpi_status +acpi_tb_verify_table(struct acpi_table_desc *table_desc, char *signature) +{ + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE(tb_verify_table); + + /* Validate the table */ + + status = acpi_tb_validate_table(table_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* If a particular signature is expected (DSDT/FACS), it must match */ + + if (signature && !ACPI_COMPARE_NAME(&table_desc->signature, signature)) { + ACPI_BIOS_ERROR((AE_INFO, + "Invalid signature 0x%X for ACPI table, expected [%s]", + table_desc->signature.integer, signature)); + status = AE_BAD_SIGNATURE; + goto invalidate_and_exit; + } + + /* Verify the checksum */ + + status = + acpi_tb_verify_checksum(table_desc->pointer, table_desc->length); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, + "%4.4s " ACPI_PRINTF_UINT + " Attempted table install failed", + acpi_ut_valid_acpi_name(table_desc->signature. + ascii) ? table_desc-> + signature.ascii : "????", + ACPI_FORMAT_TO_UINT(table_desc->address))); + goto invalidate_and_exit; + } + + return_ACPI_STATUS(AE_OK); + +invalidate_and_exit: + acpi_tb_invalidate_table(table_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_resize_root_table_list + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Expand the size of global table array + * + ******************************************************************************/ + +acpi_status acpi_tb_resize_root_table_list(void) +{ + struct acpi_table_desc *tables; + u32 table_count; + + ACPI_FUNCTION_TRACE(tb_resize_root_table_list); + + /* allow_resize flag is a parameter to acpi_initialize_tables */ + + if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) { + ACPI_ERROR((AE_INFO, + "Resize of Root Table Array is not allowed")); + return_ACPI_STATUS(AE_SUPPORT); + } + + /* Increase the Table Array size */ + + if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { + table_count = acpi_gbl_root_table_list.max_table_count; + } else { + table_count = acpi_gbl_root_table_list.current_table_count; + } + + tables = ACPI_ALLOCATE_ZEROED(((acpi_size) table_count + + ACPI_ROOT_TABLE_SIZE_INCREMENT) * + sizeof(struct acpi_table_desc)); + if (!tables) { + ACPI_ERROR((AE_INFO, + "Could not allocate new root table array")); + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* Copy and free the previous table array */ + + if (acpi_gbl_root_table_list.tables) { + ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, + (acpi_size) table_count * + sizeof(struct acpi_table_desc)); + + if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { + ACPI_FREE(acpi_gbl_root_table_list.tables); + } + } + + acpi_gbl_root_table_list.tables = tables; + acpi_gbl_root_table_list.max_table_count = + table_count + ACPI_ROOT_TABLE_SIZE_INCREMENT; + acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED; + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_next_root_index + * + * PARAMETERS: table_index - Where table index is returned + * + * RETURN: Status and table index. + * + * DESCRIPTION: Allocate a new ACPI table entry to the global table list + * + ******************************************************************************/ + +acpi_status acpi_tb_get_next_root_index(u32 *table_index) +{ + acpi_status status; + + /* Ensure that there is room for the table in the Root Table List */ + + if (acpi_gbl_root_table_list.current_table_count >= + acpi_gbl_root_table_list.max_table_count) { + status = acpi_tb_resize_root_table_list(); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + *table_index = acpi_gbl_root_table_list.current_table_count; + acpi_gbl_root_table_list.current_table_count++; + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_terminate + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Delete all internal ACPI tables + * + ******************************************************************************/ + +void acpi_tb_terminate(void) +{ + u32 i; + + ACPI_FUNCTION_TRACE(tb_terminate); + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + + /* Delete the individual tables */ + + for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { + acpi_tb_uninstall_table(&acpi_gbl_root_table_list.tables[i]); + } + + /* + * Delete the root table array if allocated locally. Array cannot be + * mapped, so we don't need to check for that flag. + */ + if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { + ACPI_FREE(acpi_gbl_root_table_list.tables); + } + + acpi_gbl_root_table_list.tables = NULL; + acpi_gbl_root_table_list.flags = 0; + acpi_gbl_root_table_list.current_table_count = 0; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n")); + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_delete_namespace_by_owner + * + * PARAMETERS: table_index - Table index + * + * RETURN: Status + * + * DESCRIPTION: Delete all namespace objects created when this table was loaded. + * + ******************************************************************************/ + +acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index) +{ + acpi_owner_id owner_id; + acpi_status status; + + ACPI_FUNCTION_TRACE(tb_delete_namespace_by_owner); + + status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + if (table_index >= acpi_gbl_root_table_list.current_table_count) { + + /* The table index does not exist */ + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(AE_NOT_EXIST); + } + + /* Get the owner ID for this table, used to delete namespace nodes */ + + owner_id = acpi_gbl_root_table_list.tables[table_index].owner_id; + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + + /* + * Need to acquire the namespace writer lock to prevent interference + * with any concurrent namespace walks. The interpreter must be + * released during the deletion since the acquisition of the deletion + * lock may block, and also since the execution of a namespace walk + * must be allowed to use the interpreter. + */ + (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); + status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock); + + acpi_ns_delete_namespace_by_owner(owner_id); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock); + + status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_allocate_owner_id + * + * PARAMETERS: table_index - Table index + * + * RETURN: Status + * + * DESCRIPTION: Allocates owner_id in table_desc + * + ******************************************************************************/ + +acpi_status acpi_tb_allocate_owner_id(u32 table_index) +{ + acpi_status status = AE_BAD_PARAMETER; + + ACPI_FUNCTION_TRACE(tb_allocate_owner_id); + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.current_table_count) { + status = + acpi_ut_allocate_owner_id(& + (acpi_gbl_root_table_list. + tables[table_index].owner_id)); + } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_release_owner_id + * + * PARAMETERS: table_index - Table index + * + * RETURN: Status + * + * DESCRIPTION: Releases owner_id in table_desc + * + ******************************************************************************/ + +acpi_status acpi_tb_release_owner_id(u32 table_index) +{ + acpi_status status = AE_BAD_PARAMETER; + + ACPI_FUNCTION_TRACE(tb_release_owner_id); + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.current_table_count) { + acpi_ut_release_owner_id(& + (acpi_gbl_root_table_list. + tables[table_index].owner_id)); + status = AE_OK; + } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_owner_id + * + * PARAMETERS: table_index - Table index + * owner_id - Where the table owner_id is returned + * + * RETURN: Status + * + * DESCRIPTION: returns owner_id for the ACPI table + * + ******************************************************************************/ + +acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id * owner_id) +{ + acpi_status status = AE_BAD_PARAMETER; + + ACPI_FUNCTION_TRACE(tb_get_owner_id); + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.current_table_count) { + *owner_id = + acpi_gbl_root_table_list.tables[table_index].owner_id; + status = AE_OK; + } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_is_table_loaded + * + * PARAMETERS: table_index - Index into the root table + * + * RETURN: Table Loaded Flag + * + ******************************************************************************/ + +u8 acpi_tb_is_table_loaded(u32 table_index) +{ + u8 is_loaded = FALSE; + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.current_table_count) { + is_loaded = (u8) + (acpi_gbl_root_table_list.tables[table_index].flags & + ACPI_TABLE_IS_LOADED); + } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return (is_loaded); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_set_table_loaded_flag + * + * PARAMETERS: table_index - Table index + * is_loaded - TRUE if table is loaded, FALSE otherwise + * + * RETURN: None + * + * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE. + * + ******************************************************************************/ + +void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded) +{ + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.current_table_count) { + if (is_loaded) { + acpi_gbl_root_table_list.tables[table_index].flags |= + ACPI_TABLE_IS_LOADED; + } else { + acpi_gbl_root_table_list.tables[table_index].flags &= + ~ACPI_TABLE_IS_LOADED; + } + } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); +} diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 50a6f229633c..d4d6029fef44 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -43,355 +43,57 @@ #include #include "accommon.h" -#include "acnamesp.h" #include "actables.h" #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbinstal") /* Local prototypes */ -static acpi_status -acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, - acpi_physical_address address, u8 flags); +static u8 +acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index); -static void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc); - -static acpi_status acpi_tb_get_root_table_entry(u32 *table_index); +/******************************************************************************* + * + * FUNCTION: acpi_tb_compare_tables + * + * PARAMETERS: table_desc - Table 1 descriptor to be compared + * table_index - Index of table 2 to be compared + * + * RETURN: TRUE if both tables are identical. + * + * DESCRIPTION: This function compares a table with another table that has + * already been installed in the root table list. + * + ******************************************************************************/ static u8 -acpi_tb_is_equivalent_table(struct acpi_table_desc *table_desc, - u32 table_index); - -/******************************************************************************* - * - * FUNCTION: acpi_tb_acquire_table - * - * PARAMETERS: table_desc - Table descriptor - * table_ptr - Where table is returned - * table_length - Where table length is returned - * table_flags - Where table allocation flags are returned - * - * RETURN: Status - * - * DESCRIPTION: Acquire an ACPI table. It can be used for tables not - * maintained in the acpi_gbl_root_table_list. - * - ******************************************************************************/ - -acpi_status -acpi_tb_acquire_table(struct acpi_table_desc *table_desc, - struct acpi_table_header **table_ptr, - u32 *table_length, u8 *table_flags) -{ - struct acpi_table_header *table = NULL; - - switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { - case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: - - table = - acpi_os_map_memory(table_desc->address, table_desc->length); - break; - - case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: - case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: - - table = - ACPI_CAST_PTR(struct acpi_table_header, - table_desc->address); - break; - - default: - - break; - } - - /* Table is not valid yet */ - - if (!table) { - return (AE_NO_MEMORY); - } - - /* Fill the return values */ - - *table_ptr = table; - *table_length = table_desc->length; - *table_flags = table_desc->flags; - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_release_table - * - * PARAMETERS: table - Pointer for the table - * table_length - Length for the table - * table_flags - Allocation flags for the table - * - * RETURN: None - * - * DESCRIPTION: Release a table. The inverse of acpi_tb_acquire_table(). - * - ******************************************************************************/ - -void -acpi_tb_release_table(struct acpi_table_header *table, - u32 table_length, u8 table_flags) -{ - - switch (table_flags & ACPI_TABLE_ORIGIN_MASK) { - case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: - - acpi_os_unmap_memory(table, table_length); - break; - - case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: - case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: - default: - - break; - } -} - -/****************************************************************************** - * - * FUNCTION: acpi_tb_validate_table - * - * PARAMETERS: table_desc - Table descriptor - * - * RETURN: Status - * - * DESCRIPTION: This function is called to validate the table, the returned - * table descriptor is in "VALIDATED" state. - * - *****************************************************************************/ - -acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc) +acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index) { acpi_status status = AE_OK; - - ACPI_FUNCTION_TRACE(tb_validate_table); - - /* Validate the table if necessary */ - - if (!table_desc->pointer) { - status = acpi_tb_acquire_table(table_desc, &table_desc->pointer, - &table_desc->length, - &table_desc->flags); - if (!table_desc->pointer) { - status = AE_NO_MEMORY; - } - } - - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_invalidate_table - * - * PARAMETERS: table_desc - Table descriptor - * - * RETURN: None - * - * DESCRIPTION: Invalidate one internal ACPI table, this is the inverse of - * acpi_tb_validate_table(). - * - ******************************************************************************/ - -void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc) -{ - - ACPI_FUNCTION_TRACE(tb_invalidate_table); - - /* Table must be validated */ - - if (!table_desc->pointer) { - return_VOID; - } - - acpi_tb_release_table(table_desc->pointer, table_desc->length, - table_desc->flags); - table_desc->pointer = NULL; - - return_VOID; -} - -/****************************************************************************** - * - * FUNCTION: acpi_tb_verify_table - * - * PARAMETERS: table_desc - Table descriptor - * signature - Table signature to verify - * - * RETURN: Status - * - * DESCRIPTION: This function is called to validate and verify the table, the - * returned table descriptor is in "VALIDATED" state. - * - *****************************************************************************/ - -acpi_status -acpi_tb_verify_table(struct acpi_table_desc *table_desc, char *signature) -{ - acpi_status status = AE_OK; - - ACPI_FUNCTION_TRACE(tb_verify_table); - - /* Validate the table */ - - status = acpi_tb_validate_table(table_desc); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* If a particular signature is expected (DSDT/FACS), it must match */ - - if (signature && !ACPI_COMPARE_NAME(&table_desc->signature, signature)) { - ACPI_BIOS_ERROR((AE_INFO, - "Invalid signature 0x%X for ACPI table, expected [%s]", - table_desc->signature.integer, signature)); - status = AE_BAD_SIGNATURE; - goto invalidate_and_exit; - } - - /* Verify the checksum */ + u8 is_identical; + struct acpi_table_header *table; + u32 table_length; + u8 table_flags; status = - acpi_tb_verify_checksum(table_desc->pointer, table_desc->length); + acpi_tb_acquire_table(&acpi_gbl_root_table_list.tables[table_index], + &table, &table_length, &table_flags); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, - "%4.4s " ACPI_PRINTF_UINT - " Attempted table install failed", - acpi_ut_valid_acpi_name(table_desc->signature. - ascii) ? table_desc-> - signature.ascii : "????", - ACPI_FORMAT_TO_UINT(table_desc->address))); - goto invalidate_and_exit; + return (FALSE); } - return_ACPI_STATUS(AE_OK); - -invalidate_and_exit: - acpi_tb_invalidate_table(table_desc); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_init_table_descriptor - * - * PARAMETERS: table_desc - Table descriptor - * address - Physical address of the table - * flags - Allocation flags of the table - * table - Pointer to the table - * - * RETURN: None - * - * DESCRIPTION: Initialize a new table descriptor - * - ******************************************************************************/ - -void -acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, - acpi_physical_address address, - u8 flags, struct acpi_table_header *table) -{ - /* - * Initialize the table descriptor. Set the pointer to NULL, since the - * table is not fully mapped at this time. + * Check for a table match on the entire table length, + * not just the header. */ - ACPI_MEMSET(table_desc, 0, sizeof(struct acpi_table_desc)); - table_desc->address = address; - table_desc->length = table->length; - table_desc->flags = flags; - ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature); -} + is_identical = (u8)((table_desc->length != table_length || + ACPI_MEMCMP(table_desc->pointer, table, + table_length)) ? FALSE : TRUE); -/******************************************************************************* - * - * FUNCTION: acpi_tb_acquire_temp_table - * - * PARAMETERS: table_desc - Table descriptor to be acquired - * address - Address of the table - * flags - Allocation flags of the table - * - * RETURN: Status - * - * DESCRIPTION: This function validates the table header to obtain the length - * of a table and fills the table descriptor to make its state as - * "INSTALLED". Such a table descriptor is only used for verified - * installation. - * - ******************************************************************************/ + /* Release the acquired table */ -static acpi_status -acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, - acpi_physical_address address, u8 flags) -{ - struct acpi_table_header *table_header; - - switch (flags & ACPI_TABLE_ORIGIN_MASK) { - case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: - - /* Get the length of the full table from the header */ - - table_header = - acpi_os_map_memory(address, - sizeof(struct acpi_table_header)); - if (!table_header) { - return (AE_NO_MEMORY); - } - - acpi_tb_init_table_descriptor(table_desc, address, flags, - table_header); - acpi_os_unmap_memory(table_header, - sizeof(struct acpi_table_header)); - return (AE_OK); - - case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: - case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: - - table_header = ACPI_CAST_PTR(struct acpi_table_header, address); - if (!table_header) { - return (AE_NO_MEMORY); - } - - acpi_tb_init_table_descriptor(table_desc, address, flags, - table_header); - return (AE_OK); - - default: - - break; - } - - /* Table is not valid yet */ - - return (AE_NO_MEMORY); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_release_temp_table - * - * PARAMETERS: table_desc - Table descriptor to be released - * - * RETURN: Status - * - * DESCRIPTION: The inverse of acpi_tb_acquire_temp_table(). - * - ******************************************************************************/ - -static void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc) -{ - - /* - * Note that the .Address is maintained by the callers of - * acpi_tb_acquire_temp_table(), thus do not invoke acpi_tb_uninstall_table() - * where .Address will be freed. - */ - acpi_tb_invalidate_table(table_desc); + acpi_tb_release_table(table, table_length, table_flags); + return (is_identical); } /******************************************************************************* @@ -507,50 +209,6 @@ acpi_tb_install_fixed_table(acpi_physical_address address, return_ACPI_STATUS(status); } -/******************************************************************************* - * - * FUNCTION: acpi_tb_is_equivalent_table - * - * PARAMETERS: table_desc - Table 1 descriptor to be compared - * table_index - Index of table 2 to be compared - * - * RETURN: TRUE if 2 tables are equivalent - * - * DESCRIPTION: This function is called to compare a table with what have - * already been installed in the root table list. - * - ******************************************************************************/ - -static u8 -acpi_tb_is_equivalent_table(struct acpi_table_desc *table_desc, u32 table_index) -{ - acpi_status status = AE_OK; - u8 is_equivalent; - struct acpi_table_header *table; - u32 table_length; - u8 table_flags; - - status = - acpi_tb_acquire_table(&acpi_gbl_root_table_list.tables[table_index], - &table, &table_length, &table_flags); - if (ACPI_FAILURE(status)) { - return (FALSE); - } - - /* - * Check for a table match on the entire table length, - * not just the header. - */ - is_equivalent = (u8)((table_desc->length != table_length || - ACPI_MEMCMP(table_desc->pointer, table, - table_length)) ? FALSE : TRUE); - - /* Release the acquired table */ - - acpi_tb_release_table(table, table_length, table_flags); - return (is_equivalent); -} - /******************************************************************************* * * FUNCTION: acpi_tb_install_standard_table @@ -652,7 +310,7 @@ acpi_tb_install_standard_table(acpi_physical_address address, * Check for a table match on the entire table length, * not just the header. */ - if (!acpi_tb_is_equivalent_table(&new_table_desc, i)) { + if (!acpi_tb_compare_tables(&new_table_desc, i)) { continue; } @@ -696,7 +354,7 @@ acpi_tb_install_standard_table(acpi_physical_address address, /* Add the table to the global root table list */ - status = acpi_tb_get_root_table_entry(&i); + status = acpi_tb_get_next_root_index(&i); if (ACPI_FAILURE(status)) { goto release_and_exit; } @@ -795,101 +453,6 @@ void acpi_tb_override_table(struct acpi_table_desc *old_table_desc) acpi_tb_release_temp_table(&new_table_desc); } -/******************************************************************************* - * - * FUNCTION: acpi_tb_resize_root_table_list - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Expand the size of global table array - * - ******************************************************************************/ - -acpi_status acpi_tb_resize_root_table_list(void) -{ - struct acpi_table_desc *tables; - u32 table_count; - - ACPI_FUNCTION_TRACE(tb_resize_root_table_list); - - /* allow_resize flag is a parameter to acpi_initialize_tables */ - - if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) { - ACPI_ERROR((AE_INFO, - "Resize of Root Table Array is not allowed")); - return_ACPI_STATUS(AE_SUPPORT); - } - - /* Increase the Table Array size */ - - if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { - table_count = acpi_gbl_root_table_list.max_table_count; - } else { - table_count = acpi_gbl_root_table_list.current_table_count; - } - - tables = ACPI_ALLOCATE_ZEROED(((acpi_size) table_count + - ACPI_ROOT_TABLE_SIZE_INCREMENT) * - sizeof(struct acpi_table_desc)); - if (!tables) { - ACPI_ERROR((AE_INFO, - "Could not allocate new root table array")); - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* Copy and free the previous table array */ - - if (acpi_gbl_root_table_list.tables) { - ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, - (acpi_size) table_count * - sizeof(struct acpi_table_desc)); - - if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { - ACPI_FREE(acpi_gbl_root_table_list.tables); - } - } - - acpi_gbl_root_table_list.tables = tables; - acpi_gbl_root_table_list.max_table_count = - table_count + ACPI_ROOT_TABLE_SIZE_INCREMENT; - acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED; - - return_ACPI_STATUS(AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_root_table_entry - * - * PARAMETERS: table_index - Where table index is returned - * - * RETURN: Status and table index. - * - * DESCRIPTION: Allocate a new ACPI table entry to the global table list - * - ******************************************************************************/ - -static acpi_status acpi_tb_get_root_table_entry(u32 *table_index) -{ - acpi_status status; - - /* Ensure that there is room for the table in the Root Table List */ - - if (acpi_gbl_root_table_list.current_table_count >= - acpi_gbl_root_table_list.max_table_count) { - status = acpi_tb_resize_root_table_list(); - if (ACPI_FAILURE(status)) { - return (status); - } - } - - *table_index = acpi_gbl_root_table_list.current_table_count; - acpi_gbl_root_table_list.current_table_count++; - return (AE_OK); -} - /******************************************************************************* * * FUNCTION: acpi_tb_store_table @@ -914,7 +477,7 @@ acpi_tb_store_table(acpi_physical_address address, acpi_status status; struct acpi_table_desc *table_desc; - status = acpi_tb_get_root_table_entry(table_index); + status = acpi_tb_get_next_root_index(table_index); if (ACPI_FAILURE(status)) { return (status); } @@ -960,250 +523,3 @@ void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc) table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL); return_VOID; } - -/******************************************************************************* - * - * FUNCTION: acpi_tb_terminate - * - * PARAMETERS: None - * - * RETURN: None - * - * DESCRIPTION: Delete all internal ACPI tables - * - ******************************************************************************/ - -void acpi_tb_terminate(void) -{ - u32 i; - - ACPI_FUNCTION_TRACE(tb_terminate); - - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - - /* Delete the individual tables */ - - for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { - acpi_tb_uninstall_table(&acpi_gbl_root_table_list.tables[i]); - } - - /* - * Delete the root table array if allocated locally. Array cannot be - * mapped, so we don't need to check for that flag. - */ - if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { - ACPI_FREE(acpi_gbl_root_table_list.tables); - } - - acpi_gbl_root_table_list.tables = NULL; - acpi_gbl_root_table_list.flags = 0; - acpi_gbl_root_table_list.current_table_count = 0; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n")); - - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_VOID; -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_delete_namespace_by_owner - * - * PARAMETERS: table_index - Table index - * - * RETURN: Status - * - * DESCRIPTION: Delete all namespace objects created when this table was loaded. - * - ******************************************************************************/ - -acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index) -{ - acpi_owner_id owner_id; - acpi_status status; - - ACPI_FUNCTION_TRACE(tb_delete_namespace_by_owner); - - status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - if (table_index >= acpi_gbl_root_table_list.current_table_count) { - - /* The table index does not exist */ - - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_ACPI_STATUS(AE_NOT_EXIST); - } - - /* Get the owner ID for this table, used to delete namespace nodes */ - - owner_id = acpi_gbl_root_table_list.tables[table_index].owner_id; - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - - /* - * Need to acquire the namespace writer lock to prevent interference - * with any concurrent namespace walks. The interpreter must be - * released during the deletion since the acquisition of the deletion - * lock may block, and also since the execution of a namespace walk - * must be allowed to use the interpreter. - */ - (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); - status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock); - - acpi_ns_delete_namespace_by_owner(owner_id); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock); - - status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_allocate_owner_id - * - * PARAMETERS: table_index - Table index - * - * RETURN: Status - * - * DESCRIPTION: Allocates owner_id in table_desc - * - ******************************************************************************/ - -acpi_status acpi_tb_allocate_owner_id(u32 table_index) -{ - acpi_status status = AE_BAD_PARAMETER; - - ACPI_FUNCTION_TRACE(tb_allocate_owner_id); - - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (table_index < acpi_gbl_root_table_list.current_table_count) { - status = - acpi_ut_allocate_owner_id(& - (acpi_gbl_root_table_list. - tables[table_index].owner_id)); - } - - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_release_owner_id - * - * PARAMETERS: table_index - Table index - * - * RETURN: Status - * - * DESCRIPTION: Releases owner_id in table_desc - * - ******************************************************************************/ - -acpi_status acpi_tb_release_owner_id(u32 table_index) -{ - acpi_status status = AE_BAD_PARAMETER; - - ACPI_FUNCTION_TRACE(tb_release_owner_id); - - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (table_index < acpi_gbl_root_table_list.current_table_count) { - acpi_ut_release_owner_id(& - (acpi_gbl_root_table_list. - tables[table_index].owner_id)); - status = AE_OK; - } - - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_owner_id - * - * PARAMETERS: table_index - Table index - * owner_id - Where the table owner_id is returned - * - * RETURN: Status - * - * DESCRIPTION: returns owner_id for the ACPI table - * - ******************************************************************************/ - -acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id * owner_id) -{ - acpi_status status = AE_BAD_PARAMETER; - - ACPI_FUNCTION_TRACE(tb_get_owner_id); - - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (table_index < acpi_gbl_root_table_list.current_table_count) { - *owner_id = - acpi_gbl_root_table_list.tables[table_index].owner_id; - status = AE_OK; - } - - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_is_table_loaded - * - * PARAMETERS: table_index - Index into the root table - * - * RETURN: Table Loaded Flag - * - ******************************************************************************/ - -u8 acpi_tb_is_table_loaded(u32 table_index) -{ - u8 is_loaded = FALSE; - - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (table_index < acpi_gbl_root_table_list.current_table_count) { - is_loaded = (u8) - (acpi_gbl_root_table_list.tables[table_index].flags & - ACPI_TABLE_IS_LOADED); - } - - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return (is_loaded); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_set_table_loaded_flag - * - * PARAMETERS: table_index - Table index - * is_loaded - TRUE if table is loaded, FALSE otherwise - * - * RETURN: None - * - * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE. - * - ******************************************************************************/ - -void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded) -{ - - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (table_index < acpi_gbl_root_table_list.current_table_count) { - if (is_loaded) { - acpi_gbl_root_table_list.tables[table_index].flags |= - ACPI_TABLE_IS_LOADED; - } else { - acpi_gbl_root_table_list.tables[table_index].flags &= - ~ACPI_TABLE_IS_LOADED; - } - } - - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); -} From 506f57dd6dfdb1d73cb77106706cd5b8953b453d Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:39:42 +0800 Subject: [PATCH 023/134] ACPICA: acpidump: Add support to generate acpidump release. The acpidump is initiated by Bob Moore and Chao Guan, fixed and completed by Lv Zheng. This patch is a generation of the commit that adds acpidump release automation into ACPICA release process. Lv Zheng. Note that this patch doesn't replace the kernel shipped acpidump with the new acpidump. The replacement is done by further patches. Original-by: Chao Guan Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acapps.h | 170 +++ tools/power/acpi/common/getopt.c | 239 +++ .../os_specific/service_layers/oslinuxtbl.c | 1275 +++++++++++++++++ .../os_specific/service_layers/osunixdir.c | 204 +++ .../os_specific/service_layers/osunixmap.c | 151 ++ tools/power/acpi/tools/acpidump/acpidump.h | 131 ++ tools/power/acpi/tools/acpidump/apdump.c | 451 ++++++ tools/power/acpi/tools/acpidump/apfiles.c | 228 +++ tools/power/acpi/tools/acpidump/apmain.c | 340 +++++ 9 files changed, 3189 insertions(+) create mode 100644 drivers/acpi/acpica/acapps.h create mode 100644 tools/power/acpi/common/getopt.c create mode 100644 tools/power/acpi/os_specific/service_layers/oslinuxtbl.c create mode 100644 tools/power/acpi/os_specific/service_layers/osunixdir.c create mode 100644 tools/power/acpi/os_specific/service_layers/osunixmap.c create mode 100644 tools/power/acpi/tools/acpidump/acpidump.h create mode 100644 tools/power/acpi/tools/acpidump/apdump.c create mode 100644 tools/power/acpi/tools/acpidump/apfiles.c create mode 100644 tools/power/acpi/tools/acpidump/apmain.c diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h new file mode 100644 index 000000000000..8698ffba6f39 --- /dev/null +++ b/drivers/acpi/acpica/acapps.h @@ -0,0 +1,170 @@ +/****************************************************************************** + * + * Module Name: acapps - common include for ACPI applications/tools + * + *****************************************************************************/ + +/* + * 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. + */ + +#ifndef _ACAPPS +#define _ACAPPS + +/* Common info for tool signons */ + +#define ACPICA_NAME "Intel ACPI Component Architecture" +#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2014 Intel Corporation" + +#if ACPI_MACHINE_WIDTH == 64 +#define ACPI_WIDTH "-64" + +#elif ACPI_MACHINE_WIDTH == 32 +#define ACPI_WIDTH "-32" + +#else +#error unknown ACPI_MACHINE_WIDTH +#define ACPI_WIDTH "-??" + +#endif + +/* Macros for signons and file headers */ + +#define ACPI_COMMON_SIGNON(utility_name) \ + "\n%s\n%s version %8.8X%s [%s]\n%s\n\n", \ + ACPICA_NAME, \ + utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, __DATE__, \ + ACPICA_COPYRIGHT + +#define ACPI_COMMON_HEADER(utility_name, prefix) \ + "%s%s\n%s%s version %8.8X%s [%s]\n%s%s\n%s\n", \ + prefix, ACPICA_NAME, \ + prefix, utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, __DATE__, \ + prefix, ACPICA_COPYRIGHT, \ + prefix + +/* Macros for usage messages */ + +#define ACPI_USAGE_HEADER(usage) \ + printf ("Usage: %s\nOptions:\n", usage); + +#define ACPI_OPTION(name, description) \ + printf (" %-18s%s\n", name, description); + +#define FILE_SUFFIX_DISASSEMBLY "dsl" +#define ACPI_TABLE_FILE_SUFFIX ".dat" + +/* + * getopt + */ +int acpi_getopt(int argc, char **argv, char *opts); + +int acpi_getopt_argument(int argc, char **argv); + +extern int acpi_gbl_optind; +extern int acpi_gbl_opterr; +extern int acpi_gbl_sub_opt_char; +extern char *acpi_gbl_optarg; + +/* + * cmfsize - Common get file size function + */ +u32 cm_get_file_size(FILE * file); + +#ifndef ACPI_DUMP_APP +/* + * adisasm + */ +acpi_status +ad_aml_disassemble(u8 out_to_file, + char *filename, char *prefix, char **out_filename); + +void ad_print_statistics(void); + +acpi_status ad_find_dsdt(u8 **dsdt_ptr, u32 *dsdt_length); + +void ad_dump_tables(void); + +acpi_status ad_get_local_tables(void); + +acpi_status +ad_parse_table(struct acpi_table_header *table, + acpi_owner_id * owner_id, u8 load_table, u8 external); + +acpi_status ad_display_tables(char *filename, struct acpi_table_header *table); + +acpi_status ad_display_statistics(void); + +/* + * adwalk + */ +void +acpi_dm_cross_reference_namespace(union acpi_parse_object *parse_tree_root, + struct acpi_namespace_node *namespace_root, + acpi_owner_id owner_id); + +void acpi_dm_dump_tree(union acpi_parse_object *origin); + +void acpi_dm_find_orphan_methods(union acpi_parse_object *origin); + +void +acpi_dm_finish_namespace_load(union acpi_parse_object *parse_tree_root, + struct acpi_namespace_node *namespace_root, + acpi_owner_id owner_id); + +void +acpi_dm_convert_resource_indexes(union acpi_parse_object *parse_tree_root, + struct acpi_namespace_node *namespace_root); + +/* + * adfile + */ +acpi_status ad_initialize(void); + +char *fl_generate_filename(char *input_filename, char *suffix); + +acpi_status +fl_split_input_pathname(char *input_path, + char **out_directory_path, char **out_filename); + +char *ad_generate_filename(char *prefix, char *table_id); + +void +ad_write_table(struct acpi_table_header *table, + u32 length, char *table_name, char *oem_table_id); +#endif + +#endif /* _ACAPPS */ diff --git a/tools/power/acpi/common/getopt.c b/tools/power/acpi/common/getopt.c new file mode 100644 index 000000000000..a302f52e4fd3 --- /dev/null +++ b/tools/power/acpi/common/getopt.c @@ -0,0 +1,239 @@ +/****************************************************************************** + * + * Module Name: getopt + * + *****************************************************************************/ + +/* + * 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. + */ + +/* + * ACPICA getopt() implementation + * + * Option strings: + * "f" - Option has no arguments + * "f:" - Option requires an argument + * "f^" - Option has optional single-char sub-options + * "f|" - Option has required single-char sub-options + */ + +#include +#include +#include +#include "accommon.h" +#include "acapps.h" + +#define ACPI_OPTION_ERROR(msg, badchar) \ + if (acpi_gbl_opterr) {fprintf (stderr, "%s%c\n", msg, badchar);} + +int acpi_gbl_opterr = 1; +int acpi_gbl_optind = 1; +int acpi_gbl_sub_opt_char = 0; +char *acpi_gbl_optarg; + +static int current_char_ptr = 1; + +/******************************************************************************* + * + * FUNCTION: acpi_getopt_argument + * + * PARAMETERS: argc, argv - from main + * + * RETURN: 0 if an argument was found, -1 otherwise. Sets acpi_gbl_Optarg + * to point to the next argument. + * + * DESCRIPTION: Get the next argument. Used to obtain arguments for the + * two-character options after the original call to acpi_getopt. + * Note: Either the argument starts at the next character after + * the option, or it is pointed to by the next argv entry. + * (After call to acpi_getopt, we need to backup to the previous + * argv entry). + * + ******************************************************************************/ + +int acpi_getopt_argument(int argc, char **argv) +{ + acpi_gbl_optind--; + current_char_ptr++; + + if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') { + acpi_gbl_optarg = + &argv[acpi_gbl_optind++][(int)(current_char_ptr + 1)]; + } else if (++acpi_gbl_optind >= argc) { + ACPI_OPTION_ERROR("Option requires an argument: -", 'v'); + + current_char_ptr = 1; + return (-1); + } else { + acpi_gbl_optarg = argv[acpi_gbl_optind++]; + } + + current_char_ptr = 1; + return (0); +} + +/******************************************************************************* + * + * FUNCTION: acpi_getopt + * + * PARAMETERS: argc, argv - from main + * opts - options info list + * + * RETURN: Option character or EOF + * + * DESCRIPTION: Get the next option + * + ******************************************************************************/ + +int acpi_getopt(int argc, char **argv, char *opts) +{ + int current_char; + char *opts_ptr; + + if (current_char_ptr == 1) { + if (acpi_gbl_optind >= argc || + argv[acpi_gbl_optind][0] != '-' || + argv[acpi_gbl_optind][1] == '\0') { + return (EOF); + } else if (strcmp(argv[acpi_gbl_optind], "--") == 0) { + acpi_gbl_optind++; + return (EOF); + } + } + + /* Get the option */ + + current_char = argv[acpi_gbl_optind][current_char_ptr]; + + /* Make sure that the option is legal */ + + if (current_char == ':' || + (opts_ptr = strchr(opts, current_char)) == NULL) { + ACPI_OPTION_ERROR("Illegal option: -", current_char); + + if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') { + acpi_gbl_optind++; + current_char_ptr = 1; + } + + return ('?'); + } + + /* Option requires an argument? */ + + if (*++opts_ptr == ':') { + if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') { + acpi_gbl_optarg = + &argv[acpi_gbl_optind++][(int) + (current_char_ptr + 1)]; + } else if (++acpi_gbl_optind >= argc) { + ACPI_OPTION_ERROR("Option requires an argument: -", + current_char); + + current_char_ptr = 1; + return ('?'); + } else { + acpi_gbl_optarg = argv[acpi_gbl_optind++]; + } + + current_char_ptr = 1; + } + + /* Option has an optional argument? */ + + else if (*opts_ptr == '+') { + if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') { + acpi_gbl_optarg = + &argv[acpi_gbl_optind++][(int) + (current_char_ptr + 1)]; + } else if (++acpi_gbl_optind >= argc) { + acpi_gbl_optarg = NULL; + } else { + acpi_gbl_optarg = argv[acpi_gbl_optind++]; + } + + current_char_ptr = 1; + } + + /* Option has optional single-char arguments? */ + + else if (*opts_ptr == '^') { + if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') { + acpi_gbl_optarg = + &argv[acpi_gbl_optind][(int)(current_char_ptr + 1)]; + } else { + acpi_gbl_optarg = "^"; + } + + acpi_gbl_sub_opt_char = acpi_gbl_optarg[0]; + acpi_gbl_optind++; + current_char_ptr = 1; + } + + /* Option has a required single-char argument? */ + + else if (*opts_ptr == '|') { + if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') { + acpi_gbl_optarg = + &argv[acpi_gbl_optind][(int)(current_char_ptr + 1)]; + } else { + ACPI_OPTION_ERROR + ("Option requires a single-character suboption: -", + current_char); + + current_char_ptr = 1; + return ('?'); + } + + acpi_gbl_sub_opt_char = acpi_gbl_optarg[0]; + acpi_gbl_optind++; + current_char_ptr = 1; + } + + /* Option with no arguments */ + + else { + if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') { + current_char_ptr = 1; + acpi_gbl_optind++; + } + + acpi_gbl_optarg = NULL; + } + + return (current_char); +} diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c new file mode 100644 index 000000000000..e975aa90016a --- /dev/null +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c @@ -0,0 +1,1275 @@ +/****************************************************************************** + * + * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables + * + *****************************************************************************/ + +/* + * 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 "acpidump.h" + +#define _COMPONENT ACPI_OS_SERVICES +ACPI_MODULE_NAME("oslinuxtbl") + +#ifndef PATH_MAX +#define PATH_MAX 256 +#endif +/* List of information about obtained ACPI tables */ +typedef struct osl_table_info { + struct osl_table_info *next; + u32 instance; + char signature[ACPI_NAME_SIZE]; + +} osl_table_info; + +/* Local prototypes */ + +static acpi_status osl_table_initialize(void); + +static acpi_status +osl_table_name_from_file(char *filename, char *signature, u32 *instance); + +static acpi_status osl_add_table_to_list(char *signature, u32 instance); + +static acpi_status +osl_read_table_from_file(char *filename, + acpi_size file_offset, + char *signature, struct acpi_table_header **table); + +static acpi_status +osl_map_table(acpi_size address, + char *signature, struct acpi_table_header **table); + +static void osl_unmap_table(struct acpi_table_header *table); + +static acpi_physical_address osl_find_rsdp_via_efi(void); + +static acpi_status osl_load_rsdp(void); + +static acpi_status osl_list_customized_tables(char *directory); + +static acpi_status +osl_get_customized_table(char *pathname, + char *signature, + u32 instance, + struct acpi_table_header **table, + acpi_physical_address * address); + +static acpi_status osl_list_bios_tables(void); + +static acpi_status +osl_get_bios_table(char *signature, + u32 instance, + struct acpi_table_header **table, + acpi_physical_address * address); + +static acpi_status osl_get_last_status(acpi_status default_status); + +/* File locations */ + +#define DYNAMIC_TABLE_DIR "/sys/firmware/acpi/tables/dynamic" +#define STATIC_TABLE_DIR "/sys/firmware/acpi/tables" +#define EFI_SYSTAB "/sys/firmware/efi/systab" + +/* Should we get dynamically loaded SSDTs from DYNAMIC_TABLE_DIR? */ + +u8 gbl_dump_dynamic_tables = TRUE; + +/* Initialization flags */ + +u8 gbl_table_list_initialized = FALSE; + +/* Local copies of main ACPI tables */ + +struct acpi_table_rsdp gbl_rsdp; +struct acpi_table_fadt *gbl_fadt = NULL; +struct acpi_table_rsdt *gbl_rsdt = NULL; +struct acpi_table_xsdt *gbl_xsdt = NULL; + +/* Table addresses */ + +acpi_physical_address gbl_fadt_address = 0; +acpi_physical_address gbl_rsdp_address = 0; + +/* Revision of RSD PTR */ + +u8 gbl_revision = 0; + +struct osl_table_info *gbl_table_list_head = NULL; +u32 gbl_table_count = 0; + +/****************************************************************************** + * + * FUNCTION: osl_get_last_status + * + * PARAMETERS: default_status - Default error status to return + * + * RETURN: Status; Converted from errno. + * + * DESCRIPTION: Get last errno and conver it to acpi_status. + * + *****************************************************************************/ + +static acpi_status osl_get_last_status(acpi_status default_status) +{ + + switch (errno) { + case EACCES: + case EPERM: + + return (AE_ACCESS); + + case ENOENT: + + return (AE_NOT_FOUND); + + case ENOMEM: + + return (AE_NO_MEMORY); + + default: + + return (default_status); + } +} + +/****************************************************************************** + * + * FUNCTION: acpi_os_get_table_by_address + * + * PARAMETERS: address - Physical address of the ACPI table + * table - Where a pointer to the table is returned + * + * RETURN: Status; Table buffer is returned if AE_OK. + * AE_NOT_FOUND: A valid table was not found at the address + * + * DESCRIPTION: Get an ACPI table via a physical memory address. + * + *****************************************************************************/ + +acpi_status +acpi_os_get_table_by_address(acpi_physical_address address, + struct acpi_table_header ** table) +{ + u32 table_length; + struct acpi_table_header *mapped_table; + struct acpi_table_header *local_table = NULL; + acpi_status status = AE_OK; + + /* Get main ACPI tables from memory on first invocation of this function */ + + status = osl_table_initialize(); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Map the table and validate it */ + + status = osl_map_table(address, NULL, &mapped_table); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Copy table to local buffer and return it */ + + table_length = ap_get_table_length(mapped_table); + if (table_length == 0) { + status = AE_BAD_HEADER; + goto exit; + } + + local_table = calloc(1, table_length); + if (!local_table) { + status = AE_NO_MEMORY; + goto exit; + } + + ACPI_MEMCPY(local_table, mapped_table, table_length); + +exit: + osl_unmap_table(mapped_table); + *table = local_table; + return (status); +} + +/****************************************************************************** + * + * FUNCTION: acpi_os_get_table_by_name + * + * PARAMETERS: signature - ACPI Signature for desired table. Must be + * a null terminated 4-character string. + * instance - Multiple table support for SSDT/UEFI (0...n) + * Must be 0 for other tables. + * table - Where a pointer to the table is returned + * address - Where the table physical address is returned + * + * RETURN: Status; Table buffer and physical address returned if AE_OK. + * AE_LIMIT: Instance is beyond valid limit + * AE_NOT_FOUND: A table with the signature was not found + * + * NOTE: Assumes the input signature is uppercase. + * + *****************************************************************************/ + +acpi_status +acpi_os_get_table_by_name(char *signature, + u32 instance, + struct acpi_table_header ** table, + acpi_physical_address * address) +{ + acpi_status status; + + /* Get main ACPI tables from memory on first invocation of this function */ + + status = osl_table_initialize(); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */ + + if (!gbl_dump_customized_tables) { + + /* Attempt to get the table from the memory */ + + status = + osl_get_bios_table(signature, instance, table, address); + } else { + /* Attempt to get the table from the static directory */ + + status = osl_get_customized_table(STATIC_TABLE_DIR, signature, + instance, table, address); + } + + if (ACPI_FAILURE(status) && status == AE_LIMIT) { + if (gbl_dump_dynamic_tables) { + + /* Attempt to get a dynamic table */ + + status = + osl_get_customized_table(DYNAMIC_TABLE_DIR, + signature, instance, table, + address); + } + } + + return (status); +} + +/****************************************************************************** + * + * FUNCTION: osl_add_table_to_list + * + * PARAMETERS: signature - Table signature + * instance - Table instance + * + * RETURN: Status; Successfully added if AE_OK. + * AE_NO_MEMORY: Memory allocation error + * + * DESCRIPTION: Insert a table structure into OSL table list. + * + *****************************************************************************/ + +static acpi_status osl_add_table_to_list(char *signature, u32 instance) +{ + struct osl_table_info *new_info; + struct osl_table_info *next; + u32 next_instance = 0; + u8 found = FALSE; + + new_info = calloc(1, sizeof(struct osl_table_info)); + if (!new_info) { + return (AE_NO_MEMORY); + } + + ACPI_MOVE_NAME(new_info->signature, signature); + + if (!gbl_table_list_head) { + gbl_table_list_head = new_info; + } else { + next = gbl_table_list_head; + while (1) { + if (ACPI_COMPARE_NAME(next->signature, signature)) { + if (next->instance == instance) { + found = TRUE; + } + if (next->instance >= next_instance) { + next_instance = next->instance + 1; + } + } + + if (!next->next) { + break; + } + next = next->next; + } + next->next = new_info; + } + + if (found) { + if (instance) { + fprintf(stderr, + "%4.4s: Warning unmatched table instance %d, expected %d\n", + signature, instance, next_instance); + } + instance = next_instance; + } + + new_info->instance = instance; + gbl_table_count++; + + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: acpi_os_get_table_by_index + * + * PARAMETERS: index - Which table to get + * table - Where a pointer to the table is returned + * instance - Where a pointer to the table instance no. is + * returned + * address - Where the table physical address is returned + * + * RETURN: Status; Table buffer and physical address returned if AE_OK. + * AE_LIMIT: Index is beyond valid limit + * + * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns + * AE_LIMIT when an invalid index is reached. Index is not + * necessarily an index into the RSDT/XSDT. + * + *****************************************************************************/ + +acpi_status +acpi_os_get_table_by_index(u32 index, + struct acpi_table_header ** table, + u32 *instance, acpi_physical_address * address) +{ + struct osl_table_info *info; + acpi_status status; + u32 i; + + /* Get main ACPI tables from memory on first invocation of this function */ + + status = osl_table_initialize(); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Validate Index */ + + if (index >= gbl_table_count) { + return (AE_LIMIT); + } + + /* Point to the table list entry specified by the Index argument */ + + info = gbl_table_list_head; + for (i = 0; i < index; i++) { + info = info->next; + } + + /* Now we can just get the table via the signature */ + + status = acpi_os_get_table_by_name(info->signature, info->instance, + table, address); + + if (ACPI_SUCCESS(status)) { + *instance = info->instance; + } + return (status); +} + +/****************************************************************************** + * + * FUNCTION: osl_find_rsdp_via_efi + * + * PARAMETERS: None + * + * RETURN: RSDP address if found + * + * DESCRIPTION: Find RSDP address via EFI. + * + *****************************************************************************/ + +static acpi_physical_address osl_find_rsdp_via_efi(void) +{ + FILE *file; + char buffer[80]; + unsigned long address = 0; + + file = fopen(EFI_SYSTAB, "r"); + if (file) { + while (fgets(buffer, 80, file)) { + if (sscanf(buffer, "ACPI20=0x%lx", &address) == 1) { + break; + } + } + fclose(file); + } + + return ((acpi_physical_address) (address)); +} + +/****************************************************************************** + * + * FUNCTION: osl_load_rsdp + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Scan and load RSDP. + * + *****************************************************************************/ + +static acpi_status osl_load_rsdp(void) +{ + struct acpi_table_header *mapped_table; + u8 *rsdp_address; + acpi_physical_address rsdp_base; + acpi_size rsdp_size; + + /* Get RSDP from memory */ + + rsdp_size = sizeof(struct acpi_table_rsdp); + if (gbl_rsdp_base) { + rsdp_base = gbl_rsdp_base; + } else { + rsdp_base = osl_find_rsdp_via_efi(); + } + + if (!rsdp_base) { + rsdp_base = ACPI_HI_RSDP_WINDOW_BASE; + rsdp_size = ACPI_HI_RSDP_WINDOW_SIZE; + } + + rsdp_address = acpi_os_map_memory(rsdp_base, rsdp_size); + if (!rsdp_address) { + return (osl_get_last_status(AE_BAD_ADDRESS)); + } + + /* Search low memory for the RSDP */ + + mapped_table = ACPI_CAST_PTR(struct acpi_table_header, + acpi_tb_scan_memory_for_rsdp(rsdp_address, + rsdp_size)); + if (!mapped_table) { + acpi_os_unmap_memory(rsdp_address, rsdp_size); + return (AE_NOT_FOUND); + } + + gbl_rsdp_address = + rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address); + + ACPI_MEMCPY(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp)); + acpi_os_unmap_memory(rsdp_address, rsdp_size); + + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: osl_table_initialize + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to + * local variables. Main ACPI tables include RSDT, FADT, RSDT, + * and/or XSDT. + * + *****************************************************************************/ + +static acpi_status osl_table_initialize(void) +{ + acpi_status status; + acpi_physical_address address; + + if (gbl_table_list_initialized) { + return (AE_OK); + } + + /* Get RSDP from memory */ + + status = osl_load_rsdp(); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Get XSDT from memory */ + + if (gbl_rsdp.revision) { + if (gbl_xsdt) { + free(gbl_xsdt); + gbl_xsdt = NULL; + } + + gbl_revision = 2; + status = osl_get_bios_table(ACPI_SIG_XSDT, 0, + ACPI_CAST_PTR(struct + acpi_table_header *, + &gbl_xsdt), &address); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + /* Get RSDT from memory */ + + if (gbl_rsdp.rsdt_physical_address) { + if (gbl_rsdt) { + free(gbl_rsdt); + gbl_rsdt = NULL; + } + + status = osl_get_bios_table(ACPI_SIG_RSDT, 0, + ACPI_CAST_PTR(struct + acpi_table_header *, + &gbl_rsdt), &address); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + /* Get FADT from memory */ + + if (gbl_fadt) { + free(gbl_fadt); + gbl_fadt = NULL; + } + + status = osl_get_bios_table(ACPI_SIG_FADT, 0, + ACPI_CAST_PTR(struct acpi_table_header *, + &gbl_fadt), + &gbl_fadt_address); + if (ACPI_FAILURE(status)) { + return (status); + } + + if (!gbl_dump_customized_tables) { + + /* Add mandatory tables to global table list first */ + + status = osl_add_table_to_list(ACPI_RSDP_NAME, 0); + if (ACPI_FAILURE(status)) { + return (status); + } + + status = osl_add_table_to_list(ACPI_SIG_RSDT, 0); + if (ACPI_FAILURE(status)) { + return (status); + } + + if (gbl_revision == 2) { + status = osl_add_table_to_list(ACPI_SIG_XSDT, 0); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + status = osl_add_table_to_list(ACPI_SIG_DSDT, 0); + if (ACPI_FAILURE(status)) { + return (status); + } + + status = osl_add_table_to_list(ACPI_SIG_FACS, 0); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Add all tables found in the memory */ + + status = osl_list_bios_tables(); + if (ACPI_FAILURE(status)) { + return (status); + } + } else { + /* Add all tables found in the static directory */ + + status = osl_list_customized_tables(STATIC_TABLE_DIR); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + if (gbl_dump_dynamic_tables) { + + /* Add all dynamically loaded tables in the dynamic directory */ + + status = osl_list_customized_tables(DYNAMIC_TABLE_DIR); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + gbl_table_list_initialized = TRUE; + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: osl_list_bios_tables + * + * PARAMETERS: None + * + * RETURN: Status; Table list is initialized if AE_OK. + * + * DESCRIPTION: Add ACPI tables to the table list from memory. + * + * NOTE: This works on Linux as table customization does not modify the + * addresses stored in RSDP/RSDT/XSDT/FADT. + * + *****************************************************************************/ + +static acpi_status osl_list_bios_tables(void) +{ + struct acpi_table_header *mapped_table = NULL; + u8 *table_data; + u8 number_of_tables; + u8 item_size; + acpi_physical_address table_address = 0; + acpi_status status = AE_OK; + u32 i; + + if (gbl_revision) { + item_size = sizeof(u64); + table_data = + ACPI_CAST8(gbl_xsdt) + sizeof(struct acpi_table_header); + number_of_tables = + (u8)((gbl_xsdt->header.length - + sizeof(struct acpi_table_header)) + / item_size); + } else { /* Use RSDT if XSDT is not available */ + + item_size = sizeof(u32); + table_data = + ACPI_CAST8(gbl_rsdt) + sizeof(struct acpi_table_header); + number_of_tables = + (u8)((gbl_rsdt->header.length - + sizeof(struct acpi_table_header)) + / item_size); + } + + /* Search RSDT/XSDT for the requested table */ + + for (i = 0; i < number_of_tables; ++i, table_data += item_size) { + if (gbl_revision) { + table_address = + (acpi_physical_address) (*ACPI_CAST64(table_data)); + } else { + table_address = + (acpi_physical_address) (*ACPI_CAST32(table_data)); + } + + status = osl_map_table(table_address, NULL, &mapped_table); + if (ACPI_FAILURE(status)) { + return (status); + } + + osl_add_table_to_list(mapped_table->signature, 0); + osl_unmap_table(mapped_table); + } + + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: osl_get_bios_table + * + * PARAMETERS: signature - ACPI Signature for common table. Must be + * a null terminated 4-character string. + * instance - Multiple table support for SSDT/UEFI (0...n) + * Must be 0 for other tables. + * table - Where a pointer to the table is returned + * address - Where the table physical address is returned + * + * RETURN: Status; Table buffer and physical address returned if AE_OK. + * AE_LIMIT: Instance is beyond valid limit + * AE_NOT_FOUND: A table with the signature was not found + * + * DESCRIPTION: Get a BIOS provided ACPI table + * + * NOTE: Assumes the input signature is uppercase. + * + *****************************************************************************/ + +static acpi_status +osl_get_bios_table(char *signature, + u32 instance, + struct acpi_table_header **table, + acpi_physical_address * address) +{ + struct acpi_table_header *local_table = NULL; + struct acpi_table_header *mapped_table = NULL; + u8 *table_data; + u8 number_of_tables; + u8 item_size; + u32 current_instance = 0; + acpi_physical_address table_address = 0; + u32 table_length = 0; + acpi_status status = AE_OK; + u32 i; + + /* Handle special tables whose addresses are not in RSDT/XSDT */ + + if (ACPI_COMPARE_NAME(signature, ACPI_RSDP_NAME) || + ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT) || + ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT) || + ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT) || + ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { + /* + * Get the appropriate address, either 32-bit or 64-bit. Be very + * careful about the FADT length and validate table addresses. + * Note: The 64-bit addresses have priority. + */ + if (ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT)) { + if ((gbl_fadt->header.length >= MIN_FADT_FOR_XDSDT) && + gbl_fadt->Xdsdt) { + table_address = + (acpi_physical_address) gbl_fadt->Xdsdt; + } else + if ((gbl_fadt->header.length >= MIN_FADT_FOR_DSDT) + && gbl_fadt->dsdt) { + table_address = + (acpi_physical_address) gbl_fadt->dsdt; + } + } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { + if ((gbl_fadt->header.length >= MIN_FADT_FOR_XFACS) && + gbl_fadt->Xfacs) { + table_address = + (acpi_physical_address) gbl_fadt->Xfacs; + } else + if ((gbl_fadt->header.length >= MIN_FADT_FOR_FACS) + && gbl_fadt->facs) { + table_address = + (acpi_physical_address) gbl_fadt->facs; + } + } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) { + if (!gbl_revision) { + return (AE_BAD_SIGNATURE); + } + table_address = + (acpi_physical_address) gbl_rsdp. + xsdt_physical_address; + } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) { + table_address = + (acpi_physical_address) gbl_rsdp. + rsdt_physical_address; + } else { + table_address = + (acpi_physical_address) gbl_rsdp_address; + signature = ACPI_SIG_RSDP; + } + + /* Now we can get the requested special table */ + + status = osl_map_table(table_address, signature, &mapped_table); + if (ACPI_FAILURE(status)) { + return (status); + } + + table_length = ap_get_table_length(mapped_table); + } else { /* Case for a normal ACPI table */ + + if (gbl_revision) { + item_size = sizeof(u64); + table_data = + ACPI_CAST8(gbl_xsdt) + + sizeof(struct acpi_table_header); + number_of_tables = + (u8)((gbl_xsdt->header.length - + sizeof(struct acpi_table_header)) + / item_size); + } else { /* Use RSDT if XSDT is not available */ + + item_size = sizeof(u32); + table_data = + ACPI_CAST8(gbl_rsdt) + + sizeof(struct acpi_table_header); + number_of_tables = + (u8)((gbl_rsdt->header.length - + sizeof(struct acpi_table_header)) + / item_size); + } + + /* Search RSDT/XSDT for the requested table */ + + for (i = 0; i < number_of_tables; ++i, table_data += item_size) { + if (gbl_revision) { + table_address = + (acpi_physical_address) (*ACPI_CAST64 + (table_data)); + } else { + table_address = + (acpi_physical_address) (*ACPI_CAST32 + (table_data)); + } + + status = + osl_map_table(table_address, NULL, &mapped_table); + if (ACPI_FAILURE(status)) { + return (status); + } + table_length = mapped_table->length; + + /* Does this table match the requested signature? */ + + if (!ACPI_COMPARE_NAME + (mapped_table->signature, signature)) { + osl_unmap_table(mapped_table); + mapped_table = NULL; + continue; + } + + /* Match table instance (for SSDT/UEFI tables) */ + + if (current_instance != instance) { + osl_unmap_table(mapped_table); + mapped_table = NULL; + current_instance++; + continue; + } + + break; + } + } + + if (!mapped_table) { + return (AE_LIMIT); + } + + if (table_length == 0) { + status = AE_BAD_HEADER; + goto exit; + } + + /* Copy table to local buffer and return it */ + + local_table = calloc(1, table_length); + if (!local_table) { + status = AE_NO_MEMORY; + goto exit; + } + + ACPI_MEMCPY(local_table, mapped_table, table_length); + *address = table_address; + *table = local_table; + +exit: + osl_unmap_table(mapped_table); + return (status); +} + +/****************************************************************************** + * + * FUNCTION: osl_list_customized_tables + * + * PARAMETERS: directory - Directory that contains the tables + * + * RETURN: Status; Table list is initialized if AE_OK. + * + * DESCRIPTION: Add ACPI tables to the table list from a directory. + * + *****************************************************************************/ + +static acpi_status osl_list_customized_tables(char *directory) +{ + void *table_dir; + u32 instance; + char temp_name[ACPI_NAME_SIZE]; + char *filename; + acpi_status status = AE_OK; + + /* Open the requested directory */ + + table_dir = acpi_os_open_directory(directory, "*", REQUEST_FILE_ONLY); + if (!table_dir) { + return (osl_get_last_status(AE_NOT_FOUND)); + } + + /* Examine all entries in this directory */ + + while ((filename = acpi_os_get_next_filename(table_dir))) { + + /* Extract table name and instance number */ + + status = + osl_table_name_from_file(filename, temp_name, &instance); + + /* Ignore meaningless files */ + + if (ACPI_FAILURE(status)) { + continue; + } + + /* Add new info node to global table list */ + + status = osl_add_table_to_list(temp_name, instance); + if (ACPI_FAILURE(status)) { + break; + } + } + + acpi_os_close_directory(table_dir); + return (status); +} + +/****************************************************************************** + * + * FUNCTION: osl_map_table + * + * PARAMETERS: address - Address of the table in memory + * signature - Optional ACPI Signature for desired table. + * Null terminated 4-character string. + * table - Where a pointer to the mapped table is + * returned + * + * RETURN: Status; Mapped table is returned if AE_OK. + * AE_NOT_FOUND: A valid table was not found at the address + * + * DESCRIPTION: Map entire ACPI table into caller's address space. + * + *****************************************************************************/ + +static acpi_status +osl_map_table(acpi_size address, + char *signature, struct acpi_table_header **table) +{ + struct acpi_table_header *mapped_table; + u32 length; + + if (!address) { + return (AE_BAD_ADDRESS); + } + + /* + * Map the header so we can get the table length. + * Use sizeof (struct acpi_table_header) as: + * 1. it is bigger than 24 to include RSDP->Length + * 2. it is smaller than sizeof (struct acpi_table_rsdp) + */ + mapped_table = + acpi_os_map_memory(address, sizeof(struct acpi_table_header)); + if (!mapped_table) { + fprintf(stderr, "Could not map table header at 0x%8.8X%8.8X\n", + ACPI_FORMAT_UINT64(address)); + return (osl_get_last_status(AE_BAD_ADDRESS)); + } + + /* If specified, signature must match */ + + if (signature && !ACPI_COMPARE_NAME(signature, mapped_table->signature)) { + acpi_os_unmap_memory(mapped_table, + sizeof(struct acpi_table_header)); + return (AE_BAD_SIGNATURE); + } + + /* Map the entire table */ + + length = ap_get_table_length(mapped_table); + acpi_os_unmap_memory(mapped_table, sizeof(struct acpi_table_header)); + if (length == 0) { + return (AE_BAD_HEADER); + } + + mapped_table = acpi_os_map_memory(address, length); + if (!mapped_table) { + fprintf(stderr, + "Could not map table at 0x%8.8X%8.8X length %8.8X\n", + ACPI_FORMAT_UINT64(address), length); + return (osl_get_last_status(AE_INVALID_TABLE_LENGTH)); + } + + (void)ap_is_valid_checksum(mapped_table); + + *table = mapped_table; + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: osl_unmap_table + * + * PARAMETERS: table - A pointer to the mapped table + * + * RETURN: None + * + * DESCRIPTION: Unmap entire ACPI table. + * + *****************************************************************************/ + +static void osl_unmap_table(struct acpi_table_header *table) +{ + if (table) { + acpi_os_unmap_memory(table, ap_get_table_length(table)); + } +} + +/****************************************************************************** + * + * FUNCTION: osl_table_name_from_file + * + * PARAMETERS: filename - File that contains the desired table + * signature - Pointer to 4-character buffer to store + * extracted table signature. + * instance - Pointer to integer to store extracted + * table instance number. + * + * RETURN: Status; Table name is extracted if AE_OK. + * + * DESCRIPTION: Extract table signature and instance number from a table file + * name. + * + *****************************************************************************/ + +static acpi_status +osl_table_name_from_file(char *filename, char *signature, u32 *instance) +{ + + /* Ignore meaningless files */ + + if (strlen(filename) < ACPI_NAME_SIZE) { + return (AE_BAD_SIGNATURE); + } + + /* Extract instance number */ + + if (isdigit((int)filename[ACPI_NAME_SIZE])) { + sscanf(&filename[ACPI_NAME_SIZE], "%d", instance); + } else if (strlen(filename) != ACPI_NAME_SIZE) { + return (AE_BAD_SIGNATURE); + } else { + *instance = 0; + } + + /* Extract signature */ + + ACPI_MOVE_NAME(signature, filename); + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: osl_read_table_from_file + * + * PARAMETERS: filename - File that contains the desired table + * file_offset - Offset of the table in file + * signature - Optional ACPI Signature for desired table. + * A null terminated 4-character string. + * table - Where a pointer to the table is returned + * + * RETURN: Status; Table buffer is returned if AE_OK. + * + * DESCRIPTION: Read a ACPI table from a file. + * + *****************************************************************************/ + +static acpi_status +osl_read_table_from_file(char *filename, + acpi_size file_offset, + char *signature, struct acpi_table_header **table) +{ + FILE *table_file; + struct acpi_table_header header; + struct acpi_table_header *local_table = NULL; + u32 table_length; + s32 count; + u32 total = 0; + acpi_status status = AE_OK; + + /* Open the file */ + + table_file = fopen(filename, "rb"); + if (table_file == NULL) { + fprintf(stderr, "Could not open table file: %s\n", filename); + return (osl_get_last_status(AE_NOT_FOUND)); + } + + fseek(table_file, file_offset, SEEK_SET); + + /* Read the Table header to get the table length */ + + count = fread(&header, 1, sizeof(struct acpi_table_header), table_file); + if (count != sizeof(struct acpi_table_header)) { + fprintf(stderr, "Could not read table header: %s\n", filename); + status = AE_BAD_HEADER; + goto exit; + } + + /* If signature is specified, it must match the table */ + + if (signature && !ACPI_COMPARE_NAME(signature, header.signature)) { + fprintf(stderr, + "Incorrect signature: Expecting %4.4s, found %4.4s\n", + signature, header.signature); + status = AE_BAD_SIGNATURE; + goto exit; + } + + table_length = ap_get_table_length(&header); + if (table_length == 0) { + status = AE_BAD_HEADER; + goto exit; + } + + /* Read the entire table into a local buffer */ + + local_table = calloc(1, table_length); + if (!local_table) { + fprintf(stderr, + "%4.4s: Could not allocate buffer for table of length %X\n", + header.signature, table_length); + status = AE_NO_MEMORY; + goto exit; + } + + fseek(table_file, file_offset, SEEK_SET); + + while (!feof(table_file) && total < table_length) { + count = fread(local_table + total, 1, table_length - total, table_file); + if (count < 0) { + fprintf(stderr, "%4.4s: Could not read table content\n", + header.signature); + status = AE_INVALID_TABLE_LENGTH; + goto exit; + } + + total += count; + } + + /* Validate checksum */ + + (void)ap_is_valid_checksum(local_table); + +exit: + fclose(table_file); + *table = local_table; + return (status); +} + +/****************************************************************************** + * + * FUNCTION: osl_get_customized_table + * + * PARAMETERS: pathname - Directory to find Linux customized table + * signature - ACPI Signature for desired table. Must be + * a null terminated 4-character string. + * instance - Multiple table support for SSDT/UEFI (0...n) + * Must be 0 for other tables. + * table - Where a pointer to the table is returned + * address - Where the table physical address is returned + * + * RETURN: Status; Table buffer is returned if AE_OK. + * AE_LIMIT: Instance is beyond valid limit + * AE_NOT_FOUND: A table with the signature was not found + * + * DESCRIPTION: Get an OS customized table. + * + *****************************************************************************/ + +static acpi_status +osl_get_customized_table(char *pathname, + char *signature, + u32 instance, + struct acpi_table_header **table, + acpi_physical_address * address) +{ + void *table_dir; + u32 current_instance = 0; + char temp_name[ACPI_NAME_SIZE]; + char table_filename[PATH_MAX]; + char *filename; + acpi_status status; + + /* Open the directory for customized tables */ + + table_dir = acpi_os_open_directory(pathname, "*", REQUEST_FILE_ONLY); + if (!table_dir) { + return (osl_get_last_status(AE_NOT_FOUND)); + } + + /* Attempt to find the table in the directory */ + + while ((filename = acpi_os_get_next_filename(table_dir))) { + + /* Ignore meaningless files */ + + if (!ACPI_COMPARE_NAME(filename, signature)) { + continue; + } + + /* Extract table name and instance number */ + + status = + osl_table_name_from_file(filename, temp_name, + ¤t_instance); + + /* Ignore meaningless files */ + + if (ACPI_FAILURE(status) || current_instance != instance) { + continue; + } + + /* Create the table pathname */ + + if (instance != 0) { + sprintf(table_filename, "%s/%4.4s%d", pathname, + temp_name, instance); + } else { + sprintf(table_filename, "%s/%4.4s", pathname, + temp_name); + } + break; + } + + acpi_os_close_directory(table_dir); + + if (!filename) { + return (AE_LIMIT); + } + + /* There is no physical address saved for customized tables, use zero */ + + *address = 0; + status = osl_read_table_from_file(table_filename, 0, NULL, table); + + return (status); +} diff --git a/tools/power/acpi/os_specific/service_layers/osunixdir.c b/tools/power/acpi/os_specific/service_layers/osunixdir.c new file mode 100644 index 000000000000..733f9e490fc4 --- /dev/null +++ b/tools/power/acpi/os_specific/service_layers/osunixdir.c @@ -0,0 +1,204 @@ +/****************************************************************************** + * + * Module Name: osunixdir - Unix directory access interfaces + * + *****************************************************************************/ + +/* + * 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 + +#include +#include +#include +#include +#include +#include +#include + +/* + * Allocated structure returned from os_open_directory + */ +typedef struct external_find_info { + char *dir_pathname; + DIR *dir_ptr; + char temp_buffer[256]; + char *wildcard_spec; + char requested_file_type; + +} external_find_info; + +/******************************************************************************* + * + * FUNCTION: acpi_os_open_directory + * + * PARAMETERS: dir_pathname - Full pathname to the directory + * wildcard_spec - string of the form "*.c", etc. + * + * RETURN: A directory "handle" to be used in subsequent search operations. + * NULL returned on failure. + * + * DESCRIPTION: Open a directory in preparation for a wildcard search + * + ******************************************************************************/ + +void *acpi_os_open_directory(char *dir_pathname, + char *wildcard_spec, char requested_file_type) +{ + struct external_find_info *external_info; + DIR *dir; + + /* Allocate the info struct that will be returned to the caller */ + + external_info = calloc(1, sizeof(struct external_find_info)); + if (!external_info) { + return (NULL); + } + + /* Get the directory stream */ + + dir = opendir(dir_pathname); + if (!dir) { + fprintf(stderr, "Cannot open directory - %s\n", dir_pathname); + free(external_info); + return (NULL); + } + + /* Save the info in the return structure */ + + external_info->wildcard_spec = wildcard_spec; + external_info->requested_file_type = requested_file_type; + external_info->dir_pathname = dir_pathname; + external_info->dir_ptr = dir; + return (external_info); +} + +/******************************************************************************* + * + * FUNCTION: acpi_os_get_next_filename + * + * PARAMETERS: dir_handle - Created via acpi_os_open_directory + * + * RETURN: Next filename matched. NULL if no more matches. + * + * DESCRIPTION: Get the next file in the directory that matches the wildcard + * specification. + * + ******************************************************************************/ + +char *acpi_os_get_next_filename(void *dir_handle) +{ + struct external_find_info *external_info = dir_handle; + struct dirent *dir_entry; + char *temp_str; + int str_len; + struct stat temp_stat; + int err; + + while ((dir_entry = readdir(external_info->dir_ptr))) { + if (!fnmatch + (external_info->wildcard_spec, dir_entry->d_name, 0)) { + if (dir_entry->d_name[0] == '.') { + continue; + } + + str_len = strlen(dir_entry->d_name) + + strlen(external_info->dir_pathname) + 2; + + temp_str = calloc(str_len, 1); + if (!temp_str) { + fprintf(stderr, + "Could not allocate buffer for temporary string\n"); + return (NULL); + } + + strcpy(temp_str, external_info->dir_pathname); + strcat(temp_str, "/"); + strcat(temp_str, dir_entry->d_name); + + err = stat(temp_str, &temp_stat); + if (err == -1) { + fprintf(stderr, + "Cannot stat file (should not happen) - %s\n", + temp_str); + free(temp_str); + return (NULL); + } + + free(temp_str); + + if ((S_ISDIR(temp_stat.st_mode) + && (external_info->requested_file_type == + REQUEST_DIR_ONLY)) + || ((!S_ISDIR(temp_stat.st_mode) + && external_info->requested_file_type == + REQUEST_FILE_ONLY))) { + + /* copy to a temp buffer because dir_entry struct is on the stack */ + + strcpy(external_info->temp_buffer, + dir_entry->d_name); + return (external_info->temp_buffer); + } + } + } + + return (NULL); +} + +/******************************************************************************* + * + * FUNCTION: acpi_os_close_directory + * + * PARAMETERS: dir_handle - Created via acpi_os_open_directory + * + * RETURN: None. + * + * DESCRIPTION: Close the open directory and cleanup. + * + ******************************************************************************/ + +void acpi_os_close_directory(void *dir_handle) +{ + struct external_find_info *external_info = dir_handle; + + /* Close the directory and free allocations */ + + closedir(external_info->dir_ptr); + free(dir_handle); +} diff --git a/tools/power/acpi/os_specific/service_layers/osunixmap.c b/tools/power/acpi/os_specific/service_layers/osunixmap.c new file mode 100644 index 000000000000..99b47b6194a3 --- /dev/null +++ b/tools/power/acpi/os_specific/service_layers/osunixmap.c @@ -0,0 +1,151 @@ +/****************************************************************************** + * + * Module Name: osunixmap - Unix OSL for file mappings + * + *****************************************************************************/ + +/* + * 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 "acpidump.h" +#include +#include +#ifdef _free_BSD +#include +#endif + +#define _COMPONENT ACPI_OS_SERVICES +ACPI_MODULE_NAME("osunixmap") + +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifdef _free_BSD +#define MMAP_FLAGS MAP_SHARED +#else +#define MMAP_FLAGS MAP_PRIVATE +#endif +#define SYSTEM_MEMORY "/dev/mem" +/******************************************************************************* + * + * FUNCTION: acpi_os_get_page_size + * + * PARAMETERS: None + * + * RETURN: Page size of the platform. + * + * DESCRIPTION: Obtain page size of the platform. + * + ******************************************************************************/ +static acpi_size acpi_os_get_page_size(void) +{ + +#ifdef PAGE_SIZE + return PAGE_SIZE; +#else + return sysconf(_SC_PAGESIZE); +#endif +} + +/****************************************************************************** + * + * FUNCTION: acpi_os_map_memory + * + * PARAMETERS: where - Physical address of memory to be mapped + * length - How much memory to map + * + * RETURN: Pointer to mapped memory. Null on error. + * + * DESCRIPTION: Map physical memory into local address space. + * + *****************************************************************************/ + +void *acpi_os_map_memory(acpi_physical_address where, acpi_size length) +{ + u8 *mapped_memory; + acpi_physical_address offset; + acpi_size page_size; + int fd; + + fd = open(SYSTEM_MEMORY, O_RDONLY | O_BINARY); + if (fd < 0) { + fprintf(stderr, "Cannot open %s\n", SYSTEM_MEMORY); + return (NULL); + } + + /* Align the offset to use mmap */ + + page_size = acpi_os_get_page_size(); + offset = where % page_size; + + /* Map the table header to get the length of the full table */ + + mapped_memory = mmap(NULL, (length + offset), PROT_READ, MMAP_FLAGS, + fd, (where - offset)); + if (mapped_memory == MAP_FAILED) { + fprintf(stderr, "Cannot map %s\n", SYSTEM_MEMORY); + close(fd); + return (NULL); + } + + close(fd); + return (ACPI_CAST8(mapped_memory + offset)); +} + +/****************************************************************************** + * + * FUNCTION: acpi_os_unmap_memory + * + * PARAMETERS: where - Logical address of memory to be unmapped + * length - How much memory to unmap + * + * RETURN: None. + * + * DESCRIPTION: Delete a previously created mapping. Where and Length must + * correspond to a previous mapping exactly. + * + *****************************************************************************/ + +void acpi_os_unmap_memory(void *where, acpi_size length) +{ + acpi_physical_address offset; + acpi_size page_size; + + page_size = acpi_os_get_page_size(); + offset = (acpi_physical_address) where % page_size; + munmap((u8 *)where - offset, (length + offset)); +} diff --git a/tools/power/acpi/tools/acpidump/acpidump.h b/tools/power/acpi/tools/acpidump/acpidump.h new file mode 100644 index 000000000000..3361b9e04d9c --- /dev/null +++ b/tools/power/acpi/tools/acpidump/acpidump.h @@ -0,0 +1,131 @@ +/****************************************************************************** + * + * Module Name: acpidump.h - Include file for acpi_dump utility + * + *****************************************************************************/ + +/* + * 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 +#include "accommon.h" +#include "actables.h" + +#include +#include +#include +#include + +/* + * Global variables. Defined in main.c only, externed in all other files + */ +#ifdef _DECLARE_GLOBALS +#define EXTERN +#define INIT_GLOBAL(a,b) a=b +#else +#define EXTERN extern +#define INIT_GLOBAL(a,b) a +#endif + +/* Globals */ + +EXTERN u8 INIT_GLOBAL(gbl_summary_mode, FALSE); +EXTERN u8 INIT_GLOBAL(gbl_verbose_mode, FALSE); +EXTERN u8 INIT_GLOBAL(gbl_binary_mode, FALSE); +EXTERN u8 INIT_GLOBAL(gbl_dump_customized_tables, FALSE); +EXTERN FILE INIT_GLOBAL(*gbl_output_file, NULL); +EXTERN char INIT_GLOBAL(*gbl_output_filename, NULL); +EXTERN u64 INIT_GLOBAL(gbl_rsdp_base, 0); + +/* Globals required for use with ACPICA modules */ + +#ifdef _DECLARE_GLOBALS +u8 acpi_gbl_enable_interpreter_slack = FALSE; +u8 acpi_gbl_integer_byte_width = 8; +u32 acpi_dbg_level = 0; +u32 acpi_dbg_layer = 0; +#endif + +/* Action table used to defer requested options */ + +struct ap_dump_action { + char *argument; + u32 to_be_done; +}; + +#define AP_MAX_ACTIONS 32 + +#define AP_DUMP_ALL_TABLES 0 +#define AP_DUMP_TABLE_BY_ADDRESS 1 +#define AP_DUMP_TABLE_BY_NAME 2 +#define AP_DUMP_TABLE_BY_FILE 3 + +#define AP_MAX_ACPI_FILES 256 /* Prevent infinite loops */ + +/* Minimum FADT sizes for various table addresses */ + +#define MIN_FADT_FOR_DSDT (ACPI_FADT_OFFSET (dsdt) + sizeof (u32)) +#define MIN_FADT_FOR_FACS (ACPI_FADT_OFFSET (facs) + sizeof (u32)) +#define MIN_FADT_FOR_XDSDT (ACPI_FADT_OFFSET (Xdsdt) + sizeof (u64)) +#define MIN_FADT_FOR_XFACS (ACPI_FADT_OFFSET (Xfacs) + sizeof (u64)) + +/* + * apdump - Table get/dump routines + */ +int ap_dump_table_from_file(char *pathname); + +int ap_dump_table_by_name(char *signature); + +int ap_dump_table_by_address(char *ascii_address); + +int ap_dump_all_tables(void); + +u8 ap_is_valid_header(struct acpi_table_header *table); + +u8 ap_is_valid_checksum(struct acpi_table_header *table); + +u32 ap_get_table_length(struct acpi_table_header *table); + +/* + * apfiles - File I/O utilities + */ +int ap_open_output_file(char *pathname); + +int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance); + +struct acpi_table_header *ap_get_table_from_file(char *pathname, + u32 *file_size); diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c new file mode 100644 index 000000000000..3cac12378366 --- /dev/null +++ b/tools/power/acpi/tools/acpidump/apdump.c @@ -0,0 +1,451 @@ +/****************************************************************************** + * + * Module Name: apdump - Dump routines for ACPI tables (acpidump) + * + *****************************************************************************/ + +/* + * 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 "acpidump.h" + +/* Local prototypes */ + +static int +ap_dump_table_buffer(struct acpi_table_header *table, + u32 instance, acpi_physical_address address); + +/****************************************************************************** + * + * FUNCTION: ap_is_valid_header + * + * PARAMETERS: table - Pointer to table to be validated + * + * RETURN: TRUE if the header appears to be valid. FALSE otherwise + * + * DESCRIPTION: Check for a valid ACPI table header + * + ******************************************************************************/ + +u8 ap_is_valid_header(struct acpi_table_header *table) +{ + + if (!ACPI_VALIDATE_RSDP_SIG(table->signature)) { + + /* Make sure signature is all ASCII and a valid ACPI name */ + + if (!acpi_ut_valid_acpi_name(table->signature)) { + fprintf(stderr, + "Table signature (0x%8.8X) is invalid\n", + *(u32 *)table->signature); + return (FALSE); + } + + /* Check for minimum table length */ + + if (table->length < sizeof(struct acpi_table_header)) { + fprintf(stderr, "Table length (0x%8.8X) is invalid\n", + table->length); + return (FALSE); + } + } + + return (TRUE); +} + +/****************************************************************************** + * + * FUNCTION: ap_is_valid_checksum + * + * PARAMETERS: table - Pointer to table to be validated + * + * RETURN: TRUE if the checksum appears to be valid. FALSE otherwise. + * + * DESCRIPTION: Check for a valid ACPI table checksum. + * + ******************************************************************************/ + +u8 ap_is_valid_checksum(struct acpi_table_header *table) +{ + acpi_status status; + struct acpi_table_rsdp *rsdp; + + if (ACPI_VALIDATE_RSDP_SIG(table->signature)) { + /* + * Checksum for RSDP. + * Note: Other checksums are computed during the table dump. + */ + rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table); + status = acpi_tb_validate_rsdp(rsdp); + } else { + status = acpi_tb_verify_checksum(table, table->length); + } + + if (ACPI_FAILURE(status)) { + fprintf(stderr, "%4.4s: Warning: wrong checksum in table\n", + table->signature); + } + + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: ap_get_table_length + * + * PARAMETERS: table - Pointer to the table + * + * RETURN: Table length + * + * DESCRIPTION: Obtain table length according to table signature. + * + ******************************************************************************/ + +u32 ap_get_table_length(struct acpi_table_header *table) +{ + struct acpi_table_rsdp *rsdp; + + /* Check if table is valid */ + + if (!ap_is_valid_header(table)) { + return (0); + } + + if (ACPI_VALIDATE_RSDP_SIG(table->signature)) { + rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table); + return (rsdp->length); + } + + /* Normal ACPI table */ + + return (table->length); +} + +/****************************************************************************** + * + * FUNCTION: ap_dump_table_buffer + * + * PARAMETERS: table - ACPI table to be dumped + * instance - ACPI table instance no. to be dumped + * address - Physical address of the table + * + * RETURN: None + * + * DESCRIPTION: Dump an ACPI table in standard ASCII hex format, with a + * header that is compatible with the acpi_xtract utility. + * + ******************************************************************************/ + +static int +ap_dump_table_buffer(struct acpi_table_header *table, + u32 instance, acpi_physical_address address) +{ + u32 table_length; + + table_length = ap_get_table_length(table); + + /* Print only the header if requested */ + + if (gbl_summary_mode) { + acpi_tb_print_table_header(address, table); + return (0); + } + + /* Dump to binary file if requested */ + + if (gbl_binary_mode) { + return (ap_write_to_binary_file(table, instance)); + } + + /* + * Dump the table with header for use with acpixtract utility. + * Note: simplest to just always emit a 64-bit address. acpi_xtract + * utility can handle this. + */ + printf("%4.4s @ 0x%8.8X%8.8X\n", table->signature, + ACPI_FORMAT_UINT64(address)); + + acpi_ut_dump_buffer(ACPI_CAST_PTR(u8, table), table_length, + DB_BYTE_DISPLAY, 0); + printf("\n"); + return (0); +} + +/****************************************************************************** + * + * FUNCTION: ap_dump_all_tables + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Get all tables from the RSDT/XSDT (or at least all of the + * tables that we can possibly get). + * + ******************************************************************************/ + +int ap_dump_all_tables(void) +{ + struct acpi_table_header *table; + u32 instance = 0; + acpi_physical_address address; + acpi_status status; + int table_status; + u32 i; + + /* Get and dump all available ACPI tables */ + + for (i = 0; i < AP_MAX_ACPI_FILES; i++) { + status = + acpi_os_get_table_by_index(i, &table, &instance, &address); + if (ACPI_FAILURE(status)) { + + /* AE_LIMIT means that no more tables are available */ + + if (status == AE_LIMIT) { + return (0); + } else if (i == 0) { + fprintf(stderr, + "Could not get ACPI tables, %s\n", + acpi_format_exception(status)); + return (-1); + } else { + fprintf(stderr, + "Could not get ACPI table at index %u, %s\n", + i, acpi_format_exception(status)); + continue; + } + } + + table_status = ap_dump_table_buffer(table, instance, address); + free(table); + + if (table_status) { + break; + } + } + + /* Something seriously bad happened if the loop terminates here */ + + return (-1); +} + +/****************************************************************************** + * + * FUNCTION: ap_dump_table_by_address + * + * PARAMETERS: ascii_address - Address for requested ACPI table + * + * RETURN: Status + * + * DESCRIPTION: Get an ACPI table via a physical address and dump it. + * + ******************************************************************************/ + +int ap_dump_table_by_address(char *ascii_address) +{ + acpi_physical_address address; + struct acpi_table_header *table; + acpi_status status; + int table_status; + u64 long_address; + + /* Convert argument to an integer physical address */ + + status = acpi_ut_strtoul64(ascii_address, 0, &long_address); + if (ACPI_FAILURE(status)) { + fprintf(stderr, "%s: Could not convert to a physical address\n", + ascii_address); + return (-1); + } + + address = (acpi_physical_address) long_address; + status = acpi_os_get_table_by_address(address, &table); + if (ACPI_FAILURE(status)) { + fprintf(stderr, "Could not get table at 0x%8.8X%8.8X, %s\n", + ACPI_FORMAT_UINT64(address), + acpi_format_exception(status)); + return (-1); + } + + table_status = ap_dump_table_buffer(table, 0, address); + free(table); + return (table_status); +} + +/****************************************************************************** + * + * FUNCTION: ap_dump_table_by_name + * + * PARAMETERS: signature - Requested ACPI table signature + * + * RETURN: Status + * + * DESCRIPTION: Get an ACPI table via a signature and dump it. Handles + * multiple tables with the same signature (SSDTs). + * + ******************************************************************************/ + +int ap_dump_table_by_name(char *signature) +{ + char local_signature[ACPI_NAME_SIZE + 1]; + u32 instance; + struct acpi_table_header *table; + acpi_physical_address address; + acpi_status status; + int table_status; + + if (strlen(signature) != ACPI_NAME_SIZE) { + fprintf(stderr, + "Invalid table signature [%s]: must be exactly 4 characters\n", + signature); + return (-1); + } + + /* Table signatures are expected to be uppercase */ + + strcpy(local_signature, signature); + acpi_ut_strupr(local_signature); + + /* To be friendly, handle tables whose signatures do not match the name */ + + if (ACPI_COMPARE_NAME(local_signature, "FADT")) { + strcpy(local_signature, ACPI_SIG_FADT); + } else if (ACPI_COMPARE_NAME(local_signature, "MADT")) { + strcpy(local_signature, ACPI_SIG_MADT); + } + + /* Dump all instances of this signature (to handle multiple SSDTs) */ + + for (instance = 0; instance < AP_MAX_ACPI_FILES; instance++) { + status = acpi_os_get_table_by_name(local_signature, instance, + &table, &address); + if (ACPI_FAILURE(status)) { + + /* AE_LIMIT means that no more tables are available */ + + if (status == AE_LIMIT) { + return (0); + } + + fprintf(stderr, + "Could not get ACPI table with signature [%s], %s\n", + local_signature, acpi_format_exception(status)); + return (-1); + } + + table_status = ap_dump_table_buffer(table, instance, address); + free(table); + + if (table_status) { + break; + } + } + + /* Something seriously bad happened if the loop terminates here */ + + return (-1); +} + +/****************************************************************************** + * + * FUNCTION: ap_dump_table_from_file + * + * PARAMETERS: pathname - File containing the binary ACPI table + * + * RETURN: Status + * + * DESCRIPTION: Dump an ACPI table from a binary file + * + ******************************************************************************/ + +int ap_dump_table_from_file(char *pathname) +{ + struct acpi_table_header *table; + u32 file_size = 0; + int table_status = -1; + + /* Get the entire ACPI table from the file */ + + table = ap_get_table_from_file(pathname, &file_size); + if (!table) { + return (-1); + } + + /* File must be at least as long as the table length */ + + if (table->length > file_size) { + fprintf(stderr, + "Table length (0x%X) is too large for input file (0x%X) %s\n", + table->length, file_size, pathname); + goto exit; + } + + if (gbl_verbose_mode) { + fprintf(stderr, + "Input file: %s contains table [%4.4s], 0x%X (%u) bytes\n", + pathname, table->signature, file_size, file_size); + } + + table_status = ap_dump_table_buffer(table, 0, 0); + +exit: + free(table); + return (table_status); +} + +/****************************************************************************** + * + * FUNCTION: acpi_os* print functions + * + * DESCRIPTION: Used for linkage with ACPICA modules + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE acpi_os_printf(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vfprintf(stdout, fmt, args); + va_end(args); +} + +void acpi_os_vprintf(const char *fmt, va_list args) +{ + vfprintf(stdout, fmt, args); +} diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c new file mode 100644 index 000000000000..4488accc010b --- /dev/null +++ b/tools/power/acpi/tools/acpidump/apfiles.c @@ -0,0 +1,228 @@ +/****************************************************************************** + * + * Module Name: apfiles - File-related functions for acpidump utility + * + *****************************************************************************/ + +/* + * 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 "acpidump.h" +#include "acapps.h" + +/****************************************************************************** + * + * FUNCTION: ap_open_output_file + * + * PARAMETERS: pathname - Output filename + * + * RETURN: Open file handle + * + * DESCRIPTION: Open a text output file for acpidump. Checks if file already + * exists. + * + ******************************************************************************/ + +int ap_open_output_file(char *pathname) +{ + struct stat stat_info; + FILE *file; + + /* If file exists, prompt for overwrite */ + + if (!stat(pathname, &stat_info)) { + fprintf(stderr, + "Target path already exists, overwrite? [y|n] "); + + if (getchar() != 'y') { + return (-1); + } + } + + /* Point stdout to the file */ + + file = freopen(pathname, "w", stdout); + if (!file) { + perror("Could not open output file"); + return (-1); + } + + /* Save the file and path */ + + gbl_output_file = file; + gbl_output_filename = pathname; + return (0); +} + +/****************************************************************************** + * + * FUNCTION: ap_write_to_binary_file + * + * PARAMETERS: table - ACPI table to be written + * instance - ACPI table instance no. to be written + * + * RETURN: Status + * + * DESCRIPTION: Write an ACPI table to a binary file. Builds the output + * filename from the table signature. + * + ******************************************************************************/ + +int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance) +{ + char filename[ACPI_NAME_SIZE + 16]; + char instance_str[16]; + FILE *file; + size_t actual; + u32 table_length; + + /* Obtain table length */ + + table_length = ap_get_table_length(table); + + /* Construct lower-case filename from the table local signature */ + + if (ACPI_VALIDATE_RSDP_SIG(table->signature)) { + ACPI_MOVE_NAME(filename, ACPI_RSDP_NAME); + } else { + ACPI_MOVE_NAME(filename, table->signature); + } + filename[0] = (char)ACPI_TOLOWER(filename[0]); + filename[1] = (char)ACPI_TOLOWER(filename[1]); + filename[2] = (char)ACPI_TOLOWER(filename[2]); + filename[3] = (char)ACPI_TOLOWER(filename[3]); + filename[ACPI_NAME_SIZE] = 0; + + /* Handle multiple SSDts - create different filenames for each */ + + if (instance > 0) { + sprintf(instance_str, "%u", instance); + strcat(filename, instance_str); + } + + strcat(filename, ACPI_TABLE_FILE_SUFFIX); + + if (gbl_verbose_mode) { + fprintf(stderr, + "Writing [%4.4s] to binary file: %s 0x%X (%u) bytes\n", + table->signature, filename, table->length, + table->length); + } + + /* Open the file and dump the entire table in binary mode */ + + file = fopen(filename, "wb"); + if (!file) { + perror("Could not open output file"); + return (-1); + } + + actual = fwrite(table, 1, table_length, file); + if (actual != table_length) { + perror("Error writing binary output file"); + fclose(file); + return (-1); + } + + fclose(file); + return (0); +} + +/****************************************************************************** + * + * FUNCTION: ap_get_table_from_file + * + * PARAMETERS: pathname - File containing the binary ACPI table + * out_file_size - Where the file size is returned + * + * RETURN: Buffer containing the ACPI table. NULL on error. + * + * DESCRIPTION: Open a file and read it entirely into a new buffer + * + ******************************************************************************/ + +struct acpi_table_header *ap_get_table_from_file(char *pathname, + u32 *out_file_size) +{ + struct acpi_table_header *buffer = NULL; + FILE *file; + u32 file_size; + size_t actual; + + /* Must use binary mode */ + + file = fopen(pathname, "rb"); + if (!file) { + perror("Could not open input file"); + return (NULL); + } + + /* Need file size to allocate a buffer */ + + file_size = cm_get_file_size(file); + if (file_size == ACPI_UINT32_MAX) { + fprintf(stderr, + "Could not get input file size: %s\n", pathname); + goto cleanup; + } + + /* Allocate a buffer for the entire file */ + + buffer = calloc(1, file_size); + if (!buffer) { + fprintf(stderr, + "Could not allocate file buffer of size: %u\n", + file_size); + goto cleanup; + } + + /* Read the entire file */ + + actual = fread(buffer, 1, file_size, file); + if (actual != file_size) { + fprintf(stderr, "Could not read input file: %s\n", pathname); + free(buffer); + buffer = NULL; + goto cleanup; + } + + *out_file_size = file_size; + +cleanup: + fclose(file); + return (buffer); +} diff --git a/tools/power/acpi/tools/acpidump/apmain.c b/tools/power/acpi/tools/acpidump/apmain.c new file mode 100644 index 000000000000..70d71ec687a5 --- /dev/null +++ b/tools/power/acpi/tools/acpidump/apmain.c @@ -0,0 +1,340 @@ +/****************************************************************************** + * + * Module Name: apmain - Main module for the acpidump utility + * + *****************************************************************************/ + +/* + * 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. + */ + +#define _DECLARE_GLOBALS +#include "acpidump.h" +#include "acapps.h" + +/* + * acpidump - A portable utility for obtaining system ACPI tables and dumping + * them in an ASCII hex format suitable for binary extraction via acpixtract. + * + * Obtaining the system ACPI tables is an OS-specific operation. + * + * This utility can be ported to any host operating system by providing a + * module containing system-specific versions of these interfaces: + * + * acpi_os_get_table_by_address + * acpi_os_get_table_by_index + * acpi_os_get_table_by_name + * + * See the ACPICA Reference Guide for the exact definitions of these + * interfaces. Also, see these ACPICA source code modules for example + * implementations: + * + * source/os_specific/service_layers/oswintbl.c + * source/os_specific/service_layers/oslinuxtbl.c + */ + +/* Local prototypes */ + +static void ap_display_usage(void); + +static int ap_do_options(int argc, char **argv); + +static void ap_insert_action(char *argument, u32 to_be_done); + +/* Table for deferred actions from command line options */ + +struct ap_dump_action action_table[AP_MAX_ACTIONS]; +u32 current_action = 0; + +#define AP_UTILITY_NAME "ACPI Binary Table Dump Utility" +#define AP_SUPPORTED_OPTIONS "?a:bcf:hn:o:r:svz" + +/****************************************************************************** + * + * FUNCTION: ap_display_usage + * + * DESCRIPTION: Usage message for the acpi_dump utility + * + ******************************************************************************/ + +static void ap_display_usage(void) +{ + + ACPI_USAGE_HEADER("acpidump [options]"); + + ACPI_OPTION("-b", "Dump tables to binary files"); + ACPI_OPTION("-c", "Dump customized tables"); + ACPI_OPTION("-h -?", "This help message"); + ACPI_OPTION("-o ", "Redirect output to file"); + ACPI_OPTION("-r
", "Dump tables from specified RSDP"); + ACPI_OPTION("-s", "Print table summaries only"); + ACPI_OPTION("-v", "Display version information"); + ACPI_OPTION("-z", "Verbose mode"); + + printf("\nTable Options:\n"); + + ACPI_OPTION("-a
", "Get table via a physical address"); + ACPI_OPTION("-f ", "Get table via a binary file"); + ACPI_OPTION("-n ", "Get table via a name/signature"); + + printf("\n" + "Invocation without parameters dumps all available tables\n" + "Multiple mixed instances of -a, -f, and -n are supported\n\n"); +} + +/****************************************************************************** + * + * FUNCTION: ap_insert_action + * + * PARAMETERS: argument - Pointer to the argument for this action + * to_be_done - What to do to process this action + * + * RETURN: None. Exits program if action table becomes full. + * + * DESCRIPTION: Add an action item to the action table + * + ******************************************************************************/ + +static void ap_insert_action(char *argument, u32 to_be_done) +{ + + /* Insert action and check for table overflow */ + + action_table[current_action].argument = argument; + action_table[current_action].to_be_done = to_be_done; + + current_action++; + if (current_action > AP_MAX_ACTIONS) { + fprintf(stderr, "Too many table options (max %u)\n", + AP_MAX_ACTIONS); + exit(-1); + } +} + +/****************************************************************************** + * + * FUNCTION: ap_do_options + * + * PARAMETERS: argc/argv - Standard argc/argv + * + * RETURN: Status + * + * DESCRIPTION: Command line option processing. The main actions for getting + * and dumping tables are deferred via the action table. + * + *****************************************************************************/ + +static int ap_do_options(int argc, char **argv) +{ + int j; + acpi_status status; + + /* Command line options */ + + while ((j = acpi_getopt(argc, argv, AP_SUPPORTED_OPTIONS)) != EOF) + switch (j) { + /* + * Global options + */ + case 'b': /* Dump all input tables to binary files */ + + gbl_binary_mode = TRUE; + continue; + + case 'c': /* Dump customized tables */ + + gbl_dump_customized_tables = TRUE; + continue; + + case 'h': + case '?': + + ap_display_usage(); + exit(0); + + case 'o': /* Redirect output to a single file */ + + if (ap_open_output_file(acpi_gbl_optarg)) { + exit(-1); + } + continue; + + case 'r': /* Dump tables from specified RSDP */ + + status = + acpi_ut_strtoul64(acpi_gbl_optarg, 0, + &gbl_rsdp_base); + if (ACPI_FAILURE(status)) { + fprintf(stderr, + "%s: Could not convert to a physical address\n", + acpi_gbl_optarg); + exit(-1); + } + continue; + + case 's': /* Print table summaries only */ + + gbl_summary_mode = TRUE; + continue; + + case 'v': /* Revision/version */ + + printf(ACPI_COMMON_SIGNON(AP_UTILITY_NAME)); + exit(0); + + case 'z': /* Verbose mode */ + + gbl_verbose_mode = TRUE; + fprintf(stderr, ACPI_COMMON_SIGNON(AP_UTILITY_NAME)); + continue; + + /* + * Table options + */ + case 'a': /* Get table by physical address */ + + ap_insert_action(acpi_gbl_optarg, + AP_DUMP_TABLE_BY_ADDRESS); + break; + + case 'f': /* Get table from a file */ + + ap_insert_action(acpi_gbl_optarg, + AP_DUMP_TABLE_BY_FILE); + break; + + case 'n': /* Get table by input name (signature) */ + + ap_insert_action(acpi_gbl_optarg, + AP_DUMP_TABLE_BY_NAME); + break; + + default: + + ap_display_usage(); + exit(-1); + } + + /* If there are no actions, this means "get/dump all tables" */ + + if (current_action == 0) { + ap_insert_action(NULL, AP_DUMP_ALL_TABLES); + } + + return (0); +} + +/****************************************************************************** + * + * FUNCTION: main + * + * PARAMETERS: argc/argv - Standard argc/argv + * + * RETURN: Status + * + * DESCRIPTION: C main function for acpidump utility + * + ******************************************************************************/ + +int ACPI_SYSTEM_XFACE main(int argc, char *argv[]) +{ + int status = 0; + struct ap_dump_action *action; + u32 file_size; + u32 i; + + ACPI_DEBUG_INITIALIZE(); /* For debug version only */ + + /* Process command line options */ + + if (ap_do_options(argc, argv)) { + return (-1); + } + + /* Get/dump ACPI table(s) as requested */ + + for (i = 0; i < current_action; i++) { + action = &action_table[i]; + switch (action->to_be_done) { + case AP_DUMP_ALL_TABLES: + + status = ap_dump_all_tables(); + break; + + case AP_DUMP_TABLE_BY_ADDRESS: + + status = ap_dump_table_by_address(action->argument); + break; + + case AP_DUMP_TABLE_BY_NAME: + + status = ap_dump_table_by_name(action->argument); + break; + + case AP_DUMP_TABLE_BY_FILE: + + status = ap_dump_table_from_file(action->argument); + break; + + default: + + fprintf(stderr, + "Internal error, invalid action: 0x%X\n", + action->to_be_done); + return (-1); + } + + if (status) { + return (status); + } + } + + if (gbl_output_file) { + if (gbl_verbose_mode) { + + /* Summary for the output file */ + + file_size = cm_get_file_size(gbl_output_file); + fprintf(stderr, + "Output file %s contains 0x%X (%u) bytes\n\n", + gbl_output_filename, file_size, file_size); + } + + fclose(gbl_output_file); + } + + return (status); +} From e2b9035f7368b8141e8c9f1d0bcc012e20e16ac1 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:39:50 +0800 Subject: [PATCH 024/134] ACPICA: acpidump: Update new structures and add missing file. This patch is the generation of a commit that updates release automation with newly added structures and files that are referenced by the acpidump. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 2 +- drivers/acpi/acpica/acutils.h | 2 +- tools/power/acpi/common/cmfsize.c | 101 ++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 tools/power/acpi/common/cmfsize.c diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 0cac564ffe93..1f602907dfab 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -509,6 +509,6 @@ ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_debug_file, NULL); ****************************************************************************/ extern const struct ah_predefined_name asl_predefined_info[]; -extern const AH_DEVICE_ID asl_device_ids[]; +extern const struct ah_device_id asl_device_ids[]; #endif /* __ACGLOBAL_H__ */ diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 2cf8d2c7133b..1e256c5bda20 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -741,6 +741,6 @@ acpi_ut_method_error(const char *module_name, */ const struct ah_predefined_name *acpi_ah_match_predefined_name(char *nameseg); -const AH_DEVICE_ID *acpi_ah_match_hardware_id(char *hid); +const struct ah_device_id *acpi_ah_match_hardware_id(char *hid); #endif /* _ACUTILS_H */ diff --git a/tools/power/acpi/common/cmfsize.c b/tools/power/acpi/common/cmfsize.c new file mode 100644 index 000000000000..5140e5edae1f --- /dev/null +++ b/tools/power/acpi/common/cmfsize.c @@ -0,0 +1,101 @@ +/****************************************************************************** + * + * Module Name: cfsize - Common get file size function + * + *****************************************************************************/ + +/* + * 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 +#include "accommon.h" +#include "acapps.h" +#include + +#define _COMPONENT ACPI_TOOLS +ACPI_MODULE_NAME("cmfsize") + +/******************************************************************************* + * + * FUNCTION: cm_get_file_size + * + * PARAMETERS: file - Open file descriptor + * + * RETURN: File Size. On error, -1 (ACPI_UINT32_MAX) + * + * DESCRIPTION: Get the size of a file. Uses seek-to-EOF. File must be open. + * Does not disturb the current file pointer. Uses perror for + * error messages. + * + ******************************************************************************/ +u32 cm_get_file_size(FILE * file) +{ + long file_size; + long current_offset; + + /* Save the current file pointer, seek to EOF to obtain file size */ + + current_offset = ftell(file); + if (current_offset < 0) { + goto offset_error; + } + + if (fseek(file, 0, SEEK_END)) { + goto seek_error; + } + + file_size = ftell(file); + if (file_size < 0) { + goto offset_error; + } + + /* Restore original file pointer */ + + if (fseek(file, current_offset, SEEK_SET)) { + goto seek_error; + } + + return ((u32)file_size); + +offset_error: + perror("Could not get file offset"); + return (ACPI_UINT32_MAX); + +seek_error: + perror("Could not seek file"); + return (ACPI_UINT32_MAX); +} From edbe47c18659588726154153e7596a50843b5e55 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:39:56 +0800 Subject: [PATCH 025/134] ACPICA: acpidump: Update Makefile to build acpidump from ACPICA. This patch updates tools Makefile to use new acpidump. ACPICA's acpidump relies on various ACPICA components/common/os_specific source code. They are located in various kernel folders, being searched and compiled using vpath technique in Makefile. These files include: 1. drivers/acpi/acpica/acapps.h 2. tools/power/acpi/common/getopt.c 3. tools/power/acpi/common/cmfsize.c 4. tools/power/acpi/os_specific/service_layers/oslinuxtbl.c 5. tools/power/acpi/os_specific/service_layers/osunixdir.c 6. tools/power/acpi/os_specific/service_layers/osunixmap.c This patch has been tested on DELL Inspiron Mini, acpidump output can be successfully generated by typing the following commands: # cd tools/power/acpi # make DEBUG=false # sudo make install DESTDIR=/opt # sudo make uninstall DESTDIR=/opt # make clean Or # cd tools # make acpi # sudo make acpi_install # sudo make acpi_uninstall # make acpi_clean A kernel build test is also performed on DELL Inspiron Mini to verify that the changes done to actypes.h and aclinux.h won't affect the kernel build process. Signed-off-by: Lv Zheng [rjw: Subject] Signed-off-by: Rafael J. Wysocki --- tools/power/acpi/Makefile | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile index d9186a2fdf06..98625fa2baf1 100644 --- a/tools/power/acpi/Makefile +++ b/tools/power/acpi/Makefile @@ -68,7 +68,8 @@ WARNINGS += $(call cc-supports,-Wstrict-prototypes) WARNINGS += $(call cc-supports,-Wdeclaration-after-statement) KERNEL_INCLUDE := ../../../include -CFLAGS += -D_LINUX -DDEFINE_ALTERNATE_TYPES -I$(KERNEL_INCLUDE) +ACPICA_INCLUDE := ../../../drivers/acpi/acpica +CFLAGS += -D_LINUX -I$(KERNEL_INCLUDE) -I$(ACPICA_INCLUDE) CFLAGS += $(WARNINGS) ifeq ($(strip $(V)),false) @@ -101,10 +102,29 @@ endif # --- ACPIDUMP BEGIN --- vpath %.c \ - tools/acpidump + ../../../drivers/acpi/acpica\ + tools/acpidump\ + common\ + os_specific/service_layers + +CFLAGS += -DACPI_DUMP_APP -Itools/acpidump DUMP_OBJS = \ - acpidump.o + apdump.o\ + apfiles.o\ + apmain.o\ + osunixdir.o\ + osunixmap.o\ + tbprint.o\ + tbxfroot.o\ + utbuffer.o\ + utexcep.o\ + utmath.o\ + utstring.o\ + utxferror.o\ + oslinuxtbl.o\ + cmfsize.o\ + getopt.o DUMP_OBJS := $(addprefix $(OUTPUT)tools/acpidump/,$(DUMP_OBJS)) From bf5afef9922624d0bb43375dabca639652e3aeec Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:40:03 +0800 Subject: [PATCH 026/134] ACPICA: acpidump: Remove old acpidump source. This patch removes old acpidump source. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- tools/power/acpi/tools/acpidump/acpidump.c | 559 --------------------- 1 file changed, 559 deletions(-) delete mode 100644 tools/power/acpi/tools/acpidump/acpidump.c diff --git a/tools/power/acpi/tools/acpidump/acpidump.c b/tools/power/acpi/tools/acpidump/acpidump.c deleted file mode 100644 index a84553a0e0df..000000000000 --- a/tools/power/acpi/tools/acpidump/acpidump.c +++ /dev/null @@ -1,559 +0,0 @@ -/* - * (c) Alexey Starikovskiy, Intel, 2005-2006. - * 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. - */ - -#ifdef DEFINE_ALTERNATE_TYPES -/* hack to enable building old application with new headers -lenb */ -#define acpi_fadt_descriptor acpi_table_fadt -#define acpi_rsdp_descriptor acpi_table_rsdp -#define DSDT_SIG ACPI_SIG_DSDT -#define FACS_SIG ACPI_SIG_FACS -#define FADT_SIG ACPI_SIG_FADT -#define xfirmware_ctrl Xfacs -#define firmware_ctrl facs - -typedef int s32; -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; -typedef long long s64; -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -static inline u8 checksum(u8 * buffer, u32 length) -{ - u8 sum = 0, *i = buffer; - buffer += length; - for (; i < buffer; sum += *(i++)); - return sum; -} - -static unsigned long psz, addr, length; -static int print, connect, skip; -static u8 select_sig[4]; - -static unsigned long read_efi_systab( void ) -{ - char buffer[80]; - unsigned long addr; - FILE *f = fopen("/sys/firmware/efi/systab", "r"); - if (f) { - while (fgets(buffer, 80, f)) { - if (sscanf(buffer, "ACPI20=0x%lx", &addr) == 1) - return addr; - } - fclose(f); - } - return 0; -} - -static u8 *acpi_map_memory(unsigned long where, unsigned length) -{ - unsigned long offset; - u8 *there; - int fd = open("/dev/mem", O_RDONLY); - if (fd < 0) { - fprintf(stderr, "acpi_os_map_memory: cannot open /dev/mem\n"); - exit(1); - } - offset = where % psz; - there = mmap(NULL, length + offset, PROT_READ, MAP_PRIVATE, - fd, where - offset); - close(fd); - if (there == MAP_FAILED) return 0; - return (there + offset); -} - -static void acpi_unmap_memory(u8 * there, unsigned length) -{ - unsigned long offset = (unsigned long)there % psz; - munmap(there - offset, length + offset); -} - -static struct acpi_table_header *acpi_map_table(unsigned long where, char *sig) -{ - unsigned size; - struct acpi_table_header *tbl = (struct acpi_table_header *) - acpi_map_memory(where, sizeof(struct acpi_table_header)); - if (!tbl || (sig && memcmp(sig, tbl->signature, 4))) return 0; - size = tbl->length; - acpi_unmap_memory((u8 *) tbl, sizeof(struct acpi_table_header)); - return (struct acpi_table_header *)acpi_map_memory(where, size); -} - -static void acpi_unmap_table(struct acpi_table_header *tbl) -{ - acpi_unmap_memory((u8 *)tbl, tbl->length); -} - -static struct acpi_rsdp_descriptor *acpi_scan_for_rsdp(u8 *begin, u32 length) -{ - struct acpi_rsdp_descriptor *rsdp; - u8 *i, *end = begin + length; - /* Search from given start address for the requested length */ - for (i = begin; i < end; i += ACPI_RSDP_SCAN_STEP) { - /* The signature and checksum must both be correct */ - if (memcmp((char *)i, "RSD PTR ", 8)) continue; - rsdp = (struct acpi_rsdp_descriptor *)i; - /* Signature matches, check the appropriate checksum */ - if (!checksum((u8 *) rsdp, (rsdp->revision < 2) ? - ACPI_RSDP_CHECKSUM_LENGTH : - ACPI_RSDP_XCHECKSUM_LENGTH)) - /* Checksum valid, we have found a valid RSDP */ - return rsdp; - } - /* Searched entire block, no RSDP was found */ - return 0; -} - -/* - * Output data - */ -static void acpi_show_data(int fd, u8 * data, int size) -{ - char buffer[256]; - int len; - int i, remain = size; - while (remain > 0) { - len = snprintf(buffer, 256, " %04x:", size - remain); - for (i = 0; i < 16 && i < remain; i++) { - len += - snprintf(&buffer[len], 256 - len, " %02x", data[i]); - } - for (; i < 16; i++) { - len += snprintf(&buffer[len], 256 - len, " "); - } - len += snprintf(&buffer[len], 256 - len, " "); - for (i = 0; i < 16 && i < remain; i++) { - buffer[len++] = (isprint(data[i])) ? data[i] : '.'; - } - buffer[len++] = '\n'; - write(fd, buffer, len); - data += 16; - remain -= 16; - } -} - -/* - * Output ACPI table - */ -static void acpi_show_table(int fd, struct acpi_table_header *table, unsigned long addr) -{ - char buff[80]; - int len = snprintf(buff, 80, "%.4s @ %p\n", table->signature, (void *)addr); - write(fd, buff, len); - acpi_show_data(fd, (u8 *) table, table->length); - buff[0] = '\n'; - write(fd, buff, 1); -} - -static void write_table(int fd, struct acpi_table_header *tbl, unsigned long addr) -{ - static int select_done = 0; - if (!select_sig[0]) { - if (print) { - acpi_show_table(fd, tbl, addr); - } else { - write(fd, tbl, tbl->length); - } - } else if (!select_done && !memcmp(select_sig, tbl->signature, 4)) { - if (skip > 0) { - --skip; - return; - } - if (print) { - acpi_show_table(fd, tbl, addr); - } else { - write(fd, tbl, tbl->length); - } - select_done = 1; - } -} - -static void acpi_dump_FADT(int fd, struct acpi_table_header *tbl, unsigned long xaddr) { - struct acpi_fadt_descriptor x; - unsigned long addr; - size_t len = sizeof(struct acpi_fadt_descriptor); - if (len > tbl->length) len = tbl->length; - memcpy(&x, tbl, len); - x.header.length = len; - if (checksum((u8 *)tbl, len)) { - fprintf(stderr, "Wrong checksum for FADT!\n"); - } - if (x.header.length >= 148 && x.Xdsdt) { - addr = (unsigned long)x.Xdsdt; - if (connect) { - x.Xdsdt = lseek(fd, 0, SEEK_CUR); - } - } else if (x.header.length >= 44 && x.dsdt) { - addr = (unsigned long)x.dsdt; - if (connect) { - x.dsdt = lseek(fd, 0, SEEK_CUR); - } - } else { - fprintf(stderr, "No DSDT in FADT!\n"); - goto no_dsdt; - } - tbl = acpi_map_table(addr, DSDT_SIG); - if (!tbl) goto no_dsdt; - if (checksum((u8 *)tbl, tbl->length)) - fprintf(stderr, "Wrong checksum for DSDT!\n"); - write_table(fd, tbl, addr); - acpi_unmap_table(tbl); -no_dsdt: - if (x.header.length >= 140 && x.xfirmware_ctrl) { - addr = (unsigned long)x.xfirmware_ctrl; - if (connect) { - x.xfirmware_ctrl = lseek(fd, 0, SEEK_CUR); - } - } else if (x.header.length >= 40 && x.firmware_ctrl) { - addr = (unsigned long)x.firmware_ctrl; - if (connect) { - x.firmware_ctrl = lseek(fd, 0, SEEK_CUR); - } - } else { - fprintf(stderr, "No FACS in FADT!\n"); - goto no_facs; - } - tbl = acpi_map_table(addr, FACS_SIG); - if (!tbl) goto no_facs; - /* do not checksum FACS */ - write_table(fd, tbl, addr); - acpi_unmap_table(tbl); -no_facs: - write_table(fd, (struct acpi_table_header *)&x, xaddr); -} - -static int acpi_dump_SDT(int fd, struct acpi_rsdp_descriptor *rsdp) -{ - struct acpi_table_header *sdt, *tbl = 0; - int xsdt = 1, i, num; - char *offset; - unsigned long addr; - if (rsdp->revision > 1 && rsdp->xsdt_physical_address) { - tbl = acpi_map_table(rsdp->xsdt_physical_address, "XSDT"); - } - if (!tbl && rsdp->rsdt_physical_address) { - xsdt = 0; - tbl = acpi_map_table(rsdp->rsdt_physical_address, "RSDT"); - } - if (!tbl) return 0; - sdt = malloc(tbl->length); - memcpy(sdt, tbl, tbl->length); - acpi_unmap_table(tbl); - if (checksum((u8 *)sdt, sdt->length)) - fprintf(stderr, "Wrong checksum for %s!\n", (xsdt)?"XSDT":"RSDT"); - num = (sdt->length - sizeof(struct acpi_table_header))/((xsdt)?sizeof(u64):sizeof(u32)); - offset = (char *)sdt + sizeof(struct acpi_table_header); - for (i = 0; i < num; ++i, offset += ((xsdt) ? sizeof(u64) : sizeof(u32))) { - addr = (xsdt) ? (unsigned long)(*(u64 *)offset): - (unsigned long)(*(u32 *)offset); - if (!addr) continue; - tbl = acpi_map_table(addr, 0); - if (!tbl) continue; - if (!memcmp(tbl->signature, FADT_SIG, 4)) { - acpi_dump_FADT(fd, tbl, addr); - } else { - if (checksum((u8 *)tbl, tbl->length)) - fprintf(stderr, "Wrong checksum for generic table!\n"); - write_table(fd, tbl, addr); - } - acpi_unmap_table(tbl); - if (connect) { - if (xsdt) - (*(u64*)offset) = lseek(fd, 0, SEEK_CUR); - else - (*(u32*)offset) = lseek(fd, 0, SEEK_CUR); - } - } - if (xsdt) { - addr = (unsigned long)rsdp->xsdt_physical_address; - if (connect) { - rsdp->xsdt_physical_address = lseek(fd, 0, SEEK_CUR); - } - } else { - addr = (unsigned long)rsdp->rsdt_physical_address; - if (connect) { - rsdp->rsdt_physical_address = lseek(fd, 0, SEEK_CUR); - } - } - write_table(fd, sdt, addr); - free (sdt); - return 1; -} - -#define DYNAMIC_SSDT "/sys/firmware/acpi/tables/dynamic" - -static void acpi_dump_dynamic_SSDT(int fd) -{ - struct stat file_stat; - char filename[256], *ptr; - DIR *tabledir; - struct dirent *entry; - FILE *fp; - int count, readcount, length; - struct acpi_table_header table_header, *ptable; - - if (stat(DYNAMIC_SSDT, &file_stat) == -1) { - /* The directory doesn't exist */ - return; - } - tabledir = opendir(DYNAMIC_SSDT); - if(!tabledir){ - /*can't open the directory */ - return; - } - - while ((entry = readdir(tabledir)) != 0){ - /* skip the file of . /.. */ - if (entry->d_name[0] == '.') - continue; - - sprintf(filename, "%s/%s", DYNAMIC_SSDT, entry->d_name); - fp = fopen(filename, "r"); - if (fp == NULL) { - fprintf(stderr, "Can't open the file of %s\n", - filename); - continue; - } - /* Read the Table header to parse the table length */ - count = fread(&table_header, 1, sizeof(struct acpi_table_header), fp); - if (count < sizeof(table_header)) { - /* the length is lessn than ACPI table header. skip it */ - fclose(fp); - continue; - } - length = table_header.length; - ptr = malloc(table_header.length); - fseek(fp, 0, SEEK_SET); - readcount = 0; - while(!feof(fp) && readcount < length) { - count = fread(ptr + readcount, 1, 256, fp); - readcount += count; - } - fclose(fp); - ptable = (struct acpi_table_header *) ptr; - if (checksum((u8 *) ptable, ptable->length)) - fprintf(stderr, "Wrong checksum " - "for dynamic SSDT table!\n"); - write_table(fd, ptable, 0); - free(ptr); - } - closedir(tabledir); - return; -} - -static void usage(const char *progname) -{ - puts("Usage:"); - printf("%s [--addr 0x1234][--table DSDT][--output filename]" - "[--binary][--length 0x456][--help]\n", progname); - puts("\t--addr 0x1234 or -a 0x1234 -- look for tables at this physical address"); - puts("\t--table DSDT or -t DSDT -- only dump table with DSDT signature"); - puts("\t--output filename or -o filename -- redirect output from stdin to filename"); - puts("\t--binary or -b -- dump data in binary form rather than in hex-dump format"); - puts("\t--length 0x456 or -l 0x456 -- works only with --addr, dump physical memory" - "\n\t\tregion without trying to understand it's contents"); - puts("\t--skip 2 or -s 2 -- skip 2 tables of the given name and output only 3rd one"); - puts("\t--help or -h -- this help message"); - exit(0); -} - -static struct option long_options[] = { - {"addr", 1, 0, 0}, - {"table", 1, 0, 0}, - {"output", 1, 0, 0}, - {"binary", 0, 0, 0}, - {"length", 1, 0, 0}, - {"skip", 1, 0, 0}, - {"help", 0, 0, 0}, - {0, 0, 0, 0} -}; -int main(int argc, char **argv) -{ - int option_index, c, fd; - u8 *raw; - struct acpi_rsdp_descriptor rsdpx, *x = 0; - char *filename = 0; - char buff[80]; - memset(select_sig, 0, 4); - print = 1; - connect = 0; - addr = length = 0; - skip = 0; - while (1) { - option_index = 0; - c = getopt_long(argc, argv, "a:t:o:bl:s:h", - long_options, &option_index); - if (c == -1) - break; - - switch (c) { - case 0: - switch (option_index) { - case 0: - addr = strtoul(optarg, (char **)NULL, 16); - break; - case 1: - memcpy(select_sig, optarg, 4); - break; - case 2: - filename = optarg; - break; - case 3: - print = 0; - break; - case 4: - length = strtoul(optarg, (char **)NULL, 16); - break; - case 5: - skip = strtoul(optarg, (char **)NULL, 10); - break; - case 6: - usage(argv[0]); - exit(0); - } - break; - case 'a': - addr = strtoul(optarg, (char **)NULL, 16); - break; - case 't': - memcpy(select_sig, optarg, 4); - break; - case 'o': - filename = optarg; - break; - case 'b': - print = 0; - break; - case 'l': - length = strtoul(optarg, (char **)NULL, 16); - break; - case 's': - skip = strtoul(optarg, (char **)NULL, 10); - break; - case 'h': - usage(argv[0]); - exit(0); - default: - printf("Unknown option!\n"); - usage(argv[0]); - exit(0); - } - } - - fd = STDOUT_FILENO; - if (filename) { - fd = creat(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); - if (fd < 0) - return fd; - } - - if (!select_sig[0] && !print) { - connect = 1; - } - - psz = sysconf(_SC_PAGESIZE); - if (length && addr) { - /* We know length and address, it means we just want a memory dump */ - if (!(raw = acpi_map_memory(addr, length))) - goto not_found; - write(fd, raw, length); - acpi_unmap_memory(raw, length); - close(fd); - return 0; - } - - length = sizeof(struct acpi_rsdp_descriptor); - if (!addr) { - addr = read_efi_systab(); - if (!addr) { - addr = ACPI_HI_RSDP_WINDOW_BASE; - length = ACPI_HI_RSDP_WINDOW_SIZE; - } - } - - if (!(raw = acpi_map_memory(addr, length)) || - !(x = acpi_scan_for_rsdp(raw, length))) - goto not_found; - - /* Find RSDP and print all found tables */ - memcpy(&rsdpx, x, sizeof(struct acpi_rsdp_descriptor)); - acpi_unmap_memory(raw, length); - if (connect) { - lseek(fd, sizeof(struct acpi_rsdp_descriptor), SEEK_SET); - } - if (!acpi_dump_SDT(fd, &rsdpx)) - goto not_found; - if (connect) { - lseek(fd, 0, SEEK_SET); - write(fd, x, (rsdpx.revision < 2) ? - ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH); - } else if (!select_sig[0] || !memcmp("RSD PTR ", select_sig, 4)) { - addr += (long)x - (long)raw; - length = snprintf(buff, 80, "RSD PTR @ %p\n", (void *)addr); - write(fd, buff, length); - acpi_show_data(fd, (u8 *) & rsdpx, (rsdpx.revision < 2) ? - ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH); - buff[0] = '\n'; - write(fd, buff, 1); - } - acpi_dump_dynamic_SSDT(fd); - close(fd); - return 0; -not_found: - close(fd); - fprintf(stderr, "ACPI tables were not found. If you know location " - "of RSD PTR table (from dmesg, etc), " - "supply it with either --addr or -a option\n"); - return 1; -} From 6c870213d6f3a25981c10728f46294a3bed1703f Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:40:09 +0800 Subject: [PATCH 027/134] ACPICA: acpidump: Update man page. This patch updates man file of acpidump. Signed-off-by: Lv Zheng [rjw: Subject] Signed-off-by: Rafael J. Wysocki --- tools/power/acpi/man/acpidump.8 | 85 ++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 12 deletions(-) diff --git a/tools/power/acpi/man/acpidump.8 b/tools/power/acpi/man/acpidump.8 index adfa99166e5e..38f095d86b52 100644 --- a/tools/power/acpi/man/acpidump.8 +++ b/tools/power/acpi/man/acpidump.8 @@ -1,18 +1,64 @@ .TH ACPIDUMP 8 .SH NAME -acpidump \- Dump system's ACPI tables to an ASCII file. +acpidump \- dump a system's ACPI tables to an ASCII file + .SH SYNOPSIS -.ft B -.B acpidump > acpidump.out +.B acpidump +.RI [ options ] +.br + .SH DESCRIPTION -\fBacpidump \fP dumps the systems ACPI tables to an ASCII file -appropriate for attaching to a bug report. +.B acpidump +dumps the systems ACPI tables to an ASCII file appropriate for +attaching to a bug report. Subsequently, they can be processed by utilities in the ACPICA package. -.SS Options -no options worth worrying about. -.PP -.SH EXAMPLE + +.SH OPTIONS +acpidump options are as follow: +.TP +.B Options +.TP +.B \-b +Dump tables to binary files +.TP +.B \-c +Dump customized tables +.TP +.B \-h \-? +This help message +.TP +.B \-o +Redirect output to file +.TP +.B \-r
+Dump tables from specified RSDP +.TP +.B \-s +Print table summaries only +.TP +.B \-v +Display version information +.TP +.B \-z +Verbose mode +.TP +.B Table Options +.TP +.B \-a
+Get table via a physical address +.TP +.B \-f +Get table via a binary file +.TP +.B \-n +Get table via a name/signature +.TP +Invocation without parameters dumps all available tables +.TP +Multiple mixed instances of -a, -f, and -n are supported + +.SH EXAMPLES .nf # acpidump > acpidump.out @@ -50,10 +96,25 @@ ACPICA: https://acpica.org/ .ta .nf /dev/mem +/sys/firmware/acpi/tables/* /sys/firmware/acpi/tables/dynamic/* +/sys/firmware/efi/systab .fi -.PP .SH AUTHOR -.nf -Written by Len Brown +.TP +Original by: + Len Brown +.TP +Written by: + Chao Guan +.TP +Updated by: + Bob Moore + Lv Zheng + +.SH SEE ALSO +\&\fIacpixtract\fR\|(8), \fIiasl\fR\|(8). + +.SH COPYRIGHT +COPYRIGHT (c) 2013, Intel Corporation. From 35476c75efa04a5fdb01074e54135dcc126c25f7 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:40:16 +0800 Subject: [PATCH 028/134] ACPICA: Update version to 20140325. Version 20140325. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 8dc934073620..913d0765adbe 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20140214 +#define ACPI_CA_VERSION 0x20140325 #include #include From 2650ef42636848db858625bd933131e8835f8d23 Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Mon, 28 Apr 2014 10:38:04 +0800 Subject: [PATCH 029/134] ACPI / scan: do not scan fixed hardware on HW-reduced platform Fixed hardware does not exist on HW-reduced ACPI platforms since the programming interface for them is not implemented on them, so no need to scan that hardware on them. This patch avoids creating the fixed power button ACPI device and eliminates a probe error message from ACPI button driver on ASUS T100. Signed-off-by: Aaron Lu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7efe546a8c42..db5fc6f9628e 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2259,12 +2259,16 @@ int __init acpi_scan_init(void) if (result) goto out; - result = acpi_bus_scan_fixed(); - if (result) { - acpi_detach_data(acpi_root->handle, acpi_scan_drop_device); - acpi_device_del(acpi_root); - put_device(&acpi_root->dev); - goto out; + /* Fixed feature devices do not exist on HW-reduced platform */ + if (!acpi_gbl_reduced_hardware) { + result = acpi_bus_scan_fixed(); + if (result) { + acpi_detach_data(acpi_root->handle, + acpi_scan_drop_device); + acpi_device_del(acpi_root); + put_device(&acpi_root->dev); + goto out; + } } acpi_update_all_gpes(); From 5b59c69ec54849f23b51d18b0a609c4f793bc35a Mon Sep 17 00:00:00 2001 From: Tony Camuso Date: Fri, 25 Apr 2014 14:19:29 -0400 Subject: [PATCH 030/134] ACPI / PAD: call schedule() when need_resched() is true The purpose of the acpi_pad driver is to implement the "processor power aggregator" device as described in the ACPI 4.0 spec section 8.5. It takes requests from the BIOS (via ACPI) to put a specified number of CPUs into idle, in order to save power, until further notice. It does this by creating high-priority threads that try to keep the CPUs in a high C-state (using the monitor/mwait CPU instructions). The mwait() call is in a loop that checks periodically if the thread should end and a few other things. It was discovered through testing that the power_saving threads were causing the system to consume more power than the system was consuming before the threads were created. A counter in the main loop of power_saving_thread() revealed that it was spinning. The mwait() instruction was not keeping the CPU in a high C state very much if at all. Here is a simplification of the loop in function power_saving_thread() in drivers/acpi/acpi_pad.c while (!kthread_should_stop()) { : try_to_freeze() : while (!need_resched()) { : if (!need_resched()) __mwait(power_saving_mwait_eax, 1); : if (jiffies > expire_time) { do_sleep = 1; break; } } } If need_resched() returns true, then mwait() is not called. It was returning true because of things like timer interrupts, as in the following sequence. hrtimer_interrupt->__run_hrtimer->tick_sched_timer-> update_process_times-> rcu_check_callbacks->rcu_pending->__rcu_pending->set_need_resched Kernels 3.5.0-rc2+ do not exhibit this problem, because a patch to try_to_freeze() in include/linux/freezer.h introduces a call to might_sleep(), which ultimately calls schedule() to clear the reschedule flag and allows the the loop to execute the call to mwait(). However, the changes to try_to_freeze are unrelated to acpi_pad, and it does not seem like a good idea to rely on an unrelated patch in a function that could later be changed and reintroduce this bug. Therefore, it seems better to make an explicit call to schedule() in the outer loop when the need_resched flag is set. Reported-and-tested-by: Stuart Hayes Signed-off-by: Tony Camuso Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_pad.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 37d73024b82e..e20708f2b8e5 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -215,8 +215,15 @@ static int power_saving_thread(void *data) * borrow CPU time from this CPU and cause RT task use > 95% * CPU time. To make 'avoid starvation' work, takes a nap here. */ - if (do_sleep) + if (unlikely(do_sleep)) schedule_timeout_killable(HZ * idle_pct / 100); + + /* If an external event has set the need_resched flag, then + * we need to deal with it, or this loop will continue to + * spin without calling __mwait(). + */ + if (unlikely(need_resched())) + schedule(); } exit_round_robin(tsk_index); From 4881f603d7b82df2bc15efd2a272f973a3bf8df1 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Fri, 25 Apr 2014 08:44:59 +0800 Subject: [PATCH 031/134] PM / hibernate: use unsigned local variables in swsusp_show_speed() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit do_div() needs 'u64' type, or it reports warning. And negative number is meaningless for "speed", so change all signed to unsigned within swsusp_show_speed(). The related warning (with allmodconfig for unicore32): CC kernel/power/hibernate.o kernel/power/hibernate.c: In function ‘swsusp_show_speed’: kernel/power/hibernate.c:237: warning: comparison of distinct pointer types lacks a cast Signed-off-by: Chen Gang [rjw: Subject] Signed-off-by: Rafael J. Wysocki --- kernel/power/hibernate.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index f4f2073711d3..de4b989cc8fd 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -228,19 +228,23 @@ static void platform_recover(int platform_mode) void swsusp_show_speed(struct timeval *start, struct timeval *stop, unsigned nr_pages, char *msg) { - s64 elapsed_centisecs64; - int centisecs; - int k; - int kps; + u64 elapsed_centisecs64; + unsigned int centisecs; + unsigned int k; + unsigned int kps; elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start); + /* + * If "(s64)elapsed_centisecs64 < 0", it will print long elapsed time, + * it is obvious enough for what went wrong. + */ do_div(elapsed_centisecs64, NSEC_PER_SEC / 100); centisecs = elapsed_centisecs64; if (centisecs == 0) centisecs = 1; /* avoid div-by-zero */ k = nr_pages * (PAGE_SIZE / 1024); kps = (k * 100) / centisecs; - printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n", + printk(KERN_INFO "PM: %s %u kbytes in %u.%02u seconds (%u.%02u MB/s)\n", msg, k, centisecs / 100, centisecs % 100, kps / 1000, (kps % 1000) / 10); From 7c7f8f7f2c6bf078874e5de35d7e2c66467fc664 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 22 Mar 2014 09:44:35 +0400 Subject: [PATCH 032/134] ARM: clps711x: Add cpuidle driver Add cpuidle support for ARM Cirrus Logic CLPS711X CPUs. This CPU has an unique internal register and write to this location will put the system into the Idle State by halting the clock to the processor until an interrupt is generated. Signed-off-by: Alexander Shiyan Signed-off-by: Daniel Lezcano --- drivers/cpuidle/Kconfig.arm | 6 +++ drivers/cpuidle/Makefile | 1 + drivers/cpuidle/cpuidle-clps711x.c | 64 ++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 drivers/cpuidle/cpuidle-clps711x.c diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm index 97ccc31dbdd8..371e75d2348d 100644 --- a/drivers/cpuidle/Kconfig.arm +++ b/drivers/cpuidle/Kconfig.arm @@ -13,6 +13,12 @@ config ARM_BIG_LITTLE_CPUIDLE define different C-states for little and big cores through the multiple CPU idle drivers infrastructure. +config ARM_CLPS711X_CPUIDLE + bool "CPU Idle Driver for CLPS711X processors" + depends on ARCH_CLPS711X || COMPILE_TEST + help + Select this to enable cpuidle on Cirrus Logic CLPS711X SOCs. + config ARM_HIGHBANK_CPUIDLE bool "CPU Idle Driver for Calxeda processors" depends on ARM_PSCI diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index f71ae1b373c5..534fff575823 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o ################################################################################## # ARM SoC drivers obj-$(CONFIG_ARM_BIG_LITTLE_CPUIDLE) += cpuidle-big_little.o +obj-$(CONFIG_ARM_CLPS711X_CPUIDLE) += cpuidle-clps711x.o obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE) += cpuidle-calxeda.o obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE) += cpuidle-kirkwood.o obj-$(CONFIG_ARM_ZYNQ_CPUIDLE) += cpuidle-zynq.o diff --git a/drivers/cpuidle/cpuidle-clps711x.c b/drivers/cpuidle/cpuidle-clps711x.c new file mode 100644 index 000000000000..5243811daa6e --- /dev/null +++ b/drivers/cpuidle/cpuidle-clps711x.c @@ -0,0 +1,64 @@ +/* + * CLPS711X CPU idle driver + * + * Copyright (C) 2014 Alexander Shiyan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#define CLPS711X_CPUIDLE_NAME "clps711x-cpuidle" + +static void __iomem *clps711x_halt; + +static int clps711x_cpuidle_halt(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + writel(0xaa, clps711x_halt); + + return index; +} + +static struct cpuidle_driver clps711x_idle_driver = { + .name = CLPS711X_CPUIDLE_NAME, + .owner = THIS_MODULE, + .states[0] = { + .name = "HALT", + .desc = "CLPS711X HALT", + .enter = clps711x_cpuidle_halt, + .exit_latency = 1, + }, + .state_count = 1, +}; + +static int __init clps711x_cpuidle_probe(struct platform_device *pdev) +{ + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + clps711x_halt = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(clps711x_halt)) + return PTR_ERR(clps711x_halt); + + return cpuidle_register(&clps711x_idle_driver, NULL); +} + +static struct platform_driver clps711x_cpuidle_driver = { + .driver = { + .name = CLPS711X_CPUIDLE_NAME, + .owner = THIS_MODULE, + }, +}; +module_platform_driver_probe(clps711x_cpuidle_driver, clps711x_cpuidle_probe); + +MODULE_AUTHOR("Alexander Shiyan "); +MODULE_DESCRIPTION("CLPS711X CPU idle driver"); +MODULE_LICENSE("GPL"); From 52c324f8a87b336496d0f5e9d8dff1aa32bb08cd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 1 May 2014 00:13:47 +0200 Subject: [PATCH 033/134] cpuidle: Combine cpuidle_enabled() with cpuidle_select() Since both cpuidle_enabled() and cpuidle_select() are only called by cpuidle_idle_call(), it is not really useful to keep them separate and combining them will help to avoid complicating cpuidle_idle_call() even further if governors are changed to return error codes sometimes. This code modification shouldn't lead to any functional changes. Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle.c | 26 ++++++-------------------- include/linux/cpuidle.h | 5 ----- kernel/sched/idle.c | 20 +++++++------------- 3 files changed, 13 insertions(+), 38 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 8236746e46bb..f38359f64cc6 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -64,26 +64,6 @@ int cpuidle_play_dead(void) return -ENODEV; } -/** - * cpuidle_enabled - check if the cpuidle framework is ready - * @dev: cpuidle device for this cpu - * @drv: cpuidle driver for this cpu - * - * Return 0 on success, otherwise: - * -NODEV : the cpuidle framework is not available - * -EBUSY : the cpuidle framework is not initialized - */ -int cpuidle_enabled(struct cpuidle_driver *drv, struct cpuidle_device *dev) -{ - if (off || !initialized) - return -ENODEV; - - if (!drv || !dev || !dev->enabled) - return -EBUSY; - - return 0; -} - /** * cpuidle_enter_state - enter the state and update stats * @dev: cpuidle device for this cpu @@ -138,6 +118,12 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, */ int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) { + if (off || !initialized) + return -ENODEV; + + if (!drv || !dev || !dev->enabled) + return -EBUSY; + return cpuidle_curr_governor->select(drv, dev); } diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index b0238cba440b..a8d5bd391a26 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -120,8 +120,6 @@ struct cpuidle_driver { #ifdef CONFIG_CPU_IDLE extern void disable_cpuidle(void); -extern int cpuidle_enabled(struct cpuidle_driver *drv, - struct cpuidle_device *dev); extern int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev); extern int cpuidle_enter(struct cpuidle_driver *drv, @@ -149,9 +147,6 @@ extern int cpuidle_play_dead(void); extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev); #else static inline void disable_cpuidle(void) { } -static inline int cpuidle_enabled(struct cpuidle_driver *drv, - struct cpuidle_device *dev) -{return -ENODEV; } static inline int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) {return -ENODEV; } diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 8f4390a079c7..a8f12247ce7c 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -101,19 +101,13 @@ static int cpuidle_idle_call(void) rcu_idle_enter(); /* - * Check if the cpuidle framework is ready, otherwise fallback - * to the default arch specific idle method + * Ask the cpuidle framework to choose a convenient idle state. + * Fall back to the default arch specific idle method on errors. */ - ret = cpuidle_enabled(drv, dev); - - if (!ret) { - /* - * Ask the governor to choose an idle state it thinks - * it is convenient to go to. There is *always* a - * convenient idle state - */ - next_state = cpuidle_select(drv, dev); + next_state = cpuidle_select(drv, dev); + ret = next_state; + if (ret >= 0) { /* * The idle task must be scheduled, it is pointless to * go to idle, just update no idle residency and get @@ -140,7 +134,7 @@ static int cpuidle_idle_call(void) CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu); - if (!ret) { + if (ret >= 0) { trace_cpu_idle_rcuidle(next_state, dev->cpu); /* @@ -175,7 +169,7 @@ static int cpuidle_idle_call(void) * We can't use the cpuidle framework, let's use the default * idle routine */ - if (ret) + if (ret < 0) arch_cpu_idle(); __current_set_polling(); From 3836785a1bdcd6706c68ad46bf53adc0b057b310 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 1 May 2014 00:14:04 +0200 Subject: [PATCH 034/134] cpuidle / menu: Return (-1) if there are no suitable states If there is a PM QoS latency limit and all of the sufficiently shallow C-states are disabled, the cpuidle menu governor returns 0 which on some systems is CPUIDLE_DRIVER_STATE_START and shouldn't be returned if that C-state has been disabled. Fix the issue by modifying the menu governor to return (-1) in such situations. Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/governors/menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 71b523293354..3ca15a8cbaa8 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -296,7 +296,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) data->needs_update = 0; } - data->last_state_idx = 0; + data->last_state_idx = CPUIDLE_DRIVER_STATE_START - 1; /* Special case when user has set very strict latency requirement */ if (unlikely(latency_req == 0)) From 2c730785d9532d2a9c46e059bd6a6c9a764c539f Mon Sep 17 00:00:00 2001 From: Sebastian Capella Date: Mon, 21 Apr 2014 17:30:46 -0700 Subject: [PATCH 035/134] PM / hibernate: no kernel_power_off when pm_power_off NULL Reboot logic in kernel/reboot will avoid calling kernel_power_off when pm_power_off is null, and instead uses kernel_halt. Change hibernate's power_down to follow the behavior in the reboot call. Calling the notifier twice (once for SYS_POWER_OFF and again for SYS_HALT) causes a panic during hibernation on Kirkwood Openblocks A6 board. Signed-off-by: Sebastian Capella Reported-by: Ezequiel Garcia Reviewed-by: Pavel Machek Signed-off-by: Rafael J. Wysocki --- kernel/power/hibernate.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index de4b989cc8fd..1f08ac7f55d8 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -599,7 +599,8 @@ static void power_down(void) case HIBERNATION_PLATFORM: hibernation_platform_enter(); case HIBERNATION_SHUTDOWN: - kernel_power_off(); + if (pm_power_off) + kernel_power_off(); break; #ifdef CONFIG_SUSPEND case HIBERNATION_SUSPEND: @@ -627,7 +628,8 @@ static void power_down(void) * corruption after resume. */ printk(KERN_CRIT "PM: Please power down manually\n"); - while(1); + while (1) + cpu_relax(); } /** From bed4d597a0f99b380d24ab3a9da47b62cbf1ad0e Mon Sep 17 00:00:00 2001 From: Chander Kashyap Date: Tue, 22 Apr 2014 18:08:04 +0530 Subject: [PATCH 036/134] cpuidle / menu: move repeated correction factor check to init In menu_select function we check for correction factor every time. If it is zero we are initializing to unity. Hence move it to init function and initialise by unity, hence avoid repeated comparisons. Signed-off-by: Chander Kashyap Reviewed-by: Tuukka Tikkanen Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/governors/menu.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 3ca15a8cbaa8..c4f80c15a48d 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -310,13 +310,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) data->bucket = which_bucket(data->next_timer_us); - /* - * if the correction factor is 0 (eg first time init or cpu hotplug - * etc), we actually want to start out with a unity factor. - */ - if (data->correction_factor[data->bucket] == 0) - data->correction_factor[data->bucket] = RESOLUTION * DECAY; - /* * Force the result of multiplication to be 64 bits even if both * operands are 32 bits. @@ -466,9 +459,17 @@ static int menu_enable_device(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct menu_device *data = &per_cpu(menu_devices, dev->cpu); + int i; memset(data, 0, sizeof(struct menu_device)); + /* + * if the correction factor is 0 (eg first time init or cpu hotplug + * etc), we actually want to start out with a unity factor. + */ + for(i = 0; i < BUCKETS; i++) + data->correction_factor[i] = RESOLUTION * DECAY; + return 0; } From 7bb516fbd1b54856ef51a43736ba18fdcdeadfed Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:03:33 +0800 Subject: [PATCH 037/134] ACPICA: Utilities: Cleanup obsoleted global variables. This patch deletes global variable declarations that are no longer used by ACPICA. No functional changes. Lv Zheng. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 1f602907dfab..e7d73eb57366 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -279,7 +279,6 @@ ACPI_GLOBAL(acpi_exception_handler, acpi_gbl_exception_handler); ACPI_GLOBAL(acpi_init_handler, acpi_gbl_init_handler); ACPI_GLOBAL(acpi_table_handler, acpi_gbl_table_handler); ACPI_GLOBAL(void *, acpi_gbl_table_handler_context); -ACPI_GLOBAL(struct acpi_walk_state *, acpi_gbl_breakpoint_walk); ACPI_GLOBAL(acpi_interface_handler, acpi_gbl_interface_handler); ACPI_GLOBAL(struct acpi_sci_handler_info *, acpi_gbl_sci_handler_list); @@ -296,7 +295,6 @@ ACPI_GLOBAL(u8, acpi_gbl_reg_methods_executed); /* Misc */ ACPI_GLOBAL(u32, acpi_gbl_original_mode); -ACPI_GLOBAL(u32, acpi_gbl_rsdp_original_location); ACPI_GLOBAL(u32, acpi_gbl_ns_lookup_count); ACPI_GLOBAL(u32, acpi_gbl_ps_find_count); ACPI_GLOBAL(u16, acpi_gbl_pm1_enable_register_save); @@ -483,11 +481,6 @@ ACPI_GLOBAL(u16, acpi_gbl_node_type_count_misc); ACPI_GLOBAL(u32, acpi_gbl_num_nodes); ACPI_GLOBAL(u32, acpi_gbl_num_objects); -ACPI_GLOBAL(u32, acpi_gbl_size_of_parse_tree); -ACPI_GLOBAL(u32, acpi_gbl_size_of_method_trees); -ACPI_GLOBAL(u32, acpi_gbl_size_of_node_entries); -ACPI_GLOBAL(u32, acpi_gbl_size_of_acpi_objects); - #endif /* ACPI_DEBUGGER */ /***************************************************************************** From fad6449b4a96d7d7e61ebdfd16fd3a80833526bf Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:03:39 +0800 Subject: [PATCH 038/134] ACPICA: Utilities: Deploy ACPI_DEBUGGER_EXEC for ACPI_DEBUGGER enabled code in utglobal.c. This patch deploys ACPI_DEBUGGER_EXEC usage to utglobal.c to reduce "ifdef" of ACPI_DEBUGGER. No functional changes. Lv Zheng. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utglobal.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index f3abeae9d2f8..825b064e21f3 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -377,9 +377,7 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_disable_mem_tracking = FALSE; #endif -#ifdef ACPI_DEBUGGER - acpi_gbl_db_terminate_threads = FALSE; -#endif + ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = FALSE); return_ACPI_STATUS(AE_OK); } From d87a2b75cd00a9e62c2b218e7d586c30961eb311 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:03:45 +0800 Subject: [PATCH 039/134] ACPICA: acpidump: Fix code issue in invoking fread in the loop. This patch fixes an issue that the while loop is not needed as fread() should return exact the bytes of expected. The patch is tested by runing diff against the output of "-c" mode and the normal mode, and only finds the following differences: 1. table addresses: the "-c" mode will always fill 0x0000000000000000 for the address. 2. RSDP/RSDT/XSDT: there is no generation of such tables for "-c" mode. So the test result shows the fix is valid. Lv Zheng. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- .../os_specific/service_layers/oslinuxtbl.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c index e975aa90016a..dc6509884c25 100644 --- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c @@ -1112,7 +1112,6 @@ osl_read_table_from_file(char *filename, struct acpi_table_header *local_table = NULL; u32 table_length; s32 count; - u32 total = 0; acpi_status status = AE_OK; /* Open the file */ @@ -1163,16 +1162,12 @@ osl_read_table_from_file(char *filename, fseek(table_file, file_offset, SEEK_SET); - while (!feof(table_file) && total < table_length) { - count = fread(local_table + total, 1, table_length - total, table_file); - if (count < 0) { - fprintf(stderr, "%4.4s: Could not read table content\n", - header.signature); - status = AE_INVALID_TABLE_LENGTH; - goto exit; - } - - total += count; + count = fread(local_table, 1, table_length, table_file); + if (count != table_length) { + fprintf(stderr, "%4.4s: Could not read table content\n", + header.signature); + status = AE_INVALID_TABLE_LENGTH; + goto exit; } /* Validate checksum */ From 3035ff70e6e6e15351e865fcc69dff182103b115 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:03:52 +0800 Subject: [PATCH 040/134] ACPICA: Update global variable definitions. No functional change. Move all of the public globals to acpixf.h for the convenience of users. Also: Adds #ifndef/#endif conditions arround ACPI_GLOBAL and ACPI_INIT_GLOBAL definition so that OSPMs might be able to: 1. Redefine ACPI_GLOBAL/ACPI_INIT_GLOBAL into no-op, and 2. Redefine external global variables into immediates to implement stubs for them. Lv Zheng. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 134 +----------------------------- include/acpi/acpixf.h | 143 ++++++++++++++++++++++++++++++--- 2 files changed, 132 insertions(+), 145 deletions(-) diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index e7d73eb57366..115eedcade1e 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -44,144 +44,14 @@ #ifndef __ACGLOBAL_H__ #define __ACGLOBAL_H__ -/* - * Ensure that the globals are actually defined and initialized only once. - * - * The use of these macros allows a single list of globals (here) in order - * to simplify maintenance of the code. - */ -#ifdef DEFINE_ACPI_GLOBALS -#define ACPI_GLOBAL(type,name) \ - extern type name; \ - type name - -#define ACPI_INIT_GLOBAL(type,name,value) \ - type name=value - -#else -#define ACPI_GLOBAL(type,name) \ - extern type name - -#define ACPI_INIT_GLOBAL(type,name,value) \ - extern type name -#endif - -#ifdef DEFINE_ACPI_GLOBALS - -/* Public globals, available from outside ACPICA subsystem */ - /***************************************************************************** * - * Runtime configuration (static defaults that can be overriden at runtime) + * Globals related to the ACPI tables * ****************************************************************************/ -/* - * Enable "slack" in the AML interpreter? Default is FALSE, and the - * interpreter strictly follows the ACPI specification. Setting to TRUE - * allows the interpreter to ignore certain errors and/or bad AML constructs. - * - * Currently, these features are enabled by this flag: - * - * 1) Allow "implicit return" of last value in a control method - * 2) Allow access beyond the end of an operation region - * 3) Allow access to uninitialized locals/args (auto-init to integer 0) - * 4) Allow ANY object type to be a source operand for the Store() operator - * 5) Allow unresolved references (invalid target name) in package objects - * 6) Enable warning messages for behavior that is not ACPI spec compliant - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_interpreter_slack, FALSE); +/* Master list of all ACPI tables that were found in the RSDT/XSDT */ -/* - * Automatically serialize all methods that create named objects? Default - * is TRUE, meaning that all non_serialized methods are scanned once at - * table load time to determine those that create named objects. Methods - * that create named objects are marked Serialized in order to prevent - * possible run-time problems if they are entered by more than one thread. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_auto_serialize_methods, TRUE); - -/* - * Create the predefined _OSI method in the namespace? Default is TRUE - * because ACPICA is fully compatible with other ACPI implementations. - * Changing this will revert ACPICA (and machine ASL) to pre-OSI behavior. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_create_osi_method, TRUE); - -/* - * Optionally use default values for the ACPI register widths. Set this to - * TRUE to use the defaults, if an FADT contains incorrect widths/lengths. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_use_default_register_widths, TRUE); - -/* - * Optionally enable output from the AML Debug Object. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_aml_debug_object, FALSE); - -/* - * Optionally copy the entire DSDT to local memory (instead of simply - * mapping it.) There are some BIOSs that corrupt or replace the original - * DSDT, creating the need for this option. Default is FALSE, do not copy - * the DSDT. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_copy_dsdt_locally, FALSE); - -/* - * Optionally ignore an XSDT if present and use the RSDT instead. - * Although the ACPI specification requires that an XSDT be used instead - * of the RSDT, the XSDT has been found to be corrupt or ill-formed on - * some machines. Default behavior is to use the XSDT if present. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE); - -/* - * Optionally use 32-bit FADT addresses if and when there is a conflict - * (address mismatch) between the 32-bit and 64-bit versions of the - * address. Although ACPICA adheres to the ACPI specification which - * requires the use of the corresponding 64-bit address if it is non-zero, - * some machines have been found to have a corrupted non-zero 64-bit - * address. Default is FALSE, do not favor the 32-bit addresses. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, FALSE); - -/* - * Optionally truncate I/O addresses to 16 bits. Provides compatibility - * with other ACPI implementations. NOTE: During ACPICA initialization, - * this value is set to TRUE if any Windows OSI strings have been - * requested by the BIOS. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_truncate_io_addresses, FALSE); - -/* - * Disable runtime checking and repair of values returned by control methods. - * Use only if the repair is causing a problem on a particular machine. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_auto_repair, FALSE); - -/* - * Optionally do not install any SSDTs from the RSDT/XSDT during initialization. - * This can be useful for debugging ACPI problems on some machines. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_install, FALSE); - -/* - * We keep track of the latest version of Windows that has been requested by - * the BIOS. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_osi_data, 0); - -#endif /* DEFINE_ACPI_GLOBALS */ - -/***************************************************************************** - * - * ACPI Table globals - * - ****************************************************************************/ - -/* - * Master list of all ACPI tables that were found in the RSDT/XSDT. - */ ACPI_GLOBAL(struct acpi_table_list, acpi_gbl_root_table_list); /* DSDT information. Used to check for DSDT corruption */ diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 913d0765adbe..010816e24f5e 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -56,13 +56,141 @@ extern u8 acpi_gbl_permanent_mmap; /* - * Globals that are publically available + * Ensure that the globals are actually defined and initialized only once. + * + * The use of these macros allows a single list of globals (here) in order + * to simplify maintenance of the code. + */ +#ifdef DEFINE_ACPI_GLOBALS +#define ACPI_GLOBAL(type,name) \ + extern type name; \ + type name + +#define ACPI_INIT_GLOBAL(type,name,value) \ + type name=value + +#else +#ifndef ACPI_GLOBAL +#define ACPI_GLOBAL(type,name) \ + extern type name +#endif + +#ifndef ACPI_INIT_GLOBAL +#define ACPI_INIT_GLOBAL(type,name,value) \ + extern type name +#endif +#endif + +/* Public globals, available from outside ACPICA subsystem */ + +/***************************************************************************** + * + * Runtime configuration (static defaults that can be overriden at runtime) + * + ****************************************************************************/ + +/* + * Enable "slack" in the AML interpreter? Default is FALSE, and the + * interpreter strictly follows the ACPI specification. Setting to TRUE + * allows the interpreter to ignore certain errors and/or bad AML constructs. + * + * Currently, these features are enabled by this flag: + * + * 1) Allow "implicit return" of last value in a control method + * 2) Allow access beyond the end of an operation region + * 3) Allow access to uninitialized locals/args (auto-init to integer 0) + * 4) Allow ANY object type to be a source operand for the Store() operator + * 5) Allow unresolved references (invalid target name) in package objects + * 6) Enable warning messages for behavior that is not ACPI spec compliant + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_interpreter_slack, FALSE); + +/* + * Automatically serialize all methods that create named objects? Default + * is TRUE, meaning that all non_serialized methods are scanned once at + * table load time to determine those that create named objects. Methods + * that create named objects are marked Serialized in order to prevent + * possible run-time problems if they are entered by more than one thread. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_auto_serialize_methods, TRUE); + +/* + * Create the predefined _OSI method in the namespace? Default is TRUE + * because ACPICA is fully compatible with other ACPI implementations. + * Changing this will revert ACPICA (and machine ASL) to pre-OSI behavior. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_create_osi_method, TRUE); + +/* + * Optionally use default values for the ACPI register widths. Set this to + * TRUE to use the defaults, if an FADT contains incorrect widths/lengths. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_use_default_register_widths, TRUE); + +/* + * Optionally enable output from the AML Debug Object. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_aml_debug_object, FALSE); + +/* + * Optionally copy the entire DSDT to local memory (instead of simply + * mapping it.) There are some BIOSs that corrupt or replace the original + * DSDT, creating the need for this option. Default is FALSE, do not copy + * the DSDT. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_copy_dsdt_locally, FALSE); + +/* + * Optionally ignore an XSDT if present and use the RSDT instead. + * Although the ACPI specification requires that an XSDT be used instead + * of the RSDT, the XSDT has been found to be corrupt or ill-formed on + * some machines. Default behavior is to use the XSDT if present. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE); + +/* + * Optionally use 32-bit FADT addresses if and when there is a conflict + * (address mismatch) between the 32-bit and 64-bit versions of the + * address. Although ACPICA adheres to the ACPI specification which + * requires the use of the corresponding 64-bit address if it is non-zero, + * some machines have been found to have a corrupted non-zero 64-bit + * address. Default is FALSE, do not favor the 32-bit addresses. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, FALSE); + +/* + * Optionally truncate I/O addresses to 16 bits. Provides compatibility + * with other ACPI implementations. NOTE: During ACPICA initialization, + * this value is set to TRUE if any Windows OSI strings have been + * requested by the BIOS. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_truncate_io_addresses, FALSE); + +/* + * Disable runtime checking and repair of values returned by control methods. + * Use only if the repair is causing a problem on a particular machine. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_auto_repair, FALSE); + +/* + * Optionally do not install any SSDTs from the RSDT/XSDT during initialization. + * This can be useful for debugging ACPI problems on some machines. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_install, FALSE); + +/* + * We keep track of the latest version of Windows that has been requested by + * the BIOS. ACPI 5.0. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_osi_data, 0); + +/* + * Other miscellaneous public globals */ extern u32 acpi_current_gpe_count; extern struct acpi_table_fadt acpi_gbl_FADT; extern u8 acpi_gbl_system_awake_and_running; extern u8 acpi_gbl_reduced_hardware; /* ACPI 5.0 */ -extern u8 acpi_gbl_osi_data; /* Runtime configuration of debug print levels */ @@ -71,19 +199,8 @@ extern u32 acpi_dbg_layer; /* ACPICA runtime options */ -extern u8 acpi_gbl_auto_serialize_methods; -extern u8 acpi_gbl_copy_dsdt_locally; -extern u8 acpi_gbl_create_osi_method; -extern u8 acpi_gbl_disable_auto_repair; -extern u8 acpi_gbl_disable_ssdt_table_install; -extern u8 acpi_gbl_do_not_use_xsdt; -extern u8 acpi_gbl_enable_aml_debug_object; -extern u8 acpi_gbl_enable_interpreter_slack; extern u32 acpi_gbl_trace_flags; extern acpi_name acpi_gbl_trace_method_name; -extern u8 acpi_gbl_truncate_io_addresses; -extern u8 acpi_gbl_use32_bit_fadt_addresses; -extern u8 acpi_gbl_use_default_register_widths; /* * Hardware-reduced prototypes. All interfaces that use these macros will From 51e35823eb57621b1b2ed39790d539620617b4a3 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 30 Apr 2014 10:03:58 +0800 Subject: [PATCH 041/134] ACPICA: Update acpi_buffer_to_resource interface. 1) Add standard trace mechanism. 2) Add ACPI_EXPORT_SYMBOL macro. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/rscreate.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index 75d369050657..049d9c22a0f9 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -72,6 +72,8 @@ acpi_buffer_to_resource(u8 *aml_buffer, void *resource; void *current_resource_ptr; + ACPI_FUNCTION_TRACE(acpi_buffer_to_resource); + /* * Note: we allow AE_AML_NO_RESOURCE_END_TAG, since an end tag * is not required here. @@ -85,7 +87,7 @@ acpi_buffer_to_resource(u8 *aml_buffer, status = AE_OK; } if (ACPI_FAILURE(status)) { - return (status); + return_ACPI_STATUS(status); } /* Allocate a buffer for the converted resource */ @@ -93,7 +95,7 @@ acpi_buffer_to_resource(u8 *aml_buffer, resource = ACPI_ALLOCATE_ZEROED(list_size_needed); current_resource_ptr = resource; if (!resource) { - return (AE_NO_MEMORY); + return_ACPI_STATUS(AE_NO_MEMORY); } /* Perform the AML-to-Resource conversion */ @@ -110,9 +112,11 @@ acpi_buffer_to_resource(u8 *aml_buffer, *resource_ptr = resource; } - return (status); + return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_buffer_to_resource) + /******************************************************************************* * * FUNCTION: acpi_rs_create_resource_list @@ -130,10 +134,9 @@ acpi_buffer_to_resource(u8 *aml_buffer, * of device resources. * ******************************************************************************/ - acpi_status acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer, - struct acpi_buffer * output_buffer) + struct acpi_buffer *output_buffer) { acpi_status status; From d36d4e30bd44e2e447a2346edb437e842df8c753 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 30 Apr 2014 10:04:06 +0800 Subject: [PATCH 042/134] ACPICA: Add support for LPIT table. Adds header, disassembler, table compiler, and template support for the Low Power Idle Table (LPIT). Note that the disassembler and table compiler are not shipped in the kernel. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/actbl2.h | 65 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index c8adad9c6b6a..687426168b0e 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -70,6 +70,7 @@ #define ACPI_SIG_HPET "HPET" /* High Precision Event Timer table */ #define ACPI_SIG_IBFT "IBFT" /* iSCSI Boot Firmware Table */ #define ACPI_SIG_IVRS "IVRS" /* I/O Virtualization Reporting Structure */ +#define ACPI_SIG_LPIT "LPIT" /* Low Power Idle Table */ #define ACPI_SIG_MCFG "MCFG" /* PCI Memory Mapped Configuration table */ #define ACPI_SIG_MCHI "MCHI" /* Management Controller Host Interface table */ #define ACPI_SIG_MTMR "MTMR" /* MID Timer table */ @@ -818,6 +819,70 @@ struct acpi_ivrs_memory { u64 memory_length; }; +/******************************************************************************* + * + * LPIT - Low Power Idle Table + * + * Conforms to "ACPI Low Power Idle Table (LPIT) and _LPD Proposal (DRAFT)" + * + ******************************************************************************/ + +struct acpi_table_lpit { + struct acpi_table_header header; /* Common ACPI table header */ +}; + +/* LPIT subtable header */ + +struct acpi_lpit_header { + u32 type; /* Subtable type */ + u32 length; /* Subtable length */ + u16 unique_id; + u16 reserved; + u32 flags; +}; + +/* Values for subtable Type above */ + +enum acpi_lpit_type { + ACPI_LPIT_TYPE_NATIVE_CSTATE = 0x00, + ACPI_LPIT_TYPE_SIMPLE_IO = 0x01 +}; + +/* Masks for Flags field above */ + +#define ACPI_LPIT_STATE_DISABLED (1) +#define ACPI_LPIT_NO_COUNTER (1<<1) + +/* + * LPIT subtables, correspond to Type in struct acpi_lpit_header + */ + +/* 0x00: Native C-state instruction based LPI structure */ + +struct acpi_lpit_native { + struct acpi_lpit_header header; + struct acpi_generic_address entry_trigger; + u32 residency; + u32 latency; + struct acpi_generic_address residency_counter; + u64 counter_frequency; +}; + +/* 0x01: Simple I/O based LPI structure */ + +struct acpi_lpit_io { + struct acpi_lpit_header header; + struct acpi_generic_address entry_trigger; + u32 trigger_action; + u64 trigger_value; + u64 trigger_mask; + struct acpi_generic_address minimum_idle_state; + u32 residency; + u32 latency; + struct acpi_generic_address residency_counter; + u64 counter_frequency; +}; + /******************************************************************************* * * MCFG - PCI Memory Mapped Configuration table and sub-table From 92cb3a8d37b96f6aeee9ebe5336dd8a8e67580a4 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 30 Apr 2014 10:04:13 +0800 Subject: [PATCH 043/134] ACPICA: Add support for _LPD and _PRP methods. This patch currently only affects acpihelp and iASL which are not shipped in the Linux kernel. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acpredef.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index a48d713e9599..34001a9fd098 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -586,6 +586,10 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = { {{"_LID", METHOD_0ARGS, METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, + {{"_LPD", METHOD_0ARGS, + METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (2 Int) */ + PACKAGE_INFO(ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0), + {{"_MAT", METHOD_0ARGS, METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, From c28fa24b97789bd61b09014380a2eb71a522090a Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Wed, 30 Apr 2014 10:04:20 +0800 Subject: [PATCH 044/134] ACPICA: Update handling of PCI ID lists. More of a style cleanup. If hw_build_pci_list is to return a non-zero status, it now deletes any partial ID list that has been constructed. If it returns AE_OK, the caller is responsible for list deletion. David Box. Signed-off-by: David E. Box Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/hwpci.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c index e701d8c33dbf..6aade8e1d2a1 100644 --- a/drivers/acpi/acpica/hwpci.c +++ b/drivers/acpi/acpica/hwpci.c @@ -140,11 +140,12 @@ acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id, /* Walk the list, updating the PCI device/function/bus numbers */ status = acpi_hw_process_pci_list(pci_id, list_head); + + /* Delete the list */ + + acpi_hw_delete_pci_list(list_head); } - /* Always delete the list */ - - acpi_hw_delete_pci_list(list_head); return_ACPI_STATUS(status); } @@ -187,6 +188,10 @@ acpi_hw_build_pci_list(acpi_handle root_pci_device, while (1) { status = acpi_get_parent(current_device, &parent_device); if (ACPI_FAILURE(status)) { + + /* Must delete the list before exit */ + + acpi_hw_delete_pci_list(*return_list_head); return (status); } @@ -199,6 +204,10 @@ acpi_hw_build_pci_list(acpi_handle root_pci_device, list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device)); if (!list_element) { + + /* Must delete the list before exit */ + + acpi_hw_delete_pci_list(*return_list_head); return (AE_NO_MEMORY); } From 1a49b72c4e0c7097b9d3cf8650ff17f87e07d8bd Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 30 Apr 2014 10:04:28 +0800 Subject: [PATCH 045/134] ACPICA: Comment updates - no functional change. Change all instances of "sub-table" to "subtable" for consistency. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/actbl1.h | 4 ++-- include/acpi/actbl2.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index 212c65de75df..4ad7da805180 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -675,7 +675,7 @@ enum acpi_madt_type { }; /* - * MADT Sub-tables, correspond to Type in struct acpi_subtable_header + * MADT Subtables, correspond to Type in struct acpi_subtable_header */ /* 0: Processor Local APIC */ @@ -918,7 +918,7 @@ enum acpi_srat_type { }; /* - * SRAT Sub-tables, correspond to Type in struct acpi_subtable_header + * SRAT Subtables, correspond to Type in struct acpi_subtable_header */ /* 0: Processor Local APIC/SAPIC Affinity */ diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 687426168b0e..860e5c883eb3 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -457,7 +457,7 @@ struct acpi_dmar_pci_path { }; /* - * DMAR Sub-tables, correspond to Type in struct acpi_dmar_header + * DMAR Subtables, correspond to Type in struct acpi_dmar_header */ /* 0: Hardware Unit Definition */ @@ -885,7 +885,7 @@ struct acpi_lpit_io { /******************************************************************************* * - * MCFG - PCI Memory Mapped Configuration table and sub-table + * MCFG - PCI Memory Mapped Configuration table and subtable * Version 1 * * Conforms to "PCI Firmware Specification", Revision 3.0, June 20, 2005 @@ -988,7 +988,7 @@ enum acpi_slic_type { }; /* - * SLIC Sub-tables, correspond to Type in struct acpi_slic_header + * SLIC Subtables, correspond to Type in struct acpi_slic_header */ /* 0: Public Key Structure */ From 3a2f3a3383f87412fa11b89290d592a24f618487 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:04:35 +0800 Subject: [PATCH 046/134] ACPICA: OSL: Move external globals from utglobal.c to acpixf.h using ACPI_INIT_GLOBAL/ACPI_GLOBAL. OSPMs like Linux trend to include all header files but leave empty stub macros for a feature that is not configured during build. This patch cleans up global variables that are defined in utglobal.c using ACPI_INIT_GLOBAL mechanism. In Linux, such global variables are used by the subsystems external to ACPICA. This patch also cleans up global variables that are defined in utglobal.c using ACPI_GLOBAL mechanism. In Linux, such global variables are not used or should not be used by the subsystems external to ACPICA. External global variables can be redefined by OSPMs using ACPI_INIT_GLOBAL/ACPI_GLOBAL macros. Thus the ACPI_GLOBAL/ACPI_INIT_GLOBAL mechanisms can be used by OSPM to implement stubs for such external globals. This patch doesn't include code for Linux to use this new mechanism, thus no functional changes. Lv Zheng. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utglobal.c | 22 --------------------- include/acpi/acpixf.h | 35 ++++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 34 deletions(-) diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 825b064e21f3..d69be3cb3fae 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -55,28 +55,7 @@ ACPI_MODULE_NAME("utglobal") * Static global variable initialization. * ******************************************************************************/ -/* Debug output control masks */ -u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT; - -u32 acpi_dbg_layer = 0; - -/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */ - -struct acpi_table_fadt acpi_gbl_FADT; -u32 acpi_gbl_trace_flags; -acpi_name acpi_gbl_trace_method_name; -u8 acpi_gbl_system_awake_and_running; -u32 acpi_current_gpe_count; - -/* - * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning - * that the ACPI hardware is no longer required. A flag in the FADT indicates - * a reduced HW machine, and that flag is duplicated here for convenience. - */ -u8 acpi_gbl_reduced_hardware; - /* Various state name strings */ - const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = { "\\_S0_", "\\_S1_", @@ -337,7 +316,6 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_acpi_hardware_present = TRUE; acpi_gbl_last_owner_id_index = 0; acpi_gbl_next_owner_id_offset = 0; - acpi_gbl_trace_method_name = 0; acpi_gbl_trace_dbg_level = 0; acpi_gbl_trace_dbg_layer = 0; acpi_gbl_debugger_configuration = DEBUGGER_THREADING; diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 010816e24f5e..8255689c864b 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -185,22 +185,33 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_install, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_osi_data, 0); /* - * Other miscellaneous public globals + * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning + * that the ACPI hardware is no longer required. A flag in the FADT indicates + * a reduced HW machine, and that flag is duplicated here for convenience. */ -extern u32 acpi_current_gpe_count; -extern struct acpi_table_fadt acpi_gbl_FADT; -extern u8 acpi_gbl_system_awake_and_running; -extern u8 acpi_gbl_reduced_hardware; /* ACPI 5.0 */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_reduced_hardware, FALSE); -/* Runtime configuration of debug print levels */ +/* + * This mechanism is used to trace a specified AML method. The method is + * traced each time it is executed. + */ +ACPI_INIT_GLOBAL(u32, acpi_gbl_trace_flags, 0); +ACPI_INIT_GLOBAL(acpi_name, acpi_gbl_trace_method_name, 0); -extern u32 acpi_dbg_level; -extern u32 acpi_dbg_layer; +/* + * Runtime configuration of debug output control masks. We want the debug + * switches statically initialized so they are already set when the debugger + * is entered. + */ +ACPI_INIT_GLOBAL(u32, acpi_dbg_level, ACPI_DEBUG_DEFAULT); +ACPI_INIT_GLOBAL(u32, acpi_dbg_layer, 0); -/* ACPICA runtime options */ - -extern u32 acpi_gbl_trace_flags; -extern acpi_name acpi_gbl_trace_method_name; +/* + * Globals that are publically available + */ +ACPI_GLOBAL(u32, acpi_current_gpe_count); +ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT); +ACPI_GLOBAL(u8, acpi_gbl_system_awake_and_running); /* * Hardware-reduced prototypes. All interfaces that use these macros will From d5caf1cdc41c311cb5d4d2c010f90809f319c7dd Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:04:42 +0800 Subject: [PATCH 047/134] ACPICA: OSL: Add configurability for memory allocation macros. OSPMs like Linux trend to include all header files but leave empty stub macros for a feature that is not configured during build. For macros defined without other symbols referencesd it is safe to leave them without protections. By investigation, there are only the following internal/external symbols referenced by the ACPICA macros: 1. C library symbols, including string, ctype, stdarg APIs. Since such symbols are always accessbile in the kernel source tree, it is safe to leave macros referencing them without protected for Linux. 2. ACPICA OSL symbols, such symbols are designed to be used only by ACPICA internal APIs. And there are macros directly referencing mutex and memory allocation OSL symbols. We need to examine the external usages of such macros. For macros referencing the mutex OSL symbols, fortunately, there is no external user directly invoking such macros. ======================================================================== !! IMPORTANT !! ======================================================================== For macros referencing memory allocation OSL symbols - 1. 'free' - ACPI_FREE 2. 'alloc' - ACPI_ALLOCATE, ACPI_ALLOCATE_ZEROED, ACPI_ALLOCATE_BUFFER, ACPI_ALLOCATE_LOCAL_BUFFER there are external users directly invoking 'alloc' macros. And the more complicated situation is the reversals of such macros are not ACPI_FREE but acpi_os_free (or kfree) in Linux. Though we can define such macros into no-op, we in fact cannot define their reversals into no-op. This patch adds mechanism to protect ACPICA memory allocation APIs for Linux so that acpi_os_free (or kfree) invoked in Linux can have a zero address returned by 'alloc' macros to free. In this way, acpi_os_free (or kfree) can be converted into no-op. ======================================================================== 3. ACPI_OFFSET and other macros that would access structure members, we need to check if such structure members are not accessible under a specific configuration. Fortunately, currently Linux doesn't use such structure members when CONFIG_ACPI is disabled. This patch thus only adds mechanism useful for implementing stubs for ACPICA provided macros - the configurability of memory allocation APIs. This patch doesn't include code for Linux to use this new mechanism, thus no functional changes. Lv Zheng. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- include/acpi/actypes.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index e76356574374..19b26bb69a70 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -329,6 +329,15 @@ typedef u32 acpi_physical_address; * ******************************************************************************/ +#ifdef ACPI_NO_MEM_ALLOCATIONS + +#define ACPI_ALLOCATE(a) NULL +#define ACPI_ALLOCATE_ZEROED(a) NULL +#define ACPI_FREE(a) +#define ACPI_MEM_TRACKING(a) + +#else /* ACPI_NO_MEM_ALLOCATIONS */ + #ifdef ACPI_DBG_TRACK_ALLOCATIONS /* * Memory allocation tracking (used by acpi_exec to detect memory leaks) @@ -350,6 +359,8 @@ typedef u32 acpi_physical_address; #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ +#endif /* ACPI_NO_MEM_ALLOCATIONS */ + /****************************************************************************** * * ACPI Specification constants (Do not change unless the specification changes) @@ -928,9 +939,19 @@ struct acpi_object_list { * Miscellaneous common Data Structures used by the interfaces */ #define ACPI_NO_BUFFER 0 + +#ifdef ACPI_NO_MEM_ALLOCATIONS + +#define ACPI_ALLOCATE_BUFFER (acpi_size) (0) +#define ACPI_ALLOCATE_LOCAL_BUFFER (acpi_size) (0) + +#else /* ACPI_NO_MEM_ALLOCATIONS */ + #define ACPI_ALLOCATE_BUFFER (acpi_size) (-1) /* Let ACPICA allocate buffer */ #define ACPI_ALLOCATE_LOCAL_BUFFER (acpi_size) (-2) /* For internal use only (enables tracking) */ +#endif /* ACPI_NO_MEM_ALLOCATIONS */ + struct acpi_buffer { acpi_size length; /* Length in bytes of the buffer */ void *pointer; /* pointer to buffer */ From 407e22afcf0701ec5543f39934c43b10082a1a97 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:04:48 +0800 Subject: [PATCH 048/134] ACPICA: OSL: Add configurability for error message functions. This patch extends ACPI_HW_DEPENDENT_x mechanism to all error message related functions so that the OSPMs can have full control to configure them into stub functions. This patch doesn't include code for Linux to use this new mechanism, thus no functional change. Lv Zheng. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utxferror.c | 2 + include/acpi/acpixf.h | 73 +++++++++++++++++++++------------ 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index edd861102f1b..88ef77f3cf88 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -53,6 +53,7 @@ ACPI_MODULE_NAME("utxferror") * This module is used for the in-kernel ACPICA as well as the ACPICA * tools/applications. */ +#ifndef ACPI_NO_ERROR_MESSAGES /* Entire module */ /******************************************************************************* * * FUNCTION: acpi_error @@ -249,3 +250,4 @@ acpi_bios_warning(const char *module_name, } ACPI_EXPORT_SYMBOL(acpi_bios_warning) +#endif /* ACPI_NO_ERROR_MESSAGES */ diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 8255689c864b..39f432e513f2 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -240,6 +240,21 @@ ACPI_GLOBAL(u8, acpi_gbl_system_awake_and_running); #endif /* !ACPI_REDUCED_HARDWARE */ +/* + * Error-message prototypes. All interfaces that use these macros will + * be configured out of the ACPICA build if the ACPI_NO_ERROR_MESSAGE flag + * is defined. + */ +#ifndef ACPI_NO_ERROR_MESSAGES +#define ACPI_MSG_DEPENDENT_RETURN_VOID(prototype) \ + prototype; + +#else +#define ACPI_MSG_DEPENDENT_RETURN_VOID(prototype) \ + static ACPI_INLINE prototype {return;} + +#endif /* ACPI_NO_ERROR_MESSAGES */ + /* * Initialization */ @@ -666,38 +681,42 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status /* * Error/Warning output */ -ACPI_PRINTF_LIKE(3) -void ACPI_INTERNAL_VAR_XFACE -acpi_error(const char *module_name, u32 line_number, const char *format, ...); - -ACPI_PRINTF_LIKE(4) -void ACPI_INTERNAL_VAR_XFACE -acpi_exception(const char *module_name, - u32 line_number, acpi_status status, const char *format, ...); - -ACPI_PRINTF_LIKE(3) -void ACPI_INTERNAL_VAR_XFACE -acpi_warning(const char *module_name, u32 line_number, const char *format, ...); - -ACPI_PRINTF_LIKE(3) -void ACPI_INTERNAL_VAR_XFACE -acpi_info(const char *module_name, u32 line_number, const char *format, ...); - -ACPI_PRINTF_LIKE(3) -void ACPI_INTERNAL_VAR_XFACE -acpi_bios_error(const char *module_name, - u32 line_number, const char *format, ...); - -ACPI_PRINTF_LIKE(3) -void ACPI_INTERNAL_VAR_XFACE -acpi_bios_warning(const char *module_name, - u32 line_number, const char *format, ...); +ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) + void ACPI_INTERNAL_VAR_XFACE + acpi_error(const char *module_name, + u32 line_number, + const char *format, ...)) +ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(4) + void ACPI_INTERNAL_VAR_XFACE + acpi_exception(const char *module_name, + u32 line_number, + acpi_status status, + const char *format, ...)) +ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) + void ACPI_INTERNAL_VAR_XFACE + acpi_warning(const char *module_name, + u32 line_number, + const char *format, ...)) +ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) + void ACPI_INTERNAL_VAR_XFACE + acpi_info(const char *module_name, + u32 line_number, + const char *format, ...)) +ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) + void ACPI_INTERNAL_VAR_XFACE + acpi_bios_error(const char *module_name, + u32 line_number, + const char *format, ...)) +ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) + void ACPI_INTERNAL_VAR_XFACE + acpi_bios_warning(const char *module_name, + u32 line_number, + const char *format, ...)) /* * Debug output */ #ifdef ACPI_DEBUG_OUTPUT - ACPI_PRINTF_LIKE(6) void ACPI_INTERNAL_VAR_XFACE acpi_debug_print(u32 requested_debug_level, From 1ce28c32d8deeca3cd53802e8cd710b9b4799398 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:04:55 +0800 Subject: [PATCH 049/134] ACPICA: OSL: Add configurability for debug output functions. This patch extends ACPI_HW_DEPENDENT_x mechanism to all debugging output related functions so that the OSPMs can have full control to configure them into stub functions. This patch doesn't include code for Linux to use this new mechanism, thus no functional change. Lv Zheng. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 49 +++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 39f432e513f2..923775a5e9e9 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -255,6 +255,21 @@ ACPI_GLOBAL(u8, acpi_gbl_system_awake_and_running); #endif /* ACPI_NO_ERROR_MESSAGES */ +/* + * Debugging-output prototypes. All interfaces that use these macros will + * be configured out of the ACPICA build if the ACPI_DEBUG_OUTPUT flag is + * not defined. + */ +#ifdef ACPI_DEBUG_OUTPUT +#define ACPI_DBG_DEPENDENT_RETURN_VOID(prototype) \ + prototype; + +#else +#define ACPI_DBG_DEPENDENT_RETURN_VOID(prototype) \ + static ACPI_INLINE prototype {return;} + +#endif /* ACPI_DEBUG_OUTPUT */ + /* * Initialization */ @@ -716,22 +731,20 @@ ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) /* * Debug output */ -#ifdef ACPI_DEBUG_OUTPUT -ACPI_PRINTF_LIKE(6) -void ACPI_INTERNAL_VAR_XFACE -acpi_debug_print(u32 requested_debug_level, - u32 line_number, - const char *function_name, - const char *module_name, - u32 component_id, const char *format, ...); - -ACPI_PRINTF_LIKE(6) -void ACPI_INTERNAL_VAR_XFACE -acpi_debug_print_raw(u32 requested_debug_level, - u32 line_number, - const char *function_name, - const char *module_name, - u32 component_id, const char *format, ...); -#endif - +ACPI_DBG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(6) + void ACPI_INTERNAL_VAR_XFACE + acpi_debug_print(u32 requested_debug_level, + u32 line_number, + const char *function_name, + const char *module_name, + u32 component_id, + const char *format, ...)) +ACPI_DBG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(6) + void ACPI_INTERNAL_VAR_XFACE + acpi_debug_print_raw(u32 requested_debug_level, + u32 line_number, + const char *function_name, + const char *module_name, + u32 component_id, + const char *format, ...)) #endif /* __ACXFACE_H__ */ From 0dedb3c43cae6968ef6c2351e081f38eced47bfa Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:05:02 +0800 Subject: [PATCH 050/134] ACPICA: OSL: Add section to collect the divergence in acpixf.h. This patch re-orders the interface prototypes defined in acpixf.h, moving those having not back ported to ACPICA into a seperate section to reduce the source code differences between Linux and ACPICA. This can help to reduce the cost of linuxizing the follow up commits. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 923775a5e9e9..7980c87643a5 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -338,17 +338,10 @@ acpi_status __init acpi_reallocate_root_table(void); acpi_status __init acpi_find_root_pointer(acpi_size *rsdp_address); -acpi_status acpi_unload_table_id(acpi_owner_id id); - acpi_status acpi_get_table_header(acpi_string signature, u32 instance, struct acpi_table_header *out_table_header); -acpi_status -acpi_get_table_with_size(acpi_string signature, - u32 instance, struct acpi_table_header **out_table, - acpi_size *tbl_size); - acpi_status acpi_get_table(acpi_string signature, u32 instance, struct acpi_table_header **out_table); @@ -390,10 +383,6 @@ acpi_attach_data(acpi_handle object, acpi_object_handler handler, void *data); acpi_status acpi_detach_data(acpi_handle object, acpi_object_handler handler); -acpi_status -acpi_get_data_full(acpi_handle object, acpi_object_handler handler, void **data, - void (*callback)(void *)); - acpi_status acpi_get_data(acpi_handle object, acpi_object_handler handler, void **data); @@ -429,8 +418,6 @@ acpi_get_next_object(acpi_object_type type, acpi_status acpi_get_type(acpi_handle object, acpi_object_type * out_type); -acpi_status acpi_get_id(acpi_handle object, acpi_owner_id * out_type); - acpi_status acpi_get_parent(acpi_handle object, acpi_handle * out_handle); /* @@ -747,4 +734,21 @@ ACPI_DBG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(6) const char *module_name, u32 component_id, const char *format, ...)) + +/* + * Divergences + */ +acpi_status acpi_get_id(acpi_handle object, acpi_owner_id * out_type); + +acpi_status acpi_unload_table_id(acpi_owner_id id); + +acpi_status +acpi_get_table_with_size(acpi_string signature, + u32 instance, struct acpi_table_header **out_table, + acpi_size *tbl_size); + +acpi_status +acpi_get_data_full(acpi_handle object, acpi_object_handler handler, void **data, + void (*callback)(void *)); + #endif /* __ACXFACE_H__ */ From 8b9c1152a018883f6f0b841e12e17671f2c64c32 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:05:08 +0800 Subject: [PATCH 051/134] ACPICA: OSL: Add configurability for generic external functions. OSPMs like Linux trend to include all header files but leave empty inline stub functions for a feature that is not configured during build. This patch adds wrappers mechanism to be used around ACPICA external interfaces to facilitate OSPM with such configurability. This patch doesn't include code for Linux to use this new mechanism, thus no functional change. Lv Zheng. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 467 +++++++++++++++++++++++++----------------- 1 file changed, 275 insertions(+), 192 deletions(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 7980c87643a5..ac04985017c5 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -81,6 +81,33 @@ extern u8 acpi_gbl_permanent_mmap; #endif #endif +/* ACPICA prototypes */ + +#ifndef ACPI_EXTERNAL_RETURN_STATUS +#define ACPI_EXTERNAL_RETURN_STATUS(prototype) \ + prototype; +#endif + +#ifndef ACPI_EXTERNAL_RETURN_OK +#define ACPI_EXTERNAL_RETURN_OK(prototype) \ + prototype; +#endif + +#ifndef ACPI_EXTERNAL_RETURN_VOID +#define ACPI_EXTERNAL_RETURN_VOID(prototype) \ + prototype; +#endif + +#ifndef ACPI_EXTERNAL_RETURN_UINT32 +#define ACPI_EXTERNAL_RETURN_UINT32(prototype) \ + prototype; +#endif + +#ifndef ACPI_EXTERNAL_RETURN_PTR +#define ACPI_EXTERNAL_RETURN_PTR(prototype) \ + prototype; +#endif + /* Public globals, available from outside ACPICA subsystem */ /***************************************************************************** @@ -220,13 +247,13 @@ ACPI_GLOBAL(u8, acpi_gbl_system_awake_and_running); */ #if (!ACPI_REDUCED_HARDWARE) #define ACPI_HW_DEPENDENT_RETURN_STATUS(prototype) \ - prototype; + ACPI_EXTERNAL_RETURN_STATUS(prototype) #define ACPI_HW_DEPENDENT_RETURN_OK(prototype) \ - prototype; + ACPI_EXTERNAL_RETURN_OK(prototype) #define ACPI_HW_DEPENDENT_RETURN_VOID(prototype) \ - prototype; + ACPI_EXTERNAL_RETURN_VOID(prototype) #else #define ACPI_HW_DEPENDENT_RETURN_STATUS(prototype) \ @@ -273,17 +300,18 @@ ACPI_GLOBAL(u8, acpi_gbl_system_awake_and_running); /* * Initialization */ -acpi_status __init -acpi_initialize_tables(struct acpi_table_desc *initial_storage, - u32 initial_table_count, u8 allow_resize); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init + acpi_initialize_tables(struct acpi_table_desc + *initial_storage, + u32 initial_table_count, + u8 allow_resize)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init acpi_initialize_subsystem(void)) -acpi_status __init acpi_initialize_subsystem(void); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init acpi_enable_subsystem(u32 flags)) -acpi_status __init acpi_enable_subsystem(u32 flags); - -acpi_status __init acpi_initialize_objects(u32 flags); - -acpi_status __init acpi_terminate(void); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init + acpi_initialize_objects(u32 flags)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init acpi_terminate(void)) /* * Miscellaneous global interfaces @@ -291,145 +319,170 @@ acpi_status __init acpi_terminate(void); ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable(void)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable(void)) #ifdef ACPI_FUTURE_USAGE -acpi_status acpi_subsystem_status(void); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_subsystem_status(void)) #endif #ifdef ACPI_FUTURE_USAGE -acpi_status acpi_get_system_info(struct acpi_buffer *ret_buffer); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_system_info(struct acpi_buffer + *ret_buffer)) #endif +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_statistics(struct acpi_statistics *stats)) +ACPI_EXTERNAL_RETURN_PTR(const char + *acpi_format_exception(acpi_status exception)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_purge_cached_objects(void)) -acpi_status acpi_get_statistics(struct acpi_statistics *stats); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_install_interface(acpi_string interface_name)) -const char *acpi_format_exception(acpi_status exception); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_remove_interface(acpi_string interface_name)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_update_interfaces(u8 action)) -acpi_status acpi_purge_cached_objects(void); - -acpi_status acpi_install_interface(acpi_string interface_name); - -acpi_status acpi_remove_interface(acpi_string interface_name); - -acpi_status acpi_update_interfaces(u8 action); - -u32 -acpi_check_address_range(acpi_adr_space_type space_id, - acpi_physical_address address, - acpi_size length, u8 warn); - -acpi_status -acpi_decode_pld_buffer(u8 *in_buffer, - acpi_size length, struct acpi_pld_info **return_buffer); +ACPI_EXTERNAL_RETURN_UINT32(u32 + acpi_check_address_range(acpi_adr_space_type + space_id, + acpi_physical_address + address, acpi_size length, + u8 warn)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_decode_pld_buffer(u8 *in_buffer, + acpi_size length, + struct acpi_pld_info + **return_buffer)) /* * ACPI table load/unload interfaces */ -acpi_status __init -acpi_install_table(acpi_physical_address address, u8 physical); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init + acpi_install_table(acpi_physical_address address, + u8 physical)) -acpi_status acpi_load_table(struct acpi_table_header *table); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_load_table(struct acpi_table_header *table)) -acpi_status acpi_unload_parent_table(acpi_handle object); - -acpi_status __init acpi_load_tables(void); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_unload_parent_table(acpi_handle object)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init acpi_load_tables(void)) /* * ACPI table manipulation interfaces */ -acpi_status __init acpi_reallocate_root_table(void); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init acpi_reallocate_root_table(void)) -acpi_status __init acpi_find_root_pointer(acpi_size *rsdp_address); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status __init + acpi_find_root_pointer(acpi_size * rsdp_address)) -acpi_status -acpi_get_table_header(acpi_string signature, - u32 instance, struct acpi_table_header *out_table_header); - -acpi_status -acpi_get_table(acpi_string signature, - u32 instance, struct acpi_table_header **out_table); - -acpi_status -acpi_get_table_by_index(u32 table_index, struct acpi_table_header **out_table); - -acpi_status -acpi_install_table_handler(acpi_table_handler handler, void *context); - -acpi_status acpi_remove_table_handler(acpi_table_handler handler); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_table_header(acpi_string signature, + u32 instance, + struct acpi_table_header + *out_table_header)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_table(acpi_string signature, u32 instance, + struct acpi_table_header + **out_table)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_table_by_index(u32 table_index, + struct acpi_table_header + **out_table)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_install_table_handler(acpi_table_handler + handler, void *context)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_remove_table_handler(acpi_table_handler + handler)) /* * Namespace and name interfaces */ -acpi_status -acpi_walk_namespace(acpi_object_type type, - acpi_handle start_object, - u32 max_depth, - acpi_walk_callback descending_callback, - acpi_walk_callback ascending_callback, - void *context, void **return_value); - -acpi_status -acpi_get_devices(const char *HID, - acpi_walk_callback user_function, - void *context, void **return_value); - -acpi_status -acpi_get_name(acpi_handle object, - u32 name_type, struct acpi_buffer *ret_path_ptr); - -acpi_status -acpi_get_handle(acpi_handle parent, - acpi_string pathname, acpi_handle * ret_handle); - -acpi_status -acpi_attach_data(acpi_handle object, acpi_object_handler handler, void *data); - -acpi_status acpi_detach_data(acpi_handle object, acpi_object_handler handler); - -acpi_status -acpi_get_data(acpi_handle object, acpi_object_handler handler, void **data); - -acpi_status -acpi_debug_trace(char *name, u32 debug_level, u32 debug_layer, u32 flags); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_walk_namespace(acpi_object_type type, + acpi_handle start_object, + u32 max_depth, + acpi_walk_callback + descending_callback, + acpi_walk_callback + ascending_callback, + void *context, + void **return_value)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_devices(const char *HID, + acpi_walk_callback user_function, + void *context, + void **return_value)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_name(acpi_handle object, u32 name_type, + struct acpi_buffer *ret_path_ptr)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_handle(acpi_handle parent, + acpi_string pathname, + acpi_handle * ret_handle)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_attach_data(acpi_handle object, + acpi_object_handler handler, + void *data)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_detach_data(acpi_handle object, + acpi_object_handler handler)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_data(acpi_handle object, + acpi_object_handler handler, + void **data)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_debug_trace(char *name, u32 debug_level, + u32 debug_layer, u32 flags)) /* * Object manipulation and enumeration */ -acpi_status -acpi_evaluate_object(acpi_handle object, - acpi_string pathname, - struct acpi_object_list *parameter_objects, - struct acpi_buffer *return_object_buffer); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_evaluate_object(acpi_handle object, + acpi_string pathname, + struct acpi_object_list + *parameter_objects, + struct acpi_buffer + *return_object_buffer)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_evaluate_object_typed(acpi_handle object, + acpi_string pathname, + struct acpi_object_list + *external_params, + struct acpi_buffer + *return_buffer, + acpi_object_type + return_type)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_object_info(acpi_handle object, + struct acpi_device_info + **return_buffer)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_install_method(u8 *buffer)) -acpi_status -acpi_evaluate_object_typed(acpi_handle object, - acpi_string pathname, - struct acpi_object_list *external_params, - struct acpi_buffer *return_buffer, - acpi_object_type return_type); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_next_object(acpi_object_type type, + acpi_handle parent, + acpi_handle child, + acpi_handle * out_handle)) -acpi_status -acpi_get_object_info(acpi_handle object, - struct acpi_device_info **return_buffer); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_type(acpi_handle object, + acpi_object_type * out_type)) -acpi_status acpi_install_method(u8 *buffer); - -acpi_status -acpi_get_next_object(acpi_object_type type, - acpi_handle parent, - acpi_handle child, acpi_handle * out_handle); - -acpi_status acpi_get_type(acpi_handle object, acpi_object_type * out_type); - -acpi_status acpi_get_parent(acpi_handle object, acpi_handle * out_handle); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_parent(acpi_handle object, + acpi_handle * out_handle)) /* * Handler interfaces */ -acpi_status -acpi_install_initialization_handler(acpi_init_handler handler, u32 function); - +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_install_initialization_handler + (acpi_init_handler handler, u32 function)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_install_sci_handler(acpi_sci_handler - address, - void *context)) + acpi_install_sci_handler(acpi_sci_handler + address, + void *context)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_remove_sci_handler(acpi_sci_handler address)) @@ -461,30 +514,42 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status u32 gpe_number, acpi_gpe_handler address)) -acpi_status acpi_install_notify_handler(acpi_handle device, u32 handler_type, - acpi_notify_handler handler, - void *context); - -acpi_status -acpi_remove_notify_handler(acpi_handle device, - u32 handler_type, acpi_notify_handler handler); - -acpi_status -acpi_install_address_space_handler(acpi_handle device, - acpi_adr_space_type space_id, - acpi_adr_space_handler handler, - acpi_adr_space_setup setup, void *context); - -acpi_status -acpi_remove_address_space_handler(acpi_handle device, - acpi_adr_space_type space_id, - acpi_adr_space_handler handler); - +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_install_notify_handler(acpi_handle device, + u32 handler_type, + acpi_notify_handler + handler, + void *context)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_remove_notify_handler(acpi_handle device, + u32 handler_type, + acpi_notify_handler + handler)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_install_address_space_handler(acpi_handle + device, + acpi_adr_space_type + space_id, + acpi_adr_space_handler + handler, + acpi_adr_space_setup + setup, + void *context)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_remove_address_space_handler(acpi_handle + device, + acpi_adr_space_type + space_id, + acpi_adr_space_handler + handler)) #ifdef ACPI_FUTURE_USAGE -acpi_status acpi_install_exception_handler(acpi_exception_handler handler); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_install_exception_handler + (acpi_exception_handler handler)) #endif - -acpi_status acpi_install_interface_handler(acpi_interface_handler handler); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_install_interface_handler + (acpi_interface_handler handler)) /* * Global Lock interfaces @@ -499,10 +564,14 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status /* * Interfaces to AML mutex objects */ -acpi_status -acpi_acquire_mutex(acpi_handle handle, acpi_string pathname, u16 timeout); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_acquire_mutex(acpi_handle handle, + acpi_string pathname, + u16 timeout)) -acpi_status acpi_release_mutex(acpi_handle handle, acpi_string pathname); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_release_mutex(acpi_handle handle, + acpi_string pathname)) /* * Fixed Event interfaces @@ -582,57 +651,69 @@ typedef acpi_status(*acpi_walk_resource_callback) (struct acpi_resource * resource, void *context); -acpi_status -acpi_get_vendor_resource(acpi_handle device, - char *name, - struct acpi_vendor_uuid *uuid, - struct acpi_buffer *ret_buffer); - -acpi_status -acpi_get_current_resources(acpi_handle device, struct acpi_buffer *ret_buffer); - +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_vendor_resource(acpi_handle device, + char *name, + struct acpi_vendor_uuid + *uuid, + struct acpi_buffer + *ret_buffer)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_current_resources(acpi_handle device, + struct acpi_buffer + *ret_buffer)) #ifdef ACPI_FUTURE_USAGE -acpi_status -acpi_get_possible_resources(acpi_handle device, struct acpi_buffer *ret_buffer); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_possible_resources(acpi_handle device, + struct acpi_buffer + *ret_buffer)) #endif - -acpi_status -acpi_get_event_resources(acpi_handle device_handle, - struct acpi_buffer *ret_buffer); - -acpi_status -acpi_walk_resource_buffer(struct acpi_buffer *buffer, - acpi_walk_resource_callback user_function, - void *context); - -acpi_status -acpi_walk_resources(acpi_handle device, - char *name, - acpi_walk_resource_callback user_function, void *context); - -acpi_status -acpi_set_current_resources(acpi_handle device, struct acpi_buffer *in_buffer); - -acpi_status -acpi_get_irq_routing_table(acpi_handle device, struct acpi_buffer *ret_buffer); - -acpi_status -acpi_resource_to_address64(struct acpi_resource *resource, - struct acpi_resource_address64 *out); - -acpi_status -acpi_buffer_to_resource(u8 *aml_buffer, - u16 aml_buffer_length, - struct acpi_resource **resource_ptr); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_event_resources(acpi_handle device_handle, + struct acpi_buffer + *ret_buffer)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_walk_resource_buffer(struct acpi_buffer + *buffer, + acpi_walk_resource_callback + user_function, + void *context)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_walk_resources(acpi_handle device, char *name, + acpi_walk_resource_callback + user_function, void *context)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_set_current_resources(acpi_handle device, + struct acpi_buffer + *in_buffer)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_irq_routing_table(acpi_handle device, + struct acpi_buffer + *ret_buffer)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_resource_to_address64(struct acpi_resource + *resource, + struct + acpi_resource_address64 + *out)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_buffer_to_resource(u8 *aml_buffer, + u16 aml_buffer_length, + struct acpi_resource + **resource_ptr)) /* * Hardware (ACPI device) interfaces */ -acpi_status acpi_reset(void); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_reset(void)) -acpi_status acpi_read(u64 *value, struct acpi_generic_address *reg); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_read(u64 *value, + struct acpi_generic_address *reg)) -acpi_status acpi_write(u64 value, struct acpi_generic_address *reg); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_write(u64 value, + struct acpi_generic_address *reg)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_read_bit_register(u32 register_id, @@ -645,18 +726,20 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status /* * Sleep/Wake interfaces */ -acpi_status -acpi_get_sleep_type_data(u8 sleep_state, u8 *slp_typ_a, u8 *slp_typ_b); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_get_sleep_type_data(u8 sleep_state, + u8 *slp_typ_a, + u8 *slp_typ_b)) -acpi_status acpi_enter_sleep_state_prep(u8 sleep_state); - -acpi_status acpi_enter_sleep_state(u8 sleep_state); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_enter_sleep_state_prep(u8 sleep_state)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_enter_sleep_state(u8 sleep_state)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enter_sleep_state_s4bios(void)) -acpi_status acpi_leave_sleep_state_prep(u8 sleep_state); - -acpi_status acpi_leave_sleep_state(u8 sleep_state); +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_leave_sleep_state_prep(u8 sleep_state)) +ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_leave_sleep_state(u8 sleep_state)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_set_firmware_waking_vector(u32 From 42873a84a22f6ee089b720c817bb61aebeff6e0d Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:05:15 +0800 Subject: [PATCH 052/134] ACPICA: Linux header: Add support for stubbed externals. Linux wants to include all header files but leave empty inline stub variables for a feature that is not configured during build. This patch configures ACPICA external globals/macros/functions out and defines them into no-op when CONFIG_ACPI is not enabled. Lv Zheng. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- include/acpi/platform/aclinux.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index f2429094b9b9..4c2f9e78001c 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -73,6 +73,37 @@ #endif #include +#ifndef CONFIG_ACPI + +/* External globals for __KERNEL__, stubs is needed */ + +#define ACPI_GLOBAL(t,a) +#define ACPI_INIT_GLOBAL(t,a,b) + +/* Generating stubs for configurable ACPICA macros */ + +#define ACPI_NO_MEM_ALLOCATIONS + +/* Generating stubs for configurable ACPICA functions */ + +#define ACPI_NO_ERROR_MESSAGES +#undef ACPI_DEBUG_OUTPUT + +/* External interface for __KERNEL__, stub is needed */ + +#define ACPI_EXTERNAL_RETURN_STATUS(prototype) \ + static ACPI_INLINE prototype {return(AE_NOT_CONFIGURED);} +#define ACPI_EXTERNAL_RETURN_OK(prototype) \ + static ACPI_INLINE prototype {return(AE_OK);} +#define ACPI_EXTERNAL_RETURN_VOID(prototype) \ + static ACPI_INLINE prototype {return;} +#define ACPI_EXTERNAL_RETURN_UINT32(prototype) \ + static ACPI_INLINE prototype {return(0);} +#define ACPI_EXTERNAL_RETURN_PTR(prototype) \ + static ACPI_INLINE prototype {return(NULL);} + +#endif /* CONFIG_ACPI */ + /* Host-dependent types and defines for in-kernel ACPICA */ #define ACPI_MACHINE_WIDTH BITS_PER_LONG From d63f37901e0977857dc19764c0ada1768ce4415d Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:05:21 +0800 Subject: [PATCH 053/134] ACPICA: acpidump: Fix truncated RSDP signature validation. This patch enforces a rule to always use ACPI_VALIDATE_RSDP_SIG for RSDP signatures passed from table header or ACPI_SIG_RSDP so that truncated string comparison can be avoided. This could help to fix the issue that "RSD " matches but "RSD PTR " doesn't match. Lv Zheng. Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- .../os_specific/service_layers/oslinuxtbl.c | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c index dc6509884c25..a8cd344d621b 100644 --- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c @@ -996,10 +996,21 @@ osl_map_table(acpi_size address, /* If specified, signature must match */ - if (signature && !ACPI_COMPARE_NAME(signature, mapped_table->signature)) { - acpi_os_unmap_memory(mapped_table, - sizeof(struct acpi_table_header)); - return (AE_BAD_SIGNATURE); + if (signature) { + if (ACPI_VALIDATE_RSDP_SIG(signature)) { + if (!ACPI_VALIDATE_RSDP_SIG(mapped_table->signature)) { + acpi_os_unmap_memory(mapped_table, + sizeof(struct + acpi_table_header)); + return (AE_BAD_SIGNATURE); + } + } else + if (!ACPI_COMPARE_NAME(signature, mapped_table->signature)) + { + acpi_os_unmap_memory(mapped_table, + sizeof(struct acpi_table_header)); + return (AE_BAD_SIGNATURE); + } } /* Map the entire table */ @@ -1135,12 +1146,22 @@ osl_read_table_from_file(char *filename, /* If signature is specified, it must match the table */ - if (signature && !ACPI_COMPARE_NAME(signature, header.signature)) { - fprintf(stderr, - "Incorrect signature: Expecting %4.4s, found %4.4s\n", - signature, header.signature); - status = AE_BAD_SIGNATURE; - goto exit; + if (signature) { + if (ACPI_VALIDATE_RSDP_SIG(signature)) { + if (!ACPI_VALIDATE_RSDP_SIG(header.signature)) { + fprintf(stderr, + "Incorrect RSDP signature: found %8.8s\n", + header.signature); + status = AE_BAD_SIGNATURE; + goto exit; + } + } else if (!ACPI_COMPARE_NAME(signature, header.signature)) { + fprintf(stderr, + "Incorrect signature: Expecting %4.4s, found %4.4s\n", + signature, header.signature); + status = AE_BAD_SIGNATURE; + goto exit; + } } table_length = ap_get_table_length(&header); From e57db4093da567215bcfb10b98ac5f3fc210b1e3 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 30 Apr 2014 10:05:27 +0800 Subject: [PATCH 054/134] ACPICA: Back port of _PRP update. This patch is the linuxize result of the following commit: Subject: ACPICA: Add check for _PRP/_HID dependency, with error message. _PRP requires that a _HID appears in the same scope. The iASL changes are not in this patch as iASL currently is not shipped in the kernel. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acnames.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h index 3dd6e838dc30..f0e713fadb1f 100644 --- a/include/acpi/acnames.h +++ b/include/acpi/acnames.h @@ -55,6 +55,7 @@ #define METHOD_NAME__HID "_HID" #define METHOD_NAME__INI "_INI" #define METHOD_NAME__PLD "_PLD" +#define METHOD_NAME__PRP "_PRP" #define METHOD_NAME__PRS "_PRS" #define METHOD_NAME__PRT "_PRT" #define METHOD_NAME__PRW "_PRW" From fea79bc01cb184432309148af9bf53a961a4d920 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 30 Apr 2014 10:05:34 +0800 Subject: [PATCH 055/134] ACPICA: Back port of improvements on exception code. This is the linuxize result of the following commit: Subject: ACPICA: Improve handling of exception code blocks. Split exception codes into three distinct blocks; for the main ASL compiler, Table compiler, and the preprocessor. This allows easy addition of new codes into each block without disturbing the others. Adds one new file, aslmessages.c The iASL changes are not in this patch as iASL currently is not shipped in the kernel. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index ac04985017c5..2d074ba1db42 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -207,7 +207,7 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_install, FALSE); /* * We keep track of the latest version of Windows that has been requested by - * the BIOS. ACPI 5.0. + * the BIOS. ACPI 5.0. */ ACPI_INIT_GLOBAL(u8, acpi_gbl_osi_data, 0); From c79322677d95c7cab65e02828677b43d8656eb61 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:05:48 +0800 Subject: [PATCH 056/134] ACPICA: acpidump: Add support to force using RSDT. This patch adds "-x" and "-x -x" options to disable XSDT for acpidump. The single "-x" can be used to stop using XSDT, RSDT will be forced to find static tables, note that XSDT will still be dumped. The double "-x" can stop dumping XSDT, which is useful when the XSDT address reported by RSDP is pointing to an invalid address. It is reported there are platforms having broken XSDT shipped, acpidump will stop working while accessing such XSDT. This patch adds new option so that users can force acpidump to dump tables listed in the RSDT. Lv Zheng. Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=73911 Buglink: https://bugs.archlinux.org/task/39811 Signed-off-by: Lv Zheng Reported-and-tested-by: Bruce Chiarelli Reported-and-tested-by: Spyros Stathopoulos Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- .../os_specific/service_layers/oslinuxtbl.c | 32 ++++++++++++++++--- tools/power/acpi/tools/acpidump/acpidump.h | 27 ++++++++-------- tools/power/acpi/tools/acpidump/apmain.c | 13 +++++++- 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c index a8cd344d621b..e0699e6e1f26 100644 --- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c @@ -503,6 +503,28 @@ static acpi_status osl_load_rsdp(void) return (AE_OK); } +/****************************************************************************** + * + * FUNCTION: osl_can_use_xsdt + * + * PARAMETERS: None + * + * RETURN: TRUE if XSDT is allowed to be used. + * + * DESCRIPTION: This function collects logic that can be used to determine if + * XSDT should be used instead of RSDT. + * + *****************************************************************************/ + +static u8 osl_can_use_xsdt(void) +{ + if (gbl_revision && !acpi_gbl_do_not_use_xsdt) { + return (TRUE); + } else { + return (FALSE); + } +} + /****************************************************************************** * * FUNCTION: osl_table_initialize @@ -535,7 +557,7 @@ static acpi_status osl_table_initialize(void) /* Get XSDT from memory */ - if (gbl_rsdp.revision) { + if (gbl_rsdp.revision && !gbl_do_not_dump_xsdt) { if (gbl_xsdt) { free(gbl_xsdt); gbl_xsdt = NULL; @@ -668,7 +690,7 @@ static acpi_status osl_list_bios_tables(void) acpi_status status = AE_OK; u32 i; - if (gbl_revision) { + if (osl_can_use_xsdt()) { item_size = sizeof(u64); table_data = ACPI_CAST8(gbl_xsdt) + sizeof(struct acpi_table_header); @@ -690,7 +712,7 @@ static acpi_status osl_list_bios_tables(void) /* Search RSDT/XSDT for the requested table */ for (i = 0; i < number_of_tables; ++i, table_data += item_size) { - if (gbl_revision) { + if (osl_can_use_xsdt()) { table_address = (acpi_physical_address) (*ACPI_CAST64(table_data)); } else { @@ -809,7 +831,7 @@ osl_get_bios_table(char *signature, table_length = ap_get_table_length(mapped_table); } else { /* Case for a normal ACPI table */ - if (gbl_revision) { + if (osl_can_use_xsdt()) { item_size = sizeof(u64); table_data = ACPI_CAST8(gbl_xsdt) + @@ -833,7 +855,7 @@ osl_get_bios_table(char *signature, /* Search RSDT/XSDT for the requested table */ for (i = 0; i < number_of_tables; ++i, table_data += item_size) { - if (gbl_revision) { + if (osl_can_use_xsdt()) { table_address = (acpi_physical_address) (*ACPI_CAST64 (table_data)); diff --git a/tools/power/acpi/tools/acpidump/acpidump.h b/tools/power/acpi/tools/acpidump/acpidump.h index 3361b9e04d9c..46f519597fe5 100644 --- a/tools/power/acpi/tools/acpidump/acpidump.h +++ b/tools/power/acpi/tools/acpidump/acpidump.h @@ -41,6 +41,18 @@ * POSSIBILITY OF SUCH DAMAGES. */ +/* + * Global variables. Defined in main.c only, externed in all other files + */ +#ifdef _DECLARE_GLOBALS +#define EXTERN +#define INIT_GLOBAL(a,b) a=b +#define DEFINE_ACPI_GLOBALS 1 +#else +#define EXTERN extern +#define INIT_GLOBAL(a,b) a +#endif + #include #include "accommon.h" #include "actables.h" @@ -50,23 +62,13 @@ #include #include -/* - * Global variables. Defined in main.c only, externed in all other files - */ -#ifdef _DECLARE_GLOBALS -#define EXTERN -#define INIT_GLOBAL(a,b) a=b -#else -#define EXTERN extern -#define INIT_GLOBAL(a,b) a -#endif - /* Globals */ EXTERN u8 INIT_GLOBAL(gbl_summary_mode, FALSE); EXTERN u8 INIT_GLOBAL(gbl_verbose_mode, FALSE); EXTERN u8 INIT_GLOBAL(gbl_binary_mode, FALSE); EXTERN u8 INIT_GLOBAL(gbl_dump_customized_tables, FALSE); +EXTERN u8 INIT_GLOBAL(gbl_do_not_dump_xsdt, FALSE); EXTERN FILE INIT_GLOBAL(*gbl_output_file, NULL); EXTERN char INIT_GLOBAL(*gbl_output_filename, NULL); EXTERN u64 INIT_GLOBAL(gbl_rsdp_base, 0); @@ -74,10 +76,7 @@ EXTERN u64 INIT_GLOBAL(gbl_rsdp_base, 0); /* Globals required for use with ACPICA modules */ #ifdef _DECLARE_GLOBALS -u8 acpi_gbl_enable_interpreter_slack = FALSE; u8 acpi_gbl_integer_byte_width = 8; -u32 acpi_dbg_level = 0; -u32 acpi_dbg_layer = 0; #endif /* Action table used to defer requested options */ diff --git a/tools/power/acpi/tools/acpidump/apmain.c b/tools/power/acpi/tools/acpidump/apmain.c index 70d71ec687a5..51e8d638db18 100644 --- a/tools/power/acpi/tools/acpidump/apmain.c +++ b/tools/power/acpi/tools/acpidump/apmain.c @@ -80,7 +80,7 @@ struct ap_dump_action action_table[AP_MAX_ACTIONS]; u32 current_action = 0; #define AP_UTILITY_NAME "ACPI Binary Table Dump Utility" -#define AP_SUPPORTED_OPTIONS "?a:bcf:hn:o:r:svz" +#define AP_SUPPORTED_OPTIONS "?a:bcf:hn:o:r:svxz" /****************************************************************************** * @@ -109,6 +109,8 @@ static void ap_display_usage(void) ACPI_OPTION("-a
", "Get table via a physical address"); ACPI_OPTION("-f ", "Get table via a binary file"); ACPI_OPTION("-n ", "Get table via a name/signature"); + ACPI_OPTION("-x", "Do not use but dump XSDT"); + ACPI_OPTION("-x -x", "Do not use or dump XSDT"); printf("\n" "Invocation without parameters dumps all available tables\n" @@ -210,6 +212,15 @@ static int ap_do_options(int argc, char **argv) gbl_summary_mode = TRUE; continue; + case 'x': /* Do not use XSDT */ + + if (!acpi_gbl_do_not_use_xsdt) { + acpi_gbl_do_not_use_xsdt = TRUE; + } else { + gbl_do_not_dump_xsdt = TRUE; + } + continue; + case 'v': /* Revision/version */ printf(ACPI_COMMON_SIGNON(AP_UTILITY_NAME)); From 0f929fbf0dc6ed21829a9fcd495838858df82291 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:05:56 +0800 Subject: [PATCH 057/134] ACPICA: Tables: Add new mechanism to skip NULL entries in RSDT and XSDT. It is reported that there are buggy BIOSes in the world: AMI uses an XSDT compiler for early BIOSes, this compiler will generate XSDT with a NULL entry. The affected BIOS versions are "AMI BIOS F2-F4". Original solution on Linux is to use an alternative heathy root table instead of the ill one. This commit is: Commit: 671cc68dc61f029d44b43a681356078e02d8dab8 Subject: ACPICA: Back port and refine validation of the XSDT root table. This is an example of such XSDT dumped from B85-HD3 (AMI F3 BIOS): [000h 0000 4] Signature : "XSDT" [Extended System Description Table] [004h 0004 4] Table Length : 00000074 [008h 0008 1] Revision : 01 [009h 0009 1] Checksum : 18 [00Ah 0010 6] Oem ID : "ALASKA" [010h 0016 8] Oem Table ID : "A M I" [018h 0024 4] Oem Revision : 01072009 [01Ch 0028 4] Asl Compiler ID : "AMI " [020h 0032 4] Asl Compiler Revision : 00010013 [024h 0036 8] ACPI Table Address 0 : 00000000BA5F8180 [02Ch 0044 8] ACPI Table Address 1 : 00000000BA5F8290 [034h 0052 8] ACPI Table Address 2 : 00000000BA5F8308 [03Ch 0060 8] ACPI Table Address 3 : 00000000BA5F8848 [044h 0068 8] ACPI Table Address 4 : 00000000BA5F9320 [04Ch 0076 8] ACPI Table Address 5 : 00000000BA5F9360 [054h 0084 8] ACPI Table Address 6 : 00000000BA5F9398 [05Ch 0092 8] ACPI Table Address 7 : 00000000BA5F9708 [064h d100 8] ACPI Table Address 8 : 00000000BA5FC9A8 [06Ch 0108 8] ACPI Table Address 9 : 0000000000000000 But according to the bug report, the XSDT in fact is not broken. In the above XSDT, ACPI Table Address 1-8 contains the same value as RSDT. The differences can only be seen on the following 2 entries: 1. The first entry points to a FADT whose Revision is 5 while the first entry in RSDT points to a FADT whose Revision is 2. The FADT dumped from the address indicated by the first entry of XSDT: FACP @ 0x00000000BA5F8180 0000: 46 41 43 50 0C 01 00 00<05>4B 41 4C 41 53 4B 41 FACP.....KALASKA ... The FADT dumped from the address indicated by the first entry of RSDT: FACP @ 0x00000000BA5ED0F0 0000: 46 41 43 50 84 00 00 00<02>A7 41 4C 41 53 4B 41 FACP......ALASKA ... 2. The last entry is a NULL terminator. According to the test result, the Revision 5 FADT is accessible. Thus the original solution turns out to be a work around that is preventing the higher revision tables to be used for such platforms (they are all x86-64 platforms, and should use XSDT and higher revision FADT). This patch offers a new solution, where a sanity check is performed before installing a table address from XSDT. If the entry is NULL, it is simply discarded. Note that, this patch doesn't remove the original solution, so for Linux kernel, this commit is actually a no-op, but it allows acpidump to be working on such platforms. By doing so, we allow another easy revertable commit to enable this feature so that when that commit is reverted, the useful sanity check will not be affected. Lv Zheng. References: https://bugzilla.kernel.org/show_bug.cgi?id=73911 References: https://bugs.archlinux.org/task/39811 Signed-off-by: Lv Zheng Reported-and-tested-by: Bruce Chiarelli Reported-and-tested-by: Spyros Stathopoulos Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/tbutils.c | 21 +++++++++++++------ .../os_specific/service_layers/oslinuxtbl.c | 12 +++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index e1638ad5db4c..801d1963d7d8 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -474,12 +474,19 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */ - status = - acpi_tb_install_standard_table(acpi_tb_get_root_table_entry - (table_entry, - table_entry_size), - ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, - FALSE, TRUE, &table_index); + address = + acpi_tb_get_root_table_entry(table_entry, table_entry_size); + + /* Skip NULL entries in RSDT/XSDT */ + + if (!address) { + goto next_table; + } + + status = acpi_tb_install_standard_table(address, + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, + FALSE, TRUE, + &table_index); if (ACPI_SUCCESS(status) && ACPI_COMPARE_NAME(&acpi_gbl_root_table_list. @@ -488,6 +495,8 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) acpi_tb_parse_fadt(table_index); } +next_table: + table_entry += table_entry_size; } diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c index e0699e6e1f26..ba7bad04dff1 100644 --- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c @@ -720,6 +720,12 @@ static acpi_status osl_list_bios_tables(void) (acpi_physical_address) (*ACPI_CAST32(table_data)); } + /* Skip NULL entries in RSDT/XSDT */ + + if (!table_address) { + continue; + } + status = osl_map_table(table_address, NULL, &mapped_table); if (ACPI_FAILURE(status)) { return (status); @@ -865,6 +871,12 @@ osl_get_bios_table(char *signature, (table_data)); } + /* Skip NULL entries in RSDT/XSDT */ + + if (!table_address) { + continue; + } + status = osl_map_table(table_address, NULL, &mapped_table); if (ACPI_FAILURE(status)) { From 57429a403eeaf4fe63e1a6956e3f57a673cfcd73 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:06:02 +0800 Subject: [PATCH 058/134] ACPICA: Tables: Remove old mechanism to validate if XSDT contains NULL entries. With the NULL entry sanity check implemented, the XSDT validation is useless because: 1. If XSDT contains NULL entries, it can be bypassed by the new sanity check mechanism; 2. If RSDP contains a bad XSDT address, invoking XSDT validation will still lead to a kernel crash. This patch deletes the old XSDT validation solution and thus enables the new NULL entry sanity check solution. Note that if there are reports reporting regressions caused by the enabling of the new feature and disabling of the old feature, this commit should be bisected and reverted. Lv Zheng. References: https://bugzilla.kernel.org/show_bug.cgi?id=73911 References: https://bugs.archlinux.org/task/39811 Signed-off-by: Lv Zheng Reported-and-tested-by: Bruce Chiarelli Reported-and-tested-by: Spyros Stathopoulos Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/tbutils.c | 105 ---------------------------------- 1 file changed, 105 deletions(-) diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 801d1963d7d8..e37a103013a4 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -49,8 +49,6 @@ ACPI_MODULE_NAME("tbutils") /* Local prototypes */ -static acpi_status acpi_tb_validate_xsdt(acpi_physical_address address); - static acpi_physical_address acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); @@ -249,87 +247,6 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size) } } -/******************************************************************************* - * - * FUNCTION: acpi_tb_validate_xsdt - * - * PARAMETERS: address - Physical address of the XSDT (from RSDP) - * - * RETURN: Status. AE_OK if the table appears to be valid. - * - * DESCRIPTION: Validate an XSDT to ensure that it is of minimum size and does - * not contain any NULL entries. A problem that is seen in the - * field is that the XSDT exists, but is actually useless because - * of one or more (or all) NULL entries. - * - ******************************************************************************/ - -static acpi_status acpi_tb_validate_xsdt(acpi_physical_address xsdt_address) -{ - struct acpi_table_header *table; - u8 *next_entry; - acpi_physical_address address; - u32 length; - u32 entry_count; - acpi_status status; - u32 i; - - /* Get the XSDT length */ - - table = - acpi_os_map_memory(xsdt_address, sizeof(struct acpi_table_header)); - if (!table) { - return (AE_NO_MEMORY); - } - - length = table->length; - acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); - - /* - * Minimum XSDT length is the size of the standard ACPI header - * plus one physical address entry - */ - if (length < (sizeof(struct acpi_table_header) + ACPI_XSDT_ENTRY_SIZE)) { - return (AE_INVALID_TABLE_LENGTH); - } - - /* Map the entire XSDT */ - - table = acpi_os_map_memory(xsdt_address, length); - if (!table) { - return (AE_NO_MEMORY); - } - - /* Get the number of entries and pointer to first entry */ - - status = AE_OK; - next_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header)); - entry_count = (u32)((table->length - sizeof(struct acpi_table_header)) / - ACPI_XSDT_ENTRY_SIZE); - - /* Validate each entry (physical address) within the XSDT */ - - for (i = 0; i < entry_count; i++) { - address = - acpi_tb_get_root_table_entry(next_entry, - ACPI_XSDT_ENTRY_SIZE); - if (!address) { - - /* Detected a NULL entry, XSDT is invalid */ - - status = AE_NULL_ENTRY; - break; - } - - next_entry += ACPI_XSDT_ENTRY_SIZE; - } - - /* Unmap table */ - - acpi_os_unmap_memory(table, length); - return (status); -} - /******************************************************************************* * * FUNCTION: acpi_tb_parse_root_table @@ -355,7 +272,6 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) u32 table_count; struct acpi_table_header *table; acpi_physical_address address; - acpi_physical_address rsdt_address; u32 length; u8 *table_entry; acpi_status status; @@ -384,14 +300,11 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) * as per the ACPI specification. */ address = (acpi_physical_address) rsdp->xsdt_physical_address; - rsdt_address = - (acpi_physical_address) rsdp->rsdt_physical_address; table_entry_size = ACPI_XSDT_ENTRY_SIZE; } else { /* Root table is an RSDT (32-bit physical addresses) */ address = (acpi_physical_address) rsdp->rsdt_physical_address; - rsdt_address = address; table_entry_size = ACPI_RSDT_ENTRY_SIZE; } @@ -401,24 +314,6 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) */ acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp)); - /* - * If it is present and used, validate the XSDT for access/size - * and ensure that all table entries are at least non-NULL - */ - if (table_entry_size == ACPI_XSDT_ENTRY_SIZE) { - status = acpi_tb_validate_xsdt(address); - if (ACPI_FAILURE(status)) { - ACPI_BIOS_WARNING((AE_INFO, - "XSDT is invalid (%s), using RSDT", - acpi_format_exception(status))); - - /* Fall back to the RSDT */ - - address = rsdt_address; - table_entry_size = ACPI_RSDT_ENTRY_SIZE; - } - } - /* Map the RSDT/XSDT table header to get the full table length */ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); From 21126b296e6f5f172e72da7cebb42b87fbd19b3a Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 30 Apr 2014 10:06:09 +0800 Subject: [PATCH 059/134] ACPICA: Remove extraneous error message for large number of GPEs. Fixes a problem where an extraneous error message was emitted during initialization if there is a GPE block larger than 255 bits. Any GPE block larger than 120 GPEs could generate the error. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/tbfadt.c | 51 +++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index a37af164b8c8..41519a958083 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -52,7 +52,8 @@ ACPI_MODULE_NAME("tbfadt") static void acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, u8 space_id, - u8 byte_width, u64 address, char *register_name); + u8 byte_width, + u64 address, char *register_name, u8 flags); static void acpi_tb_convert_fadt(void); @@ -69,13 +70,14 @@ typedef struct acpi_fadt_info { u16 address32; u16 length; u8 default_length; - u8 type; + u8 flags; } acpi_fadt_info; #define ACPI_FADT_OPTIONAL 0 #define ACPI_FADT_REQUIRED 1 #define ACPI_FADT_SEPARATE_LENGTH 2 +#define ACPI_FADT_GPE_REGISTER 4 static struct acpi_fadt_info fadt_info_table[] = { {"Pm1aEventBlock", @@ -125,14 +127,14 @@ static struct acpi_fadt_info fadt_info_table[] = { ACPI_FADT_OFFSET(gpe0_block), ACPI_FADT_OFFSET(gpe0_block_length), 0, - ACPI_FADT_SEPARATE_LENGTH}, + ACPI_FADT_SEPARATE_LENGTH | ACPI_FADT_GPE_REGISTER}, {"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block), ACPI_FADT_OFFSET(gpe1_block), ACPI_FADT_OFFSET(gpe1_block_length), 0, - ACPI_FADT_SEPARATE_LENGTH} + ACPI_FADT_SEPARATE_LENGTH | ACPI_FADT_GPE_REGISTER} }; #define ACPI_FADT_INFO_ENTRIES \ @@ -189,19 +191,29 @@ static struct acpi_fadt_pm_info fadt_pm_info_table[] = { static void acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, u8 space_id, - u8 byte_width, u64 address, char *register_name) + u8 byte_width, + u64 address, char *register_name, u8 flags) { u8 bit_width; - /* Bit width field in the GAS is only one byte long, 255 max */ - + /* + * Bit width field in the GAS is only one byte long, 255 max. + * Check for bit_width overflow in GAS. + */ bit_width = (u8)(byte_width * 8); - - if (byte_width > 31) { /* (31*8)=248 */ - ACPI_ERROR((AE_INFO, - "%s - 32-bit FADT register is too long (%u bytes, %u bits) " - "to convert to GAS struct - 255 bits max, truncating", - register_name, byte_width, (byte_width * 8))); + if (byte_width > 31) { /* (31*8)=248, (32*8)=256 */ + /* + * No error for GPE blocks, because we do not use the bit_width + * for GPEs, the legacy length (byte_width) is used instead to + * allow for a large number of GPEs. + */ + if (!(flags & ACPI_FADT_GPE_REGISTER)) { + ACPI_ERROR((AE_INFO, + "%s - 32-bit FADT register is too long (%u bytes, %u bits) " + "to convert to GAS struct - 255 bits max, truncating", + register_name, byte_width, + (byte_width * 8))); + } bit_width = 255; } @@ -450,6 +462,7 @@ static void acpi_tb_convert_fadt(void) struct acpi_generic_address *address64; u32 address32; u8 length; + u8 flags; u32 i; /* @@ -515,6 +528,7 @@ static void acpi_tb_convert_fadt(void) fadt_info_table[i].length); name = fadt_info_table[i].name; + flags = fadt_info_table[i].flags; /* * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" @@ -554,7 +568,7 @@ static void acpi_tb_convert_fadt(void) [i]. length), (u64)address32, - name); + name, flags); } else if (address64->address != (u64)address32) { /* Address mismatch */ @@ -582,7 +596,8 @@ static void acpi_tb_convert_fadt(void) length), (u64) address32, - name); + name, + flags); } } } @@ -603,7 +618,7 @@ static void acpi_tb_convert_fadt(void) address64->bit_width)); } - if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) { + if (fadt_info_table[i].flags & ACPI_FADT_REQUIRED) { /* * Field is required (Pm1a_event, Pm1a_control). * Both the address and length must be non-zero. @@ -617,7 +632,7 @@ static void acpi_tb_convert_fadt(void) address), length)); } - } else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) { + } else if (fadt_info_table[i].flags & ACPI_FADT_SEPARATE_LENGTH) { /* * Field is optional (Pm2_control, GPE0, GPE1) AND has its own * length field. If present, both the address and length must @@ -726,7 +741,7 @@ static void acpi_tb_setup_fadt_registers(void) (fadt_pm_info_table[i]. register_num * pm1_register_byte_width), - "PmRegisters"); + "PmRegisters", 0); } } } From 7505da4c3f90dd61302e825b005d08144c5de050 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 30 Apr 2014 10:06:15 +0800 Subject: [PATCH 060/134] ACPICA: Events: Update GPE handling and initialization code. 1) Eliminate most use of GAS structs, since they are not needed for GPEs. 2) Allow raw GPE numbers > 255. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acevents.h | 5 +++-- drivers/acpi/acpica/aclocal.h | 9 +++++---- drivers/acpi/acpica/evgpe.c | 13 +++++++------ drivers/acpi/acpica/evgpeblk.c | 34 ++++++++++++++++----------------- drivers/acpi/acpica/evgpeinit.c | 12 ++++++++---- drivers/acpi/acpica/evxfgpe.c | 7 ++++--- 6 files changed, 43 insertions(+), 37 deletions(-) diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 68ec61fff188..7a7811a9fc26 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -104,9 +104,10 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info); */ acpi_status acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, - struct acpi_generic_address *gpe_block_address, + u64 address, + u8 space_id, u32 register_count, - u8 gpe_block_base_number, + u16 gpe_block_base_number, u32 interrupt_number, struct acpi_gpe_block_info **return_gpe_block); diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index f68cb602dc23..91f801a2e689 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -450,9 +450,9 @@ struct acpi_gpe_event_info { struct acpi_gpe_register_info { struct acpi_generic_address status_address; /* Address of status reg */ struct acpi_generic_address enable_address; /* Address of enable reg */ + u16 base_gpe_number; /* Base GPE number for this register */ u8 enable_for_wake; /* GPEs to keep enabled when sleeping */ u8 enable_for_run; /* GPEs to keep enabled when running */ - u8 base_gpe_number; /* Base GPE number for this register */ }; /* @@ -466,11 +466,12 @@ struct acpi_gpe_block_info { struct acpi_gpe_xrupt_info *xrupt_block; /* Backpointer to interrupt block */ struct acpi_gpe_register_info *register_info; /* One per GPE register pair */ struct acpi_gpe_event_info *event_info; /* One for each GPE */ - struct acpi_generic_address block_address; /* Base address of the block */ + u64 address; /* Base address of the block */ u32 register_count; /* Number of register pairs in block */ u16 gpe_count; /* Number of individual GPEs in block */ - u8 block_base_number; /* Base GPE number for this block */ - u8 initialized; /* TRUE if this block is initialized */ + u16 block_base_number; /* Base GPE number for this block */ + u8 space_id; + u8 initialized; /* TRUE if this block is initialized */ }; /* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */ diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 955f83da68a5..48f70013b488 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -383,7 +383,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) if (!(gpe_register_info->enable_for_run | gpe_register_info->enable_for_wake)) { ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, - "Ignore disabled registers for GPE%02X-GPE%02X: " + "Ignore disabled registers for GPE %02X-%02X: " "RunEnable=%02X, WakeEnable=%02X\n", gpe_register_info-> base_gpe_number, @@ -416,7 +416,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) } ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, - "Read registers for GPE%02X-GPE%02X: Status=%02X, Enable=%02X, " + "Read registers for GPE %02X-%02X: Status=%02X, Enable=%02X, " "RunEnable=%02X, WakeEnable=%02X\n", gpe_register_info->base_gpe_number, gpe_register_info->base_gpe_number + @@ -706,7 +706,8 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, status = acpi_hw_clear_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "Unable to clear GPE%02X", gpe_number)); + "Unable to clear GPE %02X", + gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } } @@ -723,7 +724,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "Unable to disable GPE%02X", gpe_number)); + "Unable to disable GPE %02X", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } @@ -764,7 +765,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "Unable to queue handler for GPE%02X - event disabled", + "Unable to queue handler for GPE %02X - event disabled", gpe_number)); } break; @@ -776,7 +777,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, * a GPE to be enabled if it has no handler or method. */ ACPI_ERROR((AE_INFO, - "No handler or method for GPE%02X, disabling event", + "No handler or method for GPE %02X, disabling event", gpe_number)); break; diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index caaed3c673fd..d86699eea33c 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -252,21 +252,17 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) /* Init the register_info for this GPE register (8 GPEs) */ - this_register->base_gpe_number = - (u8) (gpe_block->block_base_number + - (i * ACPI_GPE_REGISTER_WIDTH)); + this_register->base_gpe_number = (u16) + (gpe_block->block_base_number + + (i * ACPI_GPE_REGISTER_WIDTH)); - this_register->status_address.address = - gpe_block->block_address.address + i; + this_register->status_address.address = gpe_block->address + i; this_register->enable_address.address = - gpe_block->block_address.address + i + - gpe_block->register_count; + gpe_block->address + i + gpe_block->register_count; - this_register->status_address.space_id = - gpe_block->block_address.space_id; - this_register->enable_address.space_id = - gpe_block->block_address.space_id; + this_register->status_address.space_id = gpe_block->space_id; + this_register->enable_address.space_id = gpe_block->space_id; this_register->status_address.bit_width = ACPI_GPE_REGISTER_WIDTH; this_register->enable_address.bit_width = @@ -334,9 +330,10 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) acpi_status acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, - struct acpi_generic_address *gpe_block_address, + u64 address, + u8 space_id, u32 register_count, - u8 gpe_block_base_number, + u16 gpe_block_base_number, u32 interrupt_number, struct acpi_gpe_block_info **return_gpe_block) { @@ -359,15 +356,14 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, /* Initialize the new GPE block */ + gpe_block->address = address; + gpe_block->space_id = space_id; gpe_block->node = gpe_device; gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH); gpe_block->initialized = FALSE; gpe_block->register_count = register_count; gpe_block->block_base_number = gpe_block_base_number; - ACPI_MEMCPY(&gpe_block->block_address, gpe_block_address, - sizeof(struct acpi_generic_address)); - /* * Create the register_info and event_info sub-structures * Note: disables and clears all GPEs in the block @@ -408,12 +404,14 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, } ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, - " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X\n", + " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n", (u32)gpe_block->block_base_number, (u32)(gpe_block->block_base_number + (gpe_block->gpe_count - 1)), gpe_device->name.ascii, gpe_block->register_count, - interrupt_number)); + interrupt_number, + interrupt_number == + acpi_gbl_FADT.sci_interrupt ? " (SCI)" : "")); /* Update global count of currently available GPEs */ diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index ae779c1e871d..49fc7effd961 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -131,8 +131,10 @@ acpi_status acpi_ev_gpe_initialize(void) /* Install GPE Block 0 */ status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, - &acpi_gbl_FADT.xgpe0_block, - register_count0, 0, + acpi_gbl_FADT.xgpe0_block. + address, + acpi_gbl_FADT.xgpe0_block. + space_id, register_count0, 0, acpi_gbl_FADT.sci_interrupt, &acpi_gbl_gpe_fadt_blocks[0]); @@ -169,8 +171,10 @@ acpi_status acpi_ev_gpe_initialize(void) status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, - &acpi_gbl_FADT.xgpe1_block, - register_count1, + acpi_gbl_FADT.xgpe1_block. + address, + acpi_gbl_FADT.xgpe1_block. + space_id, register_count1, acpi_gbl_FADT.gpe1_base, acpi_gbl_FADT. sci_interrupt, diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 20a1392ffe06..cb534faf5369 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -599,9 +599,10 @@ acpi_install_gpe_block(acpi_handle gpe_device, * For user-installed GPE Block Devices, the gpe_block_base_number * is always zero */ - status = - acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0, - interrupt_number, &gpe_block); + status = acpi_ev_create_gpe_block(node, gpe_block_address->address, + gpe_block_address->space_id, + register_count, 0, interrupt_number, + &gpe_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } From 1011080dd27ac61950afa43433c47e570e2146d7 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 30 Apr 2014 10:06:22 +0800 Subject: [PATCH 061/134] ACPICA: Comment/format update, no functional change. Add some additional commenting the the public acpixf.h file. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 75 +++++++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 2d074ba1db42..b3b21087a158 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -55,11 +55,17 @@ extern u8 acpi_gbl_permanent_mmap; -/* - * Ensure that the globals are actually defined and initialized only once. +/***************************************************************************** * - * The use of these macros allows a single list of globals (here) in order - * to simplify maintenance of the code. + * Macros used for ACPICA globals and configuration + * + ****************************************************************************/ + +/* + * Ensure that global variables are defined and initialized only once. + * + * The use of these macros allows for a single list of globals (here) + * in order to simplify maintenance of the code. */ #ifdef DEFINE_ACPI_GLOBALS #define ACPI_GLOBAL(type,name) \ @@ -81,8 +87,11 @@ extern u8 acpi_gbl_permanent_mmap; #endif #endif -/* ACPICA prototypes */ - +/* + * These macros configure the various ACPICA interfaces. They are + * useful for generating stub inline functions for features that are + * configured out of the current kernel or ACPICA application. + */ #ifndef ACPI_EXTERNAL_RETURN_STATUS #define ACPI_EXTERNAL_RETURN_STATUS(prototype) \ prototype; @@ -108,16 +117,14 @@ extern u8 acpi_gbl_permanent_mmap; prototype; #endif -/* Public globals, available from outside ACPICA subsystem */ - /***************************************************************************** * - * Runtime configuration (static defaults that can be overriden at runtime) + * Public globals and runtime configuration options * ****************************************************************************/ /* - * Enable "slack" in the AML interpreter? Default is FALSE, and the + * Enable "slack mode" of the AML interpreter? Default is FALSE, and the * interpreter strictly follows the ACPI specification. Setting to TRUE * allows the interpreter to ignore certain errors and/or bad AML constructs. * @@ -234,16 +241,34 @@ ACPI_INIT_GLOBAL(u32, acpi_dbg_level, ACPI_DEBUG_DEFAULT); ACPI_INIT_GLOBAL(u32, acpi_dbg_layer, 0); /* - * Globals that are publically available + * Other miscellaneous globals */ -ACPI_GLOBAL(u32, acpi_current_gpe_count); ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT); +ACPI_GLOBAL(u32, acpi_current_gpe_count); ACPI_GLOBAL(u8, acpi_gbl_system_awake_and_running); +/***************************************************************************** + * + * ACPICA public interface configuration. + * + * Interfaces that are configured out of the ACPICA build are replaced + * by inlined stubs by default. + * + ****************************************************************************/ + /* - * Hardware-reduced prototypes. All interfaces that use these macros will - * be configured out of the ACPICA build if the ACPI_REDUCED_HARDWARE flag + * Hardware-reduced prototypes (default: Not hardware reduced). + * + * All ACPICA hardware-related interfaces that use these macros will be + * configured out of the ACPICA build if the ACPI_REDUCED_HARDWARE flag * is set to TRUE. + * + * Note: This static build option for reduced hardware is intended to + * reduce ACPICA code size if desired or necessary. However, even if this + * option is not specified, the runtime behavior of ACPICA is dependent + * on the actual FADT reduced hardware flag (HW_REDUCED_ACPI). If set, + * the flag will enable similar behavior -- ACPICA will not attempt + * to access any ACPI-relate hardware (SCI, GPEs, Fixed Events, etc.) */ #if (!ACPI_REDUCED_HARDWARE) #define ACPI_HW_DEPENDENT_RETURN_STATUS(prototype) \ @@ -268,9 +293,11 @@ ACPI_GLOBAL(u8, acpi_gbl_system_awake_and_running); #endif /* !ACPI_REDUCED_HARDWARE */ /* - * Error-message prototypes. All interfaces that use these macros will - * be configured out of the ACPICA build if the ACPI_NO_ERROR_MESSAGE flag - * is defined. + * Error message prototypes (default: error messages enabled). + * + * All interfaces related to error and warning messages + * will be configured out of the ACPICA build if the + * ACPI_NO_ERROR_MESSAGE flag is defined. */ #ifndef ACPI_NO_ERROR_MESSAGES #define ACPI_MSG_DEPENDENT_RETURN_VOID(prototype) \ @@ -283,9 +310,11 @@ ACPI_GLOBAL(u8, acpi_gbl_system_awake_and_running); #endif /* ACPI_NO_ERROR_MESSAGES */ /* - * Debugging-output prototypes. All interfaces that use these macros will - * be configured out of the ACPICA build if the ACPI_DEBUG_OUTPUT flag is - * not defined. + * Debugging output prototypes (default: no debug output). + * + * All interfaces related to debug output messages + * will be configured out of the ACPICA build unless the + * ACPI_DEBUG_OUTPUT flag is defined. */ #ifdef ACPI_DEBUG_OUTPUT #define ACPI_DBG_DEPENDENT_RETURN_VOID(prototype) \ @@ -297,6 +326,12 @@ ACPI_GLOBAL(u8, acpi_gbl_system_awake_and_running); #endif /* ACPI_DEBUG_OUTPUT */ +/***************************************************************************** + * + * ACPICA public interface prototypes + * + ****************************************************************************/ + /* * Initialization */ From bc381eebd4b246d6cc29d97ab34d2c54ecc40a87 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 30 Apr 2014 10:06:30 +0800 Subject: [PATCH 062/134] ACPICA: Update version to 20140424. Version 20140424. Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index b3b21087a158..4e3044ca4855 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20140325 +#define ACPI_CA_VERSION 0x20140424 #include #include From d0103387bc21644d297cb61ee623c7114e395575 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 1 May 2014 01:16:06 +0200 Subject: [PATCH 063/134] ACPI / notify: Clean up handling of hotplug events Make the handling of hotplug events in acpi_bus_notify() slightly cleaner by using an extra local variable to indicate when acpi_hotplug_schedule() should be called. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index cf925c4f36b7..610261a1b6c8 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -340,16 +340,18 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) { struct acpi_device *adev; struct acpi_driver *driver; - acpi_status status; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; + bool hotplug_event = false; switch (type) { case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); + hotplug_event = true; break; case ACPI_NOTIFY_DEVICE_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); + hotplug_event = true; break; case ACPI_NOTIFY_DEVICE_WAKE: @@ -358,6 +360,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); + hotplug_event = true; break; case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: @@ -393,16 +396,9 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) driver->ops.notify(adev, type); - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - case ACPI_NOTIFY_DEVICE_CHECK: - case ACPI_NOTIFY_EJECT_REQUEST: - status = acpi_hotplug_schedule(adev, type); - if (ACPI_SUCCESS(status)) - return; - default: - break; - } + if (hotplug_event && ACPI_SUCCESS(acpi_hotplug_schedule(adev, type))) + return; + acpi_bus_put_acpi_device(adev); return; From 886129a8eebebec260165741fe31421482371006 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 6 May 2014 14:46:23 +0200 Subject: [PATCH 064/134] ACPI / video: change acpi-video brightness_switch_enabled default to 0 acpi-video is unique in that it not only generates brightness up/down keypresses, but also (sometimes) actively changes the brightness itself. This presents an inconsistent kernel interface to userspace, basically there are 2 different scenarios, depending on the laptop model: 1) On some laptops a brightness up/down keypress means: show a brightness osd with the current brightness, iow it is a brightness has changed notification. 2) Where as on (a lot of) other laptops it means a brightness up/down key was pressed, deal with it. Most of the desktop environments interpret any press as in scenario 2, and change the brightness up / down as a response to the key events, causing it to be changed twice, once by acpi-video and once by the DE. With the new default for video.use_native_backlight we will be moving even more laptops over to behaving as in scenario 2. Making the remaining laptops even more of a weird exception. Also note that it is hard to detect scenario 1 properly in userspace, and AFAIK none of the DE-s deals with it. Therefor this commit changes the default of brightness_switch_enabled to 0 making its behavior consistent with all the other backlight drivers. Signed-off-by: Hans de Goede Reviewed-by: Aaron Lu Signed-off-by: Rafael J. Wysocki --- Documentation/kernel-parameters.txt | 2 +- drivers/acpi/video.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 43842177b771..cc2c243ac781 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3461,7 +3461,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. the allocated input device; If set to 0, video driver will only send out the event without touching backlight brightness level. - default: 1 + default: 0 virtio_mmio.device= [VMMIO] Memory mapped virtio (platform) device. diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 88393899a0bc..fced27d8e42f 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 = 1; +static bool brightness_switch_enabled; module_param(brightness_switch_enabled, bool, 0644); /* From 6b90f55f63c75c2c65454aea6703c2ea91b9e372 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Tue, 6 May 2014 11:24:30 +0800 Subject: [PATCH 065/134] ACPI / PCI: Stub out pci_acpi_crs_quirks() and make it x86 specific For pci_acpi_crs_quirks(), ia64 already doesn't use it, and we can not foresee it should be used in ARM64, so stub out pci_acpi_crs_quirks() to avoid introducing platform specific dummy stub function. Signed-off-by: Hanjun Guo Reviewed-by: Bjorn Helgaas Signed-off-by: Rafael J. Wysocki --- arch/ia64/include/asm/acpi.h | 1 - include/acpi/acpi_drivers.h | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/ia64/include/asm/acpi.h b/arch/ia64/include/asm/acpi.h index d651102a4d45..97cb16086314 100644 --- a/arch/ia64/include/asm/acpi.h +++ b/arch/ia64/include/asm/acpi.h @@ -92,7 +92,6 @@ ia64_acpi_release_global_lock (unsigned int *lock) #endif #define acpi_processor_cstate_check(x) (x) /* no idle limits on IA64 :) */ static inline void disable_acpi(void) { } -static inline void pci_acpi_crs_quirks(void) { } #ifdef CONFIG_IA64_GENERIC const char *acpi_get_sysname (void); diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index d504613bbf80..ea6428b7dacb 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -96,7 +96,12 @@ struct pci_dev *acpi_get_pci_dev(acpi_handle); /* Arch-defined function to add a bus to the system */ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root); + +#ifdef CONFIG_X86 void pci_acpi_crs_quirks(void); +#else +static inline void pci_acpi_crs_quirks(void) { } +#endif /* -------------------------------------------------------------------------- Processor From a6220fc19afc07fe77cfd16f5b8e568615517091 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 5 May 2014 00:51:54 +0200 Subject: [PATCH 066/134] PM / suspend: Always use deepest C-state in the "freeze" sleep state If freeze_enter() is called, we want to bypass the current cpuidle governor and always use the deepest available (that is, not disabled) C-state, because we want to save as much energy as reasonably possible then and runtime latency constraints don't matter at that point, since the system is in a sleep state anyway. Signed-off-by: Rafael J. Wysocki Tested-by: Aubrey Li --- drivers/cpuidle/cpuidle.c | 45 ++++++++++++++++++++++++++++++++++++++- include/linux/cpuidle.h | 2 ++ kernel/power/suspend.c | 2 ++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index f38359f64cc6..cb7019977c50 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -32,6 +32,7 @@ LIST_HEAD(cpuidle_detected_devices); static int enabled_devices; static int off __read_mostly; static int initialized __read_mostly; +static bool use_deepest_state __read_mostly; int cpuidle_disabled(void) { @@ -64,6 +65,45 @@ int cpuidle_play_dead(void) return -ENODEV; } +/** + * cpuidle_use_deepest_state - Enable/disable the "deepest idle" mode. + * @enable: Whether enable or disable the feature. + * + * If the "deepest idle" mode is enabled, cpuidle will ignore the governor and + * always use the state with the greatest exit latency (out of the states that + * are not disabled). + * + * This function can only be called after cpuidle_pause() to avoid races. + */ +void cpuidle_use_deepest_state(bool enable) +{ + use_deepest_state = enable; +} + +/** + * cpuidle_find_deepest_state - Find the state of the greatest exit latency. + * @drv: cpuidle driver for a given CPU. + * @dev: cpuidle device for a given CPU. + */ +static int cpuidle_find_deepest_state(struct cpuidle_driver *drv, + struct cpuidle_device *dev) +{ + unsigned int latency_req = 0; + int i, ret = CPUIDLE_DRIVER_STATE_START - 1; + + for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { + struct cpuidle_state *s = &drv->states[i]; + struct cpuidle_state_usage *su = &dev->states_usage[i]; + + if (s->disabled || su->disable || s->exit_latency <= latency_req) + continue; + + latency_req = s->exit_latency; + ret = i; + } + return ret; +} + /** * cpuidle_enter_state - enter the state and update stats * @dev: cpuidle device for this cpu @@ -124,6 +164,9 @@ int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) if (!drv || !dev || !dev->enabled) return -EBUSY; + if (unlikely(use_deepest_state)) + return cpuidle_find_deepest_state(drv, dev); + return cpuidle_curr_governor->select(drv, dev); } @@ -155,7 +198,7 @@ int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev, */ void cpuidle_reflect(struct cpuidle_device *dev, int index) { - if (cpuidle_curr_governor->reflect) + if (cpuidle_curr_governor->reflect && !unlikely(use_deepest_state)) cpuidle_curr_governor->reflect(dev, index); } diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index a8d5bd391a26..c51a436135c4 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -143,6 +143,7 @@ extern void cpuidle_resume(void); extern int cpuidle_enable_device(struct cpuidle_device *dev); extern void cpuidle_disable_device(struct cpuidle_device *dev); extern int cpuidle_play_dead(void); +extern void cpuidle_use_deepest_state(bool enable); extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev); #else @@ -175,6 +176,7 @@ static inline int cpuidle_enable_device(struct cpuidle_device *dev) {return -ENODEV; } static inline void cpuidle_disable_device(struct cpuidle_device *dev) { } static inline int cpuidle_play_dead(void) {return -ENODEV; } +static inline void cpuidle_use_deepest_state(bool enable) {} static inline struct cpuidle_driver *cpuidle_get_cpu_driver( struct cpuidle_device *dev) {return NULL; } #endif diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 8233cd4047d7..155721f7f909 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -54,9 +54,11 @@ static void freeze_begin(void) static void freeze_enter(void) { + cpuidle_use_deepest_state(true); cpuidle_resume(); wait_event(suspend_freeze_wait_head, suspend_freeze_wake); cpuidle_pause(); + cpuidle_use_deepest_state(false); } void freeze_wake(void) From 8a54cd5bd6ebf009b96ec79510b593f7ba5c0ff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 6 May 2014 13:01:56 +0200 Subject: [PATCH 067/134] PM / hibernate: Documentation: Fix script for unswapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit System can have mmaped also character devices (e.g dri devices by X) or deleted files. Running cat on character devices is really bad idea (system can hang) so run cat only on regular files. Also mmaped files can have spaces in filenames. Signed-off-by: Pali Rohár [rjw: Subject] Signed-off-by: Rafael J. Wysocki --- Documentation/power/swsusp.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt index 079160e22bcc..f732a8321e8a 100644 --- a/Documentation/power/swsusp.txt +++ b/Documentation/power/swsusp.txt @@ -220,7 +220,10 @@ Q: After resuming, system is paging heavily, leading to very bad interactivity. A: Try running -cat `cat /proc/[0-9]*/maps | grep / | sed 's:.* /:/:' | sort -u` > /dev/null +cat /proc/[0-9]*/maps | grep / | sed 's:.* /:/:' | sort -u | while read file +do + test -f "$file" && cat "$file" > /dev/null +done after resume. swapoff -a; swapon -a may also be useful. From 317cf7e5e85e3ef9f23fc6dd8b2945ab4a258140 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 9 May 2014 23:32:08 +0200 Subject: [PATCH 068/134] PM / hibernate: convert simple_strtoul to kstrtoul Replace obsolete function. Signed-off-by: Fabian Frederick Signed-off-by: Andrew Morton Signed-off-by: Rafael J. Wysocki --- kernel/power/hibernate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 1f08ac7f55d8..2377ff72994c 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -1115,7 +1115,10 @@ static int __init resumewait_setup(char *str) static int __init resumedelay_setup(char *str) { - resume_delay = simple_strtoul(str, NULL, 0); + int rc = kstrtoul(str, 0, (unsigned long *)&resume_delay); + + if (rc) + return rc; return 1; } From fad16dd9c962229c5965ec6f5cd5f48180f94fd4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 8 May 2014 23:22:15 +0200 Subject: [PATCH 069/134] ACPI / PM: Export acpi_target_system_state() to modules Export the acpi_target_system_state() function to modules so that modular drivers can use it to check what the target ACPI sleep state of the system is (that is needed for i915 mostly at this point). Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index c40fb2e81bbc..2281ca31c1bc 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -89,6 +89,7 @@ u32 acpi_target_system_state(void) { return acpi_target_sleep_state; } +EXPORT_SYMBOL_GPL(acpi_target_system_state); static bool pwr_btn_event_pending; From 1f0b63866fc1be700260547be8edf8e6f0af37f2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 15 May 2014 23:29:57 +0200 Subject: [PATCH 070/134] ACPI / PM: Hold ACPI scan lock over the "freeze" sleep state The "freeze" sleep state suffers from the same issue that was addressed by commit ad07277e82de (ACPI / PM: Hold acpi_scan_lock over system PM transitions) for ACPI sleep states, that is, things break if ->remove() is called for devices whose system resume callbacks haven't been executed yet. It also can be addressed in the same way, by holding the ACPI scan lock over the "freeze" sleep state and PM transitions to and from that state, but ->begin() and ->end() platform operations for the "freeze" sleep state are needed for this purpose. This change has been tested on Acer Aspire S5 with Thunderbolt. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 18 ++++++++++++++++++ include/linux/suspend.h | 7 +++++++ kernel/power/suspend.c | 15 +++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 2281ca31c1bc..c11e3795431b 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -612,6 +612,22 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = { .recover = acpi_pm_finish, }; +static int acpi_freeze_begin(void) +{ + acpi_scan_lock_acquire(); + return 0; +} + +static void acpi_freeze_end(void) +{ + acpi_scan_lock_release(); +} + +static const struct platform_freeze_ops acpi_freeze_ops = { + .begin = acpi_freeze_begin, + .end = acpi_freeze_end, +}; + static void acpi_sleep_suspend_setup(void) { int i; @@ -622,7 +638,9 @@ static void acpi_sleep_suspend_setup(void) suspend_set_ops(old_suspend_ordering ? &acpi_suspend_ops_old : &acpi_suspend_ops); + freeze_set_ops(&acpi_freeze_ops); } + #else /* !CONFIG_SUSPEND */ static inline void acpi_sleep_suspend_setup(void) {} #endif /* !CONFIG_SUSPEND */ diff --git a/include/linux/suspend.h b/include/linux/suspend.h index f73cabf59012..91d66fd8dce1 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -187,6 +187,11 @@ struct platform_suspend_ops { void (*recover)(void); }; +struct platform_freeze_ops { + int (*begin)(void); + void (*end)(void); +}; + #ifdef CONFIG_SUSPEND /** * suspend_set_ops - set platform dependent suspend operations @@ -194,6 +199,7 @@ struct platform_suspend_ops { */ extern void suspend_set_ops(const struct platform_suspend_ops *ops); extern int suspend_valid_only_mem(suspend_state_t state); +extern void freeze_set_ops(const struct platform_freeze_ops *ops); extern void freeze_wake(void); /** @@ -220,6 +226,7 @@ extern int pm_suspend(suspend_state_t state); static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {} static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; } +static inline void freeze_set_ops(const struct platform_freeze_ops *ops) {} static inline void freeze_wake(void) {} #endif /* !CONFIG_SUSPEND */ diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 8233cd4047d7..73a905f83972 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -38,6 +38,7 @@ const char *const pm_states[PM_SUSPEND_MAX] = { }; static const struct platform_suspend_ops *suspend_ops; +static const struct platform_freeze_ops *freeze_ops; static bool need_suspend_ops(suspend_state_t state) { @@ -47,6 +48,13 @@ static bool need_suspend_ops(suspend_state_t state) static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head); static bool suspend_freeze_wake; +void freeze_set_ops(const struct platform_freeze_ops *ops) +{ + lock_system_sleep(); + freeze_ops = ops; + unlock_system_sleep(); +} + static void freeze_begin(void) { suspend_freeze_wake = false; @@ -269,6 +277,10 @@ int suspend_devices_and_enter(suspend_state_t state) error = suspend_ops->begin(state); if (error) goto Close; + } else if (state == PM_SUSPEND_FREEZE && freeze_ops->begin) { + error = freeze_ops->begin(); + if (error) + goto Close; } suspend_console(); suspend_test_start(); @@ -294,6 +306,9 @@ int suspend_devices_and_enter(suspend_state_t state) Close: if (need_suspend_ops(state) && suspend_ops->end) suspend_ops->end(); + else if (state == PM_SUSPEND_FREEZE && freeze_ops->end) + freeze_ops->end(); + trace_machine_suspend(PWR_EVENT_EXIT); return error; From 99678ed73a50d2df8b5f3c801e29e9b7a3e5aa85 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 15 May 2014 13:22:33 +0200 Subject: [PATCH 071/134] ACPI / video: Don't register acpi_video_resume notifier without backlight devices If we're not going to be registering any backlight devices then acpi_video_resume is always nop, so don't register it in that case. Signed-off-by: Hans de Goede Reviewed-by: Aaron Lu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/video.c | 145 +++++++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 68 deletions(-) diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index fced27d8e42f..ff79dff371fd 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -150,6 +150,7 @@ struct acpi_video_enumerated_device { struct acpi_video_bus { struct acpi_device *device; + bool backlight_registered; u8 dos_setting; struct acpi_video_enumerated_device *attached_array; u8 attached_count; @@ -1666,88 +1667,89 @@ acpi_video_bus_match(acpi_handle handle, u32 level, void *context, static void acpi_video_dev_register_backlight(struct acpi_video_device *device) { - if (acpi_video_verify_backlight_support()) { - struct backlight_properties props; - struct pci_dev *pdev; - acpi_handle acpi_parent; - struct device *parent = NULL; - int result; - static int count; - char *name; + struct backlight_properties props; + struct pci_dev *pdev; + acpi_handle acpi_parent; + struct device *parent = NULL; + int result; + static int count; + char *name; - result = acpi_video_init_brightness(device); - if (result) - return; - name = kasprintf(GFP_KERNEL, "acpi_video%d", count); - if (!name) - return; - count++; + result = acpi_video_init_brightness(device); + if (result) + return; + name = kasprintf(GFP_KERNEL, "acpi_video%d", count); + if (!name) + return; + count++; - acpi_get_parent(device->dev->handle, &acpi_parent); + acpi_get_parent(device->dev->handle, &acpi_parent); - pdev = acpi_get_pci_dev(acpi_parent); - if (pdev) { - parent = &pdev->dev; - pci_dev_put(pdev); - } - - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_FIRMWARE; - props.max_brightness = device->brightness->count - 3; - device->backlight = backlight_device_register(name, - parent, - device, - &acpi_backlight_ops, - &props); - kfree(name); - if (IS_ERR(device->backlight)) - return; - - /* - * Save current brightness level in case we have to restore it - * before acpi_video_device_lcd_set_level() is called next time. - */ - device->backlight->props.brightness = - acpi_video_get_brightness(device->backlight); - - device->cooling_dev = thermal_cooling_device_register("LCD", - device->dev, &video_cooling_ops); - if (IS_ERR(device->cooling_dev)) { - /* - * Set cooling_dev to NULL so we don't crash trying to - * free it. - * Also, why the hell we are returning early and - * not attempt to register video output if cooling - * device registration failed? - * -- dtor - */ - device->cooling_dev = NULL; - return; - } - - dev_info(&device->dev->dev, "registered as cooling_device%d\n", - device->cooling_dev->id); - result = sysfs_create_link(&device->dev->dev.kobj, - &device->cooling_dev->device.kobj, - "thermal_cooling"); - if (result) - printk(KERN_ERR PREFIX "Create sysfs link\n"); - result = sysfs_create_link(&device->cooling_dev->device.kobj, - &device->dev->dev.kobj, "device"); - if (result) - printk(KERN_ERR PREFIX "Create sysfs link\n"); + pdev = acpi_get_pci_dev(acpi_parent); + if (pdev) { + parent = &pdev->dev; + pci_dev_put(pdev); } + + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_FIRMWARE; + props.max_brightness = device->brightness->count - 3; + device->backlight = backlight_device_register(name, + parent, + device, + &acpi_backlight_ops, + &props); + kfree(name); + if (IS_ERR(device->backlight)) + return; + + /* + * Save current brightness level in case we have to restore it + * before acpi_video_device_lcd_set_level() is called next time. + */ + device->backlight->props.brightness = + acpi_video_get_brightness(device->backlight); + + device->cooling_dev = thermal_cooling_device_register("LCD", + device->dev, &video_cooling_ops); + if (IS_ERR(device->cooling_dev)) { + /* + * Set cooling_dev to NULL so we don't crash trying to free it. + * Also, why the hell we are returning early and not attempt to + * register video output if cooling device registration failed? + * -- dtor + */ + device->cooling_dev = NULL; + return; + } + + dev_info(&device->dev->dev, "registered as cooling_device%d\n", + device->cooling_dev->id); + result = sysfs_create_link(&device->dev->dev.kobj, + &device->cooling_dev->device.kobj, + "thermal_cooling"); + if (result) + printk(KERN_ERR PREFIX "Create sysfs link\n"); + result = sysfs_create_link(&device->cooling_dev->device.kobj, + &device->dev->dev.kobj, "device"); + if (result) + printk(KERN_ERR PREFIX "Create sysfs link\n"); } static int acpi_video_bus_register_backlight(struct acpi_video_bus *video) { struct acpi_video_device *dev; + if (!acpi_video_verify_backlight_support()) + return 0; + mutex_lock(&video->device_list_lock); list_for_each_entry(dev, &video->video_device_list, entry) acpi_video_dev_register_backlight(dev); mutex_unlock(&video->device_list_lock); + video->backlight_registered = true; + video->pm_nb.notifier_call = acpi_video_resume; video->pm_nb.priority = 0; return register_pm_notifier(&video->pm_nb); @@ -1775,13 +1777,20 @@ static void acpi_video_dev_unregister_backlight(struct acpi_video_device *device static int acpi_video_bus_unregister_backlight(struct acpi_video_bus *video) { struct acpi_video_device *dev; - int error = unregister_pm_notifier(&video->pm_nb); + int error; + + if (!video->backlight_registered) + return 0; + + error = unregister_pm_notifier(&video->pm_nb); mutex_lock(&video->device_list_lock); list_for_each_entry(dev, &video->video_device_list, entry) acpi_video_dev_unregister_backlight(dev); mutex_unlock(&video->device_list_lock); + video->backlight_registered = false; + return error; } From 247dba58a19a34f01c363b3aec4d2c21cfb87d8e Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Mon, 5 May 2014 12:48:25 +0800 Subject: [PATCH 072/134] ACPI / ia64: introduce variable acpi_lapic into ia64 This variable was defined and assigned in x86, is used to indicate whether LAPIC exists in MADT. Now introduce it into ia64 to help make correct judgment when get information for ACPI processor later. Signed-off-by: Baoquan He Signed-off-by: Rafael J. Wysocki --- arch/ia64/include/asm/acpi.h | 1 + arch/ia64/kernel/acpi.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/arch/ia64/include/asm/acpi.h b/arch/ia64/include/asm/acpi.h index d651102a4d45..b47821931ca6 100644 --- a/arch/ia64/include/asm/acpi.h +++ b/arch/ia64/include/asm/acpi.h @@ -85,6 +85,7 @@ ia64_acpi_release_global_lock (unsigned int *lock) ((Acq) = ia64_acpi_release_global_lock(&facs->global_lock)) #ifdef CONFIG_ACPI +extern int acpi_lapic; #define acpi_disabled 0 /* ACPI always enabled on IA64 */ #define acpi_noirq 0 /* ACPI always enabled on IA64 */ #define acpi_pci_disabled 0 /* ACPI PCI always enabled on IA64 */ diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 0d407b300762..615ef81def49 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -56,6 +56,7 @@ #define PREFIX "ACPI: " +int acpi_lapic; unsigned int acpi_cpei_override; unsigned int acpi_cpei_phys_cpuid; @@ -676,6 +677,8 @@ int __init early_acpi_boot_init(void) if (ret < 1) printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries\n"); + else + acpi_lapic = 1; #ifdef CONFIG_SMP if (available_cpus == 0) { From c401eb8ee374a5fc2b56042c0072ce51a0beb0dc Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Mon, 5 May 2014 12:48:26 +0800 Subject: [PATCH 073/134] ACPI / processor: Check if LAPIC is present during initialization In acpi_processor_get_info(), ACPI processor info is initialized including ID, namely CPU index. Currently, on a UP system running an SMP kerenl with no LAPIC in the MADT, cpu0_initialized is checked to decide whether or not the CPU has been initialized. However, this check may not be sufficient for kdump kernels. Most of time only 1 CPU is supported because of known problems in kdump kernels. So say the multiple CPUs are present in the boot kernel and a crash happens on one specific CPU, say CPU2. Then it jumps into the kdump kernel with "nr_cpus=1" in the command line. In this situation, the kdump kernel will reuse the ACPI resources from the crashed kernel directly. That means all LAPIC instances are enabled in the MADT while only one CPU is in use. In the kdump kernel, x86_cpu_to_apicid contains the correct APIC ID and it's related to the CPU ID. If cpu0_initialized is checked only, 0 will be used as the CPU index instead of that APIC ID, which is not correct. In addition to checking cpu0_initialized, check acpi_lapic. If acpi_lapic is 0, then no LAPIC is available from the MADT and the system should be treated as a UP one without a LAPIC (that is, assign 0 to the CPU index). Otherwise, use the original (valid) CPU index. Signed-off-by: Baoquan He [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_processor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 52c81c49cc7d..1c085742644f 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) { + if (!cpu0_initialized && !acpi_lapic) { cpu0_initialized = 1; /* Handle UP system running SMP kernel, with no LAPIC in MADT */ if ((cpu_index == -1) && (num_online_cpus() == 1)) From a3cffce4fbafac072660648e028cc9e629b5b3c8 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 8 May 2014 14:59:04 +0300 Subject: [PATCH 074/134] ACPI / platform: add IDs for Broadcom Bluetooth and GPS chips These IDs are used on Baytrail boards such as Lenovo Miix 2 and Asus Transformer Book T100TA. On lenovo Miix 2 8", BCM4752 is called LNV4752. All the rest of the IDs are for Broadcom BCM43241 module with the ID referring to different revision number. Signed-off-by: Heikki Krogerus Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_platform.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index dbfe49e5fd63..c0a39417ebe4 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -32,6 +32,10 @@ static const struct acpi_device_id acpi_platform_device_ids[] = { { "ACPI0003" }, { "VPC2004" }, { "BCM4752" }, + { "LNV4752" }, + { "BCM2E1A" }, + { "BCM2E39" }, + { "BCM2E3D" }, /* Intel Smart Sound Technology */ { "INT33C8" }, From 9e50bc14a7f58b5d8a55973b2d69355852ae2dae Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Sun, 4 May 2014 14:07:06 +0800 Subject: [PATCH 075/134] ACPI / battery: Accelerate battery resume callback Most time of battery resume callback is spent on executing AML code _BTP, _BIF and _BIF to get battery info, status and set alarm. These AML methods may access EC operation regions several times and consumes time. These operations are not necessary during devices resume and can run during POST_SUSPEND/HIBERNATION event when all processes are thawed. This also can avoid removing and adding battery sysfs nodes every system resume even if the battery unit is not actually changed. The original code updates sysfs nodes without check and this seems not reasonable. Signed-off-by: Lan Tianyu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 6e7b2a12860d..3b4921e4dc4e 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -696,7 +696,7 @@ static void acpi_battery_quirks(struct acpi_battery *battery) } } -static int acpi_battery_update(struct acpi_battery *battery) +static int acpi_battery_update(struct acpi_battery *battery, bool resume) { int result, old_present = acpi_battery_present(battery); result = acpi_battery_get_status(battery); @@ -707,6 +707,10 @@ static int acpi_battery_update(struct acpi_battery *battery) battery->update_time = 0; return 0; } + + if (resume) + return 0; + if (!battery->update_time || old_present != acpi_battery_present(battery)) { result = acpi_battery_get_info(battery); @@ -915,7 +919,7 @@ static print_func acpi_print_funcs[ACPI_BATTERY_NUMFILES] = { static int acpi_battery_read(int fid, struct seq_file *seq) { struct acpi_battery *battery = seq->private; - int result = acpi_battery_update(battery); + int result = acpi_battery_update(battery, false); return acpi_print_funcs[fid](seq, result); } @@ -1030,7 +1034,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) old = battery->bat.dev; if (event == ACPI_BATTERY_NOTIFY_INFO) acpi_battery_refresh(battery); - acpi_battery_update(battery); + acpi_battery_update(battery, false); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, acpi_battery_present(battery)); @@ -1045,13 +1049,27 @@ static int battery_notify(struct notifier_block *nb, { struct acpi_battery *battery = container_of(nb, struct acpi_battery, pm_nb); + int result; + switch (mode) { case PM_POST_HIBERNATION: case PM_POST_SUSPEND: - if (battery->bat.dev) { - sysfs_remove_battery(battery); - sysfs_add_battery(battery); - } + if (!acpi_battery_present(battery)) + return 0; + + if (!battery->bat.dev) { + result = acpi_battery_get_info(battery); + if (result) + return result; + + result = sysfs_add_battery(battery); + if (result) + return result; + } else + acpi_battery_refresh(battery); + + acpi_battery_init_alarm(battery); + acpi_battery_get_state(battery); break; } @@ -1087,7 +1105,7 @@ static int acpi_battery_add(struct acpi_device *device) mutex_init(&battery->sysfs_lock); if (acpi_has_method(battery->device->handle, "_BIX")) set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); - result = acpi_battery_update(battery); + result = acpi_battery_update(battery, false); if (result) goto fail; #ifdef CONFIG_ACPI_PROCFS_POWER @@ -1149,7 +1167,7 @@ static int acpi_battery_resume(struct device *dev) return -EINVAL; battery->update_time = 0; - acpi_battery_update(battery); + acpi_battery_update(battery, true); return 0; } #else From 8da8373447d6a57a5a9f55233d35beb15d92d0d2 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Thu, 8 May 2014 07:58:59 -0600 Subject: [PATCH 076/134] ACPI / processor: Fix STARTING/DYING action in acpi_cpu_soft_notify() During CPU online/offline testing on a large system, one of the processors got stuck after the message "bad: scheduling from the idle thread!". The problem is that acpi_cpu_soft_notify() calls acpi_bus_get_device() for all action types. CPU_STARTING and CPU_DYING do not allow the notify handlers to sleep. However, acpi_bus_get_device() can sleep in acpi_ut_acquire_mutex(). Change acpi_cpu_soft_notify() to return immediately for CPU_STARTING and CPU_DYING as they have no action in this handler. Signed-off-by: Toshi Kani Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_driver.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 7f70f3182d50..4fcbd670415c 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -121,6 +121,13 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, struct acpi_processor *pr = per_cpu(processors, cpu); struct acpi_device *device; + /* + * CPU_STARTING and CPU_DYING must not sleep. Return here since + * acpi_bus_get_device() may sleep. + */ + if (action == CPU_STARTING || action == CPU_DYING) + return NOTIFY_DONE; + if (!pr || acpi_bus_get_device(pr->handle, &device)) return NOTIFY_DONE; From f6514be5fe7fe796041b673bad769510414ff2b9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 14 May 2014 19:08:46 +0300 Subject: [PATCH 077/134] PM / hibernate: Fix memory corruption in resumedelay_setup() In the original code "resume_delay" is an int so on 64 bits, the call to kstrtoul() will cause memory corruption. We may as well fix a style issue here as well and make "resume_delay" unsigned int, since that's what we pass to ssleep(). Fixes: 317cf7e5e85e (PM / hibernate: convert simple_strtoul to kstrtoul) Signed-off-by: Dan Carpenter Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki --- kernel/power/hibernate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 2377ff72994c..df88d55dc436 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -35,7 +35,7 @@ static int nocompress; static int noresume; static int resume_wait; -static int resume_delay; +static unsigned int resume_delay; static char resume_file[256] = CONFIG_PM_STD_PARTITION; dev_t swsusp_resume_device; sector_t swsusp_resume_block; @@ -1115,7 +1115,7 @@ static int __init resumewait_setup(char *str) static int __init resumedelay_setup(char *str) { - int rc = kstrtoul(str, 0, (unsigned long *)&resume_delay); + int rc = kstrtouint(str, 0, &resume_delay); if (rc) return rc; From aae4518b3124b29f8dc81c829c704fd2df72e98b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 16 May 2014 02:46:50 +0200 Subject: [PATCH 078/134] PM / sleep: Mechanism to avoid resuming runtime-suspended devices unnecessarily Currently, some subsystems (e.g. PCI and the ACPI PM domain) have to resume all runtime-suspended devices during system suspend, mostly because those devices may need to be reprogrammed due to different wakeup settings for system sleep and for runtime PM. For some devices, though, it's OK to remain in runtime suspend throughout a complete system suspend/resume cycle (if the device was in runtime suspend at the start of the cycle). We would like to do this whenever possible, to avoid the overhead of extra power-up and power-down events. However, problems may arise because the device's descendants may require it to be at full power at various points during the cycle. Therefore the most straightforward way to do this safely is if the device and all its descendants can remain runtime suspended until the complete stage of system resume. To this end, introduce a new device PM flag, power.direct_complete and modify the PM core to use that flag as follows. If the ->prepare() callback of a device returns a positive number, the PM core will regard that as an indication that it may leave the device runtime-suspended. It will then check if the system power transition in progress is a suspend (and not hibernation in particular) and if the device is, indeed, runtime-suspended. In that case, the PM core will set the device's power.direct_complete flag. Otherwise it will clear power.direct_complete for the device and it also will later clear it for the device's parent (if there's one). Next, the PM core will not invoke the ->suspend() ->suspend_late(), ->suspend_irq(), ->resume_irq(), ->resume_early(), or ->resume() callbacks for all devices having power.direct_complete set. It will invoke their ->complete() callbacks, however, and those callbacks are then responsible for resuming the devices as appropriate, if necessary. For example, in some cases they may need to queue up runtime resume requests for the devices using pm_request_resume(). Changelog partly based on an Alan Stern's description of the idea (http://marc.info/?l=linux-pm&m=139940466625569&w=2). Signed-off-by: Rafael J. Wysocki Acked-by: Alan Stern --- drivers/base/power/main.c | 66 +++++++++++++++++++++++++++++--------- include/linux/pm.h | 36 ++++++++++++++++----- include/linux/pm_runtime.h | 6 ++++ 3 files changed, 85 insertions(+), 23 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 86d5e4fb5b98..343ffad59377 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -479,7 +479,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn TRACE_DEVICE(dev); TRACE_RESUME(0); - if (dev->power.syscore) + if (dev->power.syscore || dev->power.direct_complete) goto Out; if (!dev->power.is_noirq_suspended) @@ -605,7 +605,7 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn TRACE_DEVICE(dev); TRACE_RESUME(0); - if (dev->power.syscore) + if (dev->power.syscore || dev->power.direct_complete) goto Out; if (!dev->power.is_late_suspended) @@ -735,6 +735,12 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) if (dev->power.syscore) goto Complete; + if (dev->power.direct_complete) { + /* Match the pm_runtime_disable() in __device_suspend(). */ + pm_runtime_enable(dev); + goto Complete; + } + dpm_wait(dev->parent, async); dpm_watchdog_set(&wd, dev); device_lock(dev); @@ -1007,7 +1013,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a goto Complete; } - if (dev->power.syscore) + if (dev->power.syscore || dev->power.direct_complete) goto Complete; dpm_wait_for_children(dev, async); @@ -1146,7 +1152,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as goto Complete; } - if (dev->power.syscore) + if (dev->power.syscore || dev->power.direct_complete) goto Complete; dpm_wait_for_children(dev, async); @@ -1332,6 +1338,17 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) if (dev->power.syscore) goto Complete; + if (dev->power.direct_complete) { + if (pm_runtime_status_suspended(dev)) { + pm_runtime_disable(dev); + if (pm_runtime_suspended_if_enabled(dev)) + goto Complete; + + pm_runtime_enable(dev); + } + dev->power.direct_complete = false; + } + dpm_watchdog_set(&wd, dev); device_lock(dev); @@ -1382,10 +1399,19 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) End: if (!error) { + struct device *parent = dev->parent; + dev->power.is_suspended = true; - if (dev->power.wakeup_path - && dev->parent && !dev->parent->power.ignore_children) - dev->parent->power.wakeup_path = true; + if (parent) { + spin_lock_irq(&parent->power.lock); + + dev->parent->power.direct_complete = false; + if (dev->power.wakeup_path + && !dev->parent->power.ignore_children) + dev->parent->power.wakeup_path = true; + + spin_unlock_irq(&parent->power.lock); + } } device_unlock(dev); @@ -1487,7 +1513,7 @@ static int device_prepare(struct device *dev, pm_message_t state) { int (*callback)(struct device *) = NULL; char *info = NULL; - int error = 0; + int ret = 0; if (dev->power.syscore) return 0; @@ -1523,17 +1549,27 @@ static int device_prepare(struct device *dev, pm_message_t state) callback = dev->driver->pm->prepare; } - if (callback) { - error = callback(dev); - suspend_report_result(callback, error); - } + if (callback) + ret = callback(dev); device_unlock(dev); - if (error) + if (ret < 0) { + suspend_report_result(callback, ret); pm_runtime_put(dev); - - return error; + return ret; + } + /* + * A positive return value from ->prepare() means "this device appears + * to be runtime-suspended and its state is fine, so if it really is + * runtime-suspended, you can leave it in that state provided that you + * will do the same thing with all of its descendants". This only + * applies to suspend transitions, however. + */ + spin_lock_irq(&dev->power.lock); + dev->power.direct_complete = ret > 0 && state.event == PM_EVENT_SUSPEND; + spin_unlock_irq(&dev->power.lock); + return 0; } /** diff --git a/include/linux/pm.h b/include/linux/pm.h index d915d0345fa1..72c0fe098a27 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -93,13 +93,23 @@ typedef struct pm_message { * been registered) to recover from the race condition. * This method is executed for all kinds of suspend transitions and is * followed by one of the suspend callbacks: @suspend(), @freeze(), or - * @poweroff(). The PM core executes subsystem-level @prepare() for all - * devices before starting to invoke suspend callbacks for any of them, so - * generally devices may be assumed to be functional or to respond to - * runtime resume requests while @prepare() is being executed. However, - * device drivers may NOT assume anything about the availability of user - * space at that time and it is NOT valid to request firmware from within - * @prepare() (it's too late to do that). It also is NOT valid to allocate + * @poweroff(). If the transition is a suspend to memory or standby (that + * is, not related to hibernation), the return value of @prepare() may be + * used to indicate to the PM core to leave the device in runtime suspend + * if applicable. Namely, if @prepare() returns a positive number, the PM + * core will understand that as a declaration that the device appears to be + * runtime-suspended and it may be left in that state during the entire + * transition and during the subsequent resume if all of its descendants + * are left in runtime suspend too. If that happens, @complete() will be + * executed directly after @prepare() and it must ensure the proper + * functioning of the device after the system resume. + * The PM core executes subsystem-level @prepare() for all devices before + * starting to invoke suspend callbacks for any of them, so generally + * devices may be assumed to be functional or to respond to runtime resume + * requests while @prepare() is being executed. However, device drivers + * may NOT assume anything about the availability of user space at that + * time and it is NOT valid to request firmware from within @prepare() + * (it's too late to do that). It also is NOT valid to allocate * substantial amounts of memory from @prepare() in the GFP_KERNEL mode. * [To work around these limitations, drivers may register suspend and * hibernation notifiers to be executed before the freezing of tasks.] @@ -112,7 +122,16 @@ typedef struct pm_message { * of the other devices that the PM core has unsuccessfully attempted to * suspend earlier). * The PM core executes subsystem-level @complete() after it has executed - * the appropriate resume callbacks for all devices. + * the appropriate resume callbacks for all devices. If the corresponding + * @prepare() at the beginning of the suspend transition returned a + * positive number and the device was left in runtime suspend (without + * executing any suspend and resume callbacks for it), @complete() will be + * the only callback executed for the device during resume. In that case, + * @complete() must be prepared to do whatever is necessary to ensure the + * proper functioning of the device after the system resume. To this end, + * @complete() can check the power.direct_complete flag of the device to + * learn whether (unset) or not (set) the previous suspend and resume + * callbacks have been executed for it. * * @suspend: Executed before putting the system into a sleep state in which the * contents of main memory are preserved. The exact action to perform @@ -546,6 +565,7 @@ struct dev_pm_info { bool is_late_suspended:1; bool ignore_children:1; bool early_init:1; /* Owned by the PM core */ + bool direct_complete:1; /* Owned by the PM core */ spinlock_t lock; #ifdef CONFIG_PM_SLEEP struct list_head entry; diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 2a5897a4afbc..43fd6716f662 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -101,6 +101,11 @@ static inline bool pm_runtime_status_suspended(struct device *dev) return dev->power.runtime_status == RPM_SUSPENDED; } +static inline bool pm_runtime_suspended_if_enabled(struct device *dev) +{ + return pm_runtime_status_suspended(dev) && dev->power.disable_depth == 1; +} + static inline bool pm_runtime_enabled(struct device *dev) { return !dev->power.disable_depth; @@ -150,6 +155,7 @@ static inline void device_set_run_wake(struct device *dev, bool enable) {} static inline bool pm_runtime_suspended(struct device *dev) { return false; } static inline bool pm_runtime_active(struct device *dev) { return true; } static inline bool pm_runtime_status_suspended(struct device *dev) { return false; } +static inline bool pm_runtime_suspended_if_enabled(struct device *dev) { return false; } static inline bool pm_runtime_enabled(struct device *dev) { return false; } static inline void pm_runtime_no_callbacks(struct device *dev) {} From f71495f3f0c5f0801823d1235b271a4a415d3df8 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 16 May 2014 02:47:37 +0200 Subject: [PATCH 079/134] PM / sleep: Update device PM documentation to cover direct_complete Update the device PM documentation in devices.txt and runtime_pm.txt to reflect the changes in the system suspend and resume handling related to the introduction of the new power.direct_complete flag. Signed-off-by: Rafael J. Wysocki Acked-by: Alan Stern --- Documentation/power/devices.txt | 34 ++++++++++++++++++++++++++---- Documentation/power/runtime_pm.txt | 17 +++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt index 47d46dff70f7..d172bce0fd49 100644 --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt @@ -2,6 +2,7 @@ Device Power Management Copyright (c) 2010-2011 Rafael J. Wysocki , Novell Inc. Copyright (c) 2010 Alan Stern +Copyright (c) 2014 Intel Corp., Rafael J. Wysocki Most of the code in Linux is device drivers, so most of the Linux power @@ -326,6 +327,20 @@ the phases are: driver in some way for the upcoming system power transition, but it should not put the device into a low-power state. + For devices supporting runtime power management, the return value of the + prepare callback can be used to indicate to the PM core that it may + safely leave the device in runtime suspend (if runtime-suspended + already), provided that all of the device's descendants are also left in + runtime suspend. Namely, if the prepare callback returns a positive + number and that happens for all of the descendants of the device too, + and all of them (including the device itself) are runtime-suspended, the + PM core will skip the suspend, suspend_late and suspend_noirq suspend + phases as well as the resume_noirq, resume_early and resume phases of + the following system resume for all of these devices. In that case, + the complete callback will be called directly after the prepare callback + and is entirely responsible for bringing the device back to the + functional state as appropriate. + 2. The suspend methods should quiesce the device to stop it from performing I/O. They also may save the device registers and put it into the appropriate low-power state, depending on the bus type the device is on, @@ -400,12 +415,23 @@ When resuming from freeze, standby or memory sleep, the phases are: the resume callbacks occur; it's not necessary to wait until the complete phase. + Moreover, if the preceding prepare callback returned a positive number, + the device may have been left in runtime suspend throughout the whole + system suspend and resume (the suspend, suspend_late, suspend_noirq + phases of system suspend and the resume_noirq, resume_early, resume + phases of system resume may have been skipped for it). In that case, + the complete callback is entirely responsible for bringing the device + back to the functional state after system suspend if necessary. [For + example, it may need to queue up a runtime resume request for the device + for this purpose.] To check if that is the case, the complete callback + can consult the device's power.direct_complete flag. Namely, if that + flag is set when the complete callback is being run, it has been called + directly after the preceding prepare and special action may be required + to make the device work correctly afterward. + At the end of these phases, drivers should be as functional as they were before suspending: I/O can be performed using DMA and IRQs, and the relevant clocks are -gated on. Even if the device was in a low-power state before the system sleep -because of runtime power management, afterwards it should be back in its -full-power state. There are multiple reasons why it's best to do this; they are -discussed in more detail in Documentation/power/runtime_pm.txt. +gated on. However, the details here may again be platform-specific. For example, some systems support multiple "run" states, and the mode in effect at diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index 5f96daf8566a..e1bee8a4aaac 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -2,6 +2,7 @@ Runtime Power Management Framework for I/O Devices (C) 2009-2011 Rafael J. Wysocki , Novell Inc. (C) 2010 Alan Stern +(C) 2014 Intel Corp., Rafael J. Wysocki 1. Introduction @@ -444,6 +445,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: bool pm_runtime_status_suspended(struct device *dev); - return true if the device's runtime PM status is 'suspended' + bool pm_runtime_suspended_if_enabled(struct device *dev); + - return true if the device's runtime PM status is 'suspended' and its + 'power.disable_depth' field is equal to 1 + void pm_runtime_allow(struct device *dev); - set the power.runtime_auto flag for the device and decrease its usage counter (used by the /sys/devices/.../power/control interface to @@ -644,6 +649,18 @@ place (in particular, if the system is not waking up from hibernation), it may be more efficient to leave the devices that had been suspended before the system suspend began in the suspended state. +To this end, the PM core provides a mechanism allowing some coordination between +different levels of device hierarchy. Namely, if a system suspend .prepare() +callback returns a positive number for a device, that indicates to the PM core +that the device appears to be runtime-suspended and its state is fine, so it +may be left in runtime suspend provided that all of its descendants are also +left in runtime suspend. If that happens, the PM core will not execute any +system suspend and resume callbacks for all of those devices, except for the +complete callback, which is then entirely responsible for handling the device +as appropriate. This only applies to system suspend transitions that are not +related to hibernation (see Documentation/power/devices.txt for more +information). + The PM core does its best to reduce the probability of race conditions between the runtime PM and system suspend/resume (and hibernation) callbacks by carrying out the following operations: From 73577d1df8e1f31f6b1a5eebcdbc334eb0330e47 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 12 May 2014 15:50:16 +0800 Subject: [PATCH 080/134] ACPI: Fix conflict between customized DSDT and DSDT local copy This patch fixes the following issue: If DSDT is customized, no local DSDT copy is needed. References: https://bugzilla.kernel.org/show_bug.cgi?id=69711 Signed-off-by: Enrico Etxe Arte Signed-off-by: Lv Zheng Cc: 2.6.35+ # 2.6.35+ [rjw: Subject] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index cf925c4f36b7..ed9fca0250fa 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -52,6 +52,12 @@ struct proc_dir_entry *acpi_root_dir; EXPORT_SYMBOL(acpi_root_dir); #ifdef CONFIG_X86 +#ifdef CONFIG_ACPI_CUSTOM_DSDT +static inline int set_copy_dsdt(const struct dmi_system_id *id) +{ + return 0; +} +#else static int set_copy_dsdt(const struct dmi_system_id *id) { printk(KERN_NOTICE "%s detected - " @@ -59,6 +65,7 @@ static int set_copy_dsdt(const struct dmi_system_id *id) acpi_gbl_copy_dsdt_locally = 1; return 0; } +#endif static struct dmi_system_id dsdt_dmi_table[] __initdata = { /* From f25c0ae2b4c41996c1a6b609132c1788a6eea080 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 17 May 2014 00:18:13 +0200 Subject: [PATCH 081/134] ACPI / PM: Avoid resuming devices in ACPI PM domain during system suspend Rework the ACPI PM domain's PM callbacks to avoid resuming devices during system suspend (in order to modify their wakeup settings etc.) if that isn't necessary. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 43 +++++++++++++++++++++++++++++++++------- drivers/acpi/scan.c | 4 ++++ include/acpi/acpi_bus.h | 3 ++- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index d047739f3380..9e5fd9c440b7 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -900,17 +900,45 @@ EXPORT_SYMBOL_GPL(acpi_dev_resume_early); */ int acpi_subsys_prepare(struct device *dev) { - /* - * Devices having power.ignore_children set may still be necessary for - * suspending their children in the next phase of device suspend. - */ - if (dev->power.ignore_children) - pm_runtime_resume(dev); + struct acpi_device *adev = ACPI_COMPANION(dev); + u32 sys_target; + int ret, state; - return pm_generic_prepare(dev); + ret = pm_generic_prepare(dev); + if (ret < 0) + return ret; + + if (!adev || !pm_runtime_suspended(dev) + || device_may_wakeup(dev) != !!adev->wakeup.prepare_count) + return 0; + + sys_target = acpi_target_system_state(); + if (sys_target == ACPI_STATE_S0) + return 1; + + if (adev->power.flags.dsw_present) + return 0; + + ret = acpi_dev_pm_get_state(dev, adev, sys_target, NULL, &state); + return !ret && state == adev->power.state; } EXPORT_SYMBOL_GPL(acpi_subsys_prepare); +/** + * acpi_subsys_complete - Finalize device's resume during system resume. + * @dev: Device to handle. + */ +static void acpi_subsys_complete(struct device *dev) +{ + /* + * If the device had been runtime-suspended before the system went into + * the sleep state it is going out of and it has never been resumed till + * now, resume it in case the firmware powered it up. + */ + if (dev->power.direct_complete) + pm_request_resume(dev); +} + /** * acpi_subsys_suspend - Run the device driver's suspend callback. * @dev: Device to handle. @@ -979,6 +1007,7 @@ static struct dev_pm_domain acpi_general_pm_domain = { #endif #ifdef CONFIG_PM_SLEEP .prepare = acpi_subsys_prepare, + .complete = acpi_subsys_complete, .suspend = acpi_subsys_suspend, .suspend_late = acpi_subsys_suspend_late, .resume_early = acpi_subsys_resume_early, diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7efe546a8c42..df6e4c924b35 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1551,9 +1551,13 @@ static void acpi_bus_get_power_flags(struct acpi_device *device) */ if (acpi_has_method(device->handle, "_PSC")) device->power.flags.explicit_get = 1; + if (acpi_has_method(device->handle, "_IRC")) device->power.flags.inrush_current = 1; + if (acpi_has_method(device->handle, "_DSW")) + device->power.flags.dsw_present = 1; + /* * Enumerate supported power management states */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 84a2e29a2314..7417a16c8d86 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -261,7 +261,8 @@ struct acpi_device_power_flags { u32 inrush_current:1; /* Serialize Dx->D0 */ u32 power_removed:1; /* Optimize Dx->D0 */ u32 ignore_parent:1; /* Power is independent of parent power state */ - u32 reserved:27; + u32 dsw_present:1; /* _DSW present? */ + u32 reserved:26; }; struct acpi_device_power_state { From 4cf563c5d97c83d4b2fb3a778dd7d5e362cc3e34 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 15 May 2014 16:40:23 +0300 Subject: [PATCH 082/134] ACPI / PM: Export rest of the subsys PM callbacks No reason for excluding the remaining ones. Signed-off-by: Heikki Krogerus [rjw: Rebased and exported the new acpi_subsys_complete() too.] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 5 ++++- include/linux/acpi.h | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 9e5fd9c440b7..49a51277f81d 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -928,7 +928,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_prepare); * acpi_subsys_complete - Finalize device's resume during system resume. * @dev: Device to handle. */ -static void acpi_subsys_complete(struct device *dev) +void acpi_subsys_complete(struct device *dev) { /* * If the device had been runtime-suspended before the system went into @@ -938,6 +938,7 @@ static void acpi_subsys_complete(struct device *dev) if (dev->power.direct_complete) pm_request_resume(dev); } +EXPORT_SYMBOL_GPL(acpi_subsys_complete); /** * acpi_subsys_suspend - Run the device driver's suspend callback. @@ -951,6 +952,7 @@ int acpi_subsys_suspend(struct device *dev) pm_runtime_resume(dev); return pm_generic_suspend(dev); } +EXPORT_SYMBOL_GPL(acpi_subsys_suspend); /** * acpi_subsys_suspend_late - Suspend device using ACPI. @@ -996,6 +998,7 @@ int acpi_subsys_freeze(struct device *dev) pm_runtime_resume(dev); return pm_generic_freeze(dev); } +EXPORT_SYMBOL_GPL(acpi_subsys_freeze); #endif /* CONFIG_PM_SLEEP */ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 7a8f2cd66c8b..4c007262e891 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -554,14 +554,20 @@ static inline int acpi_subsys_runtime_resume(struct device *dev) { return 0; } int acpi_dev_suspend_late(struct device *dev); int acpi_dev_resume_early(struct device *dev); int acpi_subsys_prepare(struct device *dev); +void acpi_subsys_complete(struct device *dev); int acpi_subsys_suspend_late(struct device *dev); int acpi_subsys_resume_early(struct device *dev); +int acpi_subsys_suspend(struct device *dev); +int acpi_subsys_freeze(struct device *dev); #else static inline int acpi_dev_suspend_late(struct device *dev) { return 0; } static inline int acpi_dev_resume_early(struct device *dev) { return 0; } static inline int acpi_subsys_prepare(struct device *dev) { return 0; } +static inline void acpi_subsys_complete(struct device *dev) {} static inline int acpi_subsys_suspend_late(struct device *dev) { return 0; } static inline int acpi_subsys_resume_early(struct device *dev) { return 0; } +static inline int acpi_subsys_suspend(struct device *dev) { return 0; } +static inline int acpi_subsys_freeze(struct device *dev) { return 0; } #endif #if defined(CONFIG_ACPI) && defined(CONFIG_PM) From e2d0e90fae82809667f1dcf4d0d9baa421691c7a Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 15 May 2014 16:40:25 +0300 Subject: [PATCH 083/134] clk: new basic clk type for fractional divider Fractional divider clocks are fairly common. This adds basic type for them. Signed-off-by: Heikki Krogerus Acked-by: Mike Turquette Signed-off-by: Rafael J. Wysocki --- drivers/clk/Makefile | 1 + drivers/clk/clk-fractional-divider.c | 135 +++++++++++++++++++++++++++ include/linux/clk-provider.h | 31 ++++++ 3 files changed, 167 insertions(+) create mode 100644 drivers/clk/clk-fractional-divider.c diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 5f8a28735c96..0745059b1834 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o obj-$(CONFIG_COMMON_CLK) += clk-gate.o obj-$(CONFIG_COMMON_CLK) += clk-mux.o obj-$(CONFIG_COMMON_CLK) += clk-composite.o +obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o # hardware specific clock types # please keep this section sorted lexicographically by file/directory path name diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c new file mode 100644 index 000000000000..ede685ca0d20 --- /dev/null +++ b/drivers/clk/clk-fractional-divider.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2014 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Adjustable fractional divider clock implementation. + * Output rate = (m / n) * parent_rate. + */ + +#include +#include +#include +#include +#include + +#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw) + +static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_fractional_divider *fd = to_clk_fd(hw); + unsigned long flags = 0; + u32 val, m, n; + u64 ret; + + if (fd->lock) + spin_lock_irqsave(fd->lock, flags); + + val = clk_readl(fd->reg); + + if (fd->lock) + spin_unlock_irqrestore(fd->lock, flags); + + m = (val & fd->mmask) >> fd->mshift; + n = (val & fd->nmask) >> fd->nshift; + + ret = parent_rate * m; + do_div(ret, n); + + return ret; +} + +static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_fractional_divider *fd = to_clk_fd(hw); + unsigned maxn = (fd->nmask >> fd->nshift) + 1; + unsigned div; + + if (!rate || rate >= *prate) + return *prate; + + div = gcd(*prate, rate); + + while ((*prate / div) > maxn) { + div <<= 1; + rate <<= 1; + } + + return rate; +} + +static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_fractional_divider *fd = to_clk_fd(hw); + unsigned long flags = 0; + unsigned long div; + unsigned n, m; + u32 val; + + div = gcd(parent_rate, rate); + m = rate / div; + n = parent_rate / div; + + if (fd->lock) + spin_lock_irqsave(fd->lock, flags); + + val = clk_readl(fd->reg); + val &= ~(fd->mmask | fd->nmask); + val |= (m << fd->mshift) | (n << fd->nshift); + clk_writel(val, fd->reg); + + if (fd->lock) + spin_unlock_irqrestore(fd->lock, flags); + + return 0; +} + +const struct clk_ops clk_fractional_divider_ops = { + .recalc_rate = clk_fd_recalc_rate, + .round_rate = clk_fd_round_rate, + .set_rate = clk_fd_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_fractional_divider_ops); + +struct clk *clk_register_fractional_divider(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth, + u8 clk_divider_flags, spinlock_t *lock) +{ + struct clk_fractional_divider *fd; + struct clk_init_data init; + struct clk *clk; + + fd = kzalloc(sizeof(*fd), GFP_KERNEL); + if (!fd) { + dev_err(dev, "could not allocate fractional divider clk\n"); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &clk_fractional_divider_ops; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + fd->reg = reg; + fd->mshift = mshift; + fd->mmask = (BIT(mwidth) - 1) << mshift; + fd->nshift = nshift; + fd->nmask = (BIT(nwidth) - 1) << nshift; + fd->flags = clk_divider_flags; + fd->lock = lock; + fd->hw.init = &init; + + clk = clk_register(dev, &fd->hw); + if (IS_ERR(clk)) + kfree(fd); + + return clk; +} +EXPORT_SYMBOL_GPL(clk_register_fractional_divider); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 511917416fb0..fb4eca6907cd 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -413,6 +413,37 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned int mult, unsigned int div); +/** + * struct clk_fractional_divider - adjustable fractional divider clock + * + * @hw: handle between common and hardware-specific interfaces + * @reg: register containing the divider + * @mshift: shift to the numerator bit field + * @mwidth: width of the numerator bit field + * @nshift: shift to the denominator bit field + * @nwidth: width of the denominator bit field + * @lock: register lock + * + * Clock with adjustable fractional divider affecting its output frequency. + */ + +struct clk_fractional_divider { + struct clk_hw hw; + void __iomem *reg; + u8 mshift; + u32 mmask; + u8 nshift; + u32 nmask; + u8 flags; + spinlock_t *lock; +}; + +extern const struct clk_ops clk_fractional_divider_ops; +struct clk *clk_register_fractional_divider(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth, + u8 clk_divider_flags, spinlock_t *lock); + /*** * struct clk_composite - aggregate clock of mux, divider and gate clocks * From 1b7f37e1276bee9043d35a4b39ef2f43d3b2e133 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 17 May 2014 10:48:01 +0200 Subject: [PATCH 084/134] ACPI / video: Add an acpi_video_unregister_backlight function Add an acpi_video_unregister_backlight function, which only unregisters the backlight device, and leaves the acpi_notifier in place. Some acpi_vendor driver need this as they don't want the acpi_video# backlight device, but do need the acpi-video driver for hotkey handling. Chances are that this new acpi_video_unregister_backlight() is actually what existing acpi_vendor drivers have wanted all along. Currently acpi_vendor drivers which want to disable the acpi_video# backlight device, make 2 calls: acpi_video_dmi_promote_vendor(); acpi_video_unregister(); The intention here is to make things independent of when acpi_video_register() gets called. As acpi_video_register() will get called on acpi-video load time on non intel gfx machines, while it gets called on i915 load time on intel gfx machines. This leads to the following 2 interesting scenarios: a) intel gfx: 1) acpi-video module gets loaded (as it is a dependency of acpi_vendor and i915) 2) acpi-video does NOT call acpi_video_register() 3) acpi_vendor loads (lets assume it loads before i915), calls acpi_video_dmi_promote_vendor(); which sets ACPI_VIDEO_BACKLIGHT_DMI_VENDOR 4) calls acpi_video_unregister -> not registered, nop 5) i915 loads, calls acpi_video_register 6) acpi_video_register registers the acpi_notifier for the hotkeys, does NOT register a backlight device because of ACPI_VIDEO_BACKLIGHT_DMI_VENDOR b) non intel gfx 1) acpi-video module gets loaded (as it is a dependency acpi_vendor) 2) acpi-video calls acpi_video_register() 3) acpi_video_register registers the acpi_notifier for the hotkeys, and a backlight device 4) acpi_vendor loads, calls acpi_video_dmi_promote_vendor() 5) calls acpi_video_unregister, this unregisters BOTH the acpi_notifier for the hotkeys AND the backlight device So here we have possibly the same acpi_vendor module, making the same calls, but with different results, in one cases acpi-video does handle hotkeys, in the other it does not. Note that the a) scenario turns into b) if we assume the i915 module loads before the vendor_acpi module, so we also have different behavior depending on module loading order! So as said I believe that quite a few existing acpi_vendor modules really always want the behavior of a), hence this patch adds a new acpi_video_unregister_backlight() which gives the behavior of a) independent of module loading order. Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/video.c | 14 ++++++++++++++ include/acpi/video.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index ff79dff371fd..adbfe39f5454 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -2078,6 +2078,20 @@ void acpi_video_unregister(void) } EXPORT_SYMBOL(acpi_video_unregister); +void acpi_video_unregister_backlight(void) +{ + struct acpi_video_bus *video; + + if (!register_count) + return; + + mutex_lock(&video_list_lock); + list_for_each_entry(video, &video_bus_head, entry) + acpi_video_bus_unregister_backlight(video); + mutex_unlock(&video_list_lock); +} +EXPORT_SYMBOL(acpi_video_unregister_backlight); + /* * This is kind of nasty. Hardware using Intel chipsets may require * the video opregion code to be run first in order to initialise diff --git a/include/acpi/video.h b/include/acpi/video.h index 61109f2609fc..ea4c7bbded4d 100644 --- a/include/acpi/video.h +++ b/include/acpi/video.h @@ -19,11 +19,13 @@ struct acpi_device; #if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE) extern int acpi_video_register(void); extern void acpi_video_unregister(void); +extern void acpi_video_unregister_backlight(void); extern int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, void **edid); #else static inline int acpi_video_register(void) { return 0; } static inline void acpi_video_unregister(void) { return; } +static inline void acpi_video_unregister_backlight(void) { return; } static inline int acpi_video_get_edid(struct acpi_device *device, int type, int device_id, void **edid) { From d13374154e571293bb13df743b8d53b1e6797807 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 17 May 2014 10:48:02 +0200 Subject: [PATCH 085/134] acer-wmi: Switch to acpi_video_unregister_backlight Switch from acpi_video_unregister(), to acpi_video_unregister_backlight(), so that the hotkeys handler registered by acpi-video stays in place. Since there are no mappings for the atkbd raw codes for the brightness keys used by newer Acer models in /lib/udev/hwdb.d/60-keyboard.hwdb, and since we map the wmi events with a code of KE_IGNORE, we rely on acpi-video to do the hotkey handling for us. For laptops such as the Acer Aspire 5750 which uses intel gfx this works despite us calling acpi_video_unregister() because the following happens: 1) acpi-video module gets loaded (as it is a dependency of acer-wmi and i915) 2) acpi-video does NOT call acpi_video_register() 3) acer-wmi loads (assume it loads before i915), calls acpi_video_dmi_promote_vendor(); which sets ACPI_VIDEO_BACKLIGHT_DMI_VENDOR 4) calls acpi_video_unregister -> not registered, nop 5) i915 loads, calls acpi_video_register 6) acpi_video_register registers the acpi_notifier for the hotkeys, does NOT register a backlight device because of ACPI_VIDEO_BACKLIGHT_DMI_VENDOR But on the Acer Aspire 5750G, which uses nvidia graphics the following happens: 1) acpi-video module gets loaded (as it is a dependency of acer-wmi) 2) acpi-video calls acpi_video_register() 3) acpi_video_register registers the acpi_notifier for the hotkeys, and a backlight device 4) acer-wmi loads, calls acpi_video_dmi_promote_vendor() 5) calls acpi_video_unregister, this unregisters BOTH the acpi_notifier for the hotkeys AND the backlight device And we end up without any handler for the brightness hotkeys. This patch fixes this by switching over to acpi_video_unregister_backlight() which keeps the hotkey handler in place. References: https://bugzilla.kernel.org/show_bug.cgi?id=35622 Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/platform/x86/acer-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index c91f69b39db4..3a746998f92a 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -2228,7 +2228,7 @@ static int __init acer_wmi_init(void) pr_info("Brightness must be controlled by acpi video driver\n"); } else { pr_info("Disabling ACPI video driver\n"); - acpi_video_unregister(); + acpi_video_unregister_backlight(); } if (wmi_has_guid(WMID_GUID3)) { From 9404cd95507de0a61f2a000fbd76748a9cae33b4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 17 May 2014 10:48:03 +0200 Subject: [PATCH 086/134] acer-wmi: Add Aspire 5741 to video_vendor_dmi_table The Aspire 5741 has broken acpi-video backlight control, so add it to the quirk table. References: https://bugzilla.redhat.com/show_bug.cgi?id=1012674 Signed-off-by: Hans de Goede Reviewed-by: Lee, Chun-Yi Signed-off-by: Rafael J. Wysocki --- drivers/platform/x86/acer-wmi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 3a746998f92a..bbf78b2d6d93 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -570,6 +570,14 @@ static const struct dmi_system_id video_vendor_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"), }, }, + { + .callback = video_set_backlight_video_vendor, + .ident = "Acer Aspire 5741", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"), + }, + }, {} }; From 8ce62f85a81f57e86bc120ab690facc612223188 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 25 May 2014 14:38:52 +0200 Subject: [PATCH 087/134] ACPI / platform / LPSS: Enable async suspend/resume of LPSS devices To seed up suspend and resume of devices included into Intel SoCs handled by the ACPI LPSS driver during system suspend, make acpi_lpss_create_device() call device_enable_async_suspend() for every device created by it. This requires acpi_create_platform_device() to be modified to return a pointer to struct platform_device instead of an int. As a result, acpi_create_platform_device() cannot be pointed to by the .attach pointer in platform_handler directly any more, so a simple wrapper around it is necessary for this purpose. That, in turn, allows the second unused argument of acpi_create_platform_device() to be dropped, which is an improvement. Tested-by: Heikki Krogerus Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_lpss.c | 17 +++++++++++------ drivers/acpi/acpi_platform.c | 25 ++++++++++++++----------- drivers/acpi/internal.h | 3 +-- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 69e29f409d4c..0e9c0d38b85c 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -267,12 +267,14 @@ static int acpi_lpss_create_device(struct acpi_device *adev, struct lpss_private_data *pdata; struct resource_list_entry *rentry; struct list_head resource_list; + struct platform_device *pdev; int ret; dev_desc = (struct lpss_device_desc *)id->driver_data; - if (!dev_desc) - return acpi_create_platform_device(adev, id); - + if (!dev_desc) { + pdev = acpi_create_platform_device(adev); + return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1; + } pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; @@ -322,10 +324,13 @@ static int acpi_lpss_create_device(struct acpi_device *adev, dev_desc->setup(pdata); adev->driver_data = pdata; - ret = acpi_create_platform_device(adev, id); - if (ret > 0) - return ret; + pdev = acpi_create_platform_device(adev); + if (!IS_ERR_OR_NULL(pdev)) { + device_enable_async_suspend(&pdev->dev); + return 1; + } + ret = PTR_ERR(pdev); adev->driver_data = NULL; err_out: diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index c0a39417ebe4..9f7bcfdf18ef 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -47,7 +47,6 @@ static const struct acpi_device_id acpi_platform_device_ids[] = { /** * acpi_create_platform_device - Create platform device for ACPI device node * @adev: ACPI device node to create a platform device for. - * @id: ACPI device ID used to match @adev. * * Check if the given @adev can be represented as a platform device and, if * that's the case, create and register a platform device, populate its common @@ -55,8 +54,7 @@ static const struct acpi_device_id acpi_platform_device_ids[] = { * * Name of the platform device will be the same as @adev's. */ -int acpi_create_platform_device(struct acpi_device *adev, - const struct acpi_device_id *id) +struct platform_device *acpi_create_platform_device(struct acpi_device *adev) { struct platform_device *pdev = NULL; struct acpi_device *acpi_parent; @@ -68,19 +66,19 @@ int acpi_create_platform_device(struct acpi_device *adev, /* If the ACPI node already has a physical device attached, skip it. */ if (adev->physical_node_count) - return 0; + return NULL; INIT_LIST_HEAD(&resource_list); count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); if (count < 0) { - return 0; + return NULL; } else if (count > 0) { resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL); if (!resources) { dev_err(&adev->dev, "No memory for resources\n"); acpi_dev_free_resource_list(&resource_list); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } count = 0; list_for_each_entry(rentry, &resource_list, node) @@ -117,22 +115,27 @@ int acpi_create_platform_device(struct acpi_device *adev, pdevinfo.num_res = count; pdevinfo.acpi_node.companion = adev; pdev = platform_device_register_full(&pdevinfo); - if (IS_ERR(pdev)) { + if (IS_ERR(pdev)) dev_err(&adev->dev, "platform device creation failed: %ld\n", PTR_ERR(pdev)); - pdev = NULL; - } else { + else dev_dbg(&adev->dev, "created platform device %s\n", dev_name(&pdev->dev)); - } kfree(resources); + return pdev; +} + +static int acpi_platform_attach(struct acpi_device *adev, + const struct acpi_device_id *id) +{ + acpi_create_platform_device(adev); return 1; } static struct acpi_scan_handler platform_handler = { .ids = acpi_platform_device_ids, - .attach = acpi_create_platform_device, + .attach = acpi_platform_attach, }; void __init acpi_platform_init(void) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 957391306cbf..bb7de413d06d 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -180,8 +180,7 @@ static inline void suspend_nvs_restore(void) {} -------------------------------------------------------------------------- */ struct platform_device; -int acpi_create_platform_device(struct acpi_device *adev, - const struct acpi_device_id *id); +struct platform_device *acpi_create_platform_device(struct acpi_device *adev); /*-------------------------------------------------------------------------- Video From c78b0830667a7e7c1f0ca65b76b33166a84806b3 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Fri, 23 May 2014 16:15:09 +0300 Subject: [PATCH 088/134] ACPI / LPSS: custom power domain for LPSS A power domain where we save the context of the additional LPSS registers. We need to do this or all LPSS devices are left in reset state when resuming from D3 on some Baytrails. The devices with the fractional clock divider also have zeros for N and M values after resuming unless they are reset. Li Aubrey found the root cause for the issue. The idea of using power domain for LPSS came from Mika Westerberg. Reported-by: Jin Yao Suggested-by: Li Aubrey Suggested-by: Mika Westerberg Tested-by: Mika Westerberg Signed-off-by: Heikki Krogerus [rjw: Added the .complete() callback to the PM domain, fixed build warning on 32-bit.] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_lpss.c | 157 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 150 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 69e29f409d4c..a01d4d1343dd 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "internal.h" @@ -43,6 +44,8 @@ ACPI_MODULE_NAME("acpi_lpss"); #define LPSS_TX_INT 0x20 #define LPSS_TX_INT_MASK BIT(1) +#define LPSS_PRV_REG_COUNT 9 + struct lpss_shared_clock { const char *name; unsigned long rate; @@ -58,6 +61,7 @@ struct lpss_device_desc { unsigned int prv_offset; size_t prv_size_override; bool clk_gate; + bool save_ctx; struct lpss_shared_clock *shared_clock; void (*setup)(struct lpss_private_data *pdata); }; @@ -72,6 +76,7 @@ struct lpss_private_data { resource_size_t mmio_size; struct clk *clk; const struct lpss_device_desc *dev_desc; + u32 prv_reg_ctx[LPSS_PRV_REG_COUNT]; }; static void lpss_uart_setup(struct lpss_private_data *pdata) @@ -116,6 +121,7 @@ static struct lpss_shared_clock pwm_clock = { static struct lpss_device_desc byt_pwm_dev_desc = { .clk_required = true, + .save_ctx = true, .shared_clock = &pwm_clock, }; @@ -128,6 +134,7 @@ static struct lpss_device_desc byt_uart_dev_desc = { .clk_required = true, .prv_offset = 0x800, .clk_gate = true, + .save_ctx = true, .shared_clock = &uart_clock, .setup = lpss_uart_setup, }; @@ -141,6 +148,7 @@ static struct lpss_device_desc byt_spi_dev_desc = { .clk_required = true, .prv_offset = 0x400, .clk_gate = true, + .save_ctx = true, .shared_clock = &spi_clock, }; @@ -156,6 +164,7 @@ static struct lpss_shared_clock i2c_clock = { static struct lpss_device_desc byt_i2c_dev_desc = { .clk_required = true, .prv_offset = 0x800, + .save_ctx = true, .shared_clock = &i2c_clock, }; @@ -449,6 +458,126 @@ static void acpi_lpss_set_ltr(struct device *dev, s32 val) } } +#ifdef CONFIG_PM +/** + * acpi_lpss_save_ctx() - Save the private registers of LPSS device + * @dev: LPSS device + * + * Most LPSS devices have private registers which may loose their context when + * the device is powered down. acpi_lpss_save_ctx() saves those registers into + * prv_reg_ctx array. + */ +static void acpi_lpss_save_ctx(struct device *dev) +{ + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + unsigned int i; + + for (i = 0; i < LPSS_PRV_REG_COUNT; i++) { + unsigned long offset = i * sizeof(u32); + + pdata->prv_reg_ctx[i] = __lpss_reg_read(pdata, offset); + dev_dbg(dev, "saving 0x%08x from LPSS reg at offset 0x%02lx\n", + pdata->prv_reg_ctx[i], offset); + } +} + +/** + * acpi_lpss_restore_ctx() - Restore the private registers of LPSS device + * @dev: LPSS device + * + * Restores the registers that were previously stored with acpi_lpss_save_ctx(). + */ +static void acpi_lpss_restore_ctx(struct device *dev) +{ + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + unsigned int i; + + /* + * The following delay is needed or the subsequent write operations may + * fail. The LPSS devices are actually PCI devices and the PCI spec + * expects 10ms delay before the device can be accessed after D3 to D0 + * transition. + */ + msleep(10); + + for (i = 0; i < LPSS_PRV_REG_COUNT; i++) { + unsigned long offset = i * sizeof(u32); + + __lpss_reg_write(pdata->prv_reg_ctx[i], pdata, offset); + dev_dbg(dev, "restoring 0x%08x to LPSS reg at offset 0x%02lx\n", + pdata->prv_reg_ctx[i], offset); + } +} + +#ifdef CONFIG_PM_SLEEP +static int acpi_lpss_suspend_late(struct device *dev) +{ + int ret = pm_generic_suspend_late(dev); + + if (ret) + return ret; + + acpi_lpss_save_ctx(dev); + return acpi_dev_suspend_late(dev); +} + +static int acpi_lpss_restore_early(struct device *dev) +{ + int ret = acpi_dev_resume_early(dev); + + if (ret) + return ret; + + acpi_lpss_restore_ctx(dev); + return pm_generic_resume_early(dev); +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM_RUNTIME +static int acpi_lpss_runtime_suspend(struct device *dev) +{ + int ret = pm_generic_runtime_suspend(dev); + + if (ret) + return ret; + + acpi_lpss_save_ctx(dev); + return acpi_dev_runtime_suspend(dev); +} + +static int acpi_lpss_runtime_resume(struct device *dev) +{ + int ret = acpi_dev_runtime_resume(dev); + + if (ret) + return ret; + + acpi_lpss_restore_ctx(dev); + return pm_generic_runtime_resume(dev); +} +#endif /* CONFIG_PM_RUNTIME */ +#endif /* CONFIG_PM */ + +static struct dev_pm_domain acpi_lpss_pm_domain = { + .ops = { +#ifdef CONFIG_PM_SLEEP + .suspend_late = acpi_lpss_suspend_late, + .restore_early = acpi_lpss_restore_early, + .prepare = acpi_subsys_prepare, + .complete = acpi_subsys_complete, + .suspend = acpi_subsys_suspend, + .resume_early = acpi_subsys_resume_early, + .freeze = acpi_subsys_freeze, + .poweroff = acpi_subsys_suspend, + .poweroff_late = acpi_subsys_suspend_late, +#endif +#ifdef CONFIG_PM_RUNTIME + .runtime_suspend = acpi_lpss_runtime_suspend, + .runtime_resume = acpi_lpss_runtime_resume, +#endif + }, +}; + static int acpi_lpss_platform_notify(struct notifier_block *nb, unsigned long action, void *data) { @@ -456,7 +585,6 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb, struct lpss_private_data *pdata; struct acpi_device *adev; const struct acpi_device_id *id; - int ret = 0; id = acpi_match_device(acpi_lpss_device_ids, &pdev->dev); if (!id || !id->driver_data) @@ -466,7 +594,7 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb, return 0; pdata = acpi_driver_data(adev); - if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required) + if (!pdata || !pdata->mmio_base) return 0; if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) { @@ -474,12 +602,27 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb, return 0; } - if (action == BUS_NOTIFY_ADD_DEVICE) - ret = sysfs_create_group(&pdev->dev.kobj, &lpss_attr_group); - else if (action == BUS_NOTIFY_DEL_DEVICE) - sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); + switch (action) { + case BUS_NOTIFY_BOUND_DRIVER: + if (pdata->dev_desc->save_ctx) + pdev->dev.pm_domain = &acpi_lpss_pm_domain; + break; + case BUS_NOTIFY_UNBOUND_DRIVER: + if (pdata->dev_desc->save_ctx) + pdev->dev.pm_domain = NULL; + break; + case BUS_NOTIFY_ADD_DEVICE: + if (pdata->dev_desc->ltr_required) + return sysfs_create_group(&pdev->dev.kobj, + &lpss_attr_group); + case BUS_NOTIFY_DEL_DEVICE: + if (pdata->dev_desc->ltr_required) + sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); + default: + break; + } - return ret; + return 0; } static struct notifier_block acpi_lpss_nb = { From ed3a872e2ef62bde06e2f579d8d1458766ced078 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 19 May 2014 14:42:07 +0300 Subject: [PATCH 089/134] ACPI / LPSS: support for fractional divider clock This creates fractional divider type clock for the ones that have it. It is needed by the UART driver as the clock rate must accommodate to the requested baud rate. Signed-off-by: Heikki Krogerus Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_lpss.c | 75 ++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index a01d4d1343dd..d1c9b04e29a3 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -29,6 +29,7 @@ ACPI_MODULE_NAME("acpi_lpss"); #define LPSS_LTR_SIZE 0x18 /* Offsets relative to LPSS_PRIVATE_OFFSET */ +#define LPSS_CLK_DIVIDER_DEF_MASK (BIT(1) | BIT(16)) #define LPSS_GENERAL 0x08 #define LPSS_GENERAL_LTR_MODE_SW BIT(2) #define LPSS_GENERAL_UART_RTS_OVRD BIT(3) @@ -60,6 +61,7 @@ struct lpss_device_desc { bool ltr_required; unsigned int prv_offset; size_t prv_size_override; + bool clk_divider; bool clk_gate; bool save_ctx; struct lpss_shared_clock *shared_clock; @@ -94,6 +96,14 @@ static void lpss_uart_setup(struct lpss_private_data *pdata) } static struct lpss_device_desc lpt_dev_desc = { + .clk_required = true, + .prv_offset = 0x800, + .ltr_required = true, + .clk_divider = true, + .clk_gate = true, +}; + +static struct lpss_device_desc lpt_i2c_dev_desc = { .clk_required = true, .prv_offset = 0x800, .ltr_required = true, @@ -104,6 +114,7 @@ static struct lpss_device_desc lpt_uart_dev_desc = { .clk_required = true, .prv_offset = 0x800, .ltr_required = true, + .clk_divider = true, .clk_gate = true, .setup = lpss_uart_setup, }; @@ -125,31 +136,21 @@ static struct lpss_device_desc byt_pwm_dev_desc = { .shared_clock = &pwm_clock, }; -static struct lpss_shared_clock uart_clock = { - .name = "uart_clk", - .rate = 44236800, -}; - static struct lpss_device_desc byt_uart_dev_desc = { .clk_required = true, .prv_offset = 0x800, + .clk_divider = true, .clk_gate = true, .save_ctx = true, - .shared_clock = &uart_clock, .setup = lpss_uart_setup, }; -static struct lpss_shared_clock spi_clock = { - .name = "spi_clk", - .rate = 50000000, -}; - static struct lpss_device_desc byt_spi_dev_desc = { .clk_required = true, .prv_offset = 0x400, + .clk_divider = true, .clk_gate = true, .save_ctx = true, - .shared_clock = &spi_clock, }; static struct lpss_device_desc byt_sdio_dev_desc = { @@ -175,8 +176,8 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = { /* Lynxpoint LPSS devices */ { "INT33C0", (unsigned long)&lpt_dev_desc }, { "INT33C1", (unsigned long)&lpt_dev_desc }, - { "INT33C2", (unsigned long)&lpt_dev_desc }, - { "INT33C3", (unsigned long)&lpt_dev_desc }, + { "INT33C2", (unsigned long)&lpt_i2c_dev_desc }, + { "INT33C3", (unsigned long)&lpt_i2c_dev_desc }, { "INT33C4", (unsigned long)&lpt_uart_dev_desc }, { "INT33C5", (unsigned long)&lpt_uart_dev_desc }, { "INT33C6", (unsigned long)&lpt_sdio_dev_desc }, @@ -192,8 +193,8 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = { { "INT3430", (unsigned long)&lpt_dev_desc }, { "INT3431", (unsigned long)&lpt_dev_desc }, - { "INT3432", (unsigned long)&lpt_dev_desc }, - { "INT3433", (unsigned long)&lpt_dev_desc }, + { "INT3432", (unsigned long)&lpt_i2c_dev_desc }, + { "INT3433", (unsigned long)&lpt_i2c_dev_desc }, { "INT3434", (unsigned long)&lpt_uart_dev_desc }, { "INT3435", (unsigned long)&lpt_uart_dev_desc }, { "INT3436", (unsigned long)&lpt_sdio_dev_desc }, @@ -221,9 +222,11 @@ static int register_device_clock(struct acpi_device *adev, { const struct lpss_device_desc *dev_desc = pdata->dev_desc; struct lpss_shared_clock *shared_clock = dev_desc->shared_clock; + const char *devname = dev_name(&adev->dev); struct clk *clk = ERR_PTR(-ENODEV); struct lpss_clk_data *clk_data; - const char *parent; + const char *parent, *clk_name; + void __iomem *prv_base; if (!lpss_clk_dev) lpt_register_clock_device(); @@ -234,7 +237,7 @@ static int register_device_clock(struct acpi_device *adev, if (dev_desc->clkdev_name) { clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name, - dev_name(&adev->dev)); + devname); return 0; } @@ -243,6 +246,7 @@ static int register_device_clock(struct acpi_device *adev, return -ENODATA; parent = clk_data->name; + prv_base = pdata->mmio_base + dev_desc->prv_offset; if (shared_clock) { clk = shared_clock->clk; @@ -256,16 +260,41 @@ static int register_device_clock(struct acpi_device *adev, } if (dev_desc->clk_gate) { - clk = clk_register_gate(NULL, dev_name(&adev->dev), parent, 0, - pdata->mmio_base + dev_desc->prv_offset, - 0, 0, NULL); - pdata->clk = clk; + clk = clk_register_gate(NULL, devname, parent, 0, + prv_base, 0, 0, NULL); + parent = devname; + } + + if (dev_desc->clk_divider) { + /* Prevent division by zero */ + if (!readl(prv_base)) + writel(LPSS_CLK_DIVIDER_DEF_MASK, prv_base); + + clk_name = kasprintf(GFP_KERNEL, "%s-div", devname); + if (!clk_name) + return -ENOMEM; + clk = clk_register_fractional_divider(NULL, clk_name, parent, + 0, prv_base, + 1, 15, 16, 15, 0, NULL); + parent = clk_name; + + clk_name = kasprintf(GFP_KERNEL, "%s-update", devname); + if (!clk_name) { + kfree(parent); + return -ENOMEM; + } + clk = clk_register_gate(NULL, clk_name, parent, + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, + prv_base, 31, 0, NULL); + kfree(parent); + kfree(clk_name); } if (IS_ERR(clk)) return PTR_ERR(clk); - clk_register_clkdev(clk, NULL, dev_name(&adev->dev)); + pdata->clk = clk; + clk_register_clkdev(clk, NULL, devname); return 0; } From 27ddcc6596e50cb8f03d2e83248897667811d8f6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 26 May 2014 13:40:47 +0200 Subject: [PATCH 090/134] PM / sleep: Add state field to pm_states[] entries To allow sleep states corresponding to the "mem", "standby" and "freeze" lables to be different from the pm_states[] indexes of those strings, introduce struct pm_sleep_state, consisting of a string label and a state number, and turn pm_states[] into an array of objects of that type. This modification should not lead to any functional changes. Signed-off-by: Rafael J. Wysocki --- kernel/power/main.c | 16 ++++++++-------- kernel/power/power.h | 7 ++++++- kernel/power/suspend.c | 12 ++++++------ kernel/power/suspend_test.c | 22 ++++++++++------------ 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/kernel/power/main.c b/kernel/power/main.c index 6271bc4073ef..8e818432253c 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -293,12 +293,12 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, { char *s = buf; #ifdef CONFIG_SUSPEND - int i; + suspend_state_t i; + + for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) + if (valid_state(i)) + s += sprintf(s,"%s ", pm_states[i].label); - for (i = 0; i < PM_SUSPEND_MAX; i++) { - if (pm_states[i] && valid_state(i)) - s += sprintf(s,"%s ", pm_states[i]); - } #endif #ifdef CONFIG_HIBERNATION s += sprintf(s, "%s\n", "disk"); @@ -314,7 +314,7 @@ static suspend_state_t decode_state(const char *buf, size_t n) { #ifdef CONFIG_SUSPEND suspend_state_t state = PM_SUSPEND_MIN; - const char * const *s; + struct pm_sleep_state *s; #endif char *p; int len; @@ -328,7 +328,7 @@ static suspend_state_t decode_state(const char *buf, size_t n) #ifdef CONFIG_SUSPEND for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) - if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) + if (len == strlen(s->label) && !strncmp(buf, s->label, len)) return state; #endif @@ -448,7 +448,7 @@ static ssize_t autosleep_show(struct kobject *kobj, #ifdef CONFIG_SUSPEND if (state < PM_SUSPEND_MAX) return sprintf(buf, "%s\n", valid_state(state) ? - pm_states[state] : "error"); + pm_states[state].label : "error"); #endif #ifdef CONFIG_HIBERNATION return sprintf(buf, "disk\n"); diff --git a/kernel/power/power.h b/kernel/power/power.h index 15f37ea08719..99539c5da844 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -178,8 +178,13 @@ extern void swsusp_show_speed(struct timeval *, struct timeval *, unsigned int, char *); #ifdef CONFIG_SUSPEND +struct pm_sleep_state { + const char *label; + suspend_state_t state; +}; + /* kernel/power/suspend.c */ -extern const char *const pm_states[]; +extern struct pm_sleep_state pm_states[]; extern bool valid_state(suspend_state_t state); extern int suspend_devices_and_enter(suspend_state_t state); diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 155721f7f909..5d93b138a2d4 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -31,10 +31,10 @@ #include "power.h" -const char *const pm_states[PM_SUSPEND_MAX] = { - [PM_SUSPEND_FREEZE] = "freeze", - [PM_SUSPEND_STANDBY] = "standby", - [PM_SUSPEND_MEM] = "mem", +struct pm_sleep_state pm_states[PM_SUSPEND_MAX] = { + [PM_SUSPEND_FREEZE] = { "freeze", PM_SUSPEND_FREEZE }, + [PM_SUSPEND_STANDBY] = { "standby", PM_SUSPEND_STANDBY }, + [PM_SUSPEND_MEM] = { "mem", PM_SUSPEND_MEM }, }; static const struct platform_suspend_ops *suspend_ops; @@ -343,7 +343,7 @@ static int enter_state(suspend_state_t state) sys_sync(); printk("done.\n"); - pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); + pr_debug("PM: Preparing system for %s sleep\n", pm_states[state].label); error = suspend_prepare(state); if (error) goto Unlock; @@ -351,7 +351,7 @@ static int enter_state(suspend_state_t state) if (suspend_test(TEST_FREEZER)) goto Finish; - pr_debug("PM: Entering %s sleep\n", pm_states[state]); + pr_debug("PM: Entering %s sleep\n", pm_states[state].label); pm_restrict_gfp_mask(); error = suspend_devices_and_enter(state); pm_restore_gfp_mask(); diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c index 9b2a1d58558d..d4e3ab167a73 100644 --- a/kernel/power/suspend_test.c +++ b/kernel/power/suspend_test.c @@ -92,13 +92,13 @@ static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state) } if (state == PM_SUSPEND_MEM) { - printk(info_test, pm_states[state]); + printk(info_test, pm_states[state].label); status = pm_suspend(state); if (status == -ENODEV) state = PM_SUSPEND_STANDBY; } if (state == PM_SUSPEND_STANDBY) { - printk(info_test, pm_states[state]); + printk(info_test, pm_states[state].label); status = pm_suspend(state); } if (status < 0) @@ -136,18 +136,16 @@ static char warn_bad_state[] __initdata = static int __init setup_test_suspend(char *value) { - unsigned i; + suspend_state_t i; /* "=mem" ==> "mem" */ value++; - for (i = 0; i < PM_SUSPEND_MAX; i++) { - if (!pm_states[i]) - continue; - if (strcmp(pm_states[i], value) != 0) - continue; - test_state = (__force suspend_state_t) i; - return 0; - } + for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) + if (!strcmp(pm_states[i].label, value)) { + test_state = pm_states[i].state; + return 0; + } + printk(warn_bad_state, value); return 0; } @@ -165,7 +163,7 @@ static int __init test_suspend(void) if (test_state == PM_SUSPEND_ON) goto done; if (!valid_state(test_state)) { - printk(warn_bad_state, pm_states[test_state]); + printk(warn_bad_state, pm_states[test_state].label); goto done; } From 43e8317b0bba1d6eb85f38a4a233d82d7c20d732 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 26 May 2014 13:40:53 +0200 Subject: [PATCH 091/134] PM / sleep: Use valid_state() for platform-dependent sleep states only Use the observation that, for platform-dependent sleep states (PM_SUSPEND_STANDBY, PM_SUSPEND_MEM), a given state is either always supported or always unsupported and store that information in pm_states[] instead of calling valid_state() every time we need to check it. Also do not use valid_state() for PM_SUSPEND_FREEZE, which is always valid, and move the pm_test_level validity check for PM_SUSPEND_FREEZE directly into enter_state(). Signed-off-by: Rafael J. Wysocki --- kernel/power/main.c | 9 +++--- kernel/power/power.h | 2 -- kernel/power/suspend.c | 60 ++++++++++++++++++------------------- kernel/power/suspend_test.c | 2 +- 4 files changed, 36 insertions(+), 37 deletions(-) diff --git a/kernel/power/main.c b/kernel/power/main.c index 8e818432253c..9f51f0ab3d86 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -296,7 +296,7 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, suspend_state_t i; for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) - if (valid_state(i)) + if (pm_states[i].state) s += sprintf(s,"%s ", pm_states[i].label); #endif @@ -328,8 +328,9 @@ static suspend_state_t decode_state(const char *buf, size_t n) #ifdef CONFIG_SUSPEND for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) - if (len == strlen(s->label) && !strncmp(buf, s->label, len)) - return state; + if (s->state && len == strlen(s->label) + && !strncmp(buf, s->label, len)) + return s->state; #endif return PM_SUSPEND_ON; @@ -447,7 +448,7 @@ static ssize_t autosleep_show(struct kobject *kobj, #ifdef CONFIG_SUSPEND if (state < PM_SUSPEND_MAX) - return sprintf(buf, "%s\n", valid_state(state) ? + return sprintf(buf, "%s\n", pm_states[state].state ? pm_states[state].label : "error"); #endif #ifdef CONFIG_HIBERNATION diff --git a/kernel/power/power.h b/kernel/power/power.h index 99539c5da844..c60f13b5270a 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -186,14 +186,12 @@ struct pm_sleep_state { /* kernel/power/suspend.c */ extern struct pm_sleep_state pm_states[]; -extern bool valid_state(suspend_state_t state); extern int suspend_devices_and_enter(suspend_state_t state); #else /* !CONFIG_SUSPEND */ static inline int suspend_devices_and_enter(suspend_state_t state) { return -ENOSYS; } -static inline bool valid_state(suspend_state_t state) { return false; } #endif /* !CONFIG_SUSPEND */ #ifdef CONFIG_PM_TEST_SUSPEND diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 5d93b138a2d4..00aca60904b0 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -32,9 +32,9 @@ #include "power.h" struct pm_sleep_state pm_states[PM_SUSPEND_MAX] = { - [PM_SUSPEND_FREEZE] = { "freeze", PM_SUSPEND_FREEZE }, - [PM_SUSPEND_STANDBY] = { "standby", PM_SUSPEND_STANDBY }, - [PM_SUSPEND_MEM] = { "mem", PM_SUSPEND_MEM }, + [PM_SUSPEND_FREEZE] = { .label = "freeze", .state = PM_SUSPEND_FREEZE }, + [PM_SUSPEND_STANDBY] = { .label = "standby", }, + [PM_SUSPEND_MEM] = { .label = "mem", }, }; static const struct platform_suspend_ops *suspend_ops; @@ -68,42 +68,34 @@ void freeze_wake(void) } EXPORT_SYMBOL_GPL(freeze_wake); +static bool valid_state(suspend_state_t state) +{ + /* + * PM_SUSPEND_STANDBY and PM_SUSPEND_MEM states need low level + * support and need to be valid to the low level + * implementation, no valid callback implies that none are valid. + */ + return suspend_ops && suspend_ops->valid && suspend_ops->valid(state); +} + /** * suspend_set_ops - Set the global suspend method table. * @ops: Suspend operations to use. */ void suspend_set_ops(const struct platform_suspend_ops *ops) { + suspend_state_t i; + lock_system_sleep(); + suspend_ops = ops; + for (i = PM_SUSPEND_STANDBY; i <= PM_SUSPEND_MEM; i++) + pm_states[i].state = valid_state(i) ? i : 0; + unlock_system_sleep(); } EXPORT_SYMBOL_GPL(suspend_set_ops); -bool valid_state(suspend_state_t state) -{ - if (state == PM_SUSPEND_FREEZE) { -#ifdef CONFIG_PM_DEBUG - if (pm_test_level != TEST_NONE && - pm_test_level != TEST_FREEZER && - pm_test_level != TEST_DEVICES && - pm_test_level != TEST_PLATFORM) { - printk(KERN_WARNING "Unsupported pm_test mode for " - "freeze state, please choose " - "none/freezer/devices/platform.\n"); - return false; - } -#endif - return true; - } - /* - * PM_SUSPEND_STANDBY and PM_SUSPEND_MEMORY states need lowlevel - * support and need to be valid to the lowlevel - * implementation, no valid callback implies that none are valid. - */ - return suspend_ops && suspend_ops->valid && suspend_ops->valid(state); -} - /** * suspend_valid_only_mem - Generic memory-only valid callback. * @@ -330,9 +322,17 @@ static int enter_state(suspend_state_t state) { int error; - if (!valid_state(state)) - return -ENODEV; - + if (state == PM_SUSPEND_FREEZE) { +#ifdef CONFIG_PM_DEBUG + if (pm_test_level != TEST_NONE && pm_test_level <= TEST_CPUS) { + pr_warning("PM: Unsupported test mode for freeze state," + "please choose none/freezer/devices/platform.\n"); + return -EAGAIN; + } +#endif + } else if (!valid_state(state)) { + return -EINVAL; + } if (!mutex_trylock(&pm_mutex)) return -EBUSY; diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c index d4e3ab167a73..269b097e78ea 100644 --- a/kernel/power/suspend_test.c +++ b/kernel/power/suspend_test.c @@ -162,7 +162,7 @@ static int __init test_suspend(void) /* PM is initialized by now; is that state testable? */ if (test_state == PM_SUSPEND_ON) goto done; - if (!valid_state(test_state)) { + if (!pm_states[test_state].state) { printk(warn_bad_state, pm_states[test_state].label); goto done; } From 0399d4db3edf5c58b6ec7f672f089f5085e49ed5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 26 May 2014 13:40:59 +0200 Subject: [PATCH 092/134] PM / sleep: Introduce command line argument for sleep state enumeration On some systems the platform doesn't support neither PM_SUSPEND_MEM nor PM_SUSPEND_STANDBY, so PM_SUSPEND_FREEZE is the only available system sleep state. However, some user space frameworks only use the "mem" and (sometimes) "standby" sleep state labels, so the users of those systems need to modify user space in order to be able to use system suspend at all and that is not always possible. For this reason, add a new kernel command line argument, relative_sleep_states, allowing the users of those systems to change the way in which the kernel assigns labels to system sleep states. Namely, for relative_sleep_states=1, the "mem", "standby" and "freeze" labels will enumerate the available system sleem states from the deepest to the shallowest, respectively, so that "mem" is always present in /sys/power/state and the other state strings may or may not be presend depending on what is supported by the platform. Update system sleep states documentation to reflect this change. Signed-off-by: Rafael J. Wysocki --- Documentation/ABI/testing/sysfs-power | 29 ++++++--- Documentation/kernel-parameters.txt | 7 +++ Documentation/power/states.txt | 87 +++++++++++++++++---------- kernel/power/main.c | 12 ++-- kernel/power/suspend.c | 32 +++++++++- 5 files changed, 119 insertions(+), 48 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index 64c9276e9421..f4551816329e 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power @@ -7,19 +7,30 @@ Description: subsystem. What: /sys/power/state -Date: August 2006 +Date: May 2014 Contact: Rafael J. Wysocki Description: - The /sys/power/state file controls the system power state. - Reading from this file returns what states are supported, - which is hard-coded to 'freeze' (Low-Power Idle), 'standby' - (Power-On Suspend), 'mem' (Suspend-to-RAM), and 'disk' - (Suspend-to-Disk). + The /sys/power/state file controls system sleep states. + Reading from this file returns the available sleep state + labels, which may be "mem", "standby", "freeze" and "disk" + (hibernation). The meanings of the first three labels depend on + the relative_sleep_states command line argument as follows: + 1) relative_sleep_states = 1 + "mem", "standby", "freeze" represent non-hibernation sleep + states from the deepest ("mem", always present) to the + shallowest ("freeze"). "standby" and "freeze" may or may + not be present depending on the capabilities of the + platform. "freeze" can only be present if "standby" is + present. + 2) relative_sleep_states = 0 (default) + "mem" - "suspend-to-RAM", present if supported. + "standby" - "power-on suspend", present if supported. + "freeze" - "suspend-to-idle", always present. Writing to this file one of these strings causes the system to - transition into that state. Please see the file - Documentation/power/states.txt for a description of each of - these states. + transition into the corresponding state, if available. See + Documentation/power/states.txt for a description of what + "suspend-to-RAM", "power-on suspend" and "suspend-to-idle" mean. What: /sys/power/disk Date: September 2006 diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 43842177b771..e19a88b63eeb 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2889,6 +2889,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. [KNL, SMP] Set scheduler's default relax_domain_level. See Documentation/cgroups/cpusets.txt. + relative_sleep_states= + [SUSPEND] Use sleep state labeling where the deepest + state available other than hibernation is always "mem". + Format: { "0" | "1" } + 0 -- Traditional sleep state labels. + 1 -- Relative sleep state labels. + reserve= [KNL,BUGS] Force the kernel to ignore some iomem area reservetop= [X86-32] diff --git a/Documentation/power/states.txt b/Documentation/power/states.txt index 442d43df9b25..50f3ef9177c1 100644 --- a/Documentation/power/states.txt +++ b/Documentation/power/states.txt @@ -1,62 +1,87 @@ +System Power Management Sleep States -System Power Management States +(C) 2014 Intel Corp., Rafael J. Wysocki +The kernel supports up to four system sleep states generically, although three +of them depend on the platform support code to implement the low-level details +for each state. -The kernel supports four power management states generically, though -one is generic and the other three are dependent on platform support -code to implement the low-level details for each state. -This file describes each state, what they are -commonly called, what ACPI state they map to, and what string to write -to /sys/power/state to enter that state +The states are represented by strings that can be read or written to the +/sys/power/state file. Those strings may be "mem", "standby", "freeze" and +"disk", where the last one always represents hibernation (Suspend-To-Disk) and +the meaning of the remaining ones depends on the relative_sleep_states command +line argument. -state: Freeze / Low-Power Idle +For relative_sleep_states=1, the strings "mem", "standby" and "freeze" label the +available non-hibernation sleep states from the deepest to the shallowest, +respectively. In that case, "mem" is always present in /sys/power/state, +because there is at least one non-hibernation sleep state in every system. If +the given system supports two non-hibernation sleep states, "standby" is present +in /sys/power/state in addition to "mem". If the system supports three +non-hibernation sleep states, "freeze" will be present in /sys/power/state in +addition to "mem" and "standby". + +For relative_sleep_states=0, which is the default, the following descriptions +apply. + +state: Suspend-To-Idle ACPI state: S0 -String: "freeze" +Label: "freeze" -This state is a generic, pure software, light-weight, low-power state. -It allows more energy to be saved relative to idle by freezing user +This state is a generic, pure software, light-weight, system sleep state. +It allows more energy to be saved relative to runtime idle by freezing user space and putting all I/O devices into low-power states (possibly lower-power than available at run time), such that the processors can spend more time in their idle states. -This state can be used for platforms without Standby/Suspend-to-RAM + +This state can be used for platforms without Power-On Suspend/Suspend-to-RAM support, or it can be used in addition to Suspend-to-RAM (memory sleep) -to provide reduced resume latency. +to provide reduced resume latency. It is always supported. State: Standby / Power-On Suspend ACPI State: S1 -String: "standby" +Label: "standby" -This state offers minimal, though real, power savings, while providing -a very low-latency transition back to a working system. No operating -state is lost (the CPU retains power), so the system easily starts up +This state, if supported, offers moderate, though real, power savings, while +providing a relatively low-latency transition back to a working system. No +operating state is lost (the CPU retains power), so the system easily starts up again where it left off. -We try to put devices in a low-power state equivalent to D1, which -also offers low power savings, but low resume latency. Not all devices -support D1, and those that don't are left on. +In addition to freezing user space and putting all I/O devices into low-power +states, which is done for Suspend-To-Idle too, nonboot CPUs are taken offline +and all low-level system functions are suspended during transitions into this +state. For this reason, it should allow more energy to be saved relative to +Suspend-To-Idle, but the resume latency will generally be greater than for that +state. State: Suspend-to-RAM ACPI State: S3 -String: "mem" +Label: "mem" -This state offers significant power savings as everything in the -system is put into a low-power state, except for memory, which is -placed in self-refresh mode to retain its contents. +This state, if supported, offers significant power savings as everything in the +system is put into a low-power state, except for memory, which should be placed +into the self-refresh mode to retain its contents. All of the steps carried out +when entering Power-On Suspend are also carried out during transitions to STR. +Additional operations may take place depending on the platform capabilities. In +particular, on ACPI systems the kernel passes control to the BIOS (platform +firmware) as the last step during STR transitions and that usually results in +powering down some more low-level components that aren't directly controlled by +the kernel. -System and device state is saved and kept in memory. All devices are -suspended and put into D3. In many cases, all peripheral buses lose -power when entering STR, so devices must be able to handle the -transition back to the On state. +System and device state is saved and kept in memory. All devices are suspended +and put into low-power states. In many cases, all peripheral buses lose power +when entering STR, so devices must be able to handle the transition back to the +"on" state. -For at least ACPI, STR requires some minimal boot-strapping code to -resume the system from STR. This may be true on other platforms. +For at least ACPI, STR requires some minimal boot-strapping code to resume the +system from it. This may be the case on other platforms too. State: Suspend-to-disk ACPI State: S4 -String: "disk" +Label: "disk" This state offers the greatest power savings, and can be used even in the absence of low-level platform support for power management. This diff --git a/kernel/power/main.c b/kernel/power/main.c index 9f51f0ab3d86..573410d6647e 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -279,14 +279,14 @@ static inline void pm_print_times_init(void) {} struct kobject *power_kobj; /** - * state - control system power state. + * state - control system sleep states. * - * show() returns what states are supported, which is hard-coded to - * 'freeze' (Low-Power Idle), 'standby' (Power-On Suspend), - * 'mem' (Suspend-to-RAM), and 'disk' (Suspend-to-Disk). + * show() returns available sleep state labels, which may be "mem", "standby", + * "freeze" and "disk" (hibernation). See Documentation/power/states.txt for a + * description of what they mean. * - * store() accepts one of those strings, translates it into the - * proper enumerated value, and initiates a suspend transition. + * store() accepts one of those strings, translates it into the proper + * enumerated value, and initiates a suspend transition. */ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 00aca60904b0..338a6f147974 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -78,6 +78,26 @@ static bool valid_state(suspend_state_t state) return suspend_ops && suspend_ops->valid && suspend_ops->valid(state); } +/* + * If this is set, the "mem" label always corresponds to the deepest sleep state + * available, the "standby" label corresponds to the second deepest sleep state + * available (if any), and the "freeze" label corresponds to the remaining + * available sleep state (if there is one). + */ +static bool relative_states; + +static int __init sleep_states_setup(char *str) +{ + relative_states = !strncmp(str, "1", 1); + if (relative_states) { + pm_states[PM_SUSPEND_MEM].state = PM_SUSPEND_FREEZE; + pm_states[PM_SUSPEND_FREEZE].state = 0; + } + return 1; +} + +__setup("relative_sleep_states=", sleep_states_setup); + /** * suspend_set_ops - Set the global suspend method table. * @ops: Suspend operations to use. @@ -85,12 +105,20 @@ static bool valid_state(suspend_state_t state) void suspend_set_ops(const struct platform_suspend_ops *ops) { suspend_state_t i; + int j = PM_SUSPEND_MAX - 1; lock_system_sleep(); suspend_ops = ops; - for (i = PM_SUSPEND_STANDBY; i <= PM_SUSPEND_MEM; i++) - pm_states[i].state = valid_state(i) ? i : 0; + for (i = PM_SUSPEND_MEM; i >= PM_SUSPEND_STANDBY; i--) + if (valid_state(i)) + pm_states[j--].state = i; + else if (!relative_states) + pm_states[j--].state = 0; + + pm_states[j--].state = PM_SUSPEND_FREEZE; + while (j >= PM_SUSPEND_MIN) + pm_states[j--].state = 0; unlock_system_sleep(); } From 45fef5b88d1f2f47ecdefae6354372d440ca5c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 22 May 2014 12:47:47 +0200 Subject: [PATCH 093/134] ACPI: add dynamic_debug support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 1a699476e258 ("ACPI / hotplug / PCI: Hotplug notifications from acpi_bus_notify()") added debug messages for a few common events. These debug messages are unconditionally enabled if CONFIG_DYNAMIC_DEBUG is defined, contrary to the documented meaning, making the ACPI system spew lots of unwanted noise on any kernel with dynamic debugging. The bug was introduced by commit fbfddae69657 ("ACPI: Add acpi_handle_() interfaces"), which added the CONFIG_DYNAMIC_DEBUG dependency without respecting its meaning. Fix by adding real support for dynamic_debug. Fixes: fbfddae69657 ("ACPI: Add acpi_handle_() interfaces") Signed-off-by: Bjørn Mork Signed-off-by: Rafael J. Wysocki --- drivers/acpi/utils.c | 64 +++++++++++++++++++++++++++++++++++--------- include/linux/acpi.h | 22 +++++++++++++-- 2 files changed, 72 insertions(+), 14 deletions(-) diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index bba526148583..07c8c5a5ee95 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "internal.h" @@ -456,6 +457,24 @@ acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code, } EXPORT_SYMBOL(acpi_evaluate_ost); +/** + * acpi_handle_path: Return the object path of handle + * + * Caller must free the returned buffer + */ +static char *acpi_handle_path(acpi_handle handle) +{ + struct acpi_buffer buffer = { + .length = ACPI_ALLOCATE_BUFFER, + .pointer = NULL + }; + + if (in_interrupt() || + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer) != AE_OK) + return NULL; + return buffer.pointer; +} + /** * acpi_handle_printk: Print message with ACPI prefix and object path * @@ -469,29 +488,50 @@ acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...) { struct va_format vaf; va_list args; - struct acpi_buffer buffer = { - .length = ACPI_ALLOCATE_BUFFER, - .pointer = NULL - }; const char *path; va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; - if (in_interrupt() || - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer) != AE_OK) - path = ""; - else - path = buffer.pointer; - - printk("%sACPI: %s: %pV", level, path, &vaf); + path = acpi_handle_path(handle); + printk("%sACPI: %s: %pV", level, path ? path : "" , &vaf); va_end(args); - kfree(buffer.pointer); + kfree(path); } EXPORT_SYMBOL(acpi_handle_printk); +#if defined(CONFIG_DYNAMIC_DEBUG) +/** + * __acpi_handle_debug: pr_debug with ACPI prefix and object path + * + * This function is called through acpi_handle_debug macro and debug + * prints a message with ACPI prefix and object path. This function + * acquires the global namespace mutex to obtain an object path. In + * interrupt context, it shows the object path as . + */ +void +__acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle, + const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + const char *path; + + va_start(args, fmt); + vaf.fmt = fmt; + vaf.va = &args; + + path = acpi_handle_path(handle); + __dynamic_pr_debug(descriptor, "ACPI: %s: %pV", path ? path : "", &vaf); + + va_end(args); + kfree(path); +} +EXPORT_SYMBOL(__acpi_handle_debug); +#endif + /** * acpi_has_method: Check whether @handle has a method named @name * @handle: ACPI device handle diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 7a8f2cd66c8b..0e2569031a6f 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -589,6 +590,14 @@ static inline __printf(3, 4) void acpi_handle_printk(const char *level, void *handle, const char *fmt, ...) {} #endif /* !CONFIG_ACPI */ +#if defined(CONFIG_ACPI) && defined(CONFIG_DYNAMIC_DEBUG) +__printf(3, 4) +void __acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle, const char *fmt, ...); +#else +#define __acpi_handle_debug(descriptor, handle, fmt, ...) \ + acpi_handle_printk(KERN_DEBUG, handle, fmt, ##__VA_ARGS__); +#endif + /* * acpi_handle_: Print message with ACPI prefix and object path * @@ -610,11 +619,19 @@ acpi_handle_printk(const char *level, void *handle, const char *fmt, ...) {} #define acpi_handle_info(handle, fmt, ...) \ acpi_handle_printk(KERN_INFO, handle, fmt, ##__VA_ARGS__) -/* REVISIT: Support CONFIG_DYNAMIC_DEBUG when necessary */ -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#if defined(DEBUG) #define acpi_handle_debug(handle, fmt, ...) \ acpi_handle_printk(KERN_DEBUG, handle, fmt, ##__VA_ARGS__) #else +#if defined(CONFIG_DYNAMIC_DEBUG) +#define acpi_handle_debug(handle, fmt, ...) \ +do { \ + DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ + if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)) \ + __acpi_handle_debug(&descriptor, handle, pr_fmt(fmt), \ + ##__VA_ARGS__); \ +} while (0) +#else #define acpi_handle_debug(handle, fmt, ...) \ ({ \ if (0) \ @@ -622,5 +639,6 @@ acpi_handle_printk(const char *level, void *handle, const char *fmt, ...) {} 0; \ }) #endif +#endif #endif /*_LINUX_ACPI_H*/ From 72013795a73f8536d3346fa90379c987bcad0cc8 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Tue, 20 May 2014 20:59:21 +0800 Subject: [PATCH 094/134] ACPI: Add acpi_bus_attach_private_data() to attach data to ACPI handle There is already acpi_bus_get_private_data() to get ACPI handle data which is associated with acpi_bus_private_data_handler(). This patch is to add acpi_bus_attach_private_data() to make a pair and facilitate to attach and get data to/from ACPI handle. Reviewed-by: Mika Westerberg Signed-off-by: Lan Tianyu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 28 ++++++++++++++++++++++++---- include/acpi/acpi_bus.h | 2 ++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index cf925c4f36b7..8445d570f60a 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -132,6 +132,21 @@ void acpi_bus_private_data_handler(acpi_handle handle, } EXPORT_SYMBOL(acpi_bus_private_data_handler); +int acpi_bus_attach_private_data(acpi_handle handle, void *data) +{ + acpi_status status; + + status = acpi_attach_data(handle, + acpi_bus_private_data_handler, data); + if (ACPI_FAILURE(status)) { + acpi_handle_debug(handle, "Error attaching device data\n"); + return -ENODEV; + } + + return 0; +} +EXPORT_SYMBOL_GPL(acpi_bus_attach_private_data); + int acpi_bus_get_private_data(acpi_handle handle, void **data) { acpi_status status; @@ -140,15 +155,20 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data) return -EINVAL; status = acpi_get_data(handle, acpi_bus_private_data_handler, data); - if (ACPI_FAILURE(status) || !*data) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", - handle)); + if (ACPI_FAILURE(status)) { + acpi_handle_debug(handle, "No context for object\n"); return -ENODEV; } return 0; } -EXPORT_SYMBOL(acpi_bus_get_private_data); +EXPORT_SYMBOL_GPL(acpi_bus_get_private_data); + +void acpi_bus_detach_private_data(acpi_handle handle) +{ + acpi_detach_data(handle, acpi_bus_private_data_handler); +} +EXPORT_SYMBOL_GPL(acpi_bus_detach_private_data); void acpi_bus_no_hotplug(acpi_handle handle) { diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 84a2e29a2314..d2006ca31dba 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -406,6 +406,8 @@ extern struct kobject *acpi_kobj; extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); void acpi_bus_private_data_handler(acpi_handle, void *); int acpi_bus_get_private_data(acpi_handle, void **); +int acpi_bus_attach_private_data(acpi_handle, void *); +void acpi_bus_detach_private_data(acpi_handle); void acpi_bus_no_hotplug(acpi_handle handle); extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32); extern int register_acpi_notifier(struct notifier_block *); From e6f8a4d60b905eae1a20cbb0c72c67b26b2f02fd Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Tue, 20 May 2014 20:59:22 +0800 Subject: [PATCH 095/134] ACPI / thermal: Use acpi_bus_attach_private_data() to attach private data Use acpi_bus_attach_private_data() to attach private data instead of acpi_attach_data(). Reviewed-by: Mika Westerberg Signed-off-by: Lan Tianyu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/thermal.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index c1e31a41f949..ae195fde858d 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -925,13 +925,10 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) if (result) return result; - status = acpi_attach_data(tz->device->handle, - acpi_bus_private_data_handler, - tz->thermal_zone); - if (ACPI_FAILURE(status)) { - pr_err(PREFIX "Error attaching device data\n"); + status = acpi_bus_attach_private_data(tz->device->handle, + tz->thermal_zone); + if (ACPI_FAILURE(status)) return -ENODEV; - } tz->tz_enabled = 1; @@ -946,7 +943,7 @@ static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) sysfs_remove_link(&tz->thermal_zone->device.kobj, "device"); thermal_zone_device_unregister(tz->thermal_zone); tz->thermal_zone = NULL; - acpi_detach_data(tz->device->handle, acpi_bus_private_data_handler); + acpi_bus_detach_private_data(tz->device->handle); } From bee564430feec1175ee64bcfd4913cacc519f817 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 21 May 2014 15:39:53 +0200 Subject: [PATCH 096/134] nouveau: Don't check acpi_video_backlight_support() before registering backlight acpi_video_backlight_support() is supposed to be called by other (vendor specific) firmware backlight controls, not by native / raw backlight controls like nv_backlight. Userspace will normally prefer firmware interfaces over raw interfaces, so if acpi_video backlight support is present it will use that even if nv_backlight is registered as well. Except when video.use_native_backlight is present on the kernel cmdline (or enabled through a dmi based quirk). As the name indicates the goal here is to make only the raw interface available to userspace so that it will use that (it only does this when it sees a win8 compliant bios). This is done by: 1) Not registering any acpi_video# backlight devices; and 2) Making acpi_video_backlight_support() return true so that other firmware drivers, ie acer_wmi, thinkpad_acpi, dell_laptop, etc. Don't register their own vender specific interfaces. Currently nouveau breaks this setup, as when acpi_video_backlight_support() returns true, it does not register itself, resulting in no backlight control at all. This is esp. going to be a problem with 3.16 which will default to video.use_native_backlight=1, and thus nouveau based laptops with a win8 bios will get no backlight control at all. This also likely explains why the previous attempt to make video.use_native_backlight=1 the default was not a success, as without this patch having a default of video.use_native_backlight=1 will cause regressions. Note this effectively reverts commit 5bead799d3f8 (drm/nouveau: don't expose backlight control when available through ACPI). References: https://bugzilla.redhat.com/show_bug.cgi?id=1093171 Signed-off-by: Hans de Goede Acked-by: Ben Skeggs Signed-off-by: Rafael J. Wysocki --- drivers/gpu/drm/nouveau/nouveau_backlight.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 630f6e84fc01..2c1e4aad7da3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -31,7 +31,6 @@ */ #include -#include #include "nouveau_drm.h" #include "nouveau_reg.h" @@ -222,14 +221,6 @@ nouveau_backlight_init(struct drm_device *dev) struct nouveau_device *device = nv_device(drm->device); struct drm_connector *connector; -#ifdef CONFIG_ACPI - if (acpi_video_backlight_support()) { - NV_INFO(drm, "ACPI backlight interface available, " - "not registering our own\n"); - return 0; - } -#endif - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && connector->connector_type != DRM_MODE_CONNECTOR_eDP) From 3cc6919bd61315ea60baf95f3f9868aacfd1ace4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 21 May 2014 15:39:54 +0200 Subject: [PATCH 097/134] backlight: Add backlight device (un)registration notification Some firmware drivers, ie acpi-video want to get themselves out of the way (in some cases) when their also is a raw backlight device available. Due to module loading ordering being unknown, acpi-video cannot be certain that the backlight_device_registered(BACKLIGHT_RAW) it does for this is the final verdict wrt there being a BACKLIGHT_RAW device. By adding notification acpi-video can listen for backlight devices showing up after it has loaded, and unregister its backlight device if desired. Signed-off-by: Hans de Goede Acked-by: Jingoo Han Signed-off-by: Rafael J. Wysocki --- drivers/video/backlight/backlight.c | 40 +++++++++++++++++++++++++++++ include/linux/backlight.h | 7 +++++ 2 files changed, 47 insertions(+) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index bd2172c2d650..428089009cd5 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -23,6 +23,7 @@ static struct list_head backlight_dev_list; static struct mutex backlight_dev_list_mutex; +static struct blocking_notifier_head backlight_notifier; static const char *const backlight_types[] = { [BACKLIGHT_RAW] = "raw", @@ -370,6 +371,9 @@ struct backlight_device *backlight_device_register(const char *name, list_add(&new_bd->entry, &backlight_dev_list); mutex_unlock(&backlight_dev_list_mutex); + blocking_notifier_call_chain(&backlight_notifier, + BACKLIGHT_REGISTERED, new_bd); + return new_bd; } EXPORT_SYMBOL(backlight_device_register); @@ -413,6 +417,10 @@ void backlight_device_unregister(struct backlight_device *bd) pmac_backlight = NULL; mutex_unlock(&pmac_backlight_mutex); #endif + + blocking_notifier_call_chain(&backlight_notifier, + BACKLIGHT_UNREGISTERED, bd); + mutex_lock(&bd->ops_lock); bd->ops = NULL; mutex_unlock(&bd->ops_lock); @@ -437,6 +445,36 @@ static int devm_backlight_device_match(struct device *dev, void *res, return *r == data; } +/** + * backlight_register_notifier - get notified of backlight (un)registration + * @nb: notifier block with the notifier to call on backlight (un)registration + * + * @return 0 on success, otherwise a negative error code + * + * Register a notifier to get notified when backlight devices get registered + * or unregistered. + */ +int backlight_register_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&backlight_notifier, nb); +} +EXPORT_SYMBOL(backlight_register_notifier); + +/** + * backlight_unregister_notifier - unregister a backlight notifier + * @nb: notifier block to unregister + * + * @return 0 on success, otherwise a negative error code + * + * Register a notifier to get notified when backlight devices get registered + * or unregistered. + */ +int backlight_unregister_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&backlight_notifier, nb); +} +EXPORT_SYMBOL(backlight_unregister_notifier); + /** * devm_backlight_device_register - resource managed backlight_device_register() * @dev: the device to register @@ -544,6 +582,8 @@ static int __init backlight_class_init(void) backlight_class->pm = &backlight_class_dev_pm_ops; INIT_LIST_HEAD(&backlight_dev_list); mutex_init(&backlight_dev_list_mutex); + BLOCKING_INIT_NOTIFIER_HEAD(&backlight_notifier); + return 0; } diff --git a/include/linux/backlight.h b/include/linux/backlight.h index 72647429adf6..adb14a8616df 100644 --- a/include/linux/backlight.h +++ b/include/linux/backlight.h @@ -40,6 +40,11 @@ enum backlight_type { BACKLIGHT_TYPE_MAX, }; +enum backlight_notification { + BACKLIGHT_REGISTERED, + BACKLIGHT_UNREGISTERED, +}; + struct backlight_device; struct fb_info; @@ -133,6 +138,8 @@ extern void devm_backlight_device_unregister(struct device *dev, extern void backlight_force_update(struct backlight_device *bd, enum backlight_update_reason reason); extern bool backlight_device_registered(enum backlight_type type); +extern int backlight_register_notifier(struct notifier_block *nb); +extern int backlight_unregister_notifier(struct notifier_block *nb); #define to_backlight_device(obj) container_of(obj, struct backlight_device, dev) From 53a92ba7e3762154df01c4f4f5d871df0587c96b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 21 May 2014 15:39:55 +0200 Subject: [PATCH 098/134] ACPI / video: Unregister the backlight device if a raw one shows up later When video.use_native_backlight=1 and non intel gfx are in use, the raw backlight device of the gfx driver will show up after acpi-video has done its acpi_video_verify_backlight_support() check. This causes video.use_native_backlight=1 to not have the desired result. This patch fixes this by adding a backlight notifier and when a raw backlight is registered or unregistered re-doing the acpi_video_verify_backlight_support() check. Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/video.c | 57 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index cd4389262d4f..d40c04cbb422 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -151,6 +151,7 @@ struct acpi_video_enumerated_device { struct acpi_video_bus { struct acpi_device *device; bool backlight_registered; + bool backlight_notifier_registered; u8 dos_setting; struct acpi_video_enumerated_device *attached_array; u8 attached_count; @@ -162,6 +163,7 @@ struct acpi_video_bus { struct input_dev *input; char phys[32]; /* for input device */ struct notifier_block pm_nb; + struct notifier_block backlight_nb; }; struct acpi_video_device_flags { @@ -1732,6 +1734,9 @@ static int acpi_video_bus_register_backlight(struct acpi_video_bus *video) { struct acpi_video_device *dev; + if (video->backlight_registered) + return 0; + if (!acpi_video_verify_backlight_support()) return 0; @@ -1876,6 +1881,56 @@ static void acpi_video_bus_remove_notify_handler(struct acpi_video_bus *video) video->input = NULL; } +static int acpi_video_backlight_notify(struct notifier_block *nb, + unsigned long val, void *bd) +{ + struct backlight_device *backlight = bd; + struct acpi_video_bus *video; + + /* acpi_video_verify_backlight_support only cares about raw devices */ + if (backlight->props.type != BACKLIGHT_RAW) + return NOTIFY_DONE; + + video = container_of(nb, struct acpi_video_bus, backlight_nb); + + switch (val) { + case BACKLIGHT_REGISTERED: + if (!acpi_video_verify_backlight_support()) + acpi_video_bus_unregister_backlight(video); + break; + case BACKLIGHT_UNREGISTERED: + acpi_video_bus_register_backlight(video); + break; + } + + return NOTIFY_OK; +} + +static int acpi_video_bus_add_backlight_notify_handler( + struct acpi_video_bus *video) +{ + int error; + + video->backlight_nb.notifier_call = acpi_video_backlight_notify; + video->backlight_nb.priority = 0; + error = backlight_register_notifier(&video->backlight_nb); + if (error == 0) + video->backlight_notifier_registered = true; + + return error; +} + +static int acpi_video_bus_remove_backlight_notify_handler( + struct acpi_video_bus *video) +{ + if (!video->backlight_notifier_registered) + return 0; + + video->backlight_notifier_registered = false; + + return backlight_unregister_notifier(&video->backlight_nb); +} + static int acpi_video_bus_put_devices(struct acpi_video_bus *video) { struct acpi_video_device *dev, *next; @@ -1957,6 +2012,7 @@ static int acpi_video_bus_add(struct acpi_device *device) acpi_video_bus_register_backlight(video); acpi_video_bus_add_notify_handler(video); + acpi_video_bus_add_backlight_notify_handler(video); return 0; @@ -1980,6 +2036,7 @@ static int acpi_video_bus_remove(struct acpi_device *device) video = acpi_driver_data(device); + acpi_video_bus_remove_backlight_notify_handler(video); acpi_video_bus_remove_notify_handler(video); acpi_video_bus_unregister_backlight(video); acpi_video_bus_put_devices(video); From 1e815db647ada5f169dc0201b96530e30640d6df Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 21 May 2014 15:39:56 +0200 Subject: [PATCH 099/134] ACPI / video: Add use native backlight quirk for the ThinkPad W530 Like all of the other *30 ThinkPad models, the W530 has a broken acpi-video backlight control. Note in order for this to actually fix things on the ThinkPad W530 the commit titled: "nouveau: Don't check acpi_video_backlight_support() before registering backlight" is also needed. References: https://bugzilla.redhat.com/show_bug.cgi?id=1093171 Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/video.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index d40c04cbb422..ce7a006606de 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -474,6 +474,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"), }, }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad W530", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W530"), + }, + }, { .callback = video_set_use_native_backlight, .ident = "ThinkPad X1 Carbon", From 0dc6b96ac20c538a28bd8442ae74b87fc6b6f6e0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 26 May 2014 13:44:29 +0200 Subject: [PATCH 100/134] ACPI / video: Add 4 new models to the use_native_backlight DMI list Acer Aspire V5-171 References: https://bugzilla.redhat.com/show_bug.cgi?id=983342 Acer Aspire V5-471G Lenovo Yoga 2 11 Reported-and-tested-by: Vincent Gerris HP EliteBook 8470p References: https://bugzilla.redhat.com/show_bug.cgi?id=1093120 Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/video.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index ce7a006606de..101fb090dcb9 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -498,6 +498,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"), }, }, + { + .callback = video_set_use_native_backlight, + .ident = "Lenovo Yoga 2 11", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2 11"), + }, + }, { .callback = video_set_use_native_backlight, .ident = "Thinkpad Helix", @@ -530,6 +538,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5742G"), }, }, + { + .callback = video_set_use_native_backlight, + .ident = "Acer Aspire V5-171", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "V5-171"), + }, + }, { .callback = video_set_use_native_backlight, .ident = "Acer Aspire V5-431", @@ -538,6 +554,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-431"), }, }, + { + .callback = video_set_use_native_backlight, + .ident = "Acer Aspire V5-471G", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-471G"), + }, + }, { .callback = video_set_use_native_backlight, .ident = "HP ProBook 4340s", @@ -590,6 +614,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { }, { .callback = video_set_use_native_backlight, + .ident = "HP EliteBook 8470p", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8470p"), + }, + }, + { + .callback = video_set_use_native_backlight, .ident = "HP EliteBook 8780w", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), From 4ff248f3bf830ba22c988abb099e1836fbd3b1d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Sch=C3=B6lling?= Date: Thu, 22 May 2014 22:56:36 +0200 Subject: [PATCH 101/134] ACPI / PAD: Use time_before() for time comparison MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To be future-proof and for better readability the time comparisons are modified to use time_before() instead of plain, error-prone math. Signed-off-by: Manuel Schölling Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_pad.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index e20708f2b8e5..f148a0580e04 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -156,12 +156,13 @@ static int power_saving_thread(void *data) while (!kthread_should_stop()) { int cpu; - u64 expire_time; + unsigned long expire_time; try_to_freeze(); /* round robin to cpus */ - if (last_jiffies + round_robin_time * HZ < jiffies) { + expire_time = last_jiffies + round_robin_time * HZ; + if (time_before(expire_time, jiffies)) { last_jiffies = jiffies; round_robin_cpu(tsk_index); } @@ -200,7 +201,7 @@ static int power_saving_thread(void *data) CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); local_irq_enable(); - if (jiffies > expire_time) { + if (time_before(expire_time, jiffies)) { do_sleep = 1; break; } From 636fcfefa2a45f5b54f475309928ef191b27dd19 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 12 May 2014 15:45:54 +0800 Subject: [PATCH 102/134] ACPICA: Linux headers: Remove ACPI_PREEMPTION_POINT() due to no usages. This patch deletes deprecated ACPI_PREEMPTION_POINT(), there is no user for it in Linux kernel now. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/platform/aclinux.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 4c2f9e78001c..3b8b52f8a4e9 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -228,20 +228,6 @@ static inline acpi_thread_id acpi_os_get_thread_id(void) #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_thread_id -#ifndef CONFIG_PREEMPT - -/* - * Used within ACPICA to show where it is safe to preempt execution - * when CONFIG_PREEMPT=n - */ -#define ACPI_PREEMPTION_POINT() \ - do { \ - if (!irqs_disabled()) \ - cond_resched(); \ - } while (0) - -#endif - /* * When lockdep is enabled, the spin_lock_init() macro stringifies it's * argument and uses that as a name for the lock in debugging. From d13bd5a602982cd7f697e39b13ac736c2c553af1 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 12 May 2014 15:46:32 +0800 Subject: [PATCH 103/134] ACPICA: Linux headers: Add From ACPICA's perspective, should be included after inclusion of . But currently in Linux, included by has included to find ACPICA types for inline functions. This causes the following problem: 1. Redundant code in and : Linux must be careful to keep conditions for inclusion consistent with the conditions for inclusion. Which finally leads to the issue that we have to keep many useless macro definitions in or . Such conditions include: COMPILER_DEPENDENT_UINT64 COMPILER_DEPENDENT_INT64 ACPI_INLINE ACPI_SYSTEM_XFACE ACPI_EXTERNAL_XFACE ACPI_INTERNAL_XFACE ACPI_INTERNAL_VAR_XFACE ACPI_MUTEX_TYPE DEBUGGER_THREADING ACPI_ACQUIRE_GLOBAL_LOCK ACPI_RELEASE_GLOBAL_LOCK ACPI_FLUSH_CPU_CACHE They have default implementations in while Linux need to keep a copy in to avoid build errors. This patch introduces to fix this issue by splitting conditions and declarations (most of them are inline functions) into 2 header files so that the wrong inclusion of can be removed from . This patch also removes old ACPI_NATIVE_INTERFACE_HEADER mechanism which is not preferred by Linux and adds the platform/acenvex.h to be the solution to solve this issue. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acpi.h | 4 +- include/acpi/platform/acenvex.h | 63 ++++++++++++ include/acpi/platform/aclinux.h | 154 +++++++----------------------- include/acpi/platform/aclinuxex.h | 116 ++++++++++++++++++++++ 4 files changed, 216 insertions(+), 121 deletions(-) create mode 100644 include/acpi/platform/acenvex.h create mode 100644 include/acpi/platform/aclinuxex.h diff --git a/include/acpi/acpi.h b/include/acpi/acpi.h index ca0cb603b171..a08e55a263c9 100644 --- a/include/acpi/acpi.h +++ b/include/acpi/acpi.h @@ -62,8 +62,6 @@ #include /* Resource Descriptor structs */ #include /* OSL interfaces (ACPICA-to-OS) */ #include /* ACPI core subsystem external interfaces */ -#ifdef ACPI_NATIVE_INTERFACE_HEADER -#include ACPI_NATIVE_INTERFACE_HEADER -#endif +#include /* Extra environment-specific items */ #endif /* __ACPI_H__ */ diff --git a/include/acpi/platform/acenvex.h b/include/acpi/platform/acenvex.h new file mode 100644 index 000000000000..2b612384c994 --- /dev/null +++ b/include/acpi/platform/acenvex.h @@ -0,0 +1,63 @@ +/****************************************************************************** + * + * Name: acenvex.h - Extra host and compiler configuration + * + *****************************************************************************/ + +/* + * 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. + */ + +#ifndef __ACENVEX_H__ +#define __ACENVEX_H__ + +/*! [Begin] no source code translation */ + +/****************************************************************************** + * + * Extra host configuration files. All ACPICA headers are included before + * including these files. + * + *****************************************************************************/ + +#if defined(_LINUX) || defined(__linux__) +#include + +#endif + +/*! [End] no source code translation !*/ + +#endif /* __ACENVEX_H__ */ diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 3b8b52f8a4e9..0ab05d95e3a3 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -114,6 +114,42 @@ #define acpi_spinlock spinlock_t * #define acpi_cpu_flags unsigned long +/* Use native linux version of acpi_os_allocate_zeroed */ + +#define USE_NATIVE_ALLOCATE_ZEROED + +/* + * Overrides for in-kernel ACPICA + */ +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_allocate +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_allocate_zeroed +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_free +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_acquire_object +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_thread_id +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_create_lock +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_map_memory +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_unmap_memory + +/* + * OSL interfaces used by debugger/disassembler + */ +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_readable +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_writable + +/* + * OSL interfaces used by utilities + */ +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_redirect_output +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_line +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_name +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_index +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_address +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_open_directory +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_next_filename +#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_close_directory + #else /* !__KERNEL__ */ #include @@ -159,122 +195,4 @@ #include -#ifdef __KERNEL__ - -/* - * FIXME: Inclusion of actypes.h - * Linux kernel need this before defining inline OSL interfaces as - * actypes.h need to be included to find ACPICA type definitions. - * Since from ACPICA's perspective, the actypes.h should be included after - * acenv.h (aclinux.h), this leads to a inclusion mis-ordering issue. - */ -#include - -/* - * Overrides for in-kernel ACPICA - */ -acpi_status __init acpi_os_initialize(void); -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize - -acpi_status acpi_os_terminate(void); -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate - -/* - * Memory allocation/deallocation - */ - -/* - * The irqs_disabled() check is for resume from RAM. - * Interrupts are off during resume, just like they are for boot. - * However, boot has (system_state != SYSTEM_RUNNING) - * to quiet __might_sleep() in kmalloc() and resume does not. - */ -static inline void *acpi_os_allocate(acpi_size size) -{ - return kmalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); -} - -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_allocate - -/* Use native linux version of acpi_os_allocate_zeroed */ - -static inline void *acpi_os_allocate_zeroed(acpi_size size) -{ - return kzalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); -} - -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_allocate_zeroed -#define USE_NATIVE_ALLOCATE_ZEROED - -static inline void acpi_os_free(void *memory) -{ - kfree(memory); -} - -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_free - -static inline void *acpi_os_acquire_object(acpi_cache_t * cache) -{ - return kmem_cache_zalloc(cache, - irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); -} - -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_acquire_object - -static inline acpi_thread_id acpi_os_get_thread_id(void) -{ - return (acpi_thread_id) (unsigned long)current; -} - -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_thread_id - -/* - * When lockdep is enabled, the spin_lock_init() macro stringifies it's - * argument and uses that as a name for the lock in debugging. - * By executing spin_lock_init() in a macro the key changes from "lock" for - * all locks to the name of the argument of acpi_os_create_lock(), which - * prevents lockdep from reporting false positives for ACPICA locks. - */ -#define acpi_os_create_lock(__handle) \ - ({ \ - spinlock_t *lock = ACPI_ALLOCATE(sizeof(*lock)); \ - if (lock) { \ - *(__handle) = lock; \ - spin_lock_init(*(__handle)); \ - } \ - lock ? AE_OK : AE_NO_MEMORY; \ - }) -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_create_lock - -void __iomem *acpi_os_map_memory(acpi_physical_address where, acpi_size length); -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_map_memory - -void acpi_os_unmap_memory(void __iomem * logical_address, acpi_size size); -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_unmap_memory - -/* - * OSL interfaces used by debugger/disassembler - */ -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_readable -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_writable - -/* - * OSL interfaces used by utilities - */ -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_redirect_output -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_line -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_name -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_index -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_address -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_open_directory -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_next_filename -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_close_directory - -/* - * OSL interfaces added by Linux - */ -void early_acpi_os_unmap_memory(void __iomem * virt, acpi_size size); - -#endif /* __KERNEL__ */ - #endif /* __ACLINUX_H__ */ diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h new file mode 100644 index 000000000000..cce0723d05a9 --- /dev/null +++ b/include/acpi/platform/aclinuxex.h @@ -0,0 +1,116 @@ +/****************************************************************************** + * + * Name: aclinuxex.h - Extra OS specific defines, etc. for Linux + * + *****************************************************************************/ + +/* + * 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. + */ + +#ifndef __ACLINUXEX_H__ +#define __ACLINUXEX_H__ + +#ifdef __KERNEL__ + +/* + * Overrides for in-kernel ACPICA + */ +acpi_status __init acpi_os_initialize(void); + +acpi_status acpi_os_terminate(void); + +/* + * The irqs_disabled() check is for resume from RAM. + * Interrupts are off during resume, just like they are for boot. + * However, boot has (system_state != SYSTEM_RUNNING) + * to quiet __might_sleep() in kmalloc() and resume does not. + */ +static inline void *acpi_os_allocate(acpi_size size) +{ + return kmalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); +} + +static inline void *acpi_os_allocate_zeroed(acpi_size size) +{ + return kzalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); +} + +static inline void acpi_os_free(void *memory) +{ + kfree(memory); +} + +static inline void *acpi_os_acquire_object(acpi_cache_t * cache) +{ + return kmem_cache_zalloc(cache, + irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); +} + +static inline acpi_thread_id acpi_os_get_thread_id(void) +{ + return (acpi_thread_id) (unsigned long)current; +} + +/* + * When lockdep is enabled, the spin_lock_init() macro stringifies it's + * argument and uses that as a name for the lock in debugging. + * By executing spin_lock_init() in a macro the key changes from "lock" for + * all locks to the name of the argument of acpi_os_create_lock(), which + * prevents lockdep from reporting false positives for ACPICA locks. + */ +#define acpi_os_create_lock(__handle) \ + ({ \ + spinlock_t *lock = ACPI_ALLOCATE(sizeof(*lock)); \ + if (lock) { \ + *(__handle) = lock; \ + spin_lock_init(*(__handle)); \ + } \ + lock ? AE_OK : AE_NO_MEMORY; \ + }) + +void __iomem *acpi_os_map_memory(acpi_physical_address where, acpi_size length); + +void acpi_os_unmap_memory(void __iomem * logical_address, acpi_size size); + +/* + * OSL interfaces added by Linux + */ +void early_acpi_os_unmap_memory(void __iomem * virt, acpi_size size); + +#endif /* __KERNEL__ */ + +#endif /* __ACLINUXEX_H__ */ From 07d8391433380fc72f999d99c554b1cfedea9778 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 12 May 2014 15:46:38 +0800 Subject: [PATCH 104/134] ACPICA: Linux headers: Add to remove mis-ordered inclusion of There is a mis-order inclusion for . As we will enforce including for all Linux ACPI users, we can find the inclusion order is as follows: (acenv.h before including aclinux.h) ........................................................................... (aclinux.h before including asm/acpi.h) @Redundant@ (ACPICA specific stuff) ........................................................................... ........................................................................... (Linux ACPI specific stuff) ? - - - - - - - - - - - - + (aclinux.h after including asm/acpi.h) @Invisible@ | (acenv.h after including aclinux.h) @Invisible@ | other ACPICA headers @Invisible@ | ............................................................|.............. | | (Excluded) | (Linux ACPI specific stuff) ! <- - - - - - - - - - - - - + NOTE that, in ACPICA, is more like Kconfig generated for Linux, it is meant to be included before including any ACPICA code. In the above figure, there is a question mark for "Linux ACPI specific stuff" in which should be included after including all other ACPICA header files. Thus they really need to be moved to the position marked with exclaimation mark or the definitions in the blocks marked with "@Invisible@" will be invisible to such architecture specific "Linux ACPI specific stuff" header blocks. This leaves 2 issues: 1. All environmental definitions in these blocks should have a copy in the area marked with "@Redundant@" if they are required by the "Linux ACPI specific stuff". 2. We cannot use any ACPICA defined types in . This patch splits architecture specific ACPICA stuff from to fix this issue. Signed-off-by: Lv Zheng Cc: Tony Luck Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Signed-off-by: Rafael J. Wysocki --- arch/ia64/include/asm/acenv.h | 71 +++++++++++++++++++++++++++++++++ arch/ia64/include/asm/acpi.h | 50 ----------------------- arch/x86/include/asm/acenv.h | 65 ++++++++++++++++++++++++++++++ arch/x86/include/asm/acpi.h | 45 --------------------- include/acpi/platform/aclinux.h | 2 +- 5 files changed, 137 insertions(+), 96 deletions(-) create mode 100644 arch/ia64/include/asm/acenv.h create mode 100644 arch/x86/include/asm/acenv.h diff --git a/arch/ia64/include/asm/acenv.h b/arch/ia64/include/asm/acenv.h new file mode 100644 index 000000000000..e0896eb26bf1 --- /dev/null +++ b/arch/ia64/include/asm/acenv.h @@ -0,0 +1,71 @@ +/* + * IA64 specific ACPICA environments and implementation + * + * Copyright (C) 2014, Intel Corporation + * Author: Lv Zheng + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _ASM_IA64_ACENV_H +#define _ASM_IA64_ACENV_H + +#include + +#define COMPILER_DEPENDENT_INT64 long +#define COMPILER_DEPENDENT_UINT64 unsigned long + +/* + * Calling conventions: + * + * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) + * ACPI_EXTERNAL_XFACE - External ACPI interfaces + * ACPI_INTERNAL_XFACE - Internal ACPI interfaces + * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces + */ +#define ACPI_SYSTEM_XFACE +#define ACPI_EXTERNAL_XFACE +#define ACPI_INTERNAL_XFACE +#define ACPI_INTERNAL_VAR_XFACE + +/* Asm macros */ + +#define ACPI_FLUSH_CPU_CACHE() + +#ifdef CONFIG_ACPI + +static inline int +ia64_acpi_acquire_global_lock(unsigned int *lock) +{ + unsigned int old, new, val; + do { + old = *lock; + new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1)); + val = ia64_cmpxchg4_acq(lock, new, old); + } while (unlikely (val != old)); + return (new < 3) ? -1 : 0; +} + +static inline int +ia64_acpi_release_global_lock(unsigned int *lock) +{ + unsigned int old, new, val; + do { + old = *lock; + new = old & ~0x3; + val = ia64_cmpxchg4_acq(lock, new, old); + } while (unlikely (val != old)); + return old & 0x1; +} + +#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \ + ((Acq) = ia64_acpi_acquire_global_lock(&facs->global_lock)) + +#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \ + ((Acq) = ia64_acpi_release_global_lock(&facs->global_lock)) + +#endif + +#endif /* _ASM_IA64_ACENV_H */ diff --git a/arch/ia64/include/asm/acpi.h b/arch/ia64/include/asm/acpi.h index d651102a4d45..b0ddcfd384a4 100644 --- a/arch/ia64/include/asm/acpi.h +++ b/arch/ia64/include/asm/acpi.h @@ -34,56 +34,6 @@ #include #include -#define COMPILER_DEPENDENT_INT64 long -#define COMPILER_DEPENDENT_UINT64 unsigned long - -/* - * Calling conventions: - * - * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) - * ACPI_EXTERNAL_XFACE - External ACPI interfaces - * ACPI_INTERNAL_XFACE - Internal ACPI interfaces - * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces - */ -#define ACPI_SYSTEM_XFACE -#define ACPI_EXTERNAL_XFACE -#define ACPI_INTERNAL_XFACE -#define ACPI_INTERNAL_VAR_XFACE - -/* Asm macros */ - -#define ACPI_FLUSH_CPU_CACHE() - -static inline int -ia64_acpi_acquire_global_lock (unsigned int *lock) -{ - unsigned int old, new, val; - do { - old = *lock; - new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1)); - val = ia64_cmpxchg4_acq(lock, new, old); - } while (unlikely (val != old)); - return (new < 3) ? -1 : 0; -} - -static inline int -ia64_acpi_release_global_lock (unsigned int *lock) -{ - unsigned int old, new, val; - do { - old = *lock; - new = old & ~0x3; - val = ia64_cmpxchg4_acq(lock, new, old); - } while (unlikely (val != old)); - return old & 0x1; -} - -#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \ - ((Acq) = ia64_acpi_acquire_global_lock(&facs->global_lock)) - -#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \ - ((Acq) = ia64_acpi_release_global_lock(&facs->global_lock)) - #ifdef CONFIG_ACPI #define acpi_disabled 0 /* ACPI always enabled on IA64 */ #define acpi_noirq 0 /* ACPI always enabled on IA64 */ diff --git a/arch/x86/include/asm/acenv.h b/arch/x86/include/asm/acenv.h new file mode 100644 index 000000000000..6978584934f7 --- /dev/null +++ b/arch/x86/include/asm/acenv.h @@ -0,0 +1,65 @@ +/* + * X86 specific ACPICA environments and implementation + * + * Copyright (C) 2014, Intel Corporation + * Author: Lv Zheng + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _ASM_X86_ACENV_H +#define _ASM_X86_ACENV_H + +#include + +#define COMPILER_DEPENDENT_INT64 long long +#define COMPILER_DEPENDENT_UINT64 unsigned long long + +/* + * Calling conventions: + * + * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) + * ACPI_EXTERNAL_XFACE - External ACPI interfaces + * ACPI_INTERNAL_XFACE - Internal ACPI interfaces + * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces + */ +#define ACPI_SYSTEM_XFACE +#define ACPI_EXTERNAL_XFACE +#define ACPI_INTERNAL_XFACE +#define ACPI_INTERNAL_VAR_XFACE + +/* Asm macros */ + +#define ACPI_FLUSH_CPU_CACHE() wbinvd() + +#ifdef CONFIG_ACPI + +int __acpi_acquire_global_lock(unsigned int *lock); +int __acpi_release_global_lock(unsigned int *lock); + +#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \ + ((Acq) = __acpi_acquire_global_lock(&facs->global_lock)) + +#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \ + ((Acq) = __acpi_release_global_lock(&facs->global_lock)) + +/* + * Math helper asm macros + */ +#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \ + asm("divl %2;" \ + : "=a"(q32), "=d"(r32) \ + : "r"(d32), \ + "0"(n_lo), "1"(n_hi)) + +#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \ + asm("shrl $1,%2 ;" \ + "rcrl $1,%3;" \ + : "=r"(n_hi), "=r"(n_lo) \ + : "0"(n_hi), "1"(n_lo)) + +#endif + +#endif /* _ASM_X86_ACENV_H */ diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index c8c1e700c26e..e06225eda635 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h @@ -32,51 +32,6 @@ #include #include -#define COMPILER_DEPENDENT_INT64 long long -#define COMPILER_DEPENDENT_UINT64 unsigned long long - -/* - * Calling conventions: - * - * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) - * ACPI_EXTERNAL_XFACE - External ACPI interfaces - * ACPI_INTERNAL_XFACE - Internal ACPI interfaces - * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces - */ -#define ACPI_SYSTEM_XFACE -#define ACPI_EXTERNAL_XFACE -#define ACPI_INTERNAL_XFACE -#define ACPI_INTERNAL_VAR_XFACE - -/* Asm macros */ - -#define ACPI_FLUSH_CPU_CACHE() wbinvd() - -int __acpi_acquire_global_lock(unsigned int *lock); -int __acpi_release_global_lock(unsigned int *lock); - -#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \ - ((Acq) = __acpi_acquire_global_lock(&facs->global_lock)) - -#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \ - ((Acq) = __acpi_release_global_lock(&facs->global_lock)) - -/* - * Math helper asm macros - */ -#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \ - asm("divl %2;" \ - : "=a"(q32), "=d"(r32) \ - : "r"(d32), \ - "0"(n_lo), "1"(n_hi)) - - -#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \ - asm("shrl $1,%2 ;" \ - "rcrl $1,%3;" \ - : "=r"(n_hi), "=r"(n_lo) \ - : "0"(n_hi), "1"(n_lo)) - #ifdef CONFIG_ACPI extern int acpi_lapic; extern int acpi_ioapic; diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 0ab05d95e3a3..5d27e560a48e 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -71,7 +71,7 @@ #ifdef EXPORT_ACPI_INTERFACES #include #endif -#include +#include #ifndef CONFIG_ACPI From 92985ef1db428cc6129a1d375a68c277aa05820b Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 12 May 2014 15:46:49 +0800 Subject: [PATCH 105/134] ACPICA: Clean up redudant definitions already defined elsewhere Since mis-order issues have been solved, we can cleanup redundant definitions that already have defaults in . This patch removes redudant environments for __KERNEL__ surrounded code. Signed-off-by: Lv Zheng Cc: Tony Luck Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Signed-off-by: Rafael J. Wysocki --- arch/ia64/include/asm/acenv.h | 15 --------------- arch/x86/include/asm/acenv.h | 16 ---------------- include/acpi/platform/aclinux.h | 1 - 3 files changed, 32 deletions(-) diff --git a/arch/ia64/include/asm/acenv.h b/arch/ia64/include/asm/acenv.h index e0896eb26bf1..3f9eaeec9873 100644 --- a/arch/ia64/include/asm/acenv.h +++ b/arch/ia64/include/asm/acenv.h @@ -17,23 +17,8 @@ #define COMPILER_DEPENDENT_INT64 long #define COMPILER_DEPENDENT_UINT64 unsigned long -/* - * Calling conventions: - * - * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) - * ACPI_EXTERNAL_XFACE - External ACPI interfaces - * ACPI_INTERNAL_XFACE - Internal ACPI interfaces - * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces - */ -#define ACPI_SYSTEM_XFACE -#define ACPI_EXTERNAL_XFACE -#define ACPI_INTERNAL_XFACE -#define ACPI_INTERNAL_VAR_XFACE - /* Asm macros */ -#define ACPI_FLUSH_CPU_CACHE() - #ifdef CONFIG_ACPI static inline int diff --git a/arch/x86/include/asm/acenv.h b/arch/x86/include/asm/acenv.h index 6978584934f7..66873297e9f5 100644 --- a/arch/x86/include/asm/acenv.h +++ b/arch/x86/include/asm/acenv.h @@ -14,22 +14,6 @@ #include -#define COMPILER_DEPENDENT_INT64 long long -#define COMPILER_DEPENDENT_UINT64 unsigned long long - -/* - * Calling conventions: - * - * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) - * ACPI_EXTERNAL_XFACE - External ACPI interfaces - * ACPI_INTERNAL_XFACE - Internal ACPI interfaces - * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces - */ -#define ACPI_SYSTEM_XFACE -#define ACPI_EXTERNAL_XFACE -#define ACPI_INTERNAL_XFACE -#define ACPI_INTERNAL_VAR_XFACE - /* Asm macros */ #define ACPI_FLUSH_CPU_CACHE() wbinvd() diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 5d27e560a48e..e70012956db3 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -48,7 +48,6 @@ #define ACPI_USE_SYSTEM_CLIBRARY #define ACPI_USE_DO_WHILE_0 -#define ACPI_MUTEX_TYPE ACPI_BINARY_SEMAPHORE #ifdef __KERNEL__ From a238317ce8185519ed083e81e84260907fbbcf7f Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 20 May 2014 15:39:41 +0800 Subject: [PATCH 106/134] ACPI: Clean up acpi_os_map/unmap_memory() to eliminate __iomem. ACPICA doesn't include protections around address space checking, Linux build tests always complain increased sparse warnings around ACPICA internal acpi_os_map/unmap_memory() invocations. This patch tries to fix this issue permanently. There are 2 choices left for us to solve this issue: 1. Add __iomem address space awareness into ACPICA. 2. Remove sparse checker of __iomem from ACPICA source code. This patch chooses solution 2, because: 1. Most of the acpi_os_map/unmap_memory() invocations are used for ACPICA. table mappings, which in fact are not IO addresses. 2. The only IO addresses usage is for "system memory space" mapping code in: drivers/acpi/acpica/exregion.c drivers/acpi/acpica/evrgnini.c drivers/acpi/acpica/exregion.c The mapped address is accessed in the handler of "system memory space" - acpi_ex_system_memory_space_handler(). This function in fact can be changed to invoke acpi_os_read/write_memory() so that __iomem can always be type-casted in the OSL layer. According to the above investigation, we drew the following conclusion: It is not a good idea to introduce __iomem address space awareness into ACPICA mostly in order to protect non-IO addresses. We can simply remove __iomem for acpi_os_map/unmap_memory() to remove __iomem checker for ACPICA code. Then we need to enforce external usages to invoke other APIs that are aware of __iomem address space. The external usages are: drivers/acpi/apei/einj.c drivers/acpi/acpi_extlog.c drivers/char/tpm/tpm_acpi.c drivers/acpi/nvs.c This patch thus performs cleanups in this way: 1. Add acpi_os_map/unmap_iomem() to be invoked by non-ACPICA code. 2. Remove __iomem from acpi_os_map/unmap_memory(). Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_extlog.c | 16 ++++++++-------- drivers/acpi/apei/einj.c | 14 +++++++------- drivers/acpi/nvs.c | 4 ++-- drivers/acpi/osl.c | 21 +++++++++++++++++---- drivers/char/tpm/tpm_acpi.c | 4 ++-- include/acpi/acpi_io.h | 3 +++ include/acpi/platform/aclinux.h | 6 ------ include/acpi/platform/aclinuxex.h | 4 ---- 8 files changed, 39 insertions(+), 33 deletions(-) diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index c4a5d87ede7e..185334114d71 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -220,13 +220,13 @@ static int __init extlog_init(void) goto err; } - extlog_l1_hdr = acpi_os_map_memory(l1_dirbase, l1_hdr_size); + extlog_l1_hdr = acpi_os_map_iomem(l1_dirbase, l1_hdr_size); l1_head = (struct extlog_l1_head *)extlog_l1_hdr; l1_size = l1_head->total_len; l1_percpu_entry = l1_head->entries; elog_base = l1_head->elog_base; elog_size = l1_head->elog_len; - acpi_os_unmap_memory(extlog_l1_hdr, l1_hdr_size); + acpi_os_unmap_iomem(extlog_l1_hdr, l1_hdr_size); release_mem_region(l1_dirbase, l1_hdr_size); /* remap L1 header again based on completed information */ @@ -237,7 +237,7 @@ static int __init extlog_init(void) (unsigned long long)l1_dirbase + l1_size); goto err; } - extlog_l1_addr = acpi_os_map_memory(l1_dirbase, l1_size); + extlog_l1_addr = acpi_os_map_iomem(l1_dirbase, l1_size); l1_entry_base = (u64 *)((u8 *)extlog_l1_addr + l1_hdr_size); /* remap elog table */ @@ -248,7 +248,7 @@ static int __init extlog_init(void) (unsigned long long)elog_base + elog_size); goto err_release_l1_dir; } - elog_addr = acpi_os_map_memory(elog_base, elog_size); + elog_addr = acpi_os_map_iomem(elog_base, elog_size); rc = -ENOMEM; /* allocate buffer to save elog record */ @@ -270,11 +270,11 @@ static int __init extlog_init(void) err_release_elog: if (elog_addr) - acpi_os_unmap_memory(elog_addr, elog_size); + acpi_os_unmap_iomem(elog_addr, elog_size); release_mem_region(elog_base, elog_size); err_release_l1_dir: if (extlog_l1_addr) - acpi_os_unmap_memory(extlog_l1_addr, l1_size); + acpi_os_unmap_iomem(extlog_l1_addr, l1_size); release_mem_region(l1_dirbase, l1_size); err: pr_warn(FW_BUG "Extended error log disabled because of problems parsing f/w tables\n"); @@ -287,9 +287,9 @@ static void __exit extlog_exit(void) mce_unregister_decode_chain(&extlog_mce_dec); ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN; if (extlog_l1_addr) - acpi_os_unmap_memory(extlog_l1_addr, l1_size); + acpi_os_unmap_iomem(extlog_l1_addr, l1_size); if (elog_addr) - acpi_os_unmap_memory(elog_addr, elog_size); + acpi_os_unmap_iomem(elog_addr, elog_size); release_mem_region(elog_base, elog_size); release_mem_region(l1_dirbase, l1_size); kfree(elog_buf); diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index 1be6f5564485..a095d4f858da 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -202,7 +202,7 @@ static void check_vendor_extension(u64 paddr, if (!offset) return; - v = acpi_os_map_memory(paddr + offset, sizeof(*v)); + v = acpi_os_map_iomem(paddr + offset, sizeof(*v)); if (!v) return; sbdf = v->pcie_sbdf; @@ -210,7 +210,7 @@ static void check_vendor_extension(u64 paddr, sbdf >> 24, (sbdf >> 16) & 0xff, (sbdf >> 11) & 0x1f, (sbdf >> 8) & 0x7, v->vendor_id, v->device_id, v->rev_id); - acpi_os_unmap_memory(v, sizeof(*v)); + acpi_os_unmap_iomem(v, sizeof(*v)); } static void *einj_get_parameter_address(void) @@ -236,7 +236,7 @@ static void *einj_get_parameter_address(void) if (pa_v5) { struct set_error_type_with_address *v5param; - v5param = acpi_os_map_memory(pa_v5, sizeof(*v5param)); + v5param = acpi_os_map_iomem(pa_v5, sizeof(*v5param)); if (v5param) { acpi5 = 1; check_vendor_extension(pa_v5, v5param); @@ -246,11 +246,11 @@ static void *einj_get_parameter_address(void) if (param_extension && pa_v4) { struct einj_parameter *v4param; - v4param = acpi_os_map_memory(pa_v4, sizeof(*v4param)); + v4param = acpi_os_map_iomem(pa_v4, sizeof(*v4param)); if (!v4param) return NULL; if (v4param->reserved1 || v4param->reserved2) { - acpi_os_unmap_memory(v4param, sizeof(*v4param)); + acpi_os_unmap_iomem(v4param, sizeof(*v4param)); return NULL; } return v4param; @@ -794,7 +794,7 @@ static int __init einj_init(void) sizeof(struct set_error_type_with_address) : sizeof(struct einj_parameter); - acpi_os_unmap_memory(einj_param, size); + acpi_os_unmap_iomem(einj_param, size); } apei_exec_post_unmap_gars(&ctx); err_release: @@ -816,7 +816,7 @@ static void __exit einj_exit(void) sizeof(struct set_error_type_with_address) : sizeof(struct einj_parameter); - acpi_os_unmap_memory(einj_param, size); + acpi_os_unmap_iomem(einj_param, size); } einj_exec_ctx_init(&ctx); apei_exec_post_unmap_gars(&ctx); diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index de4fe03873c5..85287b8fe3aa 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -139,8 +139,8 @@ void suspend_nvs_free(void) iounmap(entry->kaddr); entry->unmap = false; } else { - acpi_os_unmap_memory(entry->kaddr, - entry->size); + acpi_os_unmap_iomem(entry->kaddr, + entry->size); } entry->kaddr = NULL; } diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 9aeae41e22fb..147bc1b91b42 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -355,7 +355,7 @@ static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr) } void __iomem *__init_refok -acpi_os_map_memory(acpi_physical_address phys, acpi_size size) +acpi_os_map_iomem(acpi_physical_address phys, acpi_size size) { struct acpi_ioremap *map; void __iomem *virt; @@ -401,10 +401,17 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size) list_add_tail_rcu(&map->list, &acpi_ioremaps); - out: +out: mutex_unlock(&acpi_ioremap_lock); return map->virt + (phys - map->phys); } +EXPORT_SYMBOL_GPL(acpi_os_map_iomem); + +void *__init_refok +acpi_os_map_memory(acpi_physical_address phys, acpi_size size) +{ + return (void *)acpi_os_map_iomem(phys, size); +} EXPORT_SYMBOL_GPL(acpi_os_map_memory); static void acpi_os_drop_map_ref(struct acpi_ioremap *map) @@ -422,7 +429,7 @@ static void acpi_os_map_cleanup(struct acpi_ioremap *map) } } -void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) +void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size) { struct acpi_ioremap *map; @@ -443,6 +450,12 @@ void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) acpi_os_map_cleanup(map); } +EXPORT_SYMBOL_GPL(acpi_os_unmap_iomem); + +void __ref acpi_os_unmap_memory(void *virt, acpi_size size) +{ + return acpi_os_unmap_iomem((void __iomem *)virt, size); +} EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) @@ -464,7 +477,7 @@ int acpi_os_map_generic_address(struct acpi_generic_address *gas) if (!addr || !gas->bit_width) return -EINVAL; - virt = acpi_os_map_memory(addr, gas->bit_width / 8); + virt = acpi_os_map_iomem(addr, gas->bit_width / 8); if (!virt) return -EIO; diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c index b9a57fa4b710..565a9478cb94 100644 --- a/drivers/char/tpm/tpm_acpi.c +++ b/drivers/char/tpm/tpm_acpi.c @@ -95,7 +95,7 @@ int read_log(struct tpm_bios_log *log) log->bios_event_log_end = log->bios_event_log + len; - virt = acpi_os_map_memory(start, len); + virt = acpi_os_map_iomem(start, len); if (!virt) { kfree(log->bios_event_log); printk("%s: ERROR - Unable to map memory\n", __func__); @@ -104,6 +104,6 @@ int read_log(struct tpm_bios_log *log) memcpy_fromio(log->bios_event_log, virt, len); - acpi_os_unmap_memory(virt, len); + acpi_os_unmap_iomem(virt, len); return 0; } diff --git a/include/acpi/acpi_io.h b/include/acpi/acpi_io.h index 2be858018c7f..444671e9c65d 100644 --- a/include/acpi/acpi_io.h +++ b/include/acpi/acpi_io.h @@ -9,6 +9,9 @@ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, return ioremap_cache(phys, size); } +void __iomem *__init_refok +acpi_os_map_iomem(acpi_physical_address phys, acpi_size size); +void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size); void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size); int acpi_os_map_generic_address(struct acpi_generic_address *addr); diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index e70012956db3..cd1f052d55bb 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -128,8 +128,6 @@ #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_acquire_object #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_thread_id #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_create_lock -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_map_memory -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_unmap_memory /* * OSL interfaces used by debugger/disassembler @@ -163,10 +161,6 @@ #define __init #endif -#ifndef __iomem -#define __iomem -#endif - /* Host-dependent types and defines for user-space ACPICA */ #define ACPI_FLUSH_CPU_CACHE() diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h index cce0723d05a9..191e741cfa0e 100644 --- a/include/acpi/platform/aclinuxex.h +++ b/include/acpi/platform/aclinuxex.h @@ -102,10 +102,6 @@ static inline acpi_thread_id acpi_os_get_thread_id(void) lock ? AE_OK : AE_NO_MEMORY; \ }) -void __iomem *acpi_os_map_memory(acpi_physical_address where, acpi_size length); - -void acpi_os_unmap_memory(void __iomem * logical_address, acpi_size size); - /* * OSL interfaces added by Linux */ From 2947c1d5f72b77078aeb3df05d4298274234534d Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 28 May 2014 01:14:55 +0800 Subject: [PATCH 107/134] ACPICA: acpidump: Fix repetitive table dump in -n mode. In "-n" mode, reserved tables (RSDP/RSDT/XSDT/DSDT/FACS) are dumped multiple times due a missing instance check in osl_get_bios_table(). This patch fixes this issue. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- tools/power/acpi/os_specific/service_layers/oslinuxtbl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c index ba7bad04dff1..28c52008e854 100644 --- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c @@ -783,6 +783,10 @@ osl_get_bios_table(char *signature, ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT) || ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT) || ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { + if (instance > 0) { + return (AE_LIMIT); + } + /* * Get the appropriate address, either 32-bit or 64-bit. Be very * careful about the FADT length and validate table addresses. From 0c5ff0ef80c2561ef20721299ecfc39c5a42f694 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 28 May 2014 15:23:35 +0800 Subject: [PATCH 108/134] PM / sleep: unregister wakeup source when disabling device wakeup When enabling a device' wakeup capability, a wakeup source is created for the device automatically. But the wakeup source is not unregistered when disabling the device' wakeup capability. This results in zombie wakeup sources, after devices/drivers are unregistered. Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/base/power/wakeup.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 2d56f4113ae7..eb1bd2ecad8b 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -318,10 +318,16 @@ int device_init_wakeup(struct device *dev, bool enable) { int ret = 0; + if (!dev) + return -EINVAL; + if (enable) { device_set_wakeup_capable(dev, true); ret = device_wakeup_enable(dev); } else { + if (dev->power.can_wakeup) + device_wakeup_disable(dev); + device_set_wakeup_capable(dev, false); } From 1ac5aaa67290b397712e4410de7f067d5cd85871 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 28 May 2014 15:23:36 +0800 Subject: [PATCH 109/134] ACPI / battery: introduce support for POWER_SUPPLY_PROP_CAPACITY_LEVEL ACPI battery device receives notifications when 1. the remaining battery capacity becomes critical low 2. the trip point set by the _BTP (Design capacity of Warning by default) is reached or crossed. So it is able to support POWER_SUPPLY_PROP_CAPACITY_LEVEL to report POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL, POWER_SUPPLY_CAPACITY_LEVEL_LOW, POWER_SUPPLY_CAPACITY_LEVEL_NORMAL, POWER_SUPPLY_CAPACITY_LEVEL_FULL, capacity levels to power supply core and user space. Introduce support for POWER_SUPPLY_PROP_CAPACITY_LEVEL in this patch. Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 3b4921e4dc4e..11285e7df278 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -56,6 +56,10 @@ /* Battery power unit: 0 means mW, 1 means mA */ #define ACPI_BATTERY_POWER_UNIT_MA 1 +#define ACPI_BATTERY_STATE_DISCHARGING 0x1 +#define ACPI_BATTERY_STATE_CHARGING 0x2 +#define ACPI_BATTERY_STATE_CRITICAL 0x4 + #define _COMPONENT ACPI_BATTERY_COMPONENT ACPI_MODULE_NAME("battery"); @@ -169,7 +173,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery); static int acpi_battery_is_charged(struct acpi_battery *battery) { - /* either charging or discharging */ + /* charging, discharging or critical low */ if (battery->state != 0) return 0; @@ -204,9 +208,9 @@ static int acpi_battery_get_property(struct power_supply *psy, return -ENODEV; switch (psp) { case POWER_SUPPLY_PROP_STATUS: - if (battery->state & 0x01) + if (battery->state & ACPI_BATTERY_STATE_DISCHARGING) val->intval = POWER_SUPPLY_STATUS_DISCHARGING; - else if (battery->state & 0x02) + else if (battery->state & ACPI_BATTERY_STATE_CHARGING) val->intval = POWER_SUPPLY_STATUS_CHARGING; else if (acpi_battery_is_charged(battery)) val->intval = POWER_SUPPLY_STATUS_FULL; @@ -269,6 +273,17 @@ static int acpi_battery_get_property(struct power_supply *psy, else val->intval = 0; break; + case POWER_SUPPLY_PROP_CAPACITY_LEVEL: + if (battery->state & ACPI_BATTERY_STATE_CRITICAL) + val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; + else if (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) && + (battery->capacity_now <= battery->alarm)) + val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW; + else if (acpi_battery_is_charged(battery)) + val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL; + else + val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; + break; case POWER_SUPPLY_PROP_MODEL_NAME: val->strval = battery->model_number; break; @@ -296,6 +311,7 @@ static enum power_supply_property charge_battery_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_SERIAL_NUMBER, @@ -313,6 +329,7 @@ static enum power_supply_property energy_battery_props[] = { POWER_SUPPLY_PROP_ENERGY_FULL, POWER_SUPPLY_PROP_ENERGY_NOW, POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_SERIAL_NUMBER, From 9113e260767b1cb44f8da0e5922e1a9a5417c4b8 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 28 May 2014 15:23:37 +0800 Subject: [PATCH 110/134] power_supply: allow power supply devices registered w/o wakeup source Currently, all the power supply devices are registered with wakeup source, this results in that every power_supply_changed() invocation brings the system out of suspend-to-freeze state. This is overkill as some device drivers, e.g. ACPI battery driver, have the ability to check the device status and wake up the system from sleeping only when necessary. Thus introduce a new API which allows device to be registered w/o wakeup source. Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/power/power_supply_core.c | 15 +++++++++++++-- include/linux/power_supply.h | 2 ++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 26606641fe44..5a5a24e7d43c 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -537,7 +537,7 @@ static void psy_unregister_cooler(struct power_supply *psy) } #endif -int power_supply_register(struct device *parent, struct power_supply *psy) +int __power_supply_register(struct device *parent, struct power_supply *psy, bool ws) { struct device *dev; int rc; @@ -568,7 +568,7 @@ int power_supply_register(struct device *parent, struct power_supply *psy) } spin_lock_init(&psy->changed_lock); - rc = device_init_wakeup(dev, true); + rc = device_init_wakeup(dev, ws); if (rc) goto wakeup_init_failed; @@ -606,8 +606,19 @@ int power_supply_register(struct device *parent, struct power_supply *psy) success: return rc; } + +int power_supply_register(struct device *parent, struct power_supply *psy) +{ + return __power_supply_register(parent, psy, true); +} EXPORT_SYMBOL_GPL(power_supply_register); +int power_supply_register_no_ws(struct device *parent, struct power_supply *psy) +{ + return __power_supply_register(parent, psy, false); +} +EXPORT_SYMBOL_GPL(power_supply_register_no_ws); + void power_supply_unregister(struct power_supply *psy) { cancel_work_sync(&psy->changed_work); diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index c9dc4e09854c..f2b76aeaf4e4 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -264,6 +264,8 @@ static inline int power_supply_is_system_supplied(void) { return -ENOSYS; } extern int power_supply_register(struct device *parent, struct power_supply *psy); +extern int power_supply_register_no_ws(struct device *parent, + struct power_supply *psy); extern void power_supply_unregister(struct power_supply *psy); extern int power_supply_powers(struct power_supply *psy, struct device *dev); From e0d1f09e311fafa33b4bfd942c852671ce25ae58 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 28 May 2014 15:23:38 +0800 Subject: [PATCH 111/134] ACPI / battery: wakeup the system only when necessary ACPI Battery device receives notifications from firmware frequently, and most of these notifications are some general events, like battery remaining capacity change, etc, which should not wake the system up if the system is in suspend/hibernate state. This causes a problem that the system wakes up from suspend to freeze shortly, because there is an ACPI battery notification every 10 seconds. Fix the problem in this patch by registering ACPI battery device' own wakeup source, and waking up the system only when the battery remaining capacity is critical low, or lower than the alarm capacity set via _BTP. Link: https://bugzilla.kernel.org/show_bug.cgi?id=76221 Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 11285e7df278..e48fc98e71c4 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -622,7 +622,8 @@ static int sysfs_add_battery(struct acpi_battery *battery) battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; battery->bat.get_property = acpi_battery_get_property; - result = power_supply_register(&battery->device->dev, &battery->bat); + result = power_supply_register_no_ws(&battery->device->dev, &battery->bat); + if (result) return result; return device_create_file(battery->bat.dev, &alarm_attr); @@ -741,7 +742,19 @@ static int acpi_battery_update(struct acpi_battery *battery, bool resume) return result; } result = acpi_battery_get_state(battery); + if (result) + return result; acpi_battery_quirks(battery); + + /* + * Wakeup the system if battery is critical low + * or lower than the alarm level + */ + if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) || + (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) && + (battery->capacity_now <= battery->alarm))) + pm_wakeup_event(&battery->device->dev, 0); + return result; } @@ -1142,6 +1155,8 @@ static int acpi_battery_add(struct acpi_device *device) battery->pm_nb.notifier_call = battery_notify; register_pm_notifier(&battery->pm_nb); + device_init_wakeup(&device->dev, 1); + return result; fail: @@ -1158,6 +1173,7 @@ static int acpi_battery_remove(struct acpi_device *device) if (!device || !acpi_driver_data(device)) return -EINVAL; + device_init_wakeup(&device->dev, 0); battery = acpi_driver_data(device); unregister_pm_notifier(&battery->pm_nb); #ifdef CONFIG_ACPI_PROCFS_POWER From aca0a4eb4e325914ddb22a8ed06fcb0222da2a26 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 May 2014 04:21:52 +0200 Subject: [PATCH 112/134] ACPI / scan: .match() callback for ACPI scan handlers Introduce a .match() callback for ACPI scan handlers to allow them to use more elaborate matching algorithms if necessary. That is needed for the upcoming PNP scan handler in particular. This change is based on a Zhang Rui's prototype. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/scan.c | 3 +++ include/acpi/acpi_bus.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index df6e4c924b35..e44438f7917b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1977,6 +1977,9 @@ static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler, { const struct acpi_device_id *devid; + if (handler->match) + return handler->match(idstr, matchid); + for (devid = handler->ids; devid->id[0]; devid++) if (!strcmp((char *)devid->id, idstr)) { if (matchid) diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 7417a16c8d86..c241c7594bbc 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -131,6 +131,7 @@ static inline struct acpi_hotplug_profile *to_acpi_hotplug_profile( struct acpi_scan_handler { const struct acpi_device_id *ids; struct list_head list_node; + bool (*match)(char *idstr, const struct acpi_device_id **matchid); int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id); void (*detach)(struct acpi_device *dev); void (*bind)(struct device *phys_dev); From eec15edbb0e14485998635ea7c62e30911b465f0 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Fri, 30 May 2014 04:23:01 +0200 Subject: [PATCH 113/134] ACPI / PNP: use device ID list for PNPACPI device enumeration ACPI can be used to enumerate PNP devices, but the code does not handle this in the right way currently. Namely, if an ACPI device object 1. Has a _CRS method, 2. Has an identification of "three capital characters followed by four hex digits", 3. Is not in the excluded IDs list, it will be enumerated to PNP bus (that is, a PNP device object will be create for it). This means that, actually, the PNP bus type is used as the default bus type for enumerating _HID devices in ACPI. However, more and more _HID devices need to be enumerated to the platform bus instead (that is, platform device objects need to be created for them). As a result, the device ID list in acpi_platform.c is used to enforce creating platform device objects rather than PNP device objects for matching devices. That list has been continuously growing recently, unfortunately, and it is pretty much guaranteed to grow even more in the future. To address that problem it is better to enumerate _HID devices as platform devices by default. To this end, change the way of enumerating PNP devices by adding a PNP ACPI scan handler that will use a device ID list to create PNP devices for the ACPI device objects whose device IDs are present in that list. The initial device ID list in the PNP ACPI scan handler contains all of the pnp_device_id strings from all the existing PNP drivers, so this change should be transparent to the PNP core and all of the PNP drivers. Still, in the future it should be possible to reduce its size by converting PNP drivers that need not be PNP for any technical reasons into platform drivers. Signed-off-by: Zhang Rui [rjw: Rewrote the changelog, modified the PNP ACPI scan handler code] Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/Makefile | 1 + drivers/acpi/acpi_cmos_rtc.c | 2 +- drivers/acpi/acpi_pnp.c | 401 +++++++++++++++++++++++++++++++++++ drivers/acpi/internal.h | 1 + drivers/acpi/scan.c | 1 + drivers/pnp/pnpacpi/core.c | 28 +-- include/linux/acpi.h | 2 + 7 files changed, 411 insertions(+), 25 deletions(-) create mode 100644 drivers/acpi/acpi_pnp.c diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index bce34afadcd0..144671a2030f 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -41,6 +41,7 @@ acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-y += pci_root.o pci_link.o pci_irq.o acpi-$(CONFIG_X86_INTEL_LPSS) += acpi_lpss.o acpi-y += acpi_platform.o +acpi-y += acpi_pnp.o acpi-y += power.o acpi-y += event.o acpi-y += sysfs.o diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c index 961b45d18a5d..2da8660262e5 100644 --- a/drivers/acpi/acpi_cmos_rtc.c +++ b/drivers/acpi/acpi_cmos_rtc.c @@ -68,7 +68,7 @@ static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev, return -ENODEV; } - return 0; + return 1; } static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev) diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c new file mode 100644 index 000000000000..567e7fc6330c --- /dev/null +++ b/drivers/acpi/acpi_pnp.c @@ -0,0 +1,401 @@ +/* + * ACPI support for PNP bus type + * + * Copyright (C) 2014, Intel Corporation + * Authors: Zhang Rui + * Rafael J. Wysocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include + +static const struct acpi_device_id acpi_pnp_device_ids[] = { + /* pata_isapnp */ + {"PNP0600"}, /* Generic ESDI/IDE/ATA compatible hard disk controller */ + /* floppy */ + {"PNP0700"}, + /* ipmi_si */ + {"IPI0001"}, + /* tpm_inf_pnp */ + {"IFX0101"}, /* Infineon TPMs */ + {"IFX0102"}, /* Infineon TPMs */ + /*tpm_tis */ + {"PNP0C31"}, /* TPM */ + {"ATM1200"}, /* Atmel */ + {"IFX0102"}, /* Infineon */ + {"BCM0101"}, /* Broadcom */ + {"BCM0102"}, /* Broadcom */ + {"NSC1200"}, /* National */ + {"ICO0102"}, /* Intel */ + /* ide */ + {"PNP0600"}, /* Generic ESDI/IDE/ATA compatible hard disk controller */ + /* ns558 */ + {"@P@0001"}, /* ALS 100 */ + {"@P@0020"}, /* ALS 200 */ + {"@P@1001"}, /* ALS 100+ */ + {"@P@2001"}, /* ALS 120 */ + {"ASB16fd"}, /* AdLib NSC16 */ + {"AZT3001"}, /* AZT1008 */ + {"CDC0001"}, /* Opl3-SAx */ + {"CSC0001"}, /* CS4232 */ + {"CSC000f"}, /* CS4236 */ + {"CSC0101"}, /* CS4327 */ + {"CTL7001"}, /* SB16 */ + {"CTL7002"}, /* AWE64 */ + {"CTL7005"}, /* Vibra16 */ + {"ENS2020"}, /* SoundscapeVIVO */ + {"ESS0001"}, /* ES1869 */ + {"ESS0005"}, /* ES1878 */ + {"ESS6880"}, /* ES688 */ + {"IBM0012"}, /* CS4232 */ + {"OPT0001"}, /* OPTi Audio16 */ + {"YMH0006"}, /* Opl3-SA */ + {"YMH0022"}, /* Opl3-SAx */ + {"PNPb02f"}, /* Generic */ + /* i8042 kbd */ + {"PNP0300"}, + {"PNP0301"}, + {"PNP0302"}, + {"PNP0303"}, + {"PNP0304"}, + {"PNP0305"}, + {"PNP0306"}, + {"PNP0309"}, + {"PNP030a"}, + {"PNP030b"}, + {"PNP0320"}, + {"PNP0343"}, + {"PNP0344"}, + {"PNP0345"}, + {"CPQA0D7"}, + /* i8042 aux */ + {"AUI0200"}, + {"FJC6000"}, + {"FJC6001"}, + {"PNP0f03"}, + {"PNP0f0b"}, + {"PNP0f0e"}, + {"PNP0f12"}, + {"PNP0f13"}, + {"PNP0f19"}, + {"PNP0f1c"}, + {"SYN0801"}, + /* fcpnp */ + {"AVM0900"}, + /* radio-cadet */ + {"MSM0c24"}, /* ADS Cadet AM/FM Radio Card */ + /* radio-gemtek */ + {"ADS7183"}, /* AOpen FX-3D/Pro Radio */ + /* radio-sf16fmr2 */ + {"MFRad13"}, /* tuner subdevice of SF16-FMD2 */ + /* ene_ir */ + {"ENE0100"}, + {"ENE0200"}, + {"ENE0201"}, + {"ENE0202"}, + /* fintek-cir */ + {"FIT0002"}, /* CIR */ + /* ite-cir */ + {"ITE8704"}, /* Default model */ + {"ITE8713"}, /* CIR found in EEEBox 1501U */ + {"ITE8708"}, /* Bridged IT8512 */ + {"ITE8709"}, /* SRAM-Bridged IT8512 */ + /* nuvoton-cir */ + {"WEC0530"}, /* CIR */ + {"NTN0530"}, /* CIR for new chip's pnp id */ + /* Winbond CIR */ + {"WEC1022"}, + /* wbsd */ + {"WEC0517"}, + {"WEC0518"}, + /* Winbond CIR */ + {"TCM5090"}, /* 3Com Etherlink III (TP) */ + {"TCM5091"}, /* 3Com Etherlink III */ + {"TCM5094"}, /* 3Com Etherlink III (combo) */ + {"TCM5095"}, /* 3Com Etherlink III (TPO) */ + {"TCM5098"}, /* 3Com Etherlink III (TPC) */ + {"PNP80f7"}, /* 3Com Etherlink III compatible */ + {"PNP80f8"}, /* 3Com Etherlink III compatible */ + /* nsc-ircc */ + {"NSC6001"}, + {"HWPC224"}, + {"IBM0071"}, + /* smsc-ircc2 */ + {"SMCf010"}, + /* sb1000 */ + {"GIC1000"}, + /* parport_pc */ + {"PNP0400"}, /* Standard LPT Printer Port */ + {"PNP0401"}, /* ECP Printer Port */ + /* apple-gmux */ + {"APP000B"}, + /* fujitsu-laptop.c */ + {"FUJ02bf"}, + {"FUJ02B1"}, + {"FUJ02E3"}, + /* system */ + {"PNP0c02"}, /* General ID for reserving resources */ + {"PNP0c01"}, /* memory controller */ + /* rtc_cmos */ + {"PNP0b00"}, + {"PNP0b01"}, + {"PNP0b02"}, + /* c6xdigio */ + {"PNP0400"}, /* Standard LPT Printer Port */ + {"PNP0401"}, /* ECP Printer Port */ + /* ni_atmio.c */ + {"NIC1900"}, + {"NIC2400"}, + {"NIC2500"}, + {"NIC2600"}, + {"NIC2700"}, + /* serial */ + {"AAC000F"}, /* Archtek America Corp. Archtek SmartLink Modem 3334BT Plug & Play */ + {"ADC0001"}, /* Anchor Datacomm BV. SXPro 144 External Data Fax Modem Plug & Play */ + {"ADC0002"}, /* SXPro 288 External Data Fax Modem Plug & Play */ + {"AEI0250"}, /* PROLiNK 1456VH ISA PnP K56flex Fax Modem */ + {"AEI1240"}, /* Actiontec ISA PNP 56K X2 Fax Modem */ + {"AKY1021"}, /* Rockwell 56K ACF II Fax+Data+Voice Modem */ + {"AZT4001"}, /* AZT3005 PnP SOUND DEVICE */ + {"BDP3336"}, /* Best Data Products Inc. Smart One 336F PnP Modem */ + {"BRI0A49"}, /* Boca Complete Ofc Communicator 14.4 Data-FAX */ + {"BRI1400"}, /* Boca Research 33,600 ACF Modem */ + {"BRI3400"}, /* Boca 33.6 Kbps Internal FD34FSVD */ + {"BRI0A49"}, /* Boca 33.6 Kbps Internal FD34FSVD */ + {"BDP3336"}, /* Best Data Products Inc. Smart One 336F PnP Modem */ + {"CPI4050"}, /* Computer Peripherals Inc. EuroViVa CommCenter-33.6 SP PnP */ + {"CTL3001"}, /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */ + {"CTL3011"}, /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */ + {"DAV0336"}, /* Davicom ISA 33.6K Modem */ + {"DMB1032"}, /* Creative Modem Blaster Flash56 DI5601-1 */ + {"DMB2001"}, /* Creative Modem Blaster V.90 DI5660 */ + {"ETT0002"}, /* E-Tech CyberBULLET PC56RVP */ + {"FUJ0202"}, /* Fujitsu 33600 PnP-I2 R Plug & Play */ + {"FUJ0205"}, /* Fujitsu FMV-FX431 Plug & Play */ + {"FUJ0206"}, /* Fujitsu 33600 PnP-I4 R Plug & Play */ + {"FUJ0209"}, /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */ + {"GVC000F"}, /* Archtek SmartLink Modem 3334BT Plug & Play */ + {"GVC0303"}, /* Archtek SmartLink Modem 3334BRV 33.6K Data Fax Voice */ + {"HAY0001"}, /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */ + {"HAY000C"}, /* Hayes Optima 336 V.34 + FAX + Voice PnP */ + {"HAY000D"}, /* Hayes Optima 336B V.34 + FAX + Voice PnP */ + {"HAY5670"}, /* Hayes Accura 56K Ext Fax Modem PnP */ + {"HAY5674"}, /* Hayes Accura 56K Ext Fax Modem PnP */ + {"HAY5675"}, /* Hayes Accura 56K Fax Modem PnP */ + {"HAYF000"}, /* Hayes 288, V.34 + FAX */ + {"HAYF001"}, /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */ + {"IBM0033"}, /* IBM Thinkpad 701 Internal Modem Voice */ + {"PNP4972"}, /* Intermec CV60 touchscreen port */ + {"IXDC801"}, /* Intertex 28k8 33k6 Voice EXT PnP */ + {"IXDC901"}, /* Intertex 33k6 56k Voice EXT PnP */ + {"IXDD801"}, /* Intertex 28k8 33k6 Voice SP EXT PnP */ + {"IXDD901"}, /* Intertex 33k6 56k Voice SP EXT PnP */ + {"IXDF401"}, /* Intertex 28k8 33k6 Voice SP INT PnP */ + {"IXDF801"}, /* Intertex 28k8 33k6 Voice SP EXT PnP */ + {"IXDF901"}, /* Intertex 33k6 56k Voice SP EXT PnP */ + {"KOR4522"}, /* KORTEX 28800 Externe PnP */ + {"KORF661"}, /* KXPro 33.6 Vocal ASVD PnP */ + {"LAS4040"}, /* LASAT Internet 33600 PnP */ + {"LAS4540"}, /* Lasat Safire 560 PnP */ + {"LAS5440"}, /* Lasat Safire 336 PnP */ + {"MNP0281"}, /* Microcom TravelPorte FAST V.34 Plug & Play */ + {"MNP0336"}, /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */ + {"MNP0339"}, /* Microcom DeskPorte FAST EP 28.8 Plug & Play */ + {"MNP0342"}, /* Microcom DeskPorte 28.8P Plug & Play */ + {"MNP0500"}, /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ + {"MNP0501"}, /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ + {"MNP0502"}, /* Microcom DeskPorte 28.8S Internal Plug & Play */ + {"MOT1105"}, /* Motorola BitSURFR Plug & Play */ + {"MOT1111"}, /* Motorola TA210 Plug & Play */ + {"MOT1114"}, /* Motorola HMTA 200 (ISDN) Plug & Play */ + {"MOT1115"}, /* Motorola BitSURFR Plug & Play */ + {"MOT1190"}, /* Motorola Lifestyle 28.8 Internal */ + {"MOT1501"}, /* Motorola V.3400 Plug & Play */ + {"MOT1502"}, /* Motorola Lifestyle 28.8 V.34 Plug & Play */ + {"MOT1505"}, /* Motorola Power 28.8 V.34 Plug & Play */ + {"MOT1509"}, /* Motorola ModemSURFR External 28.8 Plug & Play */ + {"MOT150A"}, /* Motorola Premier 33.6 Desktop Plug & Play */ + {"MOT150F"}, /* Motorola VoiceSURFR 56K External PnP */ + {"MOT1510"}, /* Motorola ModemSURFR 56K External PnP */ + {"MOT1550"}, /* Motorola ModemSURFR 56K Internal PnP */ + {"MOT1560"}, /* Motorola ModemSURFR Internal 28.8 Plug & Play */ + {"MOT1580"}, /* Motorola Premier 33.6 Internal Plug & Play */ + {"MOT15B0"}, /* Motorola OnlineSURFR 28.8 Internal Plug & Play */ + {"MOT15F0"}, /* Motorola VoiceSURFR 56K Internal PnP */ + {"MVX00A1"}, /* Deskline K56 Phone System PnP */ + {"MVX00F2"}, /* PC Rider K56 Phone System PnP */ + {"nEC8241"}, /* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */ + {"PMC2430"}, /* Pace 56 Voice Internal Plug & Play Modem */ + {"PNP0500"}, /* Generic standard PC COM port */ + {"PNP0501"}, /* Generic 16550A-compatible COM port */ + {"PNPC000"}, /* Compaq 14400 Modem */ + {"PNPC001"}, /* Compaq 2400/9600 Modem */ + {"PNPC031"}, /* Dial-Up Networking Serial Cable between 2 PCs */ + {"PNPC032"}, /* Dial-Up Networking Parallel Cable between 2 PCs */ + {"PNPC100"}, /* Standard 9600 bps Modem */ + {"PNPC101"}, /* Standard 14400 bps Modem */ + {"PNPC102"}, /* Standard 28800 bps Modem */ + {"PNPC103"}, /* Standard Modem */ + {"PNPC104"}, /* Standard 9600 bps Modem */ + {"PNPC105"}, /* Standard 14400 bps Modem */ + {"PNPC106"}, /* Standard 28800 bps Modem */ + {"PNPC107"}, /* Standard Modem */ + {"PNPC108"}, /* Standard 9600 bps Modem */ + {"PNPC109"}, /* Standard 14400 bps Modem */ + {"PNPC10A"}, /* Standard 28800 bps Modem */ + {"PNPC10B"}, /* Standard Modem */ + {"PNPC10C"}, /* Standard 9600 bps Modem */ + {"PNPC10D"}, /* Standard 14400 bps Modem */ + {"PNPC10E"}, /* Standard 28800 bps Modem */ + {"PNPC10F"}, /* Standard Modem */ + {"PNP2000"}, /* Standard PCMCIA Card Modem */ + {"ROK0030"}, /* Rockwell 33.6 DPF Internal PnP, Modular Technology 33.6 Internal PnP */ + {"ROK0100"}, /* KORTEX 14400 Externe PnP */ + {"ROK4120"}, /* Rockwell 28.8 */ + {"ROK4920"}, /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */ + {"RSS00A0"}, /* Rockwell 33.6 DPF External PnP, BT Prologue 33.6 External PnP, Modular Technology 33.6 External PnP */ + {"RSS0262"}, /* Viking 56K FAX INT */ + {"RSS0250"}, /* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */ + {"SUP1310"}, /* SupraExpress 28.8 Data/Fax PnP modem */ + {"SUP1381"}, /* SupraExpress 336i PnP Voice Modem */ + {"SUP1421"}, /* SupraExpress 33.6 Data/Fax PnP modem */ + {"SUP1590"}, /* SupraExpress 33.6 Data/Fax PnP modem */ + {"SUP1620"}, /* SupraExpress 336i Sp ASVD */ + {"SUP1760"}, /* SupraExpress 33.6 Data/Fax PnP modem */ + {"SUP2171"}, /* SupraExpress 56i Sp Intl */ + {"TEX0011"}, /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */ + {"UAC000F"}, /* Archtek SmartLink Modem 3334BT Plug & Play */ + {"USR0000"}, /* 3Com Corp. Gateway Telepath IIvi 33.6 */ + {"USR0002"}, /* U.S. Robotics Sporster 33.6K Fax INT PnP */ + {"USR0004"}, /* Sportster Vi 14.4 PnP FAX Voicemail */ + {"USR0006"}, /* U.S. Robotics 33.6K Voice INT PnP */ + {"USR0007"}, /* U.S. Robotics 33.6K Voice EXT PnP */ + {"USR0009"}, /* U.S. Robotics Courier V.Everything INT PnP */ + {"USR2002"}, /* U.S. Robotics 33.6K Voice INT PnP */ + {"USR2070"}, /* U.S. Robotics 56K Voice INT PnP */ + {"USR2080"}, /* U.S. Robotics 56K Voice EXT PnP */ + {"USR3031"}, /* U.S. Robotics 56K FAX INT */ + {"USR3050"}, /* U.S. Robotics 56K FAX INT */ + {"USR3070"}, /* U.S. Robotics 56K Voice INT PnP */ + {"USR3080"}, /* U.S. Robotics 56K Voice EXT PnP */ + {"USR3090"}, /* U.S. Robotics 56K Voice INT PnP */ + {"USR9100"}, /* U.S. Robotics 56K Message */ + {"USR9160"}, /* U.S. Robotics 56K FAX EXT PnP */ + {"USR9170"}, /* U.S. Robotics 56K FAX INT PnP */ + {"USR9180"}, /* U.S. Robotics 56K Voice EXT PnP */ + {"USR9190"}, /* U.S. Robotics 56K Voice INT PnP */ + {"WACFXXX"}, /* Wacom tablets */ + {"FPI2002"}, /* Compaq touchscreen */ + {"FUJ02B2"}, /* Fujitsu Stylistic touchscreens */ + {"FUJ02B3"}, + {"FUJ02B4"}, /* Fujitsu Stylistic LT touchscreens */ + {"FUJ02B6"}, /* Passive Fujitsu Stylistic touchscreens */ + {"FUJ02B7"}, + {"FUJ02B8"}, + {"FUJ02B9"}, + {"FUJ02BC"}, + {"FUJ02E5"}, /* Fujitsu Wacom Tablet PC device */ + {"FUJ02E6"}, /* Fujitsu P-series tablet PC device */ + {"FUJ02E7"}, /* Fujitsu Wacom 2FGT Tablet PC device */ + {"FUJ02E9"}, /* Fujitsu Wacom 1FGT Tablet PC device */ + {"LTS0001"}, /* LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in disguise) */ + {"WCI0003"}, /* Rockwell's (PORALiNK) 33600 INT PNP */ + {"WEC1022"}, /* Winbond CIR port, should not be probed. We should keep track of it to prevent the legacy serial driver from probing it */ + {"PNPCXXX"}, /* Unknown PnP modems */ + {"PNPDXXX"}, /* More unknown PnP modems */ + /* scl200wdt */ + {"NSC0800"}, /* National Semiconductor PC87307/PC97307 watchdog component */ + /* mpu401 */ + {"PNPb006"}, + /* cs423x-pnpbios */ + {"CSC0100"}, + {"CSC0000"}, + {"GIM0100"}, /* Guillemot Turtlebeach something appears to be cs4232 compatible */ + /* es18xx-pnpbios */ + {"ESS1869"}, + {"ESS1879"}, + /* snd-opl3sa2-pnpbios */ + {"YMH0021"}, + {"NMX2210"}, /* Gateway Solo 2500 */ + {""}, +}; + +static bool is_hex_digit(char c) +{ + return (c >= 0 && c <= '9') || (c >= 'A' && c <= 'F'); +} + +static bool matching_id(char *idstr, char *list_id) +{ + int i; + + if (memcmp(idstr, list_id, 3)) + return false; + + for (i = 3; i < 7; i++) { + char c = toupper(idstr[i]); + + if (!is_hex_digit(c) + || (list_id[i] != 'X' && c != toupper(list_id[i]))) + return false; + } + return true; +} + +static bool acpi_pnp_match(char *idstr, const struct acpi_device_id **matchid) +{ + const struct acpi_device_id *devid; + + for (devid = acpi_pnp_device_ids; devid->id[0]; devid++) + if (matching_id(idstr, (char *)devid->id)) { + if (matchid) + *matchid = devid; + + return true; + } + + return false; +} + +static int acpi_pnp_attach(struct acpi_device *adev, + const struct acpi_device_id *id) +{ + return 1; +} + +static struct acpi_scan_handler acpi_pnp_handler = { + .ids = acpi_pnp_device_ids, + .match = acpi_pnp_match, + .attach = acpi_pnp_attach, +}; + +/* + * For CMOS RTC devices, the PNP ACPI scan handler does not work, because + * there is a CMOS RTC ACPI scan handler installed already, so we need to + * check those devices and enumerate them to the PNP bus directly. + */ +static int is_cmos_rtc_device(struct acpi_device *adev) +{ + struct acpi_device_id ids[] = { + { "PNP0B00" }, + { "PNP0B01" }, + { "PNP0B02" }, + {""}, + }; + return !acpi_match_device_ids(adev, ids); +} + +bool acpi_is_pnp_device(struct acpi_device *adev) +{ + return adev->handler == &acpi_pnp_handler || is_cmos_rtc_device(adev); +} +EXPORT_SYMBOL_GPL(acpi_is_pnp_device); + +void __init acpi_pnp_init(void) +{ + acpi_scan_add_handler(&acpi_pnp_handler); +} diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index bb7de413d06d..5c16cb6bc76d 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -30,6 +30,7 @@ void acpi_pci_root_init(void); void acpi_pci_link_init(void); void acpi_processor_init(void); void acpi_platform_init(void); +void acpi_pnp_init(void); int acpi_sysfs_init(void); #ifdef CONFIG_ACPI_CONTAINER void acpi_container_init(void); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e44438f7917b..19d524c5c0c8 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2253,6 +2253,7 @@ int __init acpi_scan_init(void) acpi_cmos_rtc_init(); acpi_container_init(); acpi_memory_hotplug_init(); + acpi_pnp_init(); mutex_lock(&acpi_scan_lock); /* diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index c31aa07b3ba5..b81448b2c75d 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -30,26 +30,6 @@ static int num; -/* We need only to blacklist devices that have already an acpi driver that - * can't use pnp layer. We don't need to blacklist device that are directly - * used by the kernel (PCI root, ...), as it is harmless and there were - * already present in pnpbios. But there is an exception for devices that - * have irqs (PIC, Timer) because we call acpi_register_gsi. - * Finally, only devices that have a CRS method need to be in this list. - */ -static struct acpi_device_id excluded_id_list[] __initdata = { - {"PNP0C09", 0}, /* EC */ - {"PNP0C0F", 0}, /* Link device */ - {"PNP0000", 0}, /* PIC */ - {"PNP0100", 0}, /* Timer */ - {"", 0}, -}; - -static inline int __init is_exclusive_device(struct acpi_device *dev) -{ - return (!acpi_match_device_ids(dev, excluded_id_list)); -} - /* * Compatible Device IDs */ @@ -266,7 +246,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device) if (!pnpid) return 0; - if (is_exclusive_device(device) || !device->status.present) + if (!device->status.present) return 0; dev = pnp_alloc_dev(&pnpacpi_protocol, num, pnpid); @@ -326,10 +306,10 @@ static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle, { struct acpi_device *device; - if (!acpi_bus_get_device(handle, &device)) - pnpacpi_add_device(device); - else + if (acpi_bus_get_device(handle, &device)) return AE_CTRL_DEPTH; + if (acpi_is_pnp_device(device)) + pnpacpi_add_device(device); return AE_OK; } diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 4c007262e891..0b9927f4edd2 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -184,6 +184,8 @@ extern int ec_transaction(u8 command, u8 *rdata, unsigned rdata_len); extern acpi_handle ec_get_handle(void); +extern bool acpi_is_pnp_device(struct acpi_device *); + #if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE) typedef void (*wmi_notify_handler) (u32 value, void *context); From e1d2c4cf0bfa6a9b484ebcb2ce99c5f38d05c680 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Fri, 30 May 2014 04:24:04 +0200 Subject: [PATCH 114/134] ACPI / scan: drop IDs that do not comply with the ACPI PNP ID rule The PNP ACPI scan handler device ID list includes all the IDs from all of the struct pnp_device_id instances in the tree, but some of them do not follow the ACPI PNP ID rule (3 letters + 4 hex digits). For those IDs, the coressponding devices will never be enumerated via ACPI, so it is safe to remove them from the PNP ACPI ID list. Signed-off-by: Zhang Rui [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/acpi_pnp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c index 567e7fc6330c..895c45d8d25a 100644 --- a/drivers/acpi/acpi_pnp.c +++ b/drivers/acpi/acpi_pnp.c @@ -34,10 +34,6 @@ static const struct acpi_device_id acpi_pnp_device_ids[] = { /* ide */ {"PNP0600"}, /* Generic ESDI/IDE/ATA compatible hard disk controller */ /* ns558 */ - {"@P@0001"}, /* ALS 100 */ - {"@P@0020"}, /* ALS 200 */ - {"@P@1001"}, /* ALS 100+ */ - {"@P@2001"}, /* ALS 120 */ {"ASB16fd"}, /* AdLib NSC16 */ {"AZT3001"}, /* AZT1008 */ {"CDC0001"}, /* Opl3-SAx */ From 01cd4bac8ce433f125b772e3964886fc12e108c7 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Fri, 30 May 2014 04:25:15 +0200 Subject: [PATCH 115/134] ACPI / scan: drop unsupported serial IDs from PNP ACPI scan handler ID list The "serial" PNP driver supports some "unknown" PNP modems (PNPCXXX/PNPDXXX) by matching magic strings in the PNP device name or the PNP device card name. ACPI enumerated PNP devices neither are PNP cards, nor have those magic strings in device names, so this mechamism never actually works for ACPI enumerated PNPCXXX/PNPDXXX devices. Consequently, it is safe to remove those two IDs from the PNP ACPI scan handler's device ID list. Signed-off-by: Zhang Rui [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/acpi_pnp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c index 895c45d8d25a..6703c1fd993a 100644 --- a/drivers/acpi/acpi_pnp.c +++ b/drivers/acpi/acpi_pnp.c @@ -301,8 +301,6 @@ static const struct acpi_device_id acpi_pnp_device_ids[] = { {"LTS0001"}, /* LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in disguise) */ {"WCI0003"}, /* Rockwell's (PORALiNK) 33600 INT PNP */ {"WEC1022"}, /* Winbond CIR port, should not be probed. We should keep track of it to prevent the legacy serial driver from probing it */ - {"PNPCXXX"}, /* Unknown PnP modems */ - {"PNPDXXX"}, /* More unknown PnP modems */ /* scl200wdt */ {"NSC0800"}, /* National Semiconductor PC87307/PC97307 watchdog component */ /* mpu401 */ From 549e68455c6706796d9d244364dfbf5c575bd1a5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 May 2014 04:26:18 +0200 Subject: [PATCH 116/134] ACPI / scan: introduce platform_id device PNP type flag Only certain types of ACPI device objects can be enumerated as platform devices, so in order to distinguish them from the others introduce a new ACPI device PNP type flag, platform_id, and set it for devices with a valid _HID to start with. This change is based on a Zhang Rui's prototype. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/scan.c | 4 +++- include/acpi/acpi_bus.h | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 19d524c5c0c8..ebbd23c94ba2 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1797,8 +1797,10 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, return; } - if (info->valid & ACPI_VALID_HID) + if (info->valid & ACPI_VALID_HID) { acpi_add_id(pnp, info->hardware_id.string); + pnp->type.platform_id = 1; + } if (info->valid & ACPI_VALID_CID) { cid_list = &info->compatible_id_list; for (i = 0; i < cid_list->count; i++) diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c241c7594bbc..21477467441c 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -233,7 +233,8 @@ struct acpi_hardware_id { struct acpi_pnp_type { u32 hardware_id:1; u32 bus_address:1; - u32 reserved:30; + u32 platform_id:1; + u32 reserved:29; }; struct acpi_device_pnp { From d34afa9de4447367b734ec407e5a9e10617d6ec3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 May 2014 04:27:31 +0200 Subject: [PATCH 117/134] ACPI / scan: Change the meaning of missing .attach() in scan handlers Currently, some scan handlers can be compiled out entirely, which leaves the device objects they normally attach to without a scan handler. This isn't a problem as long as we don't have any default enumeration mechanism that applies to all devices without a scan handler. However, if such a default enumeration is added, it still should not be applied to devices that are normally attached to by scan handlers, because that may result in creating "physical" device objects of a wrong type for them. Since we are going to create platform device objects for all ACPI device objects with pnp.type.platform_id set by default, clear pnp.type.platform_id where there is a matching scan handler without an .attach() callback and otherwise simply treat that scan handler as though the .attach() callback was present but always returned 0. This will allow us to compile out scan handler callbacks and leave the device ID lists used by them so as to prevent creating platform device objects for the matching ACPI devices. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/scan.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ebbd23c94ba2..611bb5db7e57 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -84,7 +84,7 @@ EXPORT_SYMBOL_GPL(acpi_initialize_hp_context); int acpi_scan_add_handler(struct acpi_scan_handler *handler) { - if (!handler || !handler->attach) + if (!handler) return -EINVAL; list_add_tail(&handler->list_node, &acpi_scan_handlers_list); @@ -2081,6 +2081,10 @@ static int acpi_scan_attach_handler(struct acpi_device *device) handler = acpi_scan_match_handler(hwid->id, &devid); if (handler) { + if (!handler->attach) { + device->pnp.type.platform_id = 0; + continue; + } device->handler = handler; ret = handler->attach(device, devid); if (ret > 0) From a1ec657213b4abb00e59385171554a3e11eec27c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 May 2014 04:28:20 +0200 Subject: [PATCH 118/134] ACPI / scan: always register container scan handler Prevent platform devices from being created for ACPI containers if CONFIG_ACPI_CONTAINER is unset by compiling out the container scan handler's callbacks only in that case and still compiling its device ID list in and registering the scan handler in either case. This change is based on a prototype from Zhang Rui. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/Makefile | 2 +- drivers/acpi/container.c | 15 +++++++++++++++ drivers/acpi/internal.h | 4 ---- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 144671a2030f..4f23f3295b12 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -64,7 +64,7 @@ obj-$(CONFIG_ACPI_FAN) += fan.o obj-$(CONFIG_ACPI_VIDEO) += video.o obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o -obj-$(CONFIG_ACPI_CONTAINER) += container.o +obj-y += container.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o obj-$(CONFIG_ACPI_BATTERY) += battery.o diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 63119d09b354..76f7cff64594 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -41,6 +41,8 @@ static const struct acpi_device_id container_device_ids[] = { {"", 0}, }; +#ifdef CONFIG_ACPI_CONTAINER + static int acpi_container_offline(struct container_dev *cdev) { struct acpi_device *adev = ACPI_COMPANION(&cdev->dev); @@ -107,7 +109,20 @@ static struct acpi_scan_handler container_handler = { }, }; +void __init acpi_container_init(void) +{ + acpi_scan_add_handler(&container_handler); +} + +#else + +static struct acpi_scan_handler container_handler = { + .ids = container_device_ids, +}; + void __init acpi_container_init(void) { acpi_scan_add_handler_with_hotplug(&container_handler, "container"); } + +#endif /* CONFIG_ACPI_CONTAINER */ diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 5c16cb6bc76d..cc93efd22a24 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -32,11 +32,7 @@ void acpi_processor_init(void); void acpi_platform_init(void); void acpi_pnp_init(void); int acpi_sysfs_init(void); -#ifdef CONFIG_ACPI_CONTAINER void acpi_container_init(void); -#else -static inline void acpi_container_init(void) {} -#endif #ifdef CONFIG_ACPI_DOCK void register_dock_dependent_device(struct acpi_device *adev, acpi_handle dshandle); From cccd420859a419756bc4ed25d52989a47d702561 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 May 2014 04:29:14 +0200 Subject: [PATCH 119/134] ACPI / scan: always register memory hotplug scan handler Prevent platform devices from being created for ACPI memory device objects if CONFIG_ACPI_HOTPLUG_MEMORY is unset by compiling out the memory hotplug scan handler's callbacks only in that case and still compiling its device ID list in and registering the scan handler in either case. Also unset the memory hotplug scan handler's .attach() callback if acpi_no_memhotplug is set, but still register the scan handler to avoid creating platform devices for ACPI memory devices in that case too. This change is based on a prototype from Zhang Rui. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/Makefile | 2 +- drivers/acpi/acpi_memhotplug.c | 31 ++++++++++++++++++++++++------- drivers/acpi/internal.h | 6 +----- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 4f23f3295b12..f1c9266430d9 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -66,7 +66,7 @@ obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o obj-y += container.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o -obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o +obj-y += acpi_memhotplug.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_SBS) += sbshc.o obj-$(CONFIG_ACPI_SBS) += sbs.o diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index b67be85ff0fc..23e2319ead41 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -44,6 +44,13 @@ ACPI_MODULE_NAME("acpi_memhotplug"); +static const struct acpi_device_id memory_device_ids[] = { + {ACPI_MEMORY_DEVICE_HID, 0}, + {"", 0}, +}; + +#ifdef CONFIG_ACPI_HOTPLUG_MEMORY + /* Memory Device States */ #define MEMORY_INVALID_STATE 0 #define MEMORY_POWER_ON_STATE 1 @@ -53,11 +60,6 @@ static int acpi_memory_device_add(struct acpi_device *device, const struct acpi_device_id *not_used); static void acpi_memory_device_remove(struct acpi_device *device); -static const struct acpi_device_id memory_device_ids[] = { - {ACPI_MEMORY_DEVICE_HID, 0}, - {"", 0}, -}; - static struct acpi_scan_handler memory_device_handler = { .ids = memory_device_ids, .attach = acpi_memory_device_add, @@ -364,9 +366,11 @@ static bool __initdata acpi_no_memhotplug; void __init acpi_memory_hotplug_init(void) { - if (acpi_no_memhotplug) + if (acpi_no_memhotplug) { + memory_device_handler.attach = NULL; + acpi_scan_add_handler(&memory_device_handler); return; - + } acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory"); } @@ -376,3 +380,16 @@ static int __init disable_acpi_memory_hotplug(char *str) return 1; } __setup("acpi_no_memhotplug", disable_acpi_memory_hotplug); + +#else + +static struct acpi_scan_handler memory_device_handler = { + .ids = memory_device_ids, +}; + +void __init acpi_memory_hotplug_init(void) +{ + acpi_scan_add_handler(&memory_device_handler); +} + +#endif /* CONFIG_ACPI_HOTPLUG_MEMORY */ diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index cc93efd22a24..5ad27bf8e4bd 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -33,6 +33,7 @@ void acpi_platform_init(void); void acpi_pnp_init(void); int acpi_sysfs_init(void); void acpi_container_init(void); +void acpi_memory_hotplug_init(void); #ifdef CONFIG_ACPI_DOCK void register_dock_dependent_device(struct acpi_device *adev, acpi_handle dshandle); @@ -44,11 +45,6 @@ static inline void register_dock_dependent_device(struct acpi_device *adev, static inline int dock_notify(struct acpi_device *adev, u32 event) { return -ENODEV; } static inline void acpi_dock_add(struct acpi_device *adev) {} #endif -#ifdef CONFIG_ACPI_HOTPLUG_MEMORY -void acpi_memory_hotplug_init(void); -#else -static inline void acpi_memory_hotplug_init(void) {} -#endif #ifdef CONFIG_X86 void acpi_cmos_rtc_init(void); #else From d6ddaaac8f5c37ad84db3e6e019981f392389cf0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 May 2014 14:34:05 +0200 Subject: [PATCH 120/134] ACPI / scan: always register ACPI LPSS scan handler Prevent platform devices from being created for ACPI LPSS devices if CONFIG_X86_INTEL_LPSS is unset by compiling out the LPSS scan handler's callbacks only in that case and still compiling its device ID list in and registering the scan handler in either case. This change is based on a prototype from Zhang Rui. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/Makefile | 2 +- drivers/acpi/acpi_lpss.c | 65 +++++++++++++++++++++++++++------------- drivers/acpi/internal.h | 4 --- 3 files changed, 46 insertions(+), 25 deletions(-) diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index f1c9266430d9..ea55e0179f81 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -39,7 +39,7 @@ acpi-y += processor_core.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-y += pci_root.o pci_link.o pci_irq.o -acpi-$(CONFIG_X86_INTEL_LPSS) += acpi_lpss.o +acpi-y += acpi_lpss.o acpi-y += acpi_platform.o acpi-y += acpi_pnp.o acpi-y += power.o diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index db362a96c38e..51069b260518 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -25,6 +25,10 @@ ACPI_MODULE_NAME("acpi_lpss"); +#ifdef CONFIG_X86_INTEL_LPSS + +#define LPSS_ADDR(desc) ((unsigned long)&desc) + #define LPSS_CLK_SIZE 0x04 #define LPSS_LTR_SIZE 0x18 @@ -169,40 +173,48 @@ static struct lpss_device_desc byt_i2c_dev_desc = { .shared_clock = &i2c_clock, }; +#else + +#define LPSS_ADDR(desc) (0UL) + +#endif /* CONFIG_X86_INTEL_LPSS */ + static const struct acpi_device_id acpi_lpss_device_ids[] = { /* Generic LPSS devices */ - { "INTL9C60", (unsigned long)&lpss_dma_desc }, + { "INTL9C60", LPSS_ADDR(lpss_dma_desc) }, /* Lynxpoint LPSS devices */ - { "INT33C0", (unsigned long)&lpt_dev_desc }, - { "INT33C1", (unsigned long)&lpt_dev_desc }, - { "INT33C2", (unsigned long)&lpt_i2c_dev_desc }, - { "INT33C3", (unsigned long)&lpt_i2c_dev_desc }, - { "INT33C4", (unsigned long)&lpt_uart_dev_desc }, - { "INT33C5", (unsigned long)&lpt_uart_dev_desc }, - { "INT33C6", (unsigned long)&lpt_sdio_dev_desc }, + { "INT33C0", LPSS_ADDR(lpt_dev_desc) }, + { "INT33C1", LPSS_ADDR(lpt_dev_desc) }, + { "INT33C2", LPSS_ADDR(lpt_i2c_dev_desc) }, + { "INT33C3", LPSS_ADDR(lpt_i2c_dev_desc) }, + { "INT33C4", LPSS_ADDR(lpt_uart_dev_desc) }, + { "INT33C5", LPSS_ADDR(lpt_uart_dev_desc) }, + { "INT33C6", LPSS_ADDR(lpt_sdio_dev_desc) }, { "INT33C7", }, /* BayTrail LPSS devices */ - { "80860F09", (unsigned long)&byt_pwm_dev_desc }, - { "80860F0A", (unsigned long)&byt_uart_dev_desc }, - { "80860F0E", (unsigned long)&byt_spi_dev_desc }, - { "80860F14", (unsigned long)&byt_sdio_dev_desc }, - { "80860F41", (unsigned long)&byt_i2c_dev_desc }, + { "80860F09", LPSS_ADDR(byt_pwm_dev_desc) }, + { "80860F0A", LPSS_ADDR(byt_uart_dev_desc) }, + { "80860F0E", LPSS_ADDR(byt_spi_dev_desc) }, + { "80860F14", LPSS_ADDR(byt_sdio_dev_desc) }, + { "80860F41", LPSS_ADDR(byt_i2c_dev_desc) }, { "INT33B2", }, - { "INT3430", (unsigned long)&lpt_dev_desc }, - { "INT3431", (unsigned long)&lpt_dev_desc }, - { "INT3432", (unsigned long)&lpt_i2c_dev_desc }, - { "INT3433", (unsigned long)&lpt_i2c_dev_desc }, - { "INT3434", (unsigned long)&lpt_uart_dev_desc }, - { "INT3435", (unsigned long)&lpt_uart_dev_desc }, - { "INT3436", (unsigned long)&lpt_sdio_dev_desc }, + { "INT3430", LPSS_ADDR(lpt_dev_desc) }, + { "INT3431", LPSS_ADDR(lpt_dev_desc) }, + { "INT3432", LPSS_ADDR(lpt_i2c_dev_desc) }, + { "INT3433", LPSS_ADDR(lpt_i2c_dev_desc) }, + { "INT3434", LPSS_ADDR(lpt_uart_dev_desc) }, + { "INT3435", LPSS_ADDR(lpt_uart_dev_desc) }, + { "INT3436", LPSS_ADDR(lpt_sdio_dev_desc) }, { "INT3437", }, { } }; +#ifdef CONFIG_X86_INTEL_LPSS + static int is_memory(struct acpi_resource *res, void *not_used) { struct resource r; @@ -695,3 +707,16 @@ void __init acpi_lpss_init(void) acpi_scan_add_handler(&lpss_handler); } } + +#else + +static struct acpi_scan_handler lpss_handler = { + .ids = acpi_lpss_device_ids, +}; + +void __init acpi_lpss_init(void) +{ + acpi_scan_add_handler(&lpss_handler); +} + +#endif /* CONFIG_X86_INTEL_LPSS */ diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 5ad27bf8e4bd..7de5b603f272 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -65,11 +65,7 @@ int acpi_debugfs_init(void); #else static inline void acpi_debugfs_init(void) { return; } #endif -#ifdef CONFIG_X86_INTEL_LPSS void acpi_lpss_init(void); -#else -static inline void acpi_lpss_init(void) {} -#endif acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src); bool acpi_queue_hotplug_work(struct work_struct *work); From 48459340b92b00ae1a75179f168ef20d3e61f264 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Fri, 30 May 2014 14:35:34 +0200 Subject: [PATCH 121/134] ACPI / scan: use platform bus type by default for _HID enumeration Because of the growing demand for enumerating ACPI devices to platform bus, change the code to enumerate ACPI device objects to platform bus by default. Namely, create platform devices for the ACPI device objects that 1. Have pnp.type.platform_id set (device objects with _HID currently). 2. Do not have a scan handler attached. 3. Are not SPI/I2C slave devices (that should be enumerated to the appropriate buses bus by their parent). Signed-off-by: Zhang Rui [rjw: Subject and changelog, rebase and code cleanup] Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/acpi_platform.c | 44 +++++++----------------------------- drivers/acpi/scan.c | 42 +++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 37 deletions(-) diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 3bb89def2292..2bf9082f7523 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -22,25 +22,11 @@ ACPI_MODULE_NAME("platform"); -/* - * The following ACPI IDs are known to be suitable for representing as - * platform devices. - */ -static const struct acpi_device_id acpi_platform_device_ids[] = { - - { "PNP0D40" }, - { "VPC2004" }, - { "BCM4752" }, - { "LNV4752" }, - { "BCM2E1A" }, - { "BCM2E39" }, - { "BCM2E3D" }, - - /* Intel Smart Sound Technology */ - { "INT33C8" }, - { "80860F28" }, - - { } +static const struct acpi_device_id forbidden_id_list[] = { + {"PNP0000", 0}, /* PIC */ + {"PNP0100", 0}, /* Timer */ + {"PNP0200", 0}, /* AT DMA Controller */ + {"", 0}, }; /** @@ -67,6 +53,9 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) if (adev->physical_node_count) return NULL; + if (!acpi_match_device_ids(adev, forbidden_id_list)) + return ERR_PTR(-EINVAL); + INIT_LIST_HEAD(&resource_list); count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); if (count < 0) { @@ -124,20 +113,3 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) kfree(resources); return pdev; } - -static int acpi_platform_attach(struct acpi_device *adev, - const struct acpi_device_id *id) -{ - acpi_create_platform_device(adev); - return 1; -} - -static struct acpi_scan_handler platform_handler = { - .ids = acpi_platform_device_ids, - .attach = acpi_platform_attach, -}; - -void __init acpi_platform_init(void) -{ - acpi_scan_add_handler(&platform_handler); -} diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 611bb5db7e57..df49fc8276b9 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2070,6 +2070,44 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, return AE_OK; } +static int acpi_check_spi_i2c_slave(struct acpi_resource *ares, void *data) +{ + bool *is_spi_i2c_slave_p = data; + + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) + return 1; + + /* + * devices that are connected to UART still need to be enumerated to + * platform bus + */ + if (ares->data.common_serial_bus.type != ACPI_RESOURCE_SERIAL_TYPE_UART) + *is_spi_i2c_slave_p = true; + + /* no need to do more checking */ + return -1; +} + +static void acpi_default_enumeration(struct acpi_device *device) +{ + struct list_head resource_list; + bool is_spi_i2c_slave = false; + + if (!device->pnp.type.platform_id || device->handler) + return; + + /* + * Do not enemerate SPI/I2C slaves as they will be enuerated by their + * respective parents. + */ + INIT_LIST_HEAD(&resource_list); + acpi_dev_get_resources(device, &resource_list, acpi_check_spi_i2c_slave, + &is_spi_i2c_slave); + acpi_dev_free_resource_list(&resource_list); + if (!is_spi_i2c_slave) + acpi_create_platform_device(device); +} + static int acpi_scan_attach_handler(struct acpi_device *device) { struct acpi_hardware_id *hwid; @@ -2095,6 +2133,9 @@ static int acpi_scan_attach_handler(struct acpi_device *device) break; } } + if (!ret) + acpi_default_enumeration(device); + return ret; } @@ -2254,7 +2295,6 @@ int __init acpi_scan_init(void) acpi_pci_root_init(); acpi_pci_link_init(); acpi_processor_init(); - acpi_platform_init(); acpi_lpss_init(); acpi_cmos_rtc_init(); acpi_container_init(); From 47d68c7f688c01557cb67dd80eb540e88d7913b6 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Sat, 31 May 2014 08:14:44 +0800 Subject: [PATCH 122/134] ACPICA: Tables: Add mechanism to control early table checksum verification. It is reported that Linux x86 kernel cannot map large tables. The following large SSDT table on such platform fails to pass checksum verification and cannot be installed: ACPI: SSDT 0x00000000B9638018 07A0C4 (v02 INTEL S2600CP 00004000 INTL 20100331) It sounds strange that in the 64-bit virtual memory address space, we cannot map a single ACPI table to do checksum verification. The root cause is: 1. ACPICA doesn't split IO memory mapping and table mapping; 2. Linux x86 OSL implements acpi_os_map_memory() using a size limited fix-map mechanism during early boot stage, which is more suitable for only IO mappings. ACPICA originally only mapped table header for signature validation, and this header mapping is required by OSL override mechanism. There was no checksum verification because we could not map the whole table using this OSL. While the following ACPICA commit enforces checksum verification by mapping the whole table during Linux boot stage and it finally triggers this issue on some platforms: Commit: 86dfc6f339886559d80ee0d4bd20fe5ee90450f0 Subject: ACPICA: Tables: Fix table checksums verification before installation. Before doing further cleanups for the OSL table mapping and override implementation, this patch introduces an option for such OSPMs to temporarily discard the checksum verification feature. It then can be re-enabled easily when the ACPICA and the underlying OSL is ready. This patch also deletes a comment around the limitation of mappings because it is not correct. The limitation is not how many times we can map in the early stage, but the OSL mapping facility may not be suitable for mapping the ACPI tables and thus may complain us the size limitation. The acpi_tb_verify_table() is renamed to acpi_tb_verify_temp_table() due to the work around added, it now only applies to the table descriptor that hasn't been installed and cannot be used in other cases. Lv Zheng. Tested-by: Yuanhan Liu Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/actables.h | 8 ++-- drivers/acpi/acpica/tbdata.c | 67 ++++++++++++++++++++++++++-------- drivers/acpi/acpica/tbinstal.c | 8 ++-- drivers/acpi/acpica/tbutils.c | 4 -- include/acpi/acpixf.h | 9 +++++ 5 files changed, 70 insertions(+), 26 deletions(-) diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index bda9a7eb50c1..f14882788eee 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -69,6 +69,11 @@ acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc); +acpi_status acpi_tb_validate_temp_table(struct acpi_table_desc *table_desc); + +acpi_status +acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, char *signature); + u8 acpi_tb_is_table_loaded(u32 table_index); void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded); @@ -96,9 +101,6 @@ acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc); void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc); -acpi_status -acpi_tb_verify_table(struct acpi_table_desc *table_desc, char *signature); - void acpi_tb_override_table(struct acpi_table_desc *old_table_desc); acpi_status diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index cbe29944dc97..f499c10ceb4a 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -322,7 +322,39 @@ void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc) /****************************************************************************** * - * FUNCTION: acpi_tb_verify_table + * FUNCTION: acpi_tb_validate_temp_table + * + * PARAMETERS: table_desc - Table descriptor + * + * RETURN: Status + * + * DESCRIPTION: This function is called to validate the table, the returned + * table descriptor is in "VALIDATED" state. + * + *****************************************************************************/ + +acpi_status acpi_tb_validate_temp_table(struct acpi_table_desc *table_desc) +{ + + if (!table_desc->pointer && !acpi_gbl_verify_table_checksum) { + /* + * Only validates the header of the table. + * Note that Length contains the size of the mapping after invoking + * this work around, this value is required by + * acpi_tb_release_temp_table(). + * We can do this because in acpi_init_table_descriptor(), the Length + * field of the installed descriptor is filled with the actual + * table length obtaining from the table header. + */ + table_desc->length = sizeof(struct acpi_table_header); + } + + return (acpi_tb_validate_table(table_desc)); +} + +/****************************************************************************** + * + * FUNCTION: acpi_tb_verify_temp_table * * PARAMETERS: table_desc - Table descriptor * signature - Table signature to verify @@ -335,15 +367,15 @@ void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc) *****************************************************************************/ acpi_status -acpi_tb_verify_table(struct acpi_table_desc *table_desc, char *signature) +acpi_tb_verify_temp_table(struct acpi_table_desc * table_desc, char *signature) { acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE(tb_verify_table); + ACPI_FUNCTION_TRACE(tb_verify_temp_table); /* Validate the table */ - status = acpi_tb_validate_table(table_desc); + status = acpi_tb_validate_temp_table(table_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -360,17 +392,22 @@ acpi_tb_verify_table(struct acpi_table_desc *table_desc, char *signature) /* Verify the checksum */ - status = - acpi_tb_verify_checksum(table_desc->pointer, table_desc->length); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, - "%4.4s " ACPI_PRINTF_UINT - " Attempted table install failed", - acpi_ut_valid_acpi_name(table_desc->signature. - ascii) ? table_desc-> - signature.ascii : "????", - ACPI_FORMAT_TO_UINT(table_desc->address))); - goto invalidate_and_exit; + if (acpi_gbl_verify_table_checksum) { + status = + acpi_tb_verify_checksum(table_desc->pointer, + table_desc->length); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, + "%4.4s " ACPI_PRINTF_UINT + " Attempted table install failed", + acpi_ut_valid_acpi_name(table_desc-> + signature. + ascii) ? + table_desc->signature.ascii : "????", + ACPI_FORMAT_TO_UINT(table_desc-> + address))); + goto invalidate_and_exit; + } } return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index d4d6029fef44..755b90c40ddf 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -194,7 +194,7 @@ acpi_tb_install_fixed_table(acpi_physical_address address, /* Validate and verify a table before installation */ - status = acpi_tb_verify_table(&new_table_desc, signature); + status = acpi_tb_verify_temp_table(&new_table_desc, signature); if (ACPI_FAILURE(status)) { goto release_and_exit; } @@ -266,7 +266,7 @@ acpi_tb_install_standard_table(acpi_physical_address address, /* Validate and verify a table before installation */ - status = acpi_tb_verify_table(&new_table_desc, NULL); + status = acpi_tb_verify_temp_table(&new_table_desc, NULL); if (ACPI_FAILURE(status)) { goto release_and_exit; } @@ -424,7 +424,7 @@ void acpi_tb_override_table(struct acpi_table_desc *old_table_desc) /* Validate and verify a table before overriding */ - status = acpi_tb_verify_table(&new_table_desc, NULL); + status = acpi_tb_verify_temp_table(&new_table_desc, NULL); if (ACPI_FAILURE(status)) { return; } @@ -446,7 +446,7 @@ void acpi_tb_override_table(struct acpi_table_desc *old_table_desc) acpi_tb_init_table_descriptor(old_table_desc, new_table_desc.address, new_table_desc.flags, new_table_desc.pointer); - acpi_tb_validate_table(old_table_desc); + acpi_tb_validate_temp_table(old_table_desc); /* Release the temporary table descriptor */ diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index e37a103013a4..6b1ca9991b90 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -395,10 +395,6 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) table_entry += table_entry_size; } - /* - * It is not possible to map more than one entry in some environments, - * so unmap the root table here before mapping other tables - */ acpi_os_unmap_memory(table, length); return_ACPI_STATUS(AE_OK); diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index b5f7132f431f..35b525c19711 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -161,6 +161,15 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_create_osi_method, TRUE); */ ACPI_INIT_GLOBAL(u8, acpi_gbl_use_default_register_widths, TRUE); +/* + * Whether or not to verify the table checksum before installation. Set + * this to TRUE to verify the table checksum before install it to the table + * manager. Note that enabling this option causes errors to happen in some + * OSPMs during early initialization stages. Default behavior is to do such + * verification. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_verify_table_checksum, TRUE); + /* * Optionally enable output from the AML Debug Object. */ From 4fc0a7e889e5540305926e41931cf3bc0a60abb2 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Sat, 31 May 2014 08:15:02 +0800 Subject: [PATCH 123/134] ACPI: Fix x86 regression related to early mapping size limitation The following warning message is triggered: WARNING: CPU: 0 PID: 0 at mm/early_ioremap.c:136 __early_ioremap+0x11f/0x1f2() Modules linked in: CPU: 0 PID: 0 Comm: swapper Not tainted 3.15.0-rc1-00017-g86dfc6f3-dirty #298 Hardware name: Intel Corporation S2600CP/S2600CP, BIOS SE5C600.86B.99.99.x036.091920111209 09/19/2011 0000000000000009 ffffffff81b75c40 ffffffff817c627b 0000000000000000 ffffffff81b75c78 ffffffff81067b5d 000000000000007b 8000000000000563 00000000b96b20dc 0000000000000001 ffffffffff300e0c ffffffff81b75c88 Call Trace: [] dump_stack+0x45/0x56 [] warn_slowpath_common+0x7d/0xa0 [] warn_slowpath_null+0x1a/0x20 [] __early_ioremap+0x11f/0x1f2 [] early_ioremap+0x13/0x15 [] __acpi_map_table+0x13/0x18 [] acpi_os_map_memory+0x26/0x14e [] acpi_tb_acquire_table+0x42/0x70 [] acpi_tb_validate_table+0x27/0x37 [] acpi_tb_verify_table+0x22/0xd8 [] acpi_tb_install_non_fixed_table+0x60/0x1c9 [] acpi_tb_parse_root_table+0x218/0x26a [] ? early_idt_handlers+0x120/0x120 [] acpi_initialize_tables+0x57/0x59 [] acpi_table_init+0x1b/0x99 [] acpi_boot_table_init+0x1e/0x85 [] setup_arch+0x99d/0xcc6 [] ? early_idt_handlers+0x120/0x120 [] start_kernel+0x8b/0x415 [] ? early_idt_handlers+0x120/0x120 [] x86_64_start_reservations+0x2a/0x2c [] x86_64_start_kernel+0x13e/0x14d ---[ end trace 11ae599a1898f4e7 ]--- when installing the following table during early stage: ACPI: SSDT 0x00000000B9638018 07A0C4 (v02 INTEL S2600CP 00004000 INTL 20100331) The regression is caused by the size limitation of the x86 early IO mapping. The root cause is: 1. ACPICA doesn't split IO memory mapping and table mapping; 2. Linux x86 OSL implements acpi_os_map_memory() using a size limited fix-map mechanism during early boot stage, which is more suitable for only IO mappings. This patch fixes this issue by utilizing acpi_gbl_verify_table_checksum to disable the table mapping during early stage and enabling it again for the late stage. In this way, the normal code path is not affected. Then after the code related to the root cause is cleaned up, the early checksum verification can be easily re-enabled. A new boot parameter - acpi_force_table_verification is introduced for the platforms that require the checksum verification to stop loading bad tables. This fix also covers the checksum verification for the table overrides. Now large tables can also be overridden using the initrd override mechanism. Signed-off-by: Lv Zheng Reported-and-tested-by: Yuanhan Liu Signed-off-by: Rafael J. Wysocki --- Documentation/kernel-parameters.txt | 5 +++++ drivers/acpi/bus.c | 3 +++ drivers/acpi/tables.c | 23 +++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 60a278948652..4b7cc1481436 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -214,6 +214,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. unusable. The "log_buf_len" parameter may be useful if you need to capture more output. + acpi_force_table_verification [HW,ACPI] + Enable table checksum verification during early stage. + By default, this is disabled due to x86 early mapping + size limitation. + acpi_irq_balance [HW,ACPI] ACPI will balance active IRQs default in APIC mode diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index cf925c4f36b7..cf0b5ecf55b6 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -466,6 +466,9 @@ void __init acpi_early_init(void) printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION); + /* It's safe to verify table checksums during late stage */ + acpi_gbl_verify_table_checksum = TRUE; + /* enable workarounds, unless strict ACPI spec. compliance */ if (!acpi_strict) acpi_gbl_enable_interpreter_slack = TRUE; diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 21782290df41..05550ba44d32 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -44,6 +44,12 @@ static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata; static int acpi_apic_instance __initdata; +/* + * Disable table checksum verification for the early stage due to the size + * limitation of the current x86 early mapping implementation. + */ +static bool acpi_verify_table_checksum __initdata = false; + void acpi_table_print_madt_entry(struct acpi_subtable_header *header) { if (!header) @@ -333,6 +339,14 @@ int __init acpi_table_init(void) { acpi_status status; + if (acpi_verify_table_checksum) { + pr_info("Early table checksum verification enabled\n"); + acpi_gbl_verify_table_checksum = TRUE; + } else { + pr_info("Early table checksum verification disabled\n"); + acpi_gbl_verify_table_checksum = FALSE; + } + status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); if (ACPI_FAILURE(status)) return -EINVAL; @@ -354,3 +368,12 @@ static int __init acpi_parse_apic_instance(char *str) } early_param("acpi_apic_instance", acpi_parse_apic_instance); + +static int __init acpi_force_table_verification_setup(char *s) +{ + acpi_verify_table_checksum = true; + + return 0; +} + +early_param("acpi_force_table_verification", acpi_force_table_verification_setup); From 057b0a7518e4b8fca26201715996d6d928a62300 Mon Sep 17 00:00:00 2001 From: Niv Yehezkel Date: Sat, 31 May 2014 06:26:01 -0400 Subject: [PATCH 124/134] PM / hibernate: fixed typo in comment Fix a trivial comment typo (s/mam/map) in kernel/power/swap.c. Signed-off-by: Niv Yehezkel Signed-off-by: Rafael J. Wysocki --- kernel/power/swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 8c9a4819f798..aaa3261dea5d 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -567,7 +567,7 @@ static int lzo_compress_threadfn(void *data) /** * save_image_lzo - Save the suspend image data compressed with LZO. - * @handle: Swap mam handle to use for saving the image. + * @handle: Swap map handle to use for saving the image. * @snapshot: Image to read data from. * @nr_to_write: Number of pages to save. */ From adacdf3f2b8e65aa441613cf61c4f598e9042690 Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Thu, 29 May 2014 09:32:22 -0700 Subject: [PATCH 125/134] intel_pstate: Remove C0 tracking Commit fcb6a15c (intel_pstate: Take core C0 time into account for core busy calculation) introduced a regression referenced below. The issue with "lockup" after suspend that this commit was addressing is now dealt with in the suspend path. Fixes: fcb6a15c2e7e (intel_pstate: Take core C0 time into account for core busy calculation) Link: https://bugzilla.kernel.org/show_bug.cgi?id=66581 Link: https://bugzilla.kernel.org/show_bug.cgi?id=75121 Reported-by: Doug Smythies Cc: 3.14+ # 3.14+ Signed-off-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index eab8ccfe6beb..e5735446c7ed 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -59,7 +59,6 @@ struct sample { int32_t core_pct_busy; u64 aperf; u64 mperf; - unsigned long long tsc; int freq; }; @@ -100,7 +99,6 @@ struct cpudata { u64 prev_aperf; u64 prev_mperf; - unsigned long long prev_tsc; struct sample sample; }; @@ -561,46 +559,37 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu, struct sample *sample) { int32_t core_pct; - int32_t c0_pct; core_pct = div_fp(int_tofp((sample->aperf)), int_tofp((sample->mperf))); core_pct = mul_fp(core_pct, int_tofp(100)); FP_ROUNDUP(core_pct); - c0_pct = div_fp(int_tofp(sample->mperf), int_tofp(sample->tsc)); - sample->freq = fp_toint( mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct)); - sample->core_pct_busy = mul_fp(core_pct, c0_pct); + sample->core_pct_busy = core_pct; } static inline void intel_pstate_sample(struct cpudata *cpu) { u64 aperf, mperf; - unsigned long long tsc; rdmsrl(MSR_IA32_APERF, aperf); rdmsrl(MSR_IA32_MPERF, mperf); - tsc = native_read_tsc(); aperf = aperf >> FRAC_BITS; mperf = mperf >> FRAC_BITS; - tsc = tsc >> FRAC_BITS; cpu->sample.aperf = aperf; cpu->sample.mperf = mperf; - cpu->sample.tsc = tsc; cpu->sample.aperf -= cpu->prev_aperf; cpu->sample.mperf -= cpu->prev_mperf; - cpu->sample.tsc -= cpu->prev_tsc; intel_pstate_calc_busy(cpu, &cpu->sample); cpu->prev_aperf = aperf; cpu->prev_mperf = mperf; - cpu->prev_tsc = tsc; } static inline void intel_pstate_set_sample_time(struct cpudata *cpu) From f0fe3cd7e12d8290c82284b5c8aee723cbd0371a Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Thu, 29 May 2014 09:32:23 -0700 Subject: [PATCH 126/134] intel_pstate: Correct rounding in busy calculation Changing to fixed point math throughout the busy calculation in commit e66c1768 (Change busy calculation to use fixed point math.) Introduced some inaccuracies by rounding the busy value at two points in the calculation. This change removes roundings and moves the rounding to the output of the PID where the calculations are complete and the value returned as an integer. Fixes: e66c17683746 (intel_pstate: Change busy calculation to use fixed point math.) Reported-by: Doug Smythies Cc: 3.14+ # 3.14+ Signed-off-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index e5735446c7ed..3d57e53212d6 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -40,10 +40,10 @@ #define BYT_TURBO_VIDS 0x66d -#define FRAC_BITS 6 +#define FRAC_BITS 8 #define int_tofp(X) ((int64_t)(X) << FRAC_BITS) #define fp_toint(X) ((X) >> FRAC_BITS) -#define FP_ROUNDUP(X) ((X) += 1 << FRAC_BITS) + static inline int32_t mul_fp(int32_t x, int32_t y) { @@ -198,7 +198,10 @@ static signed int pid_calc(struct _pid *pid, int32_t busy) pid->last_err = fp_error; result = pterm + mul_fp(pid->integral, pid->i_gain) + dterm; - + if (result >= 0) + result = result + (1 << (FRAC_BITS-1)); + else + result = result - (1 << (FRAC_BITS-1)); return (signed int)fp_toint(result); } @@ -563,7 +566,6 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu, core_pct = div_fp(int_tofp((sample->aperf)), int_tofp((sample->mperf))); core_pct = mul_fp(core_pct, int_tofp(100)); - FP_ROUNDUP(core_pct); sample->freq = fp_toint( mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct)); @@ -609,7 +611,7 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu) max_pstate = int_tofp(cpu->pstate.max_pstate); current_pstate = int_tofp(cpu->pstate.current_pstate); core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate)); - return FP_ROUNDUP(core_busy); + return core_busy; } static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) From c4ee841f602e5eef8eab673295c49c5b49d7732b Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Thu, 29 May 2014 09:32:24 -0700 Subject: [PATCH 127/134] intel_pstate: add sample time scaling The PID assumes that samples are of equal time, which for a deferable timers this is not true when the system goes idle. This causes the PID to take a long time to converge to the min P state and depending on the pattern of the idle load can make the P state appear stuck. The hold-off value of three sample times before using the scaling is to give a grace period for applications that have high performance requirements and spend a lot of time idle, The poster child for this behavior is the ffmpeg benchmark in the Phoronix test suite. Cc: 3.14+ # 3.14+ Signed-off-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 3d57e53212d6..2a07588dcbac 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -60,6 +60,7 @@ struct sample { u64 aperf; u64 mperf; int freq; + ktime_t time; }; struct pstate_data { @@ -97,6 +98,7 @@ struct cpudata { struct vid_data vid; struct _pid pid; + ktime_t last_sample_time; u64 prev_aperf; u64 prev_mperf; struct sample sample; @@ -583,6 +585,8 @@ static inline void intel_pstate_sample(struct cpudata *cpu) aperf = aperf >> FRAC_BITS; mperf = mperf >> FRAC_BITS; + cpu->last_sample_time = cpu->sample.time; + cpu->sample.time = ktime_get(); cpu->sample.aperf = aperf; cpu->sample.mperf = mperf; cpu->sample.aperf -= cpu->prev_aperf; @@ -605,12 +609,24 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu) static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu) { - int32_t core_busy, max_pstate, current_pstate; + int32_t core_busy, max_pstate, current_pstate, sample_ratio; + u32 duration_us; + u32 sample_time; core_busy = cpu->sample.core_pct_busy; max_pstate = int_tofp(cpu->pstate.max_pstate); current_pstate = int_tofp(cpu->pstate.current_pstate); core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate)); + + sample_time = (pid_params.sample_rate_ms * USEC_PER_MSEC); + duration_us = (u32) ktime_us_delta(cpu->sample.time, + cpu->last_sample_time); + if (duration_us > sample_time * 3) { + sample_ratio = div_fp(int_tofp(sample_time), + int_tofp(duration_us)); + core_busy = mul_fp(core_busy, sample_ratio); + } + return core_busy; } From bf8102228a8bf053051f311e5486042fe0542894 Mon Sep 17 00:00:00 2001 From: Doug Smythies Date: Fri, 30 May 2014 10:10:57 -0700 Subject: [PATCH 128/134] intel_pstate: Improve initial busy calculation This change makes the busy calculation using 64 bit math which prevents overflow for large values of aperf/mperf. Cc: 3.14+ # 3.14+ Signed-off-by: Doug Smythies Signed-off-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 2a07588dcbac..db2e45b4808e 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -563,16 +563,19 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) static inline void intel_pstate_calc_busy(struct cpudata *cpu, struct sample *sample) { - int32_t core_pct; + int64_t core_pct; + int32_t rem; - core_pct = div_fp(int_tofp((sample->aperf)), - int_tofp((sample->mperf))); - core_pct = mul_fp(core_pct, int_tofp(100)); + core_pct = int_tofp(sample->aperf) * int_tofp(100); + core_pct = div_u64_rem(core_pct, int_tofp(sample->mperf), &rem); + + if ((rem << 1) >= int_tofp(sample->mperf)) + core_pct += 1; sample->freq = fp_toint( mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct)); - sample->core_pct_busy = core_pct; + sample->core_pct_busy = (int32_t)core_pct; } static inline void intel_pstate_sample(struct cpudata *cpu) From 729ddb657f6a47a2cb6e495f1ff68fff622c758a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 3 Jun 2014 13:20:32 +0800 Subject: [PATCH 129/134] ACPICA: Namespace: Remove _PRP method support. The _PRP method is not going to be a part of the ACPI standard. This patch removes its support code introduced by the following commits: 1. ACPICA: Predefined names: Add support for the _PRP method. 2. ACPICA: Update for _PRP predefined name. 3. ACPICA: Add support for _LPD and _PRP methods. 4. ACPICA: Back port of _PRP update. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acpredef.h | 6 ------ include/acpi/acnames.h | 1 - 2 files changed, 7 deletions(-) diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index 34001a9fd098..bd08817cafd8 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -702,12 +702,6 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = { METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), - {{"_PRP", METHOD_0ARGS, - METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: 1 Str, 1 Int/Str/Pkg */ - PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_STRING, 1, - ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | - ACPI_RTYPE_PACKAGE | ACPI_RTYPE_REFERENCE, 1, 0), - {{"_PRS", METHOD_0ARGS, METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h index f0e713fadb1f..3dd6e838dc30 100644 --- a/include/acpi/acnames.h +++ b/include/acpi/acnames.h @@ -55,7 +55,6 @@ #define METHOD_NAME__HID "_HID" #define METHOD_NAME__INI "_INI" #define METHOD_NAME__PLD "_PLD" -#define METHOD_NAME__PRP "_PRP" #define METHOD_NAME__PRS "_PRS" #define METHOD_NAME__PRT "_PRT" #define METHOD_NAME__PRW "_PRW" From 85e90679335f56d162f4a0ff525573818e17ce44 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Thu, 12 Jun 2014 08:35:44 -0700 Subject: [PATCH 130/134] drm/i915: disable power wells on suspend We want to make sure everything is disabled and at its lowest power when freezing. Reviewed-by: Imre Deak Signed-off-by: Kristen Carlson Accardi Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 651e65e051c0..458b778cd495 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -557,6 +557,8 @@ static int i915_drm_freeze(struct drm_device *dev) dev_priv->suspend_count++; + intel_display_set_init_power(dev_priv, false); + return 0; } From 156c7ca08185886329113f20249446af4fb07f60 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 12 Jun 2014 08:35:45 -0700 Subject: [PATCH 131/134] drm/i915: leave rc6 enabled at suspend time v4 This allows the system to enter the lowest power mode during system freeze. v2: delete force wake timer at suspend (Imre) v3: add GT work suspend function (Imre) v4: use uncore forcewake reset (Daniel) Reviewed-by: Imre Deak Signed-off-by: Kristen Carlson Accardi Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 4 ++-- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 20 ++++++++++++++++++++ drivers/gpu/drm/i915/intel_uncore.c | 2 +- 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 458b778cd495..704dfe36c2ed 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -529,7 +529,7 @@ static int i915_drm_freeze(struct drm_device *dev) drm_irq_uninstall(dev); dev_priv->enable_hotplug_processing = false; - intel_disable_gt_powersave(dev); + intel_suspend_gt_powersave(dev); /* * Disable CRTCs directly since we want to preserve sw state @@ -548,8 +548,8 @@ static int i915_drm_freeze(struct drm_device *dev) i915_save_state(dev); + intel_uncore_forcewake_reset(dev, false); intel_opregion_fini(dev); - intel_uncore_fini(dev); console_lock(); intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 49414d30e8d4..be4cd5e96533 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2085,6 +2085,7 @@ extern void intel_uncore_early_sanitize(struct drm_device *dev); extern void intel_uncore_init(struct drm_device *dev); extern void intel_uncore_check_errors(struct drm_device *dev); extern void intel_uncore_fini(struct drm_device *dev); +extern void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore); void i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bda0ae3d80cc..a23b83d3bc05 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -961,6 +961,7 @@ void intel_init_gt_powersave(struct drm_device *dev); void intel_cleanup_gt_powersave(struct drm_device *dev); void intel_enable_gt_powersave(struct drm_device *dev); void intel_disable_gt_powersave(struct drm_device *dev); +void intel_suspend_gt_powersave(struct drm_device *dev); void intel_reset_gt_powersave(struct drm_device *dev); void ironlake_teardown_rc6(struct drm_device *dev); void gen6_update_ring_freq(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d1e53abec1b5..685b4910eb93 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4675,6 +4675,26 @@ void intel_cleanup_gt_powersave(struct drm_device *dev) valleyview_cleanup_gt_powersave(dev); } +/** + * intel_suspend_gt_powersave - suspend PM work and helper threads + * @dev: drm device + * + * We don't want to disable RC6 or other features here, we just want + * to make sure any work we've queued has finished and won't bother + * us while we're suspended. + */ +void intel_suspend_gt_powersave(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Interrupts should be disabled already to avoid re-arming. */ + WARN_ON(dev->irq_enabled); + + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + + cancel_work_sync(&dev_priv->rps.work); +} + void intel_disable_gt_powersave(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 79cba593df0d..53e13ae6126c 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -315,7 +315,7 @@ static void gen6_force_wake_timer(unsigned long arg) intel_runtime_pm_put(dev_priv); } -static void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore) +void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; From 10d8d366790ff8da28c1853b2c795f3a74a4fdaa Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 12 Jun 2014 17:48:52 +0200 Subject: [PATCH 132/134] drm/i915: Unifiy GT powersave suspend logic Jesse's patch to only quiescent our rps work and Imre's fix to address a race with runtime pm and the forcewake reference held by the used diverging means to address the same bug: Jesse's patch uses flush_delayed_work while (since we want to make sure rps is set up) while Imre's used a cancel+manuel refcount adjustment. Unify them again by simply reusing intel_suspend_gt_powersave in intel_disable_gt_powersave. Cc: Imre Deak Cc: Jesse Barnes Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 685b4910eb93..49122204a001 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4706,10 +4706,8 @@ void intel_disable_gt_powersave(struct drm_device *dev) ironlake_disable_drps(dev); ironlake_disable_rc6(dev); } else if (IS_GEN6(dev) || IS_GEN7(dev) || IS_BROADWELL(dev)) { - if (cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work)) - intel_runtime_pm_put(dev_priv); + intel_suspend_gt_powersave(dev); - cancel_work_sync(&dev_priv->rps.work); mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev)) valleyview_disable_rps(dev); From e5747e3adcd67ae27105003ec99fb58cba180105 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 12 Jun 2014 08:35:47 -0700 Subject: [PATCH 133/134] drm/i915: send proper opregion notifications on suspend/resume This indicates to the firmware that it can power down various other components or bring them back up, depending on the target system state. Reviewed-by: Imre Deak Signed-off-by: Kristen Carlson Accardi Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 704dfe36c2ed..43b804357bcf 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -28,6 +28,7 @@ */ #include +#include #include #include #include "i915_drv.h" @@ -499,6 +500,7 @@ static int i915_drm_freeze(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; + pci_power_t opregion_target_state; intel_runtime_pm_get(dev_priv); @@ -548,6 +550,12 @@ static int i915_drm_freeze(struct drm_device *dev) i915_save_state(dev); + if (acpi_target_system_state() >= ACPI_STATE_S3) + opregion_target_state = PCI_D3cold; + else + opregion_target_state = PCI_D1; + intel_opregion_notify_adapter(dev, opregion_target_state); + intel_uncore_forcewake_reset(dev, false); intel_opregion_fini(dev); @@ -680,6 +688,8 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) dev_priv->modeset_restore = MODESET_DONE; mutex_unlock(&dev_priv->modeset_restore_lock); + intel_opregion_notify_adapter(dev, PCI_D0); + intel_runtime_pm_put(dev_priv); return 0; } From 8abdc17941c71b37311bb93876ac83dce58160c8 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Thu, 12 Jun 2014 08:35:48 -0700 Subject: [PATCH 134/134] drm/i915: make sure PC8 is enabled on suspend and disabled on resume v4 This matches the runtime suspend paths and allows the system to enter the lowest power mode at freeze time. v2: move disable_pc8 call to thaw_early (Imre) move enable_pc8 to freeze_late (Imre/Jesse) v3: drop spurious hunk from _freeze now that we have freeze_late (Jesse) v4: move back to suspend_late (Imre was right) Reviewed-by: Imre Deak Signed-off-by: Kristen Carlson Accardi Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 43b804357bcf..3536bfe537dd 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -616,6 +616,9 @@ static int i915_drm_thaw_early(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + hsw_disable_pc8(dev_priv); + intel_uncore_early_sanitize(dev); intel_uncore_sanitize(dev); intel_power_domains_init_hw(dev_priv); @@ -899,6 +902,7 @@ static int i915_pm_suspend_late(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_i915_private *dev_priv = drm_dev->dev_private; /* * We have a suspedn ordering issue with the snd-hda driver also @@ -912,6 +916,9 @@ static int i915_pm_suspend_late(struct device *dev) if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; + if (IS_HASWELL(drm_dev) || IS_BROADWELL(drm_dev)) + hsw_enable_pc8(dev_priv); + pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot);