sh: bootmem tidying for discontig/sparsemem preparation.
This reworks some of the node 0 bootmem initialization in
preparation for discontigmem and sparsemem support.
ARCH_POPULATES_NODE_MAP is switched to as a result of this.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 4d6d891..60cc216 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -4,7 +4,7 @@
* This file handles the architecture-dependent parts of initialization
*
* Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2002 - 2006 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
*/
#include <linux/screen_info.h>
#include <linux/ioport.h>
@@ -15,15 +15,18 @@
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/utsname.h>
+#include <linux/nodemask.h>
#include <linux/cpu.h>
#include <linux/pfn.h>
#include <linux/fs.h>
+#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/sections.h>
#include <asm/irq.h>
#include <asm/setup.h>
#include <asm/clock.h>
+#include <asm/mmu_context.h>
extern void * __rd_start, * __rd_end;
@@ -202,13 +205,112 @@
return 0;
}
-void __init setup_arch(char **cmdline_p)
+/*
+ * Register fully available low RAM pages with the bootmem allocator.
+ */
+static void __init register_bootmem_low_pages(void)
+{
+ unsigned long curr_pfn, last_pfn, pages;
+
+ /*
+ * We are rounding up the start address of usable memory:
+ */
+ curr_pfn = PFN_UP(__MEMORY_START);
+
+ /*
+ * ... and at the end of the usable range downwards:
+ */
+ last_pfn = PFN_DOWN(__pa(memory_end));
+
+ if (last_pfn > max_low_pfn)
+ last_pfn = max_low_pfn;
+
+ pages = last_pfn - curr_pfn;
+ free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(pages));
+}
+
+void __init setup_bootmem_allocator(unsigned long start_pfn)
{
unsigned long bootmap_size;
- unsigned long start_pfn, max_pfn, max_low_pfn;
+
+ /*
+ * Find a proper area for the bootmem bitmap. After this
+ * bootstrap step all allocations (until the page allocator
+ * is intact) must be done via bootmem_alloc().
+ */
+ bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn,
+ min_low_pfn, max_low_pfn);
+
+ register_bootmem_low_pages();
+
+ node_set_online(0);
+
+ /*
+ * Reserve the kernel text and
+ * Reserve the bootmem bitmap. We do this in two steps (first step
+ * was init_bootmem()), because this catches the (definitely buggy)
+ * case of us accidentally initializing the bootmem allocator with
+ * an invalid RAM area.
+ */
+ reserve_bootmem(__MEMORY_START+PAGE_SIZE,
+ (PFN_PHYS(start_pfn)+bootmap_size+PAGE_SIZE-1)-__MEMORY_START);
+
+ /*
+ * reserve physical page 0 - it's a special BIOS page on many boxes,
+ * enabling clean reboots, SMP operation, laptop functions.
+ */
+ reserve_bootmem(__MEMORY_START, PAGE_SIZE);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+ if (&__rd_start != &__rd_end) {
+ LOADER_TYPE = 1;
+ INITRD_START = PHYSADDR((unsigned long)&__rd_start) -
+ __MEMORY_START;
+ INITRD_SIZE = (unsigned long)&__rd_end -
+ (unsigned long)&__rd_start;
+ }
+
+ if (LOADER_TYPE && INITRD_START) {
+ if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
+ reserve_bootmem(INITRD_START + __MEMORY_START,
+ INITRD_SIZE);
+ initrd_start = INITRD_START + PAGE_OFFSET +
+ __MEMORY_START;
+ initrd_end = initrd_start + INITRD_SIZE;
+ } else {
+ printk("initrd extends beyond end of memory "
+ "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+ INITRD_START + INITRD_SIZE,
+ max_low_pfn << PAGE_SHIFT);
+ initrd_start = 0;
+ }
+ }
+#endif
+}
+
+#ifndef CONFIG_NEED_MULTIPLE_NODES
+static void __init setup_memory(void)
+{
+ unsigned long start_pfn;
+
+ /*
+ * Partially used pages are not usable - thus
+ * we are rounding upwards:
+ */
+ start_pfn = PFN_UP(__pa(_end));
+ setup_bootmem_allocator(start_pfn);
+}
+#else
+extern void __init setup_memory(void);
+#endif
+
+void __init setup_arch(char **cmdline_p)
+{
+ enable_mmu();
#ifdef CONFIG_CMDLINE_BOOL
- strcpy(COMMAND_LINE, CONFIG_CMDLINE);
+ strcpy(COMMAND_LINE, CONFIG_CMDLINE);
#endif
ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
@@ -226,14 +328,15 @@
init_mm.end_data = (unsigned long) _edata;
init_mm.brk = (unsigned long) _end;
- code_resource.start = (unsigned long)virt_to_phys(_text);
- code_resource.end = (unsigned long)virt_to_phys(_etext)-1;
- data_resource.start = (unsigned long)virt_to_phys(_etext);
- data_resource.end = (unsigned long)virt_to_phys(_edata)-1;
+ code_resource.start = virt_to_phys(_text);
+ code_resource.end = virt_to_phys(_etext)-1;
+ data_resource.start = virt_to_phys(_etext);
+ data_resource.end = virt_to_phys(_edata)-1;
+
+ parse_early_param();
sh_mv_setup(cmdline_p);
-
/*
* Find the highest page frame number we have available
*/
@@ -243,87 +346,12 @@
* Determine low and high memory ranges:
*/
max_low_pfn = max_pfn;
+ min_low_pfn = __MEMORY_START >> PAGE_SHIFT;
- /*
- * Partially used pages are not usable - thus
- * we are rounding upwards:
- */
- start_pfn = PFN_UP(__pa(_end));
-
- /*
- * Find a proper area for the bootmem bitmap. After this
- * bootstrap step all allocations (until the page allocator
- * is intact) must be done via bootmem_alloc().
- */
- bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn,
- __MEMORY_START>>PAGE_SHIFT,
- max_low_pfn);
- /*
- * Register fully available low RAM pages with the bootmem allocator.
- */
- {
- unsigned long curr_pfn, last_pfn, pages;
-
- /*
- * We are rounding up the start address of usable memory:
- */
- curr_pfn = PFN_UP(__MEMORY_START);
- /*
- * ... and at the end of the usable range downwards:
- */
- last_pfn = PFN_DOWN(__pa(memory_end));
-
- if (last_pfn > max_low_pfn)
- last_pfn = max_low_pfn;
-
- pages = last_pfn - curr_pfn;
- free_bootmem_node(NODE_DATA(0), PFN_PHYS(curr_pfn),
- PFN_PHYS(pages));
- }
-
-
- /*
- * Reserve the kernel text and
- * Reserve the bootmem bitmap. We do this in two steps (first step
- * was init_bootmem()), because this catches the (definitely buggy)
- * case of us accidentally initializing the bootmem allocator with
- * an invalid RAM area.
- */
- reserve_bootmem_node(NODE_DATA(0), __MEMORY_START+PAGE_SIZE,
- (PFN_PHYS(start_pfn)+bootmap_size+PAGE_SIZE-1)-__MEMORY_START);
-
- /*
- * reserve physical page 0 - it's a special BIOS page on many boxes,
- * enabling clean reboots, SMP operation, laptop functions.
- */
- reserve_bootmem_node(NODE_DATA(0), __MEMORY_START, PAGE_SIZE);
-
-#ifdef CONFIG_BLK_DEV_INITRD
- ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
- if (&__rd_start != &__rd_end) {
- LOADER_TYPE = 1;
- INITRD_START = PHYSADDR((unsigned long)&__rd_start) -
- __MEMORY_START;
- INITRD_SIZE = (unsigned long)&__rd_end -
- (unsigned long)&__rd_start;
- }
-
- if (LOADER_TYPE && INITRD_START) {
- if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
- reserve_bootmem_node(NODE_DATA(0), INITRD_START +
- __MEMORY_START, INITRD_SIZE);
- initrd_start = INITRD_START + PAGE_OFFSET +
- __MEMORY_START;
- initrd_end = initrd_start + INITRD_SIZE;
- } else {
- printk("initrd extends beyond end of memory "
- "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
- INITRD_START + INITRD_SIZE,
- max_low_pfn << PAGE_SHIFT);
- initrd_start = 0;
- }
- }
-#endif
+ nodes_clear(node_online_map);
+ setup_memory();
+ paging_init();
+ sparse_init();
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
@@ -332,8 +360,6 @@
/* Perform the machine specific initialisation */
if (likely(sh_mv.mv_setup))
sh_mv.mv_setup(cmdline_p);
-
- paging_init();
}
struct sh_machine_vector* __init get_mv_byname(const char* name)
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 3cac22f..5359f3d 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -291,6 +291,17 @@
For systems with an MMU that can afford to give up a page,
(the default value) say Y.
+config NODES_SHIFT
+ int
+ default "1"
+ depends on NEED_MULTIPLE_NODES
+
+config ARCH_FLATMEM_ENABLE
+ def_bool y
+
+config ARCH_POPULATES_NODE_MAP
+ def_bool y
+
choice
prompt "Kernel page size"
default PAGE_SIZE_4KB
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index ae957a9..4d03098 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -1,37 +1,20 @@
-/* $Id: init.c,v 1.19 2004/02/21 04:42:16 kkojima Exp $
- *
- * linux/arch/sh/mm/init.c
+/*
+ * linux/arch/sh/mm/init.c
*
* Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2002, 2004 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
*
* Based on linux/arch/i386/mm/init.c:
* Copyright (C) 1995 Linus Torvalds
*/
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/swap.h>
-#include <linux/smp.h>
#include <linux/init.h>
-#include <linux/highmem.h>
#include <linux/bootmem.h>
-#include <linux/pagemap.h>
#include <linux/proc_fs.h>
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/pgalloc.h>
+#include <linux/percpu.h>
+#include <linux/io.h>
#include <asm/mmu_context.h>
-#include <asm/io.h>
#include <asm/tlb.h>
#include <asm/cacheflush.h>
#include <asm/cache.h>
@@ -39,37 +22,51 @@
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
pgd_t swapper_pg_dir[PTRS_PER_PGD];
-#ifdef CONFIG_MMU
-/* It'd be good if these lines were in the standard header file. */
-#define START_PFN (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT)
-#define MAX_LOW_PFN (NODE_DATA(0)->bdata->node_low_pfn)
-#endif
-
void (*copy_page)(void *from, void *to);
void (*clear_page)(void *to);
void show_mem(void)
{
- int i, total = 0, reserved = 0;
- int shared = 0, cached = 0;
+ int total = 0, reserved = 0, free = 0;
+ int shared = 0, cached = 0, slab = 0;
+ pg_data_t *pgdat;
printk("Mem-info:\n");
show_free_areas();
- printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
- i = max_mapnr;
- while (i-- > 0) {
- total++;
- if (PageReserved(mem_map+i))
- reserved++;
- else if (PageSwapCache(mem_map+i))
- cached++;
- else if (page_count(mem_map+i))
- shared += page_count(mem_map+i) - 1;
+
+ for_each_online_pgdat(pgdat) {
+ struct page *page, *end;
+ unsigned long flags;
+
+ pgdat_resize_lock(pgdat, &flags);
+ page = pgdat->node_mem_map;
+ end = page + pgdat->node_spanned_pages;
+
+ do {
+ total++;
+ if (PageReserved(page))
+ reserved++;
+ else if (PageSwapCache(page))
+ cached++;
+ else if (PageSlab(page))
+ slab++;
+ else if (!page_count(page))
+ free++;
+ else
+ shared += page_count(page) - 1;
+ page++;
+ } while (page < end);
+
+ pgdat_resize_unlock(pgdat, &flags);
}
- printk("%d pages of RAM\n",total);
- printk("%d reserved pages\n",reserved);
- printk("%d pages shared\n",shared);
- printk("%d pages swap cached\n",cached);
+
+ printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+ printk("%d pages of RAM\n", total);
+ printk("%d free pages\n", free);
+ printk("%d reserved pages\n", reserved);
+ printk("%d slab pages\n", slab);
+ printk("%d pages shared\n", shared);
+ printk("%d pages swap cached\n", cached);
}
#ifdef CONFIG_MMU
@@ -147,52 +144,38 @@
*/
void __init paging_init(void)
{
- unsigned long zones_size[MAX_NR_ZONES] = { 0, };
+ int nid;
- /*
- * Setup some defaults for the zone sizes.. these should be safe
- * regardless of distcontiguous memory or MMU settings.
- */
- zones_size[ZONE_NORMAL] = __MEMORY_SIZE >> PAGE_SHIFT;
-#ifdef CONFIG_HIGHMEM
- zones_size[ZONE_HIGHMEM] = 0 >> PAGE_SHIFT;
-#endif
-
-#ifdef CONFIG_MMU
- /*
- * If we have an MMU, and want to be using it .. we need to adjust
- * the zone sizes accordingly, in addition to turning it on.
- */
- {
- /* We don't need to map the kernel through the TLB, as
- * it is permanatly mapped using P1. So clear the
- * entire pgd. */
- memset(swapper_pg_dir, 0, sizeof(swapper_pg_dir));
-
- /* Turn on the MMU */
- enable_mmu();
- zones_size[ZONE_NORMAL] = MAX_LOW_PFN - START_PFN;
- }
+ /* We don't need to map the kernel through the TLB, as
+ * it is permanatly mapped using P1. So clear the
+ * entire pgd. */
+ memset(swapper_pg_dir, 0, sizeof(swapper_pg_dir));
/* Set an initial value for the MMU.TTB so we don't have to
* check for a null value. */
set_TTB(swapper_pg_dir);
-#elif defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4)
- /*
- * If we don't have CONFIG_MMU set and the processor in question
- * still has an MMU, care needs to be taken to make sure it doesn't
- * stay on.. Since the boot loader could have potentially already
- * turned it on, and we clearly don't want it, we simply turn it off.
- *
- * We don't need to do anything special for the zone sizes, since the
- * default values that were already configured up above should be
- * satisfactory.
- */
- disable_mmu();
-#endif
- NODE_DATA(0)->node_mem_map = NULL;
- free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0);
+ for_each_online_node(nid) {
+ pg_data_t *pgdat = NODE_DATA(nid);
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
+ unsigned long low, start_pfn;
+
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+
+ start_pfn = pgdat->bdata->node_boot_start >> PAGE_SHIFT;
+ low = pgdat->bdata->node_low_pfn;
+
+ max_zone_pfns[ZONE_NORMAL] = low;
+ add_active_range(nid, start_pfn, low);
+
+ printk("Node %u: start_pfn = 0x%lx, low = 0x%lx\n",
+ nid, start_pfn, low);
+
+ free_area_init_nodes(max_zone_pfns);
+
+ printk("Node %u: mem_map starts at %p\n",
+ pgdat->node_id, pgdat->node_mem_map);
+ }
}
static struct kcore_list kcore_mem, kcore_vmalloc;
@@ -200,18 +183,33 @@
void __init mem_init(void)
{
int codesize, reservedpages, datasize, initsize;
- int tmp;
- extern unsigned long memory_start;
+ int nid;
-#ifdef CONFIG_MMU
- high_memory = (void *)__va(MAX_LOW_PFN * PAGE_SIZE);
-#else
- extern unsigned long memory_end;
+ reservedpages = 0;
- high_memory = (void *)(memory_end & PAGE_MASK);
-#endif
+ for_each_online_node(nid) {
+ pg_data_t *pgdat = NODE_DATA(nid);
+ unsigned long node_pages = 0;
+ void *node_high_memory;
+ int i;
- max_mapnr = num_physpages = MAP_NR(high_memory) - MAP_NR(memory_start);
+ num_physpages += pgdat->node_present_pages;
+
+ if (pgdat->node_spanned_pages)
+ node_pages = free_all_bootmem_node(pgdat);
+
+ totalram_pages += node_pages;
+
+ for (i = 0; i < node_pages; i++)
+ if (PageReserved(pgdat->node_mem_map + i))
+ reservedpages++;
+
+ node_high_memory = (void *)((pgdat->node_start_pfn +
+ pgdat->node_spanned_pages) <<
+ PAGE_SHIFT);
+ if (node_high_memory > high_memory)
+ high_memory = node_high_memory;
+ }
/* clear the zero-page */
memset(empty_zero_page, 0, PAGE_SIZE);
@@ -229,16 +227,6 @@
clear_page = clear_page_nommu;
#endif
- /* this will put all low memory onto the freelists */
- totalram_pages += free_all_bootmem_node(NODE_DATA(0));
- reservedpages = 0;
- for (tmp = 0; tmp < num_physpages; tmp++)
- /*
- * Only count reserved RAM pages
- */
- if (PageReserved(mem_map+tmp))
- reservedpages++;
-
codesize = (unsigned long) &_etext - (unsigned long) &_text;
datasize = (unsigned long) &_edata - (unsigned long) &_etext;
initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
@@ -250,7 +238,7 @@
printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
"%dk reserved, %dk data, %dk init)\n",
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
- max_mapnr << (PAGE_SHIFT-10),
+ totalram_pages << (PAGE_SHIFT-10),
codesize >> 10,
reservedpages << (PAGE_SHIFT-10),
datasize >> 10,
@@ -289,4 +277,3 @@
printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
}
#endif
-
diff --git a/include/asm-sh/mmu_context.h b/include/asm-sh/mmu_context.h
index 01acaaa..199662b 100644
--- a/include/asm-sh/mmu_context.h
+++ b/include/asm-sh/mmu_context.h
@@ -169,6 +169,8 @@
#define destroy_context(mm) do { } while (0)
#define set_asid(asid) do { } while (0)
#define get_asid() (0)
+#define set_TTB(pgd) do { } while (0)
+#define get_TTB() (0)
#define activate_context(mm,cpu) do { } while (0)
#define switch_mm(prev,next,tsk) do { } while (0)
#define deactivate_mm(tsk,mm) do { } while (0)
@@ -211,8 +213,8 @@
* MMU control handlers for processors lacking memory
* management hardware.
*/
-#define enable_mmu() do { BUG(); } while (0)
-#define disable_mmu() do { BUG(); } while (0)
+#define enable_mmu() do { } while (0)
+#define disable_mmu() do { } while (0)
#endif
#endif /* __KERNEL__ */
diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h
index ac4b467..7464de4 100644
--- a/include/asm-sh/page.h
+++ b/include/asm-sh/page.h
@@ -59,6 +59,7 @@
extern void (*copy_page)(void *to, void *from);
extern unsigned long shm_align_mask;
+extern unsigned long max_low_pfn, min_low_pfn;
#ifdef CONFIG_MMU
extern void clear_page_slow(void *to);
@@ -124,17 +125,16 @@
#define PAGE_OFFSET CONFIG_PAGE_OFFSET
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
+#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
-#define MAP_NR(addr) (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)
-
-#define phys_to_page(phys) (mem_map + (((phys)-__MEMORY_START) >> PAGE_SHIFT))
-#define page_to_phys(page) (((page - mem_map) << PAGE_SHIFT) + __MEMORY_START)
+#define phys_to_page(phys) (pfn_to_page(phys >> PAGE_SHIFT))
+#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
/* PFN start number, because of __MEMORY_START */
#define PFN_START (__MEMORY_START >> PAGE_SHIFT)
#define ARCH_PFN_OFFSET (PFN_START)
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
-#define pfn_valid(pfn) (((pfn) - PFN_START) < max_mapnr)
+#define pfn_valid(pfn) ((pfn) >= min_low_pfn && (pfn) < max_low_pfn)
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \