diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index cffb45742aa5..268699879904 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -126,6 +126,16 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE); */ u8 ACPI_INIT_GLOBAL(acpi_gbl_do_not_use_xsdt, FALSE); +/* + * Optionally use 32-bit FADT addresses if and when there is a conflict + * (address mismatch) between the 32-bit and 64-bit versions of the + * address. Although ACPICA adheres to the ACPI specification which + * requires the use of the corresponding 64-bit address if it is non-zero, + * some machines have been found to have a corrupted non-zero 64-bit + * address. Default is FALSE, do not favor the 32-bit addresses. + */ +u8 ACPI_INIT_GLOBAL(acpi_gbl_use32_bit_fadt_addresses, FALSE); + /* * Optionally truncate I/O addresses to 16 bits. Provides compatibility * with other ACPI implementations. NOTE: During ACPICA initialization, diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 9d99f2189693..8f89263ac47e 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -56,10 +56,11 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, static void acpi_tb_convert_fadt(void); -static void acpi_tb_validate_fadt(void); - static void acpi_tb_setup_fadt_registers(void); +static u64 +acpi_tb_select_address(char *register_name, u32 address32, u64 address64); + /* Table for conversion of FADT to common internal format and FADT validation */ typedef struct acpi_fadt_info { @@ -175,6 +176,7 @@ static struct acpi_fadt_pm_info fadt_pm_info_table[] = { * space_id - ACPI Space ID for this register * byte_width - Width of this register * address - Address of the register + * register_name - ASCII name of the ACPI register * * RETURN: None * @@ -218,6 +220,68 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, generic_address->access_width = 0; /* Access width ANY */ } +/******************************************************************************* + * + * FUNCTION: acpi_tb_select_address + * + * PARAMETERS: register_name - ASCII name of the ACPI register + * address32 - 32-bit address of the register + * address64 - 64-bit address of the register + * + * RETURN: The resolved 64-bit address + * + * DESCRIPTION: Select between 32-bit and 64-bit versions of addresses within + * the FADT. Used for the FACS and DSDT addresses. + * + * NOTES: + * + * Check for FACS and DSDT address mismatches. An address mismatch between + * the 32-bit and 64-bit address fields (FIRMWARE_CTRL/X_FIRMWARE_CTRL and + * DSDT/X_DSDT) could be a corrupted address field or it might indicate + * the presence of two FACS or two DSDT tables. + * + * November 2013: + * By default, as per the ACPICA specification, a valid 64-bit address is + * used regardless of the value of the 32-bit address. However, this + * behavior can be overridden via the acpi_gbl_use32_bit_fadt_addresses flag. + * + ******************************************************************************/ + +static u64 +acpi_tb_select_address(char *register_name, u32 address32, u64 address64) +{ + + if (!address64) { + + /* 64-bit address is zero, use 32-bit address */ + + return ((u64)address32); + } + + if (address32 && (address64 != (u64)address32)) { + + /* Address mismatch between 32-bit and 64-bit versions */ + + ACPI_BIOS_WARNING((AE_INFO, + "32/64X %s address mismatch in FADT: " + "0x%8.8X/0x%8.8X%8.8X, using %u-bit address", + register_name, address32, + ACPI_FORMAT_UINT64(address64), + acpi_gbl_use32_bit_fadt_addresses ? 32 : + 64)); + + /* 32-bit address override */ + + if (acpi_gbl_use32_bit_fadt_addresses) { + return ((u64)address32); + } + } + + /* Default is to use the 64-bit address */ + + return (address64); +} + /******************************************************************************* * * FUNCTION: acpi_tb_parse_fadt @@ -331,10 +395,6 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) acpi_tb_convert_fadt(); - /* Validate FADT values now, before we make any changes */ - - acpi_tb_validate_fadt(); - /* Initialize the global ACPI register structures */ acpi_tb_setup_fadt_registers(); @@ -344,65 +404,54 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) * * FUNCTION: acpi_tb_convert_fadt * - * PARAMETERS: None, uses acpi_gbl_FADT + * PARAMETERS: none - acpi_gbl_FADT is used. * * RETURN: None * * DESCRIPTION: Converts all versions of the FADT to a common internal format. - * Expand 32-bit addresses to 64-bit as necessary. + * Expand 32-bit addresses to 64-bit as necessary. Also validate + * important fields within the FADT. * - * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), - * and must contain a copy of the actual FADT. + * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), and must + * contain a copy of the actual BIOS-provided FADT. * * Notes on 64-bit register addresses: * * After this FADT conversion, later ACPICA code will only use the 64-bit "X" * fields of the FADT for all ACPI register addresses. * - * The 64-bit "X" fields are optional extensions to the original 32-bit FADT + * 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 if the corresponding X field is zero. + * 32-bit V1.0 fields to the 64-bit X fields if the the 64-bit X field is + * originally zero. * - * For ACPI 1.0 FADTs, all 32-bit address fields are expanded to the - * corresponding "X" fields in the internal FADT. + * 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 + * common FADT. * * For ACPI 2.0+ FADTs, all valid (non-zero) 32-bit address fields are expanded - * to the corresponding 64-bit X fields. For compatibility with other ACPI - * implementations, we ignore the 64-bit field if the 32-bit field is valid, - * regardless of whether the host OS is 32-bit or 64-bit. + * to the corresponding 64-bit X fields, if the 64-bit field is originally + * zero. Adhering to the ACPI specification, we completely ignore the 32-bit + * field if the 64-bit field is valid, regardless of whether the host OS is + * 32-bit or 64-bit. + * + * Possible additional checks: + * (acpi_gbl_FADT.pm1_event_length >= 4) + * (acpi_gbl_FADT.pm1_control_length >= 2) + * (acpi_gbl_FADT.pm_timer_length >= 4) + * Gpe block lengths must be multiple of 2 * ******************************************************************************/ static void acpi_tb_convert_fadt(void) { + char *name; struct acpi_generic_address *address64; u32 address32; + u8 length; u32 i; - /* - * Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary. - * Later code will always use the X 64-bit field. Also, check for an - * address mismatch between the 32-bit and 64-bit address fields - * (FIRMWARE_CTRL/X_FIRMWARE_CTRL, DSDT/X_DSDT) which would indicate - * the presence of two FACS or two DSDT tables. - */ - if (!acpi_gbl_FADT.Xfacs) { - acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs; - } else if (acpi_gbl_FADT.facs && - (acpi_gbl_FADT.Xfacs != (u64) acpi_gbl_FADT.facs)) { - ACPI_WARNING((AE_INFO, - "32/64 FACS address mismatch in FADT - two FACS tables!")); - } - - if (!acpi_gbl_FADT.Xdsdt) { - acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt; - } else if (acpi_gbl_FADT.dsdt && - (acpi_gbl_FADT.Xdsdt != (u64) acpi_gbl_FADT.dsdt)) { - ACPI_WARNING((AE_INFO, - "32/64 DSDT address mismatch in FADT - two DSDT tables!")); - } - /* * For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which * should be zero are indeed zero. This will workaround BIOSs that @@ -421,119 +470,24 @@ static void acpi_tb_convert_fadt(void) acpi_gbl_FADT.boot_flags = 0; } - /* Update the local FADT table header length */ - + /* + * Now we can update the local FADT length to the length of the + * current FADT version as defined by the ACPI specification. + * Thus, we will have a common FADT internally. + */ acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); /* - * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" - * generic address structures as necessary. Later code will always use - * the 64-bit address structures. - * - * March 2009: - * We now always use the 32-bit address if it is valid (non-null). This - * is not in accordance with the ACPI specification which states that - * the 64-bit address supersedes the 32-bit version, but we do this for - * compatibility with other ACPI implementations. Most notably, in the - * case where both the 32 and 64 versions are non-null, we use the 32-bit - * version. This is the only address that is guaranteed to have been - * tested by the BIOS manufacturer. + * Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary. + * Later ACPICA code will always use the X 64-bit field. */ - for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { - address32 = *ACPI_ADD_PTR(u32, - &acpi_gbl_FADT, - fadt_info_table[i].address32); + acpi_gbl_FADT.Xfacs = acpi_tb_select_address("FACS", + acpi_gbl_FADT.facs, + acpi_gbl_FADT.Xfacs); - address64 = ACPI_ADD_PTR(struct acpi_generic_address, - &acpi_gbl_FADT, - fadt_info_table[i].address64); - - /* - * If both 32- and 64-bit addresses are valid (non-zero), - * they must match. - */ - if (address64->address && address32 && - (address64->address != (u64)address32)) { - ACPI_BIOS_ERROR((AE_INFO, - "32/64X address mismatch in FADT/%s: " - "0x%8.8X/0x%8.8X%8.8X, using 32", - fadt_info_table[i].name, address32, - ACPI_FORMAT_UINT64(address64-> - address))); - } - - /* Always use 32-bit address if it is valid (non-null) */ - - if (address32) { - /* - * Copy the 32-bit address to the 64-bit GAS structure. The - * Space ID is always I/O for 32-bit legacy address fields - */ - acpi_tb_init_generic_address(address64, - ACPI_ADR_SPACE_SYSTEM_IO, - *ACPI_ADD_PTR(u8, - &acpi_gbl_FADT, - fadt_info_table - [i].length), - (u64) address32, - fadt_info_table[i].name); - } - } -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_validate_fadt - * - * PARAMETERS: table - Pointer to the FADT to be validated - * - * RETURN: None - * - * DESCRIPTION: Validate various important fields within the FADT. If a problem - * is found, issue a message, but no status is returned. - * Used by both the table manager and the disassembler. - * - * Possible additional checks: - * (acpi_gbl_FADT.pm1_event_length >= 4) - * (acpi_gbl_FADT.pm1_control_length >= 2) - * (acpi_gbl_FADT.pm_timer_length >= 4) - * Gpe block lengths must be multiple of 2 - * - ******************************************************************************/ - -static void acpi_tb_validate_fadt(void) -{ - char *name; - struct acpi_generic_address *address64; - u8 length; - u32 i; - - /* - * Check for FACS and DSDT address mismatches. An address mismatch between - * the 32-bit and 64-bit address fields (FIRMWARE_CTRL/X_FIRMWARE_CTRL and - * DSDT/X_DSDT) would indicate the presence of two FACS or two DSDT tables. - */ - if (acpi_gbl_FADT.facs && - (acpi_gbl_FADT.Xfacs != (u64)acpi_gbl_FADT.facs)) { - ACPI_BIOS_WARNING((AE_INFO, - "32/64X FACS address mismatch in FADT - " - "0x%8.8X/0x%8.8X%8.8X, using 32", - acpi_gbl_FADT.facs, - ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xfacs))); - - acpi_gbl_FADT.Xfacs = (u64)acpi_gbl_FADT.facs; - } - - if (acpi_gbl_FADT.dsdt && - (acpi_gbl_FADT.Xdsdt != (u64)acpi_gbl_FADT.dsdt)) { - ACPI_BIOS_WARNING((AE_INFO, - "32/64X DSDT address mismatch in FADT - " - "0x%8.8X/0x%8.8X%8.8X, using 32", - acpi_gbl_FADT.dsdt, - ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xdsdt))); - - acpi_gbl_FADT.Xdsdt = (u64)acpi_gbl_FADT.dsdt; - } + acpi_gbl_FADT.Xdsdt = acpi_tb_select_address("DSDT", + acpi_gbl_FADT.dsdt, + acpi_gbl_FADT.Xdsdt); /* If Hardware Reduced flag is set, we are all done */ @@ -545,17 +499,94 @@ static void acpi_tb_validate_fadt(void) for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { /* - * Generate pointer to the 64-bit address, get the register - * length (width) and the register name + * Get the 32-bit and 64-bit addresses, as well as the register + * length and register name. */ + address32 = *ACPI_ADD_PTR(u32, + &acpi_gbl_FADT, + fadt_info_table[i].address32); + address64 = ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, fadt_info_table[i].address64); - length = - *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, - fadt_info_table[i].length); + + length = *ACPI_ADD_PTR(u8, + &acpi_gbl_FADT, + fadt_info_table[i].length); + name = fadt_info_table[i].name; + /* + * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" + * generic address structures as necessary. Later code will always use + * the 64-bit address structures. + * + * November 2013: + * Now always use the 64-bit address if it is valid (non-zero), in + * accordance with the ACPI specification which states that a 64-bit + * address supersedes the 32-bit version. This behavior can be + * overridden by the acpi_gbl_use32_bit_fadt_addresses flag. + * + * During 64-bit address construction and verification, + * these cases are handled: + * + * Address32 zero, Address64 [don't care] - Use Address64 + * + * Address32 non-zero, Address64 zero - Copy/use Address32 + * Address32 non-zero == Address64 non-zero - Use Address64 + * Address32 non-zero != Address64 non-zero - Warning, use Address64 + * + * Override: if acpi_gbl_use32_bit_fadt_addresses is TRUE, and: + * Address32 non-zero != Address64 non-zero - Warning, copy/use Address32 + * + * Note: space_id is always I/O for 32-bit legacy address fields + */ + if (address32) { + if (!address64->address) { + + /* 64-bit address is zero, use 32-bit address */ + + acpi_tb_init_generic_address(address64, + ACPI_ADR_SPACE_SYSTEM_IO, + *ACPI_ADD_PTR(u8, + &acpi_gbl_FADT, + fadt_info_table + [i]. + length), + (u64)address32, + name); + } else if (address64->address != (u64)address32) { + + /* Address mismatch */ + + ACPI_BIOS_WARNING((AE_INFO, + "32/64X address mismatch in FADT/%s: " + "0x%8.8X/0x%8.8X%8.8X, using %u-bit address", + name, address32, + ACPI_FORMAT_UINT64 + (address64->address), + acpi_gbl_use32_bit_fadt_addresses + ? 32 : 64)); + + if (acpi_gbl_use32_bit_fadt_addresses) { + + /* 32-bit address override */ + + acpi_tb_init_generic_address(address64, + ACPI_ADR_SPACE_SYSTEM_IO, + *ACPI_ADD_PTR + (u8, + &acpi_gbl_FADT, + fadt_info_table + [i]. + length), + (u64) + address32, + name); + } + } + } + /* * For each extended field, check for length mismatch between the * legacy length field and the corresponding 64-bit X length field. diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 30b01f889538..01ba80b1f91f 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -82,6 +82,7 @@ extern u8 acpi_gbl_enable_interpreter_slack; extern u32 acpi_gbl_trace_flags; extern acpi_name acpi_gbl_trace_method_name; extern u8 acpi_gbl_truncate_io_addresses; +extern u8 acpi_gbl_use32_bit_fadt_addresses; extern u8 acpi_gbl_use_default_register_widths; /*