Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=9f3119b70cf189530f1b46a006a052e171a1622f
Commit:     9f3119b70cf189530f1b46a006a052e171a1622f
Parent:     b377fd3982ad957c796758a90e2988401a884241
Author:     Zhao Yakui <[EMAIL PROTECTED]>
AuthorDate: Fri Aug 24 16:18:16 2007 +0800
Committer:  Len Brown <[EMAIL PROTECTED]>
CommitDate: Fri Aug 24 18:46:25 2007 -0400

    ACPI: Validate XSDT, use RSDT if XSDT fails
    
    ACPI 1.0 used an RSDT with 32-bit physical addresses.
    ACPI 2.0 adds an XSDT with 32-bit physical addresses.
    An ACPI 2.0 aware OS is supposed to use the XSDT
    (when present) instead of the RSDT.
    
    However, several systems have failed because the XSDT
    contains NULL entries -- while it is missing pointers
    to needed tables, such as SSDTs.
    
    When we find an XSDT with NULL entries, discard it
    and use the ACPI 1.0 RSDT instead.
    
    http://bugzilla.kernel.org/show_bug.cgi?id=8630
    
    Signed-off-by: Zhao Yakui  <[EMAIL PROTECTED]>
    Signed-off-by: Len Brown <[EMAIL PROTECTED]>
---
 drivers/acpi/tables/tbutils.c |   71 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 71 insertions(+), 0 deletions(-)

diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index 1da64b4..8cc9492 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -51,6 +51,65 @@ ACPI_MODULE_NAME("tbutils")
 static acpi_physical_address
 acpi_tb_get_root_table_entry(u8 * table_entry,
                             acpi_native_uint table_entry_size);
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_check_xsdt
+ *
+ * PARAMETERS:  address                    - Pointer to the XSDT
+ *
+ * RETURN:      status
+ *             AE_OK - XSDT is okay
+ *             AE_NO_MEMORY - can't map XSDT
+ *             AE_INVALID_TABLE_LENGTH - invalid table length
+ *             AE_NULL_ENTRY - XSDT has NULL entry
+ *
+ * DESCRIPTION: validate XSDT
+******************************************************************************/
+
+static acpi_status
+acpi_tb_check_xsdt(acpi_physical_address address)
+{
+       struct acpi_table_header *table;
+       u32 length;
+       u64 xsdt_entry_address;
+       u8 *table_entry;
+       u32 table_count;
+       int i;
+
+       table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+       if (!table)
+               return AE_NO_MEMORY;
+
+       length = table->length;
+       acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
+       if (length < sizeof(struct acpi_table_header))
+               return AE_INVALID_TABLE_LENGTH;
+
+       table = acpi_os_map_memory(address, length);
+       if (!table)
+               return AE_NO_MEMORY;
+
+       /* Calculate the number of tables described in XSDT */
+       table_count =
+               (u32) ((table->length -
+               sizeof(struct acpi_table_header)) / sizeof(u64));
+       table_entry =
+               ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
+       for (i = 0; i < table_count; i++) {
+               ACPI_MOVE_64_TO_64(&xsdt_entry_address, table_entry);
+               if (!xsdt_entry_address) {
+                       /* XSDT has NULL entry */
+                       break;
+               }
+               table_entry += sizeof(u64);
+       }
+       acpi_os_unmap_memory(table, length);
+
+       if (i < table_count)
+               return AE_NULL_ENTRY;
+       else
+               return AE_OK;
+}
 
 
/*******************************************************************************
  *
@@ -341,6 +400,7 @@ acpi_tb_parse_root_table(acpi_physical_address 
rsdp_address, u8 flags)
        u32 table_count;
        struct acpi_table_header *table;
        acpi_physical_address address;
+       acpi_physical_address rsdt_address;
        u32 length;
        u8 *table_entry;
        acpi_status status;
@@ -369,6 +429,8 @@ acpi_tb_parse_root_table(acpi_physical_address 
rsdp_address, u8 flags)
                 */
                address = (acpi_physical_address) rsdp->xsdt_physical_address;
                table_entry_size = sizeof(u64);
+               rsdt_address = (acpi_physical_address)
+                                       rsdp->rsdt_physical_address;
        } else {
                /* Root table is an RSDT (32-bit physical addresses) */
 
@@ -382,6 +444,15 @@ acpi_tb_parse_root_table(acpi_physical_address 
rsdp_address, u8 flags)
         */
        acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
 
+       if (table_entry_size == sizeof(u64)) {
+               if (acpi_tb_check_xsdt(address) == AE_NULL_ENTRY) {
+                       /* XSDT has NULL entry, RSDT is used */
+                       address = rsdt_address;
+                       table_entry_size = sizeof(u32);
+                       ACPI_WARNING((AE_INFO, "BIOS XSDT has NULL entry,"
+                                       "using RSDT"));
+               }
+       }
        /* Map the RSDT/XSDT table header to get the full table length */
 
        table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to