[PATCH] M68k cache

From: Geert Uytterhoeven
Date: Fri Aug 29 2003 - 10:08:02 EST


M68k icache flush fixes from Roman Zippel:
- uninline flush_icache_range() and rename it to flush_icache_user_range()
- add virt_to_phys_slow() which handles vmalloc()ed space
- add flush_icache_range and flush_icache_user_page

--- linux-2.4.23-pre1/arch/m68k/kernel/m68k_ksyms.c Thu Jul 10 16:22:26 2003
+++ linux-m68k-2.4.23-pre1/arch/m68k/kernel/m68k_ksyms.c Fri Jul 25 20:02:38 2003
@@ -48,6 +48,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.4.23-pre1/arch/m68k/mm/Makefile Sun Apr 6 10:28:29 2003
+++ linux-m68k-2.4.23-pre1/arch/m68k/mm/Makefile Fri Jul 25 20:02:43 2003
@@ -9,7 +9,7 @@

O_TARGET := mm.o

-obj-y := init.o fault.o extable.o hwtest.o
+obj-y := cache.o init.o fault.o extable.o hwtest.o

ifndef CONFIG_SUN3
obj-y += kmap.o memory.o motorola.o
--- linux-2.4.23-pre1/arch/m68k/mm/cache.c Thu Jan 1 01:00:00 1970
+++ linux-m68k-2.4.23-pre1/arch/m68k/mm/cache.c Fri Jul 25 20:02:43 2003
@@ -0,0 +1,167 @@
+/*
+ * linux/arch/m68k/mm/cache.c
+ *
+ * Instruction cache handling
+ *
+ * Copyright (C) 1995 Hamish Macdonald
+ */
+
+#include <linux/config.h>
+#include <linux/pagemap.h>
+
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/segment.h>
+#include <asm/setup.h>
+#include <asm/traps.h>
+#include <asm/virtconvert.h>
+
+
+static unsigned long virt_to_phys_slow(unsigned long vaddr, mm_segment_t fs)
+{
+ if (CPU_IS_060) {
+ mm_segment_t old_fs = get_fs();
+ unsigned long paddr;
+
+ 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
+ * as for user space accesses in <asm/uaccess.h>. */
+ asm volatile (".chip 68060\n"
+ "1: plpar (%0)\n"
+ ".chip 68k\n"
+ "2:\n"
+ ".section .fixup,\"ax\"\n"
+ " .even\n"
+ "3: sub.l %0,%0\n"
+ " jra 2b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 1b,3b\n"
+ ".previous"
+ : "=a" (paddr)
+ : "0" (vaddr));
+ set_fs(old_fs);
+ return paddr;
+ } else if (CPU_IS_040) {
+ mm_segment_t old_fs = get_fs();
+ unsigned long mmusr;
+
+ set_fs(fs);
+
+ asm volatile (".chip 68040\n\t"
+ "ptestr (%1)\n\t"
+ "movec %%mmusr, %0\n\t"
+ ".chip 68k"
+ : "=r" (mmusr)
+ : "a" (vaddr));
+ set_fs(old_fs);
+
+ if (mmusr & MMU_R_040)
+ return (mmusr & PAGE_MASK) | (vaddr & ~PAGE_MASK);
+ } else {
+ unsigned short mmusr;
+ unsigned long *descaddr;
+
+ asm volatile ("ptestr %3,%2@,#7,%0\n\t"
+ "pmove %%psr,%1@"
+ : "=a&" (descaddr)
+ : "a" (&mmusr), "a" (vaddr), "d" (fs.seg));
+ if (mmusr & (MMU_I|MMU_B|MMU_L))
+ return 0;
+ descaddr = phys_to_virt((unsigned long)descaddr);
+ switch (mmusr & MMU_NUM) {
+ case 1:
+ return (*descaddr & 0xfe000000) | (vaddr & 0x01ffffff);
+ case 2:
+ return (*descaddr & 0xfffc0000) | (vaddr & 0x0003ffff);
+ case 3:
+ return (*descaddr & PAGE_MASK) | (vaddr & ~PAGE_MASK);
+ }
+ }
+ return 0;
+}
+
+/* Push n pages at kernel virtual address and clear the icache */
+/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
+void flush_icache_range(unsigned long address, unsigned long endaddr)
+{
+ if (CPU_IS_040_OR_060) {
+ address &= PAGE_MASK;
+
+ if (address >= PAGE_OFFSET && address < (unsigned long)high_memory) {
+ do {
+ asm volatile ("nop\n\t"
+ ".chip 68040\n\t"
+ "cpushp %%bc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (virt_to_phys((void *)address)));
+ address += PAGE_SIZE;
+ } while (address < endaddr);
+ } else {
+ do {
+ asm volatile ("nop\n\t"
+ ".chip 68040\n\t"
+ "cpushp %%bc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (virt_to_phys_slow(address, KERNEL_DS)));
+ 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));
+ }
+}
+
+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));
+ }
+}
+
+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));
+ }
+}
+
--- linux-2.4.23-pre1/include/asm-m68k/pgalloc.h Tue Mar 12 09:51:43 2002
+++ linux-m68k-2.4.23-pre1/include/asm-m68k/pgalloc.h Fri Jul 25 20:02:38 2003
@@ -127,35 +127,12 @@

#define flush_dcache_page(page) do { } while (0)
#define flush_icache_page(vma,pg) do { } while (0)
-#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
-
-/* Push n pages at kernel virtual address and clear the icache */
-/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
-extern inline void flush_icache_range (unsigned long address,
- unsigned long endaddr)
-{
- if (CPU_IS_040_OR_060) {
- short n = (endaddr - address + PAGE_SIZE - 1) / PAGE_SIZE;
-
- while (--n >= 0) {
- __asm__ __volatile__("nop\n\t"
- ".chip 68040\n\t"
- "cpushp %%bc,(%0)\n\t"
- ".chip 68k"
- : : "a" (virt_to_phys((void *)address)));
- address += PAGE_SIZE;
- }
- } 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);

+extern void flush_icache_range(unsigned long address, unsigned long endaddr);
+extern void flush_icache_user_range(void *address, unsigned long size);


#ifdef CONFIG_SUN3
--- linux-2.4.23-pre1/kernel/ptrace.c Wed May 28 13:11:52 2003
+++ linux-m68k-2.4.23-pre1/kernel/ptrace.c Fri Jul 25 20:02:39 2003
@@ -165,7 +165,7 @@
if (write) {
memcpy(maddr + offset, buf, bytes);
flush_page_to_ram(page);
- flush_icache_user_range(vma, page, addr, len);
+ flush_icache_user_page(vma, page, addr, len);
set_page_dirty(page);
} else {
memcpy(buf, maddr + offset, bytes);

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/