diff options
Diffstat (limited to 'drivers/acpi')
81 files changed, 2523 insertions, 705 deletions
diff --git a/drivers/acpi/acpi_configfs.c b/drivers/acpi/acpi_configfs.c index 146a77fb762d..853bc7fc673f 100644 --- a/drivers/acpi/acpi_configfs.c +++ b/drivers/acpi/acpi_configfs.c @@ -15,11 +15,15 @@ #include <linux/configfs.h> #include <linux/acpi.h> +#include "acpica/accommon.h" +#include "acpica/actables.h" + static struct config_group *acpi_table_group; struct acpi_table { struct config_item cfg; struct acpi_table_header *header; + u32 index; }; static ssize_t acpi_table_aml_write(struct config_item *cfg, @@ -52,7 +56,11 @@ static ssize_t acpi_table_aml_write(struct config_item *cfg, if (!table->header) return -ENOMEM; - ret = acpi_load_table(table->header); + ACPI_INFO(("Host-directed Dynamic ACPI Table Load:")); + ret = acpi_tb_install_and_load_table( + ACPI_PTR_TO_PHYSADDR(table->header), + ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, FALSE, + &table->index); if (ret) { kfree(table->header); table->header = NULL; @@ -215,8 +223,18 @@ static struct config_item *acpi_table_make_item(struct config_group *group, return &table->cfg; } +static void acpi_table_drop_item(struct config_group *group, + struct config_item *cfg) +{ + struct acpi_table *table = container_of(cfg, struct acpi_table, cfg); + + ACPI_INFO(("Host-directed Dynamic ACPI Table Unload")); + acpi_tb_unload_table(table->index); +} + struct configfs_group_operations acpi_table_group_ops = { .make_item = acpi_table_make_item, + .drop_item = acpi_table_drop_item, }; static struct config_item_type acpi_tables_type = { diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c index dee86925a9a1..3ec05aa1a903 100644 --- a/drivers/acpi/acpi_dbg.c +++ b/drivers/acpi/acpi_dbg.c @@ -10,7 +10,7 @@ */ /* #define DEBUG */ -#define pr_fmt(fmt) "ACPI : AML: " fmt +#define pr_fmt(fmt) "ACPI: AML: " fmt #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index 502ea4dc2080..560fdae8cc59 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -141,9 +141,9 @@ static int extlog_print(struct notifier_block *nb, unsigned long val, int cpu = mce->extcpu; struct acpi_hest_generic_status *estatus, *tmp; struct acpi_hest_generic_data *gdata; - const uuid_le *fru_id = &NULL_UUID_LE; + const guid_t *fru_id = &guid_null; char *fru_text = ""; - uuid_le *sec_type; + guid_t *sec_type; static u32 err_seq; estatus = extlog_elog_entry_check(cpu, bank); @@ -165,11 +165,11 @@ static int extlog_print(struct notifier_block *nb, unsigned long val, err_seq++; gdata = (struct acpi_hest_generic_data *)(tmp + 1); if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID) - fru_id = (uuid_le *)gdata->fru_id; + fru_id = (guid_t *)gdata->fru_id; if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT) fru_text = gdata->fru_text; - sec_type = (uuid_le *)gdata->section_type; - if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) { + sec_type = (guid_t *)gdata->section_type; + if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) { struct cper_sec_mem_err *mem = (void *)(gdata + 1); if (gdata->error_data_length >= sizeof(*mem)) trace_extlog_mem_event(mem, err_seq, fru_id, fru_text, @@ -182,17 +182,17 @@ out: static bool __init extlog_get_l1addr(void) { - u8 uuid[16]; + guid_t guid; acpi_handle handle; union acpi_object *obj; - acpi_str_to_uuid(extlog_dsm_uuid, uuid); - + if (guid_parse(extlog_dsm_uuid, &guid)) + return false; if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) return false; - if (!acpi_check_dsm(handle, uuid, EXTLOG_DSM_REV, 1 << EXTLOG_FN_ADDR)) + if (!acpi_check_dsm(handle, &guid, EXTLOG_DSM_REV, 1 << EXTLOG_FN_ADDR)) return false; - obj = acpi_evaluate_dsm_typed(handle, uuid, EXTLOG_DSM_REV, + obj = acpi_evaluate_dsm_typed(handle, &guid, EXTLOG_DSM_REV, EXTLOG_FN_ADDR, NULL, ACPI_TYPE_INTEGER); if (!obj) { return false; diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 10347e3d73ad..e51a1e98e62f 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -576,7 +576,7 @@ static struct attribute *lpss_attrs[] = { NULL, }; -static struct attribute_group lpss_attr_group = { +static const struct attribute_group lpss_attr_group = { .attrs = lpss_attrs, .name = "lpss_ltr", }; diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index dea65306b687..b125bdd3d58b 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -172,6 +172,7 @@ acpi-y += \ utosi.o \ utownerid.o \ utpredef.o \ + utresdecode.o \ utresrc.o \ utstate.o \ utstring.o \ diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index b65f2731e9e2..bb6a84b0b4b3 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -158,8 +158,8 @@ acpi_dm_finish_namespace_load(union acpi_parse_object *parse_tree_root, acpi_owner_id owner_id); void -acpi_dm_convert_resource_indexes(union acpi_parse_object *parse_tree_root, - struct acpi_namespace_node *namespace_root); +acpi_dm_convert_parse_objects(union acpi_parse_object *parse_tree_root, + struct acpi_namespace_node *namespace_root); /* * adfile diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index abe8c316908c..95eed442703f 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -315,6 +315,7 @@ 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_INIT_GLOBAL(ACPI_PARSE_OBJECT_LIST, *acpi_gbl_temp_list_head, NULL); ACPI_GLOBAL(u8, acpi_gbl_dm_opt_disasm); ACPI_GLOBAL(u8, acpi_gbl_dm_opt_listing); @@ -368,6 +369,8 @@ ACPI_GLOBAL(const char, *acpi_gbl_pld_vertical_position_list[]); ACPI_GLOBAL(const char, *acpi_gbl_pld_horizontal_position_list[]); ACPI_GLOBAL(const char, *acpi_gbl_pld_shape_list[]); +ACPI_INIT_GLOBAL(u8, acpi_gbl_disasm_flag, FALSE); + #endif /* diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index f9b3f7fef462..8ddd3b20e0c6 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -859,7 +859,7 @@ ACPI_PARSE_COMMON}; * and bytelists. */ struct acpi_parse_obj_named { - ACPI_PARSE_COMMON u8 *path; + ACPI_PARSE_COMMON char *path; u8 *data; /* AML body or bytelist data */ u32 length; /* AML length */ u32 name; /* 4-byte name or zero if no name */ @@ -1142,8 +1142,13 @@ struct acpi_port_info { #define ACPI_RESOURCE_NAME_ADDRESS64 0x8A #define ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 0x8B #define ACPI_RESOURCE_NAME_GPIO 0x8C +#define ACPI_RESOURCE_NAME_PIN_FUNCTION 0x8D #define ACPI_RESOURCE_NAME_SERIAL_BUS 0x8E -#define ACPI_RESOURCE_NAME_LARGE_MAX 0x8E +#define ACPI_RESOURCE_NAME_PIN_CONFIG 0x8F +#define ACPI_RESOURCE_NAME_PIN_GROUP 0x90 +#define ACPI_RESOURCE_NAME_PIN_GROUP_FUNCTION 0x91 +#define ACPI_RESOURCE_NAME_PIN_GROUP_CONFIG 0x92 +#define ACPI_RESOURCE_NAME_LARGE_MAX 0x92 /***************************************************************************** * @@ -1176,12 +1181,18 @@ struct acpi_external_list { #define ACPI_EXT_INTERNAL_PATH_ALLOCATED 0x04 /* Deallocate internal path on completion */ #define ACPI_EXT_EXTERNAL_EMITTED 0x08 /* External() statement has been emitted */ #define ACPI_EXT_ORIGIN_FROM_OPCODE 0x10 /* External came from a External() opcode */ +#define ACPI_EXT_CONFLICTING_DECLARATION 0x20 /* External has a conflicting declaration within AML */ struct acpi_external_file { char *path; struct acpi_external_file *next; }; +struct acpi_parse_object_list { + union acpi_parse_object *op; + struct acpi_parse_object_list *next; +}; + /***************************************************************************** * * Debugger diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index a5d9af758c52..cbd59a302679 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -112,7 +112,7 @@ #define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA) #define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST) #define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME) -#define ARGP_EXTERNAL_OP ARGP_LIST3 (ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_BYTEDATA) +#define ARGP_EXTERNAL_OP ARGP_LIST3 (ARGP_NAME, ARGP_BYTEDATA, ARGP_BYTEDATA) #define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG) #define ARGP_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST) #define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index dcfc05d40e36..cdfcad8eb74c 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -581,6 +581,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = { {{"_HID", METHOD_0ARGS, METHOD_RETURNS(ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING)}}, + {{"_HMA", METHOD_0ARGS, + METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, + {{"_HOT", METHOD_0ARGS, METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, @@ -626,6 +629,19 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = { ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER | ACPI_RTYPE_STRING, 10, 0), + {{"_LSI", METHOD_0ARGS, + METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, + PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0, 0, 0), + + {{"_LSR", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER), + METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, + PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 1, + ACPI_RTYPE_BUFFER, 1, 0), + + {{"_LSW", + METHOD_3ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_BUFFER), + METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, + {{"_MAT", METHOD_0ARGS, METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h index b4d22f6e48e2..438f3098a093 100644 --- a/drivers/acpi/acpica/acresrc.h +++ b/drivers/acpi/acpica/acresrc.h @@ -148,7 +148,10 @@ typedef enum { ACPI_RSD_UINT16, ACPI_RSD_UINT32, ACPI_RSD_UINT64, - ACPI_RSD_WORDLIST + ACPI_RSD_WORDLIST, + ACPI_RSD_LABEL, + ACPI_RSD_SOURCE_LABEL, + } ACPI_RSDUMP_OPCODES; /* restore default alignment */ @@ -329,6 +332,11 @@ extern struct acpi_rsconvert_info acpi_rs_convert_fixed_dma[]; extern struct acpi_rsconvert_info acpi_rs_convert_i2c_serial_bus[]; extern struct acpi_rsconvert_info acpi_rs_convert_spi_serial_bus[]; extern struct acpi_rsconvert_info acpi_rs_convert_uart_serial_bus[]; +extern struct acpi_rsconvert_info acpi_rs_convert_pin_function[]; +extern struct acpi_rsconvert_info acpi_rs_convert_pin_config[]; +extern struct acpi_rsconvert_info acpi_rs_convert_pin_group[]; +extern struct acpi_rsconvert_info acpi_rs_convert_pin_group_function[]; +extern struct acpi_rsconvert_info acpi_rs_convert_pin_group_config[]; /* These resources require separate get/set tables */ @@ -372,12 +380,17 @@ extern struct acpi_rsdump_info acpi_rs_dump_ext_address64[]; extern struct acpi_rsdump_info acpi_rs_dump_ext_irq[]; extern struct acpi_rsdump_info acpi_rs_dump_generic_reg[]; extern struct acpi_rsdump_info acpi_rs_dump_gpio[]; +extern struct acpi_rsdump_info acpi_rs_dump_pin_function[]; extern struct acpi_rsdump_info acpi_rs_dump_fixed_dma[]; extern struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[]; extern struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[]; extern struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[]; extern struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[]; extern struct acpi_rsdump_info acpi_rs_dump_general_flags[]; +extern struct acpi_rsdump_info acpi_rs_dump_pin_config[]; +extern struct acpi_rsdump_info acpi_rs_dump_pin_group[]; +extern struct acpi_rsdump_info acpi_rs_dump_pin_group_function[]; +extern struct acpi_rsdump_info acpi_rs_dump_pin_group_config[]; #endif #endif /* __ACRESRC_H__ */ diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 6f28cfae2212..2a3cc4296481 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -85,6 +85,7 @@ extern const char *acpi_gbl_bpb_decode[]; extern const char *acpi_gbl_sb_decode[]; extern const char *acpi_gbl_fc_decode[]; extern const char *acpi_gbl_pt_decode[]; +extern const char *acpi_gbl_ptyp_decode[]; #endif /* diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 176f7e9b4d0e..f54dc5a34bdc 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -313,6 +313,11 @@ * #A is the number of required arguments * #T is the number of target operands * #R indicates whether there is a return value + * + * These types are used for the top-level dispatch of the AML + * opcode. They group similar operators that can share common + * front-end code before dispatch to the final code that implements + * the operator. */ /* @@ -353,42 +358,42 @@ * The opcode Type is used in a dispatch table, do not change * or add anything new without updating the table. */ -#define AML_TYPE_EXEC_0A_0T_1R 0x00 -#define AML_TYPE_EXEC_1A_0T_0R 0x01 /* Monadic1 */ -#define AML_TYPE_EXEC_1A_0T_1R 0x02 /* Monadic2 */ -#define AML_TYPE_EXEC_1A_1T_0R 0x03 -#define AML_TYPE_EXEC_1A_1T_1R 0x04 /* monadic2_r */ -#define AML_TYPE_EXEC_2A_0T_0R 0x05 /* Dyadic1 */ -#define AML_TYPE_EXEC_2A_0T_1R 0x06 /* Dyadic2 */ -#define AML_TYPE_EXEC_2A_1T_1R 0x07 /* dyadic2_r */ -#define AML_TYPE_EXEC_2A_2T_1R 0x08 -#define AML_TYPE_EXEC_3A_0T_0R 0x09 -#define AML_TYPE_EXEC_3A_1T_1R 0x0A -#define AML_TYPE_EXEC_6A_0T_1R 0x0B +#define AML_TYPE_EXEC_0A_0T_1R 0x00 /* 0 Args, 0 Target, 1 ret_val */ +#define AML_TYPE_EXEC_1A_0T_0R 0x01 /* 1 Args, 0 Target, 0 ret_val */ +#define AML_TYPE_EXEC_1A_0T_1R 0x02 /* 1 Args, 0 Target, 1 ret_val */ +#define AML_TYPE_EXEC_1A_1T_0R 0x03 /* 1 Args, 1 Target, 0 ret_val */ +#define AML_TYPE_EXEC_1A_1T_1R 0x04 /* 1 Args, 1 Target, 1 ret_val */ +#define AML_TYPE_EXEC_2A_0T_0R 0x05 /* 2 Args, 0 Target, 0 ret_val */ +#define AML_TYPE_EXEC_2A_0T_1R 0x06 /* 2 Args, 0 Target, 1 ret_val */ +#define AML_TYPE_EXEC_2A_1T_1R 0x07 /* 2 Args, 1 Target, 1 ret_val */ +#define AML_TYPE_EXEC_2A_2T_1R 0x08 /* 2 Args, 2 Target, 1 ret_val */ +#define AML_TYPE_EXEC_3A_0T_0R 0x09 /* 3 Args, 0 Target, 0 ret_val */ +#define AML_TYPE_EXEC_3A_1T_1R 0x0A /* 3 Args, 1 Target, 1 ret_val */ +#define AML_TYPE_EXEC_6A_0T_1R 0x0B /* 6 Args, 0 Target, 1 ret_val */ /* End of types used in dispatch table */ -#define AML_TYPE_LITERAL 0x0B -#define AML_TYPE_CONSTANT 0x0C -#define AML_TYPE_METHOD_ARGUMENT 0x0D -#define AML_TYPE_LOCAL_VARIABLE 0x0E -#define AML_TYPE_DATA_TERM 0x0F +#define AML_TYPE_LITERAL 0x0C +#define AML_TYPE_CONSTANT 0x0D +#define AML_TYPE_METHOD_ARGUMENT 0x0E +#define AML_TYPE_LOCAL_VARIABLE 0x0F +#define AML_TYPE_DATA_TERM 0x10 /* Generic for an op that returns a value */ -#define AML_TYPE_METHOD_CALL 0x10 +#define AML_TYPE_METHOD_CALL 0x11 /* Miscellaneous types */ -#define AML_TYPE_CREATE_FIELD 0x11 -#define AML_TYPE_CREATE_OBJECT 0x12 -#define AML_TYPE_CONTROL 0x13 -#define AML_TYPE_NAMED_NO_OBJ 0x14 -#define AML_TYPE_NAMED_FIELD 0x15 -#define AML_TYPE_NAMED_SIMPLE 0x16 -#define AML_TYPE_NAMED_COMPLEX 0x17 -#define AML_TYPE_RETURN 0x18 -#define AML_TYPE_UNDEFINED 0x19 -#define AML_TYPE_BOGUS 0x1A +#define AML_TYPE_CREATE_FIELD 0x12 +#define AML_TYPE_CREATE_OBJECT 0x13 +#define AML_TYPE_CONTROL 0x14 +#define AML_TYPE_NAMED_NO_OBJ 0x15 +#define AML_TYPE_NAMED_FIELD 0x16 +#define AML_TYPE_NAMED_SIMPLE 0x17 +#define AML_TYPE_NAMED_COMPLEX 0x18 +#define AML_TYPE_RETURN 0x19 +#define AML_TYPE_UNDEFINED 0x1A +#define AML_TYPE_BOGUS 0x1B /* AML Package Length encodings */ diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index 653a3d1ef5d5..1236e9a414e4 100644 --- a/drivers/acpi/acpica/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h @@ -65,6 +65,7 @@ #define ACPI_RESTAG_DRIVESTRENGTH "_DRS" #define ACPI_RESTAG_ENDIANNESS "_END" #define ACPI_RESTAG_FLOWCONTROL "_FLC" +#define ACPI_RESTAG_FUNCTION "_FUN" #define ACPI_RESTAG_GRANULARITY "_GRA" #define ACPI_RESTAG_INTERRUPT "_INT" #define ACPI_RESTAG_INTERRUPTLEVEL "_LL_" /* active_lo(1), active_hi(0) */ @@ -84,6 +85,8 @@ #define ACPI_RESTAG_PHASE "_PHA" #define ACPI_RESTAG_PIN "_PIN" #define ACPI_RESTAG_PINCONFIG "_PPI" +#define ACPI_RESTAG_PINCONFIG_TYPE "_TYP" +#define ACPI_RESTAG_PINCONFIG_VALUE "_VAL" #define ACPI_RESTAG_POLARITY "_POL" #define ACPI_RESTAG_REGISTERBITOFFSET "_RBO" #define ACPI_RESTAG_REGISTERBITWIDTH "_RBW" @@ -404,6 +407,102 @@ struct aml_resource_uart_serialbus { #define AML_RESOURCE_UART_TYPE_REVISION 1 /* ACPI 5.0 */ #define AML_RESOURCE_UART_MIN_DATA_LEN 10 +struct aml_resource_pin_function { + AML_RESOURCE_LARGE_HEADER_COMMON u8 revision_id; + u16 flags; + u8 pin_config; + u16 function_number; + u16 pin_table_offset; + u8 res_source_index; + u16 res_source_offset; + u16 vendor_offset; + u16 vendor_length; + /* + * Optional fields follow immediately: + * 1) PIN list (Words) + * 2) Resource Source String + * 3) Vendor Data bytes + */ +}; + +#define AML_RESOURCE_PIN_FUNCTION_REVISION 1 /* ACPI 6.2 */ + +struct aml_resource_pin_config { + AML_RESOURCE_LARGE_HEADER_COMMON u8 revision_id; + u16 flags; + u8 pin_config_type; + u32 pin_config_value; + u16 pin_table_offset; + u8 res_source_index; + u16 res_source_offset; + u16 vendor_offset; + u16 vendor_length; + /* + * Optional fields follow immediately: + * 1) PIN list (Words) + * 2) Resource Source String + * 3) Vendor Data bytes + */ +}; + +#define AML_RESOURCE_PIN_CONFIG_REVISION 1 /* ACPI 6.2 */ + +struct aml_resource_pin_group { + AML_RESOURCE_LARGE_HEADER_COMMON u8 revision_id; + u16 flags; + u16 pin_table_offset; + u16 label_offset; + u16 vendor_offset; + u16 vendor_length; + /* + * Optional fields follow immediately: + * 1) PIN list (Words) + * 2) Resource Label String + * 3) Vendor Data bytes + */ +}; + +#define AML_RESOURCE_PIN_GROUP_REVISION 1 /* ACPI 6.2 */ + +struct aml_resource_pin_group_function { + AML_RESOURCE_LARGE_HEADER_COMMON u8 revision_id; + u16 flags; + u16 function_number; + u8 res_source_index; + u16 res_source_offset; + u16 res_source_label_offset; + u16 vendor_offset; + u16 vendor_length; + /* + * Optional fields follow immediately: + * 1) Resource Source String + * 2) Resource Source Label String + * 3) Vendor Data bytes + */ +}; + +#define AML_RESOURCE_PIN_GROUP_FUNCTION_REVISION 1 /* ACPI 6.2 */ + +struct aml_resource_pin_group_config { + AML_RESOURCE_LARGE_HEADER_COMMON u8 revision_id; + u16 flags; + u8 pin_config_type; + u32 pin_config_value; + u8 res_source_index; + u16 res_source_offset; + u16 res_source_label_offset; + u16 vendor_offset; + u16 vendor_length; + /* + * Optional fields follow immediately: + * 1) Resource Source String + * 2) Resource Source Label String + * 3) Vendor Data bytes + */ +}; + +#define AML_RESOURCE_PIN_GROUP_CONFIG_REVISION 1 /* ACPI 6.2 */ + /* restore default alignment */ #pragma pack() @@ -446,6 +545,11 @@ union aml_resource { struct aml_resource_spi_serialbus spi_serial_bus; struct aml_resource_uart_serialbus uart_serial_bus; struct aml_resource_common_serialbus common_serial_bus; + struct aml_resource_pin_function pin_function; + struct aml_resource_pin_config pin_config; + struct aml_resource_pin_group pin_group; + struct aml_resource_pin_group_function pin_group_function; + struct aml_resource_pin_group_config pin_group_config; /* Utility overlays */ diff --git a/drivers/acpi/acpica/dbexec.c b/drivers/acpi/acpica/dbexec.c index b611cd92b5f5..3b30319752f0 100644 --- a/drivers/acpi/acpica/dbexec.c +++ b/drivers/acpi/acpica/dbexec.c @@ -181,6 +181,18 @@ acpi_db_execute_method(struct acpi_db_method_info *info, acpi_gbl_method_executing = FALSE; if (ACPI_FAILURE(status)) { + if ((status == AE_ABORT_METHOD) || acpi_gbl_abort_method) { + + /* Clear the abort and fall back to the debugger prompt */ + + ACPI_EXCEPTION((AE_INFO, status, + "Aborting top-level method")); + + acpi_gbl_abort_method = FALSE; + status = AE_OK; + goto cleanup; + } + ACPI_EXCEPTION((AE_INFO, status, "while executing %s from debugger", info->pathname)); diff --git a/drivers/acpi/acpica/dbobject.c b/drivers/acpi/acpica/dbobject.c index f2252b1ac0b3..e7b415c20aa8 100644 --- a/drivers/acpi/acpica/dbobject.c +++ b/drivers/acpi/acpica/dbobject.c @@ -448,7 +448,7 @@ void acpi_db_decode_locals(struct acpi_walk_state *walk_state) if (display_locals) { acpi_os_printf - ("\nInitialized Local Variables for method [%4.4s]:\n", + ("\nInitialized Local Variables for Method [%4.4s]:\n", acpi_ut_get_node_name(node)); for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) { @@ -461,7 +461,7 @@ void acpi_db_decode_locals(struct acpi_walk_state *walk_state) } } else { acpi_os_printf - ("No Local Variables are initialized for method [%4.4s]\n", + ("No Local Variables are initialized for Method [%4.4s]\n", acpi_ut_get_node_name(node)); } } @@ -515,7 +515,7 @@ void acpi_db_decode_arguments(struct acpi_walk_state *walk_state) acpi_os_printf("Initialized Arguments for Method [%4.4s]: " "(%X arguments defined for method invocation)\n", acpi_ut_get_node_name(node), - obj_desc->method.param_count); + node->object->method.param_count); for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) { obj_desc = walk_state->arguments[i].object; diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c index 8f665d94b8b5..b6985323e7eb 100644 --- a/drivers/acpi/acpica/dbxface.c +++ b/drivers/acpi/acpica/dbxface.c @@ -244,7 +244,7 @@ acpi_db_single_step(struct acpi_walk_state *walk_state, if ((acpi_gbl_db_output_to_file) || (acpi_dbg_level & ACPI_LV_PARSE)) { acpi_os_printf - ("\n[AmlDebug] Next AML Opcode to execute:\n"); + ("\nAML Debug: Next AML Opcode to execute:\n"); } /* diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c index 287b3fd73cfc..2873455c986d 100644 --- a/drivers/acpi/acpica/dsargs.c +++ b/drivers/acpi/acpica/dsargs.c @@ -82,7 +82,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node, union acpi_parse_object *op; struct acpi_walk_state *walk_state; - ACPI_FUNCTION_TRACE(ds_execute_arguments); + ACPI_FUNCTION_TRACE_PTR(ds_execute_arguments, aml_start); /* Allocate a new parser op to be the root of the parsed tree */ @@ -338,7 +338,8 @@ acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc) return_ACPI_STATUS(AE_AML_INTERNAL); } - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Package Arg Init\n")); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Package Argument Init, AML Ptr: %p\n", + obj_desc->package.aml_start)); /* Execute the AML code for the term_arg arguments */ diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c index 4d885eb8eda9..d1f457eda980 100644 --- a/drivers/acpi/acpica/dsdebug.c +++ b/drivers/acpi/acpica/dsdebug.c @@ -196,6 +196,7 @@ acpi_ds_dump_method_stack(acpi_status status, op->common.next = NULL; #ifdef ACPI_DISASSEMBLER + acpi_os_printf("Failed at "); acpi_dm_disassemble(next_walk_state, op, ACPI_UINT32_MAX); #endif diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 31c9c7aec3d5..d7fc36917c67 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -212,6 +212,7 @@ acpi_status acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state) { u32 aml_offset; + acpi_name name = 0; ACPI_FUNCTION_ENTRY(); @@ -237,10 +238,13 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state) walk_state->parser_state. aml_start); - status = acpi_gbl_exception_handler(status, - walk_state->method_node ? - walk_state->method_node-> - name.integer : 0, + if (walk_state->method_node) { + name = walk_state->method_node->name.integer; + } else if (walk_state->deferred_node) { + name = walk_state->deferred_node->name.integer; + } + + status = acpi_gbl_exception_handler(status, name, walk_state->opcode, aml_offset, NULL); acpi_ex_enter_interpreter(); diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index 9a8f8a992b3e..dfc3c25a083d 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -227,13 +227,12 @@ acpi_ds_init_buffer_field(u16 aml_opcode, /* Entire field must fit within the current length of the buffer */ - if ((bit_offset + bit_count) > (8 * (u32) buffer_desc->buffer.length)) { + if ((bit_offset + bit_count) > (8 * (u32)buffer_desc->buffer.length)) { ACPI_ERROR((AE_INFO, - "Field [%4.4s] at %u exceeds Buffer [%4.4s] size %u (bits)", - acpi_ut_get_node_name(result_desc), - bit_offset + bit_count, - acpi_ut_get_node_name(buffer_desc->buffer.node), - 8 * (u32) buffer_desc->buffer.length)); + "Field [%4.4s] at bit offset/length %u/%u " + "exceeds size of target Buffer (%u bits)", + acpi_ut_get_node_name(result_desc), bit_offset, + bit_count, 8 * (u32)buffer_desc->buffer.length)); status = AE_AML_BUFFER_LIMIT; goto cleanup; } diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index 406edec20de7..0dabd9b95684 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -633,15 +633,6 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, if ((op_info->flags & AML_HAS_RETVAL) || (arg->common.flags & ACPI_PARSEOP_IN_STACK)) { - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Argument previously created, already stacked\n")); - - acpi_db_display_argument_object(walk_state-> - operands[walk_state-> - num_operands - - 1], - walk_state); - /* * Use value that was already previously returned * by the evaluation of this argument diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index a2ff8ad70d58..20d7744b06ae 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -576,8 +576,8 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) case AML_TYPE_CREATE_OBJECT: ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Executing CreateObject (Buffer/Package) Op=%p\n", - op)); + "Executing CreateObject (Buffer/Package) Op=%p AMLPtr=%p\n", + op, op->named.data)); switch (op->common.parent->common.aml_opcode) { case AML_NAME_OP: diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index cafb3ab567ab..eaa859a89702 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -397,7 +397,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state, /* Initialize the op */ #if (defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)) - op->named.path = ACPI_CAST_PTR(u8, path); + op->named.path = path; #endif if (node) { @@ -434,6 +434,10 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state) acpi_object_type object_type; acpi_status status = AE_OK; +#ifdef ACPI_ASL_COMPILER + u8 param_count; +#endif + ACPI_FUNCTION_TRACE(ds_load1_end_op); op = walk_state->op; @@ -514,6 +518,38 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state) } } } +#ifdef ACPI_ASL_COMPILER + /* + * For external opcode, get the object type from the argument and + * get the parameter count from the argument's next. + */ + if (acpi_gbl_disasm_flag && + op->common.node && op->common.aml_opcode == AML_EXTERNAL_OP) { + /* + * Note, if this external is not a method + * Op->Common.Value.Arg->Common.Next->Common.Value.Integer == 0 + * Therefore, param_count will be 0. + */ + param_count = + (u8)op->common.value.arg->common.next->common.value.integer; + object_type = (u8)op->common.value.arg->common.value.integer; + op->common.node->flags |= ANOBJ_IS_EXTERNAL; + op->common.node->type = (u8)object_type; + + acpi_dm_create_subobject_for_external((u8)object_type, + &op->common.node, + param_count); + + /* + * Add the external to the external list because we may be + * emitting code based off of the items within the external list. + */ + acpi_dm_add_op_to_external_list(op, op->named.path, + (u8)object_type, param_count, + ACPI_EXT_ORIGIN_FROM_OPCODE | + ACPI_EXT_RESOLVED_REFERENCE); + } +#endif /* * If we are executing a method, do not create any namespace objects @@ -563,7 +599,9 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state) /* Pop the scope stack (only if loading a table) */ - if (!walk_state->method_node && acpi_ns_opens_scope(object_type)) { + if (!walk_state->method_node && + op->common.aml_opcode != AML_EXTERNAL_OP && + acpi_ns_opens_scope(object_type)) { ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "(%s): Popping scope for Op %p\n", acpi_ut_get_type_name(object_type), op)); diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index 8d510c7e20c8..aad83ef5a4ec 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -310,6 +310,22 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, flags |= ACPI_NS_TEMPORARY; } } +#ifdef ACPI_ASL_COMPILER + + /* + * Do not open a scope for AML_EXTERNAL_OP + * acpi_ns_lookup can open a new scope based on the object type + * of this op. AML_EXTERNAL_OP is a declaration rather than a + * definition. In the case that this external is a method object, + * acpi_ns_lookup will open a new scope. However, an AML_EXTERNAL_OP + * associated with the ACPI_TYPE_METHOD is a declaration, rather than + * a definition. Flags is set to avoid opening a scope for any + * AML_EXTERNAL_OP. + */ + if (walk_state->opcode == AML_EXTERNAL_OP) { + flags |= ACPI_NS_DONT_OPEN_SCOPE; + } +#endif /* Add new entry or lookup existing entry */ diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index 82e8971f23a4..c773ac4892cb 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -180,6 +180,12 @@ acpi_status acpi_enable_event(u32 event, u32 flags) ACPI_FUNCTION_TRACE(acpi_enable_event); + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Decode the Fixed Event */ if (event > ACPI_EVENT_MAX) { @@ -237,6 +243,12 @@ acpi_status acpi_disable_event(u32 event, u32 flags) ACPI_FUNCTION_TRACE(acpi_disable_event); + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Decode the Fixed Event */ if (event > ACPI_EVENT_MAX) { @@ -290,6 +302,12 @@ acpi_status acpi_clear_event(u32 event) ACPI_FUNCTION_TRACE(acpi_clear_event); + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Decode the Fixed Event */ if (event > ACPI_EVENT_MAX) { diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index ec614f5a3bcb..a8191d2ca5e3 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -117,10 +117,10 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, timer = ((u32)acpi_os_get_timer() / 10); timer &= 0x03FFFFFF; - acpi_os_printf("[ACPI Debug T=0x%8.8X] %*s", timer, + acpi_os_printf("ACPI Debug: T=0x%8.8X %*s", timer, level, " "); } else { - acpi_os_printf("[ACPI Debug] %*s", level, " "); + acpi_os_printf("ACPI Debug: %*s", level, " "); } } diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 970dc6c53994..44092f744477 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -645,10 +645,12 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) /* obj_desc is a valid object */ if (depth > 0) { - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%*s[%u] %p ", - depth, " ", depth, obj_desc)); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%*s[%u] %p Refs=%u ", + depth, " ", depth, obj_desc, + obj_desc->common.reference_count)); } else { - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%p ", obj_desc)); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%p Refs=%u ", + obj_desc, obj_desc->common.reference_count)); } /* Decode object type */ @@ -690,8 +692,11 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) case ACPI_REFCLASS_NAME: - acpi_os_printf("- [%4.4s]\n", - obj_desc->reference.node->name.ascii); + acpi_ut_repair_name(obj_desc->reference.node->name. + ascii); + acpi_os_printf("- [%4.4s] (Node %p)\n", + obj_desc->reference.node->name.ascii, + obj_desc->reference.node); break; case ACPI_REFCLASS_ARG: @@ -999,9 +1004,15 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc) status = acpi_ns_handle_to_pathname(obj_desc->reference.node, &ret_buf, TRUE); if (ACPI_FAILURE(status)) { - acpi_os_printf(" Could not convert name to pathname\n"); + acpi_os_printf + (" Could not convert name to pathname: %s\n", + acpi_format_exception(status)); } else { - acpi_os_printf("%s\n", (char *)ret_buf.pointer); + acpi_os_printf("%s: %s\n", + acpi_ut_get_type_name(obj_desc-> + reference.node-> + type), + (char *)ret_buf.pointer); ACPI_FREE(ret_buf.pointer); } } else if (obj_desc->reference.object) { @@ -1111,9 +1122,8 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc, case ACPI_TYPE_LOCAL_REFERENCE: - acpi_os_printf("[Object Reference] Type [%s] %2.2X", - acpi_ut_get_reference_name(obj_desc), - obj_desc->reference.class); + acpi_os_printf("[Object Reference] Class [%s]", + acpi_ut_get_reference_name(obj_desc)); acpi_ex_dump_reference_obj(obj_desc); break; diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index e327349675cd..f787651348c1 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -921,13 +921,26 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) * This is a deref_of (object_reference) * Get the actual object from the Node (This is the dereference). * This case may only happen when a local_x or arg_x is - * dereferenced above. + * dereferenced above, or for references to device and + * thermal objects. */ - return_desc = acpi_ns_get_attached_object((struct - acpi_namespace_node - *) - operand[0]); - acpi_ut_add_reference(return_desc); + switch (((struct acpi_namespace_node *)operand[0])-> + type) { + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_THERMAL: + + /* These types have no node subobject, return the NS node */ + + return_desc = operand[0]; + break; + + default: + /* For most types, get the object attached to the node */ + + return_desc = acpi_ns_get_attached_object((struct acpi_namespace_node *)operand[0]); + acpi_ut_add_reference(return_desc); + break; + } } else { /* * This must be a reference object produced by either the diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index aa8c6fd74cc3..5e1854ea85f6 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -368,11 +368,24 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, *)obj_desc); } - if (!obj_desc) { - ACPI_ERROR((AE_INFO, - "[%4.4s] Node is unresolved or uninitialized", - acpi_ut_get_node_name(node))); - return_ACPI_STATUS(AE_AML_UNINITIALIZED_NODE); + switch (type) { + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_THERMAL: + + /* These types have no attached subobject */ + break; + + default: + + /* All other types require a subobject */ + + if (!obj_desc) { + ACPI_ERROR((AE_INFO, + "[%4.4s] Node is unresolved or uninitialized", + acpi_ut_get_node_name(node))); + return_ACPI_STATUS(AE_AML_UNINITIALIZED_NODE); + } + break; } break; diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index 5733b1167e46..7ef13934968f 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -70,11 +70,15 @@ static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id); /* Legacy functions are optional, based upon ACPI_REDUCED_HARDWARE */ static struct acpi_sleep_functions acpi_sleep_dispatch[] = { - {ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_sleep), - acpi_hw_extended_sleep}, - {ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake_prep), - acpi_hw_extended_wake_prep}, - {ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake), acpi_hw_extended_wake} + {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(legacy_function, + ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_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) } }; /* diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index fb265b5737de..e5f4fa496572 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -47,6 +47,10 @@ #include "acnamesp.h" #include "acdispat.h" +#ifdef ACPI_ASL_COMPILER +#include "acdisasm.h" +#endif + #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsaccess") @@ -580,6 +584,29 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, (char *)¤t_node->name, current_node)); } +#ifdef ACPI_ASL_COMPILER + /* + * If this ACPI name already exists within the namespace as an + * external declaration, then mark the external as a conflicting + * declaration and proceed to process the current node as if it did + * not exist in the namespace. If this node is not processed as + * normal, then it could cause improper namespace resolution + * by failing to open a new scope. + */ + if (acpi_gbl_disasm_flag && + (status == AE_ALREADY_EXISTS) && + ((this_node->flags & ANOBJ_IS_EXTERNAL) || + (walk_state + && walk_state->opcode == AML_EXTERNAL_OP))) { + this_node->flags &= ~ANOBJ_IS_EXTERNAL; + this_node->type = (u8)this_search_type; + if (walk_state->opcode != AML_EXTERNAL_OP) { + acpi_dm_mark_external_conflict + (this_node); + } + break; + } +#endif *return_node = this_node; return_ACPI_STATUS(status); diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index 3db9ca25a620..aa16aeaa8937 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -190,9 +190,6 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, (void)acpi_ns_build_normalized_path(node, buffer->pointer, required_size, no_trailing); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%X]\n", (char *)buffer->pointer, (u32) required_size)); diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 2fe87d0dd9d5..b43fe5fce64b 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -89,7 +89,7 @@ acpi_ns_print_node_pathname(struct acpi_namespace_node *node, acpi_os_printf("%s ", message); } - acpi_os_printf("[%s] (Node %p)", (char *)buffer.pointer, node); + acpi_os_printf("%s", (char *)buffer.pointer); ACPI_FREE(buffer.pointer); } } diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index c944ff5c9c3d..538c61677c10 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -85,6 +85,8 @@ acpi_evaluate_object_typed(acpi_handle handle, { acpi_status status; u8 free_buffer_on_error = FALSE; + acpi_handle target_handle; + char *full_pathname; ACPI_FUNCTION_TRACE(acpi_evaluate_object_typed); @@ -98,38 +100,51 @@ acpi_evaluate_object_typed(acpi_handle handle, free_buffer_on_error = TRUE; } + status = acpi_get_handle(handle, pathname, &target_handle); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + full_pathname = acpi_ns_get_external_pathname(target_handle); + if (!full_pathname) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + /* Evaluate the object */ - status = acpi_evaluate_object(handle, pathname, - external_params, return_buffer); + status = acpi_evaluate_object(target_handle, NULL, external_params, + return_buffer); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto exit; } - /* Type ANY means "don't care" */ + /* Type ANY means "don't care about return value type" */ if (return_type == ACPI_TYPE_ANY) { - return_ACPI_STATUS(AE_OK); + goto exit; } if (return_buffer->length == 0) { /* Error because caller specifically asked for a return value */ - ACPI_ERROR((AE_INFO, "No return value")); - return_ACPI_STATUS(AE_NULL_OBJECT); + ACPI_ERROR((AE_INFO, "%s did not return any object", + full_pathname)); + status = AE_NULL_OBJECT; + goto exit; } /* Examine the object type returned from evaluate_object */ if (((union acpi_object *)return_buffer->pointer)->type == return_type) { - return_ACPI_STATUS(AE_OK); + goto exit; } /* Return object type does not match requested type */ ACPI_ERROR((AE_INFO, - "Incorrect return type [%s] requested [%s]", + "Incorrect return type from %s - received [%s], requested [%s]", + full_pathname, acpi_ut_get_type_name(((union acpi_object *)return_buffer-> pointer)->type), acpi_ut_get_type_name(return_type))); @@ -147,7 +162,11 @@ acpi_evaluate_object_typed(acpi_handle handle, } return_buffer->length = 0; - return_ACPI_STATUS(AE_TYPE); + status = AE_TYPE; + +exit: + ACPI_FREE(full_pathname); + return_ACPI_STATUS(status); } ACPI_EXPORT_SYMBOL(acpi_evaluate_object_typed) diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index 5bcb61831706..ef6384e374fc 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -122,6 +122,9 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) (u32)(aml_offset + sizeof(struct acpi_table_header))); + ACPI_ERROR((AE_INFO, + "Aborting disassembly, AML byte code is corrupt")); + /* Dump the context surrounding the invalid opcode */ acpi_ut_dump_buffer(((u8 *)walk_state->parser_state. @@ -130,6 +133,14 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) sizeof(struct acpi_table_header) - 16)); acpi_os_printf(" */\n"); + + /* + * Just abort the disassembly, cannot continue because the + * parser is essentially lost. The disassembler can then + * randomly fail because an ill-constructed parse tree + * can result. + */ + return_ACPI_STATUS(AE_AML_BAD_OPCODE); #endif } @@ -331,6 +342,9 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, if (status == AE_CTRL_PARSE_CONTINUE) { return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); } + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } /* Create Op structure and append to parent's argument list */ diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index c343a0d5a3d2..a402ad772a1e 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -650,9 +650,11 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { /* ACPI 6.0 opcodes */ - /* 81 */ ACPI_OP("External", ARGP_EXTERNAL_OP, ARGI_EXTERNAL_OP, - ACPI_TYPE_ANY, AML_CLASS_EXECUTE, /* ? */ - AML_TYPE_EXEC_3A_0T_0R, AML_FLAGS_EXEC_3A_0T_0R), +/* 81 */ ACPI_OP("External", ARGP_EXTERNAL_OP, ARGI_EXTERNAL_OP, + ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, + AML_TYPE_NAMED_SIMPLE, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE | AML_NAMED), /* 82 */ ACPI_OP("Comment", ARGP_COMMENT_OP, ARGI_COMMENT_OP, ACPI_TYPE_STRING, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT) diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 8116a670de39..ac88319dc111 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -56,6 +56,7 @@ #include "acdispat.h" #include "amlcode.h" #include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psparse") @@ -538,9 +539,16 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) /* Either the method parse or actual execution failed */ acpi_ex_exit_interpreter(); - ACPI_ERROR_METHOD("Method parse/execution failed", - walk_state->method_node, NULL, - status); + if (status == AE_ABORT_METHOD) { + acpi_ns_print_node_pathname(walk_state-> + method_node, + "Method aborted:"); + acpi_os_printf("\n"); + } else { + ACPI_ERROR_METHOD + ("Method parse/execution failed", + walk_state->method_node, NULL, status); + } acpi_ex_enter_interpreter(); /* Check for possible multi-thread reentrancy problem */ diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index 74e47f829ccb..659fb718504a 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -340,6 +340,22 @@ acpi_rs_get_aml_length(struct acpi_resource *resource, break; + case ACPI_RESOURCE_TYPE_PIN_FUNCTION: + + total_size = (acpi_rs_length)(total_size + + (resource->data. + pin_function. + pin_table_length * 2) + + resource->data. + pin_function. + resource_source. + string_length + + resource->data. + pin_function. + vendor_length); + + break; + case ACPI_RESOURCE_TYPE_SERIAL_BUS: total_size = @@ -359,6 +375,67 @@ acpi_rs_get_aml_length(struct acpi_resource *resource, break; + case ACPI_RESOURCE_TYPE_PIN_CONFIG: + + total_size = (acpi_rs_length)(total_size + + (resource->data. + pin_config. + pin_table_length * 2) + + resource->data.pin_config. + resource_source. + string_length + + resource->data.pin_config. + vendor_length); + + break; + + case ACPI_RESOURCE_TYPE_PIN_GROUP: + + total_size = (acpi_rs_length)(total_size + + (resource->data.pin_group. + pin_table_length * 2) + + resource->data.pin_group. + resource_label. + string_length + + resource->data.pin_group. + vendor_length); + + break; + + case ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION: + + total_size = (acpi_rs_length)(total_size + + resource->data. + pin_group_function. + resource_source. + string_length + + resource->data. + pin_group_function. + resource_source_label. + string_length + + resource->data. + pin_group_function. + vendor_length); + + break; + + case ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG: + + total_size = (acpi_rs_length)(total_size + + resource->data. + pin_group_config. + resource_source. + string_length + + resource->data. + pin_group_config. + resource_source_label. + string_length + + resource->data. + pin_group_config. + vendor_length); + + break; + default: break; @@ -537,6 +614,24 @@ acpi_rs_get_list_length(u8 *aml_buffer, } break; + case ACPI_RESOURCE_NAME_PIN_FUNCTION: + + /* Vendor data is optional */ + + if (aml_resource->pin_function.vendor_length) { + extra_struct_bytes += + aml_resource->pin_function.vendor_offset - + aml_resource->pin_function. + pin_table_offset + + aml_resource->pin_function.vendor_length; + } else { + extra_struct_bytes += + aml_resource->large_header.resource_length + + sizeof(struct aml_resource_large_header) - + aml_resource->pin_function.pin_table_offset; + } + break; + case ACPI_RESOURCE_NAME_SERIAL_BUS: minimum_aml_resource_length = @@ -547,6 +642,50 @@ acpi_rs_get_list_length(u8 *aml_buffer, minimum_aml_resource_length; break; + case ACPI_RESOURCE_NAME_PIN_CONFIG: + + /* Vendor data is optional */ + + if (aml_resource->pin_config.vendor_length) { + extra_struct_bytes += + aml_resource->pin_config.vendor_offset - + aml_resource->pin_config.pin_table_offset + + aml_resource->pin_config.vendor_length; + } else { + extra_struct_bytes += + aml_resource->large_header.resource_length + + sizeof(struct aml_resource_large_header) - + aml_resource->pin_config.pin_table_offset; + } + break; + + case ACPI_RESOURCE_NAME_PIN_GROUP: + + extra_struct_bytes += + aml_resource->pin_group.vendor_offset - + aml_resource->pin_group.pin_table_offset + + aml_resource->pin_group.vendor_length; + + break; + + case ACPI_RESOURCE_NAME_PIN_GROUP_FUNCTION: + + extra_struct_bytes += + aml_resource->pin_group_function.vendor_offset - + aml_resource->pin_group_function.res_source_offset + + aml_resource->pin_group_function.vendor_length; + + break; + + case ACPI_RESOURCE_NAME_PIN_GROUP_CONFIG: + + extra_struct_bytes += + aml_resource->pin_group_config.vendor_offset - + aml_resource->pin_group_config.res_source_offset + + aml_resource->pin_group_config.vendor_length; + + break; + default: break; diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c index f4cdf8d832dc..55fd1880efbe 100644 --- a/drivers/acpi/acpica/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -75,6 +75,10 @@ static void acpi_rs_dump_short_byte_list(u8 length, u8 *data); static void acpi_rs_dump_resource_source(struct acpi_resource_source *resource_source); +static void +acpi_rs_dump_resource_label(char *title, + struct acpi_resource_label *resource_label); + static void acpi_rs_dump_address_common(union acpi_resource_data *resource); static void @@ -371,6 +375,26 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table) target)); break; + case ACPI_RSD_LABEL: + /* + * resource_label + */ + acpi_rs_dump_resource_label("Resource Label", + ACPI_CAST_PTR(struct + acpi_resource_label, + target)); + break; + + case ACPI_RSD_SOURCE_LABEL: + /* + * resource_source_label + */ + acpi_rs_dump_resource_label("Resource Source Label", + ACPI_CAST_PTR(struct + acpi_resource_label, + target)); + break; + default: acpi_os_printf("**** Invalid table opcode [%X] ****\n", @@ -414,6 +438,30 @@ acpi_rs_dump_resource_source(struct acpi_resource_source *resource_source) /******************************************************************************* * + * FUNCTION: acpi_rs_dump_resource_label + * + * PARAMETERS: title - Title of the dumped resource field + * resource_label - Pointer to a Resource Label struct + * + * RETURN: None + * + * DESCRIPTION: Common routine for dumping the resource_label + * + ******************************************************************************/ + +static void +acpi_rs_dump_resource_label(char *title, + struct acpi_resource_label *resource_label) +{ + ACPI_FUNCTION_ENTRY(); + + acpi_rs_out_string(title, + resource_label->string_ptr ? + resource_label->string_ptr : "[Not Specified]"); +} + +/******************************************************************************* + * * FUNCTION: acpi_rs_dump_address_common * * PARAMETERS: resource - Pointer to an internal resource descriptor diff --git a/drivers/acpi/acpica/rsdumpinfo.c b/drivers/acpi/acpica/rsdumpinfo.c index 8aacd28293fa..da150e17795b 100644 --- a/drivers/acpi/acpica/rsdumpinfo.c +++ b/drivers/acpi/acpica/rsdumpinfo.c @@ -314,6 +314,120 @@ struct acpi_rsdump_info acpi_rs_dump_gpio[16] = { NULL}, }; +struct acpi_rsdump_info acpi_rs_dump_pin_function[10] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_pin_function), + "PinFunction", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_function.revision_id), + "RevisionId", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_function.pin_config), "PinConfig", + acpi_gbl_ppc_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(pin_function.sharable), "Sharing", + acpi_gbl_shr_decode}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_function.function_number), + "FunctionNumber", NULL}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(pin_function.resource_source), + "ResourceSource", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_function.pin_table_length), + "PinTableLength", NULL}, + {ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET(pin_function.pin_table), "PinTable", + NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_function.vendor_length), + "VendorLength", NULL}, + {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(pin_function.vendor_data), + "VendorData", NULL}, +}; + +struct acpi_rsdump_info acpi_rs_dump_pin_config[11] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_pin_config), + "PinConfig", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_config.revision_id), "RevisionId", + NULL}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(pin_config.producer_consumer), + "ProducerConsumer", acpi_gbl_consume_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(pin_config.sharable), "Sharing", + acpi_gbl_shr_decode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_config.pin_config_type), + "PinConfigType", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(pin_config.pin_config_value), + "PinConfigValue", NULL}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(pin_config.resource_source), + "ResourceSource", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_config.pin_table_length), + "PinTableLength", NULL}, + {ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET(pin_config.pin_table), "PinTable", + NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_config.vendor_length), + "VendorLength", NULL}, + {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(pin_config.vendor_data), + "VendorData", NULL}, +}; + +struct acpi_rsdump_info acpi_rs_dump_pin_group[8] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_pin_group), + "PinGroup", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_group.revision_id), "RevisionId", + NULL}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(pin_group.producer_consumer), + "ProducerConsumer", acpi_gbl_consume_decode}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_group.pin_table_length), + "PinTableLength", NULL}, + {ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET(pin_group.pin_table), "PinTable", + NULL}, + {ACPI_RSD_LABEL, ACPI_RSD_OFFSET(pin_group.resource_label), + "ResourceLabel", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_group.vendor_length), + "VendorLength", NULL}, + {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(pin_group.vendor_data), + "VendorData", NULL}, +}; + +struct acpi_rsdump_info acpi_rs_dump_pin_group_function[9] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_pin_group_function), + "PinGroupFunction", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_group_function.revision_id), + "RevisionId", NULL}, + {ACPI_RSD_1BITFLAG, + ACPI_RSD_OFFSET(pin_group_function.producer_consumer), + "ProducerConsumer", acpi_gbl_consume_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(pin_group_function.sharable), + "Sharing", acpi_gbl_shr_decode}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_group_function.function_number), + "FunctionNumber", NULL}, + {ACPI_RSD_SOURCE_LABEL, + ACPI_RSD_OFFSET(pin_group_function.resource_source_label), + "ResourceSourceLabel", NULL}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(pin_group_function.resource_source), + "ResourceSource", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_group_function.vendor_length), + "VendorLength", NULL}, + {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(pin_group_function.vendor_data), + "VendorData", NULL}, +}; + +struct acpi_rsdump_info acpi_rs_dump_pin_group_config[10] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_pin_group_config), + "PinGroupConfig", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_group_config.revision_id), + "RevisionId", NULL}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(pin_group_config.producer_consumer), + "ProducerConsumer", acpi_gbl_consume_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(pin_group_config.sharable), + "Sharing", acpi_gbl_shr_decode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(pin_group_config.pin_config_type), + "PinConfigType", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(pin_group_config.pin_config_value), + "PinConfigValue", NULL}, + {ACPI_RSD_SOURCE_LABEL, + ACPI_RSD_OFFSET(pin_group_config.resource_source_label), + "ResourceSourceLabel", NULL}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(pin_group_config.resource_source), + "ResourceSource", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(pin_group_config.vendor_length), + "VendorLength", NULL}, + {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(pin_group_config.vendor_data), + "VendorData", NULL}, +}; + struct acpi_rsdump_info acpi_rs_dump_fixed_dma[4] = { {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_dma), "FixedDma", NULL}, diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c index 475da9d6aed5..b0e50518d766 100644 --- a/drivers/acpi/acpica/rsinfo.c +++ b/drivers/acpi/acpica/rsinfo.c @@ -80,6 +80,11 @@ struct acpi_rsconvert_info *acpi_gbl_set_resource_dispatch[] = { acpi_rs_convert_gpio, /* 0x11, ACPI_RESOURCE_TYPE_GPIO */ acpi_rs_convert_fixed_dma, /* 0x12, ACPI_RESOURCE_TYPE_FIXED_DMA */ NULL, /* 0x13, ACPI_RESOURCE_TYPE_SERIAL_BUS - Use subtype table below */ + acpi_rs_convert_pin_function, /* 0x14, ACPI_RESOURCE_TYPE_PIN_FUNCTION */ + acpi_rs_convert_pin_config, /* 0x15, ACPI_RESOURCE_TYPE_PIN_CONFIG */ + acpi_rs_convert_pin_group, /* 0x16, ACPI_RESOURCE_TYPE_PIN_GROUP */ + acpi_rs_convert_pin_group_function, /* 0x17, ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION */ + acpi_rs_convert_pin_group_config, /* 0x18, ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG */ }; /* Dispatch tables for AML-to-resource (Get Resource) conversion functions */ @@ -119,8 +124,12 @@ struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[] = { acpi_rs_convert_address64, /* 0x0A, ACPI_RESOURCE_NAME_ADDRESS64 */ acpi_rs_convert_ext_address64, /* 0x0B, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 */ acpi_rs_convert_gpio, /* 0x0C, ACPI_RESOURCE_NAME_GPIO */ - NULL, /* 0x0D, Reserved */ + acpi_rs_convert_pin_function, /* 0x0D, ACPI_RESOURCE_NAME_PIN_FUNCTION */ NULL, /* 0x0E, ACPI_RESOURCE_NAME_SERIAL_BUS - Use subtype table below */ + acpi_rs_convert_pin_config, /* 0x0F, ACPI_RESOURCE_NAME_PIN_CONFIG */ + acpi_rs_convert_pin_group, /* 0x10, ACPI_RESOURCE_NAME_PIN_GROUP */ + acpi_rs_convert_pin_group_function, /* 0x11, ACPI_RESOURCE_NAME_PIN_GROUP_FUNCTION */ + acpi_rs_convert_pin_group_config, /* 0x12, ACPI_RESOURCE_NAME_PIN_GROUP_CONFIG */ }; /* Subtype table for serial_bus -- I2C, SPI, and UART */ @@ -157,6 +166,11 @@ struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[] = { acpi_rs_dump_gpio, /* ACPI_RESOURCE_TYPE_GPIO */ acpi_rs_dump_fixed_dma, /* ACPI_RESOURCE_TYPE_FIXED_DMA */ NULL, /* ACPI_RESOURCE_TYPE_SERIAL_BUS */ + acpi_rs_dump_pin_function, /* ACPI_RESOURCE_TYPE_PIN_FUNCTION */ + acpi_rs_dump_pin_config, /* ACPI_RESOURCE_TYPE_PIN_CONFIG */ + acpi_rs_dump_pin_group, /* ACPI_RESOURCE_TYPE_PIN_GROUP */ + acpi_rs_dump_pin_group_function, /* ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION */ + acpi_rs_dump_pin_group_config, /* ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG */ }; struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[] = { @@ -193,6 +207,11 @@ const u8 acpi_gbl_aml_resource_sizes[] = { sizeof(struct aml_resource_gpio), /* ACPI_RESOURCE_TYPE_GPIO */ sizeof(struct aml_resource_fixed_dma), /* ACPI_RESOURCE_TYPE_FIXED_DMA */ sizeof(struct aml_resource_common_serialbus), /* ACPI_RESOURCE_TYPE_SERIAL_BUS */ + sizeof(struct aml_resource_pin_function), /* ACPI_RESOURCE_TYPE_PIN_FUNCTION */ + sizeof(struct aml_resource_pin_config), /* ACPI_RESOURCE_TYPE_PIN_CONFIG */ + sizeof(struct aml_resource_pin_group), /* ACPI_RESOURCE_TYPE_PIN_GROUP */ + sizeof(struct aml_resource_pin_group_function), /* ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION */ + sizeof(struct aml_resource_pin_group_config), /* ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG */ }; const u8 acpi_gbl_resource_struct_sizes[] = { @@ -230,7 +249,12 @@ const u8 acpi_gbl_resource_struct_sizes[] = { ACPI_RS_SIZE(struct acpi_resource_address64), ACPI_RS_SIZE(struct acpi_resource_extended_address64), ACPI_RS_SIZE(struct acpi_resource_gpio), - ACPI_RS_SIZE(struct acpi_resource_common_serialbus) + ACPI_RS_SIZE(struct acpi_resource_pin_function), + ACPI_RS_SIZE(struct acpi_resource_common_serialbus), + ACPI_RS_SIZE(struct acpi_resource_pin_config), + ACPI_RS_SIZE(struct acpi_resource_pin_group), + ACPI_RS_SIZE(struct acpi_resource_pin_group_function), + ACPI_RS_SIZE(struct acpi_resource_pin_group_config), }; const u8 acpi_gbl_aml_resource_serial_bus_sizes[] = { diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index 2ae79613f6b7..cc4b5486c4bc 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -596,9 +596,7 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, /* Set vendor offset only if there is vendor data */ - if (resource->data.gpio.vendor_length) { - ACPI_SET16(target, aml_length); - } + ACPI_SET16(target, aml_length); acpi_rs_set_resource_length(aml_length, aml); break; diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c index c20e6d07928d..14d12d6eb716 100644 --- a/drivers/acpi/acpica/rsserial.c +++ b/drivers/acpi/acpica/rsserial.c @@ -147,6 +147,82 @@ struct acpi_rsconvert_info acpi_rs_convert_gpio[18] = { /******************************************************************************* * + * acpi_rs_convert_pinfunction + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_pin_function[13] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_PIN_FUNCTION, + ACPI_RS_SIZE(struct acpi_resource_pin_function), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_pin_function)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_PIN_FUNCTION, + sizeof(struct aml_resource_pin_function), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_function.revision_id), + AML_OFFSET(pin_function.revision_id), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.pin_function.sharable), + AML_OFFSET(pin_function.flags), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_function.pin_config), + AML_OFFSET(pin_function.pin_config), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.pin_function.function_number), + AML_OFFSET(pin_function.function_number), + 2}, + + /* Pin Table */ + + /* + * It is OK to use GPIO operations here because none of them refer GPIO + * structures directly but instead use offsets given here. + */ + + {ACPI_RSC_COUNT_GPIO_PIN, + ACPI_RS_OFFSET(data.pin_function.pin_table_length), + AML_OFFSET(pin_function.pin_table_offset), + AML_OFFSET(pin_function.res_source_offset)}, + + {ACPI_RSC_MOVE_GPIO_PIN, ACPI_RS_OFFSET(data.pin_function.pin_table), + AML_OFFSET(pin_function.pin_table_offset), + 0}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.pin_function.resource_source.index), + AML_OFFSET(pin_function.res_source_index), + 1}, + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.pin_function.resource_source.string_length), + AML_OFFSET(pin_function.res_source_offset), + AML_OFFSET(pin_function.vendor_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_function.resource_source.string_ptr), + AML_OFFSET(pin_function.res_source_offset), + 0}, + + /* Vendor Data */ + + {ACPI_RSC_COUNT_GPIO_VEN, + ACPI_RS_OFFSET(data.pin_function.vendor_length), + AML_OFFSET(pin_function.vendor_length), + 1}, + + {ACPI_RSC_MOVE_GPIO_RES, ACPI_RS_OFFSET(data.pin_function.vendor_data), + AML_OFFSET(pin_function.vendor_offset), + 0}, +}; + +/******************************************************************************* + * * acpi_rs_convert_i2c_serial_bus * ******************************************************************************/ @@ -458,3 +534,300 @@ struct acpi_rsconvert_info acpi_rs_convert_uart_serial_bus[23] = { AML_OFFSET(uart_serial_bus.default_baud_rate), 1}, }; + +/******************************************************************************* + * + * acpi_rs_convert_pin_config + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_pin_config[14] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_PIN_CONFIG, + ACPI_RS_SIZE(struct acpi_resource_pin_config), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_pin_config)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_PIN_CONFIG, + sizeof(struct aml_resource_pin_config), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_config.revision_id), + AML_OFFSET(pin_config.revision_id), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.pin_config.sharable), + AML_OFFSET(pin_config.flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.pin_config.producer_consumer), + AML_OFFSET(pin_config.flags), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_config.pin_config_type), + AML_OFFSET(pin_config.pin_config_type), + 1}, + + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.pin_config.pin_config_value), + AML_OFFSET(pin_config.pin_config_value), + 1}, + + /* Pin Table */ + + /* + * It is OK to use GPIO operations here because none of them refer GPIO + * structures directly but instead use offsets given here. + */ + + {ACPI_RSC_COUNT_GPIO_PIN, + ACPI_RS_OFFSET(data.pin_config.pin_table_length), + AML_OFFSET(pin_config.pin_table_offset), + AML_OFFSET(pin_config.res_source_offset)}, + + {ACPI_RSC_MOVE_GPIO_PIN, ACPI_RS_OFFSET(data.pin_config.pin_table), + AML_OFFSET(pin_config.pin_table_offset), + 0}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_config.resource_source.index), + AML_OFFSET(pin_config.res_source_index), + 1}, + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.pin_config.resource_source.string_length), + AML_OFFSET(pin_config.res_source_offset), + AML_OFFSET(pin_config.vendor_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_config.resource_source.string_ptr), + AML_OFFSET(pin_config.res_source_offset), + 0}, + + /* Vendor Data */ + + {ACPI_RSC_COUNT_GPIO_VEN, ACPI_RS_OFFSET(data.pin_config.vendor_length), + AML_OFFSET(pin_config.vendor_length), + 1}, + + {ACPI_RSC_MOVE_GPIO_RES, ACPI_RS_OFFSET(data.pin_config.vendor_data), + AML_OFFSET(pin_config.vendor_offset), + 0}, +}; + +/******************************************************************************* + * + * acpi_rs_convert_pin_group + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_pin_group[10] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_PIN_GROUP, + ACPI_RS_SIZE(struct acpi_resource_pin_group), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_pin_group)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_PIN_GROUP, + sizeof(struct aml_resource_pin_group), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_group.revision_id), + AML_OFFSET(pin_group.revision_id), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.pin_group.producer_consumer), + AML_OFFSET(pin_group.flags), + 0}, + + /* Pin Table */ + + /* + * It is OK to use GPIO operations here because none of them refer GPIO + * structures directly but instead use offsets given here. + */ + + {ACPI_RSC_COUNT_GPIO_PIN, + ACPI_RS_OFFSET(data.pin_group.pin_table_length), + AML_OFFSET(pin_group.pin_table_offset), + AML_OFFSET(pin_group.label_offset)}, + + {ACPI_RSC_MOVE_GPIO_PIN, ACPI_RS_OFFSET(data.pin_group.pin_table), + AML_OFFSET(pin_group.pin_table_offset), + 0}, + + /* Resource Label */ + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group.resource_label.string_length), + AML_OFFSET(pin_group.label_offset), + AML_OFFSET(pin_group.vendor_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group.resource_label.string_ptr), + AML_OFFSET(pin_group.label_offset), + 0}, + + /* Vendor Data */ + + {ACPI_RSC_COUNT_GPIO_VEN, ACPI_RS_OFFSET(data.pin_group.vendor_length), + AML_OFFSET(pin_group.vendor_length), + 1}, + + {ACPI_RSC_MOVE_GPIO_RES, ACPI_RS_OFFSET(data.pin_group.vendor_data), + AML_OFFSET(pin_group.vendor_offset), + 0}, +}; + +/******************************************************************************* + * + * acpi_rs_convert_pin_group_function + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_pin_group_function[13] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION, + ACPI_RS_SIZE(struct acpi_resource_pin_group_function), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_pin_group_function)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_PIN_GROUP_FUNCTION, + sizeof(struct aml_resource_pin_group_function), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_group_function.revision_id), + AML_OFFSET(pin_group_function.revision_id), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.pin_group_function.sharable), + AML_OFFSET(pin_group_function.flags), + 0}, + + {ACPI_RSC_1BITFLAG, + ACPI_RS_OFFSET(data.pin_group_function.producer_consumer), + AML_OFFSET(pin_group_function.flags), + 1}, + + {ACPI_RSC_MOVE16, + ACPI_RS_OFFSET(data.pin_group_function.function_number), + AML_OFFSET(pin_group_function.function_number), + 1}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.pin_group_function.resource_source.index), + AML_OFFSET(pin_group_function.res_source_index), + 1}, + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_function.resource_source.string_length), + AML_OFFSET(pin_group_function.res_source_offset), + AML_OFFSET(pin_group_function.res_source_label_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_function.resource_source.string_ptr), + AML_OFFSET(pin_group_function.res_source_offset), + 0}, + + /* Resource Source Label */ + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_function.resource_source_label. + string_length), + AML_OFFSET(pin_group_function.res_source_label_offset), + AML_OFFSET(pin_group_function.vendor_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_function.resource_source_label. + string_ptr), + AML_OFFSET(pin_group_function.res_source_label_offset), + 0}, + + /* Vendor Data */ + + {ACPI_RSC_COUNT_GPIO_VEN, + ACPI_RS_OFFSET(data.pin_group_function.vendor_length), + AML_OFFSET(pin_group_function.vendor_length), + 1}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_function.vendor_data), + AML_OFFSET(pin_group_function.vendor_offset), + 0}, +}; + +/******************************************************************************* + * + * acpi_rs_convert_pin_group_config + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_pin_group_config[14] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG, + ACPI_RS_SIZE(struct acpi_resource_pin_group_config), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_pin_group_config)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_PIN_GROUP_CONFIG, + sizeof(struct aml_resource_pin_group_config), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_group_config.revision_id), + AML_OFFSET(pin_group_config.revision_id), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.pin_group_config.sharable), + AML_OFFSET(pin_group_config.flags), + 0}, + + {ACPI_RSC_1BITFLAG, + ACPI_RS_OFFSET(data.pin_group_config.producer_consumer), + AML_OFFSET(pin_group_config.flags), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.pin_group_config.pin_config_type), + AML_OFFSET(pin_group_config.pin_config_type), + 1}, + + {ACPI_RSC_MOVE32, + ACPI_RS_OFFSET(data.pin_group_config.pin_config_value), + AML_OFFSET(pin_group_config.pin_config_value), + 1}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.pin_group_config.resource_source.index), + AML_OFFSET(pin_group_config.res_source_index), + 1}, + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_config.resource_source.string_length), + AML_OFFSET(pin_group_config.res_source_offset), + AML_OFFSET(pin_group_config.res_source_label_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_config.resource_source.string_ptr), + AML_OFFSET(pin_group_config.res_source_offset), + 0}, + + /* Resource Source Label */ + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_config.resource_source_label. + string_length), + AML_OFFSET(pin_group_config.res_source_label_offset), + AML_OFFSET(pin_group_config.vendor_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_config.resource_source_label.string_ptr), + AML_OFFSET(pin_group_config.res_source_label_offset), + 0}, + + /* Vendor Data */ + + {ACPI_RSC_COUNT_GPIO_VEN, + ACPI_RS_OFFSET(data.pin_group_config.vendor_length), + AML_OFFSET(pin_group_config.vendor_length), + 1}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.pin_group_config.vendor_data), + AML_OFFSET(pin_group_config.vendor_offset), + 0}, +}; diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index 27c5c27d4818..c9d6fa6d7cc6 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -867,6 +867,8 @@ exit: return_ACPI_STATUS(status); } +ACPI_EXPORT_SYMBOL(acpi_tb_install_and_load_table) + /******************************************************************************* * * FUNCTION: acpi_tb_unload_table @@ -914,3 +916,5 @@ acpi_status acpi_tb_unload_table(u32 table_index) acpi_tb_set_table_loaded_flag(table_index, FALSE); return_ACPI_STATUS(status); } + +ACPI_EXPORT_SYMBOL(acpi_tb_unload_table) diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 51860bfc111e..5f051d82188d 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -449,8 +449,8 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) * The 64-bit X fields are optional extensions to the original 32-bit FADT * V1.0 fields. Even if they are present in the FADT, they are optional and * are unused if the BIOS sets them to zero. Therefore, we must copy/expand - * 32-bit V1.0 fields to the 64-bit X fields if the the 64-bit X field is - * originally zero. + * 32-bit V1.0 fields to the 64-bit X fields if the 64-bit X field is originally + * zero. * * For ACPI 1.0 FADTs (that contain no 64-bit addresses), all 32-bit address * fields are expanded to the corresponding 64-bit X fields in the internal diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 0d2e98920069..0c6768d20395 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -141,9 +141,9 @@ void acpi_tb_check_dsdt_header(void) * * FUNCTION: acpi_tb_copy_dsdt * - * PARAMETERS: table_desc - Installed table to copy + * PARAMETERS: table_index - Index of installed table to copy * - * RETURN: None + * RETURN: The copied DSDT * * DESCRIPTION: Implements a subsystem option to copy the DSDT to local memory. * Some very bad BIOSs are known to either corrupt the DSDT or @@ -239,7 +239,7 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size) * * FUNCTION: acpi_tb_parse_root_table * - * PARAMETERS: rsdp - Pointer to the RSDP + * PARAMETERS: rsdp_address - Pointer to the RSDP * * RETURN: Status * diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index 60868309e326..02cd2c2d961a 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -460,9 +460,11 @@ static const char *acpi_gbl_generic_notify[ACPI_GENERIC_NOTIFY_MAX + 1] = { /* 09 */ "Device PLD Check", /* 0A */ "Reserved", /* 0B */ "System Locality Update", - /* 0C */ "Shutdown Request", - /* Reserved in ACPI 6.0 */ - /* 0D */ "System Resource Affinity Update" + /* 0C */ "Reserved (was previously Shutdown Request)", + /* Reserved in ACPI 6.0 */ + /* 0D */ "System Resource Affinity Update", + /* 0E */ "Heterogeneous Memory Attributes Update" + /* ACPI 6.2 */ }; static const char *acpi_gbl_device_notify[5] = { diff --git a/drivers/acpi/acpica/utownerid.c b/drivers/acpi/acpica/utownerid.c index c82399f9b456..1b3ee74a87eb 100644 --- a/drivers/acpi/acpica/utownerid.c +++ b/drivers/acpi/acpica/utownerid.c @@ -104,13 +104,19 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id *owner_id) break; } - if (!(acpi_gbl_owner_id_mask[j] & (1 << k))) { + /* + * Note: the u32 cast ensures that 1 is stored as a unsigned + * integer. Omitting the cast may result in 1 being stored as an + * int. Some compilers or runtime error detection may flag this as + * an error. + */ + if (!(acpi_gbl_owner_id_mask[j] & ((u32)1 << k))) { /* * Found a free ID. The actual ID is the bit index plus one, * making zero an invalid Owner ID. Save this as the last ID * allocated and update the global ID mask. */ - acpi_gbl_owner_id_mask[j] |= (1 << k); + acpi_gbl_owner_id_mask[j] |= ((u32)1 << k); acpi_gbl_last_owner_id_index = (u8)j; acpi_gbl_next_owner_id_offset = (u8)(k + 1); @@ -201,7 +207,7 @@ void acpi_ut_release_owner_id(acpi_owner_id *owner_id_ptr) /* Decode ID to index/offset pair */ index = ACPI_DIV_32(owner_id); - bit = 1 << ACPI_MOD_32(owner_id); + bit = (u32)1 << ACPI_MOD_32(owner_id); /* Free the owner ID only if it is valid */ diff --git a/drivers/acpi/acpica/utresdecode.c b/drivers/acpi/acpica/utresdecode.c new file mode 100644 index 000000000000..e15a2538558b --- /dev/null +++ b/drivers/acpi/acpica/utresdecode.c @@ -0,0 +1,315 @@ +/******************************************************************************* + * + * Module Name: utresdecode - Resource descriptor keyword strings + * + ******************************************************************************/ + +/* + * 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 <acpi/acpi.h> +#include "accommon.h" +#include "acresrc.h" + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("utresdecode") + +#if defined (ACPI_DEBUG_OUTPUT) || \ + defined (ACPI_DISASSEMBLER) || \ + defined (ACPI_DEBUGGER) +/* + * Strings used to decode resource descriptors. + * Used by both the disassembler and the debugger resource dump routines + */ +const char *acpi_gbl_bm_decode[] = { + "NotBusMaster", + "BusMaster" +}; + +const char *acpi_gbl_config_decode[] = { + "0 - Good Configuration", + "1 - Acceptable Configuration", + "2 - Suboptimal Configuration", + "3 - ***Invalid Configuration***", +}; + +const char *acpi_gbl_consume_decode[] = { + "ResourceProducer", + "ResourceConsumer" +}; + +const char *acpi_gbl_dec_decode[] = { + "PosDecode", + "SubDecode" +}; + +const char *acpi_gbl_he_decode[] = { + "Level", + "Edge" +}; + +const char *acpi_gbl_io_decode[] = { + "Decode10", + "Decode16" +}; + +const char *acpi_gbl_ll_decode[] = { + "ActiveHigh", + "ActiveLow", + "ActiveBoth", + "Reserved" +}; + +const char *acpi_gbl_max_decode[] = { + "MaxNotFixed", + "MaxFixed" +}; + +const char *acpi_gbl_mem_decode[] = { + "NonCacheable", + "Cacheable", + "WriteCombining", + "Prefetchable" +}; + +const char *acpi_gbl_min_decode[] = { + "MinNotFixed", + "MinFixed" +}; + +const char *acpi_gbl_mtp_decode[] = { + "AddressRangeMemory", + "AddressRangeReserved", + "AddressRangeACPI", + "AddressRangeNVS" +}; + +const char *acpi_gbl_rng_decode[] = { + "InvalidRanges", + "NonISAOnlyRanges", + "ISAOnlyRanges", + "EntireRange" +}; + +const char *acpi_gbl_rw_decode[] = { + "ReadOnly", + "ReadWrite" +}; + +const char *acpi_gbl_shr_decode[] = { + "Exclusive", + "Shared", + "ExclusiveAndWake", /* ACPI 5.0 */ + "SharedAndWake" /* ACPI 5.0 */ +}; + +const char *acpi_gbl_siz_decode[] = { + "Transfer8", + "Transfer8_16", + "Transfer16", + "InvalidSize" +}; + +const char *acpi_gbl_trs_decode[] = { + "DenseTranslation", + "SparseTranslation" +}; + +const char *acpi_gbl_ttp_decode[] = { + "TypeStatic", + "TypeTranslation" +}; + +const char *acpi_gbl_typ_decode[] = { + "Compatibility", + "TypeA", + "TypeB", + "TypeF" +}; + +const char *acpi_gbl_ppc_decode[] = { + "PullDefault", + "PullUp", + "PullDown", + "PullNone" +}; + +const char *acpi_gbl_ior_decode[] = { + "IoRestrictionNone", + "IoRestrictionInputOnly", + "IoRestrictionOutputOnly", + "IoRestrictionNoneAndPreserve" +}; + +const char *acpi_gbl_dts_decode[] = { + "Width8bit", + "Width16bit", + "Width32bit", + "Width64bit", + "Width128bit", + "Width256bit", +}; + +/* GPIO connection type */ + +const char *acpi_gbl_ct_decode[] = { + "Interrupt", + "I/O" +}; + +/* Serial bus type */ + +const char *acpi_gbl_sbt_decode[] = { + "/* UNKNOWN serial bus type */", + "I2C", + "SPI", + "UART" +}; + +/* I2C serial bus access mode */ + +const char *acpi_gbl_am_decode[] = { + "AddressingMode7Bit", + "AddressingMode10Bit" +}; + +/* I2C serial bus slave mode */ + +const char *acpi_gbl_sm_decode[] = { + "ControllerInitiated", + "DeviceInitiated" +}; + +/* SPI serial bus wire mode */ + +const char *acpi_gbl_wm_decode[] = { + "FourWireMode", + "ThreeWireMode" +}; + +/* SPI serial clock phase */ + +const char *acpi_gbl_cph_decode[] = { + "ClockPhaseFirst", + "ClockPhaseSecond" +}; + +/* SPI serial bus clock polarity */ + +const char *acpi_gbl_cpo_decode[] = { + "ClockPolarityLow", + "ClockPolarityHigh" +}; + +/* SPI serial bus device polarity */ + +const char *acpi_gbl_dp_decode[] = { + "PolarityLow", + "PolarityHigh" +}; + +/* UART serial bus endian */ + +const char *acpi_gbl_ed_decode[] = { + "LittleEndian", + "BigEndian" +}; + +/* UART serial bus bits per byte */ + +const char *acpi_gbl_bpb_decode[] = { + "DataBitsFive", + "DataBitsSix", + "DataBitsSeven", + "DataBitsEight", + "DataBitsNine", + "/* UNKNOWN Bits per byte */", + "/* UNKNOWN Bits per byte */", + "/* UNKNOWN Bits per byte */" +}; + +/* UART serial bus stop bits */ + +const char *acpi_gbl_sb_decode[] = { + "StopBitsZero", + "StopBitsOne", + "StopBitsOnePlusHalf", + "StopBitsTwo" +}; + +/* UART serial bus flow control */ + +const char *acpi_gbl_fc_decode[] = { + "FlowControlNone", + "FlowControlHardware", + "FlowControlXON", + "/* UNKNOWN flow control keyword */" +}; + +/* UART serial bus parity type */ + +const char *acpi_gbl_pt_decode[] = { + "ParityTypeNone", + "ParityTypeEven", + "ParityTypeOdd", + "ParityTypeMark", + "ParityTypeSpace", + "/* UNKNOWN parity keyword */", + "/* UNKNOWN parity keyword */", + "/* UNKNOWN parity keyword */" +}; + +/* pin_config type */ + +const char *acpi_gbl_ptyp_decode[] = { + "Default", + "Bias Pull-up", + "Bias Pull-down", + "Bias Default", + "Bias Disable", + "Bias High Impedance", + "Bias Bus Hold", + "Drive Open Drain", + "Drive Open Source", + "Drive Push Pull", + "Drive Strength", + "Slew Rate", + "Input Debounce", + "Input Schmitt Trigger", +}; + +#endif diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index ff096d9755b9..70f78a4bf13b 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -48,251 +48,6 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utresrc") -#if defined(ACPI_DEBUG_OUTPUT) || defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER) -/* - * Strings used to decode resource descriptors. - * Used by both the disassembler and the debugger resource dump routines - */ -const char *acpi_gbl_bm_decode[] = { - "NotBusMaster", - "BusMaster" -}; - -const char *acpi_gbl_config_decode[] = { - "0 - Good Configuration", - "1 - Acceptable Configuration", - "2 - Suboptimal Configuration", - "3 - ***Invalid Configuration***", -}; - -const char *acpi_gbl_consume_decode[] = { - "ResourceProducer", - "ResourceConsumer" -}; - -const char *acpi_gbl_dec_decode[] = { - "PosDecode", - "SubDecode" -}; - -const char *acpi_gbl_he_decode[] = { - "Level", - "Edge" -}; - -const char *acpi_gbl_io_decode[] = { - "Decode10", - "Decode16" -}; - -const char *acpi_gbl_ll_decode[] = { - "ActiveHigh", - "ActiveLow", - "ActiveBoth", - "Reserved" -}; - -const char *acpi_gbl_max_decode[] = { - "MaxNotFixed", - "MaxFixed" -}; - -const char *acpi_gbl_mem_decode[] = { - "NonCacheable", - "Cacheable", - "WriteCombining", - "Prefetchable" -}; - -const char *acpi_gbl_min_decode[] = { - "MinNotFixed", - "MinFixed" -}; - -const char *acpi_gbl_mtp_decode[] = { - "AddressRangeMemory", - "AddressRangeReserved", - "AddressRangeACPI", - "AddressRangeNVS" -}; - -const char *acpi_gbl_rng_decode[] = { - "InvalidRanges", - "NonISAOnlyRanges", - "ISAOnlyRanges", - "EntireRange" -}; - -const char *acpi_gbl_rw_decode[] = { - "ReadOnly", - "ReadWrite" -}; - -const char *acpi_gbl_shr_decode[] = { - "Exclusive", - "Shared", - "ExclusiveAndWake", /* ACPI 5.0 */ - "SharedAndWake" /* ACPI 5.0 */ -}; - -const char *acpi_gbl_siz_decode[] = { - "Transfer8", - "Transfer8_16", - "Transfer16", - "InvalidSize" -}; - -const char *acpi_gbl_trs_decode[] = { - "DenseTranslation", - "SparseTranslation" -}; - -const char *acpi_gbl_ttp_decode[] = { - "TypeStatic", - "TypeTranslation" -}; - -const char *acpi_gbl_typ_decode[] = { - "Compatibility", - "TypeA", - "TypeB", - "TypeF" -}; - -const char *acpi_gbl_ppc_decode[] = { - "PullDefault", - "PullUp", - "PullDown", - "PullNone" -}; - -const char *acpi_gbl_ior_decode[] = { - "IoRestrictionNone", - "IoRestrictionInputOnly", - "IoRestrictionOutputOnly", - "IoRestrictionNoneAndPreserve" -}; - -const char *acpi_gbl_dts_decode[] = { - "Width8bit", - "Width16bit", - "Width32bit", - "Width64bit", - "Width128bit", - "Width256bit", -}; - -/* GPIO connection type */ - -const char *acpi_gbl_ct_decode[] = { - "Interrupt", - "I/O" -}; - -/* Serial bus type */ - -const char *acpi_gbl_sbt_decode[] = { - "/* UNKNOWN serial bus type */", - "I2C", - "SPI", - "UART" -}; - -/* I2C serial bus access mode */ - -const char *acpi_gbl_am_decode[] = { - "AddressingMode7Bit", - "AddressingMode10Bit" -}; - -/* I2C serial bus slave mode */ - -const char *acpi_gbl_sm_decode[] = { - "ControllerInitiated", - "DeviceInitiated" -}; - -/* SPI serial bus wire mode */ - -const char *acpi_gbl_wm_decode[] = { - "FourWireMode", - "ThreeWireMode" -}; - -/* SPI serial clock phase */ - -const char *acpi_gbl_cph_decode[] = { - "ClockPhaseFirst", - "ClockPhaseSecond" -}; - -/* SPI serial bus clock polarity */ - -const char *acpi_gbl_cpo_decode[] = { - "ClockPolarityLow", - "ClockPolarityHigh" -}; - -/* SPI serial bus device polarity */ - -const char *acpi_gbl_dp_decode[] = { - "PolarityLow", - "PolarityHigh" -}; - -/* UART serial bus endian */ - -const char *acpi_gbl_ed_decode[] = { - "LittleEndian", - "BigEndian" -}; - -/* UART serial bus bits per byte */ - -const char *acpi_gbl_bpb_decode[] = { - "DataBitsFive", - "DataBitsSix", - "DataBitsSeven", - "DataBitsEight", - "DataBitsNine", - "/* UNKNOWN Bits per byte */", - "/* UNKNOWN Bits per byte */", - "/* UNKNOWN Bits per byte */" -}; - -/* UART serial bus stop bits */ - -const char *acpi_gbl_sb_decode[] = { - "StopBitsZero", - "StopBitsOne", - "StopBitsOnePlusHalf", - "StopBitsTwo" -}; - -/* UART serial bus flow control */ - -const char *acpi_gbl_fc_decode[] = { - "FlowControlNone", - "FlowControlHardware", - "FlowControlXON", - "/* UNKNOWN flow control keyword */" -}; - -/* UART serial bus parity type */ - -const char *acpi_gbl_pt_decode[] = { - "ParityTypeNone", - "ParityTypeEven", - "ParityTypeOdd", - "ParityTypeMark", - "ParityTypeSpace", - "/* UNKNOWN parity keyword */", - "/* UNKNOWN parity keyword */", - "/* UNKNOWN parity keyword */" -}; - -#endif - /* * Base sizes of the raw AML resource descriptors, indexed by resource type. * Zero indicates a reserved (and therefore invalid) resource type. @@ -332,8 +87,12 @@ const u8 acpi_gbl_resource_aml_sizes[] = { ACPI_AML_SIZE_LARGE(struct aml_resource_address64), ACPI_AML_SIZE_LARGE(struct aml_resource_extended_address64), ACPI_AML_SIZE_LARGE(struct aml_resource_gpio), - 0, + ACPI_AML_SIZE_LARGE(struct aml_resource_pin_function), ACPI_AML_SIZE_LARGE(struct aml_resource_common_serialbus), + ACPI_AML_SIZE_LARGE(struct aml_resource_pin_config), + ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group), + ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group_function), + ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group_config), }; const u8 acpi_gbl_resource_aml_serial_bus_sizes[] = { @@ -384,8 +143,12 @@ static const u8 acpi_gbl_resource_types[] = { ACPI_VARIABLE_LENGTH, /* 0A Qword* address */ ACPI_FIXED_LENGTH, /* 0B Extended* address */ ACPI_VARIABLE_LENGTH, /* 0C Gpio* */ - 0, - ACPI_VARIABLE_LENGTH /* 0E *serial_bus */ + ACPI_VARIABLE_LENGTH, /* 0D pin_function */ + ACPI_VARIABLE_LENGTH, /* 0E *serial_bus */ + ACPI_VARIABLE_LENGTH, /* 0F pin_config */ + ACPI_VARIABLE_LENGTH, /* 10 pin_group */ + ACPI_VARIABLE_LENGTH, /* 11 pin_group_function */ + ACPI_VARIABLE_LENGTH, /* 12 pin_group_config */ }; /******************************************************************************* diff --git a/drivers/acpi/acpica/utxfmutex.c b/drivers/acpi/acpica/utxfmutex.c index c016211c35ae..0b85f113f726 100644 --- a/drivers/acpi/acpica/utxfmutex.c +++ b/drivers/acpi/acpica/utxfmutex.c @@ -151,6 +151,8 @@ acpi_acquire_mutex(acpi_handle handle, acpi_string pathname, u16 timeout) return (status); } +ACPI_EXPORT_SYMBOL(acpi_acquire_mutex) + /******************************************************************************* * * FUNCTION: acpi_release_mutex @@ -167,7 +169,6 @@ acpi_acquire_mutex(acpi_handle handle, acpi_string pathname, u16 timeout) * not both. * ******************************************************************************/ - acpi_status acpi_release_mutex(acpi_handle handle, acpi_string pathname) { acpi_status status; @@ -185,3 +186,5 @@ acpi_status acpi_release_mutex(acpi_handle handle, acpi_string pathname) acpi_os_release_mutex(mutex_obj->mutex.os_mutex); return (AE_OK); } + +ACPI_EXPORT_SYMBOL(acpi_release_mutex) diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index b0140c8fc733..de14d49a5c90 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig @@ -39,6 +39,21 @@ config ACPI_APEI_PCIEAER PCIe AER errors may be reported via APEI firmware first mode. Turn on this option to enable the corresponding support. +config ACPI_APEI_SEA + bool "APEI Synchronous External Abort logging/recovering support" + depends on ARM64 && ACPI_APEI_GHES + default y + help + This option should be enabled if the system supports + firmware first handling of SEA (Synchronous External Abort). + SEA happens with certain faults of data abort or instruction + abort synchronous exceptions on ARMv8 systems. If a system + supports firmware first handling of SEA, the platform analyzes + and handles hardware error notifications from SEA, and it may then + form a HW error record for the OS to parse and handle. This + option allows the OS to look for such hardware error record, and + take appropriate action. + config ACPI_APEI_MEMORY_FAILURE bool "APEI memory error recovering support" depends on ACPI_APEI && MEMORY_FAILURE diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index d0855c09f32f..d661d452b238 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -45,10 +45,14 @@ #include <linux/aer.h> #include <linux/nmi.h> #include <linux/sched/clock.h> +#include <linux/uuid.h> +#include <linux/ras.h> +#include <acpi/actbl1.h> #include <acpi/ghes.h> #include <acpi/apei.h> #include <asm/tlbflush.h> +#include <ras/ras_event.h> #include "apei-internal.h" @@ -80,6 +84,11 @@ ((struct acpi_hest_generic_status *) \ ((struct ghes_estatus_node *)(estatus_node) + 1)) +static inline bool is_hest_type_generic_v2(struct ghes *ghes) +{ + return ghes->generic->header.type == ACPI_HEST_TYPE_GENERIC_ERROR_V2; +} + /* * This driver isn't really modular, however for the time being, * continuing to use module_param is the easiest way to remain @@ -89,14 +98,14 @@ bool ghes_disable; module_param_named(disable, ghes_disable, bool, 0); /* - * All error sources notified with SCI shares one notifier function, - * so they need to be linked and checked one by one. This is applied - * to NMI too. + * All error sources notified with HED (Hardware Error Device) share a + * single notifier callback, so they need to be linked and checked one + * by one. This holds true for NMI too. * * RCU is used for these lists, so ghes_list_mutex is only used for * list changing, not for traversing. */ -static LIST_HEAD(ghes_sci); +static LIST_HEAD(ghes_hed); static DEFINE_MUTEX(ghes_list_mutex); /* @@ -110,11 +119,7 @@ static DEFINE_MUTEX(ghes_list_mutex); * Two virtual pages are used, one for IRQ/PROCESS context, the other for * NMI context (optionally). */ -#ifdef CONFIG_HAVE_ACPI_APEI_NMI #define GHES_IOREMAP_PAGES 2 -#else -#define GHES_IOREMAP_PAGES 1 -#endif #define GHES_IOREMAP_IRQ_PAGE(base) (base) #define GHES_IOREMAP_NMI_PAGE(base) ((base) + PAGE_SIZE) @@ -133,6 +138,8 @@ static unsigned long ghes_estatus_pool_size_request; static struct ghes_estatus_cache *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE]; static atomic_t ghes_estatus_cache_alloced; +static int ghes_panic_timeout __read_mostly = 30; + static int ghes_ioremap_init(void) { ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES, @@ -153,10 +160,14 @@ static void ghes_ioremap_exit(void) static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn) { unsigned long vaddr; + phys_addr_t paddr; + pgprot_t prot; vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr); - ioremap_page_range(vaddr, vaddr + PAGE_SIZE, - pfn << PAGE_SHIFT, PAGE_KERNEL); + + paddr = pfn << PAGE_SHIFT; + prot = arch_apei_get_mem_attribute(paddr); + ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot); return (void __iomem *)vaddr; } @@ -240,6 +251,16 @@ static int ghes_estatus_pool_expand(unsigned long len) return 0; } +static int map_gen_v2(struct ghes *ghes) +{ + return apei_map_generic_address(&ghes->generic_v2->read_ack_register); +} + +static void unmap_gen_v2(struct ghes *ghes) +{ + apei_unmap_generic_address(&ghes->generic_v2->read_ack_register); +} + static struct ghes *ghes_new(struct acpi_hest_generic *generic) { struct ghes *ghes; @@ -249,10 +270,17 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) ghes = kzalloc(sizeof(*ghes), GFP_KERNEL); if (!ghes) return ERR_PTR(-ENOMEM); + ghes->generic = generic; + if (is_hest_type_generic_v2(ghes)) { + rc = map_gen_v2(ghes); + if (rc) + goto err_free; + } + rc = apei_map_generic_address(&generic->error_status_address); if (rc) - goto err_free; + goto err_unmap_read_ack_addr; error_block_length = generic->error_block_length; if (error_block_length > GHES_ESTATUS_MAX_SIZE) { pr_warning(FW_WARN GHES_PFX @@ -264,13 +292,16 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) ghes->estatus = kmalloc(error_block_length, GFP_KERNEL); if (!ghes->estatus) { rc = -ENOMEM; - goto err_unmap; + goto err_unmap_status_addr; } return ghes; -err_unmap: +err_unmap_status_addr: apei_unmap_generic_address(&generic->error_status_address); +err_unmap_read_ack_addr: + if (is_hest_type_generic_v2(ghes)) + unmap_gen_v2(ghes); err_free: kfree(ghes); return ERR_PTR(rc); @@ -280,6 +311,8 @@ static void ghes_fini(struct ghes *ghes) { kfree(ghes->estatus); apei_unmap_generic_address(&ghes->generic->error_status_address); + if (is_hest_type_generic_v2(ghes)) + unmap_gen_v2(ghes); } static inline int ghes_severity(int severity) @@ -400,8 +433,7 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int unsigned long pfn; int flags = -1; int sec_sev = ghes_severity(gdata->error_severity); - struct cper_sec_mem_err *mem_err; - mem_err = (struct cper_sec_mem_err *)(gdata + 1); + struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata); if (!(mem_err->validation_bits & CPER_MEM_VALID_PA)) return; @@ -431,24 +463,32 @@ static void ghes_do_proc(struct ghes *ghes, { int sev, sec_sev; struct acpi_hest_generic_data *gdata; + guid_t *sec_type; + guid_t *fru_id = &NULL_UUID_LE; + char *fru_text = ""; sev = ghes_severity(estatus->error_severity); apei_estatus_for_each_section(estatus, gdata) { + sec_type = (guid_t *)gdata->section_type; sec_sev = ghes_severity(gdata->error_severity); - if (!uuid_le_cmp(*(uuid_le *)gdata->section_type, - CPER_SEC_PLATFORM_MEM)) { - struct cper_sec_mem_err *mem_err; - mem_err = (struct cper_sec_mem_err *)(gdata+1); + if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID) + fru_id = (guid_t *)gdata->fru_id; + + if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT) + fru_text = gdata->fru_text; + + if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) { + struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata); + ghes_edac_report_mem_error(ghes, sev, mem_err); arch_apei_report_mem_error(sev, mem_err); ghes_handle_memory_failure(gdata, sev); } #ifdef CONFIG_ACPI_APEI_PCIEAER - else if (!uuid_le_cmp(*(uuid_le *)gdata->section_type, - CPER_SEC_PCIE)) { - struct cper_sec_pcie *pcie_err; - pcie_err = (struct cper_sec_pcie *)(gdata+1); + else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { + struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata); + if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE && pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID && @@ -477,6 +517,17 @@ static void ghes_do_proc(struct ghes *ghes, } #endif + else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { + struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata); + + log_arm_hw_error(err); + } else { + void *err = acpi_hest_get_payload(gdata); + + log_non_standard_event(sec_type, fru_id, fru_text, + sec_sev, err, + gdata->error_data_length); + } } } @@ -649,6 +700,31 @@ static void ghes_estatus_cache_add( rcu_read_unlock(); } +static int ghes_ack_error(struct acpi_hest_generic_v2 *gv2) +{ + int rc; + u64 val = 0; + + rc = apei_read(&val, &gv2->read_ack_register); + if (rc) + return rc; + + val &= gv2->read_ack_preserve << gv2->read_ack_register.bit_offset; + val |= gv2->read_ack_write << gv2->read_ack_register.bit_offset; + + return apei_write(val, &gv2->read_ack_register); +} + +static void __ghes_panic(struct ghes *ghes) +{ + __ghes_print_estatus(KERN_EMERG, ghes->generic, ghes->estatus); + + /* reboot to log the error! */ + if (!panic_timeout) + panic_timeout = ghes_panic_timeout; + panic("Fatal hardware error!"); +} + static int ghes_proc(struct ghes *ghes) { int rc; @@ -656,11 +732,26 @@ static int ghes_proc(struct ghes *ghes) rc = ghes_read_estatus(ghes, 0); if (rc) goto out; + + if (ghes_severity(ghes->estatus->error_severity) >= GHES_SEV_PANIC) { + __ghes_panic(ghes); + } + if (!ghes_estatus_cached(ghes->estatus)) { if (ghes_print_estatus(NULL, ghes->generic, ghes->estatus)) ghes_estatus_cache_add(ghes->generic, ghes->estatus); } ghes_do_proc(ghes, ghes->estatus); + + /* + * GHESv2 type HEST entries introduce support for error acknowledgment, + * so only acknowledge the error if this support is present. + */ + if (is_hest_type_generic_v2(ghes)) { + rc = ghes_ack_error(ghes->generic_v2); + if (rc) + return rc; + } out: ghes_clear_estatus(ghes); return rc; @@ -702,14 +793,14 @@ static irqreturn_t ghes_irq_func(int irq, void *data) return IRQ_HANDLED; } -static int ghes_notify_sci(struct notifier_block *this, - unsigned long event, void *data) +static int ghes_notify_hed(struct notifier_block *this, unsigned long event, + void *data) { struct ghes *ghes; int ret = NOTIFY_DONE; rcu_read_lock(); - list_for_each_entry_rcu(ghes, &ghes_sci, list) { + list_for_each_entry_rcu(ghes, &ghes_hed, list) { if (!ghes_proc(ghes)) ret = NOTIFY_OK; } @@ -718,10 +809,59 @@ static int ghes_notify_sci(struct notifier_block *this, return ret; } -static struct notifier_block ghes_notifier_sci = { - .notifier_call = ghes_notify_sci, +static struct notifier_block ghes_notifier_hed = { + .notifier_call = ghes_notify_hed, }; +#ifdef CONFIG_ACPI_APEI_SEA +static LIST_HEAD(ghes_sea); + +/* + * Return 0 only if one of the SEA error sources successfully reported an error + * record sent from the firmware. + */ +int ghes_notify_sea(void) +{ + struct ghes *ghes; + int ret = -ENOENT; + + rcu_read_lock(); + list_for_each_entry_rcu(ghes, &ghes_sea, list) { + if (!ghes_proc(ghes)) + ret = 0; + } + rcu_read_unlock(); + return ret; +} + +static void ghes_sea_add(struct ghes *ghes) +{ + mutex_lock(&ghes_list_mutex); + list_add_rcu(&ghes->list, &ghes_sea); + mutex_unlock(&ghes_list_mutex); +} + +static void ghes_sea_remove(struct ghes *ghes) +{ + mutex_lock(&ghes_list_mutex); + list_del_rcu(&ghes->list); + mutex_unlock(&ghes_list_mutex); + synchronize_rcu(); +} +#else /* CONFIG_ACPI_APEI_SEA */ +static inline void ghes_sea_add(struct ghes *ghes) +{ + pr_err(GHES_PFX "ID: %d, trying to add SEA notification which is not supported\n", + ghes->generic->header.source_id); +} + +static inline void ghes_sea_remove(struct ghes *ghes) +{ + pr_err(GHES_PFX "ID: %d, trying to remove SEA notification which is not supported\n", + ghes->generic->header.source_id); +} +#endif /* CONFIG_ACPI_APEI_SEA */ + #ifdef CONFIG_HAVE_ACPI_APEI_NMI /* * printk is not safe in NMI context. So in NMI handler, we allocate @@ -742,8 +882,6 @@ static atomic_t ghes_in_nmi = ATOMIC_INIT(0); static LIST_HEAD(ghes_nmi); -static int ghes_panic_timeout __read_mostly = 30; - static void ghes_proc_in_irq(struct irq_work *irq_work) { struct llist_node *llnode, *next; @@ -829,18 +967,6 @@ static void __process_error(struct ghes *ghes) #endif } -static void __ghes_panic(struct ghes *ghes) -{ - oops_begin(); - ghes_print_queued_estatus(); - __ghes_print_estatus(KERN_EMERG, ghes->generic, ghes->estatus); - - /* reboot to log the error! */ - if (panic_timeout == 0) - panic_timeout = ghes_panic_timeout; - panic("Fatal hardware error!"); -} - static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) { struct ghes *ghes; @@ -858,8 +984,11 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) } sev = ghes_severity(ghes->estatus->error_severity); - if (sev >= GHES_SEV_PANIC) + if (sev >= GHES_SEV_PANIC) { + oops_begin(); + ghes_print_queued_estatus(); __ghes_panic(ghes); + } if (!(ghes->flags & GHES_TO_CLEAR)) continue; @@ -966,6 +1095,17 @@ static int ghes_probe(struct platform_device *ghes_dev) case ACPI_HEST_NOTIFY_POLLED: case ACPI_HEST_NOTIFY_EXTERNAL: case ACPI_HEST_NOTIFY_SCI: + case ACPI_HEST_NOTIFY_GSIV: + case ACPI_HEST_NOTIFY_GPIO: + break; + + case ACPI_HEST_NOTIFY_SEA: + if (!IS_ENABLED(CONFIG_ACPI_APEI_SEA)) { + pr_warn(GHES_PFX "Generic hardware error source: %d notified via SEA is not supported\n", + generic->header.source_id); + rc = -ENOTSUPP; + goto err; + } break; case ACPI_HEST_NOTIFY_NMI: if (!IS_ENABLED(CONFIG_HAVE_ACPI_APEI_NMI)) { @@ -1024,13 +1164,20 @@ static int ghes_probe(struct platform_device *ghes_dev) goto err_edac_unreg; } break; + case ACPI_HEST_NOTIFY_SCI: + case ACPI_HEST_NOTIFY_GSIV: + case ACPI_HEST_NOTIFY_GPIO: mutex_lock(&ghes_list_mutex); - if (list_empty(&ghes_sci)) - register_acpi_hed_notifier(&ghes_notifier_sci); - list_add_rcu(&ghes->list, &ghes_sci); + if (list_empty(&ghes_hed)) + register_acpi_hed_notifier(&ghes_notifier_hed); + list_add_rcu(&ghes->list, &ghes_hed); mutex_unlock(&ghes_list_mutex); break; + + case ACPI_HEST_NOTIFY_SEA: + ghes_sea_add(ghes); + break; case ACPI_HEST_NOTIFY_NMI: ghes_nmi_add(ghes); break; @@ -1039,6 +1186,9 @@ static int ghes_probe(struct platform_device *ghes_dev) } platform_set_drvdata(ghes_dev, ghes); + /* Handle any pending errors right away */ + ghes_proc(ghes); + return 0; err_edac_unreg: ghes_edac_unregister(ghes); @@ -1066,14 +1216,21 @@ static int ghes_remove(struct platform_device *ghes_dev) case ACPI_HEST_NOTIFY_EXTERNAL: free_irq(ghes->irq, ghes); break; + case ACPI_HEST_NOTIFY_SCI: + case ACPI_HEST_NOTIFY_GSIV: + case ACPI_HEST_NOTIFY_GPIO: mutex_lock(&ghes_list_mutex); list_del_rcu(&ghes->list); - if (list_empty(&ghes_sci)) - unregister_acpi_hed_notifier(&ghes_notifier_sci); + if (list_empty(&ghes_hed)) + unregister_acpi_hed_notifier(&ghes_notifier_hed); mutex_unlock(&ghes_list_mutex); synchronize_rcu(); break; + + case ACPI_HEST_NOTIFY_SEA: + ghes_sea_remove(ghes); + break; case ACPI_HEST_NOTIFY_NMI: ghes_nmi_remove(ghes); break; diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 8f2a98e23bba..456b488eb1df 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -52,6 +52,7 @@ static const int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = { [ACPI_HEST_TYPE_AER_ENDPOINT] = sizeof(struct acpi_hest_aer), [ACPI_HEST_TYPE_AER_BRIDGE] = sizeof(struct acpi_hest_aer_bridge), [ACPI_HEST_TYPE_GENERIC_ERROR] = sizeof(struct acpi_hest_generic), + [ACPI_HEST_TYPE_GENERIC_ERROR_V2] = sizeof(struct acpi_hest_generic_v2), }; static int hest_esrc_len(struct acpi_hest_header *hest_hdr) @@ -141,7 +142,8 @@ static int __init hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void { int *count = data; - if (hest_hdr->type == ACPI_HEST_TYPE_GENERIC_ERROR) + if (hest_hdr->type == ACPI_HEST_TYPE_GENERIC_ERROR || + hest_hdr->type == ACPI_HEST_TYPE_GENERIC_ERROR_V2) (*count)++; return 0; } @@ -152,7 +154,8 @@ static int __init hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data) struct ghes_arr *ghes_arr = data; int rc, i; - if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR) + if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR && + hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR_V2) return 0; if (!((struct acpi_hest_generic *)hest_hdr)->enabled) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 797b28dc7b34..a3215ee671c1 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -31,6 +31,11 @@ #define IORT_IOMMU_TYPE ((1 << ACPI_IORT_NODE_SMMU) | \ (1 << ACPI_IORT_NODE_SMMU_V3)) +/* Until ACPICA headers cover IORT rev. C */ +#ifndef ACPI_IORT_SMMU_V3_CAVIUM_CN99XX +#define ACPI_IORT_SMMU_V3_CAVIUM_CN99XX 0x2 +#endif + struct iort_its_msi_chip { struct list_head list; struct fwnode_handle *fw_node; @@ -234,21 +239,6 @@ static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type, return NULL; } -static acpi_status -iort_match_type_callback(struct acpi_iort_node *node, void *context) -{ - return AE_OK; -} - -bool iort_node_match(u8 type) -{ - struct acpi_iort_node *node; - - node = iort_scan_node(type, iort_match_type_callback, NULL); - - return node != NULL; -} - static acpi_status iort_match_node_callback(struct acpi_iort_node *node, void *context) { @@ -834,6 +824,36 @@ static int __init arm_smmu_v3_count_resources(struct acpi_iort_node *node) return num_res; } +static bool arm_smmu_v3_is_combined_irq(struct acpi_iort_smmu_v3 *smmu) +{ + /* + * Cavium ThunderX2 implementation doesn't not support unique + * irq line. Use single irq line for all the SMMUv3 interrupts. + */ + if (smmu->model != ACPI_IORT_SMMU_V3_CAVIUM_CN99XX) + return false; + + /* + * ThunderX2 doesn't support MSIs from the SMMU, so we're checking + * SPI numbers here. + */ + return smmu->event_gsiv == smmu->pri_gsiv && + smmu->event_gsiv == smmu->gerr_gsiv && + smmu->event_gsiv == smmu->sync_gsiv; +} + +static unsigned long arm_smmu_v3_resource_size(struct acpi_iort_smmu_v3 *smmu) +{ + /* + * Override the size, for Cavium ThunderX2 implementation + * which doesn't support the page 1 SMMU register space. + */ + if (smmu->model == ACPI_IORT_SMMU_V3_CAVIUM_CN99XX) + return SZ_64K; + + return SZ_128K; +} + static void __init arm_smmu_v3_init_resources(struct resource *res, struct acpi_iort_node *node) { @@ -844,30 +864,38 @@ static void __init arm_smmu_v3_init_resources(struct resource *res, smmu = (struct acpi_iort_smmu_v3 *)node->node_data; res[num_res].start = smmu->base_address; - res[num_res].end = smmu->base_address + SZ_128K - 1; + res[num_res].end = smmu->base_address + + arm_smmu_v3_resource_size(smmu) - 1; res[num_res].flags = IORESOURCE_MEM; num_res++; + if (arm_smmu_v3_is_combined_irq(smmu)) { + if (smmu->event_gsiv) + acpi_iort_register_irq(smmu->event_gsiv, "combined", + ACPI_EDGE_SENSITIVE, + &res[num_res++]); + } else { - if (smmu->event_gsiv) - acpi_iort_register_irq(smmu->event_gsiv, "eventq", - ACPI_EDGE_SENSITIVE, - &res[num_res++]); - - if (smmu->pri_gsiv) - acpi_iort_register_irq(smmu->pri_gsiv, "priq", - ACPI_EDGE_SENSITIVE, - &res[num_res++]); - - if (smmu->gerr_gsiv) - acpi_iort_register_irq(smmu->gerr_gsiv, "gerror", - ACPI_EDGE_SENSITIVE, - &res[num_res++]); - - if (smmu->sync_gsiv) - acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync", - ACPI_EDGE_SENSITIVE, - &res[num_res++]); + if (smmu->event_gsiv) + acpi_iort_register_irq(smmu->event_gsiv, "eventq", + ACPI_EDGE_SENSITIVE, + &res[num_res++]); + + if (smmu->pri_gsiv) + acpi_iort_register_irq(smmu->pri_gsiv, "priq", + ACPI_EDGE_SENSITIVE, + &res[num_res++]); + + if (smmu->gerr_gsiv) + acpi_iort_register_irq(smmu->gerr_gsiv, "gerror", + ACPI_EDGE_SENSITIVE, + &res[num_res++]); + + if (smmu->sync_gsiv) + acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync", + ACPI_EDGE_SENSITIVE, + &res[num_res++]); + } } static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index d42eeef9d928..1cbb88d938e5 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -782,7 +782,7 @@ static int acpi_battery_update(struct acpi_battery *battery, bool resume) if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) || (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) && (battery->capacity_now <= battery->alarm))) - pm_wakeup_event(&battery->device->dev, 0); + acpi_pm_wakeup_event(&battery->device->dev); return result; } diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c index df1c629205e7..75af78361ce5 100644 --- a/drivers/acpi/bgrt.c +++ b/drivers/acpi/bgrt.c @@ -76,7 +76,7 @@ static struct bin_attribute *bgrt_bin_attributes[] = { NULL, }; -static struct attribute_group bgrt_attribute_group = { +static const struct attribute_group bgrt_attribute_group = { .attrs = bgrt_attributes, .bin_attrs = bgrt_bin_attributes, }; diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 784bda663d16..af74b420ec83 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -196,42 +196,19 @@ static void acpi_print_osc_error(acpi_handle handle, pr_debug("\n"); } -acpi_status acpi_str_to_uuid(char *str, u8 *uuid) -{ - int i; - static int opc_map_to_uuid[16] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21, - 24, 26, 28, 30, 32, 34}; - - if (strlen(str) != 36) - return AE_BAD_PARAMETER; - for (i = 0; i < 36; i++) { - if (i == 8 || i == 13 || i == 18 || i == 23) { - if (str[i] != '-') - return AE_BAD_PARAMETER; - } else if (!isxdigit(str[i])) - return AE_BAD_PARAMETER; - } - for (i = 0; i < 16; i++) { - uuid[i] = hex_to_bin(str[opc_map_to_uuid[i]]) << 4; - uuid[i] |= hex_to_bin(str[opc_map_to_uuid[i] + 1]); - } - return AE_OK; -} -EXPORT_SYMBOL_GPL(acpi_str_to_uuid); - acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context) { acpi_status status; struct acpi_object_list input; union acpi_object in_params[4]; union acpi_object *out_obj; - u8 uuid[16]; + guid_t guid; u32 errors; struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; if (!context) return AE_ERROR; - if (ACPI_FAILURE(acpi_str_to_uuid(context->uuid_str, uuid))) + if (guid_parse(context->uuid_str, &guid)) return AE_ERROR; context->ret.length = ACPI_ALLOCATE_BUFFER; context->ret.pointer = NULL; @@ -241,7 +218,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context) input.pointer = in_params; in_params[0].type = ACPI_TYPE_BUFFER; in_params[0].buffer.length = 16; - in_params[0].buffer.pointer = uuid; + in_params[0].buffer.pointer = (u8 *)&guid; in_params[1].type = ACPI_TYPE_INTEGER; in_params[1].integer.value = context->rev; in_params[2].type = ACPI_TYPE_INTEGER; @@ -432,11 +409,15 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) driver->ops.notify(adev, type); - if (hotplug_event && ACPI_SUCCESS(acpi_hotplug_schedule(adev, type))) + if (!hotplug_event) { + acpi_bus_put_acpi_device(adev); + return; + } + + if (ACPI_SUCCESS(acpi_hotplug_schedule(adev, type))) return; acpi_bus_put_acpi_device(adev); - return; err: acpi_evaluate_ost(handle, type, ost_code, NULL); diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index e19f530f1083..ef1856b15488 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -19,7 +19,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -#define pr_fmt(fmt) "ACPI : button: " fmt +#define pr_fmt(fmt) "ACPI: button: " fmt #include <linux/kernel.h> #include <linux/module.h> @@ -217,7 +217,7 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state) } if (state) - pm_wakeup_event(&device->dev, 0); + acpi_pm_wakeup_event(&device->dev); ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); if (ret == NOTIFY_DONE) @@ -402,7 +402,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) } else { int keycode; - pm_wakeup_event(&device->dev, 0); + acpi_pm_wakeup_event(&device->dev); if (button->suspended) break; @@ -534,6 +534,7 @@ static int acpi_button_add(struct acpi_device *device) lid_device = device; } + device_init_wakeup(&device->dev, true); printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device)); return 0; diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 993fd31394c8..2ed6935d4483 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -24,6 +24,7 @@ #include <linux/pm_qos.h> #include <linux/pm_domain.h> #include <linux/pm_runtime.h> +#include <linux/suspend.h> #include "internal.h" @@ -261,8 +262,10 @@ int acpi_bus_init_power(struct acpi_device *device) return -EINVAL; device->power.state = ACPI_STATE_UNKNOWN; - if (!acpi_device_is_present(device)) + if (!acpi_device_is_present(device)) { + device->flags.initialized = false; return -ENXIO; + } result = acpi_device_get_power(device, &state); if (result) @@ -385,6 +388,12 @@ EXPORT_SYMBOL(acpi_bus_power_manageable); #ifdef CONFIG_PM static DEFINE_MUTEX(acpi_pm_notifier_lock); +void acpi_pm_wakeup_event(struct device *dev) +{ + pm_wakeup_dev_event(dev, 0, acpi_s2idle_wakeup()); +} +EXPORT_SYMBOL_GPL(acpi_pm_wakeup_event); + static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) { struct acpi_device *adev; @@ -399,9 +408,9 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) mutex_lock(&acpi_pm_notifier_lock); if (adev->wakeup.flags.notifier_present) { - __pm_wakeup_event(adev->wakeup.ws, 0); - if (adev->wakeup.context.work.func) - queue_pm_work(&adev->wakeup.context.work); + pm_wakeup_ws_event(adev->wakeup.ws, 0, acpi_s2idle_wakeup()); + if (adev->wakeup.context.func) + adev->wakeup.context.func(&adev->wakeup.context); } mutex_unlock(&acpi_pm_notifier_lock); @@ -413,7 +422,7 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) * acpi_add_pm_notifier - Register PM notify handler for given ACPI device. * @adev: ACPI device to add the notify handler for. * @dev: Device to generate a wakeup event for while handling the notification. - * @work_func: Work function to execute when handling the notification. + * @func: Work function to execute when handling the notification. * * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of * PM wakeup events. For example, wakeup events may be generated for bridges @@ -421,11 +430,11 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) * bridge itself doesn't have a wakeup GPE associated with it. */ acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, - void (*work_func)(struct work_struct *work)) + void (*func)(struct acpi_device_wakeup_context *context)) { acpi_status status = AE_ALREADY_EXISTS; - if (!dev && !work_func) + if (!dev && !func) return AE_BAD_PARAMETER; mutex_lock(&acpi_pm_notifier_lock); @@ -435,8 +444,7 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, adev->wakeup.ws = wakeup_source_register(dev_name(&adev->dev)); adev->wakeup.context.dev = dev; - if (work_func) - INIT_WORK(&adev->wakeup.context.work, work_func); + adev->wakeup.context.func = func; status = acpi_install_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY, acpi_pm_notify_handler, NULL); @@ -469,10 +477,7 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev) if (ACPI_FAILURE(status)) goto out; - if (adev->wakeup.context.work.func) { - cancel_work_sync(&adev->wakeup.context.work); - adev->wakeup.context.work.func = NULL; - } + adev->wakeup.context.func = NULL; adev->wakeup.context.dev = NULL; wakeup_source_unregister(adev->wakeup.ws); @@ -493,6 +498,13 @@ bool acpi_bus_can_wakeup(acpi_handle handle) } EXPORT_SYMBOL(acpi_bus_can_wakeup); +bool acpi_pm_device_can_wakeup(struct device *dev) +{ + struct acpi_device *adev = ACPI_COMPANION(dev); + + return adev ? acpi_device_can_wakeup(adev) : false; +} + /** * acpi_dev_pm_get_state - Get preferred power state of ACPI device. * @dev: Device whose preferred target power state to return. @@ -658,16 +670,15 @@ EXPORT_SYMBOL(acpi_pm_device_sleep_state); /** * acpi_pm_notify_work_func - ACPI devices wakeup notification work function. - * @work: Work item to handle. + * @context: Device wakeup context. */ -static void acpi_pm_notify_work_func(struct work_struct *work) +static void acpi_pm_notify_work_func(struct acpi_device_wakeup_context *context) { - struct device *dev; + struct device *dev = context->dev; - dev = container_of(work, struct acpi_device_wakeup_context, work)->dev; if (dev) { pm_wakeup_event(dev, 0); - pm_runtime_resume(dev); + pm_request_resume(dev); } } @@ -693,80 +704,53 @@ static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state, acpi_status res; int error; + if (adev->wakeup.flags.enabled) + return 0; + error = acpi_enable_wakeup_device_power(adev, target_state); if (error) return error; - if (adev->wakeup.flags.enabled) - return 0; - res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number); - if (ACPI_SUCCESS(res)) { - adev->wakeup.flags.enabled = 1; - } else { + if (ACPI_FAILURE(res)) { acpi_disable_wakeup_device_power(adev); return -EIO; } - } else { - if (adev->wakeup.flags.enabled) { - acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number); - adev->wakeup.flags.enabled = 0; - } + adev->wakeup.flags.enabled = 1; + } else if (adev->wakeup.flags.enabled) { + acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number); acpi_disable_wakeup_device_power(adev); + adev->wakeup.flags.enabled = 0; } return 0; } /** - * acpi_pm_device_run_wake - Enable/disable remote wakeup for given device. - * @dev: Device to enable/disable the platform to wake up. + * 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_device_run_wake(struct device *phys_dev, bool enable) -{ - struct acpi_device *adev; - - if (!device_run_wake(phys_dev)) - return -EINVAL; - - adev = ACPI_COMPANION(phys_dev); - if (!adev) { - dev_dbg(phys_dev, "ACPI companion missing in %s!\n", __func__); - return -ENODEV; - } - - return acpi_device_wakeup(adev, ACPI_STATE_S0, enable); -} -EXPORT_SYMBOL(acpi_pm_device_run_wake); - -#ifdef CONFIG_PM_SLEEP -/** - * acpi_pm_device_sleep_wake - Enable or disable device to wake up the system. - * @dev: Device to enable/desible to wake up the system from sleep states. - * @enable: Whether to enable or disable @dev to wake up the system. - */ -int acpi_pm_device_sleep_wake(struct device *dev, bool enable) +int acpi_pm_set_device_wakeup(struct device *dev, bool enable) { struct acpi_device *adev; int error; - if (!device_can_wakeup(dev)) - return -EINVAL; - adev = ACPI_COMPANION(dev); if (!adev) { dev_dbg(dev, "ACPI companion missing in %s!\n", __func__); return -ENODEV; } + if (!acpi_device_can_wakeup(adev)) + return -EINVAL; + error = acpi_device_wakeup(adev, acpi_target_system_state(), enable); if (!error) - dev_info(dev, "System wakeup %s by ACPI\n", - enable ? "enabled" : "disabled"); + dev_dbg(dev, "Wakeup %s by ACPI\n", enable ? "enabled" : "disabled"); return error; } -#endif /* CONFIG_PM_SLEEP */ +EXPORT_SYMBOL(acpi_pm_set_device_wakeup); /** * acpi_dev_pm_low_power - Put ACPI device into a low-power state. diff --git a/drivers/acpi/dptf/dptf_power.c b/drivers/acpi/dptf/dptf_power.c index 734642dc5008..e1c242568341 100644 --- a/drivers/acpi/dptf/dptf_power.c +++ b/drivers/acpi/dptf/dptf_power.c @@ -65,7 +65,7 @@ static struct attribute *dptf_power_attrs[] = { NULL }; -static struct attribute_group dptf_power_attribute_group = { +static const struct attribute_group dptf_power_attribute_group = { .attrs = dptf_power_attrs, .name = "dptf_power" }; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index c24235d8fb52..854d428e2a2d 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -27,7 +27,7 @@ /* Uncomment next line to get verbose printout */ /* #define DEBUG */ -#define pr_fmt(fmt) "ACPI : EC: " fmt +#define pr_fmt(fmt) "ACPI: EC: " fmt #include <linux/kernel.h> #include <linux/module.h> @@ -190,6 +190,7 @@ static struct workqueue_struct *ec_query_wq; static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */ +static int EC_FLAGS_IGNORE_DSDT_GPE; /* Needs ECDT GPE as correction setting */ /* -------------------------------------------------------------------------- * Logging/Debugging @@ -316,7 +317,7 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) ec->timestamp = jiffies; } -#ifdef DEBUG +#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) static const char *acpi_ec_cmd_string(u8 cmd) { switch (cmd) { @@ -459,8 +460,10 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec) static void acpi_ec_submit_query(struct acpi_ec *ec) { - if (acpi_ec_event_enabled(ec) && - !test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { + acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM); + if (!acpi_ec_event_enabled(ec)) + return; + if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { ec_dbg_evt("Command(%s) submitted/blocked", acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); ec->nr_pending_queries++; @@ -470,11 +473,10 @@ static void acpi_ec_submit_query(struct acpi_ec *ec) static void acpi_ec_complete_query(struct acpi_ec *ec) { - if (test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { - clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); + 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); } static inline void __acpi_ec_enable_event(struct acpi_ec *ec) @@ -1362,13 +1364,23 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) ec_parse_io_ports, ec); if (ACPI_FAILURE(status)) return status; + if (ec->data_addr == 0 || ec->command_addr == 0) + return AE_OK; - /* Get GPE bit assignment (EC events). */ - /* TODO: Add support for _GPE returning a package */ - status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); - if (ACPI_FAILURE(status)) - return status; - ec->gpe = tmp; + if (boot_ec && boot_ec_is_ecdt && EC_FLAGS_IGNORE_DSDT_GPE) { + /* + * Always inherit the GPE number setting from the ECDT + * EC. + */ + ec->gpe = boot_ec->gpe; + } else { + /* Get GPE bit assignment (EC events). */ + /* TODO: Add support for _GPE returning a package */ + status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); + if (ACPI_FAILURE(status)) + return status; + ec->gpe = tmp; + } /* Use the global lock for all EC transactions? */ tmp = 0; acpi_evaluate_integer(handle, "_GLK", NULL, &tmp); @@ -1665,12 +1677,26 @@ static const struct acpi_device_id ec_device_ids[] = { {"", 0}, }; +/* + * This function is not Windows-compatible as Windows never enumerates the + * namespace EC before the main ACPI device enumeration process. It is + * retained for historical reason and will be deprecated in the future. + */ int __init acpi_ec_dsdt_probe(void) { acpi_status status; struct acpi_ec *ec; int ret; + /* + * If a platform has ECDT, there is no need to proceed as the + * following probe is not a part of the ACPI device enumeration, + * executing _STA is not safe, and thus this probe may risk of + * picking up an invalid EC device. + */ + if (boot_ec) + return -ENODEV; + ec = acpi_ec_alloc(); if (!ec) return -ENOMEM; @@ -1753,11 +1779,43 @@ static int ec_correct_ecdt(const struct dmi_system_id *id) return 0; } +/* + * Some DSDTs contain wrong GPE setting. + * Asus FX502VD/VE, GL702VMK, X550VXK, X580VD + * https://bugzilla.kernel.org/show_bug.cgi?id=195651 + */ +static int ec_honor_ecdt_gpe(const struct dmi_system_id *id) +{ + pr_debug("Detected system needing ignore DSDT GPE setting.\n"); + EC_FLAGS_IGNORE_DSDT_GPE = 1; + return 0; +} + static struct dmi_system_id ec_dmi_table[] __initdata = { { ec_correct_ecdt, "MSI MS-171F", { DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"), DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL}, + { + ec_honor_ecdt_gpe, "ASUS FX502VD", { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "FX502VD"),}, NULL}, + { + ec_honor_ecdt_gpe, "ASUS FX502VE", { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "FX502VE"),}, NULL}, + { + ec_honor_ecdt_gpe, "ASUS GL702VMK", { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "GL702VMK"),}, NULL}, + { + ec_honor_ecdt_gpe, "ASUS X550VXK", { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X550VXK"),}, NULL}, + { + ec_honor_ecdt_gpe, "ASUS X580VD", { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X580VD"),}, NULL}, {}, }; @@ -1835,7 +1893,7 @@ static int acpi_ec_suspend(struct device *dev) struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev)); - if (ec_freeze_events) + if (acpi_sleep_no_ec_events() && ec_freeze_events) acpi_ec_disable_event(ec); return 0; } diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 66229ffa909b..9531d3276f65 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -111,7 +111,7 @@ int acpi_device_setup_files(struct acpi_device *dev); void acpi_device_remove_files(struct acpi_device *dev); void acpi_device_add_finalize(struct acpi_device *device); void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); -bool acpi_device_is_present(struct acpi_device *adev); +bool acpi_device_is_present(const struct acpi_device *adev); bool acpi_device_is_battery(struct acpi_device *adev); bool acpi_device_is_first_physical_node(struct acpi_device *adev, const struct device *dev); @@ -198,8 +198,12 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit); Suspend/Resume -------------------------------------------------------------------------- */ #ifdef CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT +extern bool acpi_s2idle_wakeup(void); +extern bool acpi_sleep_no_ec_events(void); extern int acpi_sleep_init(void); #else +static inline bool acpi_s2idle_wakeup(void) { return false; } +static inline bool acpi_sleep_no_ec_events(void) { return true; } static inline int acpi_sleep_init(void) { return -ENXIO; } #endif diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c index 7e4fbf9a53a3..3595aa9c7c18 100644 --- a/drivers/acpi/ioapic.c +++ b/drivers/acpi/ioapic.c @@ -21,7 +21,7 @@ * registered when we parsed the ACPI MADT. */ -#define pr_fmt(fmt) "ACPI : IOAPIC: " fmt +#define pr_fmt(fmt) "ACPI: IOAPIC: " fmt #include <linux/slab.h> #include <linux/acpi.h> diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 656acb5d7166..b75b734ee73a 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -20,7 +20,6 @@ #include <linux/list.h> #include <linux/acpi.h> #include <linux/sort.h> -#include <linux/pmem.h> #include <linux/io.h> #include <linux/nd.h> #include <asm/cacheflush.h> @@ -74,11 +73,11 @@ struct nfit_table_prev { struct list_head flushes; }; -static u8 nfit_uuid[NFIT_UUID_MAX][16]; +static guid_t nfit_uuid[NFIT_UUID_MAX]; -const u8 *to_nfit_uuid(enum nfit_uuids id) +const guid_t *to_nfit_uuid(enum nfit_uuids id) { - return nfit_uuid[id]; + return &nfit_uuid[id]; } EXPORT_SYMBOL(to_nfit_uuid); @@ -222,7 +221,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, u32 offset, fw_status = 0; acpi_handle handle; unsigned int func; - const u8 *uuid; + const guid_t *guid; int rc, i; func = cmd; @@ -245,7 +244,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, cmd_mask = nvdimm_cmd_mask(nvdimm); dsm_mask = nfit_mem->dsm_mask; desc = nd_cmd_dimm_desc(cmd); - uuid = to_nfit_uuid(nfit_mem->family); + guid = to_nfit_uuid(nfit_mem->family); handle = adev->handle; } else { struct acpi_device *adev = to_acpi_dev(acpi_desc); @@ -253,8 +252,10 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, cmd_name = nvdimm_bus_cmd_name(cmd); cmd_mask = nd_desc->cmd_mask; dsm_mask = cmd_mask; + if (cmd == ND_CMD_CALL) + dsm_mask = nd_desc->bus_dsm_mask; desc = nd_cmd_bus_desc(cmd); - uuid = to_nfit_uuid(NFIT_DEV_BUS); + guid = to_nfit_uuid(NFIT_DEV_BUS); handle = adev->handle; dimm_name = "bus"; } @@ -289,7 +290,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, in_buf.buffer.pointer, min_t(u32, 256, in_buf.buffer.length), true); - out_obj = acpi_evaluate_dsm(handle, uuid, 1, func, &in_obj); + out_obj = acpi_evaluate_dsm(handle, guid, 1, func, &in_obj); if (!out_obj) { dev_dbg(dev, "%s:%s _DSM failed cmd: %s\n", __func__, dimm_name, cmd_name); @@ -409,7 +410,7 @@ int nfit_spa_type(struct acpi_nfit_system_address *spa) int i; for (i = 0; i < NFIT_UUID_MAX; i++) - if (memcmp(to_nfit_uuid(i), spa->range_guid, 16) == 0) + if (guid_equal(to_nfit_uuid(i), (guid_t *)&spa->range_guid)) return i; return -1; } @@ -927,6 +928,17 @@ static int nfit_mem_init(struct acpi_nfit_desc *acpi_desc) return 0; } +static ssize_t bus_dsm_mask_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev); + struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); + + return sprintf(buf, "%#lx\n", nd_desc->bus_dsm_mask); +} +static struct device_attribute dev_attr_bus_dsm_mask = + __ATTR(dsm_mask, 0444, bus_dsm_mask_show, NULL); + static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1031,7 +1043,7 @@ static ssize_t scrub_store(struct device *dev, if (nd_desc) { struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); - rc = acpi_nfit_ars_rescan(acpi_desc); + rc = acpi_nfit_ars_rescan(acpi_desc, 0); } device_unlock(dev); if (rc) @@ -1063,10 +1075,11 @@ static struct attribute *acpi_nfit_attributes[] = { &dev_attr_revision.attr, &dev_attr_scrub.attr, &dev_attr_hw_error_scrub.attr, + &dev_attr_bus_dsm_mask.attr, NULL, }; -static struct attribute_group acpi_nfit_attribute_group = { +static const struct attribute_group acpi_nfit_attribute_group = { .name = "nfit", .attrs = acpi_nfit_attributes, .is_visible = nfit_visible, @@ -1346,7 +1359,7 @@ static umode_t acpi_nfit_dimm_attr_visible(struct kobject *kobj, return a->mode; } -static struct attribute_group acpi_nfit_dimm_attribute_group = { +static const struct attribute_group acpi_nfit_dimm_attribute_group = { .name = "nfit", .attrs = acpi_nfit_dimm_attributes, .is_visible = acpi_nfit_dimm_attr_visible, @@ -1415,7 +1428,7 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, struct acpi_device *adev, *adev_dimm; struct device *dev = acpi_desc->dev; unsigned long dsm_mask; - const u8 *uuid; + const guid_t *guid; int i; int family = -1; @@ -1444,7 +1457,7 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, /* * Until standardization materializes we need to consider 4 * different command sets. Note, that checking for function0 (bit0) - * tells us if any commands are reachable through this uuid. + * tells us if any commands are reachable through this GUID. */ for (i = NVDIMM_FAMILY_INTEL; i <= NVDIMM_FAMILY_MSFT; i++) if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1)) @@ -1474,9 +1487,9 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, return 0; } - uuid = to_nfit_uuid(nfit_mem->family); + guid = to_nfit_uuid(nfit_mem->family); for_each_set_bit(i, &dsm_mask, BITS_PER_LONG) - if (acpi_check_dsm(adev_dimm->handle, uuid, 1, 1ULL << i)) + if (acpi_check_dsm(adev_dimm->handle, guid, 1, 1ULL << i)) set_bit(i, &nfit_mem->dsm_mask); return 0; @@ -1608,11 +1621,23 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) acpi_desc); } +/* + * These constants are private because there are no kernel consumers of + * these commands. + */ +enum nfit_aux_cmds { + NFIT_CMD_TRANSLATE_SPA = 5, + NFIT_CMD_ARS_INJECT_SET = 7, + NFIT_CMD_ARS_INJECT_CLEAR = 8, + NFIT_CMD_ARS_INJECT_GET = 9, +}; + static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc) { struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc; - const u8 *uuid = to_nfit_uuid(NFIT_DEV_BUS); + const guid_t *guid = to_nfit_uuid(NFIT_DEV_BUS); struct acpi_device *adev; + unsigned long dsm_mask; int i; nd_desc->cmd_mask = acpi_desc->bus_cmd_force_en; @@ -1621,8 +1646,22 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc) return; for (i = ND_CMD_ARS_CAP; i <= ND_CMD_CLEAR_ERROR; i++) - if (acpi_check_dsm(adev->handle, uuid, 1, 1ULL << i)) + if (acpi_check_dsm(adev->handle, guid, 1, 1ULL << i)) set_bit(i, &nd_desc->cmd_mask); + set_bit(ND_CMD_CALL, &nd_desc->cmd_mask); + + dsm_mask = + (1 << ND_CMD_ARS_CAP) | + (1 << ND_CMD_ARS_START) | + (1 << ND_CMD_ARS_STATUS) | + (1 << ND_CMD_CLEAR_ERROR) | + (1 << NFIT_CMD_TRANSLATE_SPA) | + (1 << NFIT_CMD_ARS_INJECT_SET) | + (1 << NFIT_CMD_ARS_INJECT_CLEAR) | + (1 << NFIT_CMD_ARS_INJECT_GET); + for_each_set_bit(i, &dsm_mask, BITS_PER_LONG) + if (acpi_check_dsm(adev->handle, guid, 1, 1ULL << i)) + set_bit(i, &nd_desc->bus_dsm_mask); } static ssize_t range_index_show(struct device *dev, @@ -1640,7 +1679,7 @@ static struct attribute *acpi_nfit_region_attributes[] = { NULL, }; -static struct attribute_group acpi_nfit_region_attribute_group = { +static const struct attribute_group acpi_nfit_region_attribute_group = { .name = "nfit", .attrs = acpi_nfit_region_attributes, }; @@ -1663,12 +1702,29 @@ struct nfit_set_info { } mapping[0]; }; +struct nfit_set_info2 { + struct nfit_set_info_map2 { + u64 region_offset; + u32 serial_number; + u16 vendor_id; + u16 manufacturing_date; + u8 manufacturing_location; + u8 reserved[31]; + } mapping[0]; +}; + static size_t sizeof_nfit_set_info(int num_mappings) { return sizeof(struct nfit_set_info) + num_mappings * sizeof(struct nfit_set_info_map); } +static size_t sizeof_nfit_set_info2(int num_mappings) +{ + return sizeof(struct nfit_set_info2) + + num_mappings * sizeof(struct nfit_set_info_map2); +} + static int cmp_map_compat(const void *m0, const void *m1) { const struct nfit_set_info_map *map0 = m0; @@ -1690,6 +1746,18 @@ static int cmp_map(const void *m0, const void *m1) return 0; } +static int cmp_map2(const void *m0, const void *m1) +{ + const struct nfit_set_info_map2 *map0 = m0; + const struct nfit_set_info_map2 *map1 = m1; + + if (map0->region_offset < map1->region_offset) + return -1; + else if (map0->region_offset > map1->region_offset) + return 1; + return 0; +} + /* Retrieve the nth entry referencing this spa */ static struct acpi_nfit_memory_map *memdev_from_spa( struct acpi_nfit_desc *acpi_desc, u16 range_index, int n) @@ -1707,27 +1775,31 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc, struct nd_region_desc *ndr_desc, struct acpi_nfit_system_address *spa) { - int i, spa_type = nfit_spa_type(spa); struct device *dev = acpi_desc->dev; struct nd_interleave_set *nd_set; u16 nr = ndr_desc->num_mappings; + struct nfit_set_info2 *info2; struct nfit_set_info *info; - - if (spa_type == NFIT_SPA_PM || spa_type == NFIT_SPA_VOLATILE) - /* pass */; - else - return 0; + int i; nd_set = devm_kzalloc(dev, sizeof(*nd_set), GFP_KERNEL); if (!nd_set) return -ENOMEM; + ndr_desc->nd_set = nd_set; + guid_copy(&nd_set->type_guid, (guid_t *) spa->range_guid); info = devm_kzalloc(dev, sizeof_nfit_set_info(nr), GFP_KERNEL); if (!info) return -ENOMEM; + + info2 = devm_kzalloc(dev, sizeof_nfit_set_info2(nr), GFP_KERNEL); + if (!info2) + return -ENOMEM; + for (i = 0; i < nr; i++) { struct nd_mapping_desc *mapping = &ndr_desc->mapping[i]; struct nfit_set_info_map *map = &info->mapping[i]; + struct nfit_set_info_map2 *map2 = &info2->mapping[i]; struct nvdimm *nvdimm = mapping->nvdimm; struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); struct acpi_nfit_memory_map *memdev = memdev_from_spa(acpi_desc, @@ -1740,19 +1812,32 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc, map->region_offset = memdev->region_offset; map->serial_number = nfit_mem->dcr->serial_number; + + map2->region_offset = memdev->region_offset; + map2->serial_number = nfit_mem->dcr->serial_number; + map2->vendor_id = nfit_mem->dcr->vendor_id; + map2->manufacturing_date = nfit_mem->dcr->manufacturing_date; + map2->manufacturing_location = nfit_mem->dcr->manufacturing_location; } + /* v1.1 namespaces */ sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map), cmp_map, NULL); - nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0); + nd_set->cookie1 = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0); + + /* v1.2 namespaces */ + sort(&info2->mapping[0], nr, sizeof(struct nfit_set_info_map2), + cmp_map2, NULL); + nd_set->cookie2 = nd_fletcher64(info2, sizeof_nfit_set_info2(nr), 0); - /* support namespaces created with the wrong sort order */ + /* support v1.1 namespaces created with the wrong sort order */ sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map), cmp_map_compat, NULL); nd_set->altcookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0); ndr_desc->nd_set = nd_set; devm_kfree(dev, info); + devm_kfree(dev, info2); return 0; } @@ -1842,8 +1927,7 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk, } if (rw) - memcpy_to_pmem(mmio->addr.aperture + offset, - iobuf + copied, c); + memcpy_flushcache(mmio->addr.aperture + offset, iobuf + copied, c); else { if (nfit_blk->dimm_flags & NFIT_BLK_READ_FLUSH) mmio_flush_range((void __force *) @@ -1957,7 +2041,7 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, nfit_blk->bdw_offset = nfit_mem->bdw->offset; mmio = &nfit_blk->mmio[BDW]; mmio->addr.base = devm_nvdimm_memremap(dev, nfit_mem->spa_bdw->address, - nfit_mem->spa_bdw->length, ARCH_MEMREMAP_PMEM); + nfit_mem->spa_bdw->length, nd_blk_memremap_flags(ndbr)); if (!mmio->addr.base) { dev_dbg(dev, "%s: %s failed to map bdw\n", __func__, nvdimm_name(nvdimm)); @@ -2051,6 +2135,7 @@ static int ars_start(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa memset(&ars_start, 0, sizeof(ars_start)); ars_start.address = spa->address; ars_start.length = spa->length; + ars_start.flags = acpi_desc->ars_start_flags; if (nfit_spa_type(spa) == NFIT_SPA_PM) ars_start.type = ND_ARS_PERSISTENT; else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE) @@ -2077,6 +2162,7 @@ static int ars_continue(struct acpi_nfit_desc *acpi_desc) ars_start.address = ars_status->restart_address; ars_start.length = ars_status->restart_length; ars_start.type = ars_status->type; + ars_start.flags = acpi_desc->ars_start_flags; rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_START, &ars_start, sizeof(ars_start), &cmd_rc); if (rc < 0) @@ -2179,7 +2265,7 @@ static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc, struct acpi_nfit_system_address *spa = nfit_spa->spa; struct nd_blk_region_desc *ndbr_desc; struct nfit_mem *nfit_mem; - int blk_valid = 0; + int blk_valid = 0, rc; if (!nvdimm) { dev_err(acpi_desc->dev, "spa%d dimm: %#x not found\n", @@ -2211,6 +2297,9 @@ static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc, ndbr_desc = to_blk_region_desc(ndr_desc); ndbr_desc->enable = acpi_nfit_blk_region_enable; ndbr_desc->do_io = acpi_desc->blk_do_io; + rc = acpi_nfit_init_interleave_set(acpi_desc, ndr_desc, spa); + if (rc) + return rc; nfit_spa->nd_region = nvdimm_blk_region_create(acpi_desc->nvdimm_bus, ndr_desc); if (!nfit_spa->nd_region) @@ -2229,6 +2318,13 @@ static bool nfit_spa_is_virtual(struct acpi_nfit_system_address *spa) nfit_spa_type(spa) == NFIT_SPA_PCD); } +static bool nfit_spa_is_volatile(struct acpi_nfit_system_address *spa) +{ + return (nfit_spa_type(spa) == NFIT_SPA_VDISK || + nfit_spa_type(spa) == NFIT_SPA_VCD || + nfit_spa_type(spa) == NFIT_SPA_VOLATILE); +} + static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc, struct nfit_spa *nfit_spa) { @@ -2303,7 +2399,7 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc, ndr_desc); if (!nfit_spa->nd_region) rc = -ENOMEM; - } else if (nfit_spa_type(spa) == NFIT_SPA_VOLATILE) { + } else if (nfit_spa_is_volatile(spa)) { nfit_spa->nd_region = nvdimm_volatile_region_create(nvdimm_bus, ndr_desc); if (!nfit_spa->nd_region) @@ -2595,6 +2691,7 @@ static void acpi_nfit_scrub(struct work_struct *work) list_for_each_entry(nfit_spa, &acpi_desc->spas, list) acpi_nfit_async_scrub(acpi_desc, nfit_spa); acpi_desc->scrub_count++; + acpi_desc->ars_start_flags = 0; if (acpi_desc->scrub_count_state) sysfs_notify_dirent(acpi_desc->scrub_count_state); mutex_unlock(&acpi_desc->init_mutex); @@ -2613,6 +2710,7 @@ static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc) return rc; } + acpi_desc->ars_start_flags = 0; if (!acpi_desc->cancel) queue_work(nfit_wq, &acpi_desc->work); return 0; @@ -2817,7 +2915,7 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, return 0; } -int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc) +int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, u8 flags) { struct device *dev = acpi_desc->dev; struct nfit_spa *nfit_spa; @@ -2839,6 +2937,7 @@ int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc) nfit_spa->ars_required = 1; } + acpi_desc->ars_start_flags = flags; queue_work(nfit_wq, &acpi_desc->work); dev_dbg(dev, "%s: ars_scan triggered\n", __func__); mutex_unlock(&acpi_desc->init_mutex); @@ -2967,7 +3066,7 @@ static int acpi_nfit_remove(struct acpi_device *adev) return 0; } -void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event) +static void acpi_nfit_update_notify(struct device *dev, acpi_handle handle) { struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(dev); struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -2975,11 +3074,6 @@ void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event) acpi_status status; int ret; - dev_dbg(dev, "%s: event: %d\n", __func__, event); - - if (event != NFIT_NOTIFY_UPDATE) - return; - if (!dev->driver) { /* dev->driver may be null if we're being removed */ dev_dbg(dev, "%s: no driver found for dev\n", __func__); @@ -3016,6 +3110,29 @@ void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event) dev_err(dev, "Invalid _FIT\n"); kfree(buf.pointer); } + +static void acpi_nfit_uc_error_notify(struct device *dev, acpi_handle handle) +{ + struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(dev); + u8 flags = (acpi_desc->scrub_mode == HW_ERROR_SCRUB_ON) ? + 0 : ND_ARS_RETURN_PREV_DATA; + + acpi_nfit_ars_rescan(acpi_desc, flags); +} + +void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event) +{ + dev_dbg(dev, "%s: event: 0x%x\n", __func__, event); + + switch (event) { + case NFIT_NOTIFY_UPDATE: + return acpi_nfit_update_notify(dev, handle); + case NFIT_NOTIFY_UC_MEMORY_ERROR: + return acpi_nfit_uc_error_notify(dev, handle); + default: + return; + } +} EXPORT_SYMBOL_GPL(__acpi_nfit_notify); static void acpi_nfit_notify(struct acpi_device *adev, u32 event) @@ -3051,19 +3168,19 @@ static __init int nfit_init(void) BUILD_BUG_ON(sizeof(struct acpi_nfit_control_region) != 80); BUILD_BUG_ON(sizeof(struct acpi_nfit_data_region) != 40); - acpi_str_to_uuid(UUID_VOLATILE_MEMORY, nfit_uuid[NFIT_SPA_VOLATILE]); - acpi_str_to_uuid(UUID_PERSISTENT_MEMORY, nfit_uuid[NFIT_SPA_PM]); - acpi_str_to_uuid(UUID_CONTROL_REGION, nfit_uuid[NFIT_SPA_DCR]); - acpi_str_to_uuid(UUID_DATA_REGION, nfit_uuid[NFIT_SPA_BDW]); - acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_VDISK]); - acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_CD, nfit_uuid[NFIT_SPA_VCD]); - acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_PDISK]); - acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_CD, nfit_uuid[NFIT_SPA_PCD]); - acpi_str_to_uuid(UUID_NFIT_BUS, nfit_uuid[NFIT_DEV_BUS]); - acpi_str_to_uuid(UUID_NFIT_DIMM, nfit_uuid[NFIT_DEV_DIMM]); - acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE1, nfit_uuid[NFIT_DEV_DIMM_N_HPE1]); - acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE2, nfit_uuid[NFIT_DEV_DIMM_N_HPE2]); - acpi_str_to_uuid(UUID_NFIT_DIMM_N_MSFT, nfit_uuid[NFIT_DEV_DIMM_N_MSFT]); + guid_parse(UUID_VOLATILE_MEMORY, &nfit_uuid[NFIT_SPA_VOLATILE]); + guid_parse(UUID_PERSISTENT_MEMORY, &nfit_uuid[NFIT_SPA_PM]); + guid_parse(UUID_CONTROL_REGION, &nfit_uuid[NFIT_SPA_DCR]); + guid_parse(UUID_DATA_REGION, &nfit_uuid[NFIT_SPA_BDW]); + guid_parse(UUID_VOLATILE_VIRTUAL_DISK, &nfit_uuid[NFIT_SPA_VDISK]); + guid_parse(UUID_VOLATILE_VIRTUAL_CD, &nfit_uuid[NFIT_SPA_VCD]); + guid_parse(UUID_PERSISTENT_VIRTUAL_DISK, &nfit_uuid[NFIT_SPA_PDISK]); + guid_parse(UUID_PERSISTENT_VIRTUAL_CD, &nfit_uuid[NFIT_SPA_PCD]); + guid_parse(UUID_NFIT_BUS, &nfit_uuid[NFIT_DEV_BUS]); + guid_parse(UUID_NFIT_DIMM, &nfit_uuid[NFIT_DEV_DIMM]); + guid_parse(UUID_NFIT_DIMM_N_HPE1, &nfit_uuid[NFIT_DEV_DIMM_N_HPE1]); + guid_parse(UUID_NFIT_DIMM_N_HPE2, &nfit_uuid[NFIT_DEV_DIMM_N_HPE2]); + guid_parse(UUID_NFIT_DIMM_N_MSFT, &nfit_uuid[NFIT_DEV_DIMM_N_MSFT]); nfit_wq = create_singlethread_workqueue("nfit"); if (!nfit_wq) diff --git a/drivers/acpi/nfit/mce.c b/drivers/acpi/nfit/mce.c index fd86bec98dea..feeb95d574fa 100644 --- a/drivers/acpi/nfit/mce.c +++ b/drivers/acpi/nfit/mce.c @@ -79,7 +79,7 @@ static int nfit_handle_mce(struct notifier_block *nb, unsigned long val, * already in progress, just let that be the last * authoritative one */ - acpi_nfit_ars_rescan(acpi_desc); + acpi_nfit_ars_rescan(acpi_desc, 0); } break; } diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index 58fb7d68e04a..54292db61262 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h @@ -18,7 +18,6 @@ #include <linux/libnvdimm.h> #include <linux/ndctl.h> #include <linux/types.h> -#include <linux/uuid.h> #include <linux/acpi.h> #include <acpi/acuuid.h> @@ -80,6 +79,7 @@ enum { enum nfit_root_notifiers { NFIT_NOTIFY_UPDATE = 0x80, + NFIT_NOTIFY_UC_MEMORY_ERROR = 0x81, }; enum nfit_dimm_notifiers { @@ -155,6 +155,7 @@ struct acpi_nfit_desc { struct list_head idts; struct nvdimm_bus *nvdimm_bus; struct device *dev; + u8 ars_start_flags; struct nd_cmd_ars_status *ars_status; size_t ars_status_size; struct work_struct work; @@ -207,7 +208,7 @@ struct nfit_blk { extern struct list_head acpi_descs; extern struct mutex acpi_desc_lock; -int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc); +int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, u8 flags); #ifdef CONFIG_X86_MCE void nfit_mce_register(void); @@ -237,7 +238,7 @@ static inline struct acpi_nfit_desc *to_acpi_desc( return container_of(nd_desc, struct acpi_nfit_desc, nd_desc); } -const u8 *to_nfit_uuid(enum nfit_uuids id); +const guid_t *to_nfit_uuid(enum nfit_uuids id); int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *nfit, acpi_size sz); void acpi_nfit_shutdown(void *data); void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event); diff --git a/drivers/acpi/osi.c b/drivers/acpi/osi.c index 849f9d2245ca..723bee58bbcf 100644 --- a/drivers/acpi/osi.c +++ b/drivers/acpi/osi.c @@ -265,7 +265,8 @@ static void __init acpi_osi_dmi_darwin(bool enable, __acpi_osi_setup_darwin(enable); } -void __init acpi_osi_dmi_linux(bool enable, const struct dmi_system_id *d) +static void __init acpi_osi_dmi_linux(bool enable, + const struct dmi_system_id *d) { pr_notice("DMI detected to setup _OSI(\"Linux\"): %s\n", d->ident); osi_config.linux_dmi = 1; diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 919be0aa2578..9eec3095e6c3 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -523,7 +523,7 @@ static int acpi_pci_root_add(struct acpi_device *device, struct acpi_pci_root *root; acpi_handle handle = device->handle; int no_aspm = 0; - bool hotadd = system_state != SYSTEM_BOOTING; + bool hotadd = system_state == SYSTEM_RUNNING; root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); if (!root) @@ -608,8 +608,7 @@ static int acpi_pci_root_add(struct acpi_device *device, pcie_no_aspm(); pci_acpi_add_bus_pm_notifier(device); - if (device->wakeup.flags.run_wake) - device_set_run_wake(root->bus->bridge, true); + device_set_wakeup_capable(root->bus->bridge, device->wakeup.flags.valid); if (hotadd) { pcibios_resource_survey_bus(root->bus); @@ -649,7 +648,7 @@ static void acpi_pci_root_remove(struct acpi_device *device) pci_stop_root_bus(root->bus); pci_ioapic_remove(root); - device_set_run_wake(root->bus->bridge, false); + device_set_wakeup_capable(root->bus->bridge, false); pci_acpi_remove_bus_pm_notifier(device); pci_remove_root_bus(root->bus); diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c index 1a76c784cd4c..3b7d5be5b7ed 100644 --- a/drivers/acpi/pmic/intel_pmic_xpower.c +++ b/drivers/acpi/pmic/intel_pmic_xpower.c @@ -21,6 +21,11 @@ #include "intel_pmic.h" #define XPOWER_GPADC_LOW 0x5b +#define XPOWER_GPI1_CTRL 0x92 + +#define GPI1_LDO_MASK GENMASK(2, 0) +#define GPI1_LDO_ON (3 << 0) +#define GPI1_LDO_OFF (4 << 0) static struct pmic_table power_table[] = { { @@ -118,6 +123,10 @@ static struct pmic_table power_table[] = { .reg = 0x10, .bit = 0x00 }, /* BUC6 */ + { + .address = 0x4c, + .reg = 0x92, + }, /* GPI1 */ }; /* TMP0 - TMP5 are the same, all from GPADC */ @@ -156,7 +165,12 @@ static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg, if (regmap_read(regmap, reg, &data)) return -EIO; - *value = (data & BIT(bit)) ? 1 : 0; + /* GPIO1 LDO regulator needs special handling */ + if (reg == XPOWER_GPI1_CTRL) + *value = ((data & GPI1_LDO_MASK) == GPI1_LDO_ON); + else + *value = (data & BIT(bit)) ? 1 : 0; + return 0; } @@ -165,6 +179,11 @@ static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg, { int data; + /* GPIO1 LDO regulator needs special handling */ + if (reg == XPOWER_GPI1_CTRL) + return regmap_update_bits(regmap, reg, GPI1_LDO_MASK, + on ? GPI1_LDO_ON : GPI1_LDO_OFF); + if (regmap_read(regmap, reg, &data)) return -EIO; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 3a6c9b741b23..1b475bc1ae16 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -352,7 +352,7 @@ static struct attribute *attrs[] = { NULL, }; -static struct attribute_group attr_groups[] = { +static const struct attribute_group attr_groups[] = { [ACPI_STATE_D0] = { .name = "power_resources_D0", .attrs = attrs, @@ -371,14 +371,14 @@ static struct attribute_group attr_groups[] = { }, }; -static struct attribute_group wakeup_attr_group = { +static const struct attribute_group wakeup_attr_group = { .name = "power_resources_wakeup", .attrs = attrs, }; static void acpi_power_hide_list(struct acpi_device *adev, struct list_head *resources, - struct attribute_group *attr_group) + const struct attribute_group *attr_group) { struct acpi_power_resource_entry *entry; @@ -397,7 +397,7 @@ static void acpi_power_hide_list(struct acpi_device *adev, static void acpi_power_expose_list(struct acpi_device *adev, struct list_head *resources, - struct attribute_group *attr_group) + const struct attribute_group *attr_group) { struct acpi_power_resource_entry *entry; int ret; @@ -425,7 +425,7 @@ static void acpi_power_expose_list(struct acpi_device *adev, static void acpi_power_expose_hide(struct acpi_device *adev, struct list_head *resources, - struct attribute_group *attr_group, + const struct attribute_group *attr_group, bool expose) { if (expose) diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index a34669cc823b..85ac848ac6ab 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -42,7 +42,7 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) if (!dev->physical_node_count) { seq_printf(seq, "%c%-8s\n", - dev->wakeup.flags.run_wake ? '*' : ' ', + dev->wakeup.flags.valid ? '*' : ' ', device_may_wakeup(&dev->dev) ? "enabled" : "disabled"); } else { @@ -58,7 +58,7 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) seq_printf(seq, "\t\t"); seq_printf(seq, "%c%-8s %s:%s\n", - dev->wakeup.flags.run_wake ? '*' : ' ', + dev->wakeup.flags.valid ? '*' : ' ', (device_may_wakeup(&dev->dev) || device_may_wakeup(ldev)) ? "enabled" : "disabled", diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 8697a82bd465..591d1dd3f04e 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -268,9 +268,9 @@ static int acpi_processor_start(struct device *dev) return -ENODEV; /* Protect against concurrent CPU hotplug operations */ - get_online_cpus(); + cpu_hotplug_disable(); ret = __acpi_processor_start(device); - put_online_cpus(); + cpu_hotplug_enable(); return ret; } diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 3de34633f7f9..7f9aff4b8d62 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -909,6 +909,13 @@ static long __acpi_processor_get_throttling(void *data) return pr->throttling.acpi_processor_get_throttling(pr); } +static int call_on_cpu(int cpu, long (*fn)(void *), void *arg, bool direct) +{ + if (direct || (is_percpu_thread() && cpu == smp_processor_id())) + return fn(arg); + return work_on_cpu(cpu, fn, arg); +} + static int acpi_processor_get_throttling(struct acpi_processor *pr) { if (!pr) @@ -926,7 +933,7 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr) if (!cpu_online(pr->id)) return -ENODEV; - return work_on_cpu(pr->id, __acpi_processor_get_throttling, pr); + return call_on_cpu(pr->id, __acpi_processor_get_throttling, pr, false); } static int acpi_processor_get_fadt_info(struct acpi_processor *pr) @@ -1076,13 +1083,6 @@ static long acpi_processor_throttling_fn(void *data) arg->target_state, arg->force); } -static int call_on_cpu(int cpu, long (*fn)(void *), void *arg, bool direct) -{ - if (direct) - return fn(arg); - return work_on_cpu(cpu, fn, arg); -} - static int __acpi_processor_set_throttling(struct acpi_processor *pr, int state, bool force, bool direct) { diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 9364398204e9..917c789f953d 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -57,6 +57,7 @@ static bool acpi_nondev_subnode_extract(const union acpi_object *desc, dn->name = link->package.elements[0].string.pointer; dn->fwnode.type = FWNODE_ACPI_DATA; + dn->fwnode.ops = &acpi_fwnode_ops; dn->parent = parent; INIT_LIST_HEAD(&dn->data.subnodes); @@ -1119,3 +1120,119 @@ int acpi_graph_get_remote_endpoint(struct fwnode_handle *fwnode, return 0; } + +static bool acpi_fwnode_device_is_available(struct fwnode_handle *fwnode) +{ + if (!is_acpi_device_node(fwnode)) + return false; + + return acpi_device_is_present(to_acpi_device_node(fwnode)); +} + +static bool acpi_fwnode_property_present(struct fwnode_handle *fwnode, + const char *propname) +{ + return !acpi_node_prop_get(fwnode, propname, NULL); +} + +static int acpi_fwnode_property_read_int_array(struct fwnode_handle *fwnode, + const char *propname, + unsigned int elem_size, + void *val, size_t nval) +{ + enum dev_prop_type type; + + switch (elem_size) { + case sizeof(u8): + type = DEV_PROP_U8; + break; + case sizeof(u16): + type = DEV_PROP_U16; + break; + case sizeof(u32): + type = DEV_PROP_U32; + break; + case sizeof(u64): + type = DEV_PROP_U64; + break; + default: + return -ENXIO; + } + + return acpi_node_prop_read(fwnode, propname, type, val, nval); +} + +static int acpi_fwnode_property_read_string_array(struct fwnode_handle *fwnode, + const char *propname, + const char **val, size_t nval) +{ + return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, + val, nval); +} + +static struct fwnode_handle * +acpi_fwnode_get_named_child_node(struct fwnode_handle *fwnode, + const char *childname) +{ + struct fwnode_handle *child; + + /* + * Find first matching named child node of this fwnode. + * For ACPI this will be a data only sub-node. + */ + fwnode_for_each_child_node(fwnode, child) + if (acpi_data_node_match(child, childname)) + return child; + + return NULL; +} + +static struct fwnode_handle * +acpi_fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode, + struct fwnode_handle *prev) +{ + struct fwnode_handle *endpoint; + + endpoint = acpi_graph_get_next_endpoint(fwnode, prev); + if (IS_ERR(endpoint)) + return NULL; + + return endpoint; +} + +static struct fwnode_handle * +acpi_fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode) +{ + struct fwnode_handle *endpoint = NULL; + + acpi_graph_get_remote_endpoint(fwnode, NULL, NULL, &endpoint); + + return endpoint; +} + +static int acpi_fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode, + struct fwnode_endpoint *endpoint) +{ + struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode); + + endpoint->local_fwnode = fwnode; + + fwnode_property_read_u32(port_fwnode, "port", &endpoint->port); + fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id); + + return 0; +} + +const struct fwnode_operations acpi_fwnode_ops = { + .device_is_available = acpi_fwnode_device_is_available, + .property_present = acpi_fwnode_property_present, + .property_read_int_array = acpi_fwnode_property_read_int_array, + .property_read_string_array = acpi_fwnode_property_read_string_array, + .get_parent = acpi_node_get_parent, + .get_next_child_node = acpi_get_next_subnode, + .get_named_child_node = acpi_fwnode_get_named_child_node, + .graph_get_next_endpoint = acpi_fwnode_graph_get_next_endpoint, + .graph_get_remote_endpoint = acpi_fwnode_graph_get_remote_endpoint, + .graph_get_port_parent = acpi_node_get_parent, + .graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint, +}; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index d53162997f32..33897298f03e 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -404,10 +404,6 @@ void acpi_device_hotplug(struct acpi_device *adev, u32 src) error = dock_notify(adev, src); } else if (adev->flags.hotplug_notify) { error = acpi_generic_hotplug_event(adev, src); - if (error == -EPERM) { - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - goto err_out; - } } else { int (*notify)(struct acpi_device *, u32); @@ -423,8 +419,20 @@ void acpi_device_hotplug(struct acpi_device *adev, u32 src) else goto out; } - if (!error) + switch (error) { + case 0: ost_code = ACPI_OST_SC_SUCCESS; + break; + case -EPERM: + ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; + break; + case -EBUSY: + ost_code = ACPI_OST_SC_DEVICE_BUSY; + break; + default: + ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; + break; + } err_out: acpi_evaluate_ost(adev->handle, src, ost_code, NULL); @@ -835,7 +843,7 @@ static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, return err; } -static void acpi_wakeup_gpe_init(struct acpi_device *device) +static bool acpi_wakeup_gpe_init(struct acpi_device *device) { static const struct acpi_device_id button_device_ids[] = { {"PNP0C0C", 0}, @@ -845,13 +853,11 @@ static void acpi_wakeup_gpe_init(struct acpi_device *device) }; struct acpi_device_wakeup *wakeup = &device->wakeup; acpi_status status; - acpi_event_status event_status; wakeup->flags.notifier_present = 0; /* Power button, Lid switch always enable wakeup */ if (!acpi_match_device_ids(device, button_device_ids)) { - wakeup->flags.run_wake = 1; if (!acpi_match_device_ids(device, &button_device_ids[1])) { /* Do not use Lid/sleep button for S5 wakeup */ if (wakeup->sleep_state == ACPI_STATE_S5) @@ -859,17 +865,12 @@ static void acpi_wakeup_gpe_init(struct acpi_device *device) } acpi_mark_gpe_for_wake(wakeup->gpe_device, wakeup->gpe_number); device_set_wakeup_capable(&device->dev, true); - return; + return true; } - acpi_setup_gpe_for_wake(device->handle, wakeup->gpe_device, - wakeup->gpe_number); - status = acpi_get_gpe_status(wakeup->gpe_device, wakeup->gpe_number, - &event_status); - if (ACPI_FAILURE(status)) - return; - - wakeup->flags.run_wake = !!(event_status & ACPI_EVENT_FLAG_HAS_HANDLER); + status = acpi_setup_gpe_for_wake(device->handle, wakeup->gpe_device, + wakeup->gpe_number); + return ACPI_SUCCESS(status); } static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) @@ -887,10 +888,10 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) return; } - device->wakeup.flags.valid = 1; + device->wakeup.flags.valid = acpi_wakeup_gpe_init(device); device->wakeup.prepare_count = 0; - acpi_wakeup_gpe_init(device); - /* Call _PSW/_DSW object to disable its ability to wake the sleeping + /* + * Call _PSW/_DSW object to disable its ability to wake the sleeping * system for the ACPI device with the _PRW object. * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW. * So it is necessary to call _DSW object first. Only when it is not @@ -1467,6 +1468,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, device->handle = handle; device->parent = acpi_bus_get_parent(handle); device->fwnode.type = FWNODE_ACPI; + device->fwnode.ops = &acpi_fwnode_ops; acpi_set_device_status(device, sta); acpi_device_get_busid(device); acpi_set_pnp_ids(handle, &device->pnp, type); @@ -1599,13 +1601,9 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, return 0; } -bool acpi_device_is_present(struct acpi_device *adev) +bool acpi_device_is_present(const struct acpi_device *adev) { - if (adev->status.present || adev->status.functional) - return true; - - adev->flags.initialized = false; - return false; + return adev->status.present || adev->status.functional; } static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler, @@ -1838,6 +1836,7 @@ static void acpi_bus_attach(struct acpi_device *device) acpi_bus_get_status(device); /* Skip devices that are not present. */ if (!acpi_device_is_present(device)) { + device->flags.initialized = false; acpi_device_clear_enumerated(device); device->flags.power_manageable = 0; return; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 097d630ab886..be17664736b2 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -650,38 +650,165 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = { .recover = acpi_pm_finish, }; +static bool s2idle_in_progress; +static bool s2idle_wakeup; + +/* + * On platforms supporting the Low Power S0 Idle interface there is an ACPI + * device object with the PNP0D80 compatible device ID (System Power Management + * Controller) and a specific _DSM method under it. That method, if present, + * can be used to indicate to the platform that the OS is transitioning into a + * low-power state in which certain types of activity are not desirable or that + * it is leaving such a state, which allows the platform to adjust its operation + * mode accordingly. + */ +static const struct acpi_device_id lps0_device_ids[] = { + {"PNP0D80", }, + {"", }, +}; + +#define ACPI_LPS0_DSM_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66" + +#define ACPI_LPS0_SCREEN_OFF 3 +#define ACPI_LPS0_SCREEN_ON 4 +#define ACPI_LPS0_ENTRY 5 +#define ACPI_LPS0_EXIT 6 + +#define ACPI_S2IDLE_FUNC_MASK ((1 << ACPI_LPS0_ENTRY) | (1 << ACPI_LPS0_EXIT)) + +static acpi_handle lps0_device_handle; +static guid_t lps0_dsm_guid; +static char lps0_dsm_func_mask; + +static void acpi_sleep_run_lps0_dsm(unsigned int func) +{ + union acpi_object *out_obj; + + if (!(lps0_dsm_func_mask & (1 << func))) + return; + + out_obj = acpi_evaluate_dsm(lps0_device_handle, &lps0_dsm_guid, 1, func, NULL); + ACPI_FREE(out_obj); + + acpi_handle_debug(lps0_device_handle, "_DSM function %u evaluation %s\n", + func, out_obj ? "successful" : "failed"); +} + +static int lps0_device_attach(struct acpi_device *adev, + const struct acpi_device_id *not_used) +{ + union acpi_object *out_obj; + + if (lps0_device_handle) + return 0; + + if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) + return 0; + + guid_parse(ACPI_LPS0_DSM_UUID, &lps0_dsm_guid); + /* Check if the _DSM is present and as expected. */ + out_obj = acpi_evaluate_dsm(adev->handle, &lps0_dsm_guid, 1, 0, NULL); + if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) { + char bitmask = *(char *)out_obj->buffer.pointer; + + if ((bitmask & ACPI_S2IDLE_FUNC_MASK) == ACPI_S2IDLE_FUNC_MASK) { + lps0_dsm_func_mask = bitmask; + lps0_device_handle = adev->handle; + } + + acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n", + bitmask); + } else { + acpi_handle_debug(adev->handle, + "_DSM function 0 evaluation failed\n"); + } + ACPI_FREE(out_obj); + return 0; +} + +static struct acpi_scan_handler lps0_handler = { + .ids = lps0_device_ids, + .attach = lps0_device_attach, +}; + static int acpi_freeze_begin(void) { acpi_scan_lock_acquire(); + s2idle_in_progress = true; return 0; } static int acpi_freeze_prepare(void) { - acpi_enable_wakeup_devices(ACPI_STATE_S0); - acpi_enable_all_wakeup_gpes(); - acpi_os_wait_events_complete(); + if (lps0_device_handle) { + acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF); + acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY); + } else { + /* + * The configuration of GPEs is changed here to avoid spurious + * wakeups, but that should not be necessary if this is a + * "low-power S0" platform and the low-power S0 _DSM is present. + */ + acpi_enable_all_wakeup_gpes(); + acpi_os_wait_events_complete(); + } if (acpi_sci_irq_valid()) enable_irq_wake(acpi_sci_irq); + return 0; } +static void acpi_freeze_wake(void) +{ + /* + * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means + * that the SCI has triggered while suspended, so cancel the wakeup in + * case it has not been a wakeup event (the GPEs will be checked later). + */ + if (acpi_sci_irq_valid() && + !irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) { + pm_system_cancel_wakeup(); + s2idle_wakeup = true; + } +} + +static void acpi_freeze_sync(void) +{ + /* + * Process all pending events in case there are any wakeup ones. + * + * The EC driver uses the system workqueue, so that one needs to be + * flushed too. + */ + acpi_os_wait_events_complete(); + flush_scheduled_work(); + s2idle_wakeup = false; +} + static void acpi_freeze_restore(void) { - acpi_disable_wakeup_devices(ACPI_STATE_S0); if (acpi_sci_irq_valid()) disable_irq_wake(acpi_sci_irq); - acpi_enable_all_runtime_gpes(); + + if (lps0_device_handle) { + acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT); + acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON); + } else { + acpi_enable_all_runtime_gpes(); + } } static void acpi_freeze_end(void) { + s2idle_in_progress = false; acpi_scan_lock_release(); } static const struct platform_freeze_ops acpi_freeze_ops = { .begin = acpi_freeze_begin, .prepare = acpi_freeze_prepare, + .wake = acpi_freeze_wake, + .sync = acpi_freeze_sync, .restore = acpi_freeze_restore, .end = acpi_freeze_end, }; @@ -696,13 +823,28 @@ static void acpi_sleep_suspend_setup(void) suspend_set_ops(old_suspend_ordering ? &acpi_suspend_ops_old : &acpi_suspend_ops); + + acpi_scan_add_handler(&lps0_handler); freeze_set_ops(&acpi_freeze_ops); } #else /* !CONFIG_SUSPEND */ +#define s2idle_in_progress (false) +#define s2idle_wakeup (false) +#define lps0_device_handle (NULL) static inline void acpi_sleep_suspend_setup(void) {} #endif /* !CONFIG_SUSPEND */ +bool acpi_s2idle_wakeup(void) +{ + return s2idle_wakeup; +} + +bool acpi_sleep_no_ec_events(void) +{ + return !s2idle_in_progress || !lps0_device_handle; +} + #ifdef CONFIG_PM_SLEEP static u32 saved_bm_rld; diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index 3afa8c1fa127..4ac3e06b41d8 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c @@ -36,6 +36,26 @@ static bool qdf2400_erratum_44_present(struct acpi_table_header *h) return false; } +/* + * APM X-Gene v1 and v2 UART hardware is an 16550 like device but has its + * register aligned to 32-bit. In addition, the BIOS also encoded the + * access width to be 8 bits. This function detects this errata condition. + */ +static bool xgene_8250_erratum_present(struct acpi_table_spcr *tb) +{ + if (tb->interface_type != ACPI_DBG2_16550_COMPATIBLE) + return false; + + if (memcmp(tb->header.oem_id, "APMC0D", 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; + + return false; +} + /** * parse_spcr() - parse ACPI SPCR table and add preferred console * @@ -74,8 +94,22 @@ int __init parse_spcr(bool earlycon) goto done; } - iotype = table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY ? - "mmio" : "io"; + if (table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + switch (table->serial_port.access_width) { + default: + pr_err("Unexpected SPCR Access Width. Defaulting to byte size\n"); + case ACPI_ACCESS_SIZE_BYTE: + iotype = "mmio"; + break; + case ACPI_ACCESS_SIZE_WORD: + iotype = "mmio16"; + break; + case ACPI_ACCESS_SIZE_DWORD: + iotype = "mmio32"; + break; + } + } else + iotype = "io"; switch (table->interface_type) { case ACPI_DBG2_ARM_SBSA_32BIT: @@ -115,6 +149,8 @@ int __init parse_spcr(bool earlycon) if (qdf2400_erratum_44_present(&table->header)) uart = "qdf2400_e44"; + 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); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 27d0dcfcf47d..b9d956c916f5 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -613,19 +613,19 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock) /** * acpi_evaluate_dsm - evaluate device's _DSM method * @handle: ACPI device handle - * @uuid: UUID of requested functions, should be 16 bytes + * @guid: GUID of requested functions, should be 16 bytes * @rev: revision number of requested function * @func: requested function number * @argv4: the function specific parameter * - * Evaluate device's _DSM method with specified UUID, revision id and + * Evaluate device's _DSM method with specified GUID, revision id and * function number. Caller needs to free the returned object. * * Though ACPI defines the fourth parameter for _DSM should be a package, * some old BIOSes do expect a buffer or an integer etc. */ union acpi_object * -acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 func, +acpi_evaluate_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 func, union acpi_object *argv4) { acpi_status ret; @@ -638,7 +638,7 @@ acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 func, params[0].type = ACPI_TYPE_BUFFER; params[0].buffer.length = 16; - params[0].buffer.pointer = (char *)uuid; + params[0].buffer.pointer = (u8 *)guid; params[1].type = ACPI_TYPE_INTEGER; params[1].integer.value = rev; params[2].type = ACPI_TYPE_INTEGER; @@ -666,7 +666,7 @@ EXPORT_SYMBOL(acpi_evaluate_dsm); /** * acpi_check_dsm - check if _DSM method supports requested functions. * @handle: ACPI device handle - * @uuid: UUID of requested functions, should be 16 bytes at least + * @guid: GUID of requested functions, should be 16 bytes at least * @rev: revision number of requested functions * @funcs: bitmap of requested functions * @@ -674,7 +674,7 @@ EXPORT_SYMBOL(acpi_evaluate_dsm); * functions. Currently only support 64 functions at maximum, should be * enough for now. */ -bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs) +bool acpi_check_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 funcs) { int i; u64 mask = 0; @@ -683,7 +683,7 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs) if (funcs == 0) return false; - obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL); + obj = acpi_evaluate_dsm(handle, guid, rev, 0, NULL); if (!obj) return false; @@ -697,7 +697,7 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs) /* * Bit 0 indicates whether there's support for any functions other than - * function 0 for the specified UUID and revision. + * function 0 for the specified GUID and revision. */ if ((mask & 0x1) && (mask & funcs) == funcs) return true; diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 7f48156cbc0c..d179e8d9177d 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -305,6 +305,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Dell System XPS L702X"), }, }, + { + .callback = video_detect_force_native, + .ident = "Dell Precision 7510", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7510"), + }, + }, { }, }; |