From: Dave Hansen As described in this bug: http://bugme.osdl.org/show_bug.cgi?id=653 , if you enable Summit support and NUMA Discontigmem support but boot on a non-Summit box, the kernel will fail to boot. The problem is that the Summit code can not correctly get the NUMA memory configuration of a flat box. The code to do that is in get_memcfg_numa_flat(), but it never gets called. This patch implements a fallback to the generic NUMA code in get_memcfg_numa_flat() if the Summit detection fails. The patch also adds the necessary bits to the Summit code so that it *knows* when it fails. 25-akpm/arch/i386/kernel/numaq.c | 8 +++++++- 25-akpm/arch/i386/kernel/srat.c | 33 +++++++++++++++++++++++---------- 25-akpm/arch/i386/mm/discontig.c | 11 ++++++++--- 25-akpm/include/asm-i386/mmzone.h | 20 +++++++++++++++++++- 25-akpm/include/asm-i386/numaq.h | 3 +-- 25-akpm/include/asm-i386/srat.h | 3 +-- 6 files changed, 59 insertions(+), 19 deletions(-) diff -puN arch/i386/kernel/numaq.c~numa-detection-fail-fix arch/i386/kernel/numaq.c --- 25/arch/i386/kernel/numaq.c~numa-detection-fail-fix Thu Sep 11 10:29:43 2003 +++ 25-akpm/arch/i386/kernel/numaq.c Thu Sep 11 10:29:43 2003 @@ -99,8 +99,14 @@ static void __init initialize_physnode_m } } -void __init get_memcfg_numaq(void) +/* + * Unlike Summit, we don't really care to let the NUMA-Q + * fall back to flat mode. Don't compile for NUMA-Q + * unless you really need it! + */ +int __init get_memcfg_numaq(void) { smp_dump_qct(); initialize_physnode_map(); + return 1; } diff -puN arch/i386/kernel/srat.c~numa-detection-fail-fix arch/i386/kernel/srat.c --- 25/arch/i386/kernel/srat.c~numa-detection-fail-fix Thu Sep 11 10:29:43 2003 +++ 25-akpm/arch/i386/kernel/srat.c Thu Sep 11 10:29:43 2003 @@ -239,6 +239,11 @@ static int __init acpi20_parse_srat(stru } } + if (num_memory_chunks == 0) { + printk("could not finy any ACPI SRAT memory areas.\n"); + goto out_fail; + } + /* Calculate total number of nodes in system from PXM bitmap and create * a set of sequential node IDs starting at zero. (ACPI doesn't seem * to specify the range of _PXM values.) @@ -295,10 +300,12 @@ static int __init acpi20_parse_srat(stru } } } + return 1; +out_fail: return 0; } -void __init get_memcfg_from_srat(void) +int __init get_memcfg_from_srat(void) { struct acpi_table_header *header = NULL; struct acpi_table_rsdp *rsdp = NULL; @@ -316,11 +323,11 @@ void __init get_memcfg_from_srat(void) (u32)rsdp_address->pointer.physical; } else { printk("%s: rsdp_address is not a physical pointer\n", __FUNCTION__); - return; + goto out_err; } if (!rsdp) { printk("%s: Didn't find ACPI root!\n", __FUNCTION__); - return; + goto out_err; } printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision, @@ -328,7 +335,7 @@ void __init get_memcfg_from_srat(void) if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) { printk(KERN_WARNING "%s: RSDP table signature incorrect\n", __FUNCTION__); - return; + goto out_err; } rsdt = (struct acpi_table_rsdt *) @@ -338,14 +345,14 @@ void __init get_memcfg_from_srat(void) printk(KERN_WARNING "%s: ACPI: Invalid root system description tables (RSDT)\n", __FUNCTION__); - return; + goto out_err; } header = & rsdt->header; if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) { printk(KERN_WARNING "ACPI: RSDT signature incorrect\n"); - return; + goto out_err; } /* @@ -356,15 +363,18 @@ void __init get_memcfg_from_srat(void) */ tables = (header->length - sizeof(struct acpi_table_header)) / 4; + if (!tables) + goto out_err; + memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt)); if (saved_rsdt.header.length > sizeof(saved_rsdt)) { printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n", saved_rsdt.header.length); - return; + goto out_err; } -printk("Begin table scan....\n"); + printk("Begin SRAT table scan....\n"); for (i = 0; i < tables; i++) { /* Map in header, then map in full table length. */ @@ -379,10 +389,13 @@ printk("Begin table scan....\n"); if (strncmp((char *) &header->signature, "SRAT", 4)) continue; - acpi20_parse_srat((struct acpi_table_srat *)header); + /* we've found the srat table. don't need to look at any more tables */ - break; + return acpi20_parse_srat((struct acpi_table_srat *)header); } +out_err: + printk("failed to get NUMA memory information from SRAT table\n"); + return 0; } /* For each node run the memory list to determine whether there are diff -puN arch/i386/mm/discontig.c~numa-detection-fail-fix arch/i386/mm/discontig.c --- 25/arch/i386/mm/discontig.c~numa-detection-fail-fix Thu Sep 11 10:29:43 2003 +++ 25-akpm/arch/i386/mm/discontig.c Thu Sep 11 10:29:43 2003 @@ -30,6 +30,7 @@ #include #include #include +#include struct pglist_data *node_data[MAX_NUMNODES]; bootmem_data_t node0_bdata; @@ -84,7 +85,7 @@ void set_pmd_pfn(unsigned long vaddr, un * a single node with all available processors in it with a flat * memory map. */ -void __init get_memcfg_numa_flat(void) +int __init get_memcfg_numa_flat(void) { int pfn; @@ -107,6 +108,7 @@ void __init get_memcfg_numa_flat(void) /* Indicate there is one node available. */ node_set_online(0); numnodes = 1; + return 1; } /* @@ -355,17 +357,20 @@ void __init zone_sizes_init(void) unsigned long low = max_low_pfn; unsigned long start = node_start_pfn[nid]; unsigned long high = node_end_pfn[nid]; - + max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; if (start > low) { #ifdef CONFIG_HIGHMEM - zones_size[ZONE_HIGHMEM] = high - start; + BUG_ON(start > high); + zones_size[ZONE_HIGHMEM] = high - start; #endif } else { if (low < max_dma) zones_size[ZONE_DMA] = low; else { + BUG_ON(max_dma > low); + BUG_ON(low > high); zones_size[ZONE_DMA] = max_dma; zones_size[ZONE_NORMAL] = low - max_dma; #ifdef CONFIG_HIGHMEM diff -puN include/asm-i386/mmzone.h~numa-detection-fail-fix include/asm-i386/mmzone.h --- 25/include/asm-i386/mmzone.h~numa-detection-fail-fix Thu Sep 11 10:29:43 2003 +++ 25-akpm/include/asm-i386/mmzone.h Thu Sep 11 10:29:43 2003 @@ -122,11 +122,29 @@ static inline struct pglist_data *pfn_to #elif CONFIG_ACPI_SRAT #include #elif CONFIG_X86_PC -#define get_memcfg_numa get_memcfg_numa_flat #define get_zholes_size(n) (0) #else #define pfn_to_nid(pfn) (0) #endif /* CONFIG_X86_NUMAQ */ +extern int get_memcfg_numa_flat(void ); +/* + * This allows any one NUMA architecture to be compiled + * for, and still fall back to the flat function if it + * fails. + */ +static inline void get_memcfg_numa(void) +{ +#ifdef CONFIG_X86_NUMAQ + if (get_memcfg_numaq()) + return; +#elif CONFIG_ACPI_SRAT + if (get_memcfg_from_srat()) + return; +#endif + + get_memcfg_numa_flat(); +} + #endif /* CONFIG_DISCONTIGMEM */ #endif /* _ASM_MMZONE_H_ */ diff -puN include/asm-i386/numaq.h~numa-detection-fail-fix include/asm-i386/numaq.h --- 25/include/asm-i386/numaq.h~numa-detection-fail-fix Thu Sep 11 10:29:43 2003 +++ 25-akpm/include/asm-i386/numaq.h Thu Sep 11 10:29:43 2003 @@ -29,8 +29,7 @@ #ifdef CONFIG_X86_NUMAQ #define MAX_NUMNODES 16 -extern void get_memcfg_numaq(void); -#define get_memcfg_numa() get_memcfg_numaq() +extern int get_memcfg_numaq(void); /* * SYS_CFG_DATA_PRIV_ADDR, struct eachquadmem, and struct sys_cfg_data are the diff -puN include/asm-i386/srat.h~numa-detection-fail-fix include/asm-i386/srat.h --- 25/include/asm-i386/srat.h~numa-detection-fail-fix Thu Sep 11 10:29:43 2003 +++ 25-akpm/include/asm-i386/srat.h Thu Sep 11 10:29:43 2003 @@ -32,8 +32,7 @@ #endif #define MAX_NUMNODES 8 -extern void get_memcfg_from_srat(void); +extern int get_memcfg_from_srat(void); extern unsigned long *get_zholes_size(int); -#define get_memcfg_numa() get_memcfg_from_srat() #endif /* _ASM_SRAT_H_ */ _