diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-13 11:06:21 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-13 11:06:21 -0800 |
commit | a67485d4bf97918225dfb5246e531643755a7ee1 (patch) | |
tree | a91ab5b679f22a6cb056ebb526ed6f5dfde2443c /drivers/acpi | |
parent | 7b9dc3f75fc8be046e76387a22a21f421ce55b53 (diff) | |
parent | 80f1b3dea9d4262817b5510547b1313681669f66 (diff) | |
download | linux-a67485d4bf97918225dfb5246e531643755a7ee1.tar.bz2 |
Merge tag 'acpi-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI updates from Rafael Wysocki:
"The ACPICA code in the kernel gets updated as usual (included is
upstream revision 20160930 and a few commits from the next one, with
the rest waiting for an issue discovered in linux-next to be
addressed) which brings in a couple of fixes and cleanups
On top of that initial support for APEI on ARM64 is added, two new
pieces of documentation are introduced, the properties-parsing code is
updated to follow changes in the (external) documentation it is based
on and there are a few updates of SoC drivers, some new blacklist
entries, plus some assorted fixes and cleanups
Specifics:
- ACPICA update including upstream revision 20160930 and several
commits beyond it (Bob Moore, Lv Zheng)
- Initial support for ACPI APEI on ARM64 (Tomasz Nowicki)
- New document describing the handling of _OSI and _REV in Linux (Len
Brown)
- New document describing the usage rules for _DSD properties (Rafael
Wysocki)
- Update of the ACPI properties-parsing code to reflect recent
changes in the (external) documentation it is based on (Rafael
Wysocki)
- Updates of the ACPI LPSS and ACPI APD SoC drivers for additional
hardware support (Andy Shevchenko, Nehal Shah)
- New blacklist entries for _REV and video handling (Alex Hung, Hans
de Goede, Michael Pobega)
- ACPI battery driver fix to fall back to _BIF if _BIX fails (Dave
Lambley)
- NMI notifications handling fix for APEI (Prarit Bhargava)
- Error code path fix for the ACPI CPPC library (Dan Carpenter)
- Assorted cleanups (Andy Shevchenko, Longpeng Mike)"
* tag 'acpi-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (31 commits)
ACPICA: Utilities: Add new decode function for parser values
ACPI / osl: Refactor acpi_os_get_root_pointer() to drop 'else':s
ACPI / osl: Propagate actual error code for kstrtoul()
ACPI / property: Document usage rules for _DSD properties
ACPI: Document _OSI and _REV for Linux BIOS writers
ACPI / APEI / ARM64: APEI initial support for ARM64
ACPI / APEI: Fix NMI notification handling
ACPICA: Tables: Add an error message complaining driver bugs
ACPICA: Tables: Add acpi_tb_unload_table()
ACPICA: Tables: Cleanup acpi_tb_install_and_load_table()
ACPICA: Events: Fix acpi_ev_initialize_region() return value
ACPICA: Back port of "ACPICA: Dispatcher: Tune interpreter lock around AcpiEvInitializeRegion()"
ACPICA: Namespace: Add acpi_ns_handle_to_name()
ACPI / CPPC: set an error code on probe error path
ACPI / video: Add force_native quirk for HP Pavilion dv6
ACPI / video: Add force_native quirk for Dell XPS 17 L702X
ACPI / property: Hierarchical properties support update
ACPI / LPSS: enable hard LLP for DMA
ACPI / battery: If _BIX fails, retry with _BIF
ACPI / video: Move ACPI_VIDEO_NOTIFY_* defines to acpi/video.h
..
Diffstat (limited to 'drivers/acpi')
30 files changed, 453 insertions, 306 deletions
diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index 7dd70927991e..26696b693e63 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -77,6 +77,11 @@ static const struct apd_device_desc cz_i2c_desc = { .fixed_clk_rate = 133000000, }; +static const struct apd_device_desc wt_i2c_desc = { + .setup = acpi_apd_setup, + .fixed_clk_rate = 150000000, +}; + static struct property_entry uart_properties[] = { PROPERTY_ENTRY_U32("reg-io-width", 4), PROPERTY_ENTRY_U32("reg-shift", 2), @@ -156,7 +161,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = { /* Generic apd devices */ #ifdef CONFIG_X86_AMD_PLATFORM_DEVICE { "AMD0010", APD_ADDR(cz_i2c_desc) }, - { "AMDI0010", APD_ADDR(cz_i2c_desc) }, + { "AMDI0010", APD_ADDR(wt_i2c_desc) }, { "AMD0020", APD_ADDR(cz_uart_desc) }, { "AMDI0020", APD_ADDR(cz_uart_desc) }, { "AMD0030", }, diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 373657f7e35a..8ea836c046f8 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -718,13 +718,14 @@ static int acpi_lpss_resume_early(struct device *dev) #define LPSS_GPIODEF0_DMA1_D3 BIT(2) #define LPSS_GPIODEF0_DMA2_D3 BIT(3) #define LPSS_GPIODEF0_DMA_D3_MASK GENMASK(3, 2) +#define LPSS_GPIODEF0_DMA_LLP BIT(13) static DEFINE_MUTEX(lpss_iosf_mutex); static void lpss_iosf_enter_d3_state(void) { u32 value1 = 0; - u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK; + u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK | LPSS_GPIODEF0_DMA_LLP; u32 value2 = LPSS_PMCSR_D3hot; u32 mask2 = LPSS_PMCSR_Dx_MASK; /* @@ -768,8 +769,9 @@ exit: static void lpss_iosf_exit_d3_state(void) { - u32 value1 = LPSS_GPIODEF0_DMA1_D3 | LPSS_GPIODEF0_DMA2_D3; - u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK; + u32 value1 = LPSS_GPIODEF0_DMA1_D3 | LPSS_GPIODEF0_DMA2_D3 | + LPSS_GPIODEF0_DMA_LLP; + u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK | LPSS_GPIODEF0_DMA_LLP; u32 value2 = LPSS_PMCSR_D0; u32 mask2 = LPSS_PMCSR_Dx_MASK; diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index c5557d070954..201292e67ee8 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -43,17 +43,6 @@ #define ACPI_VIDEO_BUS_NAME "Video Bus" #define ACPI_VIDEO_DEVICE_NAME "Video Device" -#define ACPI_VIDEO_NOTIFY_SWITCH 0x80 -#define ACPI_VIDEO_NOTIFY_PROBE 0x81 -#define ACPI_VIDEO_NOTIFY_CYCLE 0x82 -#define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT 0x83 -#define ACPI_VIDEO_NOTIFY_PREV_OUTPUT 0x84 - -#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS 0x85 -#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 -#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 -#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x88 -#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x89 #define MAX_NAME_LEN 20 diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 92fa47c6498c..8a0049d5cdf3 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -243,9 +243,7 @@ acpi_ev_default_region_setup(acpi_handle handle, u32 function, void *handler_context, void **region_context); -acpi_status -acpi_ev_initialize_region(union acpi_operand_object *region_obj, - u8 acpi_ns_locked); +acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj); /* * evsci - SCI (System Control Interrupt) handling/dispatch diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 750fa824d42c..edbb42e251a6 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -240,10 +240,6 @@ ACPI_INIT_GLOBAL(u32, acpi_gbl_nesting_level, 0); ACPI_GLOBAL(struct acpi_thread_state *, acpi_gbl_current_walk_list); -/* Maximum number of While() loop iterations before forced abort */ - -ACPI_GLOBAL(u16, acpi_gbl_max_loop_iterations); - /* Control method single step flag */ ACPI_GLOBAL(u8, acpi_gbl_cm_single_step); @@ -318,6 +314,7 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_cstyle_disassembly, TRUE); ACPI_INIT_GLOBAL(u8, acpi_gbl_force_aml_disassembly, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_dm_opt_verbose, TRUE); ACPI_INIT_GLOBAL(u8, acpi_gbl_dm_emit_external_opcodes, FALSE); +ACPI_INIT_GLOBAL(u8, acpi_gbl_do_disassembler_optimizations, TRUE); ACPI_GLOBAL(u8, acpi_gbl_dm_opt_disasm); ACPI_GLOBAL(u8, acpi_gbl_dm_opt_listing); diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index dff1207a6078..792660054992 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -765,7 +765,7 @@ union acpi_parse_value { union acpi_parse_value value; /* Value or args associated with the opcode */\ u8 arg_list_length; /* Number of elements in the arg list */\ ACPI_DISASM_ONLY_MEMBERS (\ - u8 disasm_flags; /* Used during AML disassembly */\ + u16 disasm_flags; /* Used during AML disassembly */\ u8 disasm_opcode; /* Subtype used for disassembly */\ char *operator_symbol;/* Used for C-style operator name strings */\ char aml_op_name[16]) /* Op name (debug only) */ @@ -868,14 +868,15 @@ struct acpi_parse_state { /* Parse object disasm_flags */ -#define ACPI_PARSEOP_IGNORE 0x01 -#define ACPI_PARSEOP_PARAMETER_LIST 0x02 -#define ACPI_PARSEOP_EMPTY_TERMLIST 0x04 -#define ACPI_PARSEOP_PREDEFINED_CHECKED 0x08 -#define ACPI_PARSEOP_CLOSING_PAREN 0x10 -#define ACPI_PARSEOP_COMPOUND_ASSIGNMENT 0x20 -#define ACPI_PARSEOP_ASSIGNMENT 0x40 -#define ACPI_PARSEOP_ELSEIF 0x80 +#define ACPI_PARSEOP_IGNORE 0x0001 +#define ACPI_PARSEOP_PARAMETER_LIST 0x0002 +#define ACPI_PARSEOP_EMPTY_TERMLIST 0x0004 +#define ACPI_PARSEOP_PREDEFINED_CHECKED 0x0008 +#define ACPI_PARSEOP_CLOSING_PAREN 0x0010 +#define ACPI_PARSEOP_COMPOUND_ASSIGNMENT 0x0020 +#define ACPI_PARSEOP_ASSIGNMENT 0x0040 +#define ACPI_PARSEOP_ELSEIF 0x0080 +#define ACPI_PARSEOP_LEGACY_ASL_ONLY 0x0100 /***************************************************************************** * diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index bb7fca1c8ba3..7affdcdfcc81 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -292,6 +292,9 @@ char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node, char *acpi_ns_name_of_current_scope(struct acpi_walk_state *walk_state); acpi_status +acpi_ns_handle_to_name(acpi_handle target_handle, struct acpi_buffer *buffer); + +acpi_status acpi_ns_handle_to_pathname(acpi_handle target_handle, struct acpi_buffer *buffer, u8 no_trailing); diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index e85953b6fa0e..7dd527f8ca1d 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -127,10 +127,11 @@ acpi_status acpi_tb_load_table(u32 table_index, struct acpi_namespace_node *parent_node); acpi_status -acpi_tb_install_and_load_table(struct acpi_table_header *table, - acpi_physical_address address, +acpi_tb_install_and_load_table(acpi_physical_address address, u8 flags, u8 override, u32 *table_index); +acpi_status acpi_tb_unload_table(u32 table_index); + void acpi_tb_terminate(void); acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index); diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 0a1b53c9ee0e..845afb180a7e 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -232,6 +232,8 @@ const char *acpi_ut_get_region_name(u8 space_id); const char *acpi_ut_get_event_name(u32 event_id); +const char *acpi_ut_get_argument_type_name(u32 arg_type); + char acpi_ut_hex_to_ascii_char(u64 integer, u32 position); acpi_status acpi_ut_ascii_to_hex_byte(char *two_ascii_chars, u8 *return_byte); diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index ceb4f7365f7f..6bd8d4bcff65 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -240,6 +240,7 @@ #define ARGP_QWORDDATA 0x11 #define ARGP_SIMPLENAME 0x12 /* name_string | local_term | arg_term */ #define ARGP_NAME_OR_REF 0x13 /* For object_type only */ +#define ARGP_MAX 0x13 /* * Resolved argument types for the AML Interpreter diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index 54d48b90de2c..5de3f10cab03 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -221,8 +221,8 @@ acpi_ds_initialize_objects(u32 table_index, */ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX, - 0, acpi_ds_init_one_object, NULL, &info, - NULL); + ACPI_NS_WALK_NO_UNLOCK, + acpi_ds_init_one_object, NULL, &info, NULL); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); } diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index 4cc9d989a114..77fd7c84ec39 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -84,7 +84,7 @@ acpi_status acpi_ds_initialize_region(acpi_handle obj_handle) /* Namespace is NOT locked */ - status = acpi_ev_initialize_region(obj_desc, FALSE); + status = acpi_ev_initialize_region(obj_desc); return (status); } diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index e36218206bb0..651f35a66cc2 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -609,18 +609,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) status = acpi_ev_initialize_region - (acpi_ns_get_attached_object(node), FALSE); - - if (ACPI_FAILURE(status)) { - /* - * If AE_NOT_EXIST is returned, it is not fatal - * because many regions get created before a handler - * is installed for said region. - */ - if (AE_NOT_EXIST == status) { - status = AE_OK; - } - } + (acpi_ns_get_attached_object(node)); break; case AML_NAME_OP: diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 75ddd160a716..a9092251ce80 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -479,7 +479,6 @@ acpi_ev_default_region_setup(acpi_handle handle, * FUNCTION: acpi_ev_initialize_region * * PARAMETERS: region_obj - Region we are initializing - * acpi_ns_locked - Is namespace locked? * * RETURN: Status * @@ -497,19 +496,28 @@ acpi_ev_default_region_setup(acpi_handle handle, * MUTEX: Interpreter should be unlocked, because we may run the _REG * method for this region. * + * NOTE: Possible incompliance: + * There is a behavior conflict in automatic _REG execution: + * 1. When the interpreter is evaluating a method, we can only + * automatically run _REG for the following case: + * operation_region (OPR1, 0x80, 0x1000010, 0x4) + * 2. When the interpreter is loading a table, we can also + * automatically run _REG for the following case: + * operation_region (OPR1, 0x80, 0x1000010, 0x4) + * Though this may not be compliant to the de-facto standard, the + * logic is kept in order not to trigger regressions. And keeping + * this logic should be taken care by the caller of this function. + * ******************************************************************************/ -acpi_status -acpi_ev_initialize_region(union acpi_operand_object *region_obj, - u8 acpi_ns_locked) +acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj) { union acpi_operand_object *handler_obj; union acpi_operand_object *obj_desc; acpi_adr_space_type space_id; struct acpi_namespace_node *node; - acpi_status status; - ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked); + ACPI_FUNCTION_TRACE(ev_initialize_region); if (!region_obj) { return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -580,39 +588,17 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, handler_obj, region_obj, obj_desc)); - status = - acpi_ev_attach_region(handler_obj, - region_obj, - acpi_ns_locked); + (void)acpi_ev_attach_region(handler_obj, + region_obj, FALSE); /* * Tell all users that this region is usable by * running the _REG method */ - if (acpi_ns_locked) { - status = - acpi_ut_release_mutex - (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } - acpi_ex_exit_interpreter(); - status = - acpi_ev_execute_reg_method(region_obj, - ACPI_REG_CONNECT); + (void)acpi_ev_execute_reg_method(region_obj, + ACPI_REG_CONNECT); acpi_ex_enter_interpreter(); - - if (acpi_ns_locked) { - status = - acpi_ut_acquire_mutex - (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } - return_ACPI_STATUS(AE_OK); } } @@ -622,12 +608,15 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, node = node->parent; } - /* If we get here, there is no handler for this region */ - + /* + * If we get here, there is no handler for this region. This is not + * fatal because many regions get created before a handler is installed + * for said region. + */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "No handler for RegionType %s(%X) (RegionObj %p)\n", acpi_ut_get_region_name(space_id), space_id, region_obj)); - return_ACPI_STATUS(AE_NOT_EXIST); + return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 718428ba0b89..c32c7829878a 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -437,10 +437,9 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, ACPI_INFO(("Dynamic OEM Table Load:")); acpi_ex_exit_interpreter(); - status = - acpi_tb_install_and_load_table(table, ACPI_PTR_TO_PHYSADDR(table), - ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, - TRUE, &table_index); + status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table), + ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, + TRUE, &table_index); acpi_ex_enter_interpreter(); if (ACPI_FAILURE(status)) { @@ -500,7 +499,6 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) acpi_status status = AE_OK; union acpi_operand_object *table_desc = ddb_handle; u32 table_index; - struct acpi_table_header *table; ACPI_FUNCTION_TRACE(ex_unload_table); @@ -537,39 +535,7 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) * strict order requirement against it. */ acpi_ex_exit_interpreter(); - - /* Ensure the table is still loaded */ - - if (!acpi_tb_is_table_loaded(table_index)) { - status = AE_NOT_EXIST; - goto lock_and_exit; - } - - /* Invoke table handler if present */ - - 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); - } - } - - /* Delete the portion of the namespace owned by this table */ - - status = acpi_tb_delete_namespace_by_owner(table_index); - if (ACPI_FAILURE(status)) { - goto lock_and_exit; - } - - (void)acpi_tb_release_owner_id(table_index); - acpi_tb_set_table_loaded_flag(table_index, FALSE); - -lock_and_exit: - - /* Re-acquire the interpreter lock */ - + status = acpi_tb_unload_table(table_index); acpi_ex_enter_interpreter(); /* diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index f03dd41e86d0..94d5d3339845 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -97,6 +97,51 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) /******************************************************************************* * + * FUNCTION: acpi_ns_handle_to_name + * + * PARAMETERS: target_handle - Handle of named object whose name is + * to be found + * buffer - Where the name is returned + * + * RETURN: Status, Buffer is filled with name if status is AE_OK + * + * DESCRIPTION: Build and return a full namespace name + * + ******************************************************************************/ + +acpi_status +acpi_ns_handle_to_name(acpi_handle target_handle, struct acpi_buffer *buffer) +{ + acpi_status status; + struct acpi_namespace_node *node; + const char *node_name; + + ACPI_FUNCTION_TRACE_PTR(ns_handle_to_name, target_handle); + + node = acpi_ns_validate_handle(target_handle); + if (!node) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + /* Validate/Allocate/Clear caller buffer */ + + status = acpi_ut_initialize_buffer(buffer, ACPI_PATH_SEGMENT_LENGTH); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Just copy the ACPI name from the Node and zero terminate it */ + + node_name = acpi_ut_get_node_name(node); + ACPI_MOVE_NAME(buffer->pointer, node_name); + ((char *)buffer->pointer)[ACPI_NAME_SIZE] = 0; + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%4.4s\n", (char *)buffer->pointer)); + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * * FUNCTION: acpi_ns_handle_to_pathname * * PARAMETERS: target_handle - Handle of named object whose name is diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 76a1bd4bb070..e525cbe7d83b 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -158,8 +158,6 @@ acpi_status acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer *buffer) { acpi_status status; - struct acpi_namespace_node *node; - const char *node_name; /* Parameter validation */ @@ -172,18 +170,6 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer *buffer) return (status); } - if (name_type == ACPI_FULL_PATHNAME || - name_type == ACPI_FULL_PATHNAME_NO_TRAILING) { - - /* Get the full pathname (From the namespace root) */ - - status = acpi_ns_handle_to_pathname(handle, buffer, - name_type == - ACPI_FULL_PATHNAME ? FALSE : - TRUE); - return (status); - } - /* * Wants the single segment ACPI name. * Validate handle and convert to a namespace Node @@ -193,27 +179,20 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer *buffer) return (status); } - node = acpi_ns_validate_handle(handle); - if (!node) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - - /* Validate/Allocate/Clear caller buffer */ - - status = acpi_ut_initialize_buffer(buffer, ACPI_PATH_SEGMENT_LENGTH); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; - } + if (name_type == ACPI_FULL_PATHNAME || + name_type == ACPI_FULL_PATHNAME_NO_TRAILING) { - /* Just copy the ACPI name from the Node and zero terminate it */ + /* Get the full pathname (From the namespace root) */ - node_name = acpi_ut_get_node_name(node); - ACPI_MOVE_NAME(buffer->pointer, node_name); - ((char *)buffer->pointer)[ACPI_NAME_SIZE] = 0; - status = AE_OK; + status = acpi_ns_handle_to_pathname(handle, buffer, + name_type == + ACPI_FULL_PATHNAME ? FALSE : + TRUE); + } else { + /* Get the single name */ -unlock_and_exit: + status = acpi_ns_handle_to_name(handle, buffer); + } (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (status); diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index d9ca8c2aa2d3..82b0b5710979 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -832,9 +832,9 @@ acpi_tb_load_table(u32 table_index, struct acpi_namespace_node *parent_node) * * FUNCTION: acpi_tb_install_and_load_table * - * PARAMETERS: table - Pointer to the table - * address - Physical address of the table + * PARAMETERS: address - Physical address of the table * flags - Allocation flags of the table + * override - Whether override should be performed * table_index - Where table index is returned * * RETURN: Status @@ -844,15 +844,13 @@ acpi_tb_load_table(u32 table_index, struct acpi_namespace_node *parent_node) ******************************************************************************/ acpi_status -acpi_tb_install_and_load_table(struct acpi_table_header *table, - acpi_physical_address address, +acpi_tb_install_and_load_table(acpi_physical_address address, u8 flags, u8 override, u32 *table_index) { acpi_status status; u32 i; - acpi_owner_id owner_id; - ACPI_FUNCTION_TRACE(acpi_load_table); + ACPI_FUNCTION_TRACE(tb_install_and_load_table); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); @@ -864,45 +862,60 @@ acpi_tb_install_and_load_table(struct acpi_table_header *table, goto unlock_and_exit; } - /* - * Note: Now table is "INSTALLED", it must be validated before - * using. - */ - status = acpi_tb_validate_table(&acpi_gbl_root_table_list.tables[i]); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; - } + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + status = acpi_tb_load_table(i, acpi_gbl_root_node); + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); +unlock_and_exit: + *table_index = i; (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - status = acpi_ns_load_table(i, acpi_gbl_root_node); + return_ACPI_STATUS(status); +} - /* Execute any module-level code that was found in the table */ +/******************************************************************************* + * + * FUNCTION: acpi_tb_unload_table + * + * PARAMETERS: table_index - Table index + * + * RETURN: Status + * + * DESCRIPTION: Unload an ACPI table + * + ******************************************************************************/ - if (!acpi_gbl_parse_table_as_term_list - && acpi_gbl_group_module_level_code) { - acpi_ns_exec_module_code_list(); - } +acpi_status acpi_tb_unload_table(u32 table_index) +{ + acpi_status status = AE_OK; + struct acpi_table_header *table; - /* - * Update GPEs for any new _Lxx/_Exx methods. Ignore errors. The host is - * responsible for discovering any new wake GPEs by running _PRW methods - * that may have been loaded by this table. - */ - status = acpi_tb_get_owner_id(i, &owner_id); - if (ACPI_SUCCESS(status)) { - acpi_ev_update_gpes(owner_id); + ACPI_FUNCTION_TRACE(tb_unload_table); + + /* Ensure the table is still loaded */ + + if (!acpi_tb_is_table_loaded(table_index)) { + return_ACPI_STATUS(AE_NOT_EXIST); } /* 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); + 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); + } } - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); -unlock_and_exit: - *table_index = i; - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + /* Delete the portion of the namespace owned by this table */ + + status = acpi_tb_delete_namespace_by_owner(table_index); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + (void)acpi_tb_release_owner_id(table_index); + acpi_tb_set_table_loaded_flag(table_index, FALSE); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 4ab6b9cd0aec..d5adb7ac4684 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -167,6 +167,7 @@ ACPI_EXPORT_SYMBOL_INIT(acpi_initialize_tables) acpi_status ACPI_INIT_FUNCTION acpi_reallocate_root_table(void) { acpi_status status; + u32 i; ACPI_FUNCTION_TRACE(acpi_reallocate_root_table); @@ -178,6 +179,21 @@ acpi_status ACPI_INIT_FUNCTION acpi_reallocate_root_table(void) return_ACPI_STATUS(AE_SUPPORT); } + /* + * Ensure OS early boot logic, which is required by some hosts. If the + * table state is reported to be wrong, developers should fix the + * issue by invoking acpi_put_table() for the reported table during the + * early stage. + */ + for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { + if (acpi_gbl_root_table_list.tables[i].pointer) { + ACPI_ERROR((AE_INFO, + "Table [%4.4s] is not invalidated during early boot stage", + acpi_gbl_root_table_list.tables[i]. + signature.ascii)); + } + } + acpi_gbl_root_table_list.flags |= ACPI_ROOT_ALLOW_RESIZE; status = acpi_tb_resize_root_table_list(); diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 5569f637f669..82019c01a0e5 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -239,7 +239,7 @@ acpi_status acpi_tb_load_namespace(void) } if (!tables_failed) { - ACPI_INFO(("%u ACPI AML tables successfully acquired and loaded\n", tables_loaded)); + ACPI_INFO(("%u ACPI AML tables successfully acquired and loaded", tables_loaded)); } else { ACPI_ERROR((AE_INFO, "%u table load failures, %u successful", @@ -250,6 +250,10 @@ acpi_status acpi_tb_load_namespace(void) status = AE_CTRL_TERMINATE; } +#ifdef ACPI_APPLICATION + ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "\n")); +#endif + unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_ACPI_STATUS(status); @@ -326,10 +330,9 @@ acpi_status acpi_load_table(struct acpi_table_header *table) /* Install the table and load it into the namespace */ ACPI_INFO(("Host-directed Dynamic ACPI Table Load:")); - status = - acpi_tb_install_and_load_table(table, ACPI_PTR_TO_PHYSADDR(table), - ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, - FALSE, &table_index); + status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table), + ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, + FALSE, &table_index); return_ACPI_STATUS(status); } @@ -405,37 +408,8 @@ acpi_status acpi_unload_parent_table(acpi_handle object) break; } - /* Ensure the table is actually loaded */ - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - if (!acpi_tb_is_table_loaded(i)) { - status = AE_NOT_EXIST; - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - break; - } - - /* Invoke table handler if present */ - - if (acpi_gbl_table_handler) { - (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_UNLOAD, - acpi_gbl_root_table_list. - tables[i].pointer, - acpi_gbl_table_handler_context); - } - - /* - * Delete all namespace objects owned by this table. Note that - * these objects can appear anywhere in the namespace by virtue - * of the AML "Scope" operator. Thus, we need to track ownership - * by an ID, not simply a position within the hierarchy. - */ - status = acpi_tb_delete_namespace_by_owner(i); - if (ACPI_FAILURE(status)) { - break; - } - - status = acpi_tb_release_owner_id(i); - acpi_tb_set_table_loaded_flag(i, FALSE); + status = acpi_tb_unload_table(i); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); break; } diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index 15728ad8356b..b3d8421cfb80 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -44,6 +44,7 @@ #include <acpi/acpi.h> #include "accommon.h" #include "acnamesp.h" +#include "amlcode.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utdecode") @@ -532,6 +533,54 @@ const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type) return ("Hardware-Specific"); } + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_argument_type_name + * + * PARAMETERS: arg_type - an ARGP_* parser argument type + * + * RETURN: Decoded ARGP_* type + * + * DESCRIPTION: Decode an ARGP_* parser type, as defined in the amlcode.h file, + * and used in the acopcode.h file. For example, ARGP_TERMARG. + * Used for debug only. + * + ******************************************************************************/ + +static const char *acpi_gbl_argument_type[20] = { + /* 00 */ "Unknown ARGP", + /* 01 */ "ByteData", + /* 02 */ "ByteList", + /* 03 */ "CharList", + /* 04 */ "DataObject", + /* 05 */ "DataObjectList", + /* 06 */ "DWordData", + /* 07 */ "FieldList", + /* 08 */ "Name", + /* 09 */ "NameString", + /* 0A */ "ObjectList", + /* 0B */ "PackageLength", + /* 0C */ "SuperName", + /* 0D */ "Target", + /* 0E */ "TermArg", + /* 0F */ "TermList", + /* 10 */ "WordData", + /* 11 */ "QWordData", + /* 12 */ "SimpleName", + /* 13 */ "NameOrRef" +}; + +const char *acpi_ut_get_argument_type_name(u32 arg_type) +{ + + if (arg_type > ARGP_MAX) { + return ("Unknown ARGP"); + } + + return (acpi_gbl_argument_type[arg_type]); +} + #endif /******************************************************************************* diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 0d099a24f776..e53bef6cf53c 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -852,6 +852,8 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) if (ghes_read_estatus(ghes, 1)) { ghes_clear_estatus(ghes); continue; + } else { + ret = NMI_HANDLED; } sev = ghes_severity(ghes->estatus->error_severity); @@ -863,12 +865,11 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) __process_error(ghes); ghes_clear_estatus(ghes); - - ret = NMI_HANDLED; } #ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG - irq_work_queue(&ghes_proc_irq_work); + if (ret == NMI_HANDLED) + irq_work_queue(&ghes_proc_irq_work); #endif atomic_dec(&ghes_in_nmi); return ret; diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 20b3fcf4007c..8f2a98e23bba 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -123,7 +123,13 @@ EXPORT_SYMBOL_GPL(apei_hest_parse); */ static int __init hest_parse_cmc(struct acpi_hest_header *hest_hdr, void *data) { - return arch_apei_enable_cmcff(hest_hdr, data); + if (hest_hdr->type != ACPI_HEST_TYPE_IA32_CORRECTED_CHECK) + return 0; + + if (!acpi_disable_cmcff) + return !arch_apei_enable_cmcff(hest_hdr, data); + + return 0; } struct ghes_arr { @@ -232,8 +238,9 @@ void __init acpi_hest_init(void) goto err; } - if (!acpi_disable_cmcff) - apei_hest_parse(hest_parse_cmc, NULL); + rc = apei_hest_parse(hest_parse_cmc, NULL); + if (rc) + goto err; if (!ghes_disable) { rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count); diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 93ecae55fe6a..05fe9ebfb9b5 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -430,39 +430,24 @@ static int acpi_battery_get_status(struct acpi_battery *battery) return 0; } -static int acpi_battery_get_info(struct acpi_battery *battery) + +static int extract_battery_info(const int use_bix, + struct acpi_battery *battery, + const struct acpi_buffer *buffer) { int result = -EFAULT; - acpi_status status = 0; - char *name = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags) ? - "_BIX" : "_BIF"; - - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - if (!acpi_battery_present(battery)) - return 0; - mutex_lock(&battery->lock); - status = acpi_evaluate_object(battery->device->handle, name, - NULL, &buffer); - mutex_unlock(&battery->lock); - - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s", name)); - return -ENODEV; - } - - if (battery_bix_broken_package) - result = extract_package(battery, buffer.pointer, + if (use_bix && battery_bix_broken_package) + result = extract_package(battery, buffer->pointer, extended_info_offsets + 1, ARRAY_SIZE(extended_info_offsets) - 1); - else if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags)) - result = extract_package(battery, buffer.pointer, + else if (use_bix) + result = extract_package(battery, buffer->pointer, extended_info_offsets, ARRAY_SIZE(extended_info_offsets)); else - result = extract_package(battery, buffer.pointer, + result = extract_package(battery, buffer->pointer, info_offsets, ARRAY_SIZE(info_offsets)); - kfree(buffer.pointer); if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)) battery->full_charge_capacity = battery->design_capacity; if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) && @@ -483,6 +468,45 @@ static int acpi_battery_get_info(struct acpi_battery *battery) return result; } +static int acpi_battery_get_info(struct acpi_battery *battery) +{ + const int xinfo = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); + int use_bix; + int result = -ENODEV; + + if (!acpi_battery_present(battery)) + return 0; + + + for (use_bix = xinfo ? 1 : 0; use_bix >= 0; use_bix--) { + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_status status = AE_ERROR; + + mutex_lock(&battery->lock); + status = acpi_evaluate_object(battery->device->handle, + use_bix ? "_BIX":"_BIF", + NULL, &buffer); + mutex_unlock(&battery->lock); + + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s", + use_bix ? "_BIX":"_BIF")); + } else { + result = extract_battery_info(use_bix, + battery, + &buffer); + + kfree(buffer.pointer); + break; + } + } + + if (!result && !use_bix && xinfo) + pr_warn(FW_BUG "The _BIX method is broken, using _BIF.\n"); + + return result; +} + static int acpi_battery_get_state(struct acpi_battery *battery) { int result = 0; diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index bdc67bad61a7..4421f7c9981c 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -160,6 +160,34 @@ static struct dmi_system_id acpi_rev_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343"), }, }, + { + .callback = dmi_enable_rev_override, + .ident = "DELL Precision 5520", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Precision 5520"), + }, + }, + { + .callback = dmi_enable_rev_override, + .ident = "DELL Precision 3520", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3520"), + }, + }, + /* + * Resolves a quirk with the Dell Latitude 3350 that + * causes the ethernet adapter to not function. + */ + { + .callback = dmi_enable_rev_override, + .ident = "DELL Latitude 3350", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude 3350"), + }, + }, #endif {} }; diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index d0d0504b7c89..e0ea8f56d2bf 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -784,8 +784,10 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) /* Add per logical CPU nodes for reading its feedback counters. */ cpu_dev = get_cpu_device(pr->id); - if (!cpu_dev) + if (!cpu_dev) { + ret = -EINVAL; goto out_free; + } ret = kobject_init_and_add(&cpc_ptr->kobj, &cppc_ktype, &cpu_dev->kobj, "acpi_cppc"); diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c index 7b2c48fde4e2..24418932612e 100644 --- a/drivers/acpi/device_sysfs.c +++ b/drivers/acpi/device_sysfs.c @@ -52,7 +52,7 @@ struct acpi_data_node_attr { static ssize_t data_node_show_path(struct acpi_data_node *dn, char *buf) { - return acpi_object_path(dn->handle, buf); + return dn->handle ? acpi_object_path(dn->handle, buf) : 0; } DATA_NODE_ATTR(path); @@ -105,10 +105,10 @@ static void acpi_expose_nondev_subnodes(struct kobject *kobj, init_completion(&dn->kobj_done); ret = kobject_init_and_add(&dn->kobj, &acpi_data_node_ktype, kobj, "%s", dn->name); - if (ret) - acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret); - else + if (!ret) acpi_expose_nondev_subnodes(&dn->kobj, &dn->data); + else if (dn->handle) + acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret); } } diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 416953a42510..9a4c6abee63e 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -181,15 +181,15 @@ void acpi_os_vprintf(const char *fmt, va_list args) static unsigned long acpi_rsdp; static int __init setup_acpi_rsdp(char *arg) { - if (kstrtoul(arg, 16, &acpi_rsdp)) - return -EINVAL; - return 0; + return kstrtoul(arg, 16, &acpi_rsdp); } early_param("acpi_rsdp", setup_acpi_rsdp); #endif acpi_physical_address __init acpi_os_get_root_pointer(void) { + acpi_physical_address pa = 0; + #ifdef CONFIG_KEXEC if (acpi_rsdp) return acpi_rsdp; @@ -198,21 +198,14 @@ acpi_physical_address __init acpi_os_get_root_pointer(void) if (efi_enabled(EFI_CONFIG_TABLES)) { if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) return efi.acpi20; - else if (efi.acpi != EFI_INVALID_TABLE_ADDR) + if (efi.acpi != EFI_INVALID_TABLE_ADDR) return efi.acpi; - else { - printk(KERN_ERR PREFIX - "System description tables not found\n"); - return 0; - } + pr_err(PREFIX "System description tables not found\n"); } else if (IS_ENABLED(CONFIG_ACPI_LEGACY_TABLES_LOOKUP)) { - acpi_physical_address pa = 0; - acpi_find_root_pointer(&pa); - return pa; } - return 0; + return pa; } /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 03f5ec11ab31..3afddcd834ef 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -41,14 +41,13 @@ static bool acpi_enumerate_nondev_subnodes(acpi_handle scope, static bool acpi_extract_properties(const union acpi_object *desc, struct acpi_device_data *data); -static bool acpi_nondev_subnode_ok(acpi_handle scope, - const union acpi_object *link, - struct list_head *list) +static bool acpi_nondev_subnode_extract(const union acpi_object *desc, + acpi_handle handle, + const union acpi_object *link, + struct list_head *list) { - struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; struct acpi_data_node *dn; - acpi_handle handle; - acpi_status status; + bool result; dn = kzalloc(sizeof(*dn), GFP_KERNEL); if (!dn) @@ -58,43 +57,75 @@ static bool acpi_nondev_subnode_ok(acpi_handle scope, dn->fwnode.type = FWNODE_ACPI_DATA; INIT_LIST_HEAD(&dn->data.subnodes); - status = acpi_get_handle(scope, link->package.elements[1].string.pointer, - &handle); - if (ACPI_FAILURE(status)) - goto fail; + result = acpi_extract_properties(desc, &dn->data); - status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf, - ACPI_TYPE_PACKAGE); - if (ACPI_FAILURE(status)) - goto fail; + if (handle) { + acpi_handle scope; + acpi_status status; - if (acpi_extract_properties(buf.pointer, &dn->data)) - dn->handle = handle; + /* + * The scope for the subnode object lookup is the one of the + * namespace node (device) containing the object that has + * returned the package. That is, it's the scope of that + * object's parent. + */ + status = acpi_get_parent(handle, &scope); + if (ACPI_SUCCESS(status) + && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data)) + result = true; + } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data)) { + result = true; + } - /* - * The scope for the subnode object lookup is the one of the namespace - * node (device) containing the object that has returned the package. - * That is, it's the scope of that object's parent. - */ - status = acpi_get_parent(handle, &scope); - if (ACPI_SUCCESS(status) - && acpi_enumerate_nondev_subnodes(scope, buf.pointer, &dn->data)) + if (result) { dn->handle = handle; - - if (dn->handle) { - dn->data.pointer = buf.pointer; + dn->data.pointer = desc; list_add_tail(&dn->sibling, list); return true; } + kfree(dn); acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n"); + return false; +} + +static bool acpi_nondev_subnode_data_ok(acpi_handle handle, + const union acpi_object *link, + struct list_head *list) +{ + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; + acpi_status status; + + status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf, + ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(status)) + return false; + + if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list)) + return true; - fail: ACPI_FREE(buf.pointer); - kfree(dn); return false; } +static bool acpi_nondev_subnode_ok(acpi_handle scope, + const union acpi_object *link, + struct list_head *list) +{ + acpi_handle handle; + acpi_status status; + + if (!scope) + return false; + + status = acpi_get_handle(scope, link->package.elements[1].string.pointer, + &handle); + if (ACPI_FAILURE(status)) + return false; + + return acpi_nondev_subnode_data_ok(handle, link, list); +} + static int acpi_add_nondev_subnodes(acpi_handle scope, const union acpi_object *links, struct list_head *list) @@ -103,15 +134,37 @@ static int acpi_add_nondev_subnodes(acpi_handle scope, int i; for (i = 0; i < links->package.count; i++) { - const union acpi_object *link; + const union acpi_object *link, *desc; + acpi_handle handle; + bool result; link = &links->package.elements[i]; - /* Only two elements allowed, both must be strings. */ - if (link->package.count == 2 - && link->package.elements[0].type == ACPI_TYPE_STRING - && link->package.elements[1].type == ACPI_TYPE_STRING - && acpi_nondev_subnode_ok(scope, link, list)) - ret = true; + /* Only two elements allowed. */ + if (link->package.count != 2) + continue; + + /* The first one must be a string. */ + if (link->package.elements[0].type != ACPI_TYPE_STRING) + continue; + + /* The second one may be a string, a reference or a package. */ + switch (link->package.elements[1].type) { + case ACPI_TYPE_STRING: + result = acpi_nondev_subnode_ok(scope, link, list); + break; + case ACPI_TYPE_LOCAL_REFERENCE: + handle = link->package.elements[1].reference.handle; + result = acpi_nondev_subnode_data_ok(handle, link, list); + break; + case ACPI_TYPE_PACKAGE: + desc = &link->package.elements[1]; + result = acpi_nondev_subnode_extract(desc, NULL, link, list); + break; + default: + result = false; + break; + } + ret = ret || result; } return ret; diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index a6b36fc53aec..02ded25c82e4 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -296,6 +296,26 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), }, }, + { + /* https://bugzilla.redhat.com/show_bug.cgi?id=1123661 */ + .callback = video_detect_force_native, + .ident = "Dell XPS 17 L702X", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Dell System XPS L702X"), + }, + }, + { + /* https://bugzilla.redhat.com/show_bug.cgi?id=1204476 */ + /* https://bugs.launchpad.net/ubuntu/+source/linux-lts-trusty/+bug/1416940 */ + .callback = video_detect_force_native, + .ident = "HP Pavilion dv6", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv6 Notebook PC"), + }, + }, + { }, }; |