Index: arch/mips/mm/c-r4k.c =================================================================== RCS file: /cvs/linux-mips/arch/mips/mm/c-r4k.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- arch/mips/mm/c-r4k.c 18 Jul 2002 17:35:18 -0000 1.1 +++ arch/mips/mm/c-r4k.c 18 Jul 2002 17:41:34 -0000 1.2 @@ -36,6 +36,7 @@ /* Secondary cache (if present) parameters. */ static unsigned int scache_size, sc_lsize; /* Again, in bytes */ +static int sc_present = 0; #include #include @@ -1195,6 +1196,126 @@ #endif } +static void r5k_flush_cache_range(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct vm_area_struct *vma; + unsigned long flags; + + if (mm->context == 0) + return; + + start &= PAGE_MASK; +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + vma = find_vma(mm, start); + if (vma) { + if (mm->context != current->active_mm->context) { + _flush_cache_all(); + } else { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + int text; + + __save_and_cli(flags); + text = vma->vm_flags & VM_EXEC; + while (start < end) { + pgd = pgd_offset(mm, start); + pmd = pmd_offset(pgd, start); + pte = pte_offset(pmd, start); + + if (pte_val(*pte) & _PAGE_VALID) { + blast_dcache32_page(start); + if (text) + blast_icache32_page(start); + } + start += PAGE_SIZE; + } + __restore_flags(flags); + } + } +} + +static void +r5k_dma_cache_inv_sc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= scache_size) { + blast_r5000_scache(); + return; + } + + /* We assume the address is in KSEG0. On the R5000 we + * cannot invalidate less than a page at a time, and + * there is no Hit_xxx cache operations. + */ + a = addr & ~(PAGE_SIZE - 1); + end = (addr + size - 1) & ~(PAGE_SIZE - 1); + while (a <= end) { + blast_r5000_scache_page_indexed(a); /* Page_Invalidate */ + a += PAGE_SIZE; + } +} + +static void +r5k_dma_cache_wback_inv(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= dcache_size) { + blast_dcache32(); + } else { + a = addr & ~(dc_lsize - 1); + end = (addr + size - 1) & ~(dc_lsize - 1); + while (a <= end) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + a += dc_lsize; + } + } + if (sc_present) + r5k_dma_cache_inv_sc(addr, size); +} + +static void +r5k_dma_cache_inv(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= dcache_size) { + blast_dcache32(); + } else { + a = addr & ~(dc_lsize - 1); + end = (addr + size - 1) & ~(dc_lsize - 1); + while (a <= end) { + invalidate_dcache_line(a); /* Hit_Invalidate_D */ + a += dc_lsize; + } + } + if (sc_present) + r5k_dma_cache_inv_sc(addr, size); +} + +static void +r5k_dma_cache_wback(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= dcache_size) { + blast_dcache32(); + } else { + a = addr & ~(dc_lsize - 1); + end = (addr + size - 1) & ~(dc_lsize - 1); + while (a <= end) { + flush_dcache_line_wb(a); /* Hit_Writeback_D */ + a += dc_lsize; + } + } +} + /* Detect and size the various r4k caches. */ static void __init probe_icache(unsigned long config) { @@ -1374,7 +1495,7 @@ _dma_cache_inv = r4k_dma_cache_inv_pc; } -static void __init setup_scache_funcs(void) +static void __init setup_scache_funcs_r4k(void) { switch(sc_lsize) { case 16: @@ -1457,19 +1578,36 @@ _dma_cache_inv = r4k_dma_cache_inv_sc; } +static void __init setup_scache_funcs_r5k(void) { + _clear_page = r4k_clear_page_d32; + _copy_page = r4k_copy_page_d32; + _flush_cache_all = r4k_flush_cache_all_d32i32; + _flush_cache_range = r5k_flush_cache_range; + _flush_cache_mm = r4k_flush_cache_mm_d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_d32; + + ___flush_cache_all = _flush_cache_all; + _flush_icache_page = r4k_flush_icache_page_p; + _dma_cache_wback_inv = r5k_dma_cache_wback_inv; + _dma_cache_wback = r5k_dma_cache_wback; + _dma_cache_inv = r5k_dma_cache_inv; +} + typedef int (*probe_func_t)(unsigned long); static inline void __init setup_scache(unsigned int config) { probe_func_t probe_scache_kseg1; - int sc_present = 0; /* Maybe the cpu knows about a l2 cache? */ probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache)); sc_present = probe_scache_kseg1(config); if (sc_present) { - setup_scache_funcs(); + if (mips_cpu.cputype == CPU_R5000) + setup_scache_funcs_r5k(); + else + setup_scache_funcs_r4k(); return; } Index: include/asm-mips/r4kcache.h =================================================================== RCS file: /cvs/linux-mips/include/asm-mips/r4kcache.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- include/asm-mips/r4kcache.h 18 Jul 2002 17:34:01 -0000 1.1 +++ include/asm-mips/r4kcache.h 18 Jul 2002 17:41:35 -0000 1.2 @@ -76,6 +76,19 @@ "i" (Hit_Writeback_Inv_D)); } +extern inline void flush_dcache_line_wb(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Hit_Writeback_D)); +} + static inline void invalidate_dcache_line(unsigned long addr) { __asm__ __volatile__( @@ -606,6 +619,40 @@ static inline void blast_scache128_page_indexed(unsigned long page) { cache128_unroll32(page,Index_Writeback_Inv_SD); +} + + +#define cache_unroll(base,op) \ + __asm__ __volatile__(" \ + .set noreorder; \ + .set mips3; \ + cache %1, (%0); \ + .set mips0; \ + .set reorder" \ + : \ + : "r" (base), \ + "i" (op)); + +extern inline void blast_r5000_scache(void) +{ + unsigned long start = KSEG0; + unsigned long end = KSEG0 + scache_size; + + while(start < end) { + cache_unroll(start,Page_Invalidate); + start += 128*sc_lsize; + } +} + +extern inline void blast_r5000_scache_page_indexed(unsigned long page) +{ + unsigned long start = page; + unsigned long end = page + PAGE_SIZE; + + while(start < end) { + cache_unroll(start,Page_Invalidate); + start += 128*sc_lsize; + } } #endif /* !(_MIPS_R4KCACHE_H) */