diff options
-rw-r--r-- | arch/mips64/mm/andes.c | 123 | ||||
-rw-r--r-- | include/asm-mips64/pgtable.h | 24 |
2 files changed, 44 insertions, 103 deletions
diff --git a/arch/mips64/mm/andes.c b/arch/mips64/mm/andes.c index 9c6fb5fa4..bcbb07760 100644 --- a/arch/mips64/mm/andes.c +++ b/arch/mips64/mm/andes.c @@ -18,6 +18,8 @@ #include <asm/sgialib.h> #include <asm/mmu_context.h> +static int scache_lsz64; + /* CP0 hazard avoidance. I think we can drop this for the R10000. */ #define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ "nop; nop; nop; nop; nop; nop;\n\t" \ @@ -116,106 +118,13 @@ andes_flush_cache_l2(void) } } -static void -andes_flush_cache_mm(struct mm_struct *mm) -{ - if (CPU_CONTEXT(smp_processor_id(), mm) != 0) { -#ifdef DEBUG_CACHE - printk("cmm[%d]", (int)mm->context); -#endif - andes_flush_cache_l1(); - } -} - -static void -andes_flush_cache_range(struct mm_struct *mm, unsigned long start, - unsigned long end) +void +andes_flush_icache_page(unsigned long page) { - if (CPU_CONTEXT(smp_processor_id(), mm) != 0) { - unsigned long flags; - -#ifdef DEBUG_CACHE - printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); -#endif - save_and_cli(flags); - blast_dcache32(); blast_icache64(); - restore_flags(flags); - } -} - -static void -andes_flush_cache_page(struct vm_area_struct *vma, unsigned long page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long flags; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - int text; - - /* - * If ownes no valid ASID yet, cannot possibly have gotten - * this page into the cache. - */ - if (CPU_CONTEXT(smp_processor_id(), mm) == 0) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", (int)mm->context, page); -#endif - save_and_cli(flags); - page &= PAGE_MASK; - pgdp = pgd_offset(mm, page); - pmdp = pmd_offset(pgdp, page); - ptep = pte_offset(pmdp, page); - - /* - * If the page isn't marked valid, the page cannot possibly be - * in the cache. - */ - if(!(pte_val(*ptep) & _PAGE_PRESENT)) - goto out; - - text = (vma->vm_flags & VM_EXEC); - /* - * Doing flushes for another ASID than the current one is - * too difficult since stupid R4k caches do a TLB translation - * for every cache flush operation. So we do indexed flushes - * in that case, which doesn't overly flush the cache too much. - */ - if ((mm == current->mm) && (pte_val(*ptep) & _PAGE_VALID)) { - blast_dcache32_page(page); - if(text) - blast_icache64_page(page); - } else { - /* - * Do indexed flush, too much work to get the (possible) - * tlb refills to work correctly. - */ - page = (CKSEG0 + (page & (dcache_size - 1))); - blast_dcache32_page_indexed(page); - if(text) - blast_icache64_page_indexed(page); - } -out: - restore_flags(flags); -} - -/* Hoo hum... will this ever be called for an address that is not in CKSEG0 - and not cacheable? */ -static void -andes_flush_page_to_ram(struct page * page) -{ - unsigned long addr = page_address(page) & PAGE_MASK; - - if ((addr >= K0BASE_NONCOH && addr < (0xb0UL << 56)) - || (addr >= KSEG0 && addr < KSEG1) - || (addr >= KSEG2)) { -#ifdef DEBUG_CACHE - printk("cram[%08lx]", addr); -#endif - blast_dcache32_page(addr); - } + if (scache_lsz64) + blast_scache64_page(page); + else + blast_scache128_page(page); } static void @@ -476,16 +385,24 @@ void __init ld_mmu_andes(void) _flush_cache_l1 = andes_flush_cache_l1; _flush_cache_l2 = andes_flush_cache_l2; - _flush_cache_mm = andes_flush_cache_mm; - _flush_cache_range = andes_flush_cache_range; - _flush_cache_page = andes_flush_cache_page; _flush_cache_sigtramp = andes_flush_cache_sigtramp; - _flush_page_to_ram = andes_flush_page_to_ram; _flush_tlb_all = andes_flush_tlb_all; _flush_tlb_mm = andes_flush_tlb_mm; _flush_tlb_range = andes_flush_tlb_range; _flush_tlb_page = andes_flush_tlb_page; + + switch (sc_lsize()) { + case 64: + scache_lsz64 = 1; + break; + case 128: + scache_lsz64 = 0; + break; + default: + printk("Unknown L2 line size\n"); + while(1); + } update_mmu_cache = andes_update_mmu_cache; diff --git a/include/asm-mips64/pgtable.h b/include/asm-mips64/pgtable.h index a5b5b977d..c40380569 100644 --- a/include/asm-mips64/pgtable.h +++ b/include/asm-mips64/pgtable.h @@ -34,6 +34,8 @@ extern void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page) extern void (*_flush_page_to_ram)(struct page * page); #define flush_cache_all() do { } while(0) + +#ifndef CONFIG_CPU_R10000 #define flush_cache_mm(mm) _flush_cache_mm(mm) #define flush_cache_range(mm,start,end) _flush_cache_range(mm,start,end) #define flush_cache_page(vma,page) _flush_cache_page(vma, page) @@ -47,6 +49,28 @@ do { \ addr = page_address(page); \ _flush_cache_page(vma, addr); \ } while (0) +#else /* !CONFIG_CPU_R10000 */ +/* + * Since the r10k handles VCEs in hardware, most of the flush cache + * routines are not needed. Only the icache on a processor is not + * coherent with the dcache of the _same_ processor, so we must flush + * the icache so that it does not contain stale contents of physical + * memory. No flushes are needed for dma coherency, since the o200s + * are io coherent. The only place where we might be overoptimizing + * out icache flushes are from mprotect (when PROT_EXEC is added). + */ +extern void andes_flush_icache_page(unsigned long); +#define flush_cache_mm(mm) do { } while(0) +#define flush_cache_range(mm,start,end) do { } while(0) +#define flush_cache_page(vma,page) do { } while(0) +#define flush_page_to_ram(page) do { } while(0) +#define flush_icache_range(start, end) _flush_cache_l1() +#define flush_icache_page(vma, page) \ +do { \ + if ((vma)->vm_flags & VM_EXEC) \ + andes_flush_icache_page(page_address(page)); \ +} while (0) +#endif /* !CONFIG_CPU_R10000 */ /* * The foll cache flushing routines are MIPS specific. |