Here is a set of ppc64 specific patches that at least allow compilation/booting with the following configurations: FLATMEM SPARSEMEN SPARSEMEM + MEMORY_HOTPLUG I'll continue to work the other configuration combinations and work on increased functionality. However, it would be great if these could be added to the patch set. Thanks, -- Signed-off-by: Mike Kravetz Signed-off-by: Dave Hansen --- memhotplug-dave/arch/ppc64/Kconfig | 2 memhotplug-dave/arch/ppc64/kernel/setup.c | 4 + memhotplug-dave/arch/ppc64/mm/init.c | 103 ++++++++++++++++++++++++++- memhotplug-dave/include/asm-ppc64/abs_addr.h | 2 memhotplug-dave/include/asm-ppc64/mmzone.h | 40 ++++++---- 5 files changed, 132 insertions(+), 19 deletions(-) diff -puN arch/ppc64/Kconfig~G1-kravetz-ppc64-fixes arch/ppc64/Kconfig --- memhotplug/arch/ppc64/Kconfig~G1-kravetz-ppc64-fixes 2005-02-17 15:25:46.000000000 -0800 +++ memhotplug-dave/arch/ppc64/Kconfig 2005-02-17 15:25:46.000000000 -0800 @@ -200,6 +200,8 @@ config HMT bool "Hardware multithreading" depends on SMP && PPC_PSERIES +source "mm/Kconfig" + config ARCH_SPARSEMEM_DEFAULT bool depends on PPC_PSERIES diff -puN arch/ppc64/kernel/setup.c~G1-kravetz-ppc64-fixes arch/ppc64/kernel/setup.c --- memhotplug/arch/ppc64/kernel/setup.c~G1-kravetz-ppc64-fixes 2005-02-17 15:25:46.000000000 -0800 +++ memhotplug-dave/arch/ppc64/kernel/setup.c 2005-02-17 15:25:46.000000000 -0800 @@ -1026,6 +1026,10 @@ void __init setup_arch(char **cmdline_p) /* set up the bootmem stuff with available memory */ do_init_bootmem(); +#ifdef CONFIG_SPARSEMEM + sparse_init(); +#endif + ppc_md.setup_arch(); diff -puN arch/ppc64/mm/init.c~G1-kravetz-ppc64-fixes arch/ppc64/mm/init.c --- memhotplug/arch/ppc64/mm/init.c~G1-kravetz-ppc64-fixes 2005-02-17 15:25:46.000000000 -0800 +++ memhotplug-dave/arch/ppc64/mm/init.c 2005-02-17 15:25:46.000000000 -0800 @@ -593,13 +593,24 @@ EXPORT_SYMBOL(page_is_ram); * Initialize the bootmem system and give it all the memory we * have available. */ -#ifdef CONFIG_FLATMEM +#ifndef CONFIG_NUMA void __init do_init_bootmem(void) { unsigned long i; unsigned long start, bootmap_pages; unsigned long total_pages = lmb_end_of_DRAM() >> PAGE_SHIFT; int boot_mapsize; +#ifdef CONFIG_SPARSEMEM + unsigned long start_pfn, end_pfn; + + /* + * Note presence of first (logical/coalasced) LMB which will + * contain RMO region + */ + start_pfn = lmb.memory.region[0].physbase >> PAGE_SHIFT; + end_pfn = start_pfn + (lmb.memory.region[0].size >> PAGE_SHIFT); + memory_present(0, start_pfn, end_pfn); +#endif /* * Find an area to use for the bootmem bitmap. Calculate the size of @@ -615,12 +626,21 @@ void __init do_init_bootmem(void) max_pfn = max_low_pfn; - /* add all physical memory to the bootmem map. Also find the first */ + /* add all physical memory to the bootmem map. Also, note the + * presence of all LMBs */ for (i=0; i < lmb.memory.cnt; i++) { unsigned long physbase, size; physbase = lmb.memory.region[i].physbase; size = lmb.memory.region[i].size; +#ifdef CONFIG_SPARSEMEM + if (i) { /* already created mappings for first LMB */ + start_pfn = physbase >> PAGE_SHIFT; + end_pfn = start_pfn + (size >> PAGE_SHIFT); + } + memory_present(0, start_pfn, end_pfn); +#endif + free_bootmem(physbase, size); } @@ -659,7 +679,7 @@ void __init paging_init(void) free_area_init_node(0, &contig_page_data, zones_size, __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size); } -#endif /* CONFIG_DISCONTIGMEM */ +#endif /* CONFIG_NUMA */ static struct kcore_list kcore_vmem; @@ -899,3 +919,80 @@ void pgtable_cache_init(void) if (!zero_cache) panic("pgtable_cache_init(): could not create zero_cache!\n"); } + +#ifdef CONFIG_MEMORY_HOTPLUG + +void online_page(struct page *page) +{ + ClearPageReserved(page); + free_cold_page(page); + totalram_pages++; + num_physpages++; +} + +/* + * This works only for the non-NUMA case. Later, we'll need a lookup + * to convert from real physical addresses to nid, that doesn't use + * pfn_to_nid(). + */ +int __devinit add_memory(u64 start, u64 size, unsigned long attr) +{ + struct pglist_data *pgdata = NODE_DATA(0); + struct zone *zone; + unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long nr_pages = size >> PAGE_SHIFT; + + /* this should work for most non-highmem platforms */ + zone = pgdata->node_zones; + + return __add_pages(zone, start_pfn, nr_pages, attr); + + return 0; +} + +/* + * First pass at this code will check to determine if the remove + * request is within the RMO. Do not allow removal within the RMO. + */ +int __devinit remove_memory(u64 start, u64 size, unsigned long attr) +{ + struct zone *zone; + unsigned long start_pfn, end_pfn, nr_pages; + + start_pfn = start >> PAGE_SHIFT; + nr_pages = size >> PAGE_SHIFT; + end_pfn = start_pfn + nr_pages; + + printk("%s(): Attempting to remove memoy in range " + "%lx to %lx\n", __func__, start, start+size); + /* + * check for range within RMO + */ + zone = page_zone(pfn_to_page(start_pfn)); + + printk("%s(): memory will be removed from " + "the %s zone\n", __func__, zone->name); + + /* + * not handling removing memory ranges that + * overlap multiple zones yet + */ + if (end_pfn > (zone->zone_start_pfn + zone->spanned_pages)) + goto overlap; + + /* make sure it is NOT in RMO */ + if ((start < lmb.rmo_size) || ((start+size) < lmb.rmo_size)) { + printk("%s(): range to be removed must NOT be in RMO!\n", + __func__); + goto in_rmo; + } + + return __remove_pages(zone, start_pfn, nr_pages, attr); + +overlap: + printk("%s(): memory range to be removed overlaps " + "multiple zones!!!\n", __func__); +in_rmo: + return -1; +} +#endif /* CONFIG_MEMORY_HOTPLUG */ diff -puN include/asm-ppc64/abs_addr.h~G1-kravetz-ppc64-fixes include/asm-ppc64/abs_addr.h --- memhotplug/include/asm-ppc64/abs_addr.h~G1-kravetz-ppc64-fixes 2005-02-17 15:25:46.000000000 -0800 +++ memhotplug-dave/include/asm-ppc64/abs_addr.h 2005-02-17 15:25:46.000000000 -0800 @@ -104,5 +104,7 @@ physRpn_to_absRpn(unsigned long rpn) /* Convenience macros */ #define virt_to_abs(va) phys_to_abs(__pa(va)) #define abs_to_virt(aa) __va(abs_to_phys(aa)) +#define boot_virt_to_abs(va) phys_to_abs(__boot_pa(va)) +#define boot_abs_to_virt(aa) __boot_va(abs_to_phys(aa)) #endif /* _ABS_ADDR_H */ diff -puN include/asm-ppc64/mmzone.h~G1-kravetz-ppc64-fixes include/asm-ppc64/mmzone.h --- memhotplug/include/asm-ppc64/mmzone.h~G1-kravetz-ppc64-fixes 2005-02-17 15:25:46.000000000 -0800 +++ memhotplug-dave/include/asm-ppc64/mmzone.h 2005-02-17 15:25:46.000000000 -0800 @@ -10,6 +10,27 @@ #include #include +#ifdef CONFIG_SPARSEMEM + +/* generic non-linear memory support: + * + * 1) we will not split memory into more chunks than will fit into the + * flags field of the struct page + */ + +/* + * SECTION_SIZE_BITS 2^N: how big each section will be + * MAX_PHYSADDR_BITS 2^N: how much physical address space we have + * MAX_PHYSMEM_BITS 2^N: how much memory we can have in that space + */ +#define SECTION_SIZE_BITS 24 +#define MAX_PHYSADDR_BITS 38 +#define MAX_PHYSMEM_BITS 36 + +#endif /* CONFIG_SPARSEMEM */ + +#if defined(CONFIG_NUMA) + #if defined(CONFIG_DISCONTIGMEM) || defined(CONFIG_SPARSEMEM) extern struct pglist_data *node_data[]; @@ -31,7 +52,7 @@ extern int nr_cpus_in_node[]; #define MEMORY_INCREMENT_SHIFT 24 #define MEMORY_INCREMENT (1UL << MEMORY_INCREMENT_SHIFT) -#endif /* !CONFIG_DISCONTIGMEM || !CONFIG_SPARSEMEM */ +#endif /* CONFIG_DISCONTIGMEM || CONFIG_SPARSEMEM */ #ifdef CONFIG_DISCONTIGMEM @@ -97,21 +118,6 @@ static inline int pa_to_nid(unsigned lon #ifdef CONFIG_SPARSEMEM -/* generic non-linear memory support: - * - * 1) we will not split memory into more chunks than will fit into the - * flags field of the struct page - */ - -/* - * SECTION_SIZE_BITS 2^N: how big each section will be - * MAX_PHYSADDR_BITS 2^N: how much physical address space we have - * MAX_PHYSMEM_BITS 2^N: how much memory we can have in that space - */ -#define SECTION_SIZE_BITS 24 -#define MAX_PHYSADDR_BITS 38 -#define MAX_PHYSMEM_BITS 36 - #define pa_to_nid(pa) \ ({ \ pfn_to_nid(pa >> PAGE_SHIFT); \ @@ -119,4 +125,6 @@ static inline int pa_to_nid(unsigned lon #endif /* CONFIG_SPARSEMEM */ +#endif /* CONFIG_NUMA */ + #endif /* _ASM_MMZONE_H_ */ _