Andy, All,
I've been working to boot up a 16way+HT box here on 2.5 with ACPI, and
have been getting consistent reboots before the console inits. I tracked
down the bug to some ACPI code where we map in the ACPI tables.
Unfortunately in a few cases we map in just the header, then immediately
start processing the table, rather then reading the table length and
remapping the entire table into memory. I guess with smaller boxes, we
never had ACPI tables that crossed page boundaries, so it was never
noticed. On this box however, we start calculating the table checksum
and run off the page causing the system to reboot. ouch!
Anyway, here is a patch that fixes the spot I was having troubles with,
along with two other instances of this mistake. Andy, you may have some
stylistic complaints, but something to this effect is needed.
thanks
-john
PS: Big thanks to James Cleverdon for confirming the cause of the
problem and pointing out the other instances of it as well.
diff -Nru a/drivers/acpi/tables.c b/drivers/acpi/tables.c
--- a/drivers/acpi/tables.c Wed Feb 19 19:46:04 2003
+++ b/drivers/acpi/tables.c Wed Feb 19 19:46:04 2003
@@ -379,6 +379,7 @@
sdt.pa = ((struct acpi20_table_rsdp*)rsdp)->xsdt_address;
+ /* map in just the header */
header = (struct acpi_table_header *)
__acpi_map_table(sdt.pa, sizeof(struct acpi_table_header));
@@ -387,6 +388,15 @@
return -ENODEV;
}
+ /* remap in the entire table before processing */
+ mapped_xsdt = (struct acpi_table_xsdt *)
+ __acpi_map_table(sdt.pa, header->length);
+ if (!mapped_xsdt) {
+ printk(KERN_WARNING PREFIX "Unable to map XSDT\n");
+ return -ENODEV;
+ }
+ header = &mapped_xsdt->header;
+
if (strncmp(header->signature, "XSDT", 4)) {
printk(KERN_WARNING PREFIX "XSDT signature incorrect\n");
return -ENODEV;
@@ -404,15 +414,6 @@
sdt.count = ACPI_MAX_TABLES;
}
- mapped_xsdt = (struct acpi_table_xsdt *)
- __acpi_map_table(sdt.pa, header->length);
- if (!mapped_xsdt) {
- printk(KERN_WARNING PREFIX "Unable to map XSDT\n");
- return -ENODEV;
- }
-
- header = &mapped_xsdt->header;
-
for (i = 0; i < sdt.count; i++)
sdt.entry[i].pa = (unsigned long) mapped_xsdt->entry[i];
}
@@ -425,6 +426,7 @@
sdt.pa = rsdp->rsdt_address;
+ /* map in just the header */
header = (struct acpi_table_header *)
__acpi_map_table(sdt.pa, sizeof(struct acpi_table_header));
if (!header) {
@@ -432,6 +434,15 @@
return -ENODEV;
}
+ /* remap in the entire table before processing */
+ mapped_rsdt = (struct acpi_table_rsdt *)
+ __acpi_map_table(sdt.pa, header->length);
+ if (!mapped_rsdt) {
+ printk(KERN_WARNING PREFIX "Unable to map RSDT\n");
+ return -ENODEV;
+ }
+ header = &mapped_rsdt->header;
+
if (strncmp(header->signature, "RSDT", 4)) {
printk(KERN_WARNING PREFIX "RSDT signature incorrect\n");
return -ENODEV;
@@ -449,15 +460,6 @@
sdt.count = ACPI_MAX_TABLES;
}
- mapped_rsdt = (struct acpi_table_rsdt *)
- __acpi_map_table(sdt.pa, header->length);
- if (!mapped_rsdt) {
- printk(KERN_WARNING PREFIX "Unable to map RSDT\n");
- return -ENODEV;
- }
-
- header = &mapped_rsdt->header;
-
for (i = 0; i < sdt.count; i++)
sdt.entry[i].pa = (unsigned long) mapped_rsdt->entry[i];
}
@@ -471,12 +473,20 @@
for (i = 0; i < sdt.count; i++) {
+ /* map in just the header */
header = (struct acpi_table_header *)
__acpi_map_table(sdt.entry[i].pa,
sizeof(struct acpi_table_header));
if (!header)
continue;
+ /* remap in the entire table before processing */
+ header = (struct acpi_table_header *)
+ __acpi_map_table(sdt.entry[i].pa,
+ header->length);
+ if (!header)
+ continue;
+
acpi_table_print(header, sdt.entry[i].pa);
if (acpi_table_compute_checksum(header, header->length)) {