
The following "memhotplug testing" patches enable memory hotplug
operations to be performed on a system with no actual hardware
memory hotplug capabilities.

These are equivalent to the "fake cpu hotplug" patches that were
going around a while ago.  I would very much like them to stay in
-mm, but not be pushed up to mainline.

---

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        |    8 ++---
 memhotplug-dave/arch/i386/kernel/setup.c |    2 +
 memhotplug-dave/arch/i386/mm/init.c      |   49 ++++++++++++++++++-------------
 memhotplug-dave/drivers/base/memory.c    |   10 ++++++
 memhotplug-dave/mm/memory_hotplug.c      |   15 +++++++++
 5 files changed, 61 insertions(+), 23 deletions(-)

diff -puN arch/i386/Kconfig~E0-for-debugging-page_is_ram_hotplug arch/i386/Kconfig
--- memhotplug/arch/i386/Kconfig~E0-for-debugging-page_is_ram_hotplug	2005-07-28 13:50:26.000000000 -0700
+++ memhotplug-dave/arch/i386/Kconfig	2005-07-28 13:50:26.000000000 -0700
@@ -786,9 +786,9 @@ config ARCH_DISCONTIGMEM_ENABLE
 	def_bool y
 	depends on NUMA
 
-config ARCH_DISCONTIGMEM_DEFAULT
-	def_bool y
-	depends on NUMA && HIGHMEM
+config SIMULATED_MEM_HOTPLUG
+	bool "Simulate memory hotplug on non-hotplug hardware"
+	depends on EXPERIMENTAL && HIGHMEM
 
 config ARCH_SPARSEMEM_ENABLE
 	def_bool y
@@ -909,7 +909,7 @@ config HAVE_DEC_LOCK
 config BOOT_IOREMAP
 	bool
 	depends on (((X86_SUMMIT || X86_GENERICARCH) && NUMA) || (X86 && EFI))
-	default y
+	default y || SIMULATED_MEM_HOTPLUG
 
 config REGPARM
 	bool "Use register arguments (EXPERIMENTAL)"
diff -puN arch/i386/kernel/setup.c~E0-for-debugging-page_is_ram_hotplug arch/i386/kernel/setup.c
--- memhotplug/arch/i386/kernel/setup.c~E0-for-debugging-page_is_ram_hotplug	2005-07-28 13:50:26.000000000 -0700
+++ memhotplug-dave/arch/i386/kernel/setup.c	2005-07-28 13:50:26.000000000 -0700
@@ -145,6 +145,7 @@ struct ist_info ist_info;
 EXPORT_SYMBOL(ist_info);
 #endif
 struct e820map e820;
+struct e820map bios_e820;
 
 extern void early_cpu_init(void);
 extern void dmi_scan_machine(void);
@@ -1512,6 +1513,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~E0-for-debugging-page_is_ram_hotplug arch/i386/mm/init.c
--- memhotplug/arch/i386/mm/init.c~E0-for-debugging-page_is_ram_hotplug	2005-07-28 13:50:26.000000000 -0700
+++ memhotplug-dave/arch/i386/mm/init.c	2005-07-28 13:50:26.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;
 	}
@@ -745,3 +749,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~E0-for-debugging-page_is_ram_hotplug drivers/base/memory.c
--- memhotplug/drivers/base/memory.c~E0-for-debugging-page_is_ram_hotplug	2005-07-28 13:50:26.000000000 -0700
+++ memhotplug-dave/drivers/base/memory.c	2005-07-28 13:50:26.000000000 -0700
@@ -303,15 +303,25 @@ static int block_size_init(void)
  * as well as ppc64 will do all of their discovery in userspace
  * and will require this interface.
  */
+extern int page_is_hotpluggable_ram(unsigned long pfn);
 #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;
 
 	phys_addr = simple_strtoull(buf, NULL, 0);
 
+	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);
 
 	if (ret)
diff -puN mm/memory_hotplug.c~E0-for-debugging-page_is_ram_hotplug mm/memory_hotplug.c
--- memhotplug/mm/memory_hotplug.c~E0-for-debugging-page_is_ram_hotplug	2005-07-28 13:50:26.000000000 -0700
+++ memhotplug-dave/mm/memory_hotplug.c	2005-07-28 13:50:26.000000000 -0700
@@ -108,6 +108,21 @@ static void grow_pgdat_span(struct pglis
 		pgdat->node_spanned_pages = end_pfn - pgdat->node_spanned_pages;
 }
 
+#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)
 {
 	unsigned long i;
_
