ACPICA: acpidump: Add DSDT/FACS instance support for Linux and EFI
authorLv Zheng <lv.zheng@intel.com>
Thu, 3 Aug 2017 06:26:56 +0000 (14:26 +0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 3 Aug 2017 21:34:16 +0000 (23:34 +0200)
ACPICA commit 343fc31840d40c06001f3b170ee5bcdfd3c7f3e0

ACPI spec allows to configure different 32-bit/64-bit table addresses for
DSDT and FACS. And for FACS, it's meaningful to dump both of them as they
are used to support different suspend protocols.

While:
1. on Linux, only 1 instance is supported for DSDT/FACS; and
2. on EFI, the code in osl_get_table() is buggy with special table instances,
   causing endless file dump for such tables (reported by Shao Ming in link
   #2).

This patch adds DSDT/FACS instance support for Linux/EFI acpidump. Fixed by
Lv Zheng.

Link: https://github.com/acpica/acpica/commit/343fc318
Link: https://bugs.acpica.org/show_bug.cgi?id=1407
Link: https://github.com/acpica/acpica/issues/285
Reported-by: Shao Ming <smbest163@163.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
tools/power/acpi/os_specific/service_layers/oslinuxtbl.c

index 82a2ff8..52a39ec 100644 (file)
@@ -759,7 +759,7 @@ static acpi_status osl_list_bios_tables(void)
 
                /* Skip NULL entries in RSDT/XSDT */
 
-               if (!table_address) {
+               if (table_address == 0) {
                        continue;
                }
 
@@ -808,7 +808,8 @@ osl_get_bios_table(char *signature,
        u8 number_of_tables;
        u8 item_size;
        u32 current_instance = 0;
-       acpi_physical_address table_address = 0;
+       acpi_physical_address table_address;
+       acpi_physical_address first_table_address = 0;
        u32 table_length = 0;
        acpi_status status = AE_OK;
        u32 i;
@@ -820,9 +821,10 @@ osl_get_bios_table(char *signature,
            ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT) ||
            ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT) ||
            ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) {
-               if (instance > 0) {
-                       return (AE_LIMIT);
-               }
+
+find_next_instance:
+
+               table_address = 0;
 
                /*
                 * Get the appropriate address, either 32-bit or 64-bit. Be very
@@ -830,41 +832,66 @@ osl_get_bios_table(char *signature,
                 * Note: The 64-bit addresses have priority.
                 */
                if (ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT)) {
-                       if ((gbl_fadt->header.length >= MIN_FADT_FOR_XDSDT) &&
-                           gbl_fadt->Xdsdt) {
-                               table_address =
-                                   (acpi_physical_address)gbl_fadt->Xdsdt;
-                       } else
-                           if ((gbl_fadt->header.length >= MIN_FADT_FOR_DSDT)
-                               && gbl_fadt->dsdt) {
-                               table_address =
-                                   (acpi_physical_address)gbl_fadt->dsdt;
+                       if (current_instance < 2) {
+                               if ((gbl_fadt->header.length >=
+                                    MIN_FADT_FOR_XDSDT) && gbl_fadt->Xdsdt
+                                   && current_instance == 0) {
+                                       table_address =
+                                           (acpi_physical_address)gbl_fadt->
+                                           Xdsdt;
+                               } else
+                                   if ((gbl_fadt->header.length >=
+                                        MIN_FADT_FOR_DSDT)
+                                       && gbl_fadt->dsdt !=
+                                       first_table_address) {
+                                       table_address =
+                                           (acpi_physical_address)gbl_fadt->
+                                           dsdt;
+                               }
                        }
                } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) {
-                       if ((gbl_fadt->header.length >= MIN_FADT_FOR_XFACS) &&
-                           gbl_fadt->Xfacs) {
-                               table_address =
-                                   (acpi_physical_address)gbl_fadt->Xfacs;
-                       } else
-                           if ((gbl_fadt->header.length >= MIN_FADT_FOR_FACS)
-                               && gbl_fadt->facs) {
-                               table_address =
-                                   (acpi_physical_address)gbl_fadt->facs;
+                       if (current_instance < 2) {
+                               if ((gbl_fadt->header.length >=
+                                    MIN_FADT_FOR_XFACS) && gbl_fadt->Xfacs
+                                   && current_instance == 0) {
+                                       table_address =
+                                           (acpi_physical_address)gbl_fadt->
+                                           Xfacs;
+                               } else
+                                   if ((gbl_fadt->header.length >=
+                                        MIN_FADT_FOR_FACS)
+                                       && gbl_fadt->facs !=
+                                       first_table_address) {
+                                       table_address =
+                                           (acpi_physical_address)gbl_fadt->
+                                           facs;
+                               }
                        }
                } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) {
                        if (!gbl_revision) {
                                return (AE_BAD_SIGNATURE);
                        }
-                       table_address =
-                           (acpi_physical_address)gbl_rsdp.
-                           xsdt_physical_address;
+                       if (current_instance == 0) {
+                               table_address =
+                                   (acpi_physical_address)gbl_rsdp.
+                                   xsdt_physical_address;
+                       }
                } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) {
-                       table_address =
-                           (acpi_physical_address)gbl_rsdp.
-                           rsdt_physical_address;
+                       if (current_instance == 0) {
+                               table_address =
+                                   (acpi_physical_address)gbl_rsdp.
+                                   rsdt_physical_address;
+                       }
                } else {
-                       table_address = (acpi_physical_address)gbl_rsdp_address;
-                       signature = ACPI_SIG_RSDP;
+                       if (current_instance == 0) {
+                               table_address =
+                                   (acpi_physical_address)gbl_rsdp_address;
+                               signature = ACPI_SIG_RSDP;
+                       }
+               }
+
+               if (table_address == 0) {
+                       goto exit_find_table;
                }
 
                /* Now we can get the requested special table */
@@ -875,6 +902,18 @@ osl_get_bios_table(char *signature,
                }
 
                table_length = ap_get_table_length(mapped_table);
+               if (first_table_address == 0) {
+                       first_table_address = table_address;
+               }
+
+               /* Match table instance */
+
+               if (current_instance != instance) {
+                       osl_unmap_table(mapped_table);
+                       mapped_table = NULL;
+                       current_instance++;
+                       goto find_next_instance;
+               }
        } else {                /* Case for a normal ACPI table */
 
                if (osl_can_use_xsdt()) {
@@ -913,7 +952,7 @@ osl_get_bios_table(char *signature,
 
                        /* Skip NULL entries in RSDT/XSDT */
 
-                       if (!table_address) {
+                       if (table_address == 0) {
                                continue;
                        }
 
@@ -946,6 +985,8 @@ osl_get_bios_table(char *signature,
                }
        }
 
+exit_find_table:
+
        if (!mapped_table) {
                return (AE_LIMIT);
        }