diff options
Diffstat (limited to 'arch/parisc/kernel/cache.c')
-rw-r--r-- | arch/parisc/kernel/cache.c | 109 |
1 files changed, 17 insertions, 92 deletions
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index d054f3da3ff5..3f11331c2775 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -27,12 +27,17 @@ #include <asm/pgalloc.h> #include <asm/processor.h> #include <asm/sections.h> +#include <asm/shmparam.h> int split_tlb __read_mostly; int dcache_stride __read_mostly; int icache_stride __read_mostly; EXPORT_SYMBOL(dcache_stride); +void flush_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr); +EXPORT_SYMBOL(flush_dcache_page_asm); +void flush_icache_page_asm(unsigned long phys_addr, unsigned long vaddr); + /* On some machines (e.g. ones with the Merced bus), there can be * only a single PxTLB broadcast at a time; this must be guaranteed @@ -259,81 +264,13 @@ void disable_sr_hashing(void) panic("SpaceID hashing is still on!\n"); } -/* Simple function to work out if we have an existing address translation - * for a user space vma. */ -static inline int translation_exists(struct vm_area_struct *vma, - unsigned long addr, unsigned long pfn) -{ - pgd_t *pgd = pgd_offset(vma->vm_mm, addr); - pmd_t *pmd; - pte_t pte; - - if(pgd_none(*pgd)) - return 0; - - pmd = pmd_offset(pgd, addr); - if(pmd_none(*pmd) || pmd_bad(*pmd)) - return 0; - - /* We cannot take the pte lock here: flush_cache_page is usually - * called with pte lock already held. Whereas flush_dcache_page - * takes flush_dcache_mmap_lock, which is lower in the hierarchy: - * the vma itself is secure, but the pte might come or go racily. - */ - pte = *pte_offset_map(pmd, addr); - /* But pte_unmap() does nothing on this architecture */ - - /* Filter out coincidental file entries and swap entries */ - if (!(pte_val(pte) & (_PAGE_FLUSH|_PAGE_PRESENT))) - return 0; - - return pte_pfn(pte) == pfn; -} - -/* Private function to flush a page from the cache of a non-current - * process. cr25 contains the Page Directory of the current user - * process; we're going to hijack both it and the user space %sr3 to - * temporarily make the non-current process current. We have to do - * this because cache flushing may cause a non-access tlb miss which - * the handlers have to fill in from the pgd of the non-current - * process. */ static inline void -flush_user_cache_page_non_current(struct vm_area_struct *vma, - unsigned long vmaddr) +__flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, + unsigned long physaddr) { - /* save the current process space and pgd */ - unsigned long space = mfsp(3), pgd = mfctl(25); - - /* we don't mind taking interrupts since they may not - * do anything with user space, but we can't - * be preempted here */ - preempt_disable(); - - /* make us current */ - mtctl(__pa(vma->vm_mm->pgd), 25); - mtsp(vma->vm_mm->context, 3); - - flush_user_dcache_page(vmaddr); - if(vma->vm_flags & VM_EXEC) - flush_user_icache_page(vmaddr); - - /* put the old current process back */ - mtsp(space, 3); - mtctl(pgd, 25); - preempt_enable(); -} - - -static inline void -__flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr) -{ - if (likely(vma->vm_mm->context == mfsp(3))) { - flush_user_dcache_page(vmaddr); - if (vma->vm_flags & VM_EXEC) - flush_user_icache_page(vmaddr); - } else { - flush_user_cache_page_non_current(vma, vmaddr); - } + flush_dcache_page_asm(physaddr, vmaddr); + if (vma->vm_flags & VM_EXEC) + flush_icache_page_asm(physaddr, vmaddr); } void flush_dcache_page(struct page *page) @@ -342,10 +279,8 @@ void flush_dcache_page(struct page *page) struct vm_area_struct *mpnt; struct prio_tree_iter iter; unsigned long offset; - unsigned long addr; + unsigned long addr, old_addr = 0; pgoff_t pgoff; - unsigned long pfn = page_to_pfn(page); - if (mapping && !mapping_mapped(mapping)) { set_bit(PG_dcache_dirty, &page->flags); @@ -369,20 +304,11 @@ void flush_dcache_page(struct page *page) offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; addr = mpnt->vm_start + offset; - /* Flush instructions produce non access tlb misses. - * On PA, we nullify these instructions rather than - * taking a page fault if the pte doesn't exist. - * This is just for speed. If the page translation - * isn't there, there's no point exciting the - * nadtlb handler into a nullification frenzy. - * - * Make sure we really have this page: the private - * mappings may cover this area but have COW'd this - * particular page. - */ - if (translation_exists(mpnt, addr, pfn)) { - __flush_cache_page(mpnt, addr); - break; + if (old_addr == 0 || (old_addr & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) { + __flush_cache_page(mpnt, addr, page_to_phys(page)); + if (old_addr) + printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? mpnt->vm_file->f_path.dentry->d_name.name : "(null)"); + old_addr = addr; } } flush_dcache_mmap_unlock(mapping); @@ -573,7 +499,6 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long { BUG_ON(!vma->vm_mm->context); - if (likely(translation_exists(vma, vmaddr, pfn))) - __flush_cache_page(vma, vmaddr); + __flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn))); } |