From 1f59ab2783aed04f1318b840950801e38b2bebdf Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 12 Jul 2017 17:45:57 -0700 Subject: ACPI / video: Add force_none quirk for Dell OptiPlex 9020M Dell OptiPlex 9020M is a micro PC desktop that has no built-in LCD panel and its acpi_video does not work. Signed-off-by: Alex Hung Signed-off-by: Rafael J. Wysocki --- drivers/acpi/video_detect.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index d179e8d9177d..601e5d372887 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -103,6 +103,12 @@ static int video_detect_force_native(const struct dmi_system_id *d) return 0; } +static int video_detect_force_none(const struct dmi_system_id *d) +{ + acpi_backlight_dmi = acpi_backlight_none; + return 0; +} + static const struct dmi_system_id video_detect_dmi_table[] = { /* On Samsung X360, the BIOS will set a flag (VDRV) if generic * ACPI backlight device is used. This flag will definitively break @@ -313,6 +319,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7510"), }, }, + { + .callback = video_detect_force_none, + .ident = "Dell OptiPlex 9020M", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 9020M"), + }, + }, { }, }; -- cgit From a7718df2e71900af4cd6505c9e4bc3729ca51a5c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 10 Jul 2017 15:22:45 +0800 Subject: ACPICA: Small indentation changes, no functional change ACPICA commit bb457076d42b95b1453e261da2c8cc0c05ba4718 Fix some alignment issues Link: https://github.com/acpica/acpica/commit/bb457076 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 8ddd3b20e0c6..822dbc5eee18 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -867,7 +867,7 @@ struct acpi_parse_obj_named { /* This version is used by the iASL compiler only */ -#define ACPI_MAX_PARSEOP_NAME 20 +#define ACPI_MAX_PARSEOP_NAME 20 struct acpi_parse_obj_asl { ACPI_PARSE_COMMON union acpi_parse_object *child; @@ -907,7 +907,7 @@ union acpi_parse_object { struct asl_comment_state { u8 comment_type; u32 spaces_before; - union acpi_parse_object *latest_parse_node; + union acpi_parse_object *latest_parse_op; union acpi_parse_object *parsing_paren_brace_node; u8 capture_comments; }; -- cgit From 0c2021c047baa75f88996f2c732ecbac3e4fba29 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 10 Jul 2017 15:22:51 +0800 Subject: ACPICA: IORT: Update SMMU models for revision C ACPICA commit d00a4eb86e64bb4fa70f57ab5e5ca0a4ca2ad8ef IORT revision C has been published with a number of new SMMU implementation identifiers; define them. Link: https://github.com/acpica/acpica/commit/d00a4eb8 Signed-off-by: Robin Murphy Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/actbl2.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 707dda74c272..5829eedbf3ff 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -664,7 +664,7 @@ struct acpi_ibft_target { * IORT - IO Remapping Table * * Conforms to "IO Remapping Table System Software on ARM Platforms", - * Document number: ARM DEN 0049B, October 2015 + * Document number: ARM DEN 0049C, May 2017 * ******************************************************************************/ @@ -779,6 +779,8 @@ struct acpi_iort_smmu { #define ACPI_IORT_SMMU_V2 0x00000001 /* Generic SMMUv2 */ #define ACPI_IORT_SMMU_CORELINK_MMU400 0x00000002 /* ARM Corelink MMU-400 */ #define ACPI_IORT_SMMU_CORELINK_MMU500 0x00000003 /* ARM Corelink MMU-500 */ +#define ACPI_IORT_SMMU_CORELINK_MMU401 0x00000004 /* ARM Corelink MMU-401 */ +#define ACPI_IORT_SMMU_CAVIUM_THUNDERX 0x00000005 /* Cavium thunder_x SMMUv2 */ /* Masks for Flags field above */ @@ -799,13 +801,19 @@ struct acpi_iort_smmu_v3 { u32 flags; u32 reserved; u64 vatos_address; - u32 model; /* O: generic SMMUv3 */ + u32 model; u32 event_gsiv; u32 pri_gsiv; u32 gerr_gsiv; u32 sync_gsiv; }; +/* Values for Model field above */ + +#define ACPI_IORT_SMMU_V3_GENERIC 0x00000000 /* Generic SMMUv3 */ +#define ACPI_IORT_SMMU_V3_HISILICON_HI161X 0x00000001 /* hi_silicon Hi161x SMMUv3 */ +#define ACPI_IORT_SMMU_V3_CAVIUM_CN99XX 0x00000002 /* Cavium CN99xx SMMUv3 */ + /* Masks for Flags field above */ #define ACPI_IORT_SMMU_V3_COHACC_OVERRIDE (1) -- cgit From ff7993a753413b19c1fb9566fc80ddbf5dc785e1 Mon Sep 17 00:00:00 2001 From: Erik Schmauss Date: Mon, 10 Jul 2017 15:22:56 +0800 Subject: ACPICA: Tools: Deallocate memory allocated by ac_get_all_tables_from_file via ac_delete_table_list ACPICA commit 8521b98ebdea450011fa62c14a77fed9affa4236 Link: https://github.com/acpica/acpica/commit/8521b98e Signed-off-by: Erik Schmauss Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acapps.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index bb6a84b0b4b3..7a1a68b5ac5c 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -114,6 +114,8 @@ ac_get_all_tables_from_file(char *filename, u8 get_only_aml_tables, struct acpi_new_table_desc **return_list_head); +void ac_delete_table_list(struct acpi_new_table_desc *list_head); + u8 ac_is_file_binary(FILE * file); acpi_status ac_validate_table_header(FILE * file, long table_offset); -- cgit From 3ddd3f6a94108a5d2abfaa2a2f809b1520361e5e Mon Sep 17 00:00:00 2001 From: Erik Schmauss Date: Mon, 10 Jul 2017 15:23:02 +0800 Subject: ACPICA: iASL compiler: allow compilation of externals with paths that refer to existing names ACPICA commit 9a252114197409290813bee570e9d53c22b99d32 This change allows compilation of code like the following: definition_block (...) { External (ABCD.EFGH) Device (ABCD) { Name (IJLK,0) } } but does not allow compilation of code like the following: definition_block (...) { External (ABCD) Device (ABCD) { Name (EFGH,0) } } Link: https://github.com/acpica/acpica/commit/9a252114 Signed-off-by: Erik Schmauss Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 1 + drivers/acpi/acpica/nsaccess.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 822dbc5eee18..bae943b5f377 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -199,6 +199,7 @@ struct acpi_namespace_node { #define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ #define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (install_method) */ +#define IMPLICIT_EXTERNAL 0x02 /* iASL only: This object created implicitly via External */ #define ANOBJ_IS_EXTERNAL 0x08 /* iASL only: This object created via External() */ #define ANOBJ_METHOD_NO_RETVAL 0x10 /* iASL only: Method has no return value */ #define ANOBJ_METHOD_SOME_NO_RETVAL 0x20 /* iASL only: Method has at least one return value */ diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index e5f4fa496572..14be12fe9f35 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -634,6 +634,12 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, this_node->object; } } +#ifdef ACPI_ASL_COMPILER + if (!acpi_gbl_disasm_flag && + (this_node->flags & ANOBJ_IS_EXTERNAL)) { + this_node->flags |= IMPLICIT_EXTERNAL; + } +#endif } /* Special handling for the last segment (num_segments == 0) */ -- cgit From 99e597adf60e1a6f83ec746db8cab225b16a838b Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 10 Jul 2017 15:23:08 +0800 Subject: Back port of "ACPICA: Use designated initializers" ACPICA commit 47538f5f0773c0820d8f552e20f6e77104290c01 The following commit is not correctly linuxized by its ACPICA form (see link #1 for reference): Commit: 3d867f6c5fd6535cdeceef3170e5e84e5dd80fc1 Subject: ACPICA: Use designated initializers Thus breaks linuxize process. This patch is a linuxized back port result of the upstreamed ACPICA commit (see link #2 for reference). Link: https://github.com/acpica/acpica/pull/248/ [#1] Link: https://github.com/acpica/acpica/commit/47538f5f [#2] Signed-off-by: Kees Cook Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/hwxfsleep.c | 9 ++++++--- include/acpi/platform/acenv.h | 9 +++++---- include/acpi/platform/aclinux.h | 3 +++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index 7ef13934968f..e5c095ca6083 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -72,13 +72,16 @@ static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id); static struct acpi_sleep_functions acpi_sleep_dispatch[] = { {ACPI_STRUCT_INIT(legacy_function, ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_sleep)), - ACPI_STRUCT_INIT(extended_function, acpi_hw_extended_sleep) }, + ACPI_STRUCT_INIT(extended_function, + acpi_hw_extended_sleep)}, {ACPI_STRUCT_INIT(legacy_function, ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake_prep)), - ACPI_STRUCT_INIT(extended_function, acpi_hw_extended_wake_prep) }, + ACPI_STRUCT_INIT(extended_function, + acpi_hw_extended_wake_prep)}, {ACPI_STRUCT_INIT(legacy_function, ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake)), - ACPI_STRUCT_INIT(extended_function, acpi_hw_extended_wake) } + ACPI_STRUCT_INIT(extended_function, + acpi_hw_extended_wake)} }; /* diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index 912563c66948..043fd559de6e 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -288,6 +288,11 @@ #define ACPI_INLINE #endif +/* Use ordered initialization if compiler doesn't support designated. */ +#ifndef ACPI_STRUCT_INIT +#define ACPI_STRUCT_INIT(field, value) value +#endif + /* * Configurable calling conventions: * @@ -382,8 +387,4 @@ #define ACPI_INIT_FUNCTION #endif -#ifndef ACPI_STRUCT_INIT -#define ACPI_STRUCT_INIT(field, value) value -#endif - #endif /* __ACENV_H__ */ diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 047f13865608..afd95f28c8f0 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -178,6 +178,9 @@ #define ACPI_MSG_BIOS_ERROR KERN_ERR "ACPI BIOS Error (bug): " #define ACPI_MSG_BIOS_WARNING KERN_WARNING "ACPI BIOS Warning (bug): " +/* + * Linux wants to use designated initializers for function pointer structs. + */ #define ACPI_STRUCT_INIT(field, value) .field = value #else /* !__KERNEL__ */ -- cgit From 7679c35da5b5afa78ce6766f5966a5a4579d4332 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 10 Jul 2017 15:23:15 +0800 Subject: ACPICA: linuxize: cleanup typedef definitions ACPICA commit 894e49ef22db354eb1685cdb6f5f991766351d3c acpisrc now has capability to convert both the followings: 1. Form 1: typedef struct/union foo { struct/union foo { .... --> ... } FOO; } 2. Form 2: typedef struct/union foo FOO; --> typedef struct/union foo foo; It becomes unable to handle the following: 3. Form3: typedef struct/union foo { /* comment */ ... } FOO; --> strut/union foo { /* comment */ ... }; As: 1. The purpose of acpisrc is to convert formatted code (ACPICA coding style) into linux coding style, 2. acpisrc is a very simple tool that doesn't fully handle C language. This commit changes the definitions side in order not to regress and we shall make "no comments in struct/union line" as a new ACPICA coding style rule. Lv Zheng. Link: https://github.com/acpica/acpica/commit/894e49ef Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acobject.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 27c3f982d810..549f227348cd 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -122,7 +122,9 @@ struct acpi_object_integer { _type *pointer; \ u32 length; -struct acpi_object_string { /* Null terminated, ASCII characters only */ +/* Null terminated, ASCII characters only */ + +struct acpi_object_string { ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO(char) /* String in AML stream or allocated string */ }; @@ -211,7 +213,9 @@ struct acpi_object_method { union acpi_operand_object *notify_list[2]; /* Handlers for system/device notifies */\ union acpi_operand_object *handler; /* Handler for Address space */ -struct acpi_object_notify_common { /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */ +/* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */ + +struct acpi_object_notify_common { ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO}; struct acpi_object_device { @@ -258,7 +262,9 @@ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO}; u8 access_length; /* For serial regions/fields */ -struct acpi_object_field_common { /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */ +/* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */ + +struct acpi_object_field_common { ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Parent Operation Region object (REGION/BANK fields only) */ }; -- cgit From 96d07940623a2a40b2eec01daebf93bbaaee8a3b Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 10 Jul 2017 15:23:21 +0800 Subject: ACPICA: Tables: Add sanity check in acpi_put_table() ACPICA commit 73512384c9eb1e7f1b28d0a7372df26a3732f96b To avoid caller to trigger unexpected warning messages (Link #1): ACPI Warning: Table ffffffffbb461d20, Validation count is zero before decrement Which is reported from acpi_tb_put_table(). When the table is validated, the pointer must be non-zero. Thus the message is not suitable for invalidated tables. This patch fixes the callee side based on this fact. Reported by Cristian Aravena Romero, Fixed by Lv Zheng. Link: https://github.com/acpica/acpica/commit/73512384 Link: https://bugzilla.kernel.org/show_bug.cgi?id=191221 [#1] Reported-by: Cristian Aravena Romero Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/tbxface.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 010b1c43df92..18508b2c0c05 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -369,6 +369,10 @@ void acpi_put_table(struct acpi_table_header *table) ACPI_FUNCTION_TRACE(acpi_put_table); + if (!table) { + return_VOID; + } + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); /* Walk the root table list */ -- cgit From 9b019b0f67bf527d6412de0497702026ff37e8a6 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 10 Jul 2017 15:23:28 +0800 Subject: ACPICA: Tables: Cleanup table handler invokers ACPICA commit 4551f51fa8ba33a977721c3b250cb70a309e3f23 Recently, we allows the table mutex to be held in both early and late stage APIs. This patch further cleans up the related code to reduce redundant code related to acpi_gbl_table_handler. Lv Zheng. Link: https://github.com/acpica/acpica/commit/4551f51f Tested-by: Hans de Goede Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/actables.h | 2 ++ drivers/acpi/acpica/tbdata.c | 43 ++++++++++++++++++++++++++++-------------- drivers/acpi/acpica/tbinstal.c | 8 ++------ 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index c8da453bd960..89ed31b0f739 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -132,6 +132,8 @@ acpi_tb_install_and_load_table(acpi_physical_address address, acpi_status acpi_tb_unload_table(u32 table_index); +void acpi_tb_notify_table(u32 event, void *table); + void acpi_tb_terminate(void); acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index); diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index c9d6fa6d7cc6..7056ca01e875 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -818,13 +818,9 @@ acpi_tb_load_table(u32 table_index, struct acpi_namespace_node *parent_node) acpi_ev_update_gpes(owner_id); } - /* Invoke table handler if present */ - - if (acpi_gbl_table_handler) { - (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table, - acpi_gbl_table_handler_context); - } + /* Invoke table handler */ + acpi_tb_notify_table(ACPI_TABLE_EVENT_LOAD, table); return_ACPI_STATUS(status); } @@ -894,15 +890,11 @@ acpi_status acpi_tb_unload_table(u32 table_index) return_ACPI_STATUS(AE_NOT_EXIST); } - /* Invoke table handler if present */ + /* Invoke table handler */ - if (acpi_gbl_table_handler) { - status = acpi_get_table_by_index(table_index, &table); - if (ACPI_SUCCESS(status)) { - (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_UNLOAD, - table, - acpi_gbl_table_handler_context); - } + status = acpi_get_table_by_index(table_index, &table); + if (ACPI_SUCCESS(status)) { + acpi_tb_notify_table(ACPI_TABLE_EVENT_UNLOAD, table); } /* Delete the portion of the namespace owned by this table */ @@ -918,3 +910,26 @@ acpi_status acpi_tb_unload_table(u32 table_index) } ACPI_EXPORT_SYMBOL(acpi_tb_unload_table) + +/******************************************************************************* + * + * FUNCTION: acpi_tb_notify_table + * + * PARAMETERS: event - Table event + * table - Validated table pointer + * + * RETURN: None + * + * DESCRIPTION: Notify a table event to the users. + * + ******************************************************************************/ + +void acpi_tb_notify_table(u32 event, void *table) +{ + /* Invoke table handler if present */ + + if (acpi_gbl_table_handler) { + (void)acpi_gbl_table_handler(event, table, + acpi_gbl_table_handler_context); + } +} diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 4620f3c68c13..ee745152f25b 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -306,14 +306,10 @@ acpi_tb_install_standard_table(acpi_physical_address address, acpi_tb_install_table_with_override(&new_table_desc, override, table_index); - /* Invoke table handler if present */ + /* Invoke table handler */ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - if (acpi_gbl_table_handler) { - (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_INSTALL, - new_table_desc.pointer, - acpi_gbl_table_handler_context); - } + acpi_tb_notify_table(ACPI_TABLE_EVENT_INSTALL, new_table_desc.pointer); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); unlock_and_exit: -- cgit From 04ba15aa55cf16e18757faea55d62d1b7e407fe3 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 10 Jul 2017 15:23:37 +0800 Subject: ACPICA: Tables: Do not validate signature for dynamic table load ACPICA commit d3c944f2cdc8c7e847b7942b1864f285189f7bce Windows seems to allow arbitrary table signatures for Load/load_table opcodes: ACPI BIOS Error (bug): Table has invalid signature [PRAD] (0x44415250) So this patch removes dynamic load signature checks. However we need to find a way to avoid table loading against tables like MADT. This is not covered by this commit. This Windows behavior has been validated on link #1. An end user bug report can also be found on link #2. This patch also includes simple cleanup for static load signature check code. Reported by Ye Xiaolong, Fixed by Lv Zheng. Link: https://github.com/acpica/acpica/commit/d3c944f2 Link: https://github.com/acpica/acpica/pull/121 [#1] Link: https://bugzilla.kernel.org/show_bug.cgi?id=118601 [#2] Reported-by: Ye Xiaolong Reported-by: Olga Uhina Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/tbinstal.c | 28 ---------------------------- drivers/acpi/acpica/tbxfload.c | 2 +- 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index ee745152f25b..9d212967fad8 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -222,34 +222,6 @@ acpi_tb_install_standard_table(acpi_physical_address address, (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 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)) - && (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_nameseg(new_table_desc. - signature. - ascii) ? - new_table_desc.signature. - ascii : "????", - new_table_desc.signature.integer)); - - status = AE_BAD_SIGNATURE; - goto unlock_and_exit; - } /* Check if table is already registered */ diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index b71ce3b817ea..d81f442228b8 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -206,7 +206,7 @@ acpi_status acpi_tb_load_namespace(void) for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { table = &acpi_gbl_root_table_list.tables[i]; - if (!acpi_gbl_root_table_list.tables[i].address || + if (!table->address || (!ACPI_COMPARE_NAME(table->signature.ascii, ACPI_SIG_SSDT) && !ACPI_COMPARE_NAME(table->signature.ascii, ACPI_SIG_PSDT) -- cgit From 023e2ee16c51da7f6a9455ac936e4fb00295f47a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 10 Jul 2017 15:23:45 +0800 Subject: ACPICA: Tables: Change table duplication check to be related to acpi_gbl_verify_table_checksum ACPICA commit 3d837b5d4b1033942b4d91c7d3801a09c3157918 acpi_gbl_verify_table_checksum is used to avoid validating (mapping) an entire table in OS boot stage. 2nd "Reload" check in acpi_tb_install_standard_table() is prepared for the same purpose. So this patch combines them together using a renamed acpi_gbl_enable_table_validation flag. Lv Zheng. Link: https://github.com/acpica/acpica/commit/3d837b5d Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/tbdata.c | 4 ++-- drivers/acpi/acpica/tbinstal.c | 2 +- drivers/acpi/acpica/tbxface.c | 8 ++++++++ drivers/acpi/bus.c | 3 --- drivers/acpi/tables.c | 4 ++-- include/acpi/acpixf.h | 15 ++++++++------- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index 7056ca01e875..24d99711b2a4 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -338,7 +338,7 @@ void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc) acpi_status acpi_tb_validate_temp_table(struct acpi_table_desc *table_desc) { - if (!table_desc->pointer && !acpi_gbl_verify_table_checksum) { + if (!table_desc->pointer && !acpi_gbl_enable_table_validation) { /* * Only validates the header of the table. * Note that Length contains the size of the mapping after invoking @@ -394,7 +394,7 @@ acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, char *signature) /* Verify the checksum */ - if (acpi_gbl_verify_table_checksum) { + if (acpi_gbl_enable_table_validation) { status = acpi_tb_verify_checksum(table_desc->pointer, table_desc->length); diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 9d212967fad8..f7bc362bd3c5 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -221,7 +221,7 @@ acpi_tb_install_standard_table(acpi_physical_address address, (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (reload) { + if (acpi_gbl_enable_table_validation) { /* Check if table is already registered */ diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 18508b2c0c05..38c01049afd5 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -194,6 +194,14 @@ acpi_status ACPI_INIT_FUNCTION acpi_reallocate_root_table(void) } } + if (!acpi_gbl_enable_table_validation) { + /* + * Now it's safe to do full table validation. We can do deferred + * table initilization here once the flag is set. + */ + acpi_gbl_enable_table_validation = TRUE; + } + acpi_gbl_root_table_list.flags |= ACPI_ROOT_ALLOW_RESIZE; status = acpi_tb_resize_root_table_list(); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index af74b420ec83..59f2f96fdb7e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -995,9 +995,6 @@ 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 ff425390bfa8..80ce2a7d224b 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -740,10 +740,10 @@ int __init acpi_table_init(void) if (acpi_verify_table_checksum) { pr_info("Early table checksum verification enabled\n"); - acpi_gbl_verify_table_checksum = TRUE; + acpi_gbl_enable_table_validation = TRUE; } else { pr_info("Early table checksum verification disabled\n"); - acpi_gbl_verify_table_checksum = FALSE; + acpi_gbl_enable_table_validation = FALSE; } status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index a59c44c3edd8..12dac84c98c9 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -160,13 +160,14 @@ 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); + * Whether or not to validate (map) an entire table to verify + * checksum/duplication in early stage before install. Set this to TRUE to + * allow early table validation 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 allow such + * validation. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_table_validation, TRUE); /* * Optionally enable output from the AML Debug Object. -- cgit From f9d472ee3214cf8fc3e4b418b376869799adaf67 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 10 Jul 2017 15:23:50 +0800 Subject: ACPICA: Tables: Combine checksum/duplication verification together ACPICA commit 182bdffc0644f568be614a6d4debd651e29ca587 They are all mechanisms used to verify if a table is qualified to be installed and controlled by acpi_gbl_enable_table_validation, so combine them together. By doing so, table duplication check is applied to the statically loaded tables (however whether it is actually enabled is still determined by acpi_gbl_enable_table_validation). Lv Zheng. Link: https://github.com/acpica/acpica/commit/182bdffc Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/actables.h | 3 +- drivers/acpi/acpica/tbdata.c | 151 +++++++++++++++++++++++++++++++++++++++-- drivers/acpi/acpica/tbinstal.c | 125 ++++++---------------------------- 3 files changed, 169 insertions(+), 110 deletions(-) diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 89ed31b0f739..84a3ceb6e384 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -76,7 +76,8 @@ 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); +acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, + char *signature, u32 *table_index); u8 acpi_tb_is_table_loaded(u32 table_index); diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index 24d99711b2a4..577361b05ea9 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -50,6 +50,57 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbdata") +/* Local prototypes */ +static acpi_status +acpi_tb_check_duplication(struct acpi_table_desc *table_desc, u32 *table_index); + +static u8 +acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index); + +/******************************************************************************* + * + * FUNCTION: acpi_tb_compare_tables + * + * PARAMETERS: table_desc - Table 1 descriptor to be compared + * table_index - Index of table 2 to be compared + * + * RETURN: TRUE if both tables are identical. + * + * DESCRIPTION: This function compares a table with another table that has + * already been installed in the root table list. + * + ******************************************************************************/ + +static u8 +acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index) +{ + acpi_status status = AE_OK; + u8 is_identical; + 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_identical = (u8)((table_desc->length != table_length || + memcmp(table_desc->pointer, table, table_length)) ? + FALSE : TRUE); + + /* Release the acquired table */ + + acpi_tb_release_table(table, table_length, table_flags); + return (is_identical); +} + /******************************************************************************* * * FUNCTION: acpi_tb_init_table_descriptor @@ -64,6 +115,7 @@ ACPI_MODULE_NAME("tbdata") * DESCRIPTION: Initialize a new table descriptor * ******************************************************************************/ + void acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, acpi_physical_address address, @@ -354,12 +406,78 @@ acpi_status acpi_tb_validate_temp_table(struct acpi_table_desc *table_desc) return (acpi_tb_validate_table(table_desc)); } +/******************************************************************************* + * + * FUNCTION: acpi_tb_check_duplication + * + * PARAMETERS: table_desc - Table descriptor + * table_index - Where the table index is returned + * + * RETURN: Status + * + * DESCRIPTION: Avoid installing duplicated tables. However table override and + * user aided dynamic table load is allowed, thus comparing the + * address of the table is not sufficient, and checking the entire + * table content is required. + * + ******************************************************************************/ + +static acpi_status +acpi_tb_check_duplication(struct acpi_table_desc *table_desc, u32 *table_index) +{ + u32 i; + + ACPI_FUNCTION_TRACE(tb_check_duplication); + + /* 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_compare_tables(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 */ + + return_ACPI_STATUS(AE_ALREADY_EXISTS); + } else { + *table_index = i; + return_ACPI_STATUS(AE_CTRL_TERMINATE); + } + } + + /* Indicate no duplication to the caller */ + + return_ACPI_STATUS(AE_OK); +} + /****************************************************************************** * * FUNCTION: acpi_tb_verify_temp_table * * PARAMETERS: table_desc - Table descriptor * signature - Table signature to verify + * table_index - Where the table index is returned * * RETURN: Status * @@ -369,7 +487,8 @@ 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) +acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, + char *signature, u32 *table_index) { acpi_status status = AE_OK; @@ -392,9 +511,10 @@ acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, char *signature) goto invalidate_and_exit; } - /* Verify the checksum */ - if (acpi_gbl_enable_table_validation) { + + /* Verify the checksum */ + status = acpi_tb_verify_checksum(table_desc->pointer, table_desc->length); @@ -411,9 +531,32 @@ acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, char *signature) goto invalidate_and_exit; } + + /* Avoid duplications */ + + if (table_index) { + status = + acpi_tb_check_duplication(table_desc, table_index); + if (ACPI_FAILURE(status)) { + if (status != AE_CTRL_TERMINATE) { + ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, + "%4.4s 0x%8.8X%8.8X" + " Table is duplicated", + acpi_ut_valid_nameseg + (table_desc->signature. + ascii) ? table_desc-> + signature. + ascii : "????", + ACPI_FORMAT_UINT64 + (table_desc->address))); + } + + goto invalidate_and_exit; + } + } } - return_ACPI_STATUS(AE_OK); + return_ACPI_STATUS(status); invalidate_and_exit: acpi_tb_invalidate_table(table_desc); diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index f7bc362bd3c5..0dfc0ac3c141 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -48,54 +48,6 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbinstal") -/* Local prototypes */ -static u8 -acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index); - -/******************************************************************************* - * - * FUNCTION: acpi_tb_compare_tables - * - * PARAMETERS: table_desc - Table 1 descriptor to be compared - * table_index - Index of table 2 to be compared - * - * RETURN: TRUE if both tables are identical. - * - * DESCRIPTION: This function compares a table with another table that has - * already been installed in the root table list. - * - ******************************************************************************/ - -static u8 -acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index) -{ - acpi_status status = AE_OK; - u8 is_identical; - 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_identical = (u8)((table_desc->length != table_length || - memcmp(table_desc->pointer, table, table_length)) ? - FALSE : TRUE); - - /* Release the acquired table */ - - acpi_tb_release_table(table, table_length, table_flags); - return (is_identical); -} - /******************************************************************************* * * FUNCTION: acpi_tb_install_table_with_override @@ -112,7 +64,6 @@ acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index) * table array. * ******************************************************************************/ - void acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc, u8 override, u32 *table_index) @@ -210,67 +161,29 @@ acpi_tb_install_standard_table(acpi_physical_address address, goto release_and_exit; } - /* Validate and verify a table before installation */ - - status = acpi_tb_verify_temp_table(&new_table_desc, NULL); - if (ACPI_FAILURE(status)) { - goto release_and_exit; - } - /* Acquire the table lock */ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (acpi_gbl_enable_table_validation) { - - /* 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_compare_tables(&new_table_desc, i)) { - continue; - } + /* Validate and verify a table before installation */ + status = acpi_tb_verify_temp_table(&new_table_desc, NULL, &i); + if (ACPI_FAILURE(status)) { + if (status == AE_CTRL_TERMINATE) { /* - * 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 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_table_with_override() can be called again to + * indicate the re-installation. */ - 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 unlock_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_table_with_override() can be called again to - * indicate the re-installation. - */ - acpi_tb_uninstall_table(&new_table_desc); - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - *table_index = i; - return_ACPI_STATUS(AE_OK); - } + acpi_tb_uninstall_table(&new_table_desc); + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + *table_index = i; + return_ACPI_STATUS(AE_OK); } + goto unlock_and_exit; } /* Add the table to the global root table list */ @@ -350,9 +263,11 @@ void acpi_tb_override_table(struct acpi_table_desc *old_table_desc) finish_override: - /* Validate and verify a table before overriding */ - - status = acpi_tb_verify_temp_table(&new_table_desc, NULL); + /* + * Validate and verify a table before overriding, no nested table + * duplication check as it's too complicated and unnecessary. + */ + status = acpi_tb_verify_temp_table(&new_table_desc, NULL, NULL); if (ACPI_FAILURE(status)) { return; } -- cgit From 19df56bdf0833a8ad9dfe056931696b9e0e30463 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 10 Jul 2017 15:23:56 +0800 Subject: ACPICA: Tables: Add deferred table verification support ACPICA commit 2dd6c151d5d5e76dacba8f7db9e259fc72982d17 ACPICA commit ffddee6638aced83be18b8bc88569586c1a43e03 This patch allows tables not verified in early stage verfied in acpi_reallocate_root_table(). This is useful for OSPMs like linux where tables cannot be verified in early stage due to early ioremp limitations on some architectures. Reported by Hans de Geode, fixed by Lv Zheng. Link: https://github.com/acpica/acpica/commit/2dd6c151 Link: https://github.com/acpica/acpica/commit/ffddee66 Reported-by: Hans de Goede Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/tbdata.c | 34 ++++++++++++++++++++++++++++------ drivers/acpi/acpica/tbxface.c | 27 ++++++++++++++++++++++----- include/acpi/actbl.h | 1 + 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index 577361b05ea9..b19a2f0ea331 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -432,6 +432,15 @@ acpi_tb_check_duplication(struct acpi_table_desc *table_desc, u32 *table_index) /* Check if table is already registered */ for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { + + /* Do not compare with unverified tables */ + + if (! + (acpi_gbl_root_table_list.tables[i]. + flags & ACPI_TABLE_IS_VERIFIED)) { + continue; + } + /* * Check for a table match on the entire table length, * not just the header. @@ -483,6 +492,8 @@ acpi_tb_check_duplication(struct acpi_table_desc *table_desc, u32 *table_index) * * DESCRIPTION: This function is called to validate and verify the table, the * returned table descriptor is in "VALIDATED" state. + * Note that 'TableIndex' is required to be set to !NULL to + * enable duplication check. * *****************************************************************************/ @@ -554,6 +565,8 @@ acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, goto invalidate_and_exit; } } + + table_desc->flags |= ACPI_TABLE_IS_VERIFIED; } return_ACPI_STATUS(status); @@ -579,6 +592,8 @@ acpi_status acpi_tb_resize_root_table_list(void) { struct acpi_table_desc *tables; u32 table_count; + u32 current_table_count, max_table_count; + u32 i; ACPI_FUNCTION_TRACE(tb_resize_root_table_list); @@ -598,8 +613,8 @@ acpi_status acpi_tb_resize_root_table_list(void) table_count = acpi_gbl_root_table_list.current_table_count; } - tables = ACPI_ALLOCATE_ZEROED(((acpi_size)table_count + - ACPI_ROOT_TABLE_SIZE_INCREMENT) * + max_table_count = table_count + ACPI_ROOT_TABLE_SIZE_INCREMENT; + tables = ACPI_ALLOCATE_ZEROED(((acpi_size)max_table_count) * sizeof(struct acpi_table_desc)); if (!tables) { ACPI_ERROR((AE_INFO, @@ -609,9 +624,16 @@ acpi_status acpi_tb_resize_root_table_list(void) /* Copy and free the previous table array */ + current_table_count = 0; if (acpi_gbl_root_table_list.tables) { - memcpy(tables, acpi_gbl_root_table_list.tables, - (acpi_size)table_count * sizeof(struct acpi_table_desc)); + for (i = 0; i < table_count; i++) { + if (acpi_gbl_root_table_list.tables[i].address) { + memcpy(tables + current_table_count, + acpi_gbl_root_table_list.tables + i, + sizeof(struct acpi_table_desc)); + current_table_count++; + } + } if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { ACPI_FREE(acpi_gbl_root_table_list.tables); @@ -619,8 +641,8 @@ acpi_status acpi_tb_resize_root_table_list(void) } 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.max_table_count = max_table_count; + acpi_gbl_root_table_list.current_table_count = current_table_count; acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED; return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 38c01049afd5..26ad596c973e 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -167,7 +167,8 @@ ACPI_EXPORT_SYMBOL_INIT(acpi_initialize_tables) acpi_status ACPI_INIT_FUNCTION acpi_reallocate_root_table(void) { acpi_status status; - u32 i; + struct acpi_table_desc *table_desc; + u32 i, j; ACPI_FUNCTION_TRACE(acpi_reallocate_root_table); @@ -179,6 +180,8 @@ acpi_status ACPI_INIT_FUNCTION acpi_reallocate_root_table(void) return_ACPI_STATUS(AE_SUPPORT); } + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + /* * Ensure OS early boot logic, which is required by some hosts. If the * table state is reported to be wrong, developers should fix the @@ -186,11 +189,11 @@ acpi_status ACPI_INIT_FUNCTION acpi_reallocate_root_table(void) * early stage. */ for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { - if (acpi_gbl_root_table_list.tables[i].pointer) { + table_desc = &acpi_gbl_root_table_list.tables[i]; + if (table_desc->pointer) { ACPI_ERROR((AE_INFO, "Table [%4.4s] is not invalidated during early boot stage", - acpi_gbl_root_table_list.tables[i]. - signature.ascii)); + table_desc->signature.ascii)); } } @@ -200,11 +203,25 @@ acpi_status ACPI_INIT_FUNCTION acpi_reallocate_root_table(void) * table initilization here once the flag is set. */ acpi_gbl_enable_table_validation = TRUE; + for (i = 0; i < acpi_gbl_root_table_list.current_table_count; + ++i) { + table_desc = &acpi_gbl_root_table_list.tables[i]; + if (!(table_desc->flags & ACPI_TABLE_IS_VERIFIED)) { + status = + acpi_tb_verify_temp_table(table_desc, NULL, + &j); + if (ACPI_FAILURE(status)) { + acpi_tb_uninstall_table(table_desc); + } + } + } } acpi_gbl_root_table_list.flags |= ACPI_ROOT_ALLOW_RESIZE; - status = acpi_tb_resize_root_table_list(); + acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED; + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_ACPI_STATUS(status); } diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index bdc55c0da19c..89509b86cb54 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -394,6 +394,7 @@ struct acpi_table_desc { #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_VERIFIED (4) #define ACPI_TABLE_IS_LOADED (8) /* -- cgit From 4e6cbe5689a5af8435bebc57b77d7dd4420b4134 Mon Sep 17 00:00:00 2001 From: Alex James Date: Mon, 10 Jul 2017 15:24:02 +0800 Subject: ACPICA: iASL: Ensure that the target node is valid in acpi_ex_create_alias ACPICA commit 8b14afac65d983610cc5387ede6d85ea5ee075be The following ACPI table contains an invalid target node within the Alias operator: definition_block ("", "SSDT", 1, "Bug", "BugTable", 0x00001000) { Scope (_SB) { Device (DEV0) { Name (_ADR, 1) Device (DEV1) { Alias (_ADR, _ADR) } } } } If an ACPI table contains such an invalid target node in an Alias operator, a segmentation fault will occur when the target node is dereferenced within acpi_ex_create_alias. Add a check for such an invalid target node in acpi_ex_create_alias and return AE_NULL_OBJECT as suggested by @acpibob. Link: https://github.com/acpica/acpica/commit/8b14afac Signed-off-by: Alex James Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/excreate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index d43d7da4c734..68675868e20f 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -87,6 +87,11 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) target_node->object); } + /* Ensure that the target node is valid */ + if (!target_node) { + return_ACPI_STATUS(AE_NULL_OBJECT); + } + /* * For objects that can never change (i.e., the NS node will * permanently point to the same object), we can simply attach -- cgit From 3f20ea15f07546a20ec2caca98c65dc5f441431a Mon Sep 17 00:00:00 2001 From: Erik Schmauss Date: Mon, 10 Jul 2017 15:24:09 +0800 Subject: ACPICA: Disassembler: skip parsing of incorrect external declarations ACPICA commit ed25461901d34120067b07ec280af30abc0458f1 Link: https://github.com/acpica/acpica/commit/ed254619 Signed-off-by: Erik Schmauss Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/psobject.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index ef6384e374fc..0bef6df71bba 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -359,6 +359,32 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, acpi_ps_build_named_op(walk_state, aml_op_start, op, &named_op); acpi_ps_free_op(op); + +#ifdef ACPI_ASL_COMPILER + if (acpi_gbl_disasm_flag + && walk_state->opcode == AML_EXTERNAL_OP + && status == AE_NOT_FOUND) { + /* + * If parsing of AML_EXTERNAL_OP's name path fails, then skip + * past this opcode and keep parsing. This is a much better + * alternative than to abort the entire disassembler. At this + * point, the parser_state is at the end of the namepath of the + * external declaration opcode. Setting walk_state->Aml to + * walk_state->parser_state.Aml + 2 moves increments the + * walk_state->Aml past the object type and the paramcount of the + * external opcode. For the error message, only print the AML + * offset. We could attempt to print the name but this may cause + * a segmentation fault when printing the namepath because the + * AML may be incorrect. + */ + acpi_os_printf + ("// Invalid external declaration at AML offset 0x%x.\n", + walk_state->aml - + walk_state->parser_state.aml_start); + walk_state->aml = walk_state->parser_state.aml + 2; + return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); + } +#endif if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } -- cgit From c944230064eb65e4fa018d86779b4fd200b1d7e7 Mon Sep 17 00:00:00 2001 From: Ganapatrao Kulkarni Date: Mon, 10 Jul 2017 15:24:15 +0800 Subject: ACPICA: iasl: Update to IORT SMMUv3 disassembling ACPICA commit 8cadc4fb500e2aa52241e367c87a0f95d9760c58 ARM IORT specification has provision to define Proximity domain in SMMUv3 IORT table. Adding required changes to decode Proximity domain of SMMUv3 IORT table. Link: https://github.com/acpica/acpica/commit/8cadc4fb Signed-off-by: Ganapatrao Kulkarni Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/actbl2.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 5829eedbf3ff..d568948d3a82 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -806,6 +806,9 @@ struct acpi_iort_smmu_v3 { u32 pri_gsiv; u32 gerr_gsiv; u32 sync_gsiv; + u8 pxm; + u8 reserved1; + u16 reserved2; }; /* Values for Model field above */ @@ -818,6 +821,7 @@ struct acpi_iort_smmu_v3 { #define ACPI_IORT_SMMU_V3_COHACC_OVERRIDE (1) #define ACPI_IORT_SMMU_V3_HTTU_OVERRIDE (1<<1) +#define ACPI_IORT_SMMU_V3_PXM_VALID (1<<3) /******************************************************************************* * -- cgit From 852d4f9c71bc1582199200310c8951b79e451d6a Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 5 Jun 2017 16:40:50 +0800 Subject: ACPICA: Update resource descriptor handling ACPICA commit c8eac10178b387f9eb1935694e509d4518da77bb This change restores the change introduced by commit 23b5bbe and adds a comment concerning resource descriptor buffers that extend beyond the END_TAG descriptor. Link: https://github.com/acpica/acpica/commit/c8eac101 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utresrc.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index 70f78a4bf13b..d955bf852a03 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -184,9 +184,11 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, ACPI_FUNCTION_TRACE(ut_walk_aml_resources); - /* The absolute minimum resource template is one end_tag descriptor */ - - if (aml_length < sizeof(struct aml_resource_end_tag)) { + /* + * The absolute minimum resource template is one end_tag descriptor. + * However, we will treat a lone end_tag as just a simple buffer. + */ + if (aml_length <= sizeof(struct aml_resource_end_tag)) { return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); } @@ -243,8 +245,10 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, *context = aml; } - /* Normal exit */ - + /* + * Normal exit. Note: We allow the buffer to be larger than + * the resource template, as long as the END_TAG exists. + */ return_ACPI_STATUS(AE_OK); } -- cgit From ab539eaa50c6a97f1d6287c5ce3ee75155cb10b8 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 10 Jul 2017 15:24:27 +0800 Subject: ACPICA: Update version to 20170629 ACPICA commit 7271c1c54c095c06ed9e7d28641f2356da840038 Version 20170629 Link: https://github.com/acpica/acpica/commit/7271c1c5 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 12dac84c98c9..06b87adc97ef 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20170531 +#define ACPI_CA_VERSION 0x20170629 #include #include -- cgit From 58eefe2f3f53f294cdb5a2b6121973b5ae508f01 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 8 Jul 2017 15:40:08 +0200 Subject: ACPI / PMIC: xpower: Do pinswitch magic when reading GPADC Testing has shown that the TS-pin's bias-current needs to be disabled when reading the GPIO0 pin in GPADC mode. It seems that there is only 1 bias current source and to be able to use it for the GPIO0 pin in GPADC mode it must be temporarily turned off for the TS pin, but the datasheet does not mention this. This commit adds the necessary writes to turn the TS pin BIAS current off before and back on after reading the GPADC. This fixes the GPADC always returning a reading of 0. Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pmic/intel_pmic_xpower.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c index 3b7d5be5b7ed..6c99d3f81095 100644 --- a/drivers/acpi/pmic/intel_pmic_xpower.c +++ b/drivers/acpi/pmic/intel_pmic_xpower.c @@ -27,6 +27,9 @@ #define GPI1_LDO_ON (3 << 0) #define GPI1_LDO_OFF (4 << 0) +#define AXP288_ADC_TS_PIN_GPADC 0xf2 +#define AXP288_ADC_TS_PIN_ON 0xf3 + static struct pmic_table power_table[] = { { .address = 0x00, @@ -209,11 +212,23 @@ static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg, static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg) { u8 buf[2]; + int ret; - if (regmap_bulk_read(regmap, AXP288_GP_ADC_H, buf, 2)) - return -EIO; + ret = regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, + AXP288_ADC_TS_PIN_GPADC); + if (ret) + return ret; + + /* After switching to the GPADC pin give things some time to settle */ + usleep_range(6000, 10000); + + ret = regmap_bulk_read(regmap, AXP288_GP_ADC_H, buf, 2); + if (ret == 0) + ret = (buf[0] << 4) + ((buf[1] >> 4) & 0x0f); + + regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, AXP288_ADC_TS_PIN_ON); - return (buf[0] << 4) + ((buf[1] >> 4) & 0x0F); + return ret; } static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = { -- cgit From 861a6ee8142efbe80b3891fdfb09f74d726c9809 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Jul 2017 18:04:16 +0300 Subject: ACPI / boot: Don't define unused variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some code in acpi_parse_x2apic() conditionally compiled, though parts of it are being used in any case. This annoys gcc. arch/x86/kernel/acpi/boot.c: In function ‘acpi_parse_x2apic’: arch/x86/kernel/acpi/boot.c:203:5: warning: variable ‘enabled’ set but not used [-Wunused-but-set-variable] u8 enabled; ^~~~~~~ arch/x86/kernel/acpi/boot.c:202:6: warning: variable ‘apic_id’ set but not used [-Wunused-but-set-variable] int apic_id; ^~~~~~~ Re-arrange the code to avoid compiling unused variables. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- arch/x86/kernel/acpi/boot.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 7491e73d9253..27f0240773b3 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -199,8 +199,10 @@ static int __init acpi_parse_x2apic(struct acpi_subtable_header *header, const unsigned long end) { struct acpi_madt_local_x2apic *processor = NULL; +#ifdef CONFIG_X86_X2APIC int apic_id; u8 enabled; +#endif processor = (struct acpi_madt_local_x2apic *)header; @@ -209,9 +211,10 @@ acpi_parse_x2apic(struct acpi_subtable_header *header, const unsigned long end) acpi_table_print_madt_entry(header); +#ifdef CONFIG_X86_X2APIC apic_id = processor->local_apic_id; enabled = processor->lapic_flags & ACPI_MADT_ENABLED; -#ifdef CONFIG_X86_X2APIC + /* * We need to register disabled CPU as well to permit * counting disabled CPUs. This allows us to size -- cgit From 6c9a58e84e59a2fc937798b623f72ae4b436547d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Jul 2017 18:04:17 +0300 Subject: ACPI / boot: Correct address space of __acpi_map_table() Sparse complains about wrong address space used in __acpi_map_table() and in __acpi_unmap_table(). arch/x86/kernel/acpi/boot.c:127:29: warning: incorrect type in return expression (different address spaces) arch/x86/kernel/acpi/boot.c:127:29: expected char * arch/x86/kernel/acpi/boot.c:127:29: got void [noderef] * arch/x86/kernel/acpi/boot.c:135:23: warning: incorrect type in argument 1 (different address spaces) arch/x86/kernel/acpi/boot.c:135:23: expected void [noderef] *addr arch/x86/kernel/acpi/boot.c:135:23: got char *map Correct address space to be in align of type of returned and passed parameter. Reviewed-by: Hanjun Guo Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- arch/arm64/kernel/acpi.c | 4 ++-- arch/ia64/kernel/acpi.c | 6 +++--- arch/x86/kernel/acpi/boot.c | 4 ++-- include/linux/acpi.h | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index e25c11e727fe..b3162715ed78 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -95,7 +95,7 @@ static int __init dt_scan_depth1_nodes(unsigned long node, * __acpi_map_table() will be called before page_init(), so early_ioremap() * or early_memremap() should be called here to for ACPI table mapping. */ -char *__init __acpi_map_table(unsigned long phys, unsigned long size) +void __init __iomem *__acpi_map_table(unsigned long phys, unsigned long size) { if (!size) return NULL; @@ -103,7 +103,7 @@ char *__init __acpi_map_table(unsigned long phys, unsigned long size) return early_memremap(phys, size); } -void __init __acpi_unmap_table(char *map, unsigned long size) +void __init __acpi_unmap_table(void __iomem *map, unsigned long size) { if (!map || !size) return; diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 7508c306aa9e..1d29b2f8726b 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -159,12 +159,12 @@ int acpi_request_vector(u32 int_type) return vector; } -char *__init __acpi_map_table(unsigned long phys_addr, unsigned long size) +void __init __iomem *__acpi_map_table(unsigned long phys, unsigned long size) { - return __va(phys_addr); + return __va(phys); } -void __init __acpi_unmap_table(char *map, unsigned long size) +void __init __acpi_unmap_table(void __iomem *map, unsigned long size) { } diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 27f0240773b3..666dcc3e14e1 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -118,7 +118,7 @@ static u32 isa_irq_to_gsi[NR_IRQS_LEGACY] __read_mostly = { * This is just a simple wrapper around early_ioremap(), * with sanity checks for phys == 0 and size == 0. */ -char *__init __acpi_map_table(unsigned long phys, unsigned long size) +void __init __iomem *__acpi_map_table(unsigned long phys, unsigned long size) { if (!phys || !size) @@ -127,7 +127,7 @@ char *__init __acpi_map_table(unsigned long phys, unsigned long size) return early_ioremap(phys, size); } -void __init __acpi_unmap_table(char *map, unsigned long size) +void __init __acpi_unmap_table(void __iomem *map, unsigned long size) { if (!map || !size) return; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index c749eef1daa1..7443af1d16e7 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -228,8 +228,8 @@ struct acpi_subtable_proc { int count; }; -char * __acpi_map_table (unsigned long phys_addr, unsigned long size); -void __acpi_unmap_table(char *map, unsigned long size); +void __iomem *__acpi_map_table(unsigned long phys, unsigned long size); +void __acpi_unmap_table(void __iomem *map, unsigned long size); int early_acpi_boot_init(void); int acpi_boot_init (void); void acpi_boot_table_init (void); -- cgit From 42d516ce3414b46fae5cb74cf180606588d2777f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Jul 2017 18:04:18 +0300 Subject: ACPI / boot: Add number of legacy IRQs to debug output Sometimes it's useful to have that when mp_config_acpi_legacy_irqs() is called. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- arch/x86/kernel/acpi/boot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 666dcc3e14e1..fc639c156da3 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1086,7 +1086,7 @@ static void __init mp_config_acpi_legacy_irqs(void) mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA; #endif set_bit(MP_ISA_BUS, mp_bus_not_pci); - pr_debug("Bus #%d is ISA\n", MP_ISA_BUS); + pr_debug("Bus #%d is ISA (nIRQs: %d)\n", MP_ISA_BUS, nr_legacy_irqs()); /* * Use the default configuration for the IRQs 0-15. Unless -- cgit From b8a15eba99872206fa7b6c75e59e8272d1b4cfbb Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Thu, 20 Jul 2017 12:13:24 -0700 Subject: MAINTAINERS: device property: ACPI: add fwnode.h ACPI is impacted by changes to fwnode.h, add a file entry to ACPI Signed-off-by: Frank Rowand Signed-off-by: Rafael J. Wysocki --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index f66488dfdbc9..fc35558ce310 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -301,6 +301,7 @@ S: Supported F: drivers/acpi/ F: drivers/pnp/pnpacpi/ F: include/linux/acpi.h +F: include/linux/fwnode.h F: include/acpi/ F: Documentation/acpi/ F: Documentation/ABI/testing/sysfs-bus-acpi -- cgit From a06f29b2866ce4418154d6cb955e35899c554066 Mon Sep 17 00:00:00 2001 From: Sumeet Pawnikar Date: Sat, 22 Jul 2017 00:14:42 +0530 Subject: ACPI / lpat: Fix typos in comments and kerneldoc style This patch fix the typos in function header of acpi_lpat_raw_to_temp and acpi_lpat_temp_to_raw. Signed-off-by: Sumeet Pawnikar Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_lpat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpi_lpat.c b/drivers/acpi/acpi_lpat.c index c1c4877ca96c..2cd9f738812b 100644 --- a/drivers/acpi/acpi_lpat.c +++ b/drivers/acpi/acpi_lpat.c @@ -25,7 +25,7 @@ * @raw: the raw value, used as a key to get the temerature from the * above mapping table * - * A positive converted temperarure value will be returned on success, + * A positive converted temperature value will be returned on success, * a negative errno will be returned in error cases. */ int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table, @@ -55,11 +55,11 @@ EXPORT_SYMBOL_GPL(acpi_lpat_raw_to_temp); * acpi_lpat_temp_to_raw(): Return raw value from temperature through * LPAT conversion table * - * @lpat: the temperature_raw mapping table + * @lpat_table: the temperature_raw mapping table * @temp: the temperature, used as a key to get the raw value from the * above mapping table * - * A positive converted temperature value will be returned on success, + * The raw value will be returned on success, * a negative errno will be returned in error cases. */ int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table, -- cgit From 512bb03f4957b0ea6ebcd82f6d34147fc7f83128 Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Wed, 26 Jul 2017 18:40:12 +0800 Subject: ACPI: processor: use dev_dbg() instead of dev_warn() when CPPC probe failed _CPC is a optinal object for processor device so it's fine for processor devices in DSDT without CPPC data, but when booting the system with CPPC enabled in the kernel but without its support in the firmware, I got lots of warnings on a 64 core system: [ 6.346016] acpi ACPI0007:00: CPPC data invalid or not present [ 6.346028] acpi ACPI0007:01: CPPC data invalid or not present [ 6.346039] acpi ACPI0007:02: CPPC data invalid or not present [ 6.346050] acpi ACPI0007:03: CPPC data invalid or not present [ 6.346063] acpi ACPI0007:04: CPPC data invalid or not present ... [ 6.346737] acpi ACPI0007:3f: CPPC data invalid or not present This isn't much useful and a little bit noise, so switch the dev_warn() to dev_dbg(). Signed-off-by: Hanjun Guo Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 591d1dd3f04e..9d6aff22684e 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -237,7 +237,7 @@ static int __acpi_processor_start(struct acpi_device *device) result = acpi_cppc_processor_probe(pr); if (result && !IS_ENABLED(CONFIG_ACPI_CPU_FREQ_PSS)) - dev_warn(&device->dev, "CPPC data invalid or not present\n"); + dev_dbg(&device->dev, "CPPC data invalid or not present\n"); if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) acpi_processor_power_init(pr); -- cgit From ed3beaa832b31c5b4e4367be87874dd5b5299662 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 28 Jul 2017 09:35:51 +0200 Subject: MAINTAINERS: Add Tony and Boris as ACPI/APEI reviewers Since this piece of the ACPI pile is doing RAS, it is perhaps prudent if we at least paid attention to it and the direction it takes. So add Tony and me as reviewers. Signed-off-by: Borislav Petkov Acked-by: Tony Luck Signed-off-by: Rafael J. Wysocki --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fc35558ce310..24fdab285e18 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -311,6 +311,14 @@ F: drivers/pci/*/*acpi* F: drivers/pci/*/*/*acpi* F: tools/power/acpi/ +ACPI APEI +M: "Rafael J. Wysocki" +M: Len Brown +L: linux-acpi@vger.kernel.org +R: Tony Luck +R: Borislav Petkov +F: drivers/acpi/apei/ + ACPI COMPONENT ARCHITECTURE (ACPICA) M: Robert Moore M: Lv Zheng -- cgit From bdb9458a3382ba745a66be5526d3899103c76eda Mon Sep 17 00:00:00 2001 From: Loc Ho Date: Fri, 21 Jul 2017 11:24:37 -0700 Subject: ACPI: APEI: Enable APEI multiple GHES source to share a single external IRQ X-Gene platforms describe multiple GHES error sources with the same hardware error notification type (external interrupt) and interrupt number. Change the GHES interrupt request to support sharing the same IRQ. This change includs contributions from Tuan Phan . Signed-off-by: Loc Ho Acked-by: Borislav Petkov Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/ghes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index d661d452b238..eed09fc664e8 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -1157,7 +1157,8 @@ static int ghes_probe(struct platform_device *ghes_dev) generic->header.source_id); goto err_edac_unreg; } - rc = request_irq(ghes->irq, ghes_irq_func, 0, "GHES IRQ", ghes); + rc = request_irq(ghes->irq, ghes_irq_func, IRQF_SHARED, + "GHES IRQ", ghes); if (rc) { pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n", generic->header.source_id); -- cgit From baecc470d5fd6e2d94eb2a7e242ba291ac7182ac Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Jul 2017 14:38:08 +0200 Subject: PCI / PM: Skip bridges in pci_enable_wake() PCI bridges only have a reason to generate wakeup signals on behalf of devices below them, so avoid preparing bridges for wakeup directly in pci_enable_wake(). Also drop the pci_has_subordinate() check from pci_pm_default_resume() as this will be done by pci_enable_wake() itself now. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg Acked-by: Bjorn Helgaas --- drivers/pci/pci-driver.c | 4 +--- drivers/pci/pci.c | 7 +++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index d51e8738f9c2..e426f8b44c92 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -647,9 +647,7 @@ static int pci_legacy_resume(struct device *dev) static void pci_pm_default_resume(struct pci_dev *pci_dev) { pci_fixup_device(pci_fixup_resume, pci_dev); - - if (!pci_has_subordinate(pci_dev)) - pci_enable_wake(pci_dev, PCI_D0, false); + pci_enable_wake(pci_dev, PCI_D0, false); } static void pci_pm_default_suspend(struct pci_dev *pci_dev) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index af0cc3456dc1..0d142031ebfb 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1912,6 +1912,13 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) { int ret = 0; + /* + * Bridges can only signal wakeup on behalf of subordinate devices, + * but that is set up elsewhere, so skip them. + */ + if (pci_has_subordinate(dev)) + return 0; + /* Don't do the same thing twice in a row for one device. */ if (!!enable == !!dev->wakeup_prepared) return 0; -- cgit From 99d8845e756cb91e2865f430401d084cd6a8ccc9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Jul 2017 14:40:49 +0200 Subject: ACPI / PM: Split acpi_device_wakeup() To prepare for a subsequent change and make the code somewhat easier to follow, do the following in the ACPI device wakeup handling code: * Replace wakeup.flags.enabled under struct acpi_device with wakeup.enable_count as that will be necessary going forward. For now, wakeup.enable_count is not allowed to grow beyond 1, so the current behavior is retained. * Split acpi_device_wakeup() into acpi_device_wakeup_enable() and acpi_device_wakeup_disable() and modify the callers of it accordingly. * Introduce a new acpi_wakeup_lock mutex to protect the wakeup enabling/disabling code from races in case it is executed more than once in parallel for the same device (which may happen for bridges theoretically). Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg --- drivers/acpi/device_pm.c | 121 +++++++++++++++++++++++++++++++---------------- include/acpi/acpi_bus.h | 2 +- 2 files changed, 80 insertions(+), 43 deletions(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 2ed6935d4483..4cd4bdab053d 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -682,47 +682,74 @@ static void acpi_pm_notify_work_func(struct acpi_device_wakeup_context *context) } } +static DEFINE_MUTEX(acpi_wakeup_lock); + /** - * acpi_device_wakeup - Enable/disable wakeup functionality for device. - * @adev: ACPI device to enable/disable wakeup functionality for. + * acpi_device_wakeup_enable - Enable wakeup functionality for device. + * @adev: ACPI device to enable wakeup functionality for. * @target_state: State the system is transitioning into. - * @enable: Whether to enable or disable the wakeup functionality. * - * Enable/disable the GPE associated with @adev so that it can generate - * wakeup signals for the device in response to external (remote) events and - * enable/disable device wakeup power. + * Enable the GPE associated with @adev so that it can generate wakeup signals + * for the device in response to external (remote) events and enable wakeup + * power for it. * * Callers must ensure that @adev is a valid ACPI device node before executing * this function. */ -static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state, - bool enable) +static int acpi_device_wakeup_enable(struct acpi_device *adev, u32 target_state) { struct acpi_device_wakeup *wakeup = &adev->wakeup; + acpi_status status; + int error = 0; - if (enable) { - acpi_status res; - int error; + mutex_lock(&acpi_wakeup_lock); - if (adev->wakeup.flags.enabled) - return 0; + if (wakeup->enable_count > 0) + goto out; - error = acpi_enable_wakeup_device_power(adev, target_state); - if (error) - return error; + error = acpi_enable_wakeup_device_power(adev, target_state); + if (error) + goto out; - res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number); - if (ACPI_FAILURE(res)) { - acpi_disable_wakeup_device_power(adev); - return -EIO; - } - adev->wakeup.flags.enabled = 1; - } else if (adev->wakeup.flags.enabled) { - acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number); + status = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number); + if (ACPI_FAILURE(status)) { acpi_disable_wakeup_device_power(adev); - adev->wakeup.flags.enabled = 0; + error = -EIO; + goto out; } - return 0; + + wakeup->enable_count++; + +out: + mutex_unlock(&acpi_wakeup_lock); + return error; +} + +/** + * acpi_device_wakeup_disable - Disable wakeup functionality for device. + * @adev: ACPI device to disable wakeup functionality for. + * + * Disable the GPE associated with @adev and disable wakeup power for it. + * + * Callers must ensure that @adev is a valid ACPI device node before executing + * this function. + */ +static void acpi_device_wakeup_disable(struct acpi_device *adev) +{ + struct acpi_device_wakeup *wakeup = &adev->wakeup; + + mutex_lock(&acpi_wakeup_lock); + + if (!wakeup->enable_count) + goto out; + + acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number); + acpi_disable_wakeup_device_power(adev); + + wakeup->enable_count--; + +out: + mutex_unlock(&acpi_wakeup_lock); } /** @@ -744,9 +771,15 @@ int acpi_pm_set_device_wakeup(struct device *dev, bool enable) if (!acpi_device_can_wakeup(adev)) return -EINVAL; - error = acpi_device_wakeup(adev, acpi_target_system_state(), enable); + if (!enable) { + acpi_device_wakeup_disable(adev); + dev_dbg(dev, "Wakeup disabled by ACPI\n"); + return 0; + } + + error = acpi_device_wakeup_enable(adev, acpi_target_system_state()); if (!error) - dev_dbg(dev, "Wakeup %s by ACPI\n", enable ? "enabled" : "disabled"); + dev_dbg(dev, "Wakeup enabled by ACPI\n"); return error; } @@ -800,13 +833,15 @@ int acpi_dev_runtime_suspend(struct device *dev) remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) > PM_QOS_FLAGS_NONE; - error = acpi_device_wakeup(adev, ACPI_STATE_S0, remote_wakeup); - if (remote_wakeup && error) - return -EAGAIN; + if (remote_wakeup) { + error = acpi_device_wakeup_enable(adev, ACPI_STATE_S0); + if (error) + return -EAGAIN; + } error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0); - if (error) - acpi_device_wakeup(adev, ACPI_STATE_S0, false); + if (error && remote_wakeup) + acpi_device_wakeup_disable(adev); return error; } @@ -829,7 +864,7 @@ int acpi_dev_runtime_resume(struct device *dev) return 0; error = acpi_dev_pm_full_power(adev); - acpi_device_wakeup(adev, ACPI_STATE_S0, false); + acpi_device_wakeup_disable(adev); return error; } EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume); @@ -884,13 +919,15 @@ int acpi_dev_suspend_late(struct device *dev) target_state = acpi_target_system_state(); wakeup = device_may_wakeup(dev) && acpi_device_can_wakeup(adev); - error = acpi_device_wakeup(adev, target_state, wakeup); - if (wakeup && error) - return error; + if (wakeup) { + error = acpi_device_wakeup_enable(adev, target_state); + if (error) + return error; + } error = acpi_dev_pm_low_power(dev, adev, target_state); - if (error) - acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false); + if (error && wakeup) + acpi_device_wakeup_disable(adev); return error; } @@ -913,7 +950,7 @@ int acpi_dev_resume_early(struct device *dev) return 0; error = acpi_dev_pm_full_power(adev); - acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false); + acpi_device_wakeup_disable(adev); return error; } EXPORT_SYMBOL_GPL(acpi_dev_resume_early); @@ -1056,7 +1093,7 @@ static void acpi_dev_pm_detach(struct device *dev, bool power_off) */ dev_pm_qos_hide_latency_limit(dev); dev_pm_qos_hide_flags(dev); - acpi_device_wakeup(adev, ACPI_STATE_S0, false); + acpi_device_wakeup_disable(adev); acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0); } } @@ -1100,7 +1137,7 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) dev_pm_domain_set(dev, &acpi_general_pm_domain); if (power_on) { acpi_dev_pm_full_power(adev); - acpi_device_wakeup(adev, ACPI_STATE_S0, false); + acpi_device_wakeup_disable(adev); } dev->pm_domain->detach = acpi_dev_pm_detach; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 68bc6be447fd..b7df95dbe7e9 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -316,7 +316,6 @@ struct acpi_device_perf { struct acpi_device_wakeup_flags { u8 valid:1; /* Can successfully enable wakeup? */ u8 notifier_present:1; /* Wake-up notify handler has been installed */ - u8 enabled:1; /* Enabled for wakeup */ }; struct acpi_device_wakeup_context { @@ -333,6 +332,7 @@ struct acpi_device_wakeup { struct acpi_device_wakeup_context context; struct wakeup_source *ws; int prepare_count; + int enable_count; }; struct acpi_device_physical_node { -- cgit From 1ba51a7c1496fd8f6d5bdd58dafcb1894275b7f0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 1 Aug 2017 02:56:18 +0200 Subject: ACPI / PCI / PM: Rework acpi_pci_propagate_wakeup() The acpi_pci_propagate_wakeup() routine is there to handle cases in which PCI bridges (or PCIe ports) are expected to signal wakeup for devices below them, but currently it doesn't do that correctly. The problem is that acpi_pci_propagate_wakeup() uses acpi_pm_set_device_wakeup() for bridges and if that routine is called for multiple times to disable wakeup for the same device, it will disable it on the first invocation and the next calls will have no effect (it works analogously when called to enable wakeup, but that is not a problem). Now, say acpi_pci_propagate_wakeup() has been called for two different devices under the same bridge and it has called acpi_pm_set_device_wakeup() for that bridge each time. The bridge is now enabled to generate wakeup signals. Next, suppose that one of the devices below it resumes and acpi_pci_propagate_wakeup() is called to disable wakeup for that device. It will then call acpi_pm_set_device_wakeup() for the bridge and that will effectively disable remote wakeup for all devices under it even though some of them may still be suspended and remote wakeup may be expected to work for them. To address this (arguably theoretical) issue, allow wakeup.enable_count under struct acpi_device to grow beyond 1 in certain situations. In particular, allow that to happen in acpi_pci_propagate_wakeup() when wakeup is enabled or disabled for PCI bridges, so that wakeup is actually disabled for the bridge when all devices under it resume and not when just one of them does that. Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Reviewed-by: Mika Westerberg Acked-by: Bjorn Helgaas --- drivers/acpi/device_pm.c | 72 +++++++++++++++++++++++++++++++++--------------- drivers/pci/pci-acpi.c | 4 +-- include/acpi/acpi_bus.h | 5 ++++ 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 4cd4bdab053d..112fd6c55c2c 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -684,19 +684,8 @@ static void acpi_pm_notify_work_func(struct acpi_device_wakeup_context *context) static DEFINE_MUTEX(acpi_wakeup_lock); -/** - * acpi_device_wakeup_enable - Enable wakeup functionality for device. - * @adev: ACPI device to enable wakeup functionality for. - * @target_state: State the system is transitioning into. - * - * Enable the GPE associated with @adev so that it can generate wakeup signals - * for the device in response to external (remote) events and enable wakeup - * power for it. - * - * Callers must ensure that @adev is a valid ACPI device node before executing - * this function. - */ -static int acpi_device_wakeup_enable(struct acpi_device *adev, u32 target_state) +static int __acpi_device_wakeup_enable(struct acpi_device *adev, + u32 target_state, int max_count) { struct acpi_device_wakeup *wakeup = &adev->wakeup; acpi_status status; @@ -704,9 +693,12 @@ static int acpi_device_wakeup_enable(struct acpi_device *adev, u32 target_state) mutex_lock(&acpi_wakeup_lock); - if (wakeup->enable_count > 0) + if (wakeup->enable_count >= max_count) goto out; + if (wakeup->enable_count > 0) + goto inc; + error = acpi_enable_wakeup_device_power(adev, target_state); if (error) goto out; @@ -718,6 +710,7 @@ static int acpi_device_wakeup_enable(struct acpi_device *adev, u32 target_state) goto out; } +inc: wakeup->enable_count++; out: @@ -725,6 +718,23 @@ out: return error; } +/** + * acpi_device_wakeup_enable - Enable wakeup functionality for device. + * @adev: ACPI device to enable wakeup functionality for. + * @target_state: State the system is transitioning into. + * + * Enable the GPE associated with @adev so that it can generate wakeup signals + * for the device in response to external (remote) events and enable wakeup + * power for it. + * + * Callers must ensure that @adev is a valid ACPI device node before executing + * this function. + */ +static int acpi_device_wakeup_enable(struct acpi_device *adev, u32 target_state) +{ + return __acpi_device_wakeup_enable(adev, target_state, 1); +} + /** * acpi_device_wakeup_disable - Disable wakeup functionality for device. * @adev: ACPI device to disable wakeup functionality for. @@ -752,12 +762,8 @@ out: mutex_unlock(&acpi_wakeup_lock); } -/** - * acpi_pm_set_device_wakeup - Enable/disable remote wakeup for given device. - * @dev: Device to enable/disable to generate wakeup events. - * @enable: Whether to enable or disable the wakeup functionality. - */ -int acpi_pm_set_device_wakeup(struct device *dev, bool enable) +static int __acpi_pm_set_device_wakeup(struct device *dev, bool enable, + int max_count) { struct acpi_device *adev; int error; @@ -777,13 +783,35 @@ int acpi_pm_set_device_wakeup(struct device *dev, bool enable) return 0; } - error = acpi_device_wakeup_enable(adev, acpi_target_system_state()); + error = __acpi_device_wakeup_enable(adev, acpi_target_system_state(), + max_count); if (!error) dev_dbg(dev, "Wakeup enabled by ACPI\n"); return error; } -EXPORT_SYMBOL(acpi_pm_set_device_wakeup); + +/** + * acpi_pm_set_device_wakeup - Enable/disable remote wakeup for given device. + * @dev: Device to enable/disable to generate wakeup events. + * @enable: Whether to enable or disable the wakeup functionality. + */ +int acpi_pm_set_device_wakeup(struct device *dev, bool enable) +{ + return __acpi_pm_set_device_wakeup(dev, enable, 1); +} +EXPORT_SYMBOL_GPL(acpi_pm_set_device_wakeup); + +/** + * acpi_pm_set_bridge_wakeup - Enable/disable remote wakeup for given bridge. + * @dev: Bridge device to enable/disable to generate wakeup events. + * @enable: Whether to enable or disable the wakeup functionality. + */ +int acpi_pm_set_bridge_wakeup(struct device *dev, bool enable) +{ + return __acpi_pm_set_device_wakeup(dev, enable, INT_MAX); +} +EXPORT_SYMBOL_GPL(acpi_pm_set_bridge_wakeup); /** * acpi_dev_pm_low_power - Put ACPI device into a low-power state. diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index e70c1c7ba1bf..a8da543b3814 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -573,7 +573,7 @@ static int acpi_pci_propagate_wakeup(struct pci_bus *bus, bool enable) { while (bus->parent) { if (acpi_pm_device_can_wakeup(&bus->self->dev)) - return acpi_pm_set_device_wakeup(&bus->self->dev, enable); + return acpi_pm_set_bridge_wakeup(&bus->self->dev, enable); bus = bus->parent; } @@ -581,7 +581,7 @@ static int acpi_pci_propagate_wakeup(struct pci_bus *bus, bool enable) /* We have reached the root bus. */ if (bus->bridge) { if (acpi_pm_device_can_wakeup(bus->bridge)) - return acpi_pm_set_device_wakeup(bus->bridge, enable); + return acpi_pm_set_bridge_wakeup(bus->bridge, enable); } return 0; } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index b7df95dbe7e9..de7e8ac9d806 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -606,6 +606,7 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev); bool acpi_pm_device_can_wakeup(struct device *dev); int acpi_pm_device_sleep_state(struct device *, int *, int); int acpi_pm_set_device_wakeup(struct device *dev, bool enable); +int acpi_pm_set_bridge_wakeup(struct device *dev, bool enable); #else static inline void acpi_pm_wakeup_event(struct device *dev) { @@ -636,6 +637,10 @@ static inline int acpi_pm_set_device_wakeup(struct device *dev, bool enable) { return -ENODEV; } +static inline int acpi_pm_set_bridge_wakeup(struct device *dev, bool enable) +{ + return -ENODEV; +} #endif #ifdef CONFIG_ACPI_SLEEP -- cgit From a042e0c62b38e7bb8b5edadc46c2ff23d1091111 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 31 Jul 2017 11:40:13 +0200 Subject: ACPI / sleep: Make acpi_sleep_syscore_init() static Function acpi_sleep_syscore_init has no external user so it should be static. Signed-off-by: Jean Delvare Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index fa8243c5c062..dd5f21ca483e 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -870,7 +870,7 @@ static struct syscore_ops acpi_sleep_syscore_ops = { .resume = acpi_restore_bm_rld, }; -void acpi_sleep_syscore_init(void) +static void acpi_sleep_syscore_init(void) { register_syscore_ops(&acpi_sleep_syscore_ops); } -- cgit From 630b3aff8a51c90ef15b59c9560ac35e40e7ec09 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Tue, 1 Aug 2017 14:10:41 +0200 Subject: treewide: Consolidate Apple DMI checks We're about to amend ACPI bus scan with DMI checks whether we're running on a Mac to support Apple device properties in AML. The DMI checks are performed for every single device, adding overhead for everything x86 that isn't Apple, which is the majority. Rafael and Andy therefore request to perform the DMI match only once and cache the result. Outside of ACPI various other Apple DMI checks exist and it seems reasonable to use the cached value there as well. Rafael, Andy and Darren suggest performing the DMI check in arch code and making it available with a header in include/linux/platform_data/x86/. To this end, add early_platform_quirks() to arch/x86/kernel/quirks.c to perform the DMI check and invoke it from setup_arch(). Switch over all existing Apple DMI checks, thereby fixing two deficiencies: * They are now #defined to false on non-x86 arches and can thus be optimized away if they're located in cross-arch code. * Some of them only match "Apple Inc." but not "Apple Computer, Inc.", which is used by BIOSes released between January 2006 (when the first x86 Macs started shipping) and January 2007 (when the company name changed upon introduction of the iPhone). Suggested-by: Andy Shevchenko Suggested-by: Rafael J. Wysocki Suggested-by: Darren Hart Signed-off-by: Lukas Wunner Acked-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- arch/x86/include/asm/setup.h | 1 + arch/x86/kernel/early-quirks.c | 4 ++-- arch/x86/kernel/quirks.c | 10 +++++++++ arch/x86/kernel/setup.c | 2 ++ drivers/acpi/osi.c | 37 +++++++-------------------------- drivers/acpi/pci_root.c | 4 ++-- drivers/acpi/sbs.c | 25 ++-------------------- drivers/firmware/efi/apple-properties.c | 5 ++--- drivers/pci/quirks.c | 5 +++-- drivers/thunderbolt/icm.c | 13 ++++-------- drivers/thunderbolt/tb.c | 4 ++-- include/linux/platform_data/x86/apple.h | 13 ++++++++++++ 12 files changed, 51 insertions(+), 72 deletions(-) create mode 100644 include/linux/platform_data/x86/apple.h diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index e4585a393965..a65cf544686a 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -39,6 +39,7 @@ static inline void vsmp_init(void) { } #endif void setup_bios_corruption_check(void); +void early_platform_quirks(void); extern unsigned long saved_video_mode; diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index d907c3d8633f..a70a65ae798a 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -12,10 +12,10 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -593,7 +593,7 @@ static void __init apple_airport_reset(int bus, int slot, int func) u64 addr; int i; - if (!dmi_match(DMI_SYS_VENDOR, "Apple Inc.")) + if (!x86_apple_machine) return; /* Card may have been put into PCI_D3hot by grub quirk */ diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 0bee04d41bed..eaa591cfd98b 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c @@ -1,6 +1,7 @@ /* * This file contains work-arounds for x86 and x86_64 platform bugs. */ +#include #include #include @@ -656,3 +657,12 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, quirk_intel_brickland_xeon_ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2083, quirk_intel_purley_xeon_ras_cap); #endif #endif + +bool x86_apple_machine; +EXPORT_SYMBOL(x86_apple_machine); + +void __init early_platform_quirks(void) +{ + x86_apple_machine = dmi_match(DMI_SYS_VENDOR, "Apple Inc.") || + dmi_match(DMI_SYS_VENDOR, "Apple Computer, Inc."); +} diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 3486d0498800..77b3c3af7cba 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1206,6 +1206,8 @@ void __init setup_arch(char **cmdline_p) io_delay_init(); + early_platform_quirks(); + /* * Parse the ACPI tables for possible boot-time SMP configuration. */ diff --git a/drivers/acpi/osi.c b/drivers/acpi/osi.c index 723bee58bbcf..19cdd8a783a9 100644 --- a/drivers/acpi/osi.c +++ b/drivers/acpi/osi.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "internal.h" @@ -257,12 +258,11 @@ bool acpi_osi_is_win8(void) } EXPORT_SYMBOL(acpi_osi_is_win8); -static void __init acpi_osi_dmi_darwin(bool enable, - const struct dmi_system_id *d) +static void __init acpi_osi_dmi_darwin(void) { - pr_notice("DMI detected to setup _OSI(\"Darwin\"): %s\n", d->ident); + pr_notice("DMI detected to setup _OSI(\"Darwin\"): Apple hardware\n"); osi_config.darwin_dmi = 1; - __acpi_osi_setup_darwin(enable); + __acpi_osi_setup_darwin(true); } static void __init acpi_osi_dmi_linux(bool enable, @@ -273,13 +273,6 @@ static void __init acpi_osi_dmi_linux(bool enable, __acpi_osi_setup_linux(enable); } -static int __init dmi_enable_osi_darwin(const struct dmi_system_id *d) -{ - acpi_osi_dmi_darwin(true, d); - - return 0; -} - static int __init dmi_enable_osi_linux(const struct dmi_system_id *d) { acpi_osi_dmi_linux(true, d); @@ -481,30 +474,16 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "1015PX"), }, }, - - /* - * Enable _OSI("Darwin") for all apple platforms. - */ - { - .callback = dmi_enable_osi_darwin, - .ident = "Apple hardware", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - }, - }, - { - .callback = dmi_enable_osi_darwin, - .ident = "Apple hardware", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."), - }, - }, {} }; static __init void acpi_osi_dmi_blacklisted(void) { dmi_check_system(acpi_osi_dmi_table); + + /* Enable _OSI("Darwin") for Apple platforms. */ + if (x86_apple_machine) + acpi_osi_dmi_darwin(); } int __init early_acpi_osi_init(void) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 9eec3095e6c3..6fc204a52493 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -33,6 +33,7 @@ #include #include #include +#include #include /* for acpi_hest_init() */ #include "internal.h" @@ -431,8 +432,7 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) * been called successfully. We know the feature set supported by the * platform, so avoid calling _OSC at all */ - - if (dmi_match(DMI_SYS_VENDOR, "Apple Inc.")) { + if (x86_apple_machine) { root->osc_control_set = ~OSC_PCI_EXPRESS_PME_CONTROL; decode_osc_control(root, "OS assumes control of", root->osc_control_set); diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index ad0b13ad4bbb..a18463799ad7 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include "sbshc.h" #include "battery.h" @@ -58,8 +58,6 @@ static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); -static bool sbs_manager_broken; - #define MAX_SBS_BAT 4 #define ACPI_SBS_BLOCK_MAX 32 @@ -632,31 +630,12 @@ static void acpi_sbs_callback(void *context) } } -static int disable_sbs_manager(const struct dmi_system_id *d) -{ - sbs_manager_broken = true; - return 0; -} - -static struct dmi_system_id acpi_sbs_dmi_table[] = { - { - .callback = disable_sbs_manager, - .ident = "Apple", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc.") - }, - }, - { }, -}; - static int acpi_sbs_add(struct acpi_device *device) { struct acpi_sbs *sbs; int result = 0; int id; - dmi_check_system(acpi_sbs_dmi_table); - sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL); if (!sbs) { result = -ENOMEM; @@ -677,7 +656,7 @@ static int acpi_sbs_add(struct acpi_device *device) result = 0; - if (!sbs_manager_broken) { + if (!x86_apple_machine) { result = acpi_manager_get_info(sbs); if (!result) { sbs->manager_present = 1; diff --git a/drivers/firmware/efi/apple-properties.c b/drivers/firmware/efi/apple-properties.c index c473f4c5ca34..9f6bcf173b0e 100644 --- a/drivers/firmware/efi/apple-properties.c +++ b/drivers/firmware/efi/apple-properties.c @@ -18,8 +18,8 @@ #define pr_fmt(fmt) "apple-properties: " fmt #include -#include #include +#include #include #include #include @@ -191,8 +191,7 @@ static int __init map_properties(void) u64 pa_data; int ret; - if (!dmi_match(DMI_SYS_VENDOR, "Apple Inc.") && - !dmi_match(DMI_SYS_VENDOR, "Apple Computer, Inc.")) + if (!x86_apple_machine) return 0; pa_data = boot_params.hdr.setup_data; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 6967c6b4cf6b..ba7b7c64379e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -25,6 +25,7 @@ #include #include #include +#include #include /* isa_dma_bridge_buggy */ #include "pci.h" @@ -3447,7 +3448,7 @@ static void quirk_apple_poweroff_thunderbolt(struct pci_dev *dev) { acpi_handle bridge, SXIO, SXFP, SXLV; - if (!dmi_match(DMI_BOARD_VENDOR, "Apple Inc.")) + if (!x86_apple_machine) return; if (pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM) return; @@ -3492,7 +3493,7 @@ static void quirk_apple_wait_for_thunderbolt(struct pci_dev *dev) struct pci_dev *sibling = NULL; struct pci_dev *nhi = NULL; - if (!dmi_match(DMI_BOARD_VENDOR, "Apple Inc.")) + if (!x86_apple_machine) return; if (pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM) return; diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index 8ee340290219..17eba072e1ed 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -13,9 +13,9 @@ */ #include -#include #include #include +#include #include #include #include @@ -102,11 +102,6 @@ static inline u64 get_route(u32 route_hi, u32 route_lo) return (u64)route_hi << 32 | route_lo; } -static inline bool is_apple(void) -{ - return dmi_match(DMI_BOARD_VENDOR, "Apple Inc."); -} - static bool icm_match(const struct tb_cfg_request *req, const struct ctl_pkg *pkg) { @@ -176,7 +171,7 @@ static int icm_request(struct tb *tb, const void *request, size_t request_size, static bool icm_fr_is_supported(struct tb *tb) { - return !is_apple(); + return !x86_apple_machine; } static inline int icm_fr_get_switch_index(u32 port) @@ -517,7 +512,7 @@ static bool icm_ar_is_supported(struct tb *tb) * Starting from Alpine Ridge we can use ICM on Apple machines * as well. We just need to reset and re-enable it first. */ - if (!is_apple()) + if (!x86_apple_machine) return true; /* @@ -1004,7 +999,7 @@ static int icm_start(struct tb *tb) * don't provide images publicly either. To be on the safe side * prevent root switch NVM upgrade on Macs for now. */ - tb->root_switch->no_nvm_upgrade = is_apple(); + tb->root_switch->no_nvm_upgrade = x86_apple_machine; ret = tb_switch_add(tb->root_switch); if (ret) diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 1b02ca0b6129..0b22ad9d68b4 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "tb.h" #include "tb_regs.h" @@ -453,7 +453,7 @@ struct tb *tb_probe(struct tb_nhi *nhi) struct tb_cm *tcm; struct tb *tb; - if (!dmi_match(DMI_BOARD_VENDOR, "Apple Inc.")) + if (!x86_apple_machine) return NULL; tb = tb_domain_alloc(nhi, sizeof(*tcm)); diff --git a/include/linux/platform_data/x86/apple.h b/include/linux/platform_data/x86/apple.h new file mode 100644 index 000000000000..079e816c3c21 --- /dev/null +++ b/include/linux/platform_data/x86/apple.h @@ -0,0 +1,13 @@ +#ifndef PLATFORM_DATA_X86_APPLE_H +#define PLATFORM_DATA_X86_APPLE_H + +#ifdef CONFIG_X86 +/** + * x86_apple_machine - whether the machine is an x86 Apple Macintosh + */ +extern bool x86_apple_machine; +#else +#define x86_apple_machine false +#endif + +#endif -- cgit From 75fc70e07314347465c7df6d6b79535cf3db0e2a Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Tue, 1 Aug 2017 14:10:41 +0200 Subject: ACPI / property: Don't evaluate objects for devices w/o handle Fabricated devices such as LNXPWRBN lack a handle, causing evaluation of _CCA and _DSD to always fail with AE_BAD_PARAMETER. While that is merely a (negligible) waste of processing power, evaluating a _DSM for them (such as Apple's device properties _DSM which we're about to add) results in an ugly error: ACPI: \: failed to evaluate _DSM (0x1001) Avoid by not evaluating _DSD and the upcoming _DSM for devices without handle. Acked-by: Mika Westerberg Signed-off-by: Lukas Wunner Signed-off-by: Rafael J. Wysocki --- drivers/acpi/property.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 917c789f953d..116bfc1937b5 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -339,6 +339,9 @@ void acpi_init_properties(struct acpi_device *adev) INIT_LIST_HEAD(&adev->data.subnodes); + if (!adev->handle) + return; + /* * Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in * Device Tree compatible properties for this device. -- cgit From 899596e090ea21918c55cbccea594be840af44ea Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Tue, 1 Aug 2017 14:10:41 +0200 Subject: ACPI / property: Support Apple _DSM properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While the rest of the world has standardized on _DSD as the way to store device properties in AML (introduced with ACPI 5.1 in 2014), Apple has been using a custom _DSM to achieve the same for much longer (ever since they switched from DeviceTree-based PowerPC to Intel in 2005, verified with MacOS X 10.4.11). The theory of operation on macOS is as follows: AppleACPIPlatform.kext invokes mergeEFIproperties() and mergeDSMproperties() for each device to merge properties conveyed by EFI drivers as well as properties stored in AML into the I/O Kit registry from which they can be retrieved by drivers. We've been supporting EFI properties since commit 58c5475aba67 ("x86/efi: Retrieve and assign Apple device properties"). The present commit adds support for _DSM properties, thereby completing our support for Apple device properties. The _DSM properties are made available under the primary fwnode, the EFI properties under the secondary fwnode. So for devices which possess both property types, they can all be elegantly accessed with the uniform API in . Until recently we had no need to support _DSM properties, they contained only uninteresting garbage. The situation has changed with MacBooks and MacBook Pros introduced since 2015: Their keyboard is attached with SPI instead of USB and the _CRS data which is necessary to initialize the spi driver only contains valid information if OSPM responds "false" to _OSI("Darwin"). If OSPM responds "true", _CRS is empty and the spi driver fails to initialize. The rationale is very simple, Apple only cares about macOS and Windows: On Windows, _CRS contains valid data, whereas on macOS it is empty. Instead, macOS gleans the necessary data from the _DSM properties. Since Linux deliberately defaults to responding "true" to _OSI("Darwin"), we need to emulate macOS' behaviour by initializing the spi driver with data returned by the _DSM. An out-of-tree driver for the SPI keyboard exists which currently binds to the ACPI device, invokes the _DSM, parses the returned package and instantiates an SPI device with the data gleaned from the _DSM: https://github.com/cb22/macbook12-spi-driver/commit/9a416d699ef4 https://github.com/cb22/macbook12-spi-driver/commit/0c34936ed9a1 By adding support for Apple's _DSM properties in generic ACPI code, the out-of-tree driver will be able to register as a regular SPI driver, significantly reducing its amount of code and improving its chances to be mainlined. The SPI keyboard will not be the only user of this commit: E.g. on the MacBook8,1, the UART-attached Bluetooth device likewise returns empty _CRS data if OSPM returns "true" to _OSI("Darwin"). The _DSM returns a Package whose format unfortunately deviates slightly from the _DSD spec: The properties are marshalled up in a single Package as alternating key/value elements, unlike _DSD which stores them as a Package of 2-element Packages. The present commit therefore converts the Package to _DSD format and the ACPI core can then treat the data as if Apple would follow the standard. Well, except for one small annoyance: The properties returned by the _DSM only ever have one of two types, Integer or Buffer. The former is retrievable as usual with device_property_read_u64(), but the latter is not part of the _DSD spec and it is not possible to retrieve Buffer properties with the device_property_read_*() functions due to the type checking performed in drivers/acpi/property.c. It is however possible to retrieve them with acpi_dev_get_property(). Apple is using the Buffer type somewhat sloppily to store null-terminated strings but also integers. The real data type is not distinguishable by the ACPI core and the onus is on the caller to use the contents of the Buffer in an appropriate way. In case Apple moves to _DSD in the future, this commit first checks for _DSD and falls back to _DSM only if _DSD is not found. Tested-by: Ronald Tschalär Acked-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Lukas Wunner Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Makefile | 1 + drivers/acpi/internal.h | 6 ++ drivers/acpi/property.c | 3 + drivers/acpi/x86/apple.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 drivers/acpi/x86/apple.c diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index b1aacfc62b1f..90265ab4437a 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -50,6 +50,7 @@ acpi-$(CONFIG_ACPI_REDUCED_HARDWARE_ONLY) += evged.o acpi-y += sysfs.o acpi-y += property.o acpi-$(CONFIG_X86) += acpi_cmos_rtc.o +acpi-$(CONFIG_X86) += x86/apple.o acpi-$(CONFIG_X86) += x86/utils.o acpi-$(CONFIG_DEBUG_FS) += debugfs.o acpi-$(CONFIG_ACPI_NUMA) += numa.o diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 58dd7ab3c653..ee066d74f5bf 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -233,6 +233,12 @@ static inline void suspend_nvs_restore(void) {} void acpi_init_properties(struct acpi_device *adev); void acpi_free_properties(struct acpi_device *adev); +#ifdef CONFIG_X86 +void acpi_extract_apple_properties(struct acpi_device *adev); +#else +static inline void acpi_extract_apple_properties(struct acpi_device *adev) {} +#endif + /*-------------------------------------------------------------------------- Watchdog -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 116bfc1937b5..fc1bb083f5f0 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -376,6 +376,9 @@ void acpi_init_properties(struct acpi_device *adev) if (acpi_of && !adev->flags.of_compatible_ok) acpi_handle_info(adev->handle, ACPI_DT_NAMESPACE_HID " requires 'compatible' property\n"); + + if (!adev->data.pointer) + acpi_extract_apple_properties(adev); } static void acpi_destroy_nondev_subnodes(struct list_head *list) diff --git a/drivers/acpi/x86/apple.c b/drivers/acpi/x86/apple.c new file mode 100644 index 000000000000..51b4cf9f25da --- /dev/null +++ b/drivers/acpi/x86/apple.c @@ -0,0 +1,141 @@ +/* + * apple.c - Apple ACPI quirks + * Copyright (C) 2017 Lukas Wunner + * + * 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 +#include +#include + +/* Apple _DSM device properties GUID */ +static const guid_t apple_prp_guid = + GUID_INIT(0xa0b5b7c6, 0x1318, 0x441c, + 0xb0, 0xc9, 0xfe, 0x69, 0x5e, 0xaf, 0x94, 0x9b); + +/** + * acpi_extract_apple_properties - retrieve and convert Apple _DSM properties + * @adev: ACPI device for which to retrieve the properties + * + * Invoke Apple's custom _DSM once to check the protocol version and once more + * to retrieve the properties. They are marshalled up in a single package as + * alternating key/value elements, unlike _DSD which stores them as a package + * of 2-element packages. Convert to _DSD format and make them available under + * the primary fwnode. + */ +void acpi_extract_apple_properties(struct acpi_device *adev) +{ + unsigned int i, j = 0, newsize = 0, numprops, numvalid; + union acpi_object *props, *newprops; + unsigned long *valid = NULL; + void *free_space; + + if (!x86_apple_machine) + return; + + props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 0, + NULL, ACPI_TYPE_BUFFER); + if (!props) + return; + + if (!props->buffer.length) + goto out_free; + + if (props->buffer.pointer[0] != 3) { + acpi_handle_info(adev->handle, FW_INFO + "unsupported properties version %*ph\n", + props->buffer.length, props->buffer.pointer); + goto out_free; + } + + ACPI_FREE(props); + props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 1, + NULL, ACPI_TYPE_PACKAGE); + if (!props) + return; + + numprops = props->package.count / 2; + if (!numprops) + goto out_free; + + valid = kcalloc(BITS_TO_LONGS(numprops), sizeof(long), GFP_KERNEL); + if (!valid) + goto out_free; + + /* newsize = key length + value length of each tuple */ + for (i = 0; i < numprops; i++) { + union acpi_object *key = &props->package.elements[i * 2]; + union acpi_object *val = &props->package.elements[i * 2 + 1]; + + if ( key->type != ACPI_TYPE_STRING || + (val->type != ACPI_TYPE_INTEGER && + val->type != ACPI_TYPE_BUFFER)) + continue; /* skip invalid properties */ + + __set_bit(i, valid); + newsize += key->string.length + 1; + if ( val->type == ACPI_TYPE_BUFFER) + newsize += val->buffer.length; + } + + numvalid = bitmap_weight(valid, numprops); + if (numprops > numvalid) + acpi_handle_info(adev->handle, FW_INFO + "skipped %u properties: wrong type\n", + numprops - numvalid); + if (numvalid == 0) + goto out_free; + + /* newsize += top-level package + 3 objects for each key/value tuple */ + newsize += (1 + 3 * numvalid) * sizeof(union acpi_object); + newprops = ACPI_ALLOCATE_ZEROED(newsize); + if (!newprops) + goto out_free; + + /* layout: top-level package | packages | key/value tuples | strings */ + newprops->type = ACPI_TYPE_PACKAGE; + newprops->package.count = numvalid; + newprops->package.elements = &newprops[1]; + free_space = &newprops[1 + 3 * numvalid]; + + for_each_set_bit(i, valid, numprops) { + union acpi_object *key = &props->package.elements[i * 2]; + union acpi_object *val = &props->package.elements[i * 2 + 1]; + unsigned int k = 1 + numvalid + j * 2; /* index into newprops */ + unsigned int v = k + 1; + + newprops[1 + j].type = ACPI_TYPE_PACKAGE; + newprops[1 + j].package.count = 2; + newprops[1 + j].package.elements = &newprops[k]; + + newprops[k].type = ACPI_TYPE_STRING; + newprops[k].string.length = key->string.length; + newprops[k].string.pointer = free_space; + memcpy(free_space, key->string.pointer, key->string.length); + free_space += key->string.length + 1; + + newprops[v].type = val->type; + if (val->type == ACPI_TYPE_INTEGER) { + newprops[v].integer.value = val->integer.value; + } else { + newprops[v].buffer.length = val->buffer.length; + newprops[v].buffer.pointer = free_space; + memcpy(free_space, val->buffer.pointer, + val->buffer.length); + free_space += val->buffer.length; + } + j++; /* count valid properties */ + } + WARN_ON(free_space != (void *)newprops + newsize); + + adev->data.properties = newprops; + adev->data.pointer = newprops; + +out_free: + ACPI_FREE(props); + kfree(valid); +} -- cgit From ca9ef3ab68d3530ac93d4254f9e47724ea51758d Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Tue, 1 Aug 2017 14:10:41 +0200 Subject: ACPI / scan: Recognize Apple SPI and I2C slaves MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SPI and I2C slaves are enumerated by their respective parents rather than the ACPI core. They are recognized by presence of _CRS resources, which however are missing on Macs. Check for presence of device properties instead. Reported-and-tested-by: Ronald Tschalär Signed-off-by: Lukas Wunner Acked-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 33897298f03e..55fd248833cd 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -1452,6 +1453,12 @@ static bool acpi_is_spi_i2c_slave(struct acpi_device *device) struct list_head resource_list; bool is_spi_i2c_slave = false; + /* Macs use device properties in lieu of _CRS resources */ + if (x86_apple_machine && + (fwnode_property_present(&device->fwnode, "spiSclkPeriod") || + fwnode_property_present(&device->fwnode, "i2cAddress"))) + return true; + INIT_LIST_HEAD(&resource_list); acpi_dev_get_resources(device, &resource_list, acpi_check_spi_i2c_slave, &is_spi_i2c_slave); -- cgit From 8a2e487e6fc1dddd406175c1f99a733f4a1206e2 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Tue, 1 Aug 2017 14:10:41 +0200 Subject: spi: Use Apple device properties in absence of ACPI resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MacBooks and MacBook Pros introduced since 2015 return empty _CRS data for SPI slaves, causing device initialization to fail. Most of the information that would normally be conveyed via _CRS is available through ACPI device properties instead, so take advantage of them. The meaning and appropriate usage of the device properties was reverse engineered by Ronald Tschalär and carried over from these commits authored by him: https://github.com/cb22/macbook12-spi-driver/commit/9a416d699ef4 https://github.com/cb22/macbook12-spi-driver/commit/0c34936ed9a1 According to Ronald, the device properties have the following meaning: spiSclkPeriod /* period in ns */ spiWordSize /* in number of bits */ spiBitOrder /* 1 = MSB_FIRST, 0 = LSB_FIRST */ spiSPO /* clock polarity: 0 = low, 1 = high */ spiSPH /* clock phase: 0 = first, 1 = second */ spiCSDelay /* delay between cs and receive on reads in 10 us */ resetA2RUsec /* active-to-receive delay? */ resetRecUsec /* receive delay? */ Reported-by: Leif Liddy Tested-by: Ronald Tschalär Acked-by: Mark Brown Acked-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Lukas Wunner Signed-off-by: Rafael J. Wysocki --- drivers/spi/spi.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 4fcbb0aa71d3..7d920ea19957 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -40,6 +40,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -1693,6 +1694,35 @@ static void of_register_spi_devices(struct spi_controller *ctlr) { } #endif #ifdef CONFIG_ACPI +static void acpi_spi_parse_apple_properties(struct spi_device *spi) +{ + struct acpi_device *dev = ACPI_COMPANION(&spi->dev); + const union acpi_object *obj; + + if (!x86_apple_machine) + return; + + if (!acpi_dev_get_property(dev, "spiSclkPeriod", ACPI_TYPE_BUFFER, &obj) + && obj->buffer.length >= 4) + spi->max_speed_hz = NSEC_PER_SEC / *(u32 *)obj->buffer.pointer; + + if (!acpi_dev_get_property(dev, "spiWordSize", ACPI_TYPE_BUFFER, &obj) + && obj->buffer.length == 8) + spi->bits_per_word = *(u64 *)obj->buffer.pointer; + + if (!acpi_dev_get_property(dev, "spiBitOrder", ACPI_TYPE_BUFFER, &obj) + && obj->buffer.length == 8 && !*(u64 *)obj->buffer.pointer) + spi->mode |= SPI_LSB_FIRST; + + if (!acpi_dev_get_property(dev, "spiSPO", ACPI_TYPE_BUFFER, &obj) + && obj->buffer.length == 8 && *(u64 *)obj->buffer.pointer) + spi->mode |= SPI_CPOL; + + if (!acpi_dev_get_property(dev, "spiSPH", ACPI_TYPE_BUFFER, &obj) + && obj->buffer.length == 8 && *(u64 *)obj->buffer.pointer) + spi->mode |= SPI_CPHA; +} + static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) { struct spi_device *spi = data; @@ -1766,6 +1796,8 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, acpi_spi_add_resource, spi); acpi_dev_free_resource_list(&resource_list); + acpi_spi_parse_apple_properties(spi); + if (ret < 0 || !spi->max_speed_hz) { spi_dev_put(spi); return AE_OK; -- cgit From 19dc7134805fdf8977c5b44a95cb5a55f832da35 Mon Sep 17 00:00:00 2001 From: Amitoj Kaur Chawla Date: Tue, 1 Aug 2017 20:28:46 -0400 Subject: ACPI / dock: constify attribute_group structure Functions working with attribute_groups provided by work with const attribute_group. These attribute_group structures do not change at runtime so mark them as const. File size before: text data bss dec hex filename 7902 3528 64 11494 2ce6 drivers/acpi/dock.o File size after: text data bss dec hex filename 7998 3432 64 11494 2ce6 drivers/acpi/dock.o This change was made with the help of Coccinelle. Signed-off-by: Amitoj Kaur Chawla Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 0c00208b423e..2305e1ab978e 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -585,7 +585,7 @@ static struct attribute *dock_attributes[] = { NULL }; -static struct attribute_group dock_attribute_group = { +static const struct attribute_group dock_attribute_group = { .attrs = dock_attributes }; -- cgit From 4eebedd8f1a6609739c2e9a9b020791b23cbcceb Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 3 Aug 2017 14:26:19 +0800 Subject: ACPICA: Divergences: reduce access size definitions ACPICA commit cf27b3c98883d2a15d932016792fcb8272ace96d The following commit introduces definition of access width to ACPICA. Commit: 2bece49394872d36bbc5767fd643deac05920c55 Subject: ACPI: SPCR: Use access width to determine mmio usage Actually the access bit width can be calculated via access width. It would be better to define a macro calculating bit width rather than defining fixed values. This patch thus cleans up the definitions to reduce divergences. Link: https://github.com/acpica/acpica/commit/cf27b3c9 Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/hwregs.c | 2 +- drivers/acpi/spcr.c | 9 +++++---- include/acpi/acrestyp.h | 7 ------- include/acpi/actypes.h | 7 +++++++ 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index de74a4c25085..acb417b58bbb 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -107,7 +107,7 @@ acpi_hw_get_access_bit_width(u64 address, ACPI_IS_ALIGNED(reg->bit_width, 8)) { access_bit_width = reg->bit_width; } else if (reg->access_width) { - access_bit_width = (1 << (reg->access_width + 2)); + access_bit_width = ACPI_ACCESS_BIT_WIDTH(reg->access_width); } else { access_bit_width = ACPI_ROUND_UP_POWER_OF_TWO_8(reg->bit_offset + diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index 4ac3e06b41d8..1230f969256b 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c @@ -95,16 +95,17 @@ int __init parse_spcr(bool earlycon) } if (table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { - switch (table->serial_port.access_width) { + switch (ACPI_ACCESS_BIT_WIDTH(( + table->serial_port.access_width))) { default: pr_err("Unexpected SPCR Access Width. Defaulting to byte size\n"); - case ACPI_ACCESS_SIZE_BYTE: + case 8: iotype = "mmio"; break; - case ACPI_ACCESS_SIZE_WORD: + case 16: iotype = "mmio16"; break; - case ACPI_ACCESS_SIZE_DWORD: + case 32: iotype = "mmio32"; break; } diff --git a/include/acpi/acrestyp.h b/include/acpi/acrestyp.h index 4f7f39a02820..343dbdcef20c 100644 --- a/include/acpi/acrestyp.h +++ b/include/acpi/acrestyp.h @@ -377,13 +377,6 @@ struct acpi_resource_generic_register { u64 address; }; -/* Generic Address Space Access Sizes */ -#define ACPI_ACCESS_SIZE_UNDEFINED 0 -#define ACPI_ACCESS_SIZE_BYTE 1 -#define ACPI_ACCESS_SIZE_WORD 2 -#define ACPI_ACCESS_SIZE_DWORD 3 -#define ACPI_ACCESS_SIZE_QWORD 4 - struct acpi_resource_gpio { u8 revision_id; u8 connection_type; diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 2fcbaec8b368..0260be595d40 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -554,6 +554,13 @@ typedef u64 acpi_integer; #define ACPI_VALIDATE_RSDP_SIG(a) (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_SIG_RSDP, 8)) #define ACPI_MAKE_RSDP_SIG(dest) (memcpy (ACPI_CAST_PTR (char, (dest)), ACPI_SIG_RSDP, 8)) +/* + * Algorithm to obtain access bit width. + * Can be used with access_width of struct acpi_generic_address and access_size of + * struct acpi_resource_generic_register. + */ +#define ACPI_ACCESS_BIT_WIDTH(size) (1 << ((size) + 2)) + /******************************************************************************* * * Miscellaneous constants -- cgit From 3bd38469df0a0f4b3c73e490538c8de104914a4a Mon Sep 17 00:00:00 2001 From: James Morse Date: Thu, 3 Aug 2017 14:26:25 +0800 Subject: ACPICA: iASL: Add support for the SDEI table ACPICA commit 5ad4f0b7bf9e7ba175bd320cf7950f3b38799ff3 ACPI 6.2 adds support for the Software Delegated Exception Interface, which is described by "Software Delegated Exception Interface (SDEI)" ARM DEN0054A. Add the necessary types in the ACPICA header files and support for compiling/decompiling the table. Link: https://github.com/acpica/acpica/commit/5ad4f0b7 Signed-off-by: James Morse Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/actbl2.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index d568948d3a82..686b6f8c09dc 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -76,6 +76,7 @@ #define ACPI_SIG_MCHI "MCHI" /* Management Controller Host Interface table */ #define ACPI_SIG_MSDM "MSDM" /* Microsoft Data Management Table */ #define ACPI_SIG_MTMR "MTMR" /* MID Timer table */ +#define ACPI_SIG_SDEI "SDEI" /* Software Delegated Exception Interface Table */ #define ACPI_SIG_SLIC "SLIC" /* Software Licensing Description Table */ #define ACPI_SIG_SPCR "SPCR" /* Serial Port Console Redirection table */ #define ACPI_SIG_SPMI "SPMI" /* Server Platform Management Interface table */ @@ -1132,6 +1133,19 @@ struct acpi_mtmr_entry { u32 irq; }; +/******************************************************************************* + * + * SDEI - Software Delegated Exception Interface Descriptor Table + * + * Conforms to "Software Delegated Exception Interface (SDEI)" ARM DEN0054A, + * May 8th, 2017. Copyright 2017 ARM Ltd. + * + ******************************************************************************/ + +struct acpi_table_sdei { + struct acpi_table_header header; /* Common ACPI table header */ +}; + /******************************************************************************* * * SLIC - Software Licensing Description Table -- cgit From 6d9229d67df35f9b7f922d6bdb4d6505eb0b900f Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 3 Aug 2017 14:26:31 +0800 Subject: ACPICA: Namespace: Update/fix an error message ACPICA commit 8b7fa979ef81469e70f501f582466a265d6f595b Was emitting an internal namestring without converting it to the external format. Link: https://github.com/acpica/acpica/commit/8b7fa979 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nsaccess.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 14be12fe9f35..f2733f51ca8d 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -292,6 +292,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, { acpi_status status; char *path = pathname; + char *external_path; struct acpi_namespace_node *prefix_node; struct acpi_namespace_node *current_node = NULL; struct acpi_namespace_node *this_node = NULL; @@ -427,13 +428,22 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, num_carats++; this_node = this_node->parent; if (!this_node) { + /* + * Current scope has no parent scope. Externalize + * the internal path for error message. + */ + status = + acpi_ns_externalize_name + (ACPI_UINT32_MAX, pathname, NULL, + &external_path); + if (ACPI_SUCCESS(status)) { + ACPI_ERROR((AE_INFO, + "%s: Path has too many parent prefixes (^)", + external_path)); + + ACPI_FREE(external_path); + } - /* Current scope has no parent scope */ - - ACPI_ERROR((AE_INFO, - "%s: Path has too many parent prefixes (^) " - "- reached beyond root node", - pathname)); return_ACPI_STATUS(AE_NOT_FOUND); } } -- cgit From 583abc9bd585ff0d5fb7411e5601053b21fdd9d9 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 3 Aug 2017 14:26:38 +0800 Subject: ACPICA: Add a comment, no functional change ACPICA commit d586c29a026a6172c1113df4d75fd6d764196e77 Describe 2nd byte of the end_tag resource descriptor. Link: https://github.com/acpica/acpica/commit/d586c29a Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utresrc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index d955bf852a03..517acf8e77c8 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -239,6 +239,13 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); } + /* + * Don't attempt to perform any validation on the 2nd byte. + * Although all known ASL compilers insert a zero for the 2nd + * byte, it can also be a checksum (as per the ACPI spec), + * and this is occasionally seen in the field. July 2017. + */ + /* Return the pointer to the end_tag if requested */ if (!user_function) { -- cgit From d5f23fe192b5b549a85e98ee9f0a3b8a0f9c04c3 Mon Sep 17 00:00:00 2001 From: Shao Ming Date: Thu, 3 Aug 2017 14:26:44 +0800 Subject: ACPICA: EFI/EDK2: Sort acpi.h inclusion order ACPICA commit 43ff22215f0fcd8ca80abec5712a07d2cc9a801d acpi.h inclusion order need to be changed to build EDK-II ports of acpidump on Windows as va_list is used before it's definition in that environment. As we only need to ensure order of acenv.h/acenvex.h to be pre/post ACPICA type definitions, inclusion order is changed to make MSVC builds happy. Lv Zheng. Link: https://github.com/acpica/acpica/commit/43ff2221 Signed-off-by: "Shao, Ming" Signed-off-by: Lv Zheng Signed-off-by: Shao Ming Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- include/acpi/acpi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/acpi/acpi.h b/include/acpi/acpi.h index ca036620703c..0887d7cbb7e1 100644 --- a/include/acpi/acpi.h +++ b/include/acpi/acpi.h @@ -58,10 +58,10 @@ #include /* ACPICA data types and structures */ #include /* ACPICA exceptions */ #include /* ACPI table definitions */ -#include /* Error output and Debug macros */ #include /* Resource Descriptor structs */ +#include /* Extra environment-specific items */ +#include /* Error output and Debug macros */ #include /* OSL interfaces (ACPICA-to-OS) */ #include /* ACPI core subsystem external interfaces */ -#include /* Extra environment-specific items */ #endif /* __ACPI_H__ */ -- cgit From 65082bfcb486ef06f93b7603a9045cdf0c0022e8 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 3 Aug 2017 14:26:50 +0800 Subject: ACPICA: CLib: Add short multiply/shift support ACPICA commit 01b8f5a2350b9cc329cd8402ac8faec36fc501f5 In order to build ACPICA EFI tools with EDK-II on Windows, 64-bit multiply/shift supports are also required to be implemented. Otherwise, MSVC complains: acpidump.lib(utstrtoul64.obj) : error LNK2001: unresolved external symbol __allmul acpidump.lib(uthex.obj) : error LNK2001: unresolved external symbol __aullshr Note: 1. This patch also splits _EDK2_EFI from _GNU_EFI as they might have different math64 supports. 2. Support of gcc math64 is not included in this patch. 3. Support of EDK2 arch independent math64 is done via linking to base_lib. This patch fixes this issue. Reported by Shao Ming, fixed by Lv Zheng. For Linux kernel, this patch is a functional no-op. Link: https://github.com/acpica/acpica/commit/01b8f5a2 Tested-by: "Shao, Ming" Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acutils.h | 7 + drivers/acpi/acpica/uthex.c | 4 +- drivers/acpi/acpica/utmath.c | 222 ++++++++++++++++++++++++++++-- drivers/acpi/acpica/utprint.c | 2 +- drivers/acpi/acpica/utstrtoul64.c | 9 +- include/acpi/actypes.h | 1 + include/acpi/platform/acgcc.h | 4 + include/acpi/platform/aclinux.h | 2 + tools/power/acpi/tools/acpidump/apfiles.c | 2 +- tools/power/acpi/tools/acpidump/apmain.c | 2 +- 10 files changed, 237 insertions(+), 18 deletions(-) diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 2a3cc4296481..0a5601405584 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -538,6 +538,13 @@ acpi_status acpi_ut_short_divide(u64 in_dividend, u32 divisor, u64 *out_quotient, u32 *out_remainder); +acpi_status +acpi_ut_short_multiply(u64 in_multiplicand, u32 multiplier, u64 *outproduct); + +acpi_status acpi_ut_short_shift_left(u64 operand, u32 count, u64 *out_result); + +acpi_status acpi_ut_short_shift_right(u64 operand, u32 count, u64 *out_result); + /* * utmisc */ diff --git a/drivers/acpi/acpica/uthex.c b/drivers/acpi/acpica/uthex.c index 6600bc257516..fb406daf47fa 100644 --- a/drivers/acpi/acpica/uthex.c +++ b/drivers/acpi/acpica/uthex.c @@ -69,8 +69,10 @@ static const char acpi_gbl_hex_to_ascii[] = { char acpi_ut_hex_to_ascii_char(u64 integer, u32 position) { + u64 index; - return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]); + acpi_ut_short_shift_right(integer, position, &index); + return (acpi_gbl_hex_to_ascii[index & 0xF]); } /******************************************************************************* diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c index aa0502d1d019..5f9c680076c4 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -47,15 +47,6 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utmath") -/* - * Optional support for 64-bit double-precision integer divide. This code - * is configurable and is implemented in order to support 32-bit kernel - * environments where a 64-bit double-precision math library is not available. - * - * Support for a more normal 64-bit divide/modulo (with check for a divide- - * by-zero) appears after this optional section of code. - */ -#ifndef ACPI_USE_NATIVE_DIVIDE /* Structures used only for 64-bit divide */ typedef struct uint64_struct { u32 lo; @@ -69,6 +60,217 @@ typedef union uint64_overlay { } uint64_overlay; +/* + * Optional support for 64-bit double-precision integer multiply and shift. + * This code is configurable and is implemented in order to support 32-bit + * kernel environments where a 64-bit double-precision math library is not + * available. + */ +#ifndef ACPI_USE_NATIVE_MATH64 + +/******************************************************************************* + * + * FUNCTION: acpi_ut_short_multiply + * + * PARAMETERS: multiplicand - 64-bit multiplicand + * multiplier - 32-bit multiplier + * out_product - Pointer to where the product is returned + * + * DESCRIPTION: Perform a short multiply. + * + ******************************************************************************/ + +acpi_status +acpi_ut_short_multiply(u64 multiplicand, u32 multiplier, u64 *out_product) +{ + union uint64_overlay multiplicand_ovl; + union uint64_overlay product; + u32 carry32; + + ACPI_FUNCTION_TRACE(ut_short_multiply); + + multiplicand_ovl.full = multiplicand; + + /* + * The Product is 64 bits, the carry is always 32 bits, + * and is generated by the second multiply. + */ + ACPI_MUL_64_BY_32(0, multiplicand_ovl.part.hi, multiplier, + product.part.hi, carry32); + + ACPI_MUL_64_BY_32(0, multiplicand_ovl.part.lo, multiplier, + product.part.lo, carry32); + + product.part.hi += carry32; + + /* Return only what was requested */ + + if (out_product) { + *out_product = product.full; + } + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_short_shift_left + * + * PARAMETERS: operand - 64-bit shift operand + * count - 32-bit shift count + * out_result - Pointer to where the result is returned + * + * DESCRIPTION: Perform a short left shift. + * + ******************************************************************************/ + +acpi_status acpi_ut_short_shift_left(u64 operand, u32 count, u64 *out_result) +{ + union uint64_overlay operand_ovl; + + ACPI_FUNCTION_TRACE(ut_short_shift_left); + + operand_ovl.full = operand; + + if ((count & 63) >= 32) { + operand_ovl.part.hi = operand_ovl.part.lo; + operand_ovl.part.lo ^= operand_ovl.part.lo; + count = (count & 63) - 32; + } + ACPI_SHIFT_LEFT_64_BY_32(operand_ovl.part.hi, + operand_ovl.part.lo, count); + + /* Return only what was requested */ + + if (out_result) { + *out_result = operand_ovl.full; + } + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_short_shift_right + * + * PARAMETERS: operand - 64-bit shift operand + * count - 32-bit shift count + * out_result - Pointer to where the result is returned + * + * DESCRIPTION: Perform a short right shift. + * + ******************************************************************************/ + +acpi_status acpi_ut_short_shift_right(u64 operand, u32 count, u64 *out_result) +{ + union uint64_overlay operand_ovl; + + ACPI_FUNCTION_TRACE(ut_short_shift_right); + + operand_ovl.full = operand; + + if ((count & 63) >= 32) { + operand_ovl.part.lo = operand_ovl.part.hi; + operand_ovl.part.hi ^= operand_ovl.part.hi; + count = (count & 63) - 32; + } + ACPI_SHIFT_RIGHT_64_BY_32(operand_ovl.part.hi, + operand_ovl.part.lo, count); + + /* Return only what was requested */ + + if (out_result) { + *out_result = operand_ovl.full; + } + + return_ACPI_STATUS(AE_OK); +} +#else + +/******************************************************************************* + * + * FUNCTION: acpi_ut_short_multiply + * + * PARAMETERS: See function headers above + * + * DESCRIPTION: Native version of the ut_short_multiply function. + * + ******************************************************************************/ + +acpi_status +acpi_ut_short_multiply(u64 multiplicand, u32 multiplier, u64 *out_product) +{ + + ACPI_FUNCTION_TRACE(ut_short_multiply); + + /* Return only what was requested */ + + if (out_product) { + *out_product = multiplicand * multiplier; + } + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_short_shift_left + * + * PARAMETERS: See function headers above + * + * DESCRIPTION: Native version of the ut_short_shift_left function. + * + ******************************************************************************/ + +acpi_status acpi_ut_short_shift_left(u64 operand, u32 count, u64 *out_result) +{ + + ACPI_FUNCTION_TRACE(ut_short_shift_left); + + /* Return only what was requested */ + + if (out_result) { + *out_result = operand << count; + } + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_short_shift_right + * + * PARAMETERS: See function headers above + * + * DESCRIPTION: Native version of the ut_short_shift_right function. + * + ******************************************************************************/ + +acpi_status acpi_ut_short_shift_right(u64 operand, u32 count, u64 *out_result) +{ + + ACPI_FUNCTION_TRACE(ut_short_shift_right); + + /* Return only what was requested */ + + if (out_result) { + *out_result = operand >> count; + } + + return_ACPI_STATUS(AE_OK); +} +#endif + +/* + * Optional support for 64-bit double-precision integer divide. This code + * is configurable and is implemented in order to support 32-bit kernel + * environments where a 64-bit double-precision math library is not available. + * + * Support for a more normal 64-bit divide/modulo (with check for a divide- + * by-zero) appears after this optional section of code. + */ +#ifndef ACPI_USE_NATIVE_DIVIDE + /******************************************************************************* * * FUNCTION: acpi_ut_short_divide @@ -258,6 +460,7 @@ acpi_ut_divide(u64 in_dividend, } #else + /******************************************************************************* * * FUNCTION: acpi_ut_short_divide, acpi_ut_divide @@ -272,6 +475,7 @@ acpi_ut_divide(u64 in_dividend, * perform the divide. * ******************************************************************************/ + acpi_status acpi_ut_short_divide(u64 in_dividend, u32 divisor, u64 *out_quotient, u32 *out_remainder) diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c index 7e6e1ae6140f..23cb472e5dc8 100644 --- a/drivers/acpi/acpica/utprint.c +++ b/drivers/acpi/acpica/utprint.c @@ -176,7 +176,7 @@ const char *acpi_ut_scan_number(const char *string, u64 *number_ptr) u64 number = 0; while (isdigit((int)*string)) { - number *= 10; + acpi_ut_short_multiply(number, 10, &number); number += *(string++) - '0'; } diff --git a/drivers/acpi/acpica/utstrtoul64.c b/drivers/acpi/acpica/utstrtoul64.c index f42be01d99fd..9633ee142855 100644 --- a/drivers/acpi/acpica/utstrtoul64.c +++ b/drivers/acpi/acpica/utstrtoul64.c @@ -276,8 +276,8 @@ static u64 acpi_ut_strtoul_base10(char *string, u32 flags) /* Convert and insert (add) the decimal digit */ - next_value = - (return_value * 10) + (ascii_digit - ACPI_ASCII_ZERO); + acpi_ut_short_multiply(return_value, 10, &next_value); + next_value += (ascii_digit - ACPI_ASCII_ZERO); /* Check for overflow (32 or 64 bit) - return current converted value */ @@ -335,9 +335,8 @@ static u64 acpi_ut_strtoul_base16(char *string, u32 flags) /* Convert and insert the hex digit */ - return_value = - (return_value << 4) | - acpi_ut_ascii_char_to_hex(ascii_digit); + acpi_ut_short_shift_left(return_value, 4, &return_value); + return_value |= acpi_ut_ascii_char_to_hex(ascii_digit); string++; valid_digits++; diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 0260be595d40..dc3bb153420a 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -166,6 +166,7 @@ typedef u64 acpi_physical_address; #define ACPI_SIZE_MAX ACPI_UINT64_MAX #define ACPI_USE_NATIVE_DIVIDE /* Has native 64-bit integer support */ +#define ACPI_USE_NATIVE_MATH64 /* Has native 64-bit integer support */ /* * In the case of the Itanium Processor Family (IPF), the hardware does not diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h index 97a7e21cfbe0..9c8f8b79644e 100644 --- a/include/acpi/platform/acgcc.h +++ b/include/acpi/platform/acgcc.h @@ -84,4 +84,8 @@ typedef __builtin_va_list va_list; #define COMPILER_VA_MACRO 1 +/* GCC supports native multiply/shift on 32-bit platforms */ + +#define ACPI_USE_NATIVE_MATH64 + #endif /* __ACGCC_H__ */ diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index afd95f28c8f0..1b473efd9eb6 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -128,6 +128,7 @@ /* Host-dependent types and defines for in-kernel ACPICA */ #define ACPI_MACHINE_WIDTH BITS_PER_LONG +#define ACPI_USE_NATIVE_MATH64 #define ACPI_EXPORT_SYMBOL(symbol) EXPORT_SYMBOL(symbol); #define strtoul simple_strtoul @@ -216,6 +217,7 @@ #define COMPILER_DEPENDENT_INT64 long long #define COMPILER_DEPENDENT_UINT64 unsigned long long #define ACPI_USE_NATIVE_DIVIDE +#define ACPI_USE_NATIVE_MATH64 #endif #ifndef __cdecl diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c index 31b5a7f74015..d686e11936c4 100644 --- a/tools/power/acpi/tools/acpidump/apfiles.c +++ b/tools/power/acpi/tools/acpidump/apfiles.c @@ -61,7 +61,7 @@ static int ap_is_existing_file(char *pathname); static int ap_is_existing_file(char *pathname) { -#ifndef _GNU_EFI +#if !defined(_GNU_EFI) && !defined(_EDK2_EFI) struct stat stat_info; if (!stat(pathname, &stat_info)) { diff --git a/tools/power/acpi/tools/acpidump/apmain.c b/tools/power/acpi/tools/acpidump/apmain.c index dd82afa897bd..943b6b614683 100644 --- a/tools/power/acpi/tools/acpidump/apmain.c +++ b/tools/power/acpi/tools/acpidump/apmain.c @@ -300,7 +300,7 @@ static int ap_do_options(int argc, char **argv) * ******************************************************************************/ -#ifndef _GNU_EFI +#if !defined(_GNU_EFI) && !defined(_EDK2_EFI) int ACPI_SYSTEM_XFACE main(int argc, char *argv[]) #else int ACPI_SYSTEM_XFACE acpi_main(int argc, char *argv[]) -- cgit From 03c5b6b0da3f8ce8a4ba463daeb26b151d36f10e Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 3 Aug 2017 14:26:56 +0800 Subject: ACPICA: acpidump: Add DSDT/FACS instance support for Linux and EFI ACPICA commit 343fc31840d40c06001f3b170ee5bcdfd3c7f3e0 ACPI spec allows to configure different 32-bit/64-bit table addresses for DSDT and FACS. And for FACS, it's meaningful to dump both of them as they are used to support different suspend protocols. While: 1. on Linux, only 1 instance is supported for DSDT/FACS; and 2. on EFI, the code in osl_get_table() is buggy with special table instances, causing endless file dump for such tables (reported by Shao Ming in link #2). This patch adds DSDT/FACS instance support for Linux/EFI acpidump. Fixed by Lv Zheng. Link: https://github.com/acpica/acpica/commit/343fc318 Link: https://bugs.acpica.org/show_bug.cgi?id=1407 [#1] Link: https://github.com/acpica/acpica/issues/285 [#2] Reported-by: Shao Ming Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- .../acpi/os_specific/service_layers/oslinuxtbl.c | 105 ++++++++++++++------- 1 file changed, 73 insertions(+), 32 deletions(-) diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c index 82a2ff896a95..52a39ecf5ca1 100644 --- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c @@ -759,7 +759,7 @@ static acpi_status osl_list_bios_tables(void) /* Skip NULL entries in RSDT/XSDT */ - if (!table_address) { + if (table_address == 0) { continue; } @@ -808,7 +808,8 @@ osl_get_bios_table(char *signature, u8 number_of_tables; u8 item_size; u32 current_instance = 0; - acpi_physical_address table_address = 0; + acpi_physical_address table_address; + acpi_physical_address first_table_address = 0; u32 table_length = 0; acpi_status status = AE_OK; u32 i; @@ -820,9 +821,10 @@ osl_get_bios_table(char *signature, ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT) || ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT) || ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { - if (instance > 0) { - return (AE_LIMIT); - } + +find_next_instance: + + table_address = 0; /* * Get the appropriate address, either 32-bit or 64-bit. Be very @@ -830,41 +832,66 @@ osl_get_bios_table(char *signature, * 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; + if (current_instance < 2) { + if ((gbl_fadt->header.length >= + MIN_FADT_FOR_XDSDT) && gbl_fadt->Xdsdt + && current_instance == 0) { + table_address = + (acpi_physical_address)gbl_fadt-> + Xdsdt; + } else + if ((gbl_fadt->header.length >= + MIN_FADT_FOR_DSDT) + && gbl_fadt->dsdt != + first_table_address) { + 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; + if (current_instance < 2) { + if ((gbl_fadt->header.length >= + MIN_FADT_FOR_XFACS) && gbl_fadt->Xfacs + && current_instance == 0) { + table_address = + (acpi_physical_address)gbl_fadt-> + Xfacs; + } else + if ((gbl_fadt->header.length >= + MIN_FADT_FOR_FACS) + && gbl_fadt->facs != + first_table_address) { + 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; + if (current_instance == 0) { + 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; + if (current_instance == 0) { + table_address = + (acpi_physical_address)gbl_rsdp. + rsdt_physical_address; + } } else { - table_address = (acpi_physical_address)gbl_rsdp_address; - signature = ACPI_SIG_RSDP; + if (current_instance == 0) { + table_address = + (acpi_physical_address)gbl_rsdp_address; + signature = ACPI_SIG_RSDP; + } + } + + if (table_address == 0) { + goto exit_find_table; } /* Now we can get the requested special table */ @@ -875,6 +902,18 @@ osl_get_bios_table(char *signature, } table_length = ap_get_table_length(mapped_table); + if (first_table_address == 0) { + first_table_address = table_address; + } + + /* Match table instance */ + + if (current_instance != instance) { + osl_unmap_table(mapped_table); + mapped_table = NULL; + current_instance++; + goto find_next_instance; + } } else { /* Case for a normal ACPI table */ if (osl_can_use_xsdt()) { @@ -913,7 +952,7 @@ osl_get_bios_table(char *signature, /* Skip NULL entries in RSDT/XSDT */ - if (!table_address) { + if (table_address == 0) { continue; } @@ -946,6 +985,8 @@ osl_get_bios_table(char *signature, } } +exit_find_table: + if (!mapped_table) { return (AE_LIMIT); } -- cgit From 3958168fc8c67b69849f2b1170ab4484e1800d31 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 3 Aug 2017 14:27:03 +0800 Subject: ACPICA: EFI/EDK2: Cleanup to enable /WX for MSVC builds ACPICA commit a7c6d65a5dab20b1e191c197e09af337fc54b341 /WX turns warning into fatal erros for MSVC builds. We need /WX- during EDK2 porting to allow agile development. Now it is time to enable /WX and some explicit type conversion cleanups are required for enabling /WX. Lv Zheng. Link: https://github.com/acpica/acpica/commit/a7c6d65a Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utprint.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c index 23cb472e5dc8..c008589b41bd 100644 --- a/drivers/acpi/acpica/utprint.c +++ b/drivers/acpi/acpica/utprint.c @@ -286,7 +286,7 @@ static char *acpi_ut_format_number(char *string, /* Generate full string in reverse order */ pos = acpi_ut_put_number(reversed_string, number, base, upper); - i = ACPI_PTR_DIFF(pos, reversed_string); + i = (s32)ACPI_PTR_DIFF(pos, reversed_string); /* Printing 100 using %2d gives "100", not "00" */ @@ -475,7 +475,7 @@ int vsnprintf(char *string, acpi_size size, const char *format, va_list args) if (!s) { s = ""; } - length = acpi_ut_bound_string_length(s, precision); + length = (s32)acpi_ut_bound_string_length(s, precision); if (!(type & ACPI_FORMAT_LEFT)) { while (length < width--) { pos = @@ -579,7 +579,7 @@ int vsnprintf(char *string, acpi_size size, const char *format, va_list args) } } - return (ACPI_PTR_DIFF(pos, string)); + return ((int)ACPI_PTR_DIFF(pos, string)); } /******************************************************************************* -- cgit From a5b6e982fb9dc8e49307ff33ddc4b95f1b8e385c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 3 Aug 2017 14:27:09 +0800 Subject: ACPICA: Interpreter: Update handling for Alias operator ACPICA commit 719d0bdd48e3e8e7a62a86c04922b9f41da6def0 Provide common creation code for the Alias operator. All objects are now handled the same, with the only exception being the Method() operator. It has a special internal Alias type. Link: https://github.com/acpica/acpica/commit/719d0bdd Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/excreate.c | 61 ++++++++++-------------------------------- 1 file changed, 14 insertions(+), 47 deletions(-) diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 68675868e20f..b8adb11f1b07 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -88,72 +88,39 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) } /* Ensure that the target node is valid */ + if (!target_node) { return_ACPI_STATUS(AE_NULL_OBJECT); } - /* - * For objects that can never change (i.e., the NS node will - * permanently point to the same object), we can simply attach - * the object to the new NS node. For other objects (such as - * Integers, buffers, etc.), we have to point the Alias node - * to the original Node. - */ - switch (target_node->type) { - - /* For these types, the sub-object can change dynamically via a Store */ - - case ACPI_TYPE_INTEGER: - case ACPI_TYPE_STRING: - case ACPI_TYPE_BUFFER: - case ACPI_TYPE_PACKAGE: - case ACPI_TYPE_BUFFER_FIELD: - /* - * These types open a new scope, so we need the NS node in order to access - * any children. - */ - case ACPI_TYPE_DEVICE: - case ACPI_TYPE_POWER: - case ACPI_TYPE_PROCESSOR: - case ACPI_TYPE_THERMAL: - case ACPI_TYPE_LOCAL_SCOPE: - /* - * The new alias has the type ALIAS and points to the original - * NS node, not the object itself. - */ - alias_node->type = ACPI_TYPE_LOCAL_ALIAS; - alias_node->object = - ACPI_CAST_PTR(union acpi_operand_object, target_node); - break; + /* Construct the alias object (a namespace node) */ + switch (target_node->type) { case ACPI_TYPE_METHOD: /* - * Control method aliases need to be differentiated + * Control method aliases need to be differentiated with + * a special type */ alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS; - alias_node->object = - ACPI_CAST_PTR(union acpi_operand_object, target_node); break; default: - - /* Attach the original source object to the new Alias Node */ - /* - * The new alias assumes the type of the target, and it points - * to the same object. The reference count of the object has an - * additional reference to prevent deletion out from under either the - * target node or the alias Node + * All other object types. + * + * The new alias has the type ALIAS and points to the original + * NS node, not the object itself. */ - status = acpi_ns_attach_object(alias_node, - acpi_ns_get_attached_object - (target_node), - target_node->type); + alias_node->type = ACPI_TYPE_LOCAL_ALIAS; + alias_node->object = + ACPI_CAST_PTR(union acpi_operand_object, target_node); break; } /* Since both operands are Nodes, we don't need to delete them */ + alias_node->object = + ACPI_CAST_PTR(union acpi_operand_object, target_node); return_ACPI_STATUS(status); } -- cgit From 7ab58197d84c29cf20162eaaed1eb2cc94fc73a7 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 3 Aug 2017 14:27:15 +0800 Subject: ACPICA: Debugger: Improve support for Alias objects ACPICA commit 916993dbcd45b46e01f6c9b8337a01513f5d8dcc Properly resolve alias objects for display. General cleanup of related output. Link: https://github.com/acpica/acpica/commit/916993db Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dbdisply.c | 37 ++++++++++++++++++++++++++++++++----- drivers/acpi/acpica/exdump.c | 34 ++++++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c index 46bf270ac525..5a606eac0c22 100644 --- a/drivers/acpi/acpica/dbdisply.c +++ b/drivers/acpi/acpica/dbdisply.c @@ -310,7 +310,7 @@ dump_node: } else { - acpi_os_printf("Object (%p) Pathname: %s\n", + acpi_os_printf("Object %p: Namespace Node - Pathname: %s\n", node, (char *)ret_buf.pointer); } @@ -326,7 +326,7 @@ dump_node: obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { - acpi_os_printf("\nAttached Object (%p):\n", obj_desc); + acpi_os_printf("\nAttached Object %p:", obj_desc); if (!acpi_os_readable (obj_desc, sizeof(union acpi_operand_object))) { acpi_os_printf @@ -335,9 +335,36 @@ dump_node: return; } - acpi_ut_debug_dump_buffer((void *)obj_desc, - sizeof(union acpi_operand_object), - display, ACPI_UINT32_MAX); + if (ACPI_GET_DESCRIPTOR_TYPE(((struct acpi_namespace_node *) + obj_desc)) == + ACPI_DESC_TYPE_NAMED) { + acpi_os_printf(" Namespace Node - "); + status = + acpi_get_name((struct acpi_namespace_node *) + obj_desc, + ACPI_FULL_PATHNAME_NO_TRAILING, + &ret_buf); + if (ACPI_FAILURE(status)) { + acpi_os_printf + ("Could not convert name to pathname\n"); + } else { + acpi_os_printf("Pathname: %s", + (char *)ret_buf.pointer); + } + + acpi_os_printf("\n"); + acpi_ut_debug_dump_buffer((void *)obj_desc, + sizeof(struct + acpi_namespace_node), + display, ACPI_UINT32_MAX); + } else { + acpi_os_printf("\n"); + acpi_ut_debug_dump_buffer((void *)obj_desc, + sizeof(union + acpi_operand_object), + display, ACPI_UINT32_MAX); + } + acpi_ex_dump_object_descriptor(obj_desc, 1); } } diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 44092f744477..83398dc4b7c2 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -102,7 +102,7 @@ static struct acpi_exdump_info acpi_ex_dump_package[6] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_package), NULL}, {ACPI_EXD_NODE, ACPI_EXD_OFFSET(package.node), "Parent Node"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(package.flags), "Flags"}, - {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(package.count), "Elements"}, + {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(package.count), "Element Count"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(package.elements), "Element List"}, {ACPI_EXD_PACKAGE, 0, NULL} }; @@ -384,6 +384,10 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc, count = info->offset; while (count) { + if (!obj_desc) { + return; + } + target = ACPI_ADD_PTR(u8, obj_desc, info->offset); name = info->name; @@ -469,9 +473,9 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc, start = *ACPI_CAST_PTR(void *, target); next = start; - acpi_os_printf("%20s : %p", name, next); + acpi_os_printf("%20s : %p ", name, next); if (next) { - acpi_os_printf("(%s %2.2X)", + acpi_os_printf("%s (Type %2.2X)", acpi_ut_get_object_type_name (next), next->common.type); @@ -493,6 +497,8 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc, break; } } + } else { + acpi_os_printf("- No attached objects"); } acpi_os_printf("\n"); @@ -1129,7 +1135,9 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc, default: - acpi_os_printf("[Unknown Type] %X\n", obj_desc->common.type); + acpi_os_printf("[%s] Type: %2.2X\n", + acpi_ut_get_type_name(obj_desc->common.type), + obj_desc->common.type); break; } } @@ -1167,11 +1175,17 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags) acpi_ex_dump_namespace_node((struct acpi_namespace_node *) obj_desc, flags); - acpi_os_printf("\nAttached Object (%p):\n", - ((struct acpi_namespace_node *)obj_desc)-> - object); - obj_desc = ((struct acpi_namespace_node *)obj_desc)->object; + if (!obj_desc) { + return_VOID; + } + + acpi_os_printf("\nAttached Object %p", obj_desc); + if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_NAMED) { + acpi_os_printf(" - Namespace Node"); + } + + acpi_os_printf(":\n"); goto dump_object; } @@ -1191,6 +1205,10 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags) dump_object: + if (!obj_desc) { + return_VOID; + } + /* Common Fields */ acpi_ex_dump_object(obj_desc, acpi_ex_dump_common); -- cgit From a62a7117d91ca83d319566cbe16039f4e9f413c2 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 3 Aug 2017 14:27:22 +0800 Subject: ACPICA: Implement deferred resolution of reference package elements ACPICA commit 0c08790c56fdf0dc081ae869495a09d8c4230854 This change defers the resolution of package elements that are named references until after the entire namespace has been loaded from the definition block. This allows such references to be in fact forward references for both module level code and control methods. Link: https://github.com/acpica/acpica/commit/0c08790c Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/Makefile | 1 + drivers/acpi/acpica/acdispat.h | 13 + drivers/acpi/acpica/aclocal.h | 2 +- drivers/acpi/acpica/acobject.h | 3 +- drivers/acpi/acpica/acutils.h | 2 +- drivers/acpi/acpica/dsobject.c | 398 +++++------------------------- drivers/acpi/acpica/dsopcode.c | 9 + drivers/acpi/acpica/dspkginit.c | 496 ++++++++++++++++++++++++++++++++++++++ drivers/acpi/acpica/nsarguments.c | 21 +- drivers/acpi/acpica/nsinit.c | 14 ++ drivers/acpi/acpica/nsnames.c | 9 +- drivers/acpi/acpica/psloop.c | 14 ++ drivers/acpi/acpica/utmisc.c | 8 +- drivers/acpi/acpica/utobject.c | 5 + drivers/acpi/acpica/utstate.c | 2 +- drivers/acpi/acpica/uttrack.c | 9 +- 16 files changed, 661 insertions(+), 345 deletions(-) create mode 100644 drivers/acpi/acpica/dspkginit.c diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index b125bdd3d58b..1709551bc4aa 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -18,6 +18,7 @@ acpi-y := \ dsmthdat.o \ dsobject.o \ dsopcode.o \ + dspkginit.o \ dsutils.o \ dswexec.o \ dswload.o \ diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h index 0d95c85cce06..f8f3a6e74128 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -237,6 +237,11 @@ acpi_ds_initialize_objects(u32 table_index, * dsobject - Parser/Interpreter interface - object initialization and conversion */ acpi_status +acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + union acpi_operand_object **obj_desc_ptr); + +acpi_status acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, union acpi_parse_object *op, u32 buffer_length, @@ -258,6 +263,14 @@ acpi_ds_create_node(struct acpi_walk_state *walk_state, struct acpi_namespace_node *node, union acpi_parse_object *op); +/* + * dspkginit - Package object initialization + */ +acpi_status +acpi_ds_init_package_element(u8 object_type, + union acpi_operand_object *source_object, + union acpi_generic_state *state, void *context); + /* * dsutils - Parser/Interpreter interface utility routines */ diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index bae943b5f377..0d45b8bb1678 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -605,7 +605,7 @@ struct acpi_update_state { * Pkg state - used to traverse nested package structures */ struct acpi_pkg_state { - ACPI_STATE_COMMON u16 index; + ACPI_STATE_COMMON u32 index; union acpi_operand_object *source_object; union acpi_operand_object *dest_object; struct acpi_walk_state *walk_state; diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 549f227348cd..5226146190bf 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -339,11 +339,12 @@ struct acpi_object_addr_handler { struct acpi_object_reference { ACPI_OBJECT_COMMON_HEADER u8 class; /* Reference Class */ u8 target_type; /* Used for Index Op */ - u8 reserved; + u8 resolved; /* Reference has been resolved to a value */ void *object; /* name_op=>HANDLE to obj, index_op=>union acpi_operand_object */ struct acpi_namespace_node *node; /* ref_of or Namepath */ union acpi_operand_object **where; /* Target of Index */ u8 *index_pointer; /* Used for Buffers and Strings */ + u8 *aml; /* Used for deferred resolution of the ref */ u32 value; /* Used for Local/Arg/Index/ddb_handle */ }; diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 0a5601405584..745134ade35f 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -516,7 +516,7 @@ union acpi_generic_state *acpi_ut_create_update_state(union acpi_operand_object union acpi_generic_state *acpi_ut_create_pkg_state(void *internal_object, void *external_object, - u16 index); + u32 index); acpi_status acpi_ut_create_update_state_and_push(union acpi_operand_object *object, diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 7df3152ed856..82448551781b 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -52,12 +52,6 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsobject") -/* Local prototypes */ -static acpi_status -acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, - union acpi_parse_object *op, - union acpi_operand_object **obj_desc_ptr); - #ifndef ACPI_NO_METHOD_EXECUTION /******************************************************************************* * @@ -73,15 +67,13 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, * Simple objects are any objects other than a package object! * ******************************************************************************/ - -static acpi_status +acpi_status acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, union acpi_parse_object *op, union acpi_operand_object **obj_desc_ptr) { union acpi_operand_object *obj_desc; acpi_status status; - acpi_object_type type; ACPI_FUNCTION_TRACE(ds_build_internal_object); @@ -89,140 +81,47 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { /* * This is a named object reference. If this name was - * previously looked up in the namespace, it was stored in this op. - * Otherwise, go ahead and look it up now + * previously looked up in the namespace, it was stored in + * this op. Otherwise, go ahead and look it up now */ if (!op->common.node) { - status = acpi_ns_lookup(walk_state->scope_info, - op->common.value.string, - ACPI_TYPE_ANY, - ACPI_IMODE_EXECUTE, - ACPI_NS_SEARCH_PARENT | - ACPI_NS_DONT_OPEN_SCOPE, NULL, - ACPI_CAST_INDIRECT_PTR(struct - acpi_namespace_node, - &(op-> - common. - node))); - if (ACPI_FAILURE(status)) { - - /* Check if we are resolving a named reference within a package */ - - if ((status == AE_NOT_FOUND) - && (acpi_gbl_enable_interpreter_slack) - && - ((op->common.parent->common.aml_opcode == - AML_PACKAGE_OP) - || (op->common.parent->common.aml_opcode == - AML_VARIABLE_PACKAGE_OP))) { - /* - * We didn't find the target and we are populating elements - * of a package - ignore if slack enabled. Some ASL code - * contains dangling invalid references in packages and - * expects that no exception will be issued. Leave the - * element as a null element. It cannot be used, but it - * can be overwritten by subsequent ASL code - this is - * typically the case. - */ - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Ignoring unresolved reference in package [%4.4s]\n", - walk_state-> - scope_info->scope. - node->name.ascii)); - - return_ACPI_STATUS(AE_OK); - } else { - ACPI_ERROR_NAMESPACE(op->common.value. - string, status); - } - - return_ACPI_STATUS(status); - } - } - - /* Special object resolution for elements of a package */ - - if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || - (op->common.parent->common.aml_opcode == - AML_VARIABLE_PACKAGE_OP)) { - /* - * Attempt to resolve the node to a value before we insert it into - * the package. If this is a reference to a common data type, - * resolve it immediately. According to the ACPI spec, package - * elements can only be "data objects" or method references. - * Attempt to resolve to an Integer, Buffer, String or Package. - * If cannot, return the named reference (for things like Devices, - * Methods, etc.) Buffer Fields and Fields will resolve to simple - * objects (int/buf/str/pkg). - * - * NOTE: References to things like Devices, Methods, Mutexes, etc. - * will remain as named references. This behavior is not described - * in the ACPI spec, but it appears to be an oversight. - */ - obj_desc = - ACPI_CAST_PTR(union acpi_operand_object, - op->common.node); - - status = - acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR - (struct - acpi_namespace_node, - &obj_desc), - walk_state); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Special handling for Alias objects. We need to setup the type - * and the Op->Common.Node to point to the Alias target. Note, - * Alias has at most one level of indirection internally. - */ - type = op->common.node->type; - if (type == ACPI_TYPE_LOCAL_ALIAS) { - type = obj_desc->common.type; - op->common.node = - ACPI_CAST_PTR(struct acpi_namespace_node, - op->common.node->object); - } - - switch (type) { - /* - * For these types, we need the actual node, not the subobject. - * However, the subobject did not get an extra reference count above. - * - * TBD: should ex_resolve_node_to_value be changed to fix this? - */ - case ACPI_TYPE_DEVICE: - case ACPI_TYPE_THERMAL: - - acpi_ut_add_reference(op->common.node->object); - /*lint -fallthrough */ - /* - * For these types, we need the actual node, not the subobject. - * The subobject got an extra reference count in ex_resolve_node_to_value. - */ - case ACPI_TYPE_MUTEX: - case ACPI_TYPE_METHOD: - case ACPI_TYPE_POWER: - case ACPI_TYPE_PROCESSOR: - case ACPI_TYPE_EVENT: - case ACPI_TYPE_REGION: - - /* We will create a reference object for these types below */ - break; + /* Check if we are resolving a named reference within a package */ - default: + if ((op->common.parent->common.aml_opcode == + AML_PACKAGE_OP) + || (op->common.parent->common.aml_opcode == + AML_VARIABLE_PACKAGE_OP)) { /* - * All other types - the node was resolved to an actual - * object, we are done. + * We won't resolve package elements here, we will do this + * after all ACPI tables are loaded into the namespace. This + * behavior supports both forward references to named objects + * and external references to objects in other tables. */ - goto exit; + goto create_new_object; + } else { + status = acpi_ns_lookup(walk_state->scope_info, + op->common.value.string, + ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT | + ACPI_NS_DONT_OPEN_SCOPE, + NULL, + ACPI_CAST_INDIRECT_PTR + (struct + acpi_namespace_node, + &(op->common.node))); + if (ACPI_FAILURE(status)) { + ACPI_ERROR_NAMESPACE(op->common.value. + string, status); + return_ACPI_STATUS(status); + } } } } +create_new_object: + /* Create and init a new internal ACPI object */ obj_desc = acpi_ut_create_internal_object((acpi_ps_get_opcode_info @@ -240,7 +139,27 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, return_ACPI_STATUS(status); } -exit: + /* + * Handling for unresolved package reference elements. + * These are elements that are namepaths. + */ + if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || + (op->common.parent->common.aml_opcode == AML_VARIABLE_PACKAGE_OP)) { + obj_desc->reference.resolved = TRUE; + + if ((op->common.aml_opcode == AML_INT_NAMEPATH_OP) && + !obj_desc->reference.node) { + /* + * Name was unresolved above. + * Get the prefix node for later lookup + */ + obj_desc->reference.node = + walk_state->scope_info->scope.node; + obj_desc->reference.aml = op->common.aml; + obj_desc->reference.resolved = FALSE; + } + } + *obj_desc_ptr = obj_desc; return_ACPI_STATUS(status); } @@ -349,200 +268,6 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_OK); } -/******************************************************************************* - * - * FUNCTION: acpi_ds_build_internal_package_obj - * - * PARAMETERS: walk_state - Current walk state - * op - Parser object to be translated - * element_count - Number of elements in the package - this is - * the num_elements argument to Package() - * obj_desc_ptr - Where the ACPI internal object is returned - * - * RETURN: Status - * - * DESCRIPTION: Translate a parser Op package object to the equivalent - * namespace object - * - * NOTE: The number of elements in the package will be always be the num_elements - * count, regardless of the number of elements in the package list. If - * num_elements is smaller, only that many package list elements are used. - * if num_elements is larger, the Package object is padded out with - * objects of type Uninitialized (as per ACPI spec.) - * - * Even though the ASL compilers do not allow num_elements to be smaller - * than the Package list length (for the fixed length package opcode), some - * BIOS code modifies the AML on the fly to adjust the num_elements, and - * this code compensates for that. This also provides compatibility with - * other AML interpreters. - * - ******************************************************************************/ - -acpi_status -acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, - union acpi_parse_object *op, - u32 element_count, - union acpi_operand_object **obj_desc_ptr) -{ - union acpi_parse_object *arg; - union acpi_parse_object *parent; - union acpi_operand_object *obj_desc = NULL; - acpi_status status = AE_OK; - u32 i; - u16 index; - u16 reference_count; - - ACPI_FUNCTION_TRACE(ds_build_internal_package_obj); - - /* Find the parent of a possibly nested package */ - - parent = op->common.parent; - while ((parent->common.aml_opcode == AML_PACKAGE_OP) || - (parent->common.aml_opcode == AML_VARIABLE_PACKAGE_OP)) { - parent = parent->common.parent; - } - - /* - * If we are evaluating a Named package object "Name (xxxx, Package)", - * the package object already exists, otherwise it must be created. - */ - obj_desc = *obj_desc_ptr; - if (!obj_desc) { - obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_PACKAGE); - *obj_desc_ptr = obj_desc; - if (!obj_desc) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - obj_desc->package.node = parent->common.node; - } - - /* - * Allocate the element array (array of pointers to the individual - * objects) based on the num_elements parameter. Add an extra pointer slot - * so that the list is always null terminated. - */ - obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) - element_count + - 1) * sizeof(void *)); - - if (!obj_desc->package.elements) { - acpi_ut_delete_object_desc(obj_desc); - return_ACPI_STATUS(AE_NO_MEMORY); - } - - obj_desc->package.count = element_count; - - /* - * Initialize the elements of the package, up to the num_elements count. - * Package is automatically padded with uninitialized (NULL) elements - * if num_elements is greater than the package list length. Likewise, - * Package is truncated if num_elements is less than the list length. - */ - arg = op->common.value.arg; - arg = arg->common.next; - for (i = 0; arg && (i < element_count); i++) { - if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { - if (arg->common.node->type == ACPI_TYPE_METHOD) { - /* - * A method reference "looks" to the parser to be a method - * invocation, so we special case it here - */ - arg->common.aml_opcode = AML_INT_NAMEPATH_OP; - status = - acpi_ds_build_internal_object(walk_state, - arg, - &obj_desc-> - package. - elements[i]); - } else { - /* This package element is already built, just get it */ - - obj_desc->package.elements[i] = - ACPI_CAST_PTR(union acpi_operand_object, - arg->common.node); - } - } else { - status = - acpi_ds_build_internal_object(walk_state, arg, - &obj_desc->package. - elements[i]); - } - - if (*obj_desc_ptr) { - - /* Existing package, get existing reference count */ - - reference_count = - (*obj_desc_ptr)->common.reference_count; - if (reference_count > 1) { - - /* Make new element ref count match original ref count */ - - for (index = 0; index < (reference_count - 1); - index++) { - acpi_ut_add_reference((obj_desc-> - package. - elements[i])); - } - } - } - - arg = arg->common.next; - } - - /* Check for match between num_elements and actual length of package_list */ - - if (arg) { - /* - * num_elements was exhausted, but there are remaining elements in the - * package_list. Truncate the package to num_elements. - * - * Note: technically, this is an error, from ACPI spec: "It is an error - * for NumElements to be less than the number of elements in the - * PackageList". However, we just print a message and - * no exception is returned. This provides Windows compatibility. Some - * BIOSs will alter the num_elements on the fly, creating this type - * of ill-formed package object. - */ - while (arg) { - /* - * We must delete any package elements that were created earlier - * and are not going to be used because of the package truncation. - */ - if (arg->common.node) { - acpi_ut_remove_reference(ACPI_CAST_PTR - (union - acpi_operand_object, - arg->common.node)); - arg->common.node = NULL; - } - - /* Find out how many elements there really are */ - - i++; - arg = arg->common.next; - } - - ACPI_INFO(("Actual Package length (%u) is larger than " - "NumElements field (%u), truncated", - i, element_count)); - } else if (i < element_count) { - /* - * Arg list (elements) was exhausted, but we did not reach num_elements count. - * Note: this is not an error, the package is padded out with NULLs. - */ - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Package List length (%u) smaller than NumElements " - "count (%u), padded with null elements\n", - i, element_count)); - } - - obj_desc->package.flags |= AOPOBJ_DATA_VALID; - op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc); - return_ACPI_STATUS(status); -} - /******************************************************************************* * * FUNCTION: acpi_ds_create_node @@ -662,11 +387,20 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, case ACPI_TYPE_PACKAGE: /* - * Defer evaluation of Package term_arg operand + * Defer evaluation of Package term_arg operand and all + * package elements. (01/2017): We defer the element + * resolution to allow forward references from the package + * in order to provide compatibility with other ACPI + * implementations. */ obj_desc->package.node = ACPI_CAST_PTR(struct acpi_namespace_node, walk_state->operands[0]); + + if (!op->named.data) { + return_ACPI_STATUS(AE_OK); + } + obj_desc->package.aml_start = op->named.data; obj_desc->package.aml_length = op->named.length; break; @@ -818,9 +552,11 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, /* Node was saved in Op */ obj_desc->reference.node = op->common.node; - obj_desc->reference.object = - op->common.node->object; obj_desc->reference.class = ACPI_REFCLASS_NAME; + if (op->common.node) { + obj_desc->reference.object = + op->common.node->object; + } break; case AML_DEBUG_OP: diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index dfc3c25a083d..0336df7ac47d 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -599,6 +599,15 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state, */ walk_state->operand_index = walk_state->num_operands; + /* Ignore if child is not valid */ + + if (!op->common.value.arg) { + ACPI_ERROR((AE_INFO, + "Dispatch: Missing child while executing TermArg for %X", + op->common.aml_opcode)); + return_ACPI_STATUS(AE_OK); + } + status = acpi_ds_create_operand(walk_state, op->common.value.arg, 1); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); diff --git a/drivers/acpi/acpica/dspkginit.c b/drivers/acpi/acpica/dspkginit.c new file mode 100644 index 000000000000..6d487edfe2de --- /dev/null +++ b/drivers/acpi/acpica/dspkginit.c @@ -0,0 +1,496 @@ +/****************************************************************************** + * + * Module Name: dspkginit - Completion of deferred package initialization + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2017, 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 "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" + +#define _COMPONENT ACPI_NAMESPACE +ACPI_MODULE_NAME("dspkginit") + +/* Local prototypes */ +static void +acpi_ds_resolve_package_element(union acpi_operand_object **element); + +/******************************************************************************* + * + * FUNCTION: acpi_ds_build_internal_package_obj + * + * PARAMETERS: walk_state - Current walk state + * op - Parser object to be translated + * element_count - Number of elements in the package - this is + * the num_elements argument to Package() + * obj_desc_ptr - Where the ACPI internal object is returned + * + * RETURN: Status + * + * DESCRIPTION: Translate a parser Op package object to the equivalent + * namespace object + * + * NOTE: The number of elements in the package will be always be the num_elements + * count, regardless of the number of elements in the package list. If + * num_elements is smaller, only that many package list elements are used. + * if num_elements is larger, the Package object is padded out with + * objects of type Uninitialized (as per ACPI spec.) + * + * Even though the ASL compilers do not allow num_elements to be smaller + * than the Package list length (for the fixed length package opcode), some + * BIOS code modifies the AML on the fly to adjust the num_elements, and + * this code compensates for that. This also provides compatibility with + * other AML interpreters. + * + ******************************************************************************/ + +acpi_status +acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + u32 element_count, + union acpi_operand_object **obj_desc_ptr) +{ + union acpi_parse_object *arg; + union acpi_parse_object *parent; + union acpi_operand_object *obj_desc = NULL; + acpi_status status = AE_OK; + u16 reference_count; + u32 index; + u32 i; + + ACPI_FUNCTION_TRACE(ds_build_internal_package_obj); + + /* Find the parent of a possibly nested package */ + + parent = op->common.parent; + while ((parent->common.aml_opcode == AML_PACKAGE_OP) || + (parent->common.aml_opcode == AML_VARIABLE_PACKAGE_OP)) { + parent = parent->common.parent; + } + + /* + * If we are evaluating a Named package object of the form: + * Name (xxxx, Package) + * the package object already exists, otherwise it must be created. + */ + obj_desc = *obj_desc_ptr; + if (!obj_desc) { + obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_PACKAGE); + *obj_desc_ptr = obj_desc; + if (!obj_desc) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + obj_desc->package.node = parent->common.node; + } + + if (obj_desc->package.flags & AOPOBJ_DATA_VALID) { /* Just in case */ + return_ACPI_STATUS(AE_OK); + } + + /* + * Allocate the element array (array of pointers to the individual + * objects) based on the num_elements parameter. Add an extra pointer slot + * so that the list is always null terminated. + */ + obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) + element_count + + 1) * sizeof(void *)); + + if (!obj_desc->package.elements) { + acpi_ut_delete_object_desc(obj_desc); + return_ACPI_STATUS(AE_NO_MEMORY); + } + + obj_desc->package.count = element_count; + arg = op->common.value.arg; + arg = arg->common.next; + + if (arg) { + obj_desc->package.flags |= AOPOBJ_DATA_VALID; + } + + /* + * Initialize the elements of the package, up to the num_elements count. + * Package is automatically padded with uninitialized (NULL) elements + * if num_elements is greater than the package list length. Likewise, + * Package is truncated if num_elements is less than the list length. + */ + for (i = 0; arg && (i < element_count); i++) { + if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { + if (arg->common.node->type == ACPI_TYPE_METHOD) { + /* + * A method reference "looks" to the parser to be a method + * invocation, so we special case it here + */ + arg->common.aml_opcode = AML_INT_NAMEPATH_OP; + status = + acpi_ds_build_internal_object(walk_state, + arg, + &obj_desc-> + package. + elements[i]); + } else { + /* This package element is already built, just get it */ + + obj_desc->package.elements[i] = + ACPI_CAST_PTR(union acpi_operand_object, + arg->common.node); + } + } else { + status = + acpi_ds_build_internal_object(walk_state, arg, + &obj_desc->package. + elements[i]); + if (status == AE_NOT_FOUND) { + ACPI_ERROR((AE_INFO, "%-48s", + "****DS namepath not found")); + } + + /* + * Initialize this package element. This function handles the + * resolution of named references within the package. + */ + acpi_ds_init_package_element(0, + obj_desc->package. + elements[i], NULL, + &obj_desc->package. + elements[i]); + } + + if (*obj_desc_ptr) { + + /* Existing package, get existing reference count */ + + reference_count = + (*obj_desc_ptr)->common.reference_count; + if (reference_count > 1) { + + /* Make new element ref count match original ref count */ + /* TBD: Probably need an acpi_ut_add_references function */ + + for (index = 0; + index < ((u32)reference_count - 1); + index++) { + acpi_ut_add_reference((obj_desc-> + package. + elements[i])); + } + } + } + + arg = arg->common.next; + } + + /* Check for match between num_elements and actual length of package_list */ + + if (arg) { + /* + * num_elements was exhausted, but there are remaining elements in + * the package_list. Truncate the package to num_elements. + * + * Note: technically, this is an error, from ACPI spec: "It is an + * error for NumElements to be less than the number of elements in + * the PackageList". However, we just print a message and no + * exception is returned. This provides compatibility with other + * ACPI implementations. Some firmware implementations will alter + * the num_elements on the fly, possibly creating this type of + * ill-formed package object. + */ + while (arg) { + /* + * We must delete any package elements that were created earlier + * and are not going to be used because of the package truncation. + */ + if (arg->common.node) { + acpi_ut_remove_reference(ACPI_CAST_PTR + (union + acpi_operand_object, + arg->common.node)); + arg->common.node = NULL; + } + + /* Find out how many elements there really are */ + + i++; + arg = arg->common.next; + } + + ACPI_INFO(("Actual Package length (%u) is larger than " + "NumElements field (%u), truncated", + i, element_count)); + } else if (i < element_count) { + /* + * Arg list (elements) was exhausted, but we did not reach + * num_elements count. + * + * Note: this is not an error, the package is padded out + * with NULLs. + */ + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Package List length (%u) smaller than NumElements " + "count (%u), padded with null elements\n", + i, element_count)); + } + + obj_desc->package.flags |= AOPOBJ_DATA_VALID; + op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ds_init_package_element + * + * PARAMETERS: acpi_pkg_callback + * + * RETURN: Status + * + * DESCRIPTION: Resolve a named reference element within a package object + * + ******************************************************************************/ + +acpi_status +acpi_ds_init_package_element(u8 object_type, + union acpi_operand_object *source_object, + union acpi_generic_state *state, void *context) +{ + union acpi_operand_object **element_ptr; + + if (!source_object) { + return (AE_OK); + } + + /* + * The following code is a bit of a hack to workaround a (current) + * limitation of the acpi_pkg_callback interface. We need a pointer + * to the location within the element array because a new object + * may be created and stored there. + */ + if (context) { + + /* A direct call was made to this function */ + + element_ptr = (union acpi_operand_object **)context; + } else { + /* Call came from acpi_ut_walk_package_tree */ + + element_ptr = state->pkg.this_target_obj; + } + + /* We are only interested in reference objects/elements */ + + if (source_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) { + + /* Attempt to resolve the (named) reference to a namespace node */ + + acpi_ds_resolve_package_element(element_ptr); + } else if (source_object->common.type == ACPI_TYPE_PACKAGE) { + source_object->package.flags |= AOPOBJ_DATA_VALID; + } + + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ds_resolve_package_element + * + * PARAMETERS: element_ptr - Pointer to a reference object + * + * RETURN: Possible new element is stored to the indirect element_ptr + * + * DESCRIPTION: Resolve a package element that is a reference to a named + * object. + * + ******************************************************************************/ + +static void +acpi_ds_resolve_package_element(union acpi_operand_object **element_ptr) +{ + acpi_status status; + union acpi_generic_state scope_info; + union acpi_operand_object *element = *element_ptr; + struct acpi_namespace_node *resolved_node; + char *external_path = NULL; + acpi_object_type type; + + ACPI_FUNCTION_TRACE(ds_resolve_package_element); + + /* Check if reference element is already resolved */ + + if (element->reference.resolved) { + return_VOID; + } + + /* Element must be a reference object of correct type */ + + scope_info.scope.node = element->reference.node; /* Prefix node */ + + status = acpi_ns_lookup(&scope_info, (char *)element->reference.aml, /* Pointer to AML path */ + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, + NULL, &resolved_node); + if (ACPI_FAILURE(status)) { + status = acpi_ns_externalize_name(ACPI_UINT32_MAX, + (char *)element->reference. + aml, NULL, &external_path); + + ACPI_EXCEPTION((AE_INFO, status, + "Could not find/resolve named package element: %s", + external_path)); + + ACPI_FREE(external_path); + *element_ptr = NULL; + return_VOID; + } else if (resolved_node->type == ACPI_TYPE_ANY) { + + /* Named reference not resolved, return a NULL package element */ + + ACPI_ERROR((AE_INFO, + "Could not resolve named package element [%4.4s] in [%4.4s]", + resolved_node->name.ascii, + scope_info.scope.node->name.ascii)); + *element_ptr = NULL; + return_VOID; + } +#if 0 + else if (resolved_node->flags & ANOBJ_TEMPORARY) { + /* + * A temporary node found here indicates that the reference is + * to a node that was created within this method. We are not + * going to allow it (especially if the package is returned + * from the method) -- the temporary node will be deleted out + * from under the method. (05/2017). + */ + ACPI_ERROR((AE_INFO, + "Package element refers to a temporary name [%4.4s], " + "inserting a NULL element", + resolved_node->name.ascii)); + *element_ptr = NULL; + return_VOID; + } +#endif + + /* + * Special handling for Alias objects. We need resolved_node to point + * to the Alias target. This effectively "resolves" the alias. + */ + if (resolved_node->type == ACPI_TYPE_LOCAL_ALIAS) { + resolved_node = ACPI_CAST_PTR(struct acpi_namespace_node, + resolved_node->object); + } + + /* Update the reference object */ + + element->reference.resolved = TRUE; + element->reference.node = resolved_node; + type = element->reference.node->type; + + /* + * Attempt to resolve the node to a value before we insert it into + * the package. If this is a reference to a common data type, + * resolve it immediately. According to the ACPI spec, package + * elements can only be "data objects" or method references. + * Attempt to resolve to an Integer, Buffer, String or Package. + * If cannot, return the named reference (for things like Devices, + * Methods, etc.) Buffer Fields and Fields will resolve to simple + * objects (int/buf/str/pkg). + * + * NOTE: References to things like Devices, Methods, Mutexes, etc. + * will remain as named references. This behavior is not described + * in the ACPI spec, but it appears to be an oversight. + */ + status = acpi_ex_resolve_node_to_value(&resolved_node, NULL); + if (ACPI_FAILURE(status)) { + return_VOID; + } +#if 0 +/* TBD - alias support */ + /* + * Special handling for Alias objects. We need to setup the type + * and the Op->Common.Node to point to the Alias target. Note, + * Alias has at most one level of indirection internally. + */ + type = op->common.node->type; + if (type == ACPI_TYPE_LOCAL_ALIAS) { + type = obj_desc->common.type; + op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, + op->common.node->object); + } +#endif + + switch (type) { + /* + * These object types are a result of named references, so we will + * leave them as reference objects. In other words, these types + * have no intrinsic "value". + */ + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_THERMAL: + + /* TBD: This may not be necesssary */ + + acpi_ut_add_reference(resolved_node->object); + break; + + case ACPI_TYPE_MUTEX: + case ACPI_TYPE_METHOD: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_EVENT: + case ACPI_TYPE_REGION: + + break; + + default: + /* + * For all other types - the node was resolved to an actual + * operand object with a value, return the object + */ + *element_ptr = (union acpi_operand_object *)resolved_node; + break; + } + + return_VOID; +} diff --git a/drivers/acpi/acpica/nsarguments.c b/drivers/acpi/acpica/nsarguments.c index 9095d51f6b37..67b7370dcae5 100644 --- a/drivers/acpi/acpica/nsarguments.c +++ b/drivers/acpi/acpica/nsarguments.c @@ -69,9 +69,14 @@ void acpi_ns_check_argument_types(struct acpi_evaluate_info *info) u8 user_arg_type; u32 i; - /* If not a predefined name, cannot typecheck args */ - - if (!info->predefined) { + /* + * If not a predefined name, cannot typecheck args, because + * we have no idea what argument types are expected. + * Also, ignore typecheck if warnings/errors if this method + * has already been evaluated at least once -- in order + * to suppress repetitive messages. + */ + if (!info->predefined || (info->node->flags & ANOBJ_EVALUATED)) { return; } @@ -93,6 +98,10 @@ void acpi_ns_check_argument_types(struct acpi_evaluate_info *info) acpi_ut_get_type_name (user_arg_type), acpi_ut_get_type_name(arg_type))); + + /* Prevent any additional typechecking for this method */ + + info->node->flags |= ANOBJ_EVALUATED; } } } @@ -121,7 +130,7 @@ acpi_ns_check_acpi_compliance(char *pathname, u32 aml_param_count; u32 required_param_count; - if (!predefined) { + if (!predefined || (node->flags & ANOBJ_EVALUATED)) { return; } @@ -215,6 +224,10 @@ acpi_ns_check_argument_count(char *pathname, u32 aml_param_count; u32 required_param_count; + if (node->flags & ANOBJ_EVALUATED) { + return; + } + if (!predefined) { /* * Not a predefined name. Check the incoming user argument count diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index ce33e7297ea7..9c6297949712 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -396,6 +396,20 @@ acpi_ns_init_one_object(acpi_handle obj_handle, info->package_init++; status = acpi_ds_get_package_arguments(obj_desc); + if (ACPI_FAILURE(status)) { + break; + } + + /* + * Resolve all named references in package objects (and all + * sub-packages). This action has been deferred until the entire + * namespace has been loaded, in order to support external and + * forward references from individual package elements (05/2017). + */ + status = acpi_ut_walk_package_tree(obj_desc, NULL, + acpi_ds_init_package_element, + NULL); + obj_desc->package.flags |= AOPOBJ_DATA_VALID; break; default: diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index aa16aeaa8937..a410760a0308 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -89,7 +89,14 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) { acpi_size size; - ACPI_FUNCTION_ENTRY(); + /* Validate the Node */ + + if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) { + ACPI_ERROR((AE_INFO, + "Invalid/cached reference target node: %p, descriptor type %d", + node, ACPI_GET_DESCRIPTOR_TYPE(node))); + return (0); + } size = acpi_ns_build_normalized_path(node, NULL, 0, FALSE); return (size); diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index b4224005783c..bb04dec168ad 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -164,6 +164,11 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, INCREMENT_ARG_LIST(walk_state->arg_types); } + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "Final argument count: %u pass %u\n", + walk_state->arg_count, + walk_state->pass_number)); + /* * Handle executable code at "module-level". This refers to * executable opcodes that appear outside of any control method. @@ -277,6 +282,11 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, AML_NAME_OP) && (walk_state->pass_number <= ACPI_IMODE_LOAD_PASS2)) { + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "Setup Package/Buffer: Pass %u, AML Ptr: %p\n", + walk_state->pass_number, + aml_op_start)); + /* * Skip parsing of Buffers and Packages because we don't have * enough info in the first pass to parse them correctly. @@ -570,6 +580,10 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) /* Check for arguments that need to be processed */ + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "Parseloop: argument count: %u\n", + walk_state->arg_count)); + if (walk_state->arg_count) { /* * There are arguments (complex ones), push Op and diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 443ffad01209..4d9f3a2a4f8e 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -224,7 +224,7 @@ acpi_ut_create_update_state_and_push(union acpi_operand_object *object, * * RETURN: Status * - * DESCRIPTION: Walk through a package + * DESCRIPTION: Walk through a package, including subpackages * ******************************************************************************/ @@ -236,8 +236,8 @@ acpi_ut_walk_package_tree(union acpi_operand_object *source_object, acpi_status status = AE_OK; union acpi_generic_state *state_list = NULL; union acpi_generic_state *state; - u32 this_index; union acpi_operand_object *this_source_obj; + u32 this_index; ACPI_FUNCTION_TRACE(ut_walk_package_tree); @@ -251,8 +251,10 @@ acpi_ut_walk_package_tree(union acpi_operand_object *source_object, /* Get one element of the package */ this_index = state->pkg.index; - this_source_obj = (union acpi_operand_object *) + this_source_obj = state->pkg.source_object->package.elements[this_index]; + state->pkg.this_target_obj = + &state->pkg.source_object->package.elements[this_index]; /* * Check for: diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index 64e6641bfe82..cb3db9fed50d 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -483,6 +483,11 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object, /* A namespace node should never get here */ + ACPI_ERROR((AE_INFO, + "Received a namespace node [%4.4s] " + "where an operand object is required", + ACPI_CAST_PTR(struct acpi_namespace_node, + internal_object)->name.ascii)); return_ACPI_STATUS(AE_AML_INTERNAL); } diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c index 64308c304ade..eafabcd2fada 100644 --- a/drivers/acpi/acpica/utstate.c +++ b/drivers/acpi/acpica/utstate.c @@ -226,7 +226,7 @@ union acpi_generic_state *acpi_ut_create_update_state(union acpi_operand_object union acpi_generic_state *acpi_ut_create_pkg_state(void *internal_object, void *external_object, - u16 index) + u32 index) { union acpi_generic_state *state; diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c index 9a07a42cae34..3c8de88ecbd5 100644 --- a/drivers/acpi/acpica/uttrack.c +++ b/drivers/acpi/acpica/uttrack.c @@ -591,6 +591,10 @@ void acpi_ut_dump_allocations(u32 component, const char *module) return_VOID; } + if (!acpi_gbl_global_list) { + goto exit; + } + element = acpi_gbl_global_list->list_head; while (element) { if ((element->component & component) && @@ -602,7 +606,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module) if (element->size < sizeof(struct acpi_common_descriptor)) { - acpi_os_printf("%p Length 0x%04X %9.9s-%u " + acpi_os_printf("%p Length 0x%04X %9.9s-%4.4u " "[Not a Descriptor - too small]\n", descriptor, element->size, element->module, element->line); @@ -612,7 +616,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module) if (ACPI_GET_DESCRIPTOR_TYPE(descriptor) != ACPI_DESC_TYPE_CACHED) { acpi_os_printf - ("%p Length 0x%04X %9.9s-%u [%s] ", + ("%p Length 0x%04X %9.9s-%4.4u [%s] ", descriptor, element->size, element->module, element->line, acpi_ut_get_descriptor_name @@ -705,6 +709,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module) element = element->next; } +exit: (void)acpi_ut_release_mutex(ACPI_MTX_MEMORY); /* Print summary */ -- cgit From 376a588ceca401289cb40287503cc31dd643188f Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 3 Aug 2017 14:27:28 +0800 Subject: ACPICA: Ensure all instances of AE_AML_INTERNAL have error messages ACPICA commit ea9152daaec30760fa4c25285998f58233ec0db5 This exception is only meaningful with an associated error message. Link: https://github.com/acpica/acpica/commit/ea9152da Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dsfield.c | 2 ++ drivers/acpi/acpica/exmisc.c | 9 +++++++++ drivers/acpi/acpica/exoparg2.c | 3 +++ drivers/acpi/acpica/nsprepkg.c | 2 ++ drivers/acpi/acpica/utmisc.c | 2 ++ 5 files changed, 18 insertions(+) diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index c5dccc54307d..7bcf5f5ea029 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -184,6 +184,7 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, /* Execute flag should always be set when this function is entered */ if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) { + ACPI_ERROR((AE_INFO, "Parse execute mode is not set")); return_ACPI_STATUS(AE_AML_INTERNAL); } @@ -556,6 +557,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, return_ACPI_STATUS(AE_OK); } + ACPI_ERROR((AE_INFO, "Parse deferred mode is not set")); return_ACPI_STATUS(AE_AML_INTERNAL); } diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index f222a80ca38e..1e7649ce0a7b 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -265,6 +265,8 @@ acpi_ex_do_logical_numeric_op(u16 opcode, default: + ACPI_ERROR((AE_INFO, + "Invalid numeric logical opcode: %X", opcode)); status = AE_AML_INTERNAL; break; } @@ -345,6 +347,9 @@ acpi_ex_do_logical_op(u16 opcode, default: + ACPI_ERROR((AE_INFO, + "Invalid object type for logical operator: %X", + operand0->common.type)); status = AE_AML_INTERNAL; break; } @@ -388,6 +393,8 @@ acpi_ex_do_logical_op(u16 opcode, default: + ACPI_ERROR((AE_INFO, + "Invalid comparison opcode: %X", opcode)); status = AE_AML_INTERNAL; break; } @@ -456,6 +463,8 @@ acpi_ex_do_logical_op(u16 opcode, default: + ACPI_ERROR((AE_INFO, + "Invalid comparison opcode: %X", opcode)); status = AE_AML_INTERNAL; break; } diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index eecb3bff7fd7..57980b7d3594 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -414,6 +414,9 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) default: + ACPI_ERROR((AE_INFO, + "Invalid object type: %X", + (operand[0])->common.type)); status = AE_AML_INTERNAL; goto cleanup; } diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c index 4954cb6c9090..a8ea8fb1d299 100644 --- a/drivers/acpi/acpica/nsprepkg.c +++ b/drivers/acpi/acpica/nsprepkg.c @@ -614,6 +614,8 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info, default: /* Should not get here, type was validated by caller */ + ACPI_ERROR((AE_INFO, "Invalid Package type: %X", + package->ret_info.type)); return (AE_AML_INTERNAL); } diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 4d9f3a2a4f8e..45c78c2adbf0 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -341,6 +341,8 @@ acpi_ut_walk_package_tree(union acpi_operand_object *source_object, /* We should never get here */ + ACPI_ERROR((AE_INFO, "State list did not terminate correctly")); + return_ACPI_STATUS(AE_AML_INTERNAL); } -- cgit From 137c78352ea98db70d0f2aa648f723bb444faee8 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 3 Aug 2017 14:27:35 +0800 Subject: ACPICA: Resources: Allow _DMA method in walk resources ACPICA commit af661c00afac7aa481a961fa48c6540a99ad64a6 The _DMA object contains a resource template, this change adds support for the walk resources function so that ACPI devices containing a _DMA object can actually parse it to detect DMA ranges for the respective bus. Link: https://github.com/acpica/acpica/commit/af661c00 Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/rsxface.c | 7 ++++--- include/acpi/acnames.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 59a4f9ed06a7..be65e65e216e 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -615,7 +615,7 @@ ACPI_EXPORT_SYMBOL(acpi_walk_resource_buffer) * device we are querying * name - Method name of the resources we want. * (METHOD_NAME__CRS, METHOD_NAME__PRS, or - * METHOD_NAME__AEI) + * METHOD_NAME__AEI or METHOD_NAME__DMA) * user_function - Called for each resource * context - Passed to user_function * @@ -641,11 +641,12 @@ acpi_walk_resources(acpi_handle device_handle, if (!device_handle || !user_function || !name || (!ACPI_COMPARE_NAME(name, METHOD_NAME__CRS) && !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS) && - !ACPI_COMPARE_NAME(name, METHOD_NAME__AEI))) { + !ACPI_COMPARE_NAME(name, METHOD_NAME__AEI) && + !ACPI_COMPARE_NAME(name, METHOD_NAME__DMA))) { return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Get the _CRS/_PRS/_AEI resource list */ + /* Get the _CRS/_PRS/_AEI/_DMA resource list */ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; status = acpi_rs_get_method_data(device_handle, name, &buffer); diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h index b421584033a5..d8dd3bf51ca7 100644 --- a/include/acpi/acnames.h +++ b/include/acpi/acnames.h @@ -54,6 +54,7 @@ #define METHOD_NAME__CLS "_CLS" #define METHOD_NAME__CRS "_CRS" #define METHOD_NAME__DDN "_DDN" +#define METHOD_NAME__DMA "_DMA" #define METHOD_NAME__HID "_HID" #define METHOD_NAME__INI "_INI" #define METHOD_NAME__PLD "_PLD" -- cgit From d5efc154e797f72064ce5bac82213df09f1586b1 Mon Sep 17 00:00:00 2001 From: Erik Schmauss Date: Thu, 3 Aug 2017 14:27:42 +0800 Subject: ACPICA: Revert "Update resource descriptor handling" ACPICA commit f3300640c63df138d133740b54e2c0a1befa4086 This reverts commit c8eac10178b387f9eb1935694e509d4518da77bb. Link: https://github.com/acpica/acpica/commit/f3300640 Signed-off-by: Erik Schmauss Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utresrc.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index 517acf8e77c8..f9801d13547f 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -184,11 +184,9 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, ACPI_FUNCTION_TRACE(ut_walk_aml_resources); - /* - * The absolute minimum resource template is one end_tag descriptor. - * However, we will treat a lone end_tag as just a simple buffer. - */ - if (aml_length <= sizeof(struct aml_resource_end_tag)) { + /* The absolute minimum resource template is one end_tag descriptor */ + + if (aml_length < sizeof(struct aml_resource_end_tag)) { return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); } @@ -252,10 +250,8 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, *context = aml; } - /* - * Normal exit. Note: We allow the buffer to be larger than - * the resource template, as long as the END_TAG exists. - */ + /* Normal exit */ + return_ACPI_STATUS(AE_OK); } -- cgit From 4a9673dd50c2362f5bd2d03c89099267b49d400a Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 3 Aug 2017 14:27:48 +0800 Subject: ACPICA: Update version to 20170728 ACPICA commit 50f61636543a55d143c792a4814da7700a7fafc2 Version 20170728. Link: https://github.com/acpica/acpica/commit/50f61636 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 06b87adc97ef..53c5e2f7bcec 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20170629 +#define ACPI_CA_VERSION 0x20170728 #include #include -- cgit From 4f0450af530e62b0217522cab4803b5a65dccc46 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Thu, 3 Aug 2017 13:32:36 +0100 Subject: ACPI: Make acpi_dev_get_resources() method agnostic The function acpi_dev_get_resources() is completely generic and can be used to parse resource objects that are not necessarily coming from the _CRS method but also from other objects eg _DMA that have the same _CRS resource format. Create an acpi_dev_get_resources() helper, internal to the ACPI resources parsing compilation unit, __acpi_dev_get_resources(), that takes a const char* parameter to detect which ACPI method should be called to retrieve the resources list and make acpi_dev_get_resources() call it with a method name _CRS leaving the API behaviour unchanged. Signed-off-by: Lorenzo Pieralisi Tested-by: Nate Watterson Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 53 +++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index cd4c4271dc4c..93f1b5ce89b9 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -573,6 +573,35 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, return AE_OK; } +static int __acpi_dev_get_resources(struct acpi_device *adev, + struct list_head *list, + int (*preproc)(struct acpi_resource *, void *), + void *preproc_data, char *method) +{ + struct res_proc_context c; + acpi_status status; + + if (!adev || !adev->handle || !list_empty(list)) + return -EINVAL; + + if (!acpi_has_method(adev->handle, method)) + return 0; + + c.list = list; + c.preproc = preproc; + c.preproc_data = preproc_data; + c.count = 0; + c.error = 0; + status = acpi_walk_resources(adev->handle, method, + acpi_dev_process_resource, &c); + if (ACPI_FAILURE(status)) { + acpi_dev_free_resource_list(list); + return c.error ? c.error : -EIO; + } + + return c.count; +} + /** * acpi_dev_get_resources - Get current resources of a device. * @adev: ACPI device node to get the resources for. @@ -601,28 +630,8 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, int (*preproc)(struct acpi_resource *, void *), void *preproc_data) { - struct res_proc_context c; - acpi_status status; - - if (!adev || !adev->handle || !list_empty(list)) - return -EINVAL; - - if (!acpi_has_method(adev->handle, METHOD_NAME__CRS)) - return 0; - - c.list = list; - c.preproc = preproc; - c.preproc_data = preproc_data; - c.count = 0; - c.error = 0; - status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, - acpi_dev_process_resource, &c); - if (ACPI_FAILURE(status)) { - acpi_dev_free_resource_list(list); - return c.error ? c.error : -EIO; - } - - return c.count; + return __acpi_dev_get_resources(adev, list, preproc, preproc_data, + METHOD_NAME__CRS); } EXPORT_SYMBOL_GPL(acpi_dev_get_resources); -- cgit From c04ac679c6b86e4e36fbb675c6c061b4091f5810 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 7 Aug 2017 11:29:48 +0100 Subject: ACPI: Introduce DMA ranges parsing Some devices have limited addressing capabilities and cannot reference the whole memory address space while carrying out DMA operations (eg some devices with bus address bits range smaller than system bus - which prevents them from using bus addresses that are otherwise valid for the system). The ACPI _DMA object allows bus devices to define the DMA window that is actually addressable by devices that sit upstream the bus, therefore providing a means to parse and initialize the devices DMA masks and addressable DMA range size. By relying on the generic ACPI kernel layer to retrieve and parse resources, introduce ACPI core code to parse the _DMA object. Signed-off-by: Lorenzo Pieralisi Tested-by: Nate Watterson Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 35 ++++++++++++++++++++++ drivers/acpi/scan.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_bus.h | 2 ++ include/linux/acpi.h | 8 +++++ 4 files changed, 124 insertions(+) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 93f1b5ce89b9..d85e010ee2cc 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -635,6 +635,41 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, } EXPORT_SYMBOL_GPL(acpi_dev_get_resources); +static int is_memory(struct acpi_resource *ares, void *not_used) +{ + struct resource_win win; + struct resource *res = &win.res; + + memset(&win, 0, sizeof(win)); + + return !(acpi_dev_resource_memory(ares, res) + || acpi_dev_resource_address_space(ares, &win) + || acpi_dev_resource_ext_address_space(ares, &win)); +} + +/** + * acpi_dev_get_dma_resources - Get current DMA resources of a device. + * @adev: ACPI device node to get the resources for. + * @list: Head of the resultant list of resources (must be empty). + * + * Evaluate the _DMA method for the given device node and process its + * output. + * + * The resultant struct resource objects are put on the list pointed to + * by @list, that must be empty initially, as members of struct + * resource_entry objects. Callers of this routine should use + * %acpi_dev_free_resource_list() to free that list. + * + * The number of resources in the output list is returned on success, + * an error code reflecting the error condition is returned otherwise. + */ +int acpi_dev_get_dma_resources(struct acpi_device *adev, struct list_head *list) +{ + return __acpi_dev_get_resources(adev, list, is_memory, NULL, + METHOD_NAME__DMA); +} +EXPORT_SYMBOL_GPL(acpi_dev_get_dma_resources); + /** * acpi_dev_filter_resource_type - Filter ACPI resource according to resource * types diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 33897298f03e..94500d99f2d6 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1359,6 +1359,85 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) return DEV_DMA_NON_COHERENT; } +/** + * acpi_dma_get_range() - Get device DMA parameters. + * + * @dev: device to configure + * @dma_addr: pointer device DMA address result + * @offset: pointer to the DMA offset result + * @size: pointer to DMA range size result + * + * Evaluate DMA regions and return respectively DMA region start, offset + * and size in dma_addr, offset and size on parsing success; it does not + * update the passed in values on failure. + * + * Return 0 on success, < 0 on failure. + */ +int acpi_dma_get_range(struct device *dev, u64 *dma_addr, u64 *offset, + u64 *size) +{ + struct acpi_device *adev; + LIST_HEAD(list); + struct resource_entry *rentry; + int ret; + struct device *dma_dev = dev; + u64 len, dma_start = U64_MAX, dma_end = 0, dma_offset = 0; + + /* + * Walk the device tree chasing an ACPI companion with a _DMA + * object while we go. Stop if we find a device with an ACPI + * companion containing a _DMA method. + */ + do { + adev = ACPI_COMPANION(dma_dev); + if (adev && acpi_has_method(adev->handle, METHOD_NAME__DMA)) + break; + + dma_dev = dma_dev->parent; + } while (dma_dev); + + if (!dma_dev) + return -ENODEV; + + if (!acpi_has_method(adev->handle, METHOD_NAME__CRS)) { + acpi_handle_warn(adev->handle, "_DMA is valid only if _CRS is present\n"); + return -EINVAL; + } + + ret = acpi_dev_get_dma_resources(adev, &list); + if (ret > 0) { + list_for_each_entry(rentry, &list, node) { + if (dma_offset && rentry->offset != dma_offset) { + ret = -EINVAL; + dev_warn(dma_dev, "Can't handle multiple windows with different offsets\n"); + goto out; + } + dma_offset = rentry->offset; + + /* Take lower and upper limits */ + if (rentry->res->start < dma_start) + dma_start = rentry->res->start; + if (rentry->res->end > dma_end) + dma_end = rentry->res->end; + } + + if (dma_start >= dma_end) { + ret = -EINVAL; + dev_dbg(dma_dev, "Invalid DMA regions configuration\n"); + goto out; + } + + *dma_addr = dma_start - dma_offset; + len = dma_end - dma_start; + *size = max(len, len + 1); + *offset = dma_offset; + } + out: + acpi_dev_free_resource_list(&list); + + return ret >= 0 ? 0 : ret; +} + /** * acpi_dma_configure - Set-up DMA configuration for the device. * @dev: The pointer to the device diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 68bc6be447fd..07eb963b5026 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -578,6 +578,8 @@ struct acpi_pci_root { bool acpi_dma_supported(struct acpi_device *adev); enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev); +int acpi_dma_get_range(struct device *dev, u64 *dma_addr, u64 *offset, + u64 *size); int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr); void acpi_dma_deconfigure(struct device *dev); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index c749eef1daa1..a5eaff9f2c6d 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -427,6 +427,8 @@ void acpi_dev_free_resource_list(struct list_head *list); int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, int (*preproc)(struct acpi_resource *, void *), void *preproc_data); +int acpi_dev_get_dma_resources(struct acpi_device *adev, + struct list_head *list); int acpi_dev_filter_resource_type(struct acpi_resource *ares, unsigned long types); @@ -774,6 +776,12 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) return DEV_DMA_NOT_SUPPORTED; } +static inline int acpi_dma_get_range(struct device *dev, u64 *dma_addr, + u64 *offset, u64 *size) +{ + return -ENODEV; +} + static inline int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) { -- cgit From 7ad4263980826e8b02e121af22f4f4c9103fe86d Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 7 Aug 2017 11:29:49 +0100 Subject: ACPI: Make acpi_dma_configure() DMA regions aware Current ACPI DMA configuration set-up device DMA capabilities through kernel defaults that do not take into account platform specific DMA configurations reported by firmware. By leveraging the ACPI acpi_dev_get_dma_resources() API, add code in acpi_dma_configure() to retrieve the DMA regions to correctly set-up PCI devices DMA parameters. Rework the ACPI IORT kernel API to make sure they can accommodate the DMA set-up required by firmware. By making PCI devices DMA set-up ACPI IORT specific, the kernel is shielded from unwanted regressions that could be triggered by parsing DMA resources on arches that were previously ignoring them (ie x86/ia64), leaving kernel behaviour unchanged on those arches. Signed-off-by: Lorenzo Pieralisi Acked-by: Will Deacon Tested-by: Nate Watterson Signed-off-by: Rafael J. Wysocki --- drivers/acpi/arm64/iort.c | 37 +++++++++++++++++++++++++++++++++++-- drivers/acpi/scan.c | 12 ++++-------- include/linux/acpi_iort.h | 5 +++-- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index a3215ee671c1..606af87c425f 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -681,12 +681,17 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev, } /** - * iort_set_dma_mask - Set-up dma mask for a device. + * iort_dma_setup() - Set-up device DMA parameters. * * @dev: device to configure + * @dma_addr: device DMA address result pointer + * @size: DMA range size result pointer */ -void iort_set_dma_mask(struct device *dev) +void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) { + u64 mask, dmaaddr = 0, size = 0, offset = 0; + int ret, msb; + /* * Set default coherent_dma_mask to 32 bit. Drivers are expected to * setup the correct supported mask. @@ -700,6 +705,34 @@ void iort_set_dma_mask(struct device *dev) */ if (!dev->dma_mask) dev->dma_mask = &dev->coherent_dma_mask; + + size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); + + if (dev_is_pci(dev)) { + ret = acpi_dma_get_range(dev, &dmaaddr, &offset, &size); + if (!ret) { + msb = fls64(dmaaddr + size - 1); + /* + * Round-up to the power-of-two mask or set + * the mask to the whole 64-bit address space + * in case the DMA region covers the full + * memory window. + */ + mask = msb == 64 ? U64_MAX : (1ULL << msb) - 1; + /* + * Limit coherent and dma mask based on size + * retrieved from firmware. + */ + dev->coherent_dma_mask = mask; + *dev->dma_mask = mask; + } + } + + *dma_addr = dmaaddr; + *dma_size = size; + + dev->dma_pfn_offset = PFN_DOWN(offset); + dev_dbg(dev, "dma_pfn_offset(%#08llx)\n", offset); } /** diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 94500d99f2d6..0483d36433ac 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1446,20 +1446,16 @@ int acpi_dma_get_range(struct device *dev, u64 *dma_addr, u64 *offset, int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) { const struct iommu_ops *iommu; - u64 size; + u64 dma_addr = 0, size = 0; - iort_set_dma_mask(dev); + iort_dma_setup(dev, &dma_addr, &size); iommu = iort_iommu_configure(dev); if (IS_ERR(iommu) && PTR_ERR(iommu) == -EPROBE_DEFER) return -EPROBE_DEFER; - size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); - /* - * Assume dma valid range starts at 0 and covers the whole - * coherent_dma_mask. - */ - arch_setup_dma_ops(dev, 0, size, iommu, attr == DEV_DMA_COHERENT); + arch_setup_dma_ops(dev, dma_addr, size, + iommu, attr == DEV_DMA_COHERENT); return 0; } diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index 8379d406ad2e..8d3f0bf80379 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h @@ -36,7 +36,7 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id); void acpi_configure_pmsi_domain(struct device *dev); int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id); /* IOMMU interface */ -void iort_set_dma_mask(struct device *dev); +void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *size); const struct iommu_ops *iort_iommu_configure(struct device *dev); #else static inline void acpi_iort_init(void) { } @@ -47,7 +47,8 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev, { return NULL; } static inline void acpi_configure_pmsi_domain(struct device *dev) { } /* IOMMU interface */ -static inline void iort_set_dma_mask(struct device *dev) { } +static inline void iort_dma_setup(struct device *dev, u64 *dma_addr, + u64 *size) { } static inline const struct iommu_ops *iort_iommu_configure(struct device *dev) { return NULL; } -- cgit From 10d8ab2c15b9ef2f46c35e7c36781399d6f2cc82 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Thu, 3 Aug 2017 13:32:39 +0100 Subject: ACPI/IORT: Add IORT named component memory address limits IORT named components provide firmware configuration describing how many address bits a given device is capable of generating to address memory. Add code to the kernel to retrieve memory address limits configuration for IORT named components and configure DMA masks accordingly. Signed-off-by: Lorenzo Pieralisi Acked-by: Will Deacon Tested-by: Nate Watterson Signed-off-by: Rafael J. Wysocki --- drivers/acpi/arm64/iort.c | 54 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 606af87c425f..5b9e8dc29c09 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -680,6 +680,24 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev, return ret ? NULL : ops; } +static int nc_dma_get_range(struct device *dev, u64 *size) +{ + struct acpi_iort_node *node; + struct acpi_iort_named_component *ncomp; + + node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT, + iort_match_node_callback, dev); + if (!node) + return -ENODEV; + + ncomp = (struct acpi_iort_named_component *)node->node_data; + + *size = ncomp->memory_address_limit >= 64 ? U64_MAX : + 1ULL<memory_address_limit; + + return 0; +} + /** * iort_dma_setup() - Set-up device DMA parameters. * @@ -708,24 +726,26 @@ void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); - if (dev_is_pci(dev)) { + if (dev_is_pci(dev)) ret = acpi_dma_get_range(dev, &dmaaddr, &offset, &size); - if (!ret) { - msb = fls64(dmaaddr + size - 1); - /* - * Round-up to the power-of-two mask or set - * the mask to the whole 64-bit address space - * in case the DMA region covers the full - * memory window. - */ - mask = msb == 64 ? U64_MAX : (1ULL << msb) - 1; - /* - * Limit coherent and dma mask based on size - * retrieved from firmware. - */ - dev->coherent_dma_mask = mask; - *dev->dma_mask = mask; - } + else + ret = nc_dma_get_range(dev, &size); + + if (!ret) { + msb = fls64(dmaaddr + size - 1); + /* + * Round-up to the power-of-two mask or set + * the mask to the whole 64-bit address space + * in case the DMA region covers the full + * memory window. + */ + mask = msb == 64 ? U64_MAX : (1ULL << msb) - 1; + /* + * Limit coherent and dma mask based on size + * retrieved from firmware. + */ + dev->coherent_dma_mask = mask; + *dev->dma_mask = mask; } *dma_addr = dmaaddr; -- cgit From 66ed4cac669cae8870b13511492ff1d41f49179a Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Tue, 1 Aug 2017 13:43:57 +0100 Subject: mailbox: pcc: Drop uninformative output during boot When booting on an ACPI enabled system that does not provide the Platform Communications Channel Table (PCCT), the pcc mailbox driver prints - [ 0.484261] PCCT header not found. during probe before returning -ENODEV. This message clutters the bootlog and doesn't provide any useful information. Drop this message. Signed-off-by: Punit Agrawal Acked-by: Alexey Klimov Signed-off-by: Rafael J. Wysocki --- drivers/mailbox/pcc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index cbca5e51b975..9b7005e1345e 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -457,10 +457,8 @@ static int __init acpi_pcc_probe(void) /* Search for PCCT */ status = acpi_get_table(ACPI_SIG_PCCT, 0, &pcct_tbl); - if (ACPI_FAILURE(status) || !pcct_tbl) { - pr_warn("PCCT header not found.\n"); + if (ACPI_FAILURE(status) || !pcct_tbl) return -ENODEV; - } count = acpi_table_parse_entries(ACPI_SIG_PCCT, sizeof(struct acpi_table_pcct), -- cgit From a4bb2b4933557a8afdfe7a930cd68bd31e34a078 Mon Sep 17 00:00:00 2001 From: Ronald Tschalär Date: Wed, 9 Aug 2017 01:15:42 -0700 Subject: ACPI / LPSS: Don't abort ACPI scan on missing mem resource MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The keyboard and touchpad on MacBook's from 2015 onwards are connected via an SPI bus. On MacBook8's (2015) the ACPI device for the SPI master for this bus has _CID "INT33C1", and hence the acpi-lpss handler here is triggered for it. However, the DSDT lists no memory resources for this device, resulting in an error being returned by the attach callback and therefore the SPI master device being ignored. This prevents us from being able to register the keyboard and touchpad driver. Furthermore, the controller (a Wildcat Point-LP controller) does not appear to need the functionality provided by the apci-lpss handler. Therefore we now just skip the handler if no memory resources are found and let the ACPI scan complete successfully for this device. All of this is not an issue on later MacBook(Pro)'s because their ACPI SPI devices don't have any _CID and therefore no attempt is made to attach this handler. Returning an error was introduced in commit d3e13ff3c1aa - this restores the original behaviour. Link: https://github.com/cb22/macbook12-spi-driver Signed-off-by: Ronald Tschalär Acked-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_lpss.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index f88caf5aab76..032ae44710e5 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -465,7 +465,8 @@ static int acpi_lpss_create_device(struct acpi_device *adev, acpi_dev_free_resource_list(&resource_list); if (!pdata->mmio_base) { - ret = -ENOMEM; + /* Skip the device, but continue the namespace scan. */ + ret = 0; goto err_out; } -- cgit From dee82bc1e653126408f4108cd994d1e96949d064 Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Fri, 4 Aug 2017 22:49:43 +0100 Subject: ACPI: SPCR: extend XGENE 8250 workaround to m400 xgene v1/v2 chips are also used on moonshot cartridges that have different table headers to the ones on Mustang. Extend the quirk so it also recognises the Moonshot M400 variant too. Signed-off-by: Graeme Gregory Tested-by: Mark Salter Reviewed-by: Mark Salter Signed-off-by: Rafael J. Wysocki --- drivers/acpi/spcr.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index 98aa8c808a33..2c156941b371 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c @@ -53,17 +53,24 @@ static bool qdf2400_erratum_44_present(struct acpi_table_header *h) */ static bool xgene_8250_erratum_present(struct acpi_table_spcr *tb) { + bool xgene_8250 = false; + if (tb->interface_type != ACPI_DBG2_16550_COMPATIBLE) return false; - if (memcmp(tb->header.oem_id, "APMC0D", ACPI_OEM_ID_SIZE)) + if (memcmp(tb->header.oem_id, "APMC0D", ACPI_OEM_ID_SIZE) && + memcmp(tb->header.oem_id, "HPE ", ACPI_OEM_ID_SIZE)) return false; if (!memcmp(tb->header.oem_table_id, "XGENESPC", ACPI_OEM_TABLE_ID_SIZE) && tb->header.oem_revision == 0) - return true; + xgene_8250 = true; - return false; + if (!memcmp(tb->header.oem_table_id, "ProLiant", + ACPI_OEM_TABLE_ID_SIZE) && tb->header.oem_revision == 1) + xgene_8250 = true; + + return xgene_8250; } /** -- cgit From 03c3876f2e3b4c79ced7d1d227e5a7fe645ed666 Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Fri, 4 Aug 2017 22:49:44 +0100 Subject: ACPI: SPCR: work around clock issue on xgene UART xgene v1/v2 8250 UARTs don't run at the standard clock rate expected by the driver and there is no information on clocking available from the SPCR table. As there has been no progress on relevant vendors updating DBG2/SPCR specifications to fix this work around this using the previous xgene quirk handling to avoid setting a baud rate and therefore using the UART as configured by firmware. Signed-off-by: Graeme Gregory Tested-by: Mark Salter Reviewed-by: Mark Salter Signed-off-by: Rafael J. Wysocki --- drivers/acpi/spcr.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index 2c156941b371..40a56b538b9f 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c @@ -188,11 +188,19 @@ int __init parse_spcr(bool earlycon) uart = "qdf2400_e44"; } - if (xgene_8250_erratum_present(table)) + if (xgene_8250_erratum_present(table)) { iotype = "mmio32"; - snprintf(opts, sizeof(opts), "%s,%s,0x%llx,%d", uart, iotype, - table->serial_port.address, baud_rate); + /* for xgene v1 and v2 we don't know the clock rate of the + * UART so don't attempt to change to the baud rate state + * in the table because driver cannot calculate the dividers + */ + snprintf(opts, sizeof(opts), "%s,%s,0x%llx", uart, iotype, + table->serial_port.address); + } else { + snprintf(opts, sizeof(opts), "%s,%s,0x%llx,%d", uart, iotype, + table->serial_port.address, baud_rate); + } pr_info("console: %s\n", opts); -- cgit From ecc1165b8b743fd1503b9c799ae3a9933b89877b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 10 Aug 2017 00:30:09 +0200 Subject: ACPICA: Dispatch active GPEs at init time In some cases GPEs are already active when they are enabled by acpi_ev_initialize_gpe_block() and whatever happens next may depend on the result of handling the events signaled by them, so the events should not be discarded (which is what happens currently) and they should be handled as soon as reasonably possible. For this reason, modify acpi_ev_initialize_gpe_block() to dispatch GPEs with the status flag set in-band right after enabling them. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/acpica/evgpeblk.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 9c941947a063..c27386cca493 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -440,9 +440,11 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, void *ignored) { acpi_status status; + acpi_event_status event_status; struct acpi_gpe_event_info *gpe_event_info; u32 gpe_enabled_count; u32 gpe_index; + u32 gpe_number; u32 i; u32 j; @@ -470,30 +472,38 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j; gpe_event_info = &gpe_block->event_info[gpe_index]; + gpe_number = gpe_block->block_base_number + gpe_index; /* * Ignore GPEs that have no corresponding _Lxx/_Exx method - * and GPEs that are used to wake the system + * and GPEs that are used for wakeup */ - if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == - ACPI_GPE_DISPATCH_NONE) - || (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == - ACPI_GPE_DISPATCH_HANDLER) - || (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == - ACPI_GPE_DISPATCH_RAW_HANDLER) + if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != + ACPI_GPE_DISPATCH_METHOD) || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { continue; } + event_status = 0; + (void)acpi_hw_get_gpe_status(gpe_event_info, + &event_status); + status = acpi_ev_add_gpe_reference(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not enable GPE 0x%02X", - gpe_index + - gpe_block->block_base_number)); + gpe_number)); continue; } + if (event_status & ACPI_EVENT_FLAG_STATUS_SET) { + ACPI_INFO(("GPE 0x%02X active on init", + gpe_number)); + (void)acpi_ev_gpe_dispatch(gpe_block->node, + gpe_event_info, + gpe_number); + } + gpe_enabled_count++; } } -- cgit From 1312b7e0caca44e7ff312bc2eaa888943384e3e1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 10 Aug 2017 00:31:58 +0200 Subject: ACPICA: Make it possible to enable runtime GPEs earlier Runtime GPEs have corresponding _Lxx/_Exx methods and are enabled automatically during the initialization of the ACPI subsystem through acpi_update_all_gpes() with the assumption that acpi_setup_gpe_for_wake() will be called in advance for all of the GPEs pointed to by _PRW objects in the namespace that may be affected by acpi_update_all_gpes(). That is, acpi_ev_initialize_gpe_block() can only be called for a GPE block after acpi_setup_gpe_for_wake() has been called for all of the _PRW (wakeup) GPEs in it. The platform firmware on some systems, however, expects GPEs to be enabled before the enumeration of devices which is when acpi_setup_gpe_for_wake() is called and that goes against the above assumption. For this reason, introduce a new flag to be set by acpi_ev_initialize_gpe_block() when automatically enabling a GPE to indicate to acpi_setup_gpe_for_wake() that it needs to drop the reference to the GPE coming from acpi_ev_initialize_gpe_block() and modify acpi_setup_gpe_for_wake() accordingly. These changes allow acpi_setup_gpe_for_wake() and acpi_ev_initialize_gpe_block() to be invoked in any order. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/acpica/evgpeblk.c | 2 ++ drivers/acpi/acpica/evxfgpe.c | 8 ++++++++ include/acpi/actypes.h | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index c27386cca493..3a3cb8624f41 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -496,6 +496,8 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, continue; } + gpe_event_info->flags |= ACPI_GPE_AUTO_ENABLED; + if (event_status & ACPI_EVENT_FLAG_STATUS_SET) { ACPI_INFO(("GPE 0x%02X active on init", gpe_number)); diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 57718a3e029a..67c7c4ce276c 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -435,6 +435,14 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, */ gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY | ACPI_GPE_LEVEL_TRIGGERED); + } else if (gpe_event_info->flags & ACPI_GPE_AUTO_ENABLED) { + /* + * A reference to this GPE has been added during the GPE block + * initialization, so drop it now to prevent the GPE from being + * permanently enabled and clear its ACPI_GPE_AUTO_ENABLED flag. + */ + (void)acpi_ev_remove_gpe_reference(gpe_event_info); + gpe_event_info->flags &= ~ACPI_GPE_AUTO_ENABLED; } /* diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 2fcbaec8b368..71eddf645566 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -775,7 +775,7 @@ typedef u32 acpi_event_status; * | | | | +-- Type of dispatch:to method, handler, notify, or none * | | | +----- Interrupt type: edge or level triggered * | | +------- Is a Wake GPE - * | +--------- Is GPE masked by the software GPE masking mechanism + * | +--------- Has been enabled automatically at init time * +------------ */ #define ACPI_GPE_DISPATCH_NONE (u8) 0x00 @@ -791,6 +791,7 @@ typedef u32 acpi_event_status; #define ACPI_GPE_XRUPT_TYPE_MASK (u8) 0x08 #define ACPI_GPE_CAN_WAKE (u8) 0x10 +#define ACPI_GPE_AUTO_ENABLED (u8) 0x20 /* * Flags for GPE and Lock interfaces -- cgit From eb7f43c4adb4a789f99f53916182c3401b4e33c7 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 10 Aug 2017 00:34:23 +0200 Subject: ACPI / scan: Enable GPEs before scanning the namespace On some systems the platform firmware expects GPEs to be enabled before the enumeration of devices and if that expectation is not met, the systems in question may not boot in some situations. For this reason, change the initialization ordering of the ACPI subsystem to make it enable GPEs before scanning the namespace for the first time in order to enumerate devices. Reported-by: Mika Westerberg Suggested-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki Acked-by: Lv Zheng Tested-by: Mika Westerberg --- drivers/acpi/scan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 70fd5502c284..b7bdf9d0f5c0 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2058,6 +2058,9 @@ int __init acpi_scan_init(void) acpi_get_spcr_uart_addr(); } + acpi_gpe_apply_masked_gpes(); + acpi_update_all_gpes(); + mutex_lock(&acpi_scan_lock); /* * Enumerate devices in the ACPI namespace. @@ -2082,9 +2085,6 @@ int __init acpi_scan_init(void) } } - acpi_gpe_apply_masked_gpes(); - acpi_update_all_gpes(); - acpi_scan_initialized = true; out: -- cgit From 7db8d1d904e4b64d0d8e2bce75b59f59d445e1e2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 11 Aug 2017 01:31:54 +0200 Subject: ACPI: Add debug statements to acpi_global_event_handler() It sometimes is useful to examine the timing of ACPI events during certain operations only, like during system suspend/resume, so add pr_debug() statements for that to acpi_global_event_handler(). Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sysfs.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index e414fabf7315..32d7e43b64c4 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -2,6 +2,8 @@ * sysfs.c - ACPI sysfs interface to userspace. */ +#define pr_fmt(fmt) "ACPI: " fmt + #include #include #include @@ -552,11 +554,15 @@ static void fixed_event_count(u32 event_number) static void acpi_global_event_handler(u32 event_type, acpi_handle device, u32 event_number, void *context) { - if (event_type == ACPI_EVENT_TYPE_GPE) + if (event_type == ACPI_EVENT_TYPE_GPE) { gpe_count(event_number); - - if (event_type == ACPI_EVENT_TYPE_FIXED) + pr_debug("GPE event 0x%02x\n", event_number); + } else if (event_type == ACPI_EVENT_TYPE_FIXED) { fixed_event_count(event_number); + pr_debug("Fixed event 0x%02x\n", event_number); + } else { + pr_debug("Other event 0x%02x\n", event_number); + } } static int get_status(u32 index, acpi_event_status *status, -- cgit From 020a63756707d3074fd00507c3bfd461e1cdf3eb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 11 Aug 2017 01:32:40 +0200 Subject: ACPI / PM: Add debug statements to acpi_pm_notify_handler() Add statements to trace invocations of the ACPI PM notify handler and the work functions called by it. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 112fd6c55c2c..fbcc73f7a099 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -401,6 +401,8 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) if (val != ACPI_NOTIFY_DEVICE_WAKE) return; + acpi_handle_debug(handle, "Wake notify\n"); + adev = acpi_bus_get_acpi_device(handle); if (!adev) return; @@ -409,8 +411,12 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) if (adev->wakeup.flags.notifier_present) { pm_wakeup_ws_event(adev->wakeup.ws, 0, acpi_s2idle_wakeup()); - if (adev->wakeup.context.func) + if (adev->wakeup.context.func) { + acpi_handle_debug(handle, "Running %pF for %s\n", + adev->wakeup.context.func, + dev_name(adev->wakeup.context.dev)); adev->wakeup.context.func(&adev->wakeup.context); + } } mutex_unlock(&acpi_pm_notifier_lock); -- cgit From 69b957c26b32c3407d1b8cc0d2390b271728db8a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 17 Aug 2017 10:21:12 +0800 Subject: ACPI: EC: Fix possible issues related to EC initialization order Use the observation that the EC command/data register addresses are sufficient to determine if two EC devices are equivelent to modify acpi_is_boot_ec(). Then, for the removed comparison factors, EC ID and EC GPE, they need to be synchronized for the boot_ec: 1. Before registering the BIOS-provided EC event handlers in acpi_ec_register_query_methods(), the namespace node holding _Qxx methods should be located. The real namespace PNP0C09 device location then is apparently more trustworthy than the ECDT EC ID. 2. Because of the ASUS quirks, the ECDT EC GPE is more trustworthy than the namespace PNP0C09 device's _GPE setting. Use the above observations to synchronize the boot_ec settings in acpi_ec_add(). Finally, change the order of acpi_ec_ecdt_start() and acpi_ec_add(), called from acpi_bus_register_driver(), so as to follow the fast path of determining the location of _Qxx. Signed-off-by: Lv Zheng [ rjw : Changelog & comments ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index ae3d6d152633..7ea7aa9701e3 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1586,9 +1586,7 @@ static bool acpi_is_boot_ec(struct acpi_ec *ec) { if (!boot_ec) return false; - if (ec->handle == boot_ec->handle && - ec->gpe == boot_ec->gpe && - ec->command_addr == boot_ec->command_addr && + if (ec->command_addr == boot_ec->command_addr && ec->data_addr == boot_ec->data_addr) return true; return false; @@ -1613,6 +1611,13 @@ static int acpi_ec_add(struct acpi_device *device) if (acpi_is_boot_ec(ec)) { boot_ec_is_ecdt = false; + /* + * Trust PNP0C09 namespace location rather than ECDT ID. + * + * But trust ECDT GPE rather than _GPE because of ASUS quirks, + * so do not change boot_ec->gpe to ec->gpe. + */ + boot_ec->handle = ec->handle; acpi_handle_debug(ec->handle, "duplicated.\n"); acpi_ec_free(ec); ec = boot_ec; @@ -1747,18 +1752,20 @@ static int __init acpi_ec_ecdt_start(void) if (!boot_ec) return -ENODEV; - /* - * The DSDT EC should have already been started in - * acpi_ec_add(). - */ + /* In case acpi_ec_ecdt_start() is called after acpi_ec_add() */ if (!boot_ec_is_ecdt) return -ENODEV; /* * At this point, the namespace and the GPE is initialized, so * start to find the namespace objects and handle the events. + * + * Note: ec->handle can be valid if this function is called after + * acpi_ec_add(), hence the fast path. */ - if (!acpi_ec_ecdt_get_handle(&handle)) + if (boot_ec->handle != ACPI_ROOT_OBJECT) + handle = boot_ec->handle; + else if (!acpi_ec_ecdt_get_handle(&handle)) return -ENODEV; return acpi_config_boot_ec(boot_ec, handle, true, true); } @@ -2011,8 +2018,8 @@ int __init acpi_ec_init(void) return result; /* Drivers must be started after acpi_ec_query_init() */ - ecdt_fail = acpi_ec_ecdt_start(); dsdt_fail = acpi_bus_register_driver(&acpi_ec_driver); + ecdt_fail = acpi_ec_ecdt_start(); return ecdt_fail && dsdt_fail ? -ENODEV : 0; } -- cgit From 56f77eeb6bcae29871d33b8328c6834340ee8a41 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 11 Aug 2017 14:36:28 +0800 Subject: ACPI / EC: Clean up EC GPE mask flag EC_FLAGS_COMMAND_STORM is actually used to mask GPE during IRQ processing. This patch cleans it up using more readable flag/function names. Signed-off-by: Lv Zheng Tested-by: Tomislav Ivek Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 7ea7aa9701e3..fdfae6f3c0b1 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -112,8 +112,7 @@ enum { EC_FLAGS_EVT_HANDLER_INSTALLED, /* _Qxx handlers installed */ EC_FLAGS_STARTED, /* Driver is started */ EC_FLAGS_STOPPED, /* Driver is stopped */ - EC_FLAGS_COMMAND_STORM, /* GPE storms occurred to the - * current command processing */ + EC_FLAGS_GPE_MASKED, /* GPE masked */ }; #define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */ @@ -425,19 +424,19 @@ static void acpi_ec_complete_request(struct acpi_ec *ec) wake_up(&ec->wait); } -static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag) +static void acpi_ec_mask_gpe(struct acpi_ec *ec) { - if (!test_bit(flag, &ec->flags)) { + if (!test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) { acpi_ec_disable_gpe(ec, false); ec_dbg_drv("Polling enabled"); - set_bit(flag, &ec->flags); + set_bit(EC_FLAGS_GPE_MASKED, &ec->flags); } } -static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag) +static void acpi_ec_unmask_gpe(struct acpi_ec *ec) { - if (test_bit(flag, &ec->flags)) { - clear_bit(flag, &ec->flags); + if (test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) { + clear_bit(EC_FLAGS_GPE_MASKED, &ec->flags); acpi_ec_enable_gpe(ec, false); ec_dbg_drv("Polling disabled"); } @@ -464,7 +463,7 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec) static void acpi_ec_submit_query(struct acpi_ec *ec) { - acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM); + acpi_ec_mask_gpe(ec); if (!acpi_ec_event_enabled(ec)) return; if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { @@ -480,7 +479,7 @@ static void acpi_ec_complete_query(struct acpi_ec *ec) if (test_and_clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) ec_dbg_evt("Command(%s) unblocked", acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); - acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM); + acpi_ec_unmask_gpe(ec); } static inline void __acpi_ec_enable_event(struct acpi_ec *ec) @@ -700,7 +699,7 @@ err: ++t->irq_count; /* Allow triggering on 0 threshold */ if (t->irq_count == ec_storm_threshold) - acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM); + acpi_ec_mask_gpe(ec); } } out: @@ -798,7 +797,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, spin_lock_irqsave(&ec->lock, tmp); if (t->irq_count == ec_storm_threshold) - acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM); + acpi_ec_unmask_gpe(ec); ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command)); ec->curr = NULL; /* Disable GPE for command processing (IBF=0/OBF=1) */ -- cgit From 0ed780e316f48e38b9dc33d783440da7a22c044d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 15 Aug 2017 10:46:30 +0100 Subject: ACPI / processor: make function acpi_processor_check_duplicates() static The function acpi_processor_check_duplicates() is local to the source and does not need to be in global scope, so make it static. Cleans up sparse warnings: symbol 'acpi_processor_check_duplicates' was not declared. Should it be static? Signed-off-by: Colin Ian King Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_processor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index f098e25b6b41..86c10599d9f8 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -670,7 +670,7 @@ err: } -void __init acpi_processor_check_duplicates(void) +static void __init acpi_processor_check_duplicates(void) { /* check the correctness for all processors in ACPI namespace */ acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, -- cgit From c4335fdd38227788178953c101b77180504d7ea0 Mon Sep 17 00:00:00 2001 From: gengdongjiu Date: Thu, 17 Aug 2017 20:07:18 +0800 Subject: ACPI: APEI: fix the wrong iteration of generic error status block The revision 0x300 generic error data entry is different from the old version, but currently iterating through the GHES estatus blocks does not take into account this difference. This will lead to failure to get the right data entry if GHES has revision 0x300 error data entry. Update the GHES estatus iteration macro to properly increment using acpi_hest_get_next(), and correct the iteration termination condition because the status block data length only includes error data length. Convert the CPER estatus checking and printing iteration logic to use same macro. Signed-off-by: Dongjiu Geng Tested-by: Tyler Baicar Reviewed-by: Borislav Petkov Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/apei-internal.h | 5 ----- drivers/firmware/efi/cper.c | 12 ++---------- include/acpi/ghes.h | 5 +++++ 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index 6e9f14c0a71b..cb4126051f62 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -120,11 +120,6 @@ int apei_exec_collect_resources(struct apei_exec_context *ctx, struct dentry; struct dentry *apei_get_debugfs_dir(void); -#define apei_estatus_for_each_section(estatus, section) \ - for (section = (struct acpi_hest_generic_data *)(estatus + 1); \ - (void *)section - (void *)estatus < estatus->data_length; \ - section = (void *)(section+1) + section->error_data_length) - static inline u32 cper_estatus_len(struct acpi_hest_generic_status *estatus) { if (estatus->raw_data_length) diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index 48a8f69da42a..bf3672a81e49 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -606,7 +606,6 @@ void cper_estatus_print(const char *pfx, const struct acpi_hest_generic_status *estatus) { struct acpi_hest_generic_data *gdata; - unsigned int data_len; int sec_no = 0; char newpfx[64]; __u16 severity; @@ -617,14 +616,10 @@ void cper_estatus_print(const char *pfx, "It has been corrected by h/w " "and requires no further action"); printk("%s""event severity: %s\n", pfx, cper_severity_str(severity)); - data_len = estatus->data_length; - gdata = (struct acpi_hest_generic_data *)(estatus + 1); snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); - while (data_len >= acpi_hest_get_size(gdata)) { + apei_estatus_for_each_section(estatus, gdata) { cper_estatus_print_section(newpfx, gdata, sec_no); - data_len -= acpi_hest_get_record_size(gdata); - gdata = acpi_hest_get_next(gdata); sec_no++; } } @@ -653,15 +648,12 @@ int cper_estatus_check(const struct acpi_hest_generic_status *estatus) if (rc) return rc; data_len = estatus->data_length; - gdata = (struct acpi_hest_generic_data *)(estatus + 1); - while (data_len >= acpi_hest_get_size(gdata)) { + apei_estatus_for_each_section(estatus, gdata) { gedata_len = acpi_hest_get_error_length(gdata); if (gedata_len > data_len - acpi_hest_get_size(gdata)) return -EINVAL; - data_len -= acpi_hest_get_record_size(gdata); - gdata = acpi_hest_get_next(gdata); } if (data_len) return -EINVAL; diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h index 9f26e01186ae..9061c5c743b3 100644 --- a/include/acpi/ghes.h +++ b/include/acpi/ghes.h @@ -113,6 +113,11 @@ static inline void *acpi_hest_get_next(struct acpi_hest_generic_data *gdata) return (void *)(gdata) + acpi_hest_get_record_size(gdata); } +#define apei_estatus_for_each_section(estatus, section) \ + for (section = (struct acpi_hest_generic_data *)(estatus + 1); \ + (void *)section - (void *)(estatus + 1) < estatus->data_length; \ + section = acpi_hest_get_next(section)) + int ghes_notify_sea(void); #endif /* GHES_H */ -- cgit From 7dae6326ed76431653793df0388b3a404de1217e Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 18 Aug 2017 16:19:00 -0700 Subject: ACPI / sysfs: Extend ACPI sysfs to provide access to boot error region The ACPI sysfs interface provides a way to read each ACPI table from userspace via entries in /sys/firmware/acpi/tables/ The BERT table simply provides the size and address of the error record in BIOS reserved memory and users may want access to this record. In an earlier age we might have used /dev/mem to retrieve this error record, but many systems disable /dev/mem for security reasons. Extend this driver to provide read-only access to the data via a file in a new directory /sys/firmware/acpi/tables/data/BERT Acked-by: Punit Agrawal Signed-off-by: Tony Luck v4: fix typo reported by Punit Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sysfs.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index e414fabf7315..faa1aa3ed0e1 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -306,11 +306,13 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); /* * ACPI table sysfs I/F: * /sys/firmware/acpi/tables/ + * /sys/firmware/acpi/tables/data/ * /sys/firmware/acpi/tables/dynamic/ */ static LIST_HEAD(acpi_table_attr_list); static struct kobject *tables_kobj; +static struct kobject *tables_data_kobj; static struct kobject *dynamic_tables_kobj; static struct kobject *hotplug_kobj; @@ -325,6 +327,11 @@ struct acpi_table_attr { struct list_head node; }; +struct acpi_data_attr { + struct bin_attribute attr; + u64 addr; +}; + static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t offset, size_t count) @@ -420,6 +427,70 @@ acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context) return AE_OK; } +static ssize_t acpi_data_show(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t offset, size_t count) +{ + struct acpi_data_attr *data_attr; + void __iomem *base; + ssize_t rc; + + data_attr = container_of(bin_attr, struct acpi_data_attr, attr); + + base = acpi_os_map_memory(data_attr->addr, data_attr->attr.size); + if (!base) + return -ENOMEM; + rc = memory_read_from_buffer(buf, count, &offset, base, + data_attr->attr.size); + acpi_os_unmap_memory(base, data_attr->attr.size); + + return rc; +} + +static int acpi_bert_data_init(void *th, struct acpi_data_attr *data_attr) +{ + struct acpi_table_bert *bert = th; + + if (bert->header.length < sizeof(struct acpi_table_bert) || + bert->region_length < sizeof(struct acpi_hest_generic_status)) { + kfree(data_attr); + return -EINVAL; + } + data_attr->addr = bert->address; + data_attr->attr.size = bert->region_length; + data_attr->attr.attr.name = "BERT"; + + return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr); +} + +static struct acpi_data_obj { + char *name; + int (*fn)(void *, struct acpi_data_attr *); +} acpi_data_objs[] = { + { ACPI_SIG_BERT, acpi_bert_data_init }, +}; + +#define NUM_ACPI_DATA_OBJS ARRAY_SIZE(acpi_data_objs) + +static int acpi_table_data_init(struct acpi_table_header *th) +{ + struct acpi_data_attr *data_attr; + int i; + + for (i = 0; i < NUM_ACPI_DATA_OBJS; i++) { + if (ACPI_COMPARE_NAME(th->signature, acpi_data_objs[i].name)) { + data_attr = kzalloc(sizeof(*data_attr), GFP_KERNEL); + if (!data_attr) + return -ENOMEM; + sysfs_attr_init(&data_attr->attr.attr); + data_attr->attr.read = acpi_data_show; + data_attr->attr.attr.mode = 0400; + return acpi_data_objs[i].fn(th, data_attr); + } + } + return 0; +} + static int acpi_tables_sysfs_init(void) { struct acpi_table_attr *table_attr; @@ -432,6 +503,10 @@ static int acpi_tables_sysfs_init(void) if (!tables_kobj) goto err; + tables_data_kobj = kobject_create_and_add("data", tables_kobj); + if (!tables_data_kobj) + goto err_tables_data; + dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj); if (!dynamic_tables_kobj) goto err_dynamic_tables; @@ -456,13 +531,17 @@ static int acpi_tables_sysfs_init(void) return ret; } list_add_tail(&table_attr->node, &acpi_table_attr_list); + acpi_table_data_init(table_header); } kobject_uevent(tables_kobj, KOBJ_ADD); + kobject_uevent(tables_data_kobj, KOBJ_ADD); kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); return 0; err_dynamic_tables: + kobject_put(tables_data_kobj); +err_tables_data: kobject_put(tables_kobj); err: return -ENOMEM; -- cgit From 82d2b610586763f21f8f6e1f8c163c1f14b94e1c Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Mon, 21 Aug 2017 17:13:07 +0530 Subject: ACPI: make device_attribute const Make these const as they are only passed as an argument to the function device_create_file and device_remove_file and the corresponding arguments are of type const. Done using Coccinelle Signed-off-by: Bhumika Goyal Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 2 +- drivers/acpi/sbs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 1cbb88d938e5..13e7b56e33ae 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -620,7 +620,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev, return count; } -static struct device_attribute alarm_attr = { +static const struct device_attribute alarm_attr = { .attr = {.name = "alarm", .mode = 0644}, .show = acpi_battery_alarm_show, .store = acpi_battery_alarm_store, diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index ad0b13ad4bbb..ad6d817f5788 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -476,7 +476,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev, return count; } -static struct device_attribute alarm_attr = { +static const struct device_attribute alarm_attr = { .attr = {.name = "alarm", .mode = 0644}, .show = acpi_battery_alarm_show, .store = acpi_battery_alarm_store, -- cgit From 1d5d820b8fe83b5f859d1ebb028a09ada426447e Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Mon, 28 Aug 2017 13:13:14 -0500 Subject: ACPI, APEI, EINJ: Subtract any matching Register Region from Trigger resources ACPI defines a number of instructions to use for triggering errors. However we are currently removing the address resources from the trigger resources for only the WRITE_REGISTER_VALUE instruction. This leads to a resource conflict for any other valid instruction. Check that the instruction is less than or equal to the WRITE_REGISTER_VALUE instruction. This allows all valid memory access instructions and protects against invalid instructions. Fixes: b4e008dc53a3 (ACPI, APEI, EINJ, Refine the fix of resource conflict) Signed-off-by: Yazen Ghannam Acked-by: Tony Luck Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/einj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index ec50c32ea3da..b38737c83a24 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -281,7 +281,7 @@ static struct acpi_generic_address *einj_get_trigger_parameter_region( ((char *)trigger_tab + sizeof(struct acpi_einj_trigger)); for (i = 0; i < trigger_tab->entry_count; i++) { if (entry->action == ACPI_EINJ_TRIGGER_ERROR && - entry->instruction == ACPI_EINJ_WRITE_REGISTER_VALUE && + entry->instruction <= ACPI_EINJ_WRITE_REGISTER_VALUE && entry->register_region.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY && (entry->register_region.address & param2) == (param1 & param2)) -- cgit From 5aa5911a0ed9355ebb02f83de4be9ba435a45a2c Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Wed, 23 Aug 2017 16:54:43 -0600 Subject: ACPI / blacklist: add acpi_match_platform_list() ACPI OEM ID / OEM Table ID / Revision can be used to identify a platform based on ACPI firmware info. acpi_blacklisted(), intel_pstate_platform_pwr_mgmt_exists(), and some other funcs, have been using similar check to detect a list of platforms that require special handlings. Move the platform check in acpi_blacklisted() to a new common utility function, acpi_match_platform_list(), so that other drivers do not have to implement their own version. There is no change in functionality. Signed-off-by: Toshi Kani Reviewed-by: Borislav Petkov Signed-off-by: Rafael J. Wysocki --- drivers/acpi/blacklist.c | 83 ++++++++---------------------------------------- drivers/acpi/utils.c | 36 +++++++++++++++++++++ include/linux/acpi.h | 19 +++++++++++ 3 files changed, 69 insertions(+), 69 deletions(-) diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index bb542acc0574..037fd537bbf6 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -30,30 +30,13 @@ #include "internal.h" -enum acpi_blacklist_predicates { - all_versions, - less_than_or_equal, - equal, - greater_than_or_equal, -}; - -struct acpi_blacklist_item { - char oem_id[7]; - char oem_table_id[9]; - u32 oem_revision; - char *table; - enum acpi_blacklist_predicates oem_revision_predicate; - char *reason; - u32 is_critical_error; -}; - static struct dmi_system_id acpi_rev_dmi_table[] __initdata; /* * POLICY: If *anything* doesn't work, put it on the blacklist. * If they are critical errors, mark it critical, and abort driver load. */ -static struct acpi_blacklist_item acpi_blacklist[] __initdata = { +static struct acpi_platform_list acpi_blacklist[] __initdata = { /* Compaq Presario 1700 */ {"PTLTD ", " DSDT ", 0x06040000, ACPI_SIG_DSDT, less_than_or_equal, "Multiple problems", 1}, @@ -67,65 +50,27 @@ static struct acpi_blacklist_item acpi_blacklist[] __initdata = { {"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal, "Incorrect _ADR", 1}, - {""} + { } }; int __init acpi_blacklisted(void) { - int i = 0; + int i; int blacklisted = 0; - struct acpi_table_header table_header; - - while (acpi_blacklist[i].oem_id[0] != '\0') { - if (acpi_get_table_header(acpi_blacklist[i].table, 0, &table_header)) { - i++; - continue; - } - - if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) { - i++; - continue; - } - - if (strncmp - (acpi_blacklist[i].oem_table_id, table_header.oem_table_id, - 8)) { - i++; - continue; - } - - if ((acpi_blacklist[i].oem_revision_predicate == all_versions) - || (acpi_blacklist[i].oem_revision_predicate == - less_than_or_equal - && table_header.oem_revision <= - acpi_blacklist[i].oem_revision) - || (acpi_blacklist[i].oem_revision_predicate == - greater_than_or_equal - && table_header.oem_revision >= - acpi_blacklist[i].oem_revision) - || (acpi_blacklist[i].oem_revision_predicate == equal - && table_header.oem_revision == - acpi_blacklist[i].oem_revision)) { - printk(KERN_ERR PREFIX - "Vendor \"%6.6s\" System \"%8.8s\" " - "Revision 0x%x has a known ACPI BIOS problem.\n", - acpi_blacklist[i].oem_id, - acpi_blacklist[i].oem_table_id, - acpi_blacklist[i].oem_revision); + i = acpi_match_platform_list(acpi_blacklist); + if (i >= 0) { + pr_err(PREFIX "Vendor \"%6.6s\" System \"%8.8s\" Revision 0x%x has a known ACPI BIOS problem.\n", + acpi_blacklist[i].oem_id, + acpi_blacklist[i].oem_table_id, + acpi_blacklist[i].oem_revision); - printk(KERN_ERR PREFIX - "Reason: %s. This is a %s error\n", - acpi_blacklist[i].reason, - (acpi_blacklist[i]. - is_critical_error ? "non-recoverable" : - "recoverable")); + pr_err(PREFIX "Reason: %s. This is a %s error\n", + acpi_blacklist[i].reason, + (acpi_blacklist[i].data ? + "non-recoverable" : "recoverable")); - blacklisted = acpi_blacklist[i].is_critical_error; - break; - } else { - i++; - } + blacklisted = acpi_blacklist[i].data; } (void)early_acpi_osi_init(); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index b9d956c916f5..0a9e5979aaa9 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -816,3 +816,39 @@ static int __init acpi_backlight(char *str) return 1; } __setup("acpi_backlight=", acpi_backlight); + +/** + * acpi_match_platform_list - Check if the system matches with a given list + * @plat: pointer to acpi_platform_list table terminated by a NULL entry + * + * Return the matched index if the system is found in the platform list. + * Otherwise, return a negative error code. + */ +int acpi_match_platform_list(const struct acpi_platform_list *plat) +{ + struct acpi_table_header hdr; + int idx = 0; + + if (acpi_disabled) + return -ENODEV; + + for (; plat->oem_id[0]; plat++, idx++) { + if (ACPI_FAILURE(acpi_get_table_header(plat->table, 0, &hdr))) + continue; + + if (strncmp(plat->oem_id, hdr.oem_id, ACPI_OEM_ID_SIZE)) + continue; + + if (strncmp(plat->oem_table_id, hdr.oem_table_id, ACPI_OEM_TABLE_ID_SIZE)) + continue; + + if ((plat->pred == all_versions) || + (plat->pred == less_than_or_equal && hdr.oem_revision <= plat->oem_revision) || + (plat->pred == greater_than_or_equal && hdr.oem_revision >= plat->oem_revision) || + (plat->pred == equal && hdr.oem_revision == plat->oem_revision)) + return idx; + } + + return -ENODEV; +} +EXPORT_SYMBOL(acpi_match_platform_list); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 27b4b6615263..1c8a97d8b09b 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -556,6 +556,25 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, #define ACPI_OST_SC_DRIVER_LOAD_FAILURE 0x81 #define ACPI_OST_SC_INSERT_NOT_SUPPORTED 0x82 +enum acpi_predicate { + all_versions, + less_than_or_equal, + equal, + greater_than_or_equal, +}; + +/* Table must be terminted by a NULL entry */ +struct acpi_platform_list { + char oem_id[ACPI_OEM_ID_SIZE+1]; + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE+1]; + u32 oem_revision; + char *table; + enum acpi_predicate pred; + char *reason; + u32 data; +}; +int acpi_match_platform_list(const struct acpi_platform_list *plat); + extern void acpi_early_init(void); extern void acpi_subsystem_init(void); -- cgit From 5e9323219410eaecd36937a4c9c5f8de45dab412 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Wed, 23 Aug 2017 16:54:44 -0600 Subject: intel_pstate: convert to use acpi_match_platform_list() Convert to use acpi_match_platform_list() for the platform check. There is no change in functionality. Signed-off-by: Toshi Kani Acked-by: Srinivas Pandruvada Reviewed-by: Borislav Petkov Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 64 +++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 65ee4fcace1f..ad713cd6b364 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -2466,39 +2466,31 @@ enum { PPC, }; -struct hw_vendor_info { - u16 valid; - char oem_id[ACPI_OEM_ID_SIZE]; - char oem_table_id[ACPI_OEM_TABLE_ID_SIZE]; - int oem_pwr_table; -}; - /* Hardware vendor-specific info that has its own power management modes */ -static struct hw_vendor_info vendor_info[] __initdata = { - {1, "HP ", "ProLiant", PSS}, - {1, "ORACLE", "X4-2 ", PPC}, - {1, "ORACLE", "X4-2L ", PPC}, - {1, "ORACLE", "X4-2B ", PPC}, - {1, "ORACLE", "X3-2 ", PPC}, - {1, "ORACLE", "X3-2L ", PPC}, - {1, "ORACLE", "X3-2B ", PPC}, - {1, "ORACLE", "X4470M2 ", PPC}, - {1, "ORACLE", "X4270M3 ", PPC}, - {1, "ORACLE", "X4270M2 ", PPC}, - {1, "ORACLE", "X4170M2 ", PPC}, - {1, "ORACLE", "X4170 M3", PPC}, - {1, "ORACLE", "X4275 M3", PPC}, - {1, "ORACLE", "X6-2 ", PPC}, - {1, "ORACLE", "Sudbury ", PPC}, - {0, "", ""}, +static struct acpi_platform_list plat_info[] __initdata = { + {"HP ", "ProLiant", 0, ACPI_SIG_FADT, all_versions, 0, PSS}, + {"ORACLE", "X4-2 ", 0, ACPI_SIG_FADT, all_versions, 0, PPC}, + {"ORACLE", "X4-2L ", 0, ACPI_SIG_FADT, all_versions, 0, PPC}, + {"ORACLE", "X4-2B ", 0, ACPI_SIG_FADT, all_versions, 0, PPC}, + {"ORACLE", "X3-2 ", 0, ACPI_SIG_FADT, all_versions, 0, PPC}, + {"ORACLE", "X3-2L ", 0, ACPI_SIG_FADT, all_versions, 0, PPC}, + {"ORACLE", "X3-2B ", 0, ACPI_SIG_FADT, all_versions, 0, PPC}, + {"ORACLE", "X4470M2 ", 0, ACPI_SIG_FADT, all_versions, 0, PPC}, + {"ORACLE", "X4270M3 ", 0, ACPI_SIG_FADT, all_versions, 0, PPC}, + {"ORACLE", "X4270M2 ", 0, ACPI_SIG_FADT, all_versions, 0, PPC}, + {"ORACLE", "X4170M2 ", 0, ACPI_SIG_FADT, all_versions, 0, PPC}, + {"ORACLE", "X4170 M3", 0, ACPI_SIG_FADT, all_versions, 0, PPC}, + {"ORACLE", "X4275 M3", 0, ACPI_SIG_FADT, all_versions, 0, PPC}, + {"ORACLE", "X6-2 ", 0, ACPI_SIG_FADT, all_versions, 0, PPC}, + {"ORACLE", "Sudbury ", 0, ACPI_SIG_FADT, all_versions, 0, PPC}, + { } /* End */ }; static bool __init intel_pstate_platform_pwr_mgmt_exists(void) { - struct acpi_table_header hdr; - struct hw_vendor_info *v_info; const struct x86_cpu_id *id; u64 misc_pwr; + int idx; id = x86_match_cpu(intel_pstate_cpu_oob_ids); if (id) { @@ -2507,21 +2499,15 @@ static bool __init intel_pstate_platform_pwr_mgmt_exists(void) return true; } - if (acpi_disabled || - ACPI_FAILURE(acpi_get_table_header(ACPI_SIG_FADT, 0, &hdr))) + idx = acpi_match_platform_list(plat_info); + if (idx < 0) return false; - for (v_info = vendor_info; v_info->valid; v_info++) { - if (!strncmp(hdr.oem_id, v_info->oem_id, ACPI_OEM_ID_SIZE) && - !strncmp(hdr.oem_table_id, v_info->oem_table_id, - ACPI_OEM_TABLE_ID_SIZE)) - switch (v_info->oem_pwr_table) { - case PSS: - return intel_pstate_no_acpi_pss(); - case PPC: - return intel_pstate_has_acpi_ppc() && - (!force_load); - } + switch (plat_info[idx].data) { + case PSS: + return intel_pstate_no_acpi_pss(); + case PPC: + return intel_pstate_has_acpi_ppc() && !force_load; } return false; -- cgit From e931d0dab4393f7195f84f42ed6fd973c26f62f1 Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Tue, 29 Aug 2017 14:20:20 +0100 Subject: ACPI / APEI: Suppress message if HEST not present According to the ACPI specification, firmware is not required to provide the Hardware Error Source Table (HEST). When HEST is not present, the following superfluous message is printed to the kernel boot log - [ 3.460067] GHES: HEST is not enabled! Extend hest_disable variable to track whether the firmware provides this table and if it is not present skip any log output. The existing behaviour is preserved in all other cases. Suggested-by: Borislav Petkov Signed-off-by: Punit Agrawal Reviewed-by: Borislav Petkov Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/ghes.c | 7 ++++++- drivers/acpi/apei/hest.c | 13 +++++++------ include/acpi/apei.h | 8 +++++++- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index eed09fc664e8..077f9bad6f44 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -1266,9 +1266,14 @@ static int __init ghes_init(void) if (acpi_disabled) return -ENODEV; - if (hest_disable) { + switch (hest_disable) { + case HEST_NOT_FOUND: + return -ENODEV; + case HEST_DISABLED: pr_info(GHES_PFX "HEST is not enabled!\n"); return -EINVAL; + default: + break; } if (ghes_disable) { diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 456b488eb1df..9cb74115a43d 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -37,7 +37,7 @@ #define HEST_PFX "HEST: " -bool hest_disable; +int hest_disable; EXPORT_SYMBOL_GPL(hest_disable); /* HEST table parsing */ @@ -213,7 +213,7 @@ err: static int __init setup_hest_disable(char *str) { - hest_disable = 1; + hest_disable = HEST_DISABLED; return 0; } @@ -232,9 +232,10 @@ void __init acpi_hest_init(void) status = acpi_get_table(ACPI_SIG_HEST, 0, (struct acpi_table_header **)&hest_tab); - if (status == AE_NOT_FOUND) - goto err; - else if (ACPI_FAILURE(status)) { + if (status == AE_NOT_FOUND) { + hest_disable = HEST_NOT_FOUND; + return; + } else if (ACPI_FAILURE(status)) { const char *msg = acpi_format_exception(status); pr_err(HEST_PFX "Failed to get table, %s\n", msg); rc = -EINVAL; @@ -257,5 +258,5 @@ void __init acpi_hest_init(void) pr_info(HEST_PFX "Table parsing has been initialized.\n"); return; err: - hest_disable = 1; + hest_disable = HEST_DISABLED; } diff --git a/include/acpi/apei.h b/include/acpi/apei.h index 76284bb560a6..c46694abea28 100644 --- a/include/acpi/apei.h +++ b/include/acpi/apei.h @@ -16,7 +16,13 @@ #ifdef __KERNEL__ -extern bool hest_disable; +enum hest_status { + HEST_ENABLED, + HEST_DISABLED, + HEST_NOT_FOUND, +}; + +extern int hest_disable; extern int erst_disable; #ifdef CONFIG_ACPI_APEI_GHES extern bool ghes_disable; -- cgit