>>>>> On Mon, 21 Apr 2003 19:14:37 +0900 (JST), Atsushi Nemoto <anemo@mba.ocn.ne.jp> said: anemo> Here is a patch for TX39 fixes and cleanups: anemo> - kernel/cpu-probe.c: anemo> - TX39 does not have LLSC. anemo> - mm/c-tx39.c anemo> - Remove unused functions. anemo> - Add missing extern declarations. anemo> - Sync with recent c-r4k.c changes. (including anemo> _PAGE_VALID/_PAGE_PRESENT fix, dc_alias checking) anemo> - Use proper cp0.config macro. anemo> - Add TX39_STOP_STREAMING() to ensure icache-flushing. And this is a 2.5 version (untested). diff -ur linux-mips-2.5/arch/mips/kernel/cpu-probe.c linux-2.5.new/arch/mips/kernel/cpu-probe.c --- linux-mips-2.5/arch/mips/kernel/cpu-probe.c Wed Apr 16 21:52:15 2003 +++ linux-2.5.new/arch/mips/kernel/cpu-probe.c Wed Apr 23 00:34:06 2003 @@ -278,7 +278,7 @@ #endif case PRID_IMP_TX39: current_cpu_data.isa_level = MIPS_CPU_ISA_I; - current_cpu_data.options = MIPS_CPU_TLB | MIPS_CPU_LLSC; + current_cpu_data.options = MIPS_CPU_TLB; if ((current_cpu_data.processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) { diff -ur linux-mips-2.5/arch/mips/mm/c-tx39.c linux-2.5.new/arch/mips/mm/c-tx39.c --- linux-mips-2.5/arch/mips/mm/c-tx39.c Tue Apr 15 21:07:05 2003 +++ linux-2.5.new/arch/mips/mm/c-tx39.c Wed Apr 23 00:32:49 2003 @@ -28,16 +28,23 @@ static unsigned long icache_way_size, dcache_way_size; /* Size divided by ways */ extern long scache_size; -#define icache_lsize current_cpu_data.icache.linesz -#define dcache_lsize current_cpu_data.dcache.linesz - #include <asm/r4kcache.h> +extern void r3k_clear_page(void * page); +extern void r3k_copy_page(void * to, void * from); + extern int r3k_have_wired_reg; /* in r3k-tlb.c */ -static void tx39h_flush_data_cache_page(unsigned long addr) -{ -} +/* This sequence is required to ensure icache is disabled immediately */ +#define TX39_STOP_STREAMING() \ +__asm__ __volatile__( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + "b 1f\n\t" \ + "nop\n\t" \ + "1:\n\t" \ + ".set pop" \ + ) /* TX39H-style cache flush routines. */ static void tx39h_flush_icache_all(void) @@ -50,6 +57,7 @@ local_irq_save(flags); config = read_c0_conf(); write_c0_conf(config & ~TX39_CONF_ICE); + TX39_STOP_STREAMING(); /* invalidate icache */ while (start < end) { @@ -64,15 +72,15 @@ static void tx39h_dma_cache_wback_inv(unsigned long addr, unsigned long size) { unsigned long end, a; - int lsize = dcache_lsize; + unsigned long dc_lsize = current_cpu_data.dcache.linesz; iob(); - a = addr & ~(lsize - 1); - end = (addr + size - 1) & ~(lsize - 1); + a = addr & ~(dc_lsize - 1); + end = (addr + size - 1) & ~(dc_lsize - 1); while (1) { invalidate_dcache_line(a); /* Hit_Invalidate_D */ if (a == end) break; - a += lsize; + a += dc_lsize; } } @@ -101,6 +109,7 @@ local_irq_save(flags); config = read_c0_conf(); write_c0_conf(config & ~TX39_CONF_ICE); + TX39_STOP_STREAMING(); blast_icache16_page(addr); write_c0_conf(config); local_irq_restore(flags); @@ -113,6 +122,7 @@ local_irq_save(flags); config = read_c0_conf(); write_c0_conf(config & ~TX39_CONF_ICE); + TX39_STOP_STREAMING(); blast_icache16_page_indexed(addr); write_c0_conf(config); local_irq_restore(flags); @@ -125,6 +135,7 @@ local_irq_save(flags); config = read_c0_conf(); write_c0_conf(config & ~TX39_CONF_ICE); + TX39_STOP_STREAMING(); blast_icache16(); write_c0_conf(config); local_irq_restore(flags); @@ -132,12 +143,24 @@ static inline void tx39_flush_cache_all(void) { + if (!cpu_has_dc_aliases) + return; + + tx39_blast_dcache(); + tx39_blast_icache(); +} + +static inline void tx39___flush_cache_all(void) +{ tx39_blast_dcache(); tx39_blast_icache(); } static void tx39_flush_cache_mm(struct mm_struct *mm) { + if (!cpu_has_dc_aliases) + return; + if (cpu_context(smp_processor_id(), mm) != 0) { tx39_flush_cache_all(); } @@ -148,6 +171,9 @@ { struct mm_struct *mm = vma->vm_mm; + if (!cpu_has_dc_aliases) + return; + if (cpu_context(smp_processor_id(), mm) != 0) { tx39_blast_dcache(); tx39_blast_icache(); @@ -179,7 +205,7 @@ * If the page isn't marked valid, the page cannot possibly be * in the cache. */ - if (!(pte_val(*ptep) & _PAGE_VALID)) + if (!(pte_val(*ptep) & _PAGE_PRESENT)) return; /* @@ -188,8 +214,9 @@ * 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->active_mm) { - tx39_blast_dcache_page(page); + if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { + if (cpu_has_dc_aliases || exec) + tx39_blast_dcache_page(page); if (exec) tx39_blast_icache_page(page); @@ -201,7 +228,8 @@ * to work correctly. */ page = (KSEG0 + (page & (dcache_size - 1))); - tx39_blast_dcache_page_indexed(page); + if (cpu_has_dc_aliases || exec) + tx39_blast_dcache_page_indexed(page); if (exec) tx39_blast_icache_page_indexed(page); } @@ -213,7 +241,45 @@ static void tx39_flush_icache_range(unsigned long start, unsigned long end) { - flush_cache_all(); + unsigned long dc_lsize = current_cpu_data.dcache.linesz; + unsigned long addr, aend; + + if (end - start > dcache_size) + tx39_blast_dcache(); + else { + addr = start & ~(dc_lsize - 1); + aend = (end - 1) & ~(dc_lsize - 1); + + while (1) { + /* Hit_Writeback_Inv_D */ + protected_writeback_dcache_line(addr); + if (addr == aend) + break; + addr += dc_lsize; + } + } + + if (end - start > icache_size) + tx39_blast_icache(); + else { + unsigned long flags, config; + addr = start & ~(dc_lsize - 1); + aend = (end - 1) & ~(dc_lsize - 1); + /* disable icache (set ICE#) */ + local_irq_save(flags); + config = read_c0_conf(); + write_c0_conf(config & ~TX39_CONF_ICE); + TX39_STOP_STREAMING(); + while (1) { + /* Hit_Invalidate_I */ + protected_flush_icache_line(addr); + if (addr == aend) + break; + addr += dc_lsize; + } + write_c0_conf(config); + local_irq_restore(flags); + } } /* @@ -225,12 +291,22 @@ */ static void tx39_flush_icache_page(struct vm_area_struct *vma, struct page *page) { - if (vma->vm_flags & VM_EXEC) { - unsigned long addr = (unsigned long) page_address(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; - tx39_blast_dcache_page(addr); - tx39_blast_icache(); - } + 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) @@ -246,13 +322,13 @@ } else if (size > dcache_size) { tx39_blast_dcache(); } else { - int lsize = dcache_lsize; - a = addr & ~(lsize - 1); - end = (addr + size - 1) & ~(lsize - 1); + unsigned long dc_lsize = current_cpu_data.dcache.linesz; + a = addr & ~(dc_lsize - 1); + end = (addr + size - 1) & ~(dc_lsize - 1); while (1) { flush_dcache_line(a); /* Hit_Writeback_Inv_D */ if (a == end) break; - a += lsize; + a += dc_lsize; } } } @@ -270,34 +346,32 @@ } else if (size > dcache_size) { tx39_blast_dcache(); } else { - int lsize = dcache_lsize; - a = addr & ~(lsize - 1); - end = (addr + size - 1) & ~(lsize - 1); + unsigned long dc_lsize = current_cpu_data.dcache.linesz; + a = addr & ~(dc_lsize - 1); + end = (addr + size - 1) & ~(dc_lsize - 1); while (1) { invalidate_dcache_line(a); /* Hit_Invalidate_D */ if (a == end) break; - a += lsize; + a += dc_lsize; } } } -static void tx39_dma_cache_wback(unsigned long addr, unsigned long size) -{ - panic("tx39_dma_cache called - should not happen."); -} - static void tx39_flush_cache_sigtramp(unsigned long addr) { + unsigned long ic_lsize = current_cpu_data.icache.linesz; + unsigned long dc_lsize = current_cpu_data.dcache.linesz; unsigned long config; - unsigned int flags; + unsigned long flags; - protected_writeback_dcache_line(addr & ~(dcache_lsize - 1)); + protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); /* disable icache (set ICE#) */ local_irq_save(flags); config = read_c0_conf(); write_c0_conf(config & ~TX39_CONF_ICE); - protected_flush_icache_line(addr & ~(icache_lsize - 1)); + TX39_STOP_STREAMING(); + protected_flush_icache_line(addr & ~(ic_lsize - 1)); write_c0_conf(config); local_irq_restore(flags); } @@ -308,28 +382,30 @@ config = read_c0_conf(); - icache_size = 1 << (10 + ((config >> 19) & 3)); - dcache_size = 1 << (10 + ((config >> 16) & 3)); + icache_size = 1 << (10 + ((config & TX39_CONF_ICS_MASK) >> + TX39_CONF_ICS_SHIFT)); + dcache_size = 1 << (10 + ((config & TX39_CONF_DCS_MASK) >> + TX39_CONF_DCS_SHIFT)); - icache_lsize = 16; + current_cpu_data.icache.linesz = 16; switch (current_cpu_data.cputype) { case CPU_TX3912: current_cpu_data.icache.ways = 1; current_cpu_data.dcache.ways = 1; - dcache_lsize = 4; + current_cpu_data.dcache.linesz = 4; break; case CPU_TX3927: current_cpu_data.icache.ways = 2; current_cpu_data.dcache.ways = 2; - dcache_lsize = 16; + current_cpu_data.dcache.linesz = 16; break; case CPU_TX3922: default: current_cpu_data.icache.ways = 1; current_cpu_data.dcache.ways = 1; - dcache_lsize = 16; + current_cpu_data.dcache.linesz = 16; break; } } @@ -376,7 +452,7 @@ /* board-dependent init code may set WBON */ flush_cache_all = tx39_flush_cache_all; - __flush_cache_all = tx39_flush_cache_all; + __flush_cache_all = tx39___flush_cache_all; flush_cache_mm = tx39_flush_cache_mm; flush_cache_range = tx39_flush_cache_range; flush_cache_page = tx39_flush_cache_page; @@ -387,7 +463,7 @@ flush_data_cache_page = tx39_flush_data_cache_page; _dma_cache_wback_inv = tx39_dma_cache_wback_inv; - _dma_cache_wback = tx39_dma_cache_wback; + _dma_cache_wback = tx39_dma_cache_wback_inv; _dma_cache_inv = tx39_dma_cache_inv; shm_align_mask = max_t(unsigned long, @@ -400,17 +476,19 @@ icache_way_size = icache_size / current_cpu_data.icache.ways; dcache_way_size = dcache_size / current_cpu_data.dcache.ways; - current_cpu_data.icache.sets = icache_way_size / icache_lsize; - current_cpu_data.dcache.sets = dcache_way_size / dcache_lsize; + current_cpu_data.icache.sets = + icache_way_size / current_cpu_data.icache.linesz; + current_cpu_data.dcache.sets = + dcache_way_size / current_cpu_data.dcache.linesz; - current_cpu_data.icache.sets = icache_way_size / icache_lsize; - current_cpu_data.dcache.sets = dcache_way_size / dcache_lsize; + if (dcache_way_size > PAGE_SIZE) + current_cpu_data.dcache.flags |= MIPS_CACHE_ALIASES; current_cpu_data.icache.waybit = 0; current_cpu_data.dcache.waybit = 0; - printk("Primary instruction cache %dkb, linesize %d bytes\n", - (int) (icache_size >> 10), (int) icache_lsize); - printk("Primary data cache %dkb, linesize %d bytes\n", - (int) (dcache_size >> 10), (int) dcache_lsize); + printk("Primary instruction cache %ldkb, linesize %d bytes\n", + icache_size >> 10, current_cpu_data.icache.linesz); + printk("Primary data cache %ldkb, linesize %d bytes\n", + dcache_size >> 10, current_cpu_data.dcache.linesz); } --- Atsushi Nemoto