diff -r b320cfe1f10f xen/arch/x86/acpi/boot.c --- a/xen/arch/x86/acpi/boot.c Thu Jun 05 13:04:07 2008 +0100 +++ b/xen/arch/x86/acpi/boot.c Fri Jun 06 16:19:48 2008 +0800 @@ -39,6 +39,53 @@ #include #include #include + +typedef struct acpi_fadt_info { + char *name; + u8 target; + u8 source; + u8 length; + u8 type; +} acpi_fadt_info; + +#define ACPI_FADT_REQUIRED 1 +#define ACPI_FADT_SEPARATE_LENGTH 2 + +static struct acpi_fadt_info fadt_info_table[] = { + {"Pm1aEventBlock", ACPI_FADT_OFFSET(xpm1a_event_block), + ACPI_FADT_OFFSET(pm1a_event_block), + ACPI_FADT_OFFSET(pm1_event_length), ACPI_FADT_REQUIRED}, + + {"Pm1bEventBlock", ACPI_FADT_OFFSET(xpm1b_event_block), + ACPI_FADT_OFFSET(pm1b_event_block), + ACPI_FADT_OFFSET(pm1_event_length), 0}, + + {"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block), + ACPI_FADT_OFFSET(pm1a_control_block), + ACPI_FADT_OFFSET(pm1_control_length), ACPI_FADT_REQUIRED}, + + {"Pm1bControlBlock", ACPI_FADT_OFFSET(xpm1b_control_block), + ACPI_FADT_OFFSET(pm1b_control_block), + ACPI_FADT_OFFSET(pm1_control_length), 0}, + + {"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block), + ACPI_FADT_OFFSET(pm2_control_block), + ACPI_FADT_OFFSET(pm2_control_length), ACPI_FADT_SEPARATE_LENGTH}, + + {"PmTimerBlock", ACPI_FADT_OFFSET(xpm_timer_block), + ACPI_FADT_OFFSET(pm_timer_block), + ACPI_FADT_OFFSET(pm_timer_length), ACPI_FADT_REQUIRED}, + + {"Gpe0Block", ACPI_FADT_OFFSET(xgpe0_block), + ACPI_FADT_OFFSET(gpe0_block), + ACPI_FADT_OFFSET(gpe0_block_length), ACPI_FADT_SEPARATE_LENGTH}, + + {"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block), + ACPI_FADT_OFFSET(gpe1_block), + ACPI_FADT_OFFSET(gpe1_block_length), ACPI_FADT_SEPARATE_LENGTH} +}; + +#define ACPI_FADT_INFO_ENTRIES (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info)) int sbf_port; #define CONFIG_ACPI_PCI @@ -454,26 +501,60 @@ } #endif +static void inline +acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, + u8 bit_width, u64 address) +{ + /* + * The 64-bit Address field is non-aligned in the byte packed + * GAS struct. + */ + ACPI_MOVE_64_TO_64(&generic_address->address, &address); + + /* All other fields are byte-wide */ + + generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO; + generic_address->bit_width = bit_width; + generic_address->bit_offset = 0; + generic_address->access_width = 0; +} + + static void __init acpi_fadt_parse_reg(struct acpi_table_fadt *fadt) { - unsigned int len; + unsigned int len, i; + struct acpi_generic_address *target; len = min_t(unsigned int, fadt->header.length, sizeof(*fadt)); memcpy(&acpi_gbl_FADT, fadt, len); - if (len > offsetof(struct acpi_table_fadt, xpm1b_event_block)) { - memcpy(&acpi_gbl_xpm1a_enable, &fadt->xpm1a_event_block, - sizeof(acpi_gbl_xpm1a_enable)); - memcpy(&acpi_gbl_xpm1b_enable, &fadt->xpm1b_event_block, - sizeof(acpi_gbl_xpm1b_enable)); + /* If ACPI 1.0, convert into ACPI 2.0+ format*/ + for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { + target = ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, + fadt_info_table[i].target); - acpi_gbl_xpm1a_enable.address += + /* Expand only if the X target is null */ + + if (!target->address) { + acpi_tb_init_generic_address(target, + *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, + fadt_info_table[i].length), + (u64) * ACPI_ADD_PTR(u32, &acpi_gbl_FADT, + fadt_info_table[i].source)); + } + } + + memcpy(&acpi_gbl_xpm1a_enable, &acpi_gbl_FADT.xpm1a_event_block, + sizeof(acpi_gbl_xpm1a_enable)); + memcpy(&acpi_gbl_xpm1b_enable, &acpi_gbl_FADT.xpm1b_event_block, + sizeof(acpi_gbl_xpm1b_enable)); + + acpi_gbl_xpm1a_enable.address += + acpi_gbl_FADT.pm1_event_length / 2; + if ( acpi_gbl_xpm1b_enable.address ) + acpi_gbl_xpm1b_enable.address += acpi_gbl_FADT.pm1_event_length / 2; - if ( acpi_gbl_xpm1b_enable.address ) - acpi_gbl_xpm1b_enable.address += - acpi_gbl_FADT.pm1_event_length / 2; - } } static int __init acpi_parse_fadt(unsigned long phys, unsigned long size)