summaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
authorFenghua Yu <fenghua.yu@intel.com>2008-06-09 16:48:18 -0700
committerLen Brown <len.brown@intel.com>2008-06-11 19:13:46 -0400
commit39b8931b5cad9a7cbcd2394a40a088311e783a82 (patch)
tree4db8369a3d5cc54a61942f38de9eb392e7e5bc60 /drivers/acpi
parent36d872a370d3d10e5a7faa9dcacce744260fb13b (diff)
ACPI: handle invalid ACPI SLIT table
This is a SLIT sanity checking patch. It moves slit_valid() function to generic ACPI code and does sanity checking for both x86 and ia64. It sets up node_distance with LOCAL_DISTANCE and REMOTE_DISTANCE when hitting invalid SLIT table on ia64. It also cleans up unused variable localities in acpi_parse_slit() on x86. Signed-off-by: Fenghua Yu <fenghua.yu@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/numa.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 5d59cb33b1a..658e5f3abae 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -140,19 +140,42 @@ acpi_table_print_srat_entry(struct acpi_subtable_header *header)
}
}
+/*
+ * A lot of BIOS fill in 10 (= no distance) everywhere. This messes
+ * up the NUMA heuristics which wants the local node to have a smaller
+ * distance than the others.
+ * Do some quick checks here and only use the SLIT if it passes.
+ */
+static __init int slit_valid(struct acpi_table_slit *slit)
+{
+ int i, j;
+ int d = slit->locality_count;
+ for (i = 0; i < d; i++) {
+ for (j = 0; j < d; j++) {
+ u8 val = slit->entry[d*i + j];
+ if (i == j) {
+ if (val != LOCAL_DISTANCE)
+ return 0;
+ } else if (val <= LOCAL_DISTANCE)
+ return 0;
+ }
+ }
+ return 1;
+}
+
static int __init acpi_parse_slit(struct acpi_table_header *table)
{
struct acpi_table_slit *slit;
- u32 localities;
if (!table)
return -EINVAL;
slit = (struct acpi_table_slit *)table;
- /* downcast just for %llu vs %lu for i386/ia64 */
- localities = (u32) slit->locality_count;
-
+ if (!slit_valid(slit)) {
+ printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n");
+ return -EINVAL;
+ }
acpi_numa_slit_init(slit);
return 0;