Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | /* * memory.c: memory initialisation code. * * Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine * Copyright (C) 2000, 2002 Maciej W. Rozycki */ #include <linux/config.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/bootmem.h> #include <linux/types.h> #include <asm/addrspace.h> #include <asm/bootinfo.h> #include <asm/dec/machtype.h> #include <asm/dec/prom.h> #include <asm/page.h> #include <asm/sections.h> volatile unsigned long mem_err = 0; /* So we know an error occurred */ /* * Probe memory in 4MB chunks, waiting for an error to tell us we've fallen * off the end of real memory. Only suitable for the 2100/3100's (PMAX). */ #define CHUNK_SIZE 0x400000 static inline void pmax_setup_memory_region(void) { volatile unsigned char *memory_page, dummy; char old_handler[0x80]; extern char genexcept_early; /* Install exception handler */ memcpy(&old_handler, (void *)(CKSEG0 + 0x80), 0x80); memcpy((void *)(CKSEG0 + 0x80), &genexcept_early, 0x80); /* read unmapped and uncached (KSEG1) * DECstations have at least 4MB RAM * Assume less than 480MB of RAM, as this is max for 5000/2xx * FIXME this should be replaced by the first free page! */ for (memory_page = (unsigned char *)CKSEG1 + CHUNK_SIZE; mem_err == 0 && memory_page < (unsigned char *)CKSEG1 + 0x1e00000; memory_page += CHUNK_SIZE) { dummy = *memory_page; } memcpy((void *)(CKSEG0 + 0x80), &old_handler, 0x80); add_memory_region(0, (unsigned long)memory_page - CKSEG1 - CHUNK_SIZE, BOOT_MEM_RAM); } /* * Use the REX prom calls to get hold of the memory bitmap, and thence * determine memory size. */ static inline void rex_setup_memory_region(void) { int i, bitmap_size; unsigned long mem_start = 0, mem_size = 0; memmap *bm; /* some free 64k */ bm = (memmap *)CKSEG0ADDR(0x28000); bitmap_size = rex_getbitmap(bm); for (i = 0; i < bitmap_size; i++) { /* FIXME: very simplistically only add full sets of pages */ if (bm->bitmap[i] == 0xff) mem_size += (8 * bm->pagesize); else if (!mem_size) mem_start += (8 * bm->pagesize); else { add_memory_region(mem_start, mem_size, BOOT_MEM_RAM); mem_start += mem_size + (8 * bm->pagesize); mem_size = 0; } } if (mem_size) add_memory_region(mem_start, mem_size, BOOT_MEM_RAM); } void __init prom_meminit(u32 magic) { if (!prom_is_rex(magic)) pmax_setup_memory_region(); else rex_setup_memory_region(); } unsigned long __init prom_free_prom_memory(void) { unsigned long addr, end; /* * Free everything below the kernel itself but leave * the first page reserved for the exception handlers. */ #if defined(CONFIG_DECLANCE) || defined(CONFIG_DECLANCE_MODULE) /* * Leave 128 KB reserved for Lance memory for * IOASIC DECstations. * * XXX: save this address for use in dec_lance.c? */ if (IOASIC) end = __pa(&_text) - 0x00020000; else #endif end = __pa(&_text); addr = PAGE_SIZE; while (addr < end) { ClearPageReserved(virt_to_page(__va(addr))); set_page_count(virt_to_page(__va(addr)), 1); free_page((unsigned long)__va(addr)); addr += PAGE_SIZE; } printk("Freeing unused PROM memory: %ldk freed\n", (end - PAGE_SIZE) >> 10); return end - PAGE_SIZE; } |