summaryrefslogtreecommitdiffstats
path: root/arch/sparc/mm/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/mm/init.c')
-rw-r--r--arch/sparc/mm/init.c430
1 files changed, 258 insertions, 172 deletions
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index 40aab1d66..221496f98 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.69 1999/09/06 22:56:17 ecd Exp $
+/* $Id: init.c,v 1.72 1999/12/27 06:30:06 anton Exp $
* linux/arch/sparc/mm/init.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -22,6 +22,8 @@
#include <linux/blk.h>
#endif
#include <linux/init.h>
+#include <linux/highmem.h>
+#include <linux/bootmem.h>
#include <asm/system.h>
#include <asm/segment.h>
@@ -30,22 +32,21 @@
#include <asm/pgtable.h>
#include <asm/vaddrs.h>
-/* Turn this off if you suspect some place in some physical memory hole
- might get into page tables (something would be broken very much). */
-
-#define FREE_UNUSED_MEM_MAP
-
extern void show_net_buffers(void);
unsigned long *sparc_valid_addr_bitmap;
+unsigned long phys_base;
+
struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
unsigned long sparc_unmapped_base;
struct pgtable_cache_struct pgt_quicklists;
/* References to section boundaries */
-extern char __init_begin, __init_end, etext;
+extern char __init_begin, __init_end, _start, _end, etext , edata;
+
+static unsigned long totalram_pages = 0;
/*
* BAD_PAGE is the page that is used for page faults when linux
@@ -62,50 +63,31 @@ extern char __init_begin, __init_end, etext;
*/
pte_t *__bad_pagetable(void)
{
- memset((void *) EMPTY_PGT, 0, PAGE_SIZE);
- return (pte_t *) EMPTY_PGT;
+ memset((void *) &empty_bad_page_table, 0, PAGE_SIZE);
+ return (pte_t *) &empty_bad_page_table;
}
pte_t __bad_page(void)
{
- memset((void *) EMPTY_PGE, 0, PAGE_SIZE);
- return pte_mkdirty(mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED));
+ memset((void *) &empty_bad_page, 0, PAGE_SIZE);
+ return pte_mkdirty(mk_pte_phys((((unsigned long) &empty_bad_page)
+ - PAGE_OFFSET + phys_base),
+ PAGE_SHARED));
}
void show_mem(void)
{
- int free = 0,total = 0,reserved = 0;
- int shared = 0, cached = 0;
- struct page *page, *end;
-
- printk("\nMem-info:\n");
+ printk("Mem-info:\n");
show_free_areas();
- printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
- for (page = mem_map, end = mem_map + max_mapnr;
- page < end; page++) {
- if (PageSkip(page)) {
- if (page->next_hash < page)
- break;
- page = page->next_hash;
- }
- total++;
- if (PageReserved(page))
- reserved++;
- else if (PageSwapCache(page))
- cached++;
- else if (!atomic_read(&page->count))
- free++;
- else
- shared += atomic_read(&page->count) - 1;
- }
- printk("%d pages of RAM\n",total);
- printk("%d free pages\n",free);
- printk("%d reserved pages\n",reserved);
- printk("%d pages shared\n",shared);
- printk("%d pages swap cached\n",cached);
- printk("%ld page tables cached\n",pgtable_cache_size);
+ printk("Free swap: %6dkB\n",
+ nr_swap_pages << (PAGE_SHIFT-10));
+ printk("%ld pages of RAM\n", totalram_pages);
+ printk("%d free pages\n", nr_free_pages());
+ printk("%ld pages in page table cache\n",pgtable_cache_size);
+#ifndef __SMP__
if (sparc_cpu_model == sun4m || sparc_cpu_model == sun4d)
- printk("%ld page dirs cached\n", pgd_cache_size);
+ printk("%ld entries in page dir cache\n",pgd_cache_size);
+#endif
show_buffers();
#ifdef CONFIG_NET
show_net_buffers();
@@ -114,12 +96,12 @@ void show_mem(void)
extern pgprot_t protection_map[16];
-unsigned long __init sparc_context_init(unsigned long start_mem, int numctx)
+void __init sparc_context_init(int numctx)
{
int ctx;
- ctx_list_pool = (struct ctx_list *) start_mem;
- start_mem += (numctx * sizeof(struct ctx_list));
+ ctx_list_pool = __alloc_bootmem(numctx * sizeof(struct ctx_list), SMP_CACHE_BYTES, 0UL);
+
for(ctx = 0; ctx < numctx; ctx++) {
struct ctx_list *clist;
@@ -131,7 +113,98 @@ unsigned long __init sparc_context_init(unsigned long start_mem, int numctx)
ctx_used.next = ctx_used.prev = &ctx_used;
for(ctx = 0; ctx < numctx; ctx++)
add_to_free_ctxlist(ctx_list_pool + ctx);
- return start_mem;
+}
+
+#undef DEBUG_BOOTMEM
+
+extern unsigned long cmdline_memory_size;
+
+unsigned long __init bootmem_init(void)
+{
+ unsigned long bootmap_size, start_pfn, end_pfn;
+ unsigned long end_of_phys_memory = 0UL;
+ int i;
+
+ /* XXX It is a bit ambiguous here, whether we should
+ * XXX treat the user specified mem=xxx as total wanted
+ * XXX physical memory, or as a limit to the upper
+ * XXX physical address we allow. For now it is the
+ * XXX latter. -DaveM
+ */
+#ifdef DEBUG_BOOTMEM
+ prom_printf("bootmem_init: Scan sp_banks, ");
+#endif
+ for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+ end_of_phys_memory = sp_banks[i].base_addr +
+ sp_banks[i].num_bytes;
+ if (cmdline_memory_size) {
+ if (end_of_phys_memory > cmdline_memory_size) {
+ if (cmdline_memory_size > sp_banks[i].base_addr) {
+ end_of_phys_memory =
+ sp_banks[i-1].base_addr +
+ sp_banks[i-1].num_bytes;
+ sp_banks[i].base_addr = 0xdeadbeef;
+ sp_banks[i].num_bytes = 0;
+ } else {
+ sp_banks[i].num_bytes -=
+ (end_of_phys_memory -
+ cmdline_memory_size);
+ end_of_phys_memory = cmdline_memory_size;
+ sp_banks[++i].base_addr = 0xdeadbeef;
+ sp_banks[i].num_bytes = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ /* Start with page aligned address of last symbol in kernel
+ * image.
+ */
+ start_pfn = PAGE_ALIGN((unsigned long) &_end) - PAGE_OFFSET;
+
+ /* Adjust up to the physical address where the kernel begins. */
+ start_pfn += phys_base;
+
+ /* Now shift down to get the real physical page frame number. */
+ start_pfn >>= PAGE_SHIFT;
+
+ end_pfn = end_of_phys_memory >> PAGE_SHIFT;
+
+ /* Initialize the boot-time allocator. */
+#ifdef DEBUG_BOOTMEM
+ prom_printf("init_bootmem(spfn[%lx],epfn[%lx])\n",
+ start_pfn, end_pfn);
+#endif
+ bootmap_size = init_bootmem(start_pfn, end_pfn);
+
+ /* Now register the available physical memory with the
+ * allocator.
+ */
+ for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+#ifdef DEBUG_BOOTMEM
+ prom_printf("free_bootmem: base[%lx] size[%lx]\n",
+ sp_banks[i].base_addr,
+ sp_banks[i].num_bytes);
+#endif
+ free_bootmem(sp_banks[i].base_addr,
+ sp_banks[i].num_bytes);
+ }
+
+ /* Reserve the kernel text/data/bss and the bootmem bitmap. */
+#ifdef DEBUG_BOOTMEM
+ prom_printf("reserve_bootmem: base[%lx] size[%lx]\n",
+ phys_base,
+ (((start_pfn << PAGE_SHIFT) +
+ bootmap_size) - phys_base));
+#endif
+ reserve_bootmem(phys_base, (((start_pfn << PAGE_SHIFT) +
+ bootmap_size) - phys_base));
+
+#ifdef DEBUG_BOOTMEM
+ prom_printf("init_bootmem: return end_pfn[%lx]\n", end_pfn);
+#endif
+ return end_pfn;
}
/*
@@ -139,31 +212,32 @@ unsigned long __init sparc_context_init(unsigned long start_mem, int numctx)
* init routine based upon the Sun model type on the Sparc.
*
*/
-extern unsigned long sun4c_paging_init(unsigned long, unsigned long);
-extern unsigned long srmmu_paging_init(unsigned long, unsigned long);
-extern unsigned long device_scan(unsigned long);
+extern void sun4c_paging_init(void);
+extern void srmmu_paging_init(void);
+extern void device_scan(void);
+
+unsigned long last_valid_pfn;
-unsigned long __init
-paging_init(unsigned long start_mem, unsigned long end_mem)
+void __init paging_init(void)
{
switch(sparc_cpu_model) {
case sun4c:
case sun4e:
case sun4:
- start_mem = sun4c_paging_init(start_mem, end_mem);
+ sun4c_paging_init();
sparc_unmapped_base = 0xe0000000;
BTFIXUPSET_SETHI(sparc_unmapped_base, 0xe0000000);
break;
case sun4m:
case sun4d:
- start_mem = srmmu_paging_init(start_mem, end_mem);
+ srmmu_paging_init();
sparc_unmapped_base = 0x50000000;
BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000);
break;
case ap1000:
#if CONFIG_AP1000
- start_mem = apmmu_paging_init(start_mem, end_mem);
+ apmmu_paging_init();
sparc_unmapped_base = 0x50000000;
BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000);
break;
@@ -194,74 +268,121 @@ paging_init(unsigned long start_mem, unsigned long end_mem)
protection_map[14] = PAGE_SHARED;
protection_map[15] = PAGE_SHARED;
btfixup();
- return device_scan(start_mem);
+ device_scan();
}
struct cache_palias *sparc_aliases;
-extern void srmmu_frob_mem_map(unsigned long);
+static void __init taint_real_pages(void)
+{
+ int i;
-int physmem_mapped_contig __initdata = 1;
+ for (i = 0; sp_banks[i].num_bytes; i++) {
+ unsigned long start, end;
-static void __init taint_real_pages(unsigned long start_mem, unsigned long end_mem)
-{
- unsigned long addr, tmp2 = 0;
-
- if(physmem_mapped_contig) {
- for(addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
- if(addr >= KERNBASE && addr < start_mem)
- addr = start_mem;
- for(tmp2=0; sp_banks[tmp2].num_bytes != 0; tmp2++) {
- unsigned long phys_addr = (addr - PAGE_OFFSET);
- unsigned long base = sp_banks[tmp2].base_addr;
- unsigned long limit = base + sp_banks[tmp2].num_bytes;
-
- if((phys_addr >= base) && (phys_addr < limit) &&
- ((phys_addr + PAGE_SIZE) < limit)) {
- mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved);
- set_bit(MAP_NR(addr) >> 8, sparc_valid_addr_bitmap);
- }
- }
+ start = sp_banks[i].base_addr;
+ end = start +
+ sp_banks[i].num_bytes;
+ while (start < end) {
+ set_bit (start >> 20,
+ sparc_valid_addr_bitmap);
+ start += PAGE_SIZE;
}
- } else {
- if((sparc_cpu_model == sun4m) || (sparc_cpu_model == sun4d)) {
- srmmu_frob_mem_map(start_mem);
+ }
+}
+
+void __init free_mem_map_range(struct page *first, struct page *last)
+{
+ first = (struct page *) PAGE_ALIGN((unsigned long)first);
+ last = (struct page *) ((unsigned long)last & PAGE_MASK);
+#ifdef DEBUG_BOOTMEM
+ prom_printf("[%p,%p] ", first, last);
+#endif
+ while (first < last) {
+ ClearPageReserved(mem_map + MAP_NR(first));
+ set_page_count(mem_map + MAP_NR(first), 1);
+ free_page((unsigned long)first);
+ totalram_pages++;
+ num_physpages++;
+
+ first = (struct page *)((unsigned long)first + PAGE_SIZE);
+ }
+}
+
+/* Walk through holes in sp_banks regions, if the mem_map array
+ * areas representing those holes consume a page or more, free
+ * up such pages. This helps a lot on machines where physical
+ * ram is configured such that it begins at some hugh value.
+ *
+ * The sp_banks array is sorted by base address.
+ */
+void __init free_unused_mem_map(void)
+{
+ int i;
+
+#ifdef DEBUG_BOOTMEM
+ prom_printf("free_unused_mem_map: ");
+#endif
+ for (i = 0; sp_banks[i].num_bytes; i++) {
+ if (i == 0) {
+ struct page *first, *last;
+
+ first = mem_map;
+ last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT];
+ free_mem_map_range(first, last);
} else {
- for(addr = start_mem; addr < end_mem; addr += PAGE_SIZE) {
- mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved);
- set_bit(MAP_NR(addr) >> 8, sparc_valid_addr_bitmap);
+ struct page *first, *last;
+ unsigned long prev_end;
+
+ prev_end = sp_banks[i-1].base_addr +
+ sp_banks[i-1].num_bytes;
+ prev_end = PAGE_ALIGN(prev_end);
+ first = &mem_map[prev_end >> PAGE_SHIFT];
+ last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT];
+
+ free_mem_map_range(first, last);
+
+ if (!sp_banks[i+1].num_bytes) {
+ prev_end = sp_banks[i].base_addr +
+ sp_banks[i].num_bytes;
+ first = &mem_map[prev_end >> PAGE_SHIFT];
+ last = &mem_map[last_valid_pfn];
+ free_mem_map_range(first, last);
}
}
}
+#ifdef DEBUG_BOOTMEM
+ prom_printf("\n");
+#endif
}
-void __init mem_init(unsigned long start_mem, unsigned long end_mem)
+void __init mem_init(void)
{
int codepages = 0;
int datapages = 0;
int initpages = 0;
int i;
- unsigned long addr;
- struct page *page, *end;
+ unsigned long addr, last;
/* Saves us work later. */
memset((void *) ZERO_PAGE(0), 0, PAGE_SIZE);
- end_mem &= PAGE_MASK;
- max_mapnr = MAP_NR(end_mem);
- high_memory = (void *) end_mem;
-
- sparc_valid_addr_bitmap = (unsigned long *)start_mem;
- i = max_mapnr >> (8 + 5);
+ i = last_valid_pfn >> (8 + 5);
i += 1;
- memset(sparc_valid_addr_bitmap, 0, i << 2);
- start_mem += i << 2;
- start_mem = PAGE_ALIGN(start_mem);
- num_physpages = 0;
+ sparc_valid_addr_bitmap = (unsigned long *)
+ __alloc_bootmem(i << 2, SMP_CACHE_BYTES, 0UL);
+
+ if (sparc_valid_addr_bitmap == NULL) {
+ prom_printf("mem_init: Cannot alloc valid_addr_bitmap.\n");
+ prom_halt();
+ }
+ memset(sparc_valid_addr_bitmap, 0, i << 2);
addr = KERNBASE;
- while(addr < start_mem) {
+ last = PAGE_ALIGN((unsigned long)&_end);
+ /* fix this */
+ while(addr < last) {
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end)
mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved);
@@ -272,69 +393,39 @@ void __init mem_init(unsigned long start_mem, unsigned long end_mem)
addr += PAGE_SIZE;
}
- taint_real_pages(start_mem, end_mem);
-
-#ifdef FREE_UNUSED_MEM_MAP
- end = mem_map + max_mapnr;
- for (page = mem_map; page < end; page++) {
- if (PageSkip(page)) {
- unsigned long low, high;
-
- /* See srmmu_frob_mem_map() for why this is done. -DaveM */
- page++;
-
- low = PAGE_ALIGN((unsigned long)(page+1));
- if (page->next_hash < page)
- high = ((unsigned long)end) & PAGE_MASK;
- else
- high = ((unsigned long)page->next_hash) & PAGE_MASK;
- while (low < high) {
- mem_map[MAP_NR(low)].flags &= ~(1<<PG_reserved);
- low += PAGE_SIZE;
- }
- }
- }
+ taint_real_pages();
+
+ max_mapnr = last_valid_pfn;
+ high_memory = __va(last_valid_pfn << PAGE_SHIFT);
+
+#ifdef DEBUG_BOOTMEM
+ prom_printf("mem_init: Calling free_all_bootmem().\n");
#endif
-
- for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
- if (PageSkip(mem_map + MAP_NR(addr))) {
- unsigned long next = mem_map[MAP_NR(addr)].next_hash - mem_map;
+ num_physpages = totalram_pages = free_all_bootmem();
- next = (next << PAGE_SHIFT) + PAGE_OFFSET;
- if (next < addr || next >= end_mem)
- break;
- addr = next;
- }
- num_physpages++;
- if(PageReserved(mem_map + MAP_NR(addr))) {
- if ((addr < (unsigned long) &etext) && (addr >= KERNBASE))
- codepages++;
- else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
- initpages++;
- else if((addr < start_mem) && (addr >= KERNBASE))
- datapages++;
- continue;
- }
- atomic_set(&mem_map[MAP_NR(addr)].count, 1);
-#ifdef CONFIG_BLK_DEV_INITRD
- if (!initrd_start ||
- (addr < initrd_start || addr >= initrd_end))
+#if 0
+ free_unused_mem_map();
#endif
- free_page(addr);
- }
+
+ codepages = (((unsigned long) &etext) - ((unsigned long)&_start));
+ codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT;
+ datapages = (((unsigned long) &edata) - ((unsigned long)&etext));
+ datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT;
+ initpages = (((unsigned long) &__init_end) - ((unsigned long) &__init_begin));
+ initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT;
printk("Memory: %dk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
- nr_free_pages << (PAGE_SHIFT-10),
+ nr_free_pages() << (PAGE_SHIFT-10),
codepages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
initpages << (PAGE_SHIFT-10),
- (unsigned long)PAGE_OFFSET, end_mem);
+ (unsigned long)PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT));
/* NOTE NOTE NOTE NOTE
* Please keep track of things and make sure this
* always matches the code in mm/page_alloc.c -DaveM
*/
- i = nr_free_pages >> 7;
+ i = nr_free_pages() >> 7;
if (i < 48)
i = 48;
if (i > 256)
@@ -347,39 +438,34 @@ void __init mem_init(unsigned long start_mem, unsigned long end_mem)
void free_initmem (void)
{
unsigned long addr;
-
+
addr = (unsigned long)(&__init_begin);
for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
- atomic_set(&mem_map[MAP_NR(addr)].count, 1);
- free_page(addr);
+ unsigned long page;
+ struct page *p;
+
+ page = (addr +
+ ((unsigned long) __va(phys_base)) -
+ PAGE_OFFSET);
+ p = mem_map + MAP_NR(page);
+
+ ClearPageReserved(p);
+ set_page_count(p, 1);
+ __free_page(p);
+ totalram_pages++;
+ num_physpages++;
}
}
void si_meminfo(struct sysinfo *val)
{
- struct page *page, *end;
-
- val->totalram = 0;
+ val->totalram = totalram_pages;
val->sharedram = 0;
- val->freeram = nr_free_pages << PAGE_SHIFT;
- val->bufferram = atomic_read(&buffermem);
- for (page = mem_map, end = mem_map + max_mapnr;
- page < end; page++) {
- if (PageSkip(page)) {
- if (page->next_hash < page)
- break;
- page = page->next_hash;
- }
- if (PageReserved(page))
- continue;
- val->totalram++;
- if (!atomic_read(&page->count))
- continue;
- val->sharedram += atomic_read(&page->count) - 1;
- }
- val->totalram <<= PAGE_SHIFT;
- val->sharedram <<= PAGE_SHIFT;
- val->totalbig = 0;
- val->freebig = 0;
+ val->freeram = nr_free_pages();
+ val->bufferram = atomic_read(&buffermem_pages);
+
+ val->totalhigh = 0;
+ val->freehigh = 0;
+
+ val->mem_unit = PAGE_SIZE;
}