From: NIIBE Y. <gn...@m1...> - 2001-08-06 02:18:01
|
NIIBE Yutaka wrote: > (flush_cache_page): New implementation. (Assumes PTE is valid.) This was not correct. We flush the cache of different MM, so we can't directry do with OCB functions. Following is updated version. * arch/sh/mm/clear_page.S: Use aligned address for write back. * arch/sh/mm/__copy_user_page-sh4.S: Likewise. * arch/sh/mm/copy_page.S: Likewise. * arch/sh/mm/cache-sh4.c (CACHE_IC_NUM_WAYS, CACHE_OC_NUM_WAYS): Removed. (cache_wback_all): Removed and integrate to cache_init. * arch/sh/mm/copy_page.S: Write back TO, * arch/sh/mm/clear_page.S: Write back TO. * arch/sh/mm/cache-sh3.c (cache_init): Read CCR at P2. * arch/sh/mm/cache-sh4.c (cache_init): Likewise. (__flush_cache_page): Fix bug. Call restore_flags. (flush_cache_page): New implementation. (clear_user_page, copy_user_page): Do it in assembler routines. Index: arch/sh/mm/__copy_user_page-sh4.S =================================================================== RCS file: /cvsroot/linuxsh/kernel/arch/sh/mm/__copy_user_page-sh4.S,v retrieving revision 1.2 diff -u -p -r1.2 __copy_user_page-sh4.S --- arch/sh/mm/__copy_user_page-sh4.S 2001/07/28 14:22:06 1.2 +++ arch/sh/mm/__copy_user_page-sh4.S 2001/08/06 02:13:13 @@ -46,6 +46,7 @@ ENTRY(__copy_user_page) mov.l @r11+,r6 mov.l @r11+,r7 movca.l r0,@r10 + mov r10,r0 add #32,r10 mov.l r7,@-r10 mov.l r6,@-r10 @@ -54,11 +55,10 @@ ENTRY(__copy_user_page) mov.l r3,@-r10 mov.l r2,@-r10 mov.l r1,@-r10 - mov r10,r0 - add #28,r10 + ocbwb @r0 cmp/eq r11,r8 bf/s 1b - ocbwb @r0 + add #28,r10 ! mov.l @r15+,r11 mov.l @r15+,r10 Index: arch/sh/mm/cache-sh3.c =================================================================== RCS file: /cvsroot/linuxsh/kernel/arch/sh/mm/cache-sh3.c,v retrieving revision 1.1 diff -u -p -r1.1 cache-sh3.c --- arch/sh/mm/cache-sh3.c 2001/07/23 09:02:17 1.1 +++ arch/sh/mm/cache-sh3.c 2001/08/06 02:13:13 @@ -131,8 +131,8 @@ void __init cache_init(void) detect_cpu_and_cache_system(); - ccr = ctrl_inl(CCR); jump_to_P2(); + ccr = ctrl_inl(CCR); if (ccr & CCR_CACHE_ENABLE) /* * XXX: Should check RA here. Index: arch/sh/mm/cache-sh4.c =================================================================== RCS file: /cvsroot/linuxsh/kernel/arch/sh/mm/cache-sh4.c,v retrieving revision 1.9 diff -u -p -r1.9 cache-sh4.c --- arch/sh/mm/cache-sh4.c 2001/08/04 00:04:48 1.9 +++ arch/sh/mm/cache-sh4.c 2001/08/06 02:13:13 @@ -40,33 +40,9 @@ #define CACHE_IC_ENTRY_MASK 0x1fe0 #define CACHE_IC_NUM_ENTRIES 256 #define CACHE_OC_NUM_ENTRIES 512 -#define CACHE_OC_NUM_WAYS 1 -#define CACHE_IC_NUM_WAYS 1 -/* - * Write back all the cache. - * - * For SH-4, we only need to flush (write back) Operand Cache, - * as Instruction Cache doesn't have "updated" data. - * - * Assumes that this is called in interrupt disabled context, and P2. - * Shuld be INLINE function. - */ -static inline void cache_wback_all(void) -{ - unsigned long addr, data, i, j; - - for (i=0; i<CACHE_OC_NUM_ENTRIES; i++) { - for (j=0; j<CACHE_OC_NUM_WAYS; j++) { - addr = CACHE_OC_ADDRESS_ARRAY|(j<<CACHE_OC_WAY_SHIFT)| - (i<<CACHE_OC_ENTRY_SHIFT); - data = ctrl_inl(addr); - if ((data & (CACHE_UPDATED|CACHE_VALID)) - == (CACHE_UPDATED|CACHE_VALID)) - ctrl_outl(data & ~CACHE_UPDATED, addr); - } - } -} +/* Page is 4K, OC size is 16K, there are four lines. */ +#define CACHE_ALIAS 0x00003000 static void __init detect_cpu_and_cache_system(void) @@ -86,14 +62,25 @@ void __init cache_init(void) detect_cpu_and_cache_system(); - ccr = ctrl_inl(CCR); jump_to_P2(); - if (ccr & CCR_CACHE_ENABLE) + ccr = ctrl_inl(CCR); + if (ccr & CCR_CACHE_ENABLE) { /* * XXX: Should check RA here. * If RA was 1, we only need to flush the half of the caches. */ - cache_wback_all(); + unsigned long addr, data; + + for (addr = CACHE_OC_ADDRESS_ARRAY; + addr < (CACHE_OC_ADDRESS_ARRAY+ + (CACHE_OC_NUM_ENTRIES << CACHE_OC_ENTRY_SHIFT)); + addr += (1 << CACHE_OC_ENTRY_SHIFT)) { + data = ctrl_inl(addr); + if ((data & (CACHE_UPDATED|CACHE_VALID)) + == (CACHE_UPDATED|CACHE_VALID)) + ctrl_outl(data & ~CACHE_UPDATED, addr); + } + } ctrl_outl(CCR_CACHE_INIT, CCR); back_to_P1(); @@ -130,7 +117,7 @@ void __flush_wback_region(void *start, i unsigned long v; unsigned long begin, end; - begin = (unsigned long)start& ~(L1_CACHE_BYTES-1); + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); end = ((unsigned long)start + size + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); for (v = begin; v < end; v+=L1_CACHE_BYTES) { @@ -150,7 +137,7 @@ void __flush_purge_region(void *start, i unsigned long v; unsigned long begin, end; - begin = (unsigned long)start& ~(L1_CACHE_BYTES-1); + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); end = ((unsigned long)start + size + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); for (v = begin; v < end; v+=L1_CACHE_BYTES) { @@ -169,7 +156,7 @@ void __flush_invalidate_region(void *sta unsigned long v; unsigned long begin, end; - begin = (unsigned long)start& ~(L1_CACHE_BYTES-1); + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); end = ((unsigned long)start + size + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); for (v = begin; v < end; v+=L1_CACHE_BYTES) { @@ -244,7 +231,7 @@ void __flush_cache_page(unsigned long ph ctrl_outl(0, addr); } back_to_P1(); - save_and_cli(flags); + restore_flags(flags); } void __flush_icache_page(unsigned long u0, unsigned long phys) @@ -357,26 +344,64 @@ void flush_cache_range(struct mm_struct * * ADDR: Virtual Address (U0 address) */ -void flush_cache_page(struct vm_area_struct *vma, unsigned long addr) +void flush_cache_page(struct vm_area_struct *vma, unsigned long address) { pgd_t *dir; pmd_t *pmd; pte_t *pte; pte_t entry; - unsigned long phys; + unsigned long phys, addr, addr_end, data; + unsigned long flags; - dir = pgd_offset(vma->vm_mm, addr); - pmd = pmd_offset(dir, addr); - if (pmd_none(*pmd)) - return; - if (pmd_bad(*pmd)) + dir = pgd_offset(vma->vm_mm, address); + pmd = pmd_offset(dir, address); + if (pmd_none(*pmd) || pmd_bad(*pmd)) return; - pte = pte_offset(pmd, addr); + pte = pte_offset(pmd, address); entry = *pte; if (pte_none(entry) || !pte_present(entry)) return; - phys = PHYSADDR(pte_val(entry)&PAGE_MASK); - __flush_cache_page(phys, (vma->vm_flags & VM_EXEC)); + + phys = pte_val(entry)&PTE_PHYS_MASK; + + phys |= CACHE_VALID; + save_and_cli(flags); + jump_to_P2(); + + /* We only need to flush D-cache when we have alias */ + if ((address^phys) & CACHE_ALIAS) { + /* Loop 4K of the D-cache */ + for (addr = CACHE_OC_ADDRESS_ARRAY | (address & CACHE_ALIAS); + addr < (CACHE_OC_ADDRESS_ARRAY + (address & CACHE_ALIAS) + +(CACHE_OC_NUM_ENTRIES/4<<CACHE_OC_ENTRY_SHIFT)); + addr += (1<<CACHE_OC_ENTRY_SHIFT)) { + data = ctrl_inl(addr)&(0x1ffff000|CACHE_VALID); + if (data == phys) + ctrl_outl(0, addr); + } + /* Loop another 4K of the D-cache */ + for (addr = CACHE_OC_ADDRESS_ARRAY | (phys & CACHE_ALIAS); + addr < (CACHE_OC_ADDRESS_ARRAY + (phys & CACHE_ALIAS) + +(CACHE_OC_NUM_ENTRIES/4<<CACHE_OC_ENTRY_SHIFT)); + addr += (1<<CACHE_OC_ENTRY_SHIFT)) { + data = ctrl_inl(addr)&(0x1ffff000|CACHE_VALID); + if (data == phys) + ctrl_outl(0, addr); + } + } + + if (vma->vm_flags & VM_EXEC) + /* Loop 4K of the I-cache */ + for (addr = CACHE_IC_ADDRESS_ARRAY|(address&0x1000); + addr < ((CACHE_IC_ADDRESS_ARRAY|(address&0x1000)) + +(CACHE_IC_NUM_ENTRIES/2<<CACHE_IC_ENTRY_SHIFT)); + addr += (1<<CACHE_IC_ENTRY_SHIFT)) { + data = ctrl_inl(addr)&(0x1ffff000|CACHE_VALID); + if (data == phys) + ctrl_outl(0, addr); + } + back_to_P1(); + restore_flags(flags); } /* @@ -441,9 +466,6 @@ void check_cache_page(struct page *pg) } } -/* Page is 4K, OC size is 16K, there are four lines. */ -#define CACHE_ALIAS 0x00003000 - /* * clear_user_page * @to: P1 address @@ -451,10 +473,9 @@ void check_cache_page(struct page *pg) */ void clear_user_page(void *to, unsigned long address) { - if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) { + if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) clear_page(to); - __flush_wback_region(to, PAGE_SIZE); - } else { + else { pgprot_t pgprot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED | @@ -488,10 +509,9 @@ void clear_user_page(void *to, unsigned */ void copy_user_page(void *to, void *from, unsigned long address) { - if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) { + if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) copy_page(to, from); - __flush_wback_region(to, PAGE_SIZE); - } else { + else { pgprot_t pgprot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED | Index: arch/sh/mm/clear_page.S =================================================================== RCS file: /cvsroot/linuxsh/kernel/arch/sh/mm/clear_page.S,v retrieving revision 1.2 diff -u -p -r1.2 clear_page.S --- arch/sh/mm/clear_page.S 2001/07/23 10:27:24 1.2 +++ arch/sh/mm/clear_page.S 2001/08/06 02:13:13 @@ -30,6 +30,7 @@ ENTRY(clear_page) mov.l r0,@r4 #elif defined(__SH4__) movca.l r0,@r4 + mov r4,r1 #endif add #32,r4 mov.l r0,@-r4 @@ -39,6 +40,9 @@ ENTRY(clear_page) mov.l r0,@-r4 mov.l r0,@-r4 mov.l r0,@-r4 +#if defined(__SH4__) + ocbwb @r1 +#endif cmp/eq r5,r4 bf/s 1b add #28,r4 Index: arch/sh/mm/copy_page.S =================================================================== RCS file: /cvsroot/linuxsh/kernel/arch/sh/mm/copy_page.S,v retrieving revision 1.3 diff -u -p -r1.3 copy_page.S --- arch/sh/mm/copy_page.S 2001/07/28 15:23:38 1.3 +++ arch/sh/mm/copy_page.S 2001/08/06 02:13:13 @@ -44,6 +44,7 @@ ENTRY(copy_page) mov.l r0,@r10 #elif defined(__SH4__) movca.l r0,@r10 + mov r10,r0 #endif add #32,r10 mov.l r7,@-r10 @@ -53,6 +54,9 @@ ENTRY(copy_page) mov.l r3,@-r10 mov.l r2,@-r10 mov.l r1,@-r10 +#if defined(__SH4__) + ocbwb @r0 +#endif cmp/eq r11,r8 bf/s 1b add #28,r10 -- |