Commit 678937f0 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] allow x86 NUMA architecture detection to fail

From: Dave Hansen <haveblue@us.ibm.com>

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.
parent 0774b4db
...@@ -99,8 +99,14 @@ static void __init initialize_physnode_map(void) ...@@ -99,8 +99,14 @@ static void __init initialize_physnode_map(void)
} }
} }
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(); smp_dump_qct();
initialize_physnode_map(); initialize_physnode_map();
return 1;
} }
...@@ -239,6 +239,11 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp) ...@@ -239,6 +239,11 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp)
} }
} }
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 /* 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 * a set of sequential node IDs starting at zero. (ACPI doesn't seem
* to specify the range of _PXM values.) * to specify the range of _PXM values.)
...@@ -295,10 +300,12 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp) ...@@ -295,10 +300,12 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp)
} }
} }
} }
return 1;
out_fail:
return 0; 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_header *header = NULL;
struct acpi_table_rsdp *rsdp = NULL; struct acpi_table_rsdp *rsdp = NULL;
...@@ -316,11 +323,11 @@ void __init get_memcfg_from_srat(void) ...@@ -316,11 +323,11 @@ void __init get_memcfg_from_srat(void)
(u32)rsdp_address->pointer.physical; (u32)rsdp_address->pointer.physical;
} else { } else {
printk("%s: rsdp_address is not a physical pointer\n", __FUNCTION__); printk("%s: rsdp_address is not a physical pointer\n", __FUNCTION__);
return; goto out_err;
} }
if (!rsdp) { if (!rsdp) {
printk("%s: Didn't find ACPI root!\n", __FUNCTION__); 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, printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision,
...@@ -328,7 +335,7 @@ void __init get_memcfg_from_srat(void) ...@@ -328,7 +335,7 @@ void __init get_memcfg_from_srat(void)
if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) { if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) {
printk(KERN_WARNING "%s: RSDP table signature incorrect\n", __FUNCTION__); printk(KERN_WARNING "%s: RSDP table signature incorrect\n", __FUNCTION__);
return; goto out_err;
} }
rsdt = (struct acpi_table_rsdt *) rsdt = (struct acpi_table_rsdt *)
...@@ -338,14 +345,14 @@ void __init get_memcfg_from_srat(void) ...@@ -338,14 +345,14 @@ void __init get_memcfg_from_srat(void)
printk(KERN_WARNING printk(KERN_WARNING
"%s: ACPI: Invalid root system description tables (RSDT)\n", "%s: ACPI: Invalid root system description tables (RSDT)\n",
__FUNCTION__); __FUNCTION__);
return; goto out_err;
} }
header = & rsdt->header; header = & rsdt->header;
if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) { if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) {
printk(KERN_WARNING "ACPI: RSDT signature incorrect\n"); printk(KERN_WARNING "ACPI: RSDT signature incorrect\n");
return; goto out_err;
} }
/* /*
...@@ -356,15 +363,18 @@ void __init get_memcfg_from_srat(void) ...@@ -356,15 +363,18 @@ void __init get_memcfg_from_srat(void)
*/ */
tables = (header->length - sizeof(struct acpi_table_header)) / 4; tables = (header->length - sizeof(struct acpi_table_header)) / 4;
if (!tables)
goto out_err;
memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt)); memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt));
if (saved_rsdt.header.length > sizeof(saved_rsdt)) { if (saved_rsdt.header.length > sizeof(saved_rsdt)) {
printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n", printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n",
saved_rsdt.header.length); 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++) { for (i = 0; i < tables; i++) {
/* Map in header, then map in full table length. */ /* Map in header, then map in full table length. */
...@@ -379,10 +389,13 @@ printk("Begin table scan....\n"); ...@@ -379,10 +389,13 @@ printk("Begin table scan....\n");
if (strncmp((char *) &header->signature, "SRAT", 4)) if (strncmp((char *) &header->signature, "SRAT", 4))
continue; continue;
acpi20_parse_srat((struct acpi_table_srat *)header);
/* we've found the srat table. don't need to look at any more tables */ /* 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 /* For each node run the memory list to determine whether there are
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/initrd.h> #include <linux/initrd.h>
#include <asm/e820.h> #include <asm/e820.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/mmzone.h>
struct pglist_data *node_data[MAX_NUMNODES]; struct pglist_data *node_data[MAX_NUMNODES];
bootmem_data_t node0_bdata; bootmem_data_t node0_bdata;
...@@ -84,7 +85,7 @@ void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags); ...@@ -84,7 +85,7 @@ void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
* a single node with all available processors in it with a flat * a single node with all available processors in it with a flat
* memory map. * memory map.
*/ */
void __init get_memcfg_numa_flat(void) int __init get_memcfg_numa_flat(void)
{ {
int pfn; int pfn;
...@@ -107,6 +108,7 @@ void __init get_memcfg_numa_flat(void) ...@@ -107,6 +108,7 @@ void __init get_memcfg_numa_flat(void)
/* Indicate there is one node available. */ /* Indicate there is one node available. */
node_set_online(0); node_set_online(0);
numnodes = 1; numnodes = 1;
return 1;
} }
/* /*
...@@ -355,17 +357,20 @@ void __init zone_sizes_init(void) ...@@ -355,17 +357,20 @@ void __init zone_sizes_init(void)
unsigned long low = max_low_pfn; unsigned long low = max_low_pfn;
unsigned long start = node_start_pfn[nid]; unsigned long start = node_start_pfn[nid];
unsigned long high = node_end_pfn[nid]; unsigned long high = node_end_pfn[nid];
max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
if (start > low) { if (start > low) {
#ifdef CONFIG_HIGHMEM #ifdef CONFIG_HIGHMEM
zones_size[ZONE_HIGHMEM] = high - start; BUG_ON(start > high);
zones_size[ZONE_HIGHMEM] = high - start;
#endif #endif
} else { } else {
if (low < max_dma) if (low < max_dma)
zones_size[ZONE_DMA] = low; zones_size[ZONE_DMA] = low;
else { else {
BUG_ON(max_dma > low);
BUG_ON(low > high);
zones_size[ZONE_DMA] = max_dma; zones_size[ZONE_DMA] = max_dma;
zones_size[ZONE_NORMAL] = low - max_dma; zones_size[ZONE_NORMAL] = low - max_dma;
#ifdef CONFIG_HIGHMEM #ifdef CONFIG_HIGHMEM
......
...@@ -122,11 +122,29 @@ static inline struct pglist_data *pfn_to_pgdat(unsigned long pfn) ...@@ -122,11 +122,29 @@ static inline struct pglist_data *pfn_to_pgdat(unsigned long pfn)
#elif CONFIG_ACPI_SRAT #elif CONFIG_ACPI_SRAT
#include <asm/srat.h> #include <asm/srat.h>
#elif CONFIG_X86_PC #elif CONFIG_X86_PC
#define get_memcfg_numa get_memcfg_numa_flat
#define get_zholes_size(n) (0) #define get_zholes_size(n) (0)
#else #else
#define pfn_to_nid(pfn) (0) #define pfn_to_nid(pfn) (0)
#endif /* CONFIG_X86_NUMAQ */ #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 /* CONFIG_DISCONTIGMEM */
#endif /* _ASM_MMZONE_H_ */ #endif /* _ASM_MMZONE_H_ */
...@@ -29,8 +29,7 @@ ...@@ -29,8 +29,7 @@
#ifdef CONFIG_X86_NUMAQ #ifdef CONFIG_X86_NUMAQ
#define MAX_NUMNODES 16 #define MAX_NUMNODES 16
extern void get_memcfg_numaq(void); extern int get_memcfg_numaq(void);
#define get_memcfg_numa() get_memcfg_numaq()
/* /*
* SYS_CFG_DATA_PRIV_ADDR, struct eachquadmem, and struct sys_cfg_data are the * SYS_CFG_DATA_PRIV_ADDR, struct eachquadmem, and struct sys_cfg_data are the
......
...@@ -32,8 +32,7 @@ ...@@ -32,8 +32,7 @@
#endif #endif
#define MAX_NUMNODES 8 #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); extern unsigned long *get_zholes_size(int);
#define get_memcfg_numa() get_memcfg_from_srat()
#endif /* _ASM_SRAT_H_ */ #endif /* _ASM_SRAT_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment