
We need this for the time being because mem= will overwrite the
BIOS e820 table.  We need to make sure that any pages that we
online are actualy RAM, so we need to consult the original
e820.  Otherwise, we online pages in, say, the PCI config space
and the adapters get angry when you hand those to userspace.

Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
---

 memhotplug-dave/arch/i386/Kconfig        |   14 +++++---
 memhotplug-dave/arch/i386/kernel/setup.c |    2 +
 memhotplug-dave/arch/i386/mm/init.c      |   49 ++++++++++++++++++-------------
 memhotplug-dave/drivers/base/memory.c    |   11 +++++-
 memhotplug-dave/mm/memory_hotplug.c      |   19 +++++++++++-
 5 files changed, 68 insertions(+), 27 deletions(-)

diff -puN arch/i386/Kconfig~Y2-page_is_ram_hotplug arch/i386/Kconfig
--- memhotplug/arch/i386/Kconfig~Y2-page_is_ram_hotplug	2005-04-13 14:21:17.000000000 -0700
+++ memhotplug-dave/arch/i386/Kconfig	2005-04-13 14:21:17.000000000 -0700
@@ -794,17 +794,21 @@ config ARCH_DISCONTIGMEM_ENABLE
 	def_bool y
 	depends on NUMA
 
-config ARCH_DISCONTIGMEM_DEFAULT
-	def_bool y
-	depends on NUMA
+config SIMULATED_MEM_HOTPLUG
+	bool "Simulate memory hotplug on non-hotplug hardware"
+	depends on EXPERIMENTAL
 
 config X86_SPARSEMEM_DEBUG_NONUMA
 	bool "Enable SPARSEMEM on flat systems (debugging only)"
-	depends on !NUMA
+	depends on !NUMA && EXPERIMENTAL
+
+config ARCH_DISCONTIGMEM_DEFAULT
+	def_bool y
+	depends on NUMA
 
 config ARCH_SPARSEMEM_ENABLE
 	def_bool y
-	depends on NUMA || X86_SPARSEMEM_DEBUG_NONUMA
+	depends on NUMA || X86_SPARSEMEM_DEBUG_NONUMA || SIMULATED_MEM_HOTPLUG
 
 config SELECT_MEMORY_MODEL
 	def_bool y
diff -puN arch/i386/kernel/setup.c~Y2-page_is_ram_hotplug arch/i386/kernel/setup.c
--- memhotplug/arch/i386/kernel/setup.c~Y2-page_is_ram_hotplug	2005-04-13 14:21:17.000000000 -0700
+++ memhotplug-dave/arch/i386/kernel/setup.c	2005-04-13 14:21:17.000000000 -0700
@@ -117,6 +117,7 @@ struct sys_desc_table_struct {
 struct edid_info edid_info;
 struct ist_info ist_info;
 struct e820map e820;
+struct e820map bios_e820;
 
 extern void early_cpu_init(void);
 extern void dmi_scan_machine(void);
@@ -1441,6 +1442,7 @@ void __init setup_arch(char **cmdline_p)
 	else {
 		printk(KERN_INFO "BIOS-provided physical RAM map:\n");
 		print_memory_map(machine_specific_memory_setup());
+		bios_e820 = e820;
 	}
 
 	copy_edd();
diff -puN arch/i386/mm/init.c~Y2-page_is_ram_hotplug arch/i386/mm/init.c
--- memhotplug/arch/i386/mm/init.c~Y2-page_is_ram_hotplug	2005-04-13 14:21:17.000000000 -0700
+++ memhotplug-dave/arch/i386/mm/init.c	2005-04-13 14:21:17.000000000 -0700
@@ -192,38 +192,42 @@ static inline int page_kills_ppro(unsign
 
 extern int is_available_memory(efi_memory_desc_t *);
 
-int page_is_ram(unsigned long pagenr)
+static int page_is_ram_efi(unsigned long pagenr)
 {
+#ifdef CONFIG_EFI
 	int i;
 	unsigned long addr, end;
+	efi_memory_desc_t *md;
 
-	if (efi_enabled) {
-		efi_memory_desc_t *md;
-
-		for (i = 0; i < memmap.nr_map; i++) {
-			md = &memmap.map[i];
-			if (!is_available_memory(md))
-				continue;
-			addr = (md->phys_addr+PAGE_SIZE-1) >> PAGE_SHIFT;
-			end = (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >> PAGE_SHIFT;
-
-			if ((pagenr >= addr) && (pagenr < end))
-				return 1;
-		}
-		return 0;
+	for (i = 0; i < memmap.nr_map; i++) {
+		md = &memmap.map[i];
+		if (!is_available_memory(md))
+			continue;
+		addr = (md->phys_addr+PAGE_SIZE-1) >> PAGE_SHIFT;
+		end = (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >> PAGE_SHIFT;
+		if ((pagenr >= addr) && (pagenr < end))
+			return 1;
 	}
+#endif /* CONFIG_EFI */
+	return 0;
+}
 
-	for (i = 0; i < e820.nr_map; i++) {
+int page_is_ram_e820(unsigned long pagenr, struct e820map *local_e820)
+{
+	int i;
+	unsigned long addr, end;
+
+	for (i = 0; i < local_e820->nr_map; i++) {
 
-		if (e820.map[i].type != E820_RAM)	/* not usable memory */
+		if (local_e820->map[i].type != E820_RAM) /* not usable memory */
 			continue;
 		/*
 		 *	!!!FIXME!!! Some BIOSen report areas as RAM that
 		 *	are not. Notably the 640->1Mb area. We need a sanity
 		 *	check here.
 		 */
-		addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT;
-		end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT;
+		addr = (local_e820->map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT;
+		end = (local_e820->map[i].addr+local_e820->map[i].size) >> PAGE_SHIFT;
 		if  ((pagenr >= addr) && (pagenr < end))
 			return 1;
 	}
@@ -794,3 +798,10 @@ void free_initrd_mem(unsigned long start
 	}
 }
 #endif
+
+int page_is_ram(unsigned long pagenr)
+{
+	if (efi_enabled)
+		return page_is_ram_efi(pagenr);
+	return page_is_ram_e820(pagenr, &e820);
+}
diff -puN drivers/base/memory.c~Y2-page_is_ram_hotplug drivers/base/memory.c
--- memhotplug/drivers/base/memory.c~Y2-page_is_ram_hotplug	2005-04-13 14:21:17.000000000 -0700
+++ memhotplug-dave/drivers/base/memory.c	2005-04-13 14:21:17.000000000 -0700
@@ -297,12 +297,14 @@ static int block_size_init(void)
  * All the probe stuff here
  */
 
+extern int page_is_hotpluggable_ram(unsigned long pfn);
 /* define this off in some header somewhere ... */
 #ifdef CONFIG_ARCH_MEMORY_PROBE
 static ssize_t
 memory_probe_store(struct class *class, const char __user *buf, size_t count)
 {
 	u64 phys_addr;
+	unsigned long offset;
 	int ret;
 	/*
 	 * Hmmm... what do we really want this to do?
@@ -313,8 +315,13 @@ memory_probe_store(struct class *class, 
 	phys_addr = simple_strtoull(buf, NULL, 0);
 
 	// a hardware check for the ram?
-	//if (!ram_present(phys_addr, PAGES_PER_SECTION))
-	//	return -EINVAL;
+	for (offset = 0; offset < PAGES_PER_SECTION; offset++) {
+		unsigned long page_nr = (phys_addr >> PAGE_SHIFT) + offset;
+		if (page_is_hotpluggable_ram(page_nr))
+			break;
+	}
+	if (offset == PAGES_PER_SECTION)
+		return -EINVAL;
 
 	ret = add_memory(phys_addr, (PAGES_PER_SECTION << PAGE_SHIFT), 0);
 
diff -puN mm/memory_hotplug.c~Y2-page_is_ram_hotplug mm/memory_hotplug.c
--- memhotplug/mm/memory_hotplug.c~Y2-page_is_ram_hotplug	2005-04-13 14:21:17.000000000 -0700
+++ memhotplug-dave/mm/memory_hotplug.c	2005-04-13 14:21:17.000000000 -0700
@@ -47,6 +47,7 @@ got_map_ptr:
 }
 
 extern int sparse_add_one_section(int, int, struct page *); /* FIXME header*/
+void zonetable_add(struct zone *zone, int nid, int zid, unsigned long pfn, unsigned long size);
 int __add_section(struct zone *zone, unsigned long phys_start_pfn,
 		  unsigned long attr)
 {
@@ -148,6 +149,21 @@ int __add_pages(struct zone *zone, unsig
 	return err;
 }
 
+#ifdef CONFIG_SIMULATED_MEM_HOTPLUG
+int page_is_hotpluggable_ram(unsigned long pfn)
+{
+	extern struct e820map bios_e820;
+	extern int page_is_ram_e820(unsigned long, struct e820map*);
+
+	return page_is_ram_e820(pfn, &bios_e820);
+}
+#else
+int page_is_hotpluggable_ram(unsigned long pfn)
+{
+	return 1;
+}
+#endif
+
 int online_pages(unsigned long pfn, unsigned long nr_pages)
 {
 	int i;
@@ -157,7 +173,8 @@ int online_pages(unsigned long pfn, unsi
 
 	for (i = 0; i < nr_pages; i++) {
 		struct page *page = pfn_to_page(pfn + i);
-		if (page_is_ram(pfn + i))
+
+		if (page_is_hotpluggable_ram(pfn + i))
 			online_page(page);
 	}
 
_
