<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">

This patch includes the add/remove/online functions for 
memory hotplug as well as changes that allow for 
init_memory_mapping() and friends to be used during
hot-add at runtime.  

Include functions for adding and removing memory regions
in arch specified zones as well as a function for onlining
pages.  This also makes the requisite changes (via liberal
use of the after_bootmem flag) to allow for reuse of the 
init_memory_mapping() function to create and/or initialize 
kernel pgtables for newly added regions.

Signed-off-by: Matt Tolentino &lt;matthew.e.tolentino@intel.com&gt;
Signed-off-by: Dave Hansen &lt;haveblue@us.ibm.com&gt;
---

 memhotplug-dave/arch/x86_64/mm/init.c |  123 +++++++++++++++++++++++++++++-----
 1 files changed, 107 insertions(+), 16 deletions(-)

diff -puN arch/x86_64/mm/init.c~H6-add_remove_memory_functions_late_pgtable_init_code arch/x86_64/mm/init.c
--- memhotplug/arch/x86_64/mm/init.c~H6-add_remove_memory_functions_late_pgtable_init_code	2004-11-10 13:14:26.000000000 -0800
+++ memhotplug-dave/arch/x86_64/mm/init.c	2004-11-10 13:14:26.000000000 -0800
@@ -22,6 +22,8 @@
 #include &lt;linux/pagemap.h&gt;
 #include &lt;linux/bootmem.h&gt;
 #include &lt;linux/proc_fs.h&gt;
+#include &lt;linux/memory_hotplug.h&gt;
+#include &lt;linux/module.h&gt;
 
 #include &lt;asm/processor.h&gt;
 #include &lt;asm/system.h&gt;
@@ -186,6 +188,12 @@ static __init void *alloc_low_page(int *
 	unsigned long pfn = table_end++, paddr; 
 	void *adr;
 
+	if (after_bootmem) {
+		adr = (void *)get_zeroed_page(GFP_ATOMIC);
+		*phys = __pa(adr);
+		return adr;
+	}
+
 	if (pfn &gt;= end_pfn) 
 		panic("alloc_low_page: ran out of memory"); 
 	for (i = 0; temp_mappings[i].allocated; i++) {
@@ -205,12 +213,16 @@ static __init void *alloc_low_page(int *
 
 static __init void unmap_low_page(int i)
 { 
-	struct temp_map *ti = &amp;temp_mappings[i];
+	struct temp_map *ti;
+
+	if (after_bootmem)
+		return;
+	ti = &amp;temp_mappings[i];
 	set_pmd(ti-&gt;pmd, __pmd(0));
 	ti-&gt;allocated = 0; 
 } 
 
-static void __init phys_pmd_init(pmd_t *pmd, unsigned long address, unsigned long end)
+static void phys_pmd_init(pmd_t *pmd, unsigned long address, unsigned long end)
 {
 	int i;
 
@@ -228,11 +240,32 @@ static void __init phys_pmd_init(pmd_t *
 	}
 }
 
-static void __init phys_pgd_init(pgd_t *pgd, unsigned long address, unsigned long end)
+static inline void
+phys_pmd_update(pgd_t *pgd, unsigned long address, unsigned long end)
+{
+	pmd_t *pmd = pmd_offset(pgd, (unsigned long)__va(address));
+
+	if (pmd_none(*pmd)) {
+		spin_lock(&amp;init_mm.page_table_lock);
+		phys_pmd_init(pmd, address, end);
+		spin_unlock(&amp;init_mm.page_table_lock);
+		__flush_tlb_all();
+	}
+}
+
+static void phys_pgd_init(pgd_t *pgd, unsigned long address, unsigned long end)
 { 
 	long i = pgd_index(address);
 
 	pgd = pgd + i;
+
+	if (after_bootmem) {
+		if (pgd_val(*pgd)) {
+			phys_pmd_update(pgd, address, end);
+			return;
+		}
+	}
+
 	for (; i &lt; PTRS_PER_PGD; pgd++, i++) {
 		int map; 
 		unsigned long paddr, pmd_phys;
@@ -240,19 +273,26 @@ static void __init phys_pgd_init(pgd_t *
 
 		paddr = (address &amp; PML4_MASK) + i*PGDIR_SIZE;
 		if (paddr &gt;= end) { 
-			for (; i &lt; PTRS_PER_PGD; i++, pgd++) 
+			for (; i &lt; PTRS_PER_PGD; i++, pgd++) {
+				if (after_bootmem) spin_lock(&amp;init_mm.page_table_lock);
 				set_pgd(pgd, __pgd(0)); 
+				if (after_bootmem) spin_unlock(&amp;init_mm.page_table_lock);
+			}
 			break;
 		} 
 
-		if (!e820_mapped(paddr, paddr+PGDIR_SIZE, 0)) { 
-			set_pgd(pgd, __pgd(0)); 
-			continue;
-		} 
+		if (!after_bootmem) {
+			if (!e820_mapped(paddr, paddr+PGDIR_SIZE, 0)) {
+				set_pgd(pgd, __pgd(0));
+				continue;
+			}
+		}
 
 		pmd = alloc_low_page(&amp;map, &amp;pmd_phys);
+		if (after_bootmem) spin_lock(&amp;init_mm.page_table_lock);
 		set_pgd(pgd, __pgd(pmd_phys | _KERNPG_TABLE));
 		phys_pmd_init(pmd, paddr, end);
+		if (after_bootmem) spin_unlock(&amp;init_mm.page_table_lock);
 		unmap_low_page(map);
 	}
 	__flush_tlb();
@@ -272,13 +312,17 @@ static void __init find_early_table_spac
 
 	table_start &gt;&gt;= PAGE_SHIFT;
 	table_end = table_start;
+
+	early_printk("kernel direct mapping tables upto %lx @ %lx-%lx\n", end,
+	       table_start&lt;&lt;PAGE_SHIFT,
+	       table_end&lt;&lt;PAGE_SHIFT);
 }
 
 
 /* Setup the direct mapping of the physical memory at PAGE_OFFSET.
    This runs before bootmem is initialized and gets pages directly from the 
    physical memory. To access them they are temporarily mapped. */
-void __init init_memory_mapping(unsigned long start, unsigned long end)
+void init_memory_mapping(unsigned long start, unsigned long end)
 { 
 	unsigned long next; 
 
@@ -290,7 +334,8 @@ void __init init_memory_mapping(unsigned
 	 * mapped.  Unfortunately this is done currently before the nodes are 
 	 * discovered.
 	 */
-	find_early_table_space(end);
+	if (!after_bootmem)
+		find_early_table_space(end);
 
 	start += __PAGE_OFFSET;
 	end += __PAGE_OFFSET; /* turn virtual */  	
@@ -298,21 +343,24 @@ void __init init_memory_mapping(unsigned
 	for (; start &lt; end; start = next) {
 		int map;
 		unsigned long pgd_phys; 
-		pgd_t *pgd = alloc_low_page(&amp;map, &amp;pgd_phys);
 		pml4_t *pml4 = pml4_offset_k(start);
+		pgd_t *pgd;
 
+		if (after_bootmem)
+			pgd = level3_offset_k(pml4, __PAGE_OFFSET);
+		else
+			pgd = alloc_low_page(&amp;map, &amp;pgd_phys);
 		next = start + PML4_SIZE;
 		if (next &gt; end) 
 			next = end; 
 		phys_pgd_init(pgd, start-PAGE_OFFSET, end-PAGE_OFFSET);
-		set_pml4(pml4, mk_kernel_pml4(pgd_phys));
+		if (!after_bootmem)	/* matt - temporarily don't consider this */
+			set_pml4(pml4, mk_kernel_pml4(pgd_phys));
 		unmap_low_page(map);   
 	} 
-	asm volatile("movq %%cr4,%0" : "=r" (mmu_cr4_features));
+	if (!after_bootmem)
+		asm volatile("movq %%cr4,%0" : "=r" (mmu_cr4_features));
 	__flush_tlb_all();
-	early_printk("kernel direct mapping tables upto %lx @ %lx-%lx\n", end, 
-	       table_start&lt;&lt;PAGE_SHIFT, 
-	       table_end&lt;&lt;PAGE_SHIFT);
 }
 
 extern struct x8664_pda cpu_pda[NR_CPUS];
@@ -405,6 +453,49 @@ static inline int page_is_ram (unsigned 
 extern int swiotlb_force;
 
 /*
+ * Memory hotplug specific functions
+ */
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+
+void online_page(struct page *page)
+{
+	ClearPageReserved(page);
+	set_page_count(page, 1);
+	__free_page(page);
+	totalram_pages++;
+	num_physpages++;
+}
+
+int add_memory(u64 start, u64 size, unsigned long attr)
+{
+	struct pglist_data *pgdat = &amp;contig_page_data;
+	struct zone *zone = pgdat-&gt;node_zones + MAX_NR_ZONES - 2;
+	unsigned long start_pfn = start &gt;&gt; PAGE_SHIFT;
+	unsigned long nr_pages = size &gt;&gt; PAGE_SHIFT;
+	int ret;
+
+	ret = __add_pages(zone, start_pfn, nr_pages, attr);
+	if (ret)
+		goto error;
+
+	init_memory_mapping(start, (start + size - 1));
+	return ret;
+error:
+	printk("%s: Problem encountered in __add_pages!\n", __func__);
+	return ret;
+}
+EXPORT_SYMBOL(add_memory);
+
+int remove_memory(u64 start, u64 size, unsigned long attr)
+{
+	return -ENOSYS;
+}
+EXPORT_SYMBOL(remove_memory);
+
+#endif
+
+/*
  * devmem_is_allowed() checks to see if /dev/mem access to a certain address is
  * valid. The argument is a physical page number.
  *
_
</pre></body></html>