]> git.hungrycats.org Git - linux/commitdiff
ia64: Based on patch by Jess Barnes: split up memory-initialization
authorDavid Mosberger <davidm@tiger.hpl.hp.com>
Mon, 22 Sep 2003 11:50:28 +0000 (04:50 -0700)
committerDavid Mosberger <davidm@tiger.hpl.hp.com>
Mon, 22 Sep 2003 11:50:28 +0000 (04:50 -0700)
from kernel/setup.c into two separate files: mm/{dis,contig}.c
to handle contiguous vs. discontiguous memory layouts.

arch/ia64/kernel/setup.c
arch/ia64/mm/Makefile
arch/ia64/mm/contig.c [new file with mode: 0644]
arch/ia64/mm/discontig.c
arch/ia64/mm/init.c
include/asm-ia64/meminit.h [new file with mode: 0644]
include/asm-ia64/numa.h

index 01bd7fe3437eddb0f920a89df76315f2256e4083..f8ee520eb6599bf0da7b295ece2166dc87b84b18 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/ia32.h>
 #include <asm/machvec.h>
 #include <asm/mca.h>
+#include <asm/meminit.h>
 #include <asm/page.h>
 #include <asm/patch.h>
 #include <asm/pgtable.h>
@@ -83,91 +84,12 @@ unsigned long ia64_max_iommu_merge_mask = ~0UL;
 
 char saved_command_line[COMMAND_LINE_SIZE]; /* used in proc filesystem */
 
-/*
- * Entries defined so far:
- *     - boot param structure itself
- *     - memory map
- *     - initrd (optional)
- *     - command line string
- *     - kernel code & data
- *
- * More could be added if necessary
- */
-#define IA64_MAX_RSVD_REGIONS 5
-
-struct rsvd_region {
-       unsigned long start;    /* virtual address of beginning of element */
-       unsigned long end;      /* virtual address of end of element + 1 */
-};
-
 /*
  * We use a special marker for the end of memory and it uses the extra (+1) slot
  */
-static struct rsvd_region rsvd_region[IA64_MAX_RSVD_REGIONS + 1];
-static int num_rsvd_regions;
-
-#define IGNORE_PFN0    1       /* XXX fix me: ignore pfn 0 until TLB miss handler is updated... */
-
-#ifndef CONFIG_DISCONTIGMEM
-
-static unsigned long bootmap_start; /* physical address where the bootmem map is located */
-
-static int
-find_max_pfn (unsigned long start, unsigned long end, void *arg)
-{
-       unsigned long *max_pfnp = arg, pfn;
-
-       pfn = (PAGE_ALIGN(end - 1) - PAGE_OFFSET) >> PAGE_SHIFT;
-       if (pfn > *max_pfnp)
-               *max_pfnp = pfn;
-       return 0;
-}
+struct rsvd_region rsvd_region[IA64_MAX_RSVD_REGIONS + 1];
+int num_rsvd_regions;
 
-#else /* CONFIG_DISCONTIGMEM */
-
-/*
- * efi_memmap_walk() knows nothing about layout of memory across nodes. Find
- * out to which node a block of memory belongs.  Ignore memory that we cannot
- * identify, and split blocks that run across multiple nodes.
- *
- * Take this opportunity to round the start address up and the end address
- * down to page boundaries.
- */
-void
-call_pernode_memory (unsigned long start, unsigned long end, void *arg)
-{
-       unsigned long rs, re;
-       void (*func)(unsigned long, unsigned long, int, int);
-       int i;
-
-       start = PAGE_ALIGN(start);
-       end &= PAGE_MASK;
-       if (start >= end)
-               return;
-
-       func = arg;
-
-       if (!num_memblks) {
-               /*
-                * This machine doesn't have SRAT, so call func with
-                * nid=0, bank=0.
-                */
-               if (start < end)
-                       (*func)(start, end - start, 0, 0);
-               return;
-       }
-
-       for (i = 0; i < num_memblks; i++) {
-               rs = max(start, node_memblk[i].start_paddr);
-               re = min(end, node_memblk[i].start_paddr+node_memblk[i].size);
-
-               if (rs < re)
-                       (*func)(rs, re-rs, node_memblk[i].nid,
-                               node_memblk[i].bank);
-       }
-}
-
-#endif /* CONFIG_DISCONTIGMEM */
 
 /*
  * Filter incoming memory segments based on the primitive map created from the boot
@@ -215,48 +137,6 @@ filter_rsvd_memory (unsigned long start, unsigned long end, void *arg)
        return 0;
 }
 
-
-#ifndef CONFIG_DISCONTIGMEM
-/*
- * Find a place to put the bootmap and return its starting address in bootmap_start.
- * This address must be page-aligned.
- */
-static int
-find_bootmap_location (unsigned long start, unsigned long end, void *arg)
-{
-       unsigned long needed = *(unsigned long *)arg;
-       unsigned long range_start, range_end, free_start;
-       int i;
-
-#if IGNORE_PFN0
-       if (start == PAGE_OFFSET) {
-               start += PAGE_SIZE;
-               if (start >= end) return 0;
-       }
-#endif
-
-       free_start = PAGE_OFFSET;
-
-       for (i = 0; i < num_rsvd_regions; i++) {
-               range_start = max(start, free_start);
-               range_end   = min(end, rsvd_region[i].start & PAGE_MASK);
-
-               if (range_end <= range_start) continue; /* skip over empty range */
-
-               if (range_end - range_start >= needed) {
-                       bootmap_start = __pa(range_start);
-                       return 1;       /* done */
-               }
-
-               /* nothing more available in this segment */
-               if (range_end == end) return 0;
-
-               free_start = PAGE_ALIGN(rsvd_region[i].end);
-       }
-       return 0;
-}
-#endif /* !CONFIG_DISCONTIGMEM */
-
 static void
 sort_regions (struct rsvd_region *rsvd_region, int max)
 {
@@ -275,10 +155,15 @@ sort_regions (struct rsvd_region *rsvd_region, int max)
        }
 }
 
-static void
-find_memory (void)
+/**
+ * reserve_memory - setup reserved memory areas
+ *
+ * Setup the reserved memory areas set aside for the boot parameters, initrd,
+ * etc.
+ */
+void
+reserve_memory (void)
 {
-       unsigned long bootmap_size;
        int n = 0;
 
        /*
@@ -317,36 +202,17 @@ find_memory (void)
        num_rsvd_regions = n;
 
        sort_regions(rsvd_region, num_rsvd_regions);
+}
 
-#ifdef CONFIG_DISCONTIGMEM
-       {
-               extern void discontig_mem_init (void);
-
-               bootmap_size = max_pfn = 0;     /* stop gcc warnings */
-               discontig_mem_init();
-       }
-#else /* !CONFIG_DISCONTIGMEM */
-
-       /* first find highest page frame number */
-       max_pfn = 0;
-       efi_memmap_walk(find_max_pfn, &max_pfn);
-
-       /* how many bytes to cover all the pages */
-       bootmap_size = bootmem_bootmap_pages(max_pfn) << PAGE_SHIFT;
-
-       /* look for a location to hold the bootmap */
-       bootmap_start = ~0UL;
-       efi_memmap_walk(find_bootmap_location, &bootmap_size);
-       if (bootmap_start == ~0UL)
-               panic("Cannot find %ld bytes for bootmap\n", bootmap_size);
-
-       bootmap_size = init_bootmem(bootmap_start >> PAGE_SHIFT, max_pfn);
-
-       /* Free all available memory, then mark bootmem-map as being in use.  */
-       efi_memmap_walk(filter_rsvd_memory, free_bootmem);
-       reserve_bootmem(bootmap_start, bootmap_size);
-#endif /* !CONFIG_DISCONTIGMEM */
-
+/**
+ * find_initrd - get initrd parameters from the boot parameter structure
+ *
+ * Grab the initrd start and end from the boot parameter struct given us by
+ * the boot loader.
+ */
+void
+find_initrd (void)
+{
 #ifdef CONFIG_BLK_DEV_INITRD
        if (ia64_boot_param->initrd_start) {
                initrd_start = (unsigned long)__va(ia64_boot_param->initrd_start);
index 728146bfba5408fa70d2f6b5521dc459a681d116..7078f67887ecc3d1e36b93e066fb87c705f2ca89 100644 (file)
@@ -7,3 +7,6 @@ obj-y := init.o fault.o tlb.o extable.o
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
 obj-$(CONFIG_NUMA)        += numa.o
 obj-$(CONFIG_DISCONTIGMEM) += discontig.o
+ifndef CONFIG_DISCONTIGMEM
+obj-y += contig.o
+endif
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
new file mode 100644 (file)
index 0000000..e9650c7
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1998-2003 Hewlett-Packard Co
+ *     David Mosberger-Tang <davidm@hpl.hp.com>
+ *     Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com>
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 2003 Silicon Graphics, Inc. All rights reserved.
+ *
+ * Routines used by ia64 machines with contiguous (or virtually contiguous)
+ * memory.
+ */
+#include <linux/config.h>
+#include <linux/bootmem.h>
+#include <linux/efi.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+
+#include <asm/meminit.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/sections.h>
+
+/**
+ * show_mem - display a memory statistics summary
+ *
+ * Just walks the pages in the system and describes where they're allocated.
+ */
+void
+show_mem (void)
+{
+       int i, total = 0, reserved = 0;
+       int shared = 0, cached = 0;
+
+       printk("Mem-info:\n");
+       show_free_areas();
+
+       printk("Free swap:       %6dkB\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;
+       }
+       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("%ld pages in page table cache\n", pgtable_cache_size);
+}
+
+/* physical address where the bootmem map is located */
+unsigned long bootmap_start;
+
+/**
+ * find_max_pfn - adjust the maximum page number callback
+ * @start: start of range
+ * @end: end of range
+ * @arg: address of pointer to global max_pfn variable
+ *
+ * Passed as a callback function to efi_memmap_walk() to determine the highest
+ * available page frame number in the system.
+ */
+int
+find_max_pfn (unsigned long start, unsigned long end, void *arg)
+{
+       unsigned long *max_pfnp = arg, pfn;
+
+       pfn = (PAGE_ALIGN(end - 1) - PAGE_OFFSET) >> PAGE_SHIFT;
+       if (pfn > *max_pfnp)
+               *max_pfnp = pfn;
+       return 0;
+}
+
+/**
+ * find_bootmap_location - callback to find a memory area for the bootmap
+ * @start: start of region
+ * @end: end of region
+ * @arg: unused callback data
+ *
+ * Find a place to put the bootmap and return its starting address in
+ * bootmap_start.  This address must be page-aligned.
+ */
+int
+find_bootmap_location (unsigned long start, unsigned long end, void *arg)
+{
+       unsigned long needed = *(unsigned long *)arg;
+       unsigned long range_start, range_end, free_start;
+       int i;
+
+#if IGNORE_PFN0
+       if (start == PAGE_OFFSET) {
+               start += PAGE_SIZE;
+               if (start >= end)
+                       return 0;
+       }
+#endif
+
+       free_start = PAGE_OFFSET;
+
+       for (i = 0; i < num_rsvd_regions; i++) {
+               range_start = max(start, free_start);
+               range_end   = min(end, rsvd_region[i].start & PAGE_MASK);
+
+               if (range_end <= range_start)
+                       continue; /* skip over empty range */
+
+               if (range_end - range_start >= needed) {
+                       bootmap_start = __pa(range_start);
+                       return 1;       /* done */
+               }
+
+               /* nothing more available in this segment */
+               if (range_end == end)
+                       return 0;
+
+               free_start = PAGE_ALIGN(rsvd_region[i].end);
+       }
+       return 0;
+}
+
+/**
+ * find_memory - setup memory map
+ *
+ * Walk the EFI memory map and find usable memory for the system, taking
+ * into account reserved areas.
+ */
+void
+find_memory (void)
+{
+       unsigned long bootmap_size;
+
+       reserve_memory();
+
+       /* first find highest page frame number */
+       max_pfn = 0;
+       efi_memmap_walk(find_max_pfn, &max_pfn);
+
+       /* how many bytes to cover all the pages */
+       bootmap_size = bootmem_bootmap_pages(max_pfn) << PAGE_SHIFT;
+
+       /* look for a location to hold the bootmap */
+       bootmap_start = ~0UL;
+       efi_memmap_walk(find_bootmap_location, &bootmap_size);
+       if (bootmap_start == ~0UL)
+               panic("Cannot find %ld bytes for bootmap\n", bootmap_size);
+
+       bootmap_size = init_bootmem(bootmap_start >> PAGE_SHIFT, max_pfn);
+
+       /* Free all available memory, then mark bootmem-map as being in use. */
+       efi_memmap_walk(filter_rsvd_memory, free_bootmem);
+       reserve_bootmem(bootmap_start, bootmap_size);
+
+       find_initrd();
+}
index c2bd413eedbcf9dfd91b9d4ff8b492dd12640678..7c885aa1754c04950559a3f39bffdc0759abdba9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 2000, 2003 Silicon Graphics, Inc.  All rights reserved.
  * Copyright (c) 2001 Intel Corp.
  * Copyright (c) 2001 Tony Luck <tony.luck@intel.com>
  * Copyright (c) 2002 NEC Corp.
 
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/swap.h>
 #include <linux/bootmem.h>
 #include <linux/mmzone.h>
 #include <linux/acpi.h>
 #include <linux/efi.h>
+#include <asm/pgalloc.h>
+#include <asm/meminit.h>
 
 
 /*
@@ -27,9 +30,6 @@ static struct ia64_node_data  *node_data[NR_NODES];
 static long                    boot_pg_data[8*NR_NODES+sizeof(pg_data_t)]  __initdata;
 static pg_data_t               *pg_data_ptr[NR_NODES] __initdata;
 static bootmem_data_t          bdata[NR_NODES][NR_BANKS_PER_NODE+1] __initdata;
-
-extern int  filter_rsvd_memory (unsigned long start, unsigned long end, void *arg);
-
 /*
  * Return the compact node number of this cpu. Used prior to
  * setting up the cpu_data area.
@@ -198,7 +198,7 @@ allocate_pernode_structures(void)
                pgdat->pgdat_next = new_pgdat_list;
                new_pgdat_list = pgdat;
        }
-       
+
        memcpy(node_data[mynode]->pg_data_ptrs, pg_data_ptr, sizeof(pg_data_ptr));
        memcpy(node_data[mynode]->node_data_ptrs, node_data, sizeof(node_data));
 
@@ -209,11 +209,12 @@ allocate_pernode_structures(void)
  * Called early in boot to setup the boot memory allocator, and to
  * allocate the node-local pg_data & node-directory data structures..
  */
-void __init
-discontig_mem_init(void)
+void __init find_memory(void)
 {
        int     node;
 
+       reserve_memory();
+
        if (numnodes == 0) {
                printk(KERN_ERR "node info missing!\n");
                numnodes = 1;
@@ -232,6 +233,8 @@ discontig_mem_init(void)
         efi_memmap_walk(filter_rsvd_memory, discontig_free_bootmem_node);
        discontig_reserve_bootmem();
        allocate_pernode_structures();
+
+       find_initrd();
 }
 
 /*
@@ -242,8 +245,8 @@ discontig_mem_init(void)
  *       the per-bank mem_map entries.
  *     - fix the page struct "virtual" pointers. These are bank specific
  *       values that the paging system doesn't understand.
- *     - replicate the nodedir structure to other nodes        
- */ 
+ *     - replicate the nodedir structure to other nodes
+ */
 
 void __init
 discontig_paging_init(void)
@@ -305,3 +308,71 @@ discontig_paging_init(void)
                }
 }
 
+void show_mem(void)
+{
+       int i, reserved = 0;
+       int shared = 0, cached = 0;
+       pg_data_t *pgdat;
+
+       printk("Mem-info:\n");
+       show_free_areas();
+       printk("Free swap:       %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+       for_each_pgdat(pgdat) {
+               printk("Node ID: %d\n", pgdat->node_id);
+               for(i = 0; i < pgdat->node_spanned_pages; i++) {
+                       if (PageReserved(pgdat->node_mem_map+i))
+                               reserved++;
+                       else if (PageSwapCache(pgdat->node_mem_map+i))
+                               cached++;
+                       else if (page_count(pgdat->node_mem_map+i))
+                               shared += page_count(pgdat->node_mem_map+i)-1;
+               }
+               printk("\t%ld pages of RAM\n", pgdat->node_present_pages);
+               printk("\t%d reserved pages\n", reserved);
+               printk("\t%d pages shared\n", shared);
+               printk("\t%d pages swap cached\n", cached);
+       }
+       printk("Total of %ld pages in page table cache\n", pgtable_cache_size);
+       printk("%d free buffer pages\n", nr_free_buffer_pages());
+}
+
+/*
+ * efi_memmap_walk() knows nothing about layout of memory across nodes. Find
+ * out to which node a block of memory belongs.  Ignore memory that we cannot
+ * identify, and split blocks that run across multiple nodes.
+ *
+ * Take this opportunity to round the start address up and the end address
+ * down to page boundaries.
+ */
+void call_pernode_memory(unsigned long start, unsigned long end, void *arg)
+{
+       unsigned long rs, re;
+       void (*func)(unsigned long, unsigned long, int, int);
+       int i;
+
+       start = PAGE_ALIGN(start);
+       end &= PAGE_MASK;
+       if (start >= end)
+               return;
+
+       func = arg;
+
+       if (!num_memblks) {
+               /*
+                * This machine doesn't have SRAT, so call func with
+                * nid=0, bank=0.
+                */
+               if (start < end)
+                       (*func)(start, end - start, 0, 0);
+               return;
+       }
+
+       for (i = 0; i < num_memblks; i++) {
+               rs = max(start, node_memblk[i].start_paddr);
+               re = min(end, node_memblk[i].start_paddr+node_memblk[i].size);
+
+               if (rs < re)
+                       (*func)(rs, re-rs, node_memblk[i].nid,
+                               node_memblk[i].bank);
+       }
+}
index fda0504f2dc398df96b5436f65ef40ed151fb571..05dc179d45d6744f7e5a7999b274306038cca9f4 100644 (file)
@@ -214,58 +214,6 @@ free_initrd_mem (unsigned long start, unsigned long end)
        }
 }
 
-void
-show_mem(void)
-{
-       int i, total = 0, reserved = 0;
-       int shared = 0, cached = 0;
-
-       printk("Mem-info:\n");
-       show_free_areas();
-
-#ifdef CONFIG_DISCONTIGMEM
-       {
-               pg_data_t *pgdat;
-
-               printk("Free swap:       %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
-               for_each_pgdat(pgdat) {
-                       printk("Node ID: %d\n", pgdat->node_id);
-                       for(i = 0; i < pgdat->node_spanned_pages; i++) {
-                               if (PageReserved(pgdat->node_mem_map+i))
-                                       reserved++;
-                               else if (PageSwapCache(pgdat->node_mem_map+i))
-                                       cached++;
-                               else if (page_count(pgdat->node_mem_map + i))
-                                       shared += page_count(pgdat->node_mem_map + i) - 1;
-                       }
-                       printk("\t%d pages of RAM\n", pgdat->node_spanned_pages);
-                       printk("\t%d reserved pages\n", reserved);
-                       printk("\t%d pages shared\n", shared);
-                       printk("\t%d pages swap cached\n", cached);
-               }
-               printk("Total of %ld pages in page table cache\n", pgtable_cache_size);
-               printk("%d free buffer pages\n", nr_free_buffer_pages());
-       }
-#else /* !CONFIG_DISCONTIGMEM */
-       printk("Free swap:       %6dkB\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;
-       }
-       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("%ld pages in page table cache\n", pgtable_cache_size);
-#endif /* !CONFIG_DISCONTIGMEM */
-}
-
 /*
  * This is like put_dirty_page() but installs a clean page in the kernel's page table.
  */
diff --git a/include/asm-ia64/meminit.h b/include/asm-ia64/meminit.h
new file mode 100644 (file)
index 0000000..0742197
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef meminit_h
+#define meminit_h
+
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * Entries defined so far:
+ *     - boot param structure itself
+ *     - memory map
+ *     - initrd (optional)
+ *     - command line string
+ *     - kernel code & data
+ *
+ * More could be added if necessary
+ */
+#define IA64_MAX_RSVD_REGIONS 5
+
+struct rsvd_region {
+       unsigned long start;    /* virtual address of beginning of element */
+       unsigned long end;      /* virtual address of end of element + 1 */
+};
+
+extern struct rsvd_region rsvd_region[IA64_MAX_RSVD_REGIONS + 1];
+extern int num_rsvd_regions;
+
+extern void find_memory (void);
+extern void reserve_memory (void);
+extern void find_initrd (void);
+extern int filter_rsvd_memory (unsigned long start, unsigned long end, void *arg);
+
+#ifdef CONFIG_DISCONTIGMEM
+extern void call_pernode_memory (unsigned long start, unsigned long end, void *arg);
+#endif
+
+#define IGNORE_PFN0    1       /* XXX fix me: ignore pfn 0 until TLB miss handler is updated... */
+
+#endif /* meminit_h */
index c3a26e12cd07c612a457f21f56dcdeaf16e4922a..aa5864eff837ebae16a3eb1c1b10e40edc76c5b5 100644 (file)
@@ -11,6 +11,9 @@
 #ifndef _ASM_IA64_NUMA_H
 #define _ASM_IA64_NUMA_H
 
+#include <linux/config.h>
+#include <linux/cpumask.h>
+
 #ifdef CONFIG_NUMA
 
 #ifdef CONFIG_DISCONTIGMEM