diff options
author | Andi Kleen <ak@suse.de> | 2006-01-11 22:43:42 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-11 19:04:51 -0800 |
commit | 1584b89c921acefe88881f08d836d80f00600a84 (patch) | |
tree | 112d64a284488f490045b19aa910bb1b2abcbff4 /arch | |
parent | 7a4a76cc1057de0dc96ee481590347aa8c5b9ffb (diff) | |
download | linux-3.10-1584b89c921acefe88881f08d836d80f00600a84.tar.gz linux-3.10-1584b89c921acefe88881f08d836d80f00600a84.tar.bz2 linux-3.10-1584b89c921acefe88881f08d836d80f00600a84.zip |
[PATCH] x86_64: Validate SLIT table
A lot of Opteron BIOS just pass 10 in all SLIT entries (10 is the
normalized unit). This is actually worse than the default heuristic
because it leads to pci_distance not knowing the difference between
local and remote nodes anymore. This messes up some NUMA
heuristics in generic code.
In this case it's better to fall back to the default heuristic
which just does nodea == nodeb ? 10 : 20.
This patch does some basic sanity checking on the SLIT and only accepts
the SLIT when it passes.
Invariants enforced are:
- Node to itself shall be 10
- Any other distance shouldn't be 10
- Distances smaller than 10 are illegal
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86_64/mm/srat.c | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index 33340bd1e32..9f69d28652f 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -91,9 +91,36 @@ 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; } |