From: NIIBE Y. <gn...@m1...> - 2001-08-05 08:11:00
|
* 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. (Assumes PTE is valid.) (clear_user_page, copy_user_page): Do it in assembler routines. 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/05 08:06:53 @@ -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/05 08:06:53 @@ -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,15 +62,26 @@ 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(); } @@ -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,48 @@ 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, 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)) + __flush_purge_region((void *)(address&PAGE_MASK), PAGE_SIZE); + + dir = pgd_offset(vma->vm_mm, address); + pmd = pmd_offset(dir, address); + if (pmd_none(*pmd) || pmd_bad(*pmd)) { + printk(KERN_ERR "flush_cache_page: No valid PMD"); return; - pte = pte_offset(pmd, addr); + } + pte = pte_offset(pmd, address); entry = *pte; - if (pte_none(entry) || !pte_present(entry)) + if (pte_none(entry) || !pte_present(entry)) { + printk(KERN_ERR "flush_cache_page: No valid PTE"); return; - phys = PHYSADDR(pte_val(entry)&PAGE_MASK); - __flush_cache_page(phys, (vma->vm_flags & VM_EXEC)); + } + + phys = pte_val(entry)&PTE_PHYS_MASK; + if (((address^phys) & CACHE_ALIAS) != 0) + __flush_invalidate_region((void *)P1SEGADDR(phys), PAGE_SIZE); + + phys |= CACHE_VALID; + save_and_cli(flags); + jump_to_P2(); + /* 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 +450,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 +457,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 +493,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/05 08:06:53 @@ -39,6 +39,9 @@ ENTRY(clear_page) mov.l r0,@-r4 mov.l r0,@-r4 mov.l r0,@-r4 +#if defined(__SH4__) + ocbwb @r4 +#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/05 08:06:53 @@ -53,6 +53,9 @@ ENTRY(copy_page) mov.l r3,@-r10 mov.l r2,@-r10 mov.l r1,@-r10 +#if defined(__SH4__) + ocbwb @r10 +#endif cmp/eq r11,r8 bf/s 1b add #28,r10 -- |