diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-10-05 01:18:40 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-10-05 01:18:40 +0000 |
commit | 012bb3e61e5eced6c610f9e036372bf0c8def2d1 (patch) | |
tree | 87efc733f9b164e8c85c0336f92c8fb7eff6d183 /arch/ppc/mm/init.c | |
parent | 625a1589d3d6464b5d90b8a0918789e3afffd220 (diff) |
Merge with Linux 2.4.0-test9. Please check DECstation, I had a number
of rejects to fixup while integrating Linus patches. I also found
that this kernel will only boot SMP on Origin; the UP kernel freeze
soon after bootup with SCSI timeout messages. I commit this anyway
since I found that the last CVS versions had the same problem.
Diffstat (limited to 'arch/ppc/mm/init.c')
-rw-r--r-- | arch/ppc/mm/init.c | 322 |
1 files changed, 162 insertions, 160 deletions
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 67257c50b..be7d1f063 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -36,6 +36,7 @@ #include <linux/delay.h> #include <linux/openpic.h> #include <linux/bootmem.h> +#include <linux/highmem.h> #ifdef CONFIG_BLK_DEV_INITRD #include <linux/blk.h> /* for initrd_* */ #endif @@ -69,15 +70,20 @@ #include "4xx_tlb.h" #endif +#define MAX_LOW_MEM (640 << 20) + #define PGTOKB(pages) (((pages) * PAGE_SIZE) >> 10) int prom_trashed; atomic_t next_mmu_context; unsigned long *end_of_DRAM; +unsigned long total_memory; +unsigned long total_lowmem; int mem_init_done; int init_bootmem_done; int boot_mapsize; unsigned long totalram_pages = 0; +unsigned long totalhigh_pages = 0; extern pgd_t swapper_pg_dir[]; extern char _start[], _end[]; extern char etext[], _stext[]; @@ -98,22 +104,26 @@ extern unsigned int rtas_data, rtas_size; #ifndef CONFIG_SMP struct pgtable_cache_struct quicklists; #endif +#ifdef CONFIG_HIGHMEM +pte_t *kmap_pte; +pgprot_t kmap_prot; +#endif void MMU_init(void); static void *MMU_get_page(void); -unsigned long *prep_find_end_of_memory(void); -unsigned long *pmac_find_end_of_memory(void); -unsigned long *apus_find_end_of_memory(void); -unsigned long *gemini_find_end_of_memory(void); -extern unsigned long *find_end_of_memory(void); +unsigned long prep_find_end_of_memory(void); +unsigned long pmac_find_end_of_memory(void); +unsigned long apus_find_end_of_memory(void); +unsigned long gemini_find_end_of_memory(void); +extern unsigned long find_end_of_memory(void); #ifdef CONFIG_8xx -unsigned long *m8xx_find_end_of_memory(void); +unsigned long m8xx_find_end_of_memory(void); #endif /* CONFIG_8xx */ #ifdef CONFIG_4xx -unsigned long *oak_find_end_of_memory(void); +unsigned long oak_find_end_of_memory(void); #endif #ifdef CONFIG_8260 -unsigned long *m8260_find_end_of_memory(void); +unsigned long m8260_find_end_of_memory(void); #endif /* CONFIG_8260 */ static void mapin_ram(void); void map_page(unsigned long va, unsigned long pa, int flags); @@ -269,6 +279,7 @@ void show_mem(void) int i,free = 0,total = 0,reserved = 0; int shared = 0, cached = 0; struct task_struct *p; + int highmem = 0; printk("Mem-info:\n"); show_free_areas(); @@ -276,6 +287,8 @@ void show_mem(void) i = max_mapnr; while (i-- > 0) { total++; + if (PageHighMem(mem_map+i)) + highmem++; if (PageReserved(mem_map+i)) reserved++; else if (PageSwapCache(mem_map+i)) @@ -286,6 +299,7 @@ void show_mem(void) shared += atomic_read(&mem_map[i].count) - 1; } printk("%d pages of RAM\n",total); + printk("%d pages of HIGHMEM\n", highmem); printk("%d free pages\n",free); printk("%d reserved pages\n",reserved); printk("%d pages shared\n",shared); @@ -354,6 +368,8 @@ void si_meminfo(struct sysinfo *val) continue; val->sharedram += atomic_read(&mem_map[i].count) - 1; } + val->totalhigh = totalhigh_pages; + val->freehigh = nr_free_highpages(); val->mem_unit = PAGE_SIZE; } @@ -443,7 +459,8 @@ out: void iounmap(void *addr) { - /* XXX todo */ + if (addr > high_memory && (unsigned long) addr < ioremap_bot) + vfree((void *) (PAGE_MASK & (unsigned long) addr)); } unsigned long iopa(unsigned long addr) @@ -476,7 +493,7 @@ map_page(unsigned long va, unsigned long pa, int flags) { pmd_t *pd, oldpd; pte_t *pg; - + /* Use upper 10 bits of VA to index the first level map */ pd = pmd_offset(pgd_offset_k(va), va); oldpd = *pd; @@ -516,6 +533,7 @@ local_flush_tlb_all(void) flush_hash_segments(0xd, 0xffffff); #else __clear_user(Hash, Hash_size); + _tlbia(); #ifdef CONFIG_SMP smp_send_tlb_invalidate(0); #endif /* CONFIG_SMP */ @@ -610,6 +628,13 @@ mmu_context_overflow(void) } #endif /* CONFIG_8xx */ +void flush_page_to_ram(struct page *page) +{ + unsigned long vaddr = kmap(page); + __flush_page_to_ram(vaddr); + kunmap(page); +} + #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) static void get_mem_prop(char *, struct mem_pieces *); @@ -722,7 +747,7 @@ static void __init mapin_ram(void) if (align && align < max_size) max_size = align; - tot = (unsigned long)end_of_DRAM - KERNELBASE; + tot = total_lowmem; for (bl = 128<<10; bl < max_size; bl <<= 1) { if (bl * 2 > tot) break; @@ -745,6 +770,8 @@ static void __init mapin_ram(void) for (i = 0; i < phys_mem.n_regions; ++i) { v = (ulong)__va(phys_mem.regions[i].address); p = phys_mem.regions[i].address; + if (p >= total_lowmem) + break; for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) { /* On the MPC8xx, we want the page shared so we * don't get ASID compares on kernel space. @@ -766,6 +793,8 @@ static void __init mapin_ram(void) map_page(v, p, f); v += PAGE_SIZE; p += PAGE_SIZE; + if (p >= total_lowmem) + break; } } } @@ -788,77 +817,42 @@ static void __init *MMU_get_page(void) return p; } -void __init free_initmem(void) +static void free_sec(unsigned long start, unsigned long end, const char *name) { - unsigned long a; - unsigned long num_freed_pages = 0, num_prep_pages = 0, - num_pmac_pages = 0, num_openfirmware_pages = 0, - num_apus_pages = 0, num_chrp_pages = 0; -#define FREESEC(START,END,CNT) do { \ - a = (unsigned long)(&START); \ - for (; a < (unsigned long)(&END); a += PAGE_SIZE) { \ - clear_bit(PG_reserved, &virt_to_page(a)->flags); \ - set_page_count(virt_to_page(a), 1); \ - free_page(a); \ - CNT++; \ - } \ -} while (0) - - FREESEC(__init_begin,__init_end,num_freed_pages); - switch (_machine) - { - case _MACH_Pmac: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_chrp: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - break; - case _MACH_prep: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_mbx: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_apus: - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_gemini: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - } + unsigned long cnt = 0; - if ( !have_of ) - FREESEC( __openfirmware_begin, __openfirmware_end, - num_openfirmware_pages ); - - printk ("Freeing unused kernel memory: %ldk init", - PGTOKB(num_freed_pages)); - - if ( num_prep_pages ) - printk(" %ldk prep", PGTOKB(num_prep_pages)); - if ( num_chrp_pages ) - printk(" %ldk chrp", PGTOKB(num_chrp_pages)); - if ( num_pmac_pages ) - printk(" %ldk pmac", PGTOKB(num_pmac_pages)); - if ( num_openfirmware_pages ) - printk(" %ldk open firmware", PGTOKB(num_openfirmware_pages)); - if ( num_apus_pages ) - printk(" %ldk apus", PGTOKB(num_apus_pages)); - printk("\n"); + while (start < end) { + clear_bit(PG_reserved, &virt_to_page(start)->flags); + set_page_count(virt_to_page(start), 1); + free_page(start); + cnt++; + start += PAGE_SIZE; + } + if (cnt) + printk(" %ldk %s", PGTOKB(cnt), name); +} + +void free_initmem(void) +{ +#define FREESEC(TYPE) \ + free_sec((unsigned long)(&__ ## TYPE ## _begin), \ + (unsigned long)(&__ ## TYPE ## _end), \ + #TYPE); + + printk ("Freeing unused kernel memory:"); + FREESEC(init); + if (_machine != _MACH_Pmac) + FREESEC(pmac); + if (_machine != _MACH_chrp) + FREESEC(chrp); + if (_machine != _MACH_prep) + FREESEC(prep); + if (_machine != _MACH_apus) + FREESEC(apus); + if (!have_of) + FREESEC(openfirmware); + printk("\n"); +#undef FREESEC } #ifdef CONFIG_BLK_DEV_INITRD @@ -909,7 +903,8 @@ MMU_init(void) * at KERNELBASE. */ - end_of_DRAM = oak_find_end_of_memory(); + total_memory = total_lowmem = oak_find_end_of_memory(); + end_of_DRAM = __va(total_memory); mapin_ram(); /* @@ -939,23 +934,33 @@ void __init MMU_init(void) if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); #ifndef CONFIG_8xx if (have_of) - end_of_DRAM = pmac_find_end_of_memory(); + total_memory = pmac_find_end_of_memory(); #ifdef CONFIG_APUS else if (_machine == _MACH_apus ) - end_of_DRAM = apus_find_end_of_memory(); + total_memory = apus_find_end_of_memory(); #endif #ifdef CONFIG_GEMINI else if ( _machine == _MACH_gemini ) - end_of_DRAM = gemini_find_end_of_memory(); + total_memory = gemini_find_end_of_memory(); #endif /* CONFIG_GEMINI */ #if defined(CONFIG_8260) else - end_of_DRAM = m8260_find_end_of_memory(); + total_memory = m8260_find_end_of_memory(); #else else /* prep */ - end_of_DRAM = prep_find_end_of_memory(); + total_memory = prep_find_end_of_memory(); #endif + total_lowmem = total_memory; +#ifdef CONFIG_HIGHMEM + if (total_lowmem > MAX_LOW_MEM) { + total_lowmem = MAX_LOW_MEM; + mem_pieces_remove(&phys_avail, total_lowmem, + total_memory - total_lowmem, 0); + } +#endif /* CONFIG_HIGHMEM */ + end_of_DRAM = __va(total_lowmem); + if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300); hash_init(); #ifndef CONFIG_PPC64BRIDGE @@ -995,7 +1000,7 @@ void __init MMU_init(void) #endif break; case _MACH_Pmac: - ioremap_base = 0xf8000000; + ioremap_base = 0xfe000000; break; case _MACH_apus: /* Map PPC exception vectors. */ @@ -1022,7 +1027,15 @@ void __init MMU_init(void) #endif /* CONFIG_POWER4 */ #else /* CONFIG_8xx */ - end_of_DRAM = m8xx_find_end_of_memory(); + total_memory = total_lowmem = m8xx_find_end_of_memory(); +#ifdef CONFIG_HIGHMEM + if (total_lowmem > MAX_LOW_MEM) { + total_lowmem = MAX_LOW_MEM; + mem_pieces_remove(&phys_avail, total_lowmem, + total_memory - total_lowmem, 0); + } +#endif /* CONFIG_HIGHMEM */ + end_of_DRAM = __va(total_lowmem); /* Map in all of RAM starting at KERNELBASE */ mapin_ram(); @@ -1055,7 +1068,7 @@ void __init MMU_init(void) if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211); #ifdef CONFIG_BOOTX_TEXT /* Must be done last, or ppc_md.progress will die */ - if (_machine == _MACH_Pmac) + if (_machine == _MACH_Pmac || _machine == _MACH_chrp) map_bootx_text(); #endif } @@ -1092,7 +1105,7 @@ void __init do_init_bootmem(void) start = PAGE_ALIGN(start); boot_mapsize = init_bootmem(start >> PAGE_SHIFT, - __pa(end_of_DRAM) >> PAGE_SHIFT); + total_lowmem >> PAGE_SHIFT); /* remove the bootmem bitmap from the available memory */ mem_pieces_remove(&phys_avail, start, boot_mapsize, 1); @@ -1105,47 +1118,6 @@ void __init do_init_bootmem(void) init_bootmem_done = 1; } -#if 0 -/* - * Find some memory for setup_arch to return. - * We use the largest chunk of available memory as the area - * that setup_arch returns, making sure that there are at - * least 32 pages unused before this for MMU_get_page to use. - */ -unsigned long __init find_available_memory(void) -{ - int i, rn; - unsigned long a, free; - unsigned long start, end; - - if (_machine == _MACH_mbx) { - /* Return the first, not the last region, because we - * may not yet have properly initialized the additonal - * memory DIMM. - */ - a = PAGE_ALIGN(phys_avail.regions[0].address); - avail_start = (unsigned long) __va(a); - return avail_start; - } - - rn = 0; - for (i = 1; i < phys_avail.n_regions; ++i) - if (phys_avail.regions[i].size > phys_avail.regions[rn].size) - rn = i; - free = 0; - for (i = 0; i < rn; ++i) { - start = phys_avail.regions[i].address; - end = start + phys_avail.regions[i].size; - free += (end & PAGE_MASK) - PAGE_ALIGN(start); - } - a = PAGE_ALIGN(phys_avail.regions[rn].address); - if (free < 32 * PAGE_SIZE) - a += 32 * PAGE_SIZE - free; - avail_start = (unsigned long) __va(a); - return avail_start; -} -#endif /* 0 */ - /* * paging_init() sets up the page tables - in fact we've already done this. */ @@ -1153,6 +1125,14 @@ void __init paging_init(void) { unsigned long zones_size[MAX_NR_ZONES], i; +#ifdef CONFIG_HIGHMEM + map_page(PKMAP_BASE, 0, 0); /* XXX gross */ + pkmap_page_table = pte_offset(pmd_offset(pgd_offset_k(PKMAP_BASE), PKMAP_BASE), PKMAP_BASE); + map_page(KMAP_FIX_BEGIN, 0, 0); /* XXX gross */ + kmap_pte = pte_offset(pmd_offset(pgd_offset_k(KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN); + kmap_prot = PAGE_KERNEL; +#endif /* CONFIG_HIGHMEM */ + /* * Grab some memory for bad_page and bad_pagetable to use. */ @@ -1162,9 +1142,14 @@ void __init paging_init(void) /* * All pages are DMA-able so we put them all in the DMA zone. */ - zones_size[0] = ((unsigned long)end_of_DRAM - KERNELBASE) >> PAGE_SHIFT; + zones_size[ZONE_DMA] = total_lowmem >> PAGE_SHIFT; for (i = 1; i < MAX_NR_ZONES; i++) zones_size[i] = 0; + +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_HIGHMEM] = (total_memory - total_lowmem) >> PAGE_SHIFT; +#endif /* CONFIG_HIGHMEM */ + free_area_init(zones_size); } @@ -1176,7 +1161,17 @@ void __init mem_init(void) int codepages = 0; int datapages = 0; int initpages = 0; +#ifdef CONFIG_HIGHMEM + unsigned long highmem_mapnr; + + highmem_mapnr = total_lowmem >> PAGE_SHIFT; + highmem_start_page = mem_map + highmem_mapnr; + max_mapnr = total_memory >> PAGE_SHIFT; + totalram_pages += max_mapnr - highmem_mapnr; +#else max_mapnr = max_low_pfn; +#endif /* CONFIG_HIGHMEM */ + high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); num_physpages = max_mapnr; /* RAM is assumed contiguous */ @@ -1217,11 +1212,28 @@ void __init mem_init(void) datapages++; } - printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n", +#ifdef CONFIG_HIGHMEM + { + unsigned long pfn; + + for (pfn = highmem_mapnr; pfn < max_mapnr; ++pfn) { + struct page *page = mem_map + pfn; + + ClearPageReserved(page); + set_bit(PG_highmem, &page->flags); + atomic_set(&page->count, 1); + __free_page(page); + totalhigh_pages++; + } + totalram_pages += totalhigh_pages; + } +#endif /* CONFIG_HIGHMEM */ + + printk("Memory: %luk available (%dk kernel code, %dk data, %dk init, %ldk highmem)\n", (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10), codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10), initpages<< (PAGE_SHIFT-10), - PAGE_OFFSET, (unsigned long) end_of_DRAM); + (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))); mem_init_done = 1; } @@ -1234,7 +1246,7 @@ void __init mem_init(void) * Our text, data, bss use something over 1MB, starting at 0. * Open Firmware may be using 1MB at the 4MB point. */ -unsigned long __init *pmac_find_end_of_memory(void) +unsigned long __init pmac_find_end_of_memory(void) { unsigned long a, total; unsigned long ram_limit = 0xe0000000 - KERNELBASE; @@ -1279,7 +1291,7 @@ unsigned long __init *pmac_find_end_of_memory(void) set_phys_avail(&phys_mem); - return __va(total); + return total; } #endif /* CONFIG_ALL_PPC */ @@ -1290,7 +1302,7 @@ unsigned long __init *pmac_find_end_of_memory(void) * this will likely stay separate from the pmac. * -- Cort */ -unsigned long __init *prep_find_end_of_memory(void) +unsigned long __init prep_find_end_of_memory(void) { unsigned long total; total = res->TotalMemory; @@ -1308,15 +1320,15 @@ unsigned long __init *prep_find_end_of_memory(void) mem_pieces_append(&phys_mem, 0, total); set_phys_avail(&phys_mem); - return (__va(total)); + return (total); } #endif /* defined(CONFIG_ALL_PPC) */ #if defined(CONFIG_GEMINI) -unsigned long __init *gemini_find_end_of_memory(void) +unsigned long __init gemini_find_end_of_memory(void) { - unsigned long total, *ret; + unsigned long total; unsigned char reg; reg = readb(GEMINI_MEMCFG); @@ -1327,9 +1339,8 @@ unsigned long __init *gemini_find_end_of_memory(void) phys_mem.regions[0].size = total; phys_mem.n_regions = 1; - ret = __va(phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return ret; + return phys_mem.regions[0].size; } #endif /* defined(CONFIG_GEMINI) */ @@ -1337,10 +1348,9 @@ unsigned long __init *gemini_find_end_of_memory(void) /* * Same hack as 8xx. */ -unsigned long __init *m8260_find_end_of_memory(void) +unsigned long __init m8260_find_end_of_memory(void) { bd_t *binfo; - unsigned long *ret; extern unsigned char __res[]; binfo = (bd_t *)__res; @@ -1349,15 +1359,14 @@ unsigned long __init *m8260_find_end_of_memory(void) phys_mem.regions[0].size = binfo->bi_memsize; phys_mem.n_regions = 1; - ret = __va(phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return ret; + return phys_mem.regions[0].size; } #endif /* CONFIG_8260 */ #ifdef CONFIG_APUS #define HARDWARE_MAPPED_SIZE (512*1024) -unsigned long __init *apus_find_end_of_memory(void) +unsigned long __init apus_find_end_of_memory(void) { int shadow = 0; @@ -1421,7 +1430,7 @@ unsigned long __init *apus_find_end_of_memory(void) the PowerUP board. Other system memory is horrible slow in comparison. The user can use other memory for swapping using the z2ram device. */ - return __va(memory[0].addr + memory[0].size); + return memory[0].addr + memory[0].size; } #endif /* CONFIG_APUS */ @@ -1484,7 +1493,7 @@ static void __init hash_init(void) /* Find some memory for the hash table. */ if ( Hash_size ) { Hash = mem_pieces_find(Hash_size, Hash_size); - /*__clear_user(Hash, Hash_size);*/ + cacheable_memzero(Hash, Hash_size); } else Hash = 0; #endif /* CONFIG_PPC64BRIDGE */ @@ -1544,10 +1553,9 @@ static void __init hash_init(void) * functions in the image just to get prom_init, all we really need right * now is the initialization of the physical memory region. */ -unsigned long __init *m8xx_find_end_of_memory(void) +unsigned long __init m8xx_find_end_of_memory(void) { bd_t *binfo; - unsigned long *ret; extern unsigned char __res[]; binfo = (bd_t *)__res; @@ -1555,12 +1563,9 @@ unsigned long __init *m8xx_find_end_of_memory(void) phys_mem.regions[0].address = 0; phys_mem.regions[0].size = binfo->bi_memsize; phys_mem.n_regions = 1; - - ret = __va(phys_mem.regions[0].address+ - phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return ret; + return phys_mem.regions[0].address + phys_mem.regions[0].size; } #endif /* !CONFIG_4xx && !CONFIG_8xx */ @@ -1569,7 +1574,7 @@ unsigned long __init *m8xx_find_end_of_memory(void) * Return the virtual address representing the top of physical RAM * on the Oak board. */ -unsigned long __init * +unsigned long __init oak_find_end_of_memory(void) { extern unsigned char __res[]; @@ -1580,12 +1585,9 @@ oak_find_end_of_memory(void) phys_mem.regions[0].address = 0; phys_mem.regions[0].size = bip->bi_memsize; phys_mem.n_regions = 1; - - ret = __va(phys_mem.regions[0].address + - phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return (ret); + return (phys_mem.regions[0].address + phys_mem.regions[0].size); } #endif |