To: linus, akpm Cc: lkml Subject: [PATCH] M68k cache updates M68k icache flush fixes from Roman Zippel: - Rename flush_icache_user_range() to flush_icache_user_page() - Add flush_icache_user_range() and flush_icache_user_page() - Add missing cache flush to copy_to_user_page() --- arch/m68k/kernel/m68k_ksyms.c | 1 arch/m68k/mm/memory.c | 64 +++++++++++++++++++++++++++++++++++------- include/asm-m68k/cacheflush.h | 32 ++++++++++++--------- 3 files changed, 74 insertions(+), 23 deletions(-) --- linux-2.6.0/arch/m68k/kernel/m68k_ksyms.c 2003-04-08 10:04:43.000000000 +0200 +++ linux-m68k-2.6.0/arch/m68k/kernel/m68k_ksyms.c 2003-10-26 11:59:39.000000000 +0100 @@ -47,6 +47,7 @@ EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(kernel_set_cachemode); #endif /* !CONFIG_SUN3 */ +EXPORT_SYMBOL(flush_icache_user_range); EXPORT_SYMBOL(m68k_debug_device); EXPORT_SYMBOL(mach_hwclk); EXPORT_SYMBOL(mach_get_ss); --- linux-2.6.0/arch/m68k/mm/memory.c 2003-07-29 18:18:35.000000000 +0200 +++ linux-m68k-2.6.0/arch/m68k/mm/memory.c 2003-10-26 11:59:41.000000000 +0100 @@ -354,13 +354,13 @@ #endif } -static unsigned long virt_to_phys_slow(unsigned long vaddr) +static unsigned long virt_to_phys_slow(unsigned long vaddr, mm_segment_t fs) { if (CPU_IS_060) { - mm_segment_t fs = get_fs(); + mm_segment_t old_fs = get_fs(); unsigned long paddr; - set_fs(get_ds()); + set_fs(fs); /* The PLPAR instruction causes an access error if the translation * is not possible. To catch this we use the same exception mechanism @@ -380,13 +380,13 @@ ".previous" : "=a" (paddr) : "0" (vaddr)); - set_fs(fs); + set_fs(old_fs); return paddr; } else if (CPU_IS_040) { - mm_segment_t fs = get_fs(); + mm_segment_t old_fs = get_fs(); unsigned long mmusr; - set_fs(get_ds()); + set_fs(fs); asm volatile (".chip 68040\n\t" "ptestr (%1)\n\t" @@ -394,7 +394,7 @@ ".chip 68k" : "=r" (mmusr) : "a" (vaddr)); - set_fs(fs); + set_fs(old_fs); if (mmusr & MMU_R_040) return (mmusr & PAGE_MASK) | (vaddr & ~PAGE_MASK); @@ -402,10 +402,10 @@ unsigned short mmusr; unsigned long *descaddr; - asm volatile ("ptestr #5,%2@,#7,%0\n\t" + asm volatile ("ptestr %3,%2@,#7,%0\n\t" "pmove %%psr,%1@" : "=a&" (descaddr) - : "a" (&mmusr), "a" (vaddr)); + : "a" (&mmusr), "a" (vaddr), "d" (fs.seg)); if (mmusr & (MMU_I|MMU_B|MMU_L)) return 0; descaddr = phys_to_virt((unsigned long)descaddr); @@ -443,7 +443,7 @@ ".chip 68040\n\t" "cpushp %%bc,(%0)\n\t" ".chip 68k" - : : "a" (virt_to_phys_slow(address))); + : : "a" (virt_to_phys_slow(address, KERNEL_DS))); address += PAGE_SIZE; } while (address < endaddr); } @@ -457,6 +457,50 @@ } } +void flush_icache_user_range(void *addr, unsigned long size) +{ + unsigned long address = (unsigned long)addr; + unsigned long endaddr = address + size; + + if (CPU_IS_040_OR_060) { + address &= PAGE_MASK; + + do { + asm volatile ("nop\n\t" + ".chip 68040\n\t" + "cpushp %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (virt_to_phys_slow(address, get_fs()))); + address += PAGE_SIZE; + } while (address < endaddr); + } else { + unsigned long tmp; + asm volatile ("movec %%cacr,%0\n\t" + "orw %1,%0\n\t" + "movec %0,%%cacr" + : "=&d" (tmp) + : "di" (FLUSH_I)); + } +} + +extern void flush_icache_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long addr, int len) +{ + if (CPU_IS_040_OR_060) { + asm volatile ("nop\n\t" + ".chip 68040\n\t" + "cpushp %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (page_to_phys(page))); + } else { + unsigned long tmp; + asm volatile ("movec %%cacr,%0\n\t" + "orw %1,%0\n\t" + "movec %0,%%cacr" + : "=&d" (tmp) + : "di" (FLUSH_I)); + } +} #ifndef CONFIG_SINGLE_MEMORY_CHUNK int mm_end_of_chunk (unsigned long addr, int len) --- linux-2.6.10-rc1/include/asm-m68k/cacheflush.h 2004-09-30 12:54:07.000000000 +0200 +++ linux-m68k-2.6.10-rc1/include/asm-m68k/cacheflush.h 2004-10-21 21:33:15.000000000 +0200 @@ -130,20 +130,26 @@ static inline void __flush_page_to_ram(v #define flush_dcache_mmap_lock(mapping) do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) #define flush_icache_page(vma, page) __flush_page_to_ram(page_address(page)) -#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) - -#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ - do { \ - flush_cache_page(vma, vaddr, page_to_pfn(page));\ - memcpy(dst, src, len); \ - } while (0) - -#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ - do { \ - flush_cache_page(vma, vaddr, page_to_pfn(page));\ - memcpy(dst, src, len); \ - } while (0) +extern void flush_icache_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long addr, int len); extern void flush_icache_range(unsigned long address, unsigned long endaddr); +extern void flush_icache_user_range(void *address, unsigned long size); + +static inline void copy_to_user_page(struct vm_area_struct *vma, + struct page *page, unsigned long vaddr, + void *dst, void *src, int len) +{ + flush_cache_page(vma, vaddr, page_to_pfn(page)); + memcpy(dst, src, len); + flush_icache_user_page(vma, page, vaddr, len); +} +static inline void copy_from_user_page(struct vm_area_struct *vma, + struct page *page, unsigned long vaddr, + void *dst, void *src, int len) +{ + flush_cache_page(vma, vaddr, page_to_pfn(page)); + memcpy(dst, src, len); +} #endif /* _M68K_CACHEFLUSH_H */