diff options
Diffstat (limited to 'arch/sparc64/mm/init.c')
-rw-r--r-- | arch/sparc64/mm/init.c | 235 |
1 files changed, 134 insertions, 101 deletions
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 960b3cbbd..a8d903b25 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,15 +1,17 @@ -/* $Id: init.c,v 1.29 1997/05/27 06:28:13 davem Exp $ +/* $Id: init.c,v 1.39 1997/07/07 02:50:57 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ +#include <linux/config.h> #include <linux/string.h> #include <linux/init.h> #include <linux/blk.h> #include <linux/swap.h> +#include <asm/head.h> #include <asm/system.h> #include <asm/page.h> #include <asm/pgtable.h> @@ -33,7 +35,7 @@ extern unsigned long empty_null_pte_table; unsigned long tlb_context_cache = CTX_FIRST_VERSION; /* References to section boundaries */ -extern char __init_begin, __init_end, etext, __p1275_loc, __bss_start; +extern char __init_begin, __init_end, etext, __bss_start; /* * BAD_PAGE is the page that is used for page faults when linux @@ -59,13 +61,15 @@ pmd_t *__bad_pmd(void) pte_t *__bad_pte(void) { memset((void *) &empty_bad_pte_table, 0, PAGE_SIZE); - return (pte_t *) (((unsigned long)&empty_bad_pte_table) + phys_base); + return (pte_t *) (((unsigned long)&empty_bad_pte_table) + - ((unsigned long)&empty_zero_page) + phys_base + PAGE_OFFSET); } pte_t __bad_page(void) { memset((void *) &empty_bad_page, 0, PAGE_SIZE); - return pte_mkdirty(mk_pte((((unsigned long) &empty_bad_page)+phys_base), + return pte_mkdirty(mk_pte((((unsigned long) &empty_bad_page) + - ((unsigned long)&empty_zero_page) + phys_base + PAGE_OFFSET), PAGE_SHARED)); } @@ -288,7 +292,7 @@ struct linux_prom_translation { }; #define MAX_TRANSLATIONS 64 -static void inherit_prom_mappings(void) +static inline void inherit_prom_mappings(void) { struct linux_prom_translation transl[MAX_TRANSLATIONS]; pgd_t *pgdp; @@ -332,7 +336,11 @@ static void inherit_prom_mappings(void) } } -static void inherit_locked_prom_mappings(void) +int prom_itlb_ent, prom_dtlb_ent; +unsigned long prom_itlb_tag, prom_itlb_data; +unsigned long prom_dtlb_tag, prom_dtlb_data; + +static inline void inherit_locked_prom_mappings(void) { int i; int dtlb_seen = 0; @@ -359,6 +367,9 @@ static void inherit_locked_prom_mappings(void) data = spitfire_get_dtlb_data(i); if(!dtlb_seen && (data & _PAGE_L)) { unsigned long tag = spitfire_get_dtlb_tag(i); + prom_dtlb_ent = i; + prom_dtlb_tag = tag; + prom_dtlb_data = data; __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); membar("#Sync"); @@ -379,6 +390,9 @@ static void inherit_locked_prom_mappings(void) data = spitfire_get_itlb_data(i); if(!itlb_seen && (data & _PAGE_L)) { unsigned long tag = spitfire_get_itlb_tag(i); + prom_itlb_ent = i; + prom_itlb_tag = tag; + prom_itlb_data = data; __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); membar("#Sync"); @@ -399,6 +413,64 @@ static void inherit_locked_prom_mappings(void) } } +/* Give PROM back his world, done during reboots... */ +void prom_reload_locked(void) +{ + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (prom_dtlb_tag), "r" (TLB_TAG_ACCESS), + "i" (ASI_DMMU)); + membar("#Sync"); + spitfire_put_dtlb_data(prom_dtlb_ent, prom_dtlb_data); + membar("#Sync"); + + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (prom_itlb_tag), "r" (TLB_TAG_ACCESS), + "i" (ASI_IMMU)); + membar("#Sync"); + spitfire_put_itlb_data(prom_itlb_ent, prom_itlb_data); + membar("#Sync"); +} + +/* If not locked, zap it. */ +void flush_tlb_all(void) +{ + unsigned long flags; + int i; + + save_flags(flags); cli(); + for(i = 0; i < 64; i++) { + if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) { + __asm__ __volatile__("stxa %%g0, [%0] %1" + : /* no outputs */ + : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); + membar("#Sync"); + spitfire_put_dtlb_data(i, 0x0UL); + membar("#Sync"); + } + if(!(spitfire_get_itlb_data(i) & _PAGE_L)) { + __asm__ __volatile__("stxa %%g0, [%0] %1" + : /* no outputs */ + : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); + membar("#Sync"); + spitfire_put_itlb_data(i, 0x0UL); + membar("#Sync"); + } + } + restore_flags(flags); +} + +void get_new_mmu_context(struct mm_struct *mm, unsigned long ctx) +{ + if((ctx & ~(CTX_VERSION_MASK)) == 0) { + flush_tlb_all(); + ctx = (ctx & CTX_VERSION_MASK) + CTX_FIRST_VERSION; + if(ctx == 1) + ctx = CTX_FIRST_VERSION; + } + tlb_context_cache = ctx + 1; + mm->context = ctx; +} + __initfunc(static void allocate_ptable_skeleton(unsigned long start, unsigned long end)) { @@ -440,9 +512,9 @@ void sparc_ultra_mapioaddr(unsigned long physaddr, unsigned long virt_addr, physaddr &= PAGE_MASK; if(rdonly) - pte = mk_pte_phys(physaddr, __pgprot(pg_iobits)); + pte = mk_pte_phys(physaddr, __pgprot(pg_iobits | __PRIV_BITS)); else - pte = mk_pte_phys(physaddr, __pgprot(pg_iobits | __DIRTY_BITS)); + pte = mk_pte_phys(physaddr, __pgprot(pg_iobits | __DIRTY_BITS | __PRIV_BITS)); set_pte(ptep, pte); } @@ -500,51 +572,42 @@ paging_init(unsigned long start_mem, unsigned long end_mem)) { extern unsigned long phys_base; extern void setup_tba(unsigned long kpgdir); - extern void __bfill64(void *, unsigned long); - pgd_t *pgdp; + extern void __bfill64(void *, unsigned long *); pmd_t *pmdp; - pte_t *ptep, pte; int i; - - /* Must create 2nd locked DTLB entry if physical ram starts at - * 4MB absolute or higher, kernel image has been placed in the - * right place at PAGE_OFFSET but references to start_mem and pages - * will be to the perfect alias mapping, so set it up now. + unsigned long alias_base = phys_base + PAGE_OFFSET; + unsigned long pt; + unsigned long flags; + unsigned long shift = alias_base - ((unsigned long)&empty_zero_page); + + /* We assume physical memory starts at some 4mb multiple, + * if this were not true we wouldn't boot up to this point + * anyways. */ - if(phys_base >= (4 * 1024 * 1024)) { - unsigned long alias_base = phys_base + PAGE_OFFSET; - unsigned long pte; - unsigned long flags; - - /* We assume physical memory starts at some 4mb multiple, - * if this were not true we wouldn't boot up to this point - * anyways. - */ - pte = phys_base | _PAGE_VALID | _PAGE_SZ4MB; - pte |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W; - save_flags(flags); cli(); - __asm__ __volatile__(" - stxa %1, [%0] %3 - stxa %2, [%5] %4 - membar #Sync - flush %%g4 - nop - nop - nop" - : /* No outputs */ - : "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pte), - "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3) - : "memory"); - restore_flags(flags); - - /* Now set kernel pgd to upper alias so physical page computations - * work. - */ - init_mm.pgd += (phys_base / (sizeof(pgd_t *))); - } + pt = phys_base | _PAGE_VALID | _PAGE_SZ4MB; + pt |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W; + save_flags(flags); cli(); + __asm__ __volatile__(" + stxa %1, [%0] %3 + stxa %2, [%5] %4 + membar #Sync + flush %%g6 + nop + nop + nop" + : /* No outputs */ + : "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt), + "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3) + : "memory"); + restore_flags(flags); + + /* Now set kernel pgd to upper alias so physical page computations + * work. + */ + init_mm.pgd += ((shift) / (sizeof(pgd_t *))); - null_pmd_table = __pa(((unsigned long)&empty_null_pmd_table) + phys_base); - null_pte_table = __pa(((unsigned long)&empty_null_pte_table) + phys_base); + null_pmd_table = __pa(((unsigned long)&empty_null_pmd_table) + shift); + null_pte_table = __pa(((unsigned long)&empty_null_pte_table) + shift); pmdp = (pmd_t *) &empty_null_pmd_table; for(i = 0; i < 1024; i++) @@ -553,13 +616,13 @@ paging_init(unsigned long start_mem, unsigned long end_mem)) memset((void *) &empty_null_pte_table, 0, PAGE_SIZE); /* Now can init the kernel/bad page tables. */ - __bfill64((void *)swapper_pg_dir, null_pmd_table); - __bfill64((void *)&empty_bad_pmd_table, null_pte_table); + __bfill64((void *)swapper_pg_dir, &null_pmd_table); + __bfill64((void *)&empty_bad_pmd_table, &null_pte_table); /* We use mempool to create page tables, therefore adjust it up * such that __pa() macros etc. work. */ - mempool = PAGE_ALIGN(start_mem) + phys_base; + mempool = PAGE_ALIGN(start_mem) + shift; /* FIXME: This should be done much nicer. * Just now we allocate 64M for each. @@ -567,48 +630,29 @@ paging_init(unsigned long start_mem, unsigned long end_mem)) allocate_ptable_skeleton(IOBASE_VADDR, IOBASE_VADDR + 0x4000000); allocate_ptable_skeleton(DVMA_VADDR, DVMA_VADDR + 0x4000000); inherit_prom_mappings(); - allocate_ptable_skeleton(0, 0x8000 + PAGE_SIZE); - - /* Map prom interface page. */ - pgdp = pgd_offset(init_task.mm, 0x8000); - pmdp = pmd_offset(pgdp, 0x8000); - ptep = pte_offset(pmdp, 0x8000); - pte = mk_pte(((unsigned long)&__p1275_loc)+phys_base, PAGE_KERNEL); - set_pte(ptep, pte); - + /* Ok, we can use our TLB miss and window trap handlers safely. */ setup_tba((unsigned long)init_mm.pgd); - /* Kill locked PROM interface page mapping, the mapping will - * re-enter on the next PROM interface call via our TLB miss - * handlers. - */ - spitfire_flush_dtlb_primary_page(0x8000); - membar("#Sync"); - spitfire_flush_itlb_primary_page(0x8000); - membar("#Sync"); - /* Really paranoid. */ - flushi(PAGE_OFFSET); + flushi((long)&empty_zero_page); membar("#Sync"); /* Cleanup the extra locked TLB entry we created since we have the * nice TLB miss handlers of ours installed now. */ - if(phys_base >= (4 * 1024 * 1024)) { - /* We only created DTLB mapping of this stuff. */ - spitfire_flush_dtlb_nucleus_page(phys_base + PAGE_OFFSET); - membar("#Sync"); - - /* Paranoid */ - flushi(PAGE_OFFSET); - membar("#Sync"); - } + /* We only created DTLB mapping of this stuff. */ + spitfire_flush_dtlb_nucleus_page(alias_base); + membar("#Sync"); - inherit_locked_prom_mappings(); + /* Paranoid */ + flushi((long)&empty_zero_page); + membar("#Sync"); + inherit_locked_prom_mappings(); + flush_tlb_all(); - + start_mem = free_area_init(PAGE_ALIGN(mempool), end_mem); return device_scan (PAGE_ALIGN (start_mem)); @@ -642,9 +686,8 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) int codepages = 0; int datapages = 0; int initpages = 0; - int prompages = 0; unsigned long tmp2, addr; - unsigned long data_end; + unsigned long alias_base = phys_base + PAGE_OFFSET - (long)(&empty_zero_page); end_mem &= PAGE_MASK; max_mapnr = MAP_NR(end_mem); @@ -665,16 +708,14 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) } taint_real_pages(start_mem, end_mem); - data_end = start_mem - phys_base; for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) { if(PageReserved(mem_map + MAP_NR(addr))) { - if ((addr < (unsigned long) &etext) && (addr >= PAGE_OFFSET)) + if ((addr < ((unsigned long) &etext) + alias_base) && (addr >= alias_base)) codepages++; - else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end)) + else if((addr >= ((unsigned long)&__init_begin) + alias_base) + && (addr < ((unsigned long)&__init_end) + alias_base)) initpages++; - else if((addr >= (unsigned long)&__p1275_loc && addr < (unsigned long)&__bss_start)) - prompages++; - else if((addr < data_end) && (addr >= PAGE_OFFSET)) + else if((addr < start_mem) && (addr >= alias_base)) datapages++; continue; } @@ -689,12 +730,11 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) tmp2 = nr_free_pages << PAGE_SHIFT; - printk("Memory: %luk available (%dk kernel code, %dk data, %dk init, %dk prom) [%016lx,%016lx]\n", + printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%016lx,%016lx]\n", tmp2 >> 10, codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10), - prompages << (PAGE_SHIFT-10), PAGE_OFFSET, end_mem); min_free_pages = nr_free_pages >> 7; @@ -702,11 +742,6 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) min_free_pages = 16; free_pages_low = min_free_pages + (min_free_pages >> 1); free_pages_high = min_free_pages + min_free_pages; - -#if 0 - printk("Testing fault handling...\n"); - *(char *)0x00000deadbef0000UL = 0; -#endif } void free_initmem (void) @@ -715,10 +750,8 @@ void free_initmem (void) addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { - unsigned long page = addr; - - if(page < ((unsigned long)__va(phys_base))) - page += phys_base; + unsigned long page = addr + (long)__va(phys_base) + - (long)(&empty_zero_page); mem_map[MAP_NR(page)].flags &= ~(1 << PG_reserved); atomic_set(&mem_map[MAP_NR(page)].count, 1); |