* [Patch]: ACPI: Force to use RSDT when XSDT has NULL entry
@ 2007-08-24 8:18 Zhao Yakui
2007-08-24 22:53 ` Len Brown
0 siblings, 1 reply; 2+ messages in thread
From: Zhao Yakui @ 2007-08-24 8:18 UTC (permalink / raw)
To: Linux-acpi; +Cc: lenb
Subject: ACPI: Force to use RSDT when XSDT has NULL entry
From: Zhao Yakui <yakui.zhao@intel.com>
Maybe XSDT has NULL entry address. When it is found that
XSDT has NULL entry address, the promote info is given to user
("XSDT has NULL entry address, RSDT is used automatically ") and
RSDT is used automatically.
http://bugzilla.kernel.org/show_bug.cgi?id=8630
Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
---
drivers/acpi/tables/tbutils.c | 83
+++++++++++++++++++++++++++++++++++++++---
1 file changed, 78 insertions(+), 5 deletions(-)
Index: linux-2.6.23-rc3/drivers/acpi/tables/tbutils.c
===================================================================
--- linux-2.6.23-rc3.orig/drivers/acpi/tables/tbutils.c
+++ linux-2.6.23-rc3/drivers/acpi/tables/tbutils.c
@@ -51,6 +51,71 @@ 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 means that there exists XSDT
+ AE_NO_MEMORY means that it can't be mmaped to virt address
+ AE_INVALID_TABLE_LENGTH means uncorrect table length
+ AE_NULL_ENTRY means that XSDT has NULL entry
+ *
+ * DESCRIPTION: check whether the XSDT has NULL entry
+******************************************************************************/
+
+static acpi_status
+acpi_tb_check_xsdt(acpi_physical_address address)
+{
+ struct acpi_table_header *table;
+ acpi_native_uint table_entry_size;
+ u32 length;
+ u64 xsdt_entry_address;
+ u8 *table_entry;
+ u32 table_count;
+ int i;
+ acpi_status status = AE_OK;
+
+ table_entry_size = sizeof(u64);
+ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+ if (!table) {
+ /* XSDT can't be mmaped to virt address space */
+ status = AE_NO_MEMORY;
+ return status;
+ }
+ /* Get the length of the full table, and map entire table */
+ length = table->length;
+ acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
+ if (length < sizeof(struct acpi_table_header)) {
+ /* the length of XSDT isn't correct */
+ status = AE_INVALID_TABLE_LENGTH;
+ return status;
+ }
+ table = acpi_os_map_memory(address, length);
+ if (!table) {
+ status = AE_NO_MEMORY;
+ return status;
+ }
+ /* Calculate the number of tables described in the root table */
+ table_count =
+ (u32) ((table->length -
+ sizeof(struct acpi_table_header)) / table_entry_size);
+ 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 */
+ status = AE_NULL_ENTRY ;
+ break;
+ }
+ table_entry += table_entry_size;
+ }
+ acpi_os_unmap_memory(table, length);
+ return status;
+}
/*******************************************************************************
*
@@ -341,12 +406,12 @@ acpi_tb_parse_root_table(acpi_physical_a
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;
ACPI_FUNCTION_TRACE(tb_parse_root_table);
-
/*
* Map the entire RSDP and extract the address of the RSDT or XSDT
*/
@@ -369,19 +434,29 @@ acpi_tb_parse_root_table(acpi_physical_a
*/
address = (acpi_physical_address) rsdp->xsdt_physical_address;
table_entry_size = sizeof(u64);
+ /* backup rsdt_address */
+ rsdt_address = (acpi_physical_address)
+ rsdp->rsdt_physical_address;
} else {
/* Root table is an RSDT (32-bit physical addresses) */
address = (acpi_physical_address) rsdp->rsdt_physical_address;
table_entry_size = sizeof(u32);
}
-
/*
* It is not possible to map more than one entry in some environments,
* so unmap the RSDP here before mapping other tables
*/
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, "XSDT has NULL entry,"
+ "RSDT is used automatically"));
+ }
+ }
/* Map the RSDT/XSDT table header to get the full table length */
table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
@@ -455,11 +530,9 @@ acpi_tb_parse_root_table(acpi_physical_a
acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
address =
acpi_tb_get_root_table_entry(table_entry, table_entry_size);
-
table_entry += table_entry_size;
acpi_gbl_root_table_list.count++;
}
-
/*
* It is not possible to map more than one entry in some environments,
* so unmap the root table here before mapping other tables
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: [Patch]: ACPI: Force to use RSDT when XSDT has NULL entry
2007-08-24 8:18 [Patch]: ACPI: Force to use RSDT when XSDT has NULL entry Zhao Yakui
@ 2007-08-24 22:53 ` Len Brown
0 siblings, 0 replies; 2+ messages in thread
From: Len Brown @ 2007-08-24 22:53 UTC (permalink / raw)
To: Zhao Yakui; +Cc: Linux-acpi
Thanks, Yakui.
I've refreshed the patch and applied it as below.
Some trivia for next time:
please send to: me, and cc: the list, rather than the reverse.
After the
---
please note anything you don't want to say, but exclude
from the check-in comments.
in particular, this is a good place to say things like,
this patch has been tested, please apply,
or this patch is untested, or please give me feedback etc.
Please do not delete white-space that is not directly related
to the logical change at hand. white-space is useful.
I couldn't resist deleting some temporary variables
and updating the comments and check-in comments etc,
Hopefully I didn't mess it up.
diff your patch and this one to see what I did.
thanks,
-Len
Subject: ACPI: Validate XSDT, use RSDT if XSDT fails
From: Zhao Yakui <yakui.zhao@intel.com>
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 <yakui.zhao@intel.com>
---
tbutils.c | 71 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 71 insertions(+)
Index: linus/drivers/acpi/tables/tbutils.c
===================================================================
--- linus.orig/drivers/acpi/tables/tbutils.c
+++ linus/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_a
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_a
*/
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_a
*/
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));
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2007-08-24 22:53 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-08-24 8:18 [Patch]: ACPI: Force to use RSDT when XSDT has NULL entry Zhao Yakui
2007-08-24 22:53 ` Len Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).