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.  



 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 <linux/initrd.h>
 #include <asm/e820.h>
 #include <asm/setup.h>
+#include <asm/mmzone.h>
 
 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 <asm/srat.h>
 #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_ */

_