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. Index: linux-2.6.13/arch/i386/Kconfig =================================================================== --- linux-2.6.13.orig/arch/i386/Kconfig 2005-08-30 12:10:18.000000000 -0700 +++ linux-2.6.13/arch/i386/Kconfig 2005-08-30 12:10:35.000000000 -0700 @@ -787,9 +787,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 @@ -910,7 +910,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)" Index: linux-2.6.13/arch/i386/kernel/setup.c =================================================================== --- linux-2.6.13.orig/arch/i386/kernel/setup.c 2005-08-28 16:41:01.000000000 -0700 +++ linux-2.6.13/arch/i386/kernel/setup.c 2005-08-30 12:10:35.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(); Index: linux-2.6.13/arch/i386/mm/init.c =================================================================== --- linux-2.6.13.orig/arch/i386/mm/init.c 2005-08-30 12:10:18.000000000 -0700 +++ linux-2.6.13/arch/i386/mm/init.c 2005-08-30 12:10:35.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); +} Index: linux-2.6.13/drivers/base/memory.c =================================================================== --- linux-2.6.13.orig/drivers/base/memory.c 2005-08-30 12:10:12.000000000 -0700 +++ linux-2.6.13/drivers/base/memory.c 2005-08-30 12:10:35.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) Index: linux-2.6.13/mm/memory_hotplug.c =================================================================== --- linux-2.6.13.orig/mm/memory_hotplug.c 2005-08-30 12:10:17.000000000 -0700 +++ linux-2.6.13/mm/memory_hotplug.c 2005-08-30 12:10:35.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;