init.c 4.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * arch/xtensa/mm/init.c
 *
 * Derived from MIPS, PPC.
 *
 * 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) 2001 - 2005 Tensilica Inc.
 *
 * Chris Zankel	<chris@zankel.net>
 * Joe Taylor	<joe@tensilica.com, joetylr@yahoo.com>
 * Marc Gauthier
 * Kevin Chea
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/bootmem.h>
21
#include <linux/gfp.h>
22
#include <linux/swap.h>
23 24 25
#include <linux/mman.h>
#include <linux/nodemask.h>
#include <linux/mm.h>
26 27 28

#include <asm/bootparam.h>
#include <asm/page.h>
29
#include <asm/sections.h>
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
#include <asm/sysmem.h>

struct sysmem_info sysmem __initdata;

int __init add_sysmem_bank(unsigned long start, unsigned long end)
{
	if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) {
		pr_warn("Ignoring memory bank 0x%08lx size %ldKB\n",
			start, end - start);
		return -EINVAL;
	}
	sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(start);
	sysmem.bank[sysmem.nr_banks].end   = end & PAGE_MASK;
	sysmem.nr_banks++;

	return 0;
}
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94

/*
 * mem_reserve(start, end, must_exist)
 *
 * Reserve some memory from the memory pool.
 *
 * Parameters:
 *  start	Start of region,
 *  end		End of region,
 *  must_exist	Must exist in memory pool.
 *
 * Returns:
 *  0 (memory area couldn't be mapped)
 * -1 (success)
 */

int __init mem_reserve(unsigned long start, unsigned long end, int must_exist)
{
	int i;

	if (start == end)
		return 0;

	start = start & PAGE_MASK;
	end = PAGE_ALIGN(end);

	for (i = 0; i < sysmem.nr_banks; i++)
		if (start < sysmem.bank[i].end
		    && end >= sysmem.bank[i].start)
			break;

	if (i == sysmem.nr_banks) {
		if (must_exist)
			printk (KERN_WARNING "mem_reserve: [0x%0lx, 0x%0lx) "
				"not in any region!\n", start, end);
		return 0;
	}

	if (start > sysmem.bank[i].start) {
		if (end < sysmem.bank[i].end) {
			/* split entry */
			if (sysmem.nr_banks >= SYSMEM_BANKS_MAX)
				panic("meminfo overflow\n");
			sysmem.bank[sysmem.nr_banks].start = end;
			sysmem.bank[sysmem.nr_banks].end = sysmem.bank[i].end;
			sysmem.nr_banks++;
		}
		sysmem.bank[i].end = start;
95 96 97 98

	} else if (end < sysmem.bank[i].end) {
		sysmem.bank[i].start = end;

99
	} else {
100 101 102 103
		/* remove entry */
		sysmem.nr_banks--;
		sysmem.bank[i].start = sysmem.bank[sysmem.nr_banks].start;
		sysmem.bank[i].end   = sysmem.bank[sysmem.nr_banks].end;
104 105 106 107 108 109
	}
	return -1;
}


/*
110
 * Initialize the bootmem system and give it all low memory we have available.
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
 */

void __init bootmem_init(void)
{
	unsigned long pfn;
	unsigned long bootmap_start, bootmap_size;
	int i;

	max_low_pfn = max_pfn = 0;
	min_low_pfn = ~0;

	for (i=0; i < sysmem.nr_banks; i++) {
		pfn = PAGE_ALIGN(sysmem.bank[i].start) >> PAGE_SHIFT;
		if (pfn < min_low_pfn)
			min_low_pfn = pfn;
		pfn = PAGE_ALIGN(sysmem.bank[i].end - 1) >> PAGE_SHIFT;
		if (pfn > max_pfn)
			max_pfn = pfn;
	}

	if (min_low_pfn > max_pfn)
		panic("No memory found!\n");

134 135
	max_low_pfn = max_pfn < MAX_MEM_PFN >> PAGE_SHIFT ?
		max_pfn : MAX_MEM_PFN >> PAGE_SHIFT;
136 137 138

	/* Find an area to use for the bootmem bitmap. */

139 140
	bootmap_size = bootmem_bootmap_pages(max_low_pfn - min_low_pfn);
	bootmap_size <<= PAGE_SHIFT;
141 142 143 144 145 146 147 148 149 150 151 152 153 154
	bootmap_start = ~0;

	for (i=0; i<sysmem.nr_banks; i++)
		if (sysmem.bank[i].end - sysmem.bank[i].start >= bootmap_size) {
			bootmap_start = sysmem.bank[i].start;
			break;
		}

	if (bootmap_start == ~0UL)
		panic("Cannot find %ld bytes for bootmap\n", bootmap_size);

	/* Reserve the bootmem bitmap area */

	mem_reserve(bootmap_start, bootmap_start + bootmap_size, 1);
155
	bootmap_size = init_bootmem_node(NODE_DATA(0),
156
					 bootmap_start >> PAGE_SHIFT,
157
					 min_low_pfn,
158 159 160 161
					 max_low_pfn);

	/* Add all remaining memory pieces into the bootmem map */

162 163 164 165 166 167 168 169
	for (i = 0; i < sysmem.nr_banks; i++) {
		if (sysmem.bank[i].start >> PAGE_SHIFT < max_low_pfn) {
			unsigned long end = min(max_low_pfn << PAGE_SHIFT,
						sysmem.bank[i].end);
			free_bootmem(sysmem.bank[i].start,
				     end - sysmem.bank[i].start);
		}
	}
170 171 172 173

}


J
Johannes Weiner 已提交
174
void __init zones_init(void)
175 176 177 178 179 180
{
	unsigned long zones_size[MAX_NR_ZONES];
	int i;

	/* All pages are DMA-able, so we put them all in the DMA zone. */

181
	zones_size[ZONE_DMA] = max_low_pfn - ARCH_PFN_OFFSET;
182 183 184 185 186 187 188
	for (i = 1; i < MAX_NR_ZONES; i++)
		zones_size[i] = 0;

#ifdef CONFIG_HIGHMEM
	zones_size[ZONE_HIGHMEM] = max_pfn - max_low_pfn;
#endif

189
	free_area_init_node(0, zones_size, ARCH_PFN_OFFSET, NULL);
190 191 192 193 194 195 196 197
}

/*
 * Initialize memory pages.
 */

void __init mem_init(void)
{
198
	max_mapnr = max_low_pfn - ARCH_PFN_OFFSET;
199
	high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
200

201
#ifdef CONFIG_HIGHMEM
202 203 204
#error HIGHGMEM not implemented in init.c
#endif

205
	free_all_bootmem();
206

207
	mem_init_print_info(NULL);
208 209 210 211 212 213 214
}

#ifdef CONFIG_BLK_DEV_INITRD
extern int initrd_is_mapped;

void free_initrd_mem(unsigned long start, unsigned long end)
{
215
	if (initrd_is_mapped)
216
		free_reserved_area((void *)start, (void *)end, -1, "initrd");
217 218 219 220 221
}
#endif

void free_initmem(void)
{
222
	free_initmem_default(-1);
223
}