From: Luming Yu <luyu@redhat.com> Date: Fri, 20 Jun 2008 15:48:15 +0800 Subject: [ia64] handle invalid ACPI SLIT table Message-id: 485B60BF.9030100@redhat.com O-Subject: [RHEL 5.3 PATCH] bz 451591: Handle invalid ACPI SLIT table Bugzilla: 451591 RH-Acked-by: Prarit Bhargava <prarit@redhat.com> RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com> bz 451591 Description of problem: 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. Upstream status: 39b8931b5cad9a7cbcd2394a40a088311e783a82 Testing status: Boot fine on tiger4 and Cold fusion, and nothing unusual found. I don't see "ACPI: SLIT table looks invalid. Not used" in dmesgs from my testing. It seems to indicate that I don't have box with broken SLIT, or even just NO SLIT. Please review, and ACK. Thanks, Luming diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 97c2fbd..cdf5be9 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -456,7 +456,6 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit) printk(KERN_ERR "ACPI 2.0 SLIT: size mismatch: %d expected, %d actual\n", len, slit->header.length); - memset(numa_slit, 10, sizeof(numa_slit)); return; } slit_table = slit; @@ -566,8 +565,14 @@ void __init acpi_numa_arch_fixup(void) printk(KERN_INFO "Number of memory chunks in system = %d\n", num_node_memblks); - if (!slit_table) + if (!slit_table) { + for (i = 0; i < MAX_NUMNODES; i++) + for (j = 0; j < MAX_NUMNODES; j++) + node_distance(i, j) = i == j ? LOCAL_DISTANCE : + REMOTE_DISTANCE; return; + } + memset(numa_slit, -1, sizeof(numa_slit)); for (i = 0; i < slit_table->localities; i++) { if (!pxm_bit_test(i)) diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index 54c471c..371241a 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -89,36 +89,9 @@ static __init inline int srat_disabled(void) return numa_off || acpi_numa < 0; } -/* - * 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->localities; - for (i = 0; i < d; i++) { - for (j = 0; j < d; j++) { - u8 val = slit->entry[d*i + j]; - if (i == j) { - if (val != 10) - return 0; - } else if (val <= 10) - return 0; - } - } - return 1; -} - /* Callback for SLIT parsing */ void __init acpi_numa_slit_init(struct acpi_table_slit *slit) { - if (!slit_valid(slit)) { - printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n"); - return; - } acpi_slit = slit; } diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index e5e448e..56b1dbe 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -141,19 +141,42 @@ void __init acpi_table_print_srat_entry(acpi_table_entry_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->localities; + 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(unsigned long phys_addr, unsigned long size) { struct acpi_table_slit *slit; - u32 localities; if (!phys_addr || !size) return -EINVAL; slit = (struct acpi_table_slit *)__va(phys_addr); - /* downcast just for %llu vs %lu for i386/ia64 */ - localities = (u32) slit->localities; - + if (!slit_valid(slit)) { + printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n"); + return -EINVAL; + } acpi_numa_slit_init(slit); return 0; diff --git a/include/linux/topology.h b/include/linux/topology.h index b47ae36..5ccdb15 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -52,10 +52,11 @@ void arch_update_cpu_topology(void); -#ifndef node_distance /* Conform to ACPI 2.0 SLIT distance definitions */ #define LOCAL_DISTANCE 10 #define REMOTE_DISTANCE 20 + +#ifndef node_distance #define node_distance(from,to) ((from) == (to) ? LOCAL_DISTANCE : REMOTE_DISTANCE) #endif #ifndef RECLAIM_DISTANCE