From 1d44efab14ed537d7c9585c110ce4c103ced336f Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:36:47 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 @@ exit: return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_install_sci_handler) + /******************************************************************************* * * FUNCTION: acpi_remove_sci_handler @@ -468,7 +470,6 @@ exit: * 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 @@ unlock_and_exit: return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_remove_sci_handler) + /******************************************************************************* * * FUNCTION: acpi_install_global_event_handler @@ -537,7 +540,6 @@ unlock_and_exit: * Can be used to update event counters, etc. * ******************************************************************************/ - acpi_status acpi_install_global_event_handler(acpi_gbl_event_handler handler, void *context) { -- cgit v1.2.3 From 5d42b0fa25df7ef2f575107597c1aaebe2407d10 Mon Sep 17 00:00:00 2001 From: David Binderman Date: Fri, 4 Apr 2014 12:36:55 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 */ -- cgit v1.2.3 From 6085bb18afa431823a6287a0aa4d13641acb658d Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:37:11 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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. */ -- cgit v1.2.3 From 43d1a62d651233fe4d28f7d9e8f9c13d2a1ad1bc Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:37:26 +0800 Subject: 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(+) (limited to 'drivers/acpi') 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() -- cgit v1.2.3 From b944b29c90a18d6254fca4a018195adc8802cf2e Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:37:35 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 */ -- cgit v1.2.3 From 06a63e33f32fd6b68cc78fd88f294d0fee6b889a Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:37:44 +0800 Subject: 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 | 74 +++++++++++++++++++++++++++++++++++------- 3 files changed, 66 insertions(+), 14 deletions(-) (limited to 'drivers/acpi') 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 (acpi_gbl_generic_notify[notify_value]); + } + + /* 0D - 7F are reserved */ + + 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"); } + + /* 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 -- cgit v1.2.3 From 69c841b6dd8313c9a673246cc0e2535174272cab Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:37:51 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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); -- cgit v1.2.3 From 0745fb41c3c8ab3c472c8195baed1e5098b44e09 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:38:12 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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"}, -- cgit v1.2.3 From 5582982d1acefe37528a3de8b42e81a7b0a75cfb Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:38:18 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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; -- cgit v1.2.3 From dc156adf0d1b9d9ea54a86ca803ac5202ab139c7 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:38:26 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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; -- cgit v1.2.3 From 55df23f0d620c5194ecbd3b68ecdb2798778bf93 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:38:35 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 = -- cgit v1.2.3 From 7f9fc99cde939187c1ee6dac115bdb76655cc798 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:38:42 +0800 Subject: 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 | 299 ++++++++++++++++++++++++++++------------- drivers/acpi/acpica/tbutils.c | 11 +- drivers/acpi/acpica/tbxface.c | 6 +- drivers/acpi/acpica/tbxfload.c | 6 +- 6 files changed, 235 insertions(+), 108 deletions(-) (limited to 'drivers/acpi') 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_verify_table(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) { - acpi_status status = AE_OK; + struct acpi_table_header *table = NULL; - ACPI_FUNCTION_TRACE(tb_verify_table); + switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_MAPPED: - /* Map the table if necessary */ + table = + acpi_os_map_memory(table_desc->address, table_desc->length); + break; - if (!table_desc->pointer) { - switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { - case ACPI_TABLE_ORIGIN_MAPPED: + case ACPI_TABLE_ORIGIN_ALLOCATED: + case ACPI_TABLE_ORIGIN_UNKNOWN: + case ACPI_TABLE_ORIGIN_OVERRIDE: - table_desc->pointer = - acpi_os_map_memory(table_desc->address, - table_desc->length); - break; + table = + ACPI_CAST_PTR(struct acpi_table_header, + table_desc->address); + break; - case ACPI_TABLE_ORIGIN_ALLOCATED: - case ACPI_TABLE_ORIGIN_UNKNOWN: - case ACPI_TABLE_ORIGIN_OVERRIDE: + default: - table_desc->pointer = - ACPI_CAST_PTR(struct acpi_table_header, - table_desc->address); - break; + break; + } - default: + /* Table is not valid yet */ - break; - } + 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_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) { + 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 @@ release: /******************************************************************************* * - * 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 @@ release: * * 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 */ - - if (!table_desc->pointer) { - return; - } - - switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { - case ACPI_TABLE_ORIGIN_MAPPED: - - acpi_os_unmap_memory(table_desc->pointer, table_desc->length); - break; - - case ACPI_TABLE_ORIGIN_ALLOCATED: + ACPI_FUNCTION_TRACE(tb_uninstall_table); - ACPI_FREE(table_desc->pointer); - table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL); - break; + /* Table must be installed */ - /* Not mapped or allocated, there is nothing we can do */ + if (!table_desc->address) { + return_VOID; + } - default: + acpi_tb_invalidate_table(table_desc); - 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; } -- cgit v1.2.3 From eb0c65bd2c276b4b346db545d938d4113e1a4e9c Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:38:50 +0800 Subject: 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(+) (limited to 'drivers/acpi') 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); } } -- cgit v1.2.3 From 86dfc6f339886559d80ee0d4bd20fe5ee90450f0 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:38:57 +0800 Subject: 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 | 708 ++++++++++++++++++++++++++++++----------- drivers/acpi/acpica/tbutils.c | 173 ++-------- drivers/acpi/acpica/tbxfload.c | 26 +- 6 files changed, 607 insertions(+), 409 deletions(-) (limited to 'drivers/acpi') 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_add_table(struct acpi_table_desc *table_desc, u32 *table_index) +acpi_tb_verify_table(struct acpi_table_desc *table_desc, char *signature) { - u32 i; acpi_status status = AE_OK; - struct acpi_table_header *final_table; - ACPI_FUNCTION_TRACE(tb_add_table); + ACPI_FUNCTION_TRACE(tb_verify_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 table */ + + status = acpi_tb_validate_table(table_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(AE_NO_MEMORY); } - /* - * 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 ((table_desc->pointer->signature[0] != 0x00) && - (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)) - && (ACPI_STRNCMP(table_desc->pointer->signature, "OEM", 3))) { + /* 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, - "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)); + "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 */ - return_ACPI_STATUS(AE_BAD_SIGNATURE); + 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; } - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(AE_OK); - /* Check if table is already registered */ +invalidate_and_exit: + acpi_tb_invalidate_table(table_desc); + return_ACPI_STATUS(status); +} - 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_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. + * + ******************************************************************************/ - /* - * 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; +void +acpi_tb_install_table(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 + * 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_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); - if (ACPI_MEMCMP(table_desc->pointer, - acpi_gbl_root_table_list.tables[i].pointer, - acpi_gbl_root_table_list.tables[i].length)) { - continue; + 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); - /* - * 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; + default: - if (acpi_gbl_root_table_list.tables[i]. - flags & ACPI_TABLE_IS_LOADED) { + break; + } - /* Table is still loaded, this is an error */ + /* Table is not valid yet */ - 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; - } + return (AE_NO_MEMORY); +} + +/******************************************************************************* + * + * 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(). + * + ******************************************************************************/ + +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); +} + +/******************************************************************************* + * + * 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. + * + ******************************************************************************/ + +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); + + acpi_tb_install_table(&acpi_gbl_root_table_list.tables[table_index], + new_table_desc->address, new_table_desc->flags, + new_table_desc->pointer); - /* Ensure table descriptor is in "VALIDATED" state */ + acpi_tb_print_table_header(new_table_desc->address, + new_table_desc->pointer); - table_desc->pointer = 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(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 @@ release: * * 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); } /******************************************************************************* @@ -526,26 +836,19 @@ acpi_status acpi_tb_resize_root_table_list(void) /******************************************************************************* * - * FUNCTION: acpi_tb_store_table + * FUNCTION: acpi_tb_acquire_root_table_entry * - * PARAMETERS: address - Table address - * table - Table header - * length - Table length - * flags - flags + * PARAMETERS: table_index - Where table index is returned * * RETURN: Status and table index. * - * DESCRIPTION: Add an ACPI table to the global table list + * DESCRIPTION: Allocate a new ACPI table entry to the global table list * ******************************************************************************/ -acpi_status -acpi_tb_store_table(acpi_physical_address address, - struct acpi_table_header *table, - u32 length, u8 flags, u32 *table_index) +static acpi_status acpi_tb_acquire_root_table_entry(u32 *table_index) { acpi_status status; - struct acpi_table_desc *new_table; /* Ensure that there is room for the table in the Root Table List */ @@ -557,22 +860,45 @@ acpi_tb_store_table(acpi_physical_address address, } } - new_table = - &acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list. - current_table_count]; + *table_index = acpi_gbl_root_table_list.current_table_count; + acpi_gbl_root_table_list.current_table_count++; + return (AE_OK); +} - /* Initialize added table */ +/******************************************************************************* + * + * FUNCTION: acpi_tb_store_table + * + * PARAMETERS: address - Table address + * table - Table header + * length - Table length + * flags - flags + * + * RETURN: Status and table index. + * + * DESCRIPTION: Add an ACPI table to the global table list + * + ******************************************************************************/ + +acpi_status +acpi_tb_store_table(acpi_physical_address address, + struct acpi_table_header * table, + u32 length, u8 flags, u32 *table_index) +{ + acpi_status status; + struct acpi_table_desc *table_desc; + + status = acpi_tb_acquire_root_table_entry(table_index); + if (ACPI_FAILURE(status)) { + return (status); + } - new_table->address = address; - new_table->pointer = table; - new_table->length = length; - new_table->owner_id = 0; - new_table->flags = flags; + /* Initialize added table */ - ACPI_MOVE_32_TO_32(&new_table->signature, table->signature); + table_desc = &acpi_gbl_root_table_list.tables[*table_index]; + acpi_tb_install_table(table_desc, address, flags, table); + table_desc->pointer = table; - *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 @@ unlock_and_exit: 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; } -- cgit v1.2.3 From 8a216d7f6aa94c3e252bbfdb2c422e2d0380084e Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:39:04 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 -- cgit v1.2.3 From a94e88cdd8057fe8ea84bbb6d9a89a823c7bc49b Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:39:11 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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; -- cgit v1.2.3 From caf4a15c5f930aae41951b4916289e3e59dda8eb Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:39:18 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 @@ unlock_and_exit: 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 @@ unlock_and_exit: * 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); -- cgit v1.2.3 From ed6f1d44dae8a4eec42a74acae95cc177ee2e1ad Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:39:26 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 @@ invalidate_and_exit: /******************************************************************************* * - * 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 @@ invalidate_and_exit: * * 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 @@ finish_override: * 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) -- cgit v1.2.3 From c418ce19030f8cd9304b4e97c8e0dd580a81ace5 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 4 Apr 2014 12:39:34 +0800 Subject: 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 | 738 ++--------------------------------------- 4 files changed, 771 insertions(+), 720 deletions(-) create mode 100644 drivers/acpi/acpica/tbdata.c (limited to 'drivers/acpi') 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 void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc); - -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, - 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_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); -} +acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index); /******************************************************************************* * - * FUNCTION: acpi_tb_invalidate_table + * FUNCTION: acpi_tb_compare_tables * - * PARAMETERS: table_desc - Table descriptor + * PARAMETERS: table_desc - Table 1 descriptor to be compared + * table_index - Index of table 2 to be compared * - * RETURN: None + * RETURN: TRUE if both tables are identical. * - * DESCRIPTION: Invalidate one internal ACPI table, this is the inverse of - * acpi_tb_validate_table(). + * DESCRIPTION: This function compares a table with another table that has + * already been installed in the root table list. * ******************************************************************************/ -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) +static u8 +acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index) { 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); -} - -/******************************************************************************* - * - * 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. - * - ******************************************************************************/ - -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: + is_identical = (u8)((table_desc->length != table_length || + ACPI_MEMCMP(table_desc->pointer, table, + table_length)) ? FALSE : TRUE); - 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) -{ + /* Release the acquired table */ - /* - * 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 @@ release_and_exit: 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 @@ finish_override: 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); -} -- cgit v1.2.3 From 506f57dd6dfdb1d73cb77106706cd5b8953b453d Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:39:42 +0800 Subject: 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 ++++ .../acpi/os_specific/service_layers/oslinuxtbl.c | 1275 ++++++++++++++++++++ .../acpi/os_specific/service_layers/osunixdir.c | 204 ++++ .../acpi/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 (limited to 'drivers/acpi') 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); +} -- cgit v1.2.3 From e2b9035f7368b8141e8c9f1d0bcc012e20e16ac1 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 4 Apr 2014 12:39:50 +0800 Subject: 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 (limited to 'drivers/acpi') 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); +} -- cgit v1.2.3 From 2650ef42636848db858625bd933131e8835f8d23 Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Mon, 28 Apr 2014 10:38:04 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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(); -- cgit v1.2.3 From 5b59c69ec54849f23b51d18b0a609c4f793bc35a Mon Sep 17 00:00:00 2001 From: Tony Camuso Date: Fri, 25 Apr 2014 14:19:29 -0400 Subject: 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(-) (limited to 'drivers/acpi') 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); -- cgit v1.2.3 From 7bb516fbd1b54856ef51a43736ba18fdcdeadfed Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:03:33 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 */ /***************************************************************************** -- cgit v1.2.3 From fad6449b4a96d7d7e61ebdfd16fd3a80833526bf Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:03:39 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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); } -- cgit v1.2.3 From 3035ff70e6e6e15351e865fcc69dff182103b115 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:03:52 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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); - -/* - * 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); +/* Master list of all ACPI tables that were found in the RSDT/XSDT */ -/* - * 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 -- cgit v1.2.3 From 51e35823eb57621b1b2ed39790d539620617b4a3 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 30 Apr 2014 10:03:58 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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; -- cgit v1.2.3 From 92cb3a8d37b96f6aeee9ebe5336dd8a8e67580a4 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 30 Apr 2014 10:04:13 +0800 Subject: 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(+) (limited to 'drivers/acpi') 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)}}, -- cgit v1.2.3 From c28fa24b97789bd61b09014380a2eb71a522090a Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Wed, 30 Apr 2014 10:04:20 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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); - } - /* Always delete the list */ + /* Delete the list */ + + acpi_hw_delete_pci_list(list_head); + } - 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); } -- cgit v1.2.3 From 3a2f3a3383f87412fa11b89290d592a24f618487 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:04:35 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 */ - -extern u32 acpi_dbg_level; -extern u32 acpi_dbg_layer; +/* + * 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); -/* ACPICA runtime options */ +/* + * 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); -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 -- cgit v1.2.3 From 407e22afcf0701ec5543f39934c43b10082a1a97 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:04:48 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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, -- cgit v1.2.3 From 0f929fbf0dc6ed21829a9fcd495838858df82291 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:05:56 +0800 Subject: 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 +++++++++++++++------ .../acpi/os_specific/service_layers/oslinuxtbl.c | 12 ++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) (limited to 'drivers/acpi') 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)) { -- cgit v1.2.3 From 57429a403eeaf4fe63e1a6956e3f57a673cfcd73 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 30 Apr 2014 10:06:02 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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)); -- cgit v1.2.3 From 21126b296e6f5f172e72da7cebb42b87fbd19b3a Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 30 Apr 2014 10:06:09 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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); } } } -- cgit v1.2.3 From 7505da4c3f90dd61302e825b005d08144c5de050 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 30 Apr 2014 10:06:15 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 @@ error_exit: 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; } -- cgit v1.2.3 From d0103387bc21644d297cb61ee623c7114e395575 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 1 May 2014 01:16:06 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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; -- cgit v1.2.3 From 886129a8eebebec260165741fe31421482371006 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 6 May 2014 14:46:23 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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); /* -- cgit v1.2.3 From fad16dd9c962229c5965ec6f5cd5f48180f94fd4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 8 May 2014 23:22:15 +0200 Subject: 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(+) (limited to 'drivers/acpi') 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; -- cgit v1.2.3 From 1f0b63866fc1be700260547be8edf8e6f0af37f2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 15 May 2014 23:29:57 +0200 Subject: 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(+) (limited to 'drivers/acpi') 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; -- cgit v1.2.3 From 99678ed73a50d2df8b5f3c801e29e9b7a3e5aa85 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 15 May 2014 13:22:33 +0200 Subject: 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 | 139 +++++++++++++++++++++++++++------------------------ 1 file changed, 74 insertions(+), 65 deletions(-) (limited to 'drivers/acpi') 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; - - result = acpi_video_init_brightness(device); - if (result) - return; - name = kasprintf(GFP_KERNEL, "acpi_video%d", count); - if (!name) - return; - count++; + struct backlight_properties props; + struct pci_dev *pdev; + acpi_handle acpi_parent; + struct device *parent = NULL; + int result; + static int count; + char *name; - acpi_get_parent(device->dev->handle, &acpi_parent); + result = acpi_video_init_brightness(device); + if (result) + return; + name = kasprintf(GFP_KERNEL, "acpi_video%d", count); + if (!name) + return; + count++; - pdev = acpi_get_pci_dev(acpi_parent); - if (pdev) { - parent = &pdev->dev; - pci_dev_put(pdev); - } + acpi_get_parent(device->dev->handle, &acpi_parent); - 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; + pdev = acpi_get_pci_dev(acpi_parent); + if (pdev) { + parent = &pdev->dev; + pci_dev_put(pdev); + } - /* - * 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); + 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; - 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; - } + /* + * 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); - 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"); + 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; } -- cgit v1.2.3 From c401eb8ee374a5fc2b56042c0072ce51a0beb0dc Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Mon, 5 May 2014 12:48:26 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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)) -- cgit v1.2.3 From a3cffce4fbafac072660648e028cc9e629b5b3c8 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 8 May 2014 14:59:04 +0300 Subject: 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(+) (limited to 'drivers/acpi') 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" }, -- cgit v1.2.3 From 9e50bc14a7f58b5d8a55973b2d69355852ae2dae Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Sun, 4 May 2014 14:07:06 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 -- cgit v1.2.3 From 8da8373447d6a57a5a9f55233d35beb15d92d0d2 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Thu, 8 May 2014 07:58:59 -0600 Subject: 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(+) (limited to 'drivers/acpi') 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; -- cgit v1.2.3 From 73577d1df8e1f31f6b1a5eebcdbc334eb0330e47 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 12 May 2014 15:50:16 +0800 Subject: 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(+) (limited to 'drivers/acpi') 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 = { /* -- cgit v1.2.3 From f25c0ae2b4c41996c1a6b609132c1788a6eea080 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 17 May 2014 00:18:13 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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; + + 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; - return pm_generic_prepare(dev); + 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 { -- cgit v1.2.3 From 4cf563c5d97c83d4b2fb3a778dd7d5e362cc3e34 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 15 May 2014 16:40:23 +0300 Subject: 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(-) (limited to 'drivers/acpi') 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) -- cgit v1.2.3 From 1b7f37e1276bee9043d35a4b39ef2f43d3b2e133 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 17 May 2014 10:48:01 +0200 Subject: 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(+) (limited to 'drivers/acpi') 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) { -- cgit v1.2.3 From 8ce62f85a81f57e86bc120ab690facc612223188 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 25 May 2014 14:38:52 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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 -- cgit v1.2.3 From c78b0830667a7e7c1f0ca65b76b33166a84806b3 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Fri, 23 May 2014 16:15:09 +0300 Subject: 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(-) (limited to 'drivers/acpi') 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 = { -- cgit v1.2.3 From ed3a872e2ef62bde06e2f579d8d1458766ced078 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 19 May 2014 14:42:07 +0300 Subject: 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(-) (limited to 'drivers/acpi') 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; } -- cgit v1.2.3 From 45fef5b88d1f2f47ecdefae6354372d440ca5c84 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Thu, 22 May 2014 12:47:47 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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*/ -- cgit v1.2.3 From 72013795a73f8536d3346fa90379c987bcad0cc8 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Tue, 20 May 2014 20:59:21 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 *); -- cgit v1.2.3 From e6f8a4d60b905eae1a20cbb0c72c67b26b2f02fd Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Tue, 20 May 2014 20:59:22 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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); } -- cgit v1.2.3 From 53a92ba7e3762154df01c4f4f5d871df0587c96b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 21 May 2014 15:39:55 +0200 Subject: 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(+) (limited to 'drivers/acpi') 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); -- cgit v1.2.3 From 1e815db647ada5f169dc0201b96530e30640d6df Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 21 May 2014 15:39:56 +0200 Subject: 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(+) (limited to 'drivers/acpi') 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", -- cgit v1.2.3 From 0dc6b96ac20c538a28bd8442ae74b87fc6b6f6e0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 26 May 2014 13:44:29 +0200 Subject: 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(+) (limited to 'drivers/acpi') 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"), -- cgit v1.2.3 From 4ff248f3bf830ba22c988abb099e1836fbd3b1d0 Mon Sep 17 00:00:00 2001 From: Manuel Schölling Date: Thu, 22 May 2014 22:56:36 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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; } -- cgit v1.2.3 From a238317ce8185519ed083e81e84260907fbbcf7f Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 20 May 2014 15:39:41 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 @@ err_unmap: 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 */ -- cgit v1.2.3 From 1ac5aaa67290b397712e4410de7f067d5cd85871 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 28 May 2014 15:23:36 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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, -- cgit v1.2.3 From e0d1f09e311fafa33b4bfd942c852671ce25ae58 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 28 May 2014 15:23:38 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 -- cgit v1.2.3 From aca0a4eb4e325914ddb22a8ed06fcb0222da2a26 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 May 2014 04:21:52 +0200 Subject: 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(+) (limited to 'drivers/acpi') 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); -- cgit v1.2.3 From eec15edbb0e14485998635ea7c62e30911b465f0 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Fri, 30 May 2014 04:23:01 +0200 Subject: 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 (limited to 'drivers/acpi') 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); -- cgit v1.2.3 From e1d2c4cf0bfa6a9b484ebcb2ce99c5f38d05c680 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Fri, 30 May 2014 04:24:04 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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 */ -- cgit v1.2.3 From 01cd4bac8ce433f125b772e3964886fc12e108c7 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Fri, 30 May 2014 04:25:15 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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 */ -- cgit v1.2.3 From 549e68455c6706796d9d244364dfbf5c575bd1a5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 May 2014 04:26:18 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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 { -- cgit v1.2.3 From d34afa9de4447367b734ec407e5a9e10617d6ec3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 May 2014 04:27:31 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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) -- cgit v1.2.3 From a1ec657213b4abb00e59385171554a3e11eec27c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 May 2014 04:28:20 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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); -- cgit v1.2.3 From cccd420859a419756bc4ed25d52989a47d702561 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 May 2014 04:29:14 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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 -- cgit v1.2.3 From d6ddaaac8f5c37ad84db3e6e019981f392389cf0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 30 May 2014 14:34:05 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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); -- cgit v1.2.3 From 48459340b92b00ae1a75179f168ef20d3e61f264 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Fri, 30 May 2014 14:35:34 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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(); -- cgit v1.2.3 From 47d68c7f688c01557cb67dd80eb540e88d7913b6 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Sat, 31 May 2014 08:14:44 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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 @@ finish_override: /* 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 @@ finish_override: 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 @@ next_table: 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. */ -- cgit v1.2.3 From 4fc0a7e889e5540305926e41931cf3bc0a60abb2 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Sat, 31 May 2014 08:15:02 +0800 Subject: 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(+) (limited to 'drivers/acpi') 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); -- cgit v1.2.3 From 729ddb657f6a47a2cb6e495f1ff68fff622c758a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 3 Jun 2014 13:20:32 +0800 Subject: 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(-) (limited to 'drivers/acpi') 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" -- cgit v1.2.3