diff options
Diffstat (limited to 'drivers/acpi/acpica/tbfadt.c')
-rw-r--r-- | drivers/acpi/acpica/tbfadt.c | 363 |
1 files changed, 206 insertions, 157 deletions
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 3636e4f8fb73..71e655d14cb0 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -57,6 +57,8 @@ static void acpi_tb_convert_fadt(void); static void acpi_tb_validate_fadt(void); +static void acpi_tb_setup_fadt_registers(void); + /* Table for conversion of FADT to common internal format and FADT validation */ typedef struct acpi_fadt_info { @@ -130,7 +132,38 @@ static struct acpi_fadt_info fadt_info_table[] = { ACPI_FADT_SEPARATE_LENGTH} }; -#define ACPI_FADT_INFO_ENTRIES (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info)) +#define ACPI_FADT_INFO_ENTRIES \ + (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info)) + +/* Table used to split Event Blocks into separate status/enable registers */ + +typedef struct acpi_fadt_pm_info { + struct acpi_generic_address *target; + u8 source; + u8 register_num; + +} acpi_fadt_pm_info; + +static struct acpi_fadt_pm_info fadt_pm_info_table[] = { + {&acpi_gbl_xpm1a_status, + ACPI_FADT_OFFSET(xpm1a_event_block), + 0}, + + {&acpi_gbl_xpm1a_enable, + ACPI_FADT_OFFSET(xpm1a_event_block), + 1}, + + {&acpi_gbl_xpm1b_status, + ACPI_FADT_OFFSET(xpm1b_event_block), + 0}, + + {&acpi_gbl_xpm1b_enable, + ACPI_FADT_OFFSET(xpm1b_event_block), + 1} +}; + +#define ACPI_FADT_PM_INFO_ENTRIES \ + (sizeof (fadt_pm_info_table) / sizeof (struct acpi_fadt_pm_info)) /******************************************************************************* * @@ -172,7 +205,6 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, * FUNCTION: acpi_tb_parse_fadt * * PARAMETERS: table_index - Index for the FADT - * Flags - Flags * * RETURN: None * @@ -181,7 +213,7 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, * ******************************************************************************/ -void acpi_tb_parse_fadt(u32 table_index, u8 flags) +void acpi_tb_parse_fadt(u32 table_index) { u32 length; struct acpi_table_header *table; @@ -208,7 +240,7 @@ void acpi_tb_parse_fadt(u32 table_index, u8 flags) */ (void)acpi_tb_verify_checksum(table, length); - /* Obtain a local copy of the FADT in common ACPI 2.0+ format */ + /* Create a local copy of the FADT in common ACPI 2.0+ format */ acpi_tb_create_local_fadt(table, length); @@ -219,10 +251,10 @@ void acpi_tb_parse_fadt(u32 table_index, u8 flags) /* Obtain the DSDT and FACS tables via their addresses within the FADT */ acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, - flags, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); + ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs, - flags, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS); + ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS); } /******************************************************************************* @@ -266,11 +298,17 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) ACPI_MEMCPY(&acpi_gbl_FADT, table, ACPI_MIN(length, sizeof(struct acpi_table_fadt))); - /* - * 1) Convert the local copy of the FADT to the common internal format - * 2) Validate some of the important values within the FADT - */ + /* Convert the local copy of the FADT to the common internal format */ + 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(); } /******************************************************************************* @@ -282,31 +320,35 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) * RETURN: None * * DESCRIPTION: Converts all versions of the FADT to a common internal format. - * Expand all 32-bit addresses to 64-bit. + * Expand 32-bit addresses to 64-bit as necessary. * * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), * and must contain a copy of the actual FADT. * - * ACPICA will use the "X" fields of the FADT for all addresses. + * 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. * - * "X" fields are optional extensions to the original V1.0 fields. Even if - * they are present in the structure, they can be optionally not used by - * setting them to zero. Therefore, we must selectively expand V1.0 fields - * if the corresponding X field is zero. + * 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. * - * For ACPI 1.0 FADTs, all address fields are expanded to the corresponding - * "X" fields. + * For ACPI 1.0 FADTs, all 32-bit address fields are expanded to the + * corresponding "X" fields in the internal FADT. * - * For ACPI 2.0 FADTs, any "X" fields that are NULL are filled in by - * expanding the corresponding ACPI 1.0 field. + * 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. * ******************************************************************************/ static void acpi_tb_convert_fadt(void) { - u8 pm1_register_bit_width; - u8 pm1_register_byte_width; - struct acpi_generic_address *target64; + struct acpi_generic_address *address64; + u32 address32; u32 i; /* Update the local FADT table header length */ @@ -355,140 +397,56 @@ static void acpi_tb_convert_fadt(void) * 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. */ for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { - target64 = - ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, - fadt_info_table[i].address64); + address32 = *ACPI_ADD_PTR(u32, + &acpi_gbl_FADT, + fadt_info_table[i].address32); - /* Expand only if the 64-bit X target is null */ + address64 = ACPI_ADD_PTR(struct acpi_generic_address, + &acpi_gbl_FADT, + fadt_info_table[i].address64); - if (!target64->address) { + /* + * If both 32- and 64-bit addresses are valid (non-zero), + * they must match. + */ + if (address64->address && address32 && + (address64->address != (u64) address32)) { + ACPI_ERROR((AE_INFO, + "32/64X address mismatch in %s: %8.8X/%8.8X%8.8X, using 32", + fadt_info_table[i].name, address32, + ACPI_FORMAT_UINT64(address64->address))); + } - /* The space_id is always I/O for the 32-bit legacy address fields */ + /* Always use 32-bit address if it is valid (non-null) */ - acpi_tb_init_generic_address(target64, + 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) * ACPI_ADD_PTR(u32, - &acpi_gbl_FADT, - fadt_info_table - [i]. - address32)); - } - } - - /* Validate FADT values now, before we make any changes */ - - acpi_tb_validate_fadt(); - - /* - * Optionally check all register lengths against the default values and - * update them if they are incorrect. - */ - if (acpi_gbl_use_default_register_widths) { - for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { - target64 = - ACPI_ADD_PTR(struct acpi_generic_address, - &acpi_gbl_FADT, - fadt_info_table[i].address64); - - /* - * If a valid register (Address != 0) and the (default_length > 0) - * (Not a GPE register), then check the width against the default. - */ - if ((target64->address) && - (fadt_info_table[i].default_length > 0) && - (fadt_info_table[i].default_length != - target64->bit_width)) { - ACPI_WARNING((AE_INFO, - "Invalid length for %s: %d, using default %d", - fadt_info_table[i].name, - target64->bit_width, - fadt_info_table[i]. - default_length)); - - /* Incorrect size, set width to the default */ - - target64->bit_width = - fadt_info_table[i].default_length; - } + address32); } } - - /* - * Get the length of the individual PM1 registers (enable and status). - * Each register is defined to be (event block length / 2). - */ - pm1_register_bit_width = - (u8)ACPI_DIV_2(acpi_gbl_FADT.xpm1a_event_block.bit_width); - pm1_register_byte_width = (u8)ACPI_DIV_8(pm1_register_bit_width); - - /* - * Adjust the lengths of the PM1 Event Blocks so that they can be used to - * access the PM1 status register(s). Use (width / 2) - */ - acpi_gbl_FADT.xpm1a_event_block.bit_width = pm1_register_bit_width; - acpi_gbl_FADT.xpm1b_event_block.bit_width = pm1_register_bit_width; - - /* - * Calculate separate GAS structs for the PM1 Enable registers. - * These addresses do not appear (directly) in the FADT, so it is - * useful to calculate them once, here. - * - * The PM event blocks are split into two register blocks, first is the - * PM Status Register block, followed immediately by the PM Enable - * Register block. Each is of length (xpm1x_event_block.bit_width/2). - * - * On various systems the v2 fields (and particularly the bit widths) - * cannot be relied upon, though. Hence resort to using the v1 length - * here (and warn about the inconsistency). - */ - if (acpi_gbl_FADT.xpm1a_event_block.bit_width - != acpi_gbl_FADT.pm1_event_length * 8) - printk(KERN_WARNING "FADT: " - "X_PM1a_EVT_BLK.bit_width (%u) does not match" - " PM1_EVT_LEN (%u)\n", - acpi_gbl_FADT.xpm1a_event_block.bit_width, - acpi_gbl_FADT.pm1_event_length); - - /* The PM1A register block is required */ - - acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable, - acpi_gbl_FADT.xpm1a_event_block.space_id, - pm1_register_byte_width, - (acpi_gbl_FADT.xpm1a_event_block.address + - pm1_register_byte_width)); - /* Don't forget to copy space_id of the GAS */ - acpi_gbl_xpm1a_enable.space_id = - acpi_gbl_FADT.xpm1a_event_block.space_id; - - /* The PM1B register block is optional, ignore if not present */ - - if (acpi_gbl_FADT.xpm1b_event_block.address) { - if (acpi_gbl_FADT.xpm1b_event_block.bit_width - != acpi_gbl_FADT.pm1_event_length * 8) - printk(KERN_WARNING "FADT: " - "X_PM1b_EVT_BLK.bit_width (%u) does not match" - " PM1_EVT_LEN (%u)\n", - acpi_gbl_FADT.xpm1b_event_block.bit_width, - acpi_gbl_FADT.pm1_event_length); - acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, - acpi_gbl_FADT.xpm1b_event_block.space_id, - pm1_register_byte_width, - (acpi_gbl_FADT.xpm1b_event_block. - address + pm1_register_byte_width)); - /* Don't forget to copy space_id of the GAS */ - acpi_gbl_xpm1b_enable.space_id = - acpi_gbl_FADT.xpm1b_event_block.space_id; - - } } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_tb_validate_fadt * @@ -525,18 +483,22 @@ static void acpi_tb_validate_fadt(void) (acpi_gbl_FADT.Xfacs != (u64) acpi_gbl_FADT.facs)) { ACPI_WARNING((AE_INFO, "32/64X FACS address mismatch in FADT - " - "two FACS tables! %8.8X/%8.8X%8.8X", + "%8.8X/%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_WARNING((AE_INFO, "32/64X DSDT address mismatch in FADT - " - "two DSDT tables! %8.8X/%8.8X%8.8X", + "%8.8X/%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; } /* Examine all of the 64-bit extended address fields (X fields) */ @@ -561,7 +523,8 @@ static void acpi_tb_validate_fadt(void) * For each extended field, check for length mismatch between the * legacy length field and the corresponding 64-bit X length field. */ - if (address64 && (address64->bit_width != ACPI_MUL_8(length))) { + if (address64->address && + (address64->bit_width != ACPI_MUL_8(length))) { ACPI_WARNING((AE_INFO, "32/64X length mismatch in %s: %d/%d", name, ACPI_MUL_8(length), @@ -575,7 +538,8 @@ static void acpi_tb_validate_fadt(void) */ if (!address64->address || !length) { ACPI_ERROR((AE_INFO, - "Required field %s has zero address and/or length: %8.8X%8.8X/%X", + "Required field %s has zero address and/or length:" + " %8.8X%8.8X/%X", name, ACPI_FORMAT_UINT64(address64-> address), @@ -584,27 +548,112 @@ static void acpi_tb_validate_fadt(void) } else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) { /* * Field is optional (PM2Control, GPE0, GPE1) AND has its own - * length field. If present, both the address and length must be valid. + * length field. If present, both the address and length must + * be valid. */ - if ((address64->address && !length) - || (!address64->address && length)) { + if ((address64->address && !length) || + (!address64->address && length)) { ACPI_WARNING((AE_INFO, - "Optional field %s has zero address or length: %8.8X%8.8X/%X", + "Optional field %s has zero address or length: " + "%8.8X%8.8X/%X", name, ACPI_FORMAT_UINT64(address64-> address), length)); } } + } +} - /* If both 32- and 64-bit addresses are valid (non-zero), they must match */ +/******************************************************************************* + * + * FUNCTION: acpi_tb_setup_fadt_registers + * + * PARAMETERS: None, uses acpi_gbl_FADT. + * + * RETURN: None + * + * DESCRIPTION: Initialize global ACPI PM1 register definitions. Optionally, + * force FADT register definitions to their default lengths. + * + ******************************************************************************/ - if (address64->address && *address32 && - (address64->address != (u64) * address32)) { - ACPI_ERROR((AE_INFO, - "32/64X address mismatch in %s: %8.8X/%8.8X%8.8X, using 64X", - name, *address32, - ACPI_FORMAT_UINT64(address64->address))); +static void acpi_tb_setup_fadt_registers(void) +{ + struct acpi_generic_address *target64; + struct acpi_generic_address *source64; + u8 pm1_register_byte_width; + u32 i; + + /* + * Optionally check all register lengths against the default values and + * update them if they are incorrect. + */ + if (acpi_gbl_use_default_register_widths) { + for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { + target64 = + ACPI_ADD_PTR(struct acpi_generic_address, + &acpi_gbl_FADT, + fadt_info_table[i].address64); + + /* + * If a valid register (Address != 0) and the (default_length > 0) + * (Not a GPE register), then check the width against the default. + */ + if ((target64->address) && + (fadt_info_table[i].default_length > 0) && + (fadt_info_table[i].default_length != + target64->bit_width)) { + ACPI_WARNING((AE_INFO, + "Invalid length for %s: %d, using default %d", + fadt_info_table[i].name, + target64->bit_width, + fadt_info_table[i]. + default_length)); + + /* Incorrect size, set width to the default */ + + target64->bit_width = + fadt_info_table[i].default_length; + } + } + } + + /* + * Get the length of the individual PM1 registers (enable and status). + * Each register is defined to be (event block length / 2). Extra divide + * by 8 converts bits to bytes. + */ + pm1_register_byte_width = (u8) + ACPI_DIV_16(acpi_gbl_FADT.xpm1a_event_block.bit_width); + + /* + * Calculate separate GAS structs for the PM1x (A/B) Status and Enable + * registers. These addresses do not appear (directly) in the FADT, so it + * is useful to pre-calculate them from the PM1 Event Block definitions. + * + * The PM event blocks are split into two register blocks, first is the + * PM Status Register block, followed immediately by the PM Enable + * Register block. Each is of length (pm1_event_length/2) + * + * Note: The PM1A event block is required by the ACPI specification. + * However, the PM1B event block is optional and is rarely, if ever, + * used. + */ + + for (i = 0; i < ACPI_FADT_PM_INFO_ENTRIES; i++) { + source64 = + ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, + fadt_pm_info_table[i].source); + + if (source64->address) { + acpi_tb_init_generic_address(fadt_pm_info_table[i]. + target, source64->space_id, + pm1_register_byte_width, + source64->address + + (fadt_pm_info_table[i]. + register_num * + pm1_register_byte_width)); } } } |