diff options
Diffstat (limited to 'arch/mips/mm')
-rw-r--r-- | arch/mips/mm/c-r3k.c | 21 | ||||
-rw-r--r-- | arch/mips/mm/c-r4k.c | 101 | ||||
-rw-r--r-- | arch/mips/mm/c-sb1.c | 105 | ||||
-rw-r--r-- | arch/mips/mm/c-tx39.c | 29 | ||||
-rw-r--r-- | arch/mips/mm/cache.c | 17 | ||||
-rw-r--r-- | arch/mips/mm/fault.c | 4 | ||||
-rw-r--r-- | arch/mips/mm/init.c | 4 | ||||
-rw-r--r-- | arch/mips/mm/tlb-r4k.c | 21 | ||||
-rw-r--r-- | arch/mips/mm/tlbex-fault.S | 4 |
9 files changed, 60 insertions, 246 deletions
diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c index bb041a22f20..d1af42c2a52 100644 --- a/arch/mips/mm/c-r3k.c +++ b/arch/mips/mm/c-r3k.c @@ -268,26 +268,6 @@ static void r3k_flush_data_cache_page(unsigned long addr) { } -static void r3k_flush_icache_page(struct vm_area_struct *vma, struct page *page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long physpage; - - if (cpu_context(smp_processor_id(), mm) == 0) - return; - - if (!(vma->vm_flags & VM_EXEC)) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", cpu_context(smp_processor_id(), mm), page); -#endif - - physpage = (unsigned long) page_address(page); - if (physpage) - r3k_flush_icache_range(physpage, physpage + PAGE_SIZE); -} - static void r3k_flush_cache_sigtramp(unsigned long addr) { unsigned long flags; @@ -335,7 +315,6 @@ void __init r3k_cache_init(void) flush_cache_mm = r3k_flush_cache_mm; flush_cache_range = r3k_flush_cache_range; flush_cache_page = r3k_flush_cache_page; - flush_icache_page = r3k_flush_icache_page; flush_icache_range = r3k_flush_icache_range; flush_cache_sigtramp = r3k_flush_cache_sigtramp; diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 069803f58f3..cc895dad71d 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -89,7 +89,7 @@ static inline void r4k_blast_dcache_page_dc32(unsigned long addr) blast_dcache32_page(addr); } -static inline void r4k_blast_dcache_page_setup(void) +static void __init r4k_blast_dcache_page_setup(void) { unsigned long dc_lsize = cpu_dcache_line_size(); @@ -103,7 +103,7 @@ static inline void r4k_blast_dcache_page_setup(void) static void (* r4k_blast_dcache_page_indexed)(unsigned long addr); -static inline void r4k_blast_dcache_page_indexed_setup(void) +static void __init r4k_blast_dcache_page_indexed_setup(void) { unsigned long dc_lsize = cpu_dcache_line_size(); @@ -117,7 +117,7 @@ static inline void r4k_blast_dcache_page_indexed_setup(void) static void (* r4k_blast_dcache)(void); -static inline void r4k_blast_dcache_setup(void) +static void __init r4k_blast_dcache_setup(void) { unsigned long dc_lsize = cpu_dcache_line_size(); @@ -202,7 +202,7 @@ static inline void tx49_blast_icache32_page_indexed(unsigned long page) static void (* r4k_blast_icache_page)(unsigned long addr); -static inline void r4k_blast_icache_page_setup(void) +static void __init r4k_blast_icache_page_setup(void) { unsigned long ic_lsize = cpu_icache_line_size(); @@ -219,7 +219,7 @@ static inline void r4k_blast_icache_page_setup(void) static void (* r4k_blast_icache_page_indexed)(unsigned long addr); -static inline void r4k_blast_icache_page_indexed_setup(void) +static void __init r4k_blast_icache_page_indexed_setup(void) { unsigned long ic_lsize = cpu_icache_line_size(); @@ -243,7 +243,7 @@ static inline void r4k_blast_icache_page_indexed_setup(void) static void (* r4k_blast_icache)(void); -static inline void r4k_blast_icache_setup(void) +static void __init r4k_blast_icache_setup(void) { unsigned long ic_lsize = cpu_icache_line_size(); @@ -264,7 +264,7 @@ static inline void r4k_blast_icache_setup(void) static void (* r4k_blast_scache_page)(unsigned long addr); -static inline void r4k_blast_scache_page_setup(void) +static void __init r4k_blast_scache_page_setup(void) { unsigned long sc_lsize = cpu_scache_line_size(); @@ -282,7 +282,7 @@ static inline void r4k_blast_scache_page_setup(void) static void (* r4k_blast_scache_page_indexed)(unsigned long addr); -static inline void r4k_blast_scache_page_indexed_setup(void) +static void __init r4k_blast_scache_page_indexed_setup(void) { unsigned long sc_lsize = cpu_scache_line_size(); @@ -300,7 +300,7 @@ static inline void r4k_blast_scache_page_indexed_setup(void) static void (* r4k_blast_scache)(void); -static inline void r4k_blast_scache_setup(void) +static void __init r4k_blast_scache_setup(void) { unsigned long sc_lsize = cpu_scache_line_size(); @@ -475,7 +475,7 @@ static inline void local_r4k_flush_cache_page(void *args) } } if (exec) { - if (cpu_has_vtag_icache) { + if (cpu_has_vtag_icache && mm == current->active_mm) { int cpu = smp_processor_id(); if (cpu_context(cpu, mm) != 0) @@ -551,82 +551,6 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end) instruction_hazard(); } -/* - * Ok, this seriously sucks. We use them to flush a user page but don't - * know the virtual address, so we have to blast away the whole icache - * which is significantly more expensive than the real thing. Otoh we at - * least know the kernel address of the page so we can flush it - * selectivly. - */ - -struct flush_icache_page_args { - struct vm_area_struct *vma; - struct page *page; -}; - -static inline void local_r4k_flush_icache_page(void *args) -{ - struct flush_icache_page_args *fip_args = args; - struct vm_area_struct *vma = fip_args->vma; - struct page *page = fip_args->page; - - /* - * Tricky ... Because we don't know the virtual address we've got the - * choice of either invalidating the entire primary and secondary - * caches or invalidating the secondary caches also. With the subset - * enforcment on R4000SC, R4400SC, R10000 and R12000 invalidating the - * secondary cache will result in any entries in the primary caches - * also getting invalidated which hopefully is a bit more economical. - */ - if (cpu_has_inclusive_pcaches) { - unsigned long addr = (unsigned long) page_address(page); - - r4k_blast_scache_page(addr); - ClearPageDcacheDirty(page); - - return; - } - - if (!cpu_has_ic_fills_f_dc) { - unsigned long addr = (unsigned long) page_address(page); - r4k_blast_dcache_page(addr); - if (!cpu_icache_snoops_remote_store) - r4k_blast_scache_page(addr); - ClearPageDcacheDirty(page); - } - - /* - * We're not sure of the virtual address(es) involved here, so - * we have to flush the entire I-cache. - */ - if (cpu_has_vtag_icache) { - int cpu = smp_processor_id(); - - if (cpu_context(cpu, vma->vm_mm) != 0) - drop_mmu_context(vma->vm_mm, cpu); - } else - r4k_blast_icache(); -} - -static void r4k_flush_icache_page(struct vm_area_struct *vma, - struct page *page) -{ - struct flush_icache_page_args args; - - /* - * If there's no context yet, or the page isn't executable, no I-cache - * flush is needed. - */ - if (!(vma->vm_flags & VM_EXEC)) - return; - - args.vma = vma; - args.page = page; - - r4k_on_each_cpu(local_r4k_flush_icache_page, &args, 1, 1); -} - - #ifdef CONFIG_DMA_NONCOHERENT static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) @@ -1221,7 +1145,7 @@ void au1x00_fixup_config_od(void) } } -static inline void coherency_setup(void) +static void __init coherency_setup(void) { change_c0_config(CONF_CM_CMASK, CONF_CM_DEFAULT); @@ -1242,7 +1166,7 @@ static inline void coherency_setup(void) clear_c0_config(CONF_CU); break; /* - * We need to catch the ealry Alchemy SOCs with + * We need to catch the early Alchemy SOCs with * the write-only co_config.od bit and set it back to one... */ case CPU_AU1000: /* rev. DA, HA, HB */ @@ -1291,7 +1215,6 @@ void __init r4k_cache_init(void) __flush_cache_all = r4k___flush_cache_all; flush_cache_mm = r4k_flush_cache_mm; flush_cache_page = r4k_flush_cache_page; - flush_icache_page = r4k_flush_icache_page; flush_cache_range = r4k_flush_cache_range; flush_cache_sigtramp = r4k_flush_cache_sigtramp; diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c index 2d71efb82ac..5537558f19f 100644 --- a/arch/mips/mm/c-sb1.c +++ b/arch/mips/mm/c-sb1.c @@ -155,6 +155,26 @@ static inline void __sb1_flush_icache_all(void) } /* + * Invalidate a range of the icache. The addresses are virtual, and + * the cache is virtually indexed and tagged. However, we don't + * necessarily have the right ASID context, so use index ops instead + * of hit ops. + */ +static inline void __sb1_flush_icache_range(unsigned long start, + unsigned long end) +{ + start &= ~(icache_line_size - 1); + end = (end + icache_line_size - 1) & ~(icache_line_size - 1); + + while (start != end) { + cache_set_op(Index_Invalidate_I, start & icache_index_mask); + start += icache_line_size; + } + mispredict(); + sync(); +} + +/* * Flush the icache for a given physical page. Need to writeback the * dcache first, then invalidate the icache. If the page isn't * executable, nothing is required. @@ -173,8 +193,11 @@ static void local_sb1_flush_cache_page(struct vm_area_struct *vma, unsigned long /* * Bumping the ASID is probably cheaper than the flush ... */ - if (cpu_context(cpu, vma->vm_mm) != 0) - drop_mmu_context(vma->vm_mm, cpu); + if (vma->vm_mm == current->active_mm) { + if (cpu_context(cpu, vma->vm_mm) != 0) + drop_mmu_context(vma->vm_mm, cpu); + } else + __sb1_flush_icache_range(addr, addr + PAGE_SIZE); } #ifdef CONFIG_SMP @@ -210,26 +233,6 @@ void sb1_flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsign __attribute__((alias("local_sb1_flush_cache_page"))); #endif -/* - * Invalidate a range of the icache. The addresses are virtual, and - * the cache is virtually indexed and tagged. However, we don't - * necessarily have the right ASID context, so use index ops instead - * of hit ops. - */ -static inline void __sb1_flush_icache_range(unsigned long start, - unsigned long end) -{ - start &= ~(icache_line_size - 1); - end = (end + icache_line_size - 1) & ~(icache_line_size - 1); - - while (start != end) { - cache_set_op(Index_Invalidate_I, start & icache_index_mask); - start += icache_line_size; - } - mispredict(); - sync(); -} - /* * Invalidate all caches on this CPU @@ -304,63 +307,6 @@ void sb1_flush_icache_range(unsigned long start, unsigned long end) #endif /* - * Flush the icache for a given physical page. Need to writeback the - * dcache first, then invalidate the icache. If the page isn't - * executable, nothing is required. - */ -static void local_sb1_flush_icache_page(struct vm_area_struct *vma, - struct page *page) -{ - unsigned long start; - int cpu = smp_processor_id(); - -#ifndef CONFIG_SMP - if (!(vma->vm_flags & VM_EXEC)) - return; -#endif - - /* Need to writeback any dirty data for that page, we have the PA */ - start = (unsigned long)(page-mem_map) << PAGE_SHIFT; - __sb1_writeback_inv_dcache_phys_range(start, start + PAGE_SIZE); - /* - * If there's a context, bump the ASID (cheaper than a flush, - * since we don't know VAs!) - */ - if (cpu_context(cpu, vma->vm_mm) != 0) { - drop_mmu_context(vma->vm_mm, cpu); - } -} - -#ifdef CONFIG_SMP -struct flush_icache_page_args { - struct vm_area_struct *vma; - struct page *page; -}; - -static void sb1_flush_icache_page_ipi(void *info) -{ - struct flush_icache_page_args *args = info; - local_sb1_flush_icache_page(args->vma, args->page); -} - -/* Dirty dcache could be on another CPU, so do the IPIs */ -static void sb1_flush_icache_page(struct vm_area_struct *vma, - struct page *page) -{ - struct flush_icache_page_args args; - - if (!(vma->vm_flags & VM_EXEC)) - return; - args.vma = vma; - args.page = page; - on_each_cpu(sb1_flush_icache_page_ipi, (void *) &args, 1, 1); -} -#else -void sb1_flush_icache_page(struct vm_area_struct *vma, struct page *page) - __attribute__((alias("local_sb1_flush_icache_page"))); -#endif - -/* * A signal trampoline must fit into a single cacheline. */ static void local_sb1_flush_cache_sigtramp(unsigned long addr) @@ -520,7 +466,6 @@ void sb1_cache_init(void) /* These routines are for Icache coherence with the Dcache */ flush_icache_range = sb1_flush_icache_range; - flush_icache_page = sb1_flush_icache_page; flush_icache_all = __sb1_flush_icache_all; /* local only */ /* This implies an Icache flush too, so can't be nop'ed */ diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c index 5dfc9b1901f..f32ebde30cc 100644 --- a/arch/mips/mm/c-tx39.c +++ b/arch/mips/mm/c-tx39.c @@ -248,33 +248,6 @@ static void tx39_flush_icache_range(unsigned long start, unsigned long end) } } -/* - * Ok, this seriously sucks. We use them to flush a user page but don't - * know the virtual address, so we have to blast away the whole icache - * which is significantly more expensive than the real thing. Otoh we at - * least know the kernel address of the page so we can flush it - * selectivly. - */ -static void tx39_flush_icache_page(struct vm_area_struct *vma, struct page *page) -{ - unsigned long addr; - /* - * If there's no context yet, or the page isn't executable, no icache - * flush is needed. - */ - if (!(vma->vm_flags & VM_EXEC)) - return; - - addr = (unsigned long) page_address(page); - tx39_blast_dcache_page(addr); - - /* - * We're not sure of the virtual address(es) involved here, so - * we have to flush the entire I-cache. - */ - tx39_blast_icache(); -} - static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size) { unsigned long end; @@ -382,7 +355,6 @@ void __init tx39_cache_init(void) flush_cache_mm = (void *) tx39h_flush_icache_all; flush_cache_range = (void *) tx39h_flush_icache_all; flush_cache_page = (void *) tx39h_flush_icache_all; - flush_icache_page = (void *) tx39h_flush_icache_all; flush_icache_range = (void *) tx39h_flush_icache_all; flush_cache_sigtramp = (void *) tx39h_flush_icache_all; @@ -408,7 +380,6 @@ void __init tx39_cache_init(void) flush_cache_mm = tx39_flush_cache_mm; flush_cache_range = tx39_flush_cache_range; flush_cache_page = tx39_flush_cache_page; - flush_icache_page = tx39_flush_icache_page; flush_icache_range = tx39_flush_icache_range; flush_cache_sigtramp = tx39_flush_cache_sigtramp; diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index ddd3a2de1d7..caf807ded51 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -25,7 +25,6 @@ void (*flush_cache_range)(struct vm_area_struct *vma, unsigned long start, void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn); void (*flush_icache_range)(unsigned long start, unsigned long end); -void (*flush_icache_page)(struct vm_area_struct *vma, struct page *page); /* MIPS specific cache operations */ void (*flush_cache_sigtramp)(unsigned long addr); @@ -70,6 +69,8 @@ void __flush_dcache_page(struct page *page) struct address_space *mapping = page_mapping(page); unsigned long addr; + if (PageHighMem(page)) + return; if (mapping && !mapping_mapped(mapping)) { SetPageDcacheDirty(page); return; @@ -91,16 +92,16 @@ void __update_cache(struct vm_area_struct *vma, unsigned long address, { struct page *page; unsigned long pfn, addr; + int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc; pfn = pte_pfn(pte); - if (pfn_valid(pfn) && (page = pfn_to_page(pfn), page_mapping(page)) && - Page_dcache_dirty(page)) { - if (pages_do_alias((unsigned long)page_address(page), - address & PAGE_MASK)) { - addr = (unsigned long) page_address(page); + if (unlikely(!pfn_valid(pfn))) + return; + page = pfn_to_page(pfn); + if (page_mapping(page) && Page_dcache_dirty(page)) { + addr = (unsigned long) page_address(page); + if (exec || pages_do_alias(addr, address & PAGE_MASK)) flush_data_cache_page(addr); - } - ClearPageDcacheDirty(page); } } diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index e3a61722486..8423d859077 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -89,7 +89,7 @@ good_area: if (!(vma->vm_flags & VM_WRITE)) goto bad_area; } else { - if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + if (!(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC))) goto bad_area; } @@ -171,7 +171,7 @@ no_context: */ out_of_memory: up_read(&mm->mmap_sem); - if (tsk->pid == 1) { + if (is_init(tsk)) { yield(); down_read(&mm->mmap_sem); goto survive; diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index c52497bb102..5b06349af2d 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -163,10 +163,10 @@ static int __init page_is_ram(unsigned long pagenr) void __init paging_init(void) { - unsigned long zones_size[] = { [0 ... MAX_NR_ZONES - 1] = 0 }; + unsigned long zones_size[] = { 0, }; unsigned long max_dma, high, low; #ifndef CONFIG_FLATMEM - unsigned long zholes_size[] = { [0 ... MAX_NR_ZONES - 1] = 0 }; + unsigned long zholes_size[] = { 0, }; unsigned long i, j, pfn; #endif diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index 2cde1b77244..2e0e21ef433 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -26,11 +26,6 @@ extern void build_tlb_refill_handler(void); */ #define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1))) -/* CP0 hazard avoidance. */ -#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ - "nop; nop; nop; nop; nop; nop;\n\t" \ - ".set reorder\n\t") - /* Atomicity and interruptability */ #ifdef CONFIG_MIPS_MT_SMTC @@ -126,7 +121,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, start += (PAGE_SIZE << 1); mtc0_tlbw_hazard(); tlb_probe(); - BARRIER; + tlb_probe_hazard(); idx = read_c0_index(); write_c0_entrylo0(0); write_c0_entrylo1(0); @@ -168,7 +163,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) start += (PAGE_SIZE << 1); mtc0_tlbw_hazard(); tlb_probe(); - BARRIER; + tlb_probe_hazard(); idx = read_c0_index(); write_c0_entrylo0(0); write_c0_entrylo1(0); @@ -202,7 +197,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) write_c0_entryhi(page | newpid); mtc0_tlbw_hazard(); tlb_probe(); - BARRIER; + tlb_probe_hazard(); idx = read_c0_index(); write_c0_entrylo0(0); write_c0_entrylo1(0); @@ -235,7 +230,7 @@ void local_flush_tlb_one(unsigned long page) write_c0_entryhi(page); mtc0_tlbw_hazard(); tlb_probe(); - BARRIER; + tlb_probe_hazard(); idx = read_c0_index(); write_c0_entrylo0(0); write_c0_entrylo1(0); @@ -279,7 +274,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) pgdp = pgd_offset(vma->vm_mm, address); mtc0_tlbw_hazard(); tlb_probe(); - BARRIER; + tlb_probe_hazard(); pudp = pud_offset(pgdp, address); pmdp = pmd_offset(pudp, address); idx = read_c0_index(); @@ -320,7 +315,7 @@ static void r4k_update_mmu_cache_hwbug(struct vm_area_struct * vma, pgdp = pgd_offset(vma->vm_mm, address); mtc0_tlbw_hazard(); tlb_probe(); - BARRIER; + tlb_probe_hazard(); pmdp = pmd_offset(pgdp, address); idx = read_c0_index(); ptep = pte_offset_map(pmdp, address); @@ -351,7 +346,7 @@ void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, wired = read_c0_wired(); write_c0_wired(wired + 1); write_c0_index(wired); - BARRIER; + tlbw_use_hazard(); /* What is the hazard here? */ write_c0_pagemask(pagemask); write_c0_entryhi(entryhi); write_c0_entrylo0(entrylo0); @@ -361,7 +356,7 @@ void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, tlbw_use_hazard(); write_c0_entryhi(old_ctx); - BARRIER; + tlbw_use_hazard(); /* What is the hazard here? */ write_c0_pagemask(old_pagemask); local_flush_tlb_all(); EXIT_CRITICAL(flags); diff --git a/arch/mips/mm/tlbex-fault.S b/arch/mips/mm/tlbex-fault.S index 9e7f4175b49..e99eaa1fbed 100644 --- a/arch/mips/mm/tlbex-fault.S +++ b/arch/mips/mm/tlbex-fault.S @@ -19,8 +19,8 @@ move a0, sp REG_S a2, PT_BVADDR(sp) li a1, \write - jal do_page_fault - j ret_from_exception + PTR_LA ra, ret_from_exception + j do_page_fault END(tlb_do_page_fault_\write) .endm |