From: David W. <dw...@in...> - 2001-08-10 12:37:36
|
This patch adds cache flush/invalidate/purge routines to cache-sh3.c. It's required for PCI support on SH3 boards because the SH3 processors don't have on-chip PCI host bridges, hence don't have cache-coherent PCI DMA and need to deal with it all manually. Next, of course, I'll need to make the PCI DMA code actually use these functions as appropriate. I took out all the CACHE_IC_ definitions too, while I was at it. Now that cache-sh3.c and cache-sh4.c are separate there's really no need for them to be there. Index: ChangeLog =================================================================== RCS file: /cvsroot/linuxsh/kernel/ChangeLog,v retrieving revision 1.321 diff -u -r1.321 ChangeLog --- ChangeLog 2001/08/10 01:26:17 1.321 +++ ChangeLog 2001/08/10 12:18:36 @@ -1,3 +1,11 @@ +2001-08-10 David Woodhouse <dw...@in...> + + * arch/sh/mm/cache-sh3.c: Implementation of cache management + routines __flush_{wback,invalidate,purge}_region. Required for + SH3 platforms which have DMA hardware. + * include/asm-sh/pgtable.h: Take the 'extern' definitions of the + above out of #ifdef __SH4__ + 2001-08-10 David Woodhouse <dw...@in...> * drivers/mtd/maps/solutionengine.c: Map driver for flash chips Index: arch/sh/mm/cache-sh3.c =================================================================== RCS file: /cvsroot/linuxsh/kernel/arch/sh/mm/cache-sh3.c,v retrieving revision 1.2 diff -u -r1.2 cache-sh3.c --- arch/sh/mm/cache-sh3.c 2001/08/06 02:19:56 1.2 +++ arch/sh/mm/cache-sh3.c 2001/08/10 12:18:36 @@ -25,10 +25,10 @@ #define CCR_CACHE_INIT 0x0000000d /* 8k-byte cache, CF, P1-wb, enable */ #define CCR_CACHE_ENABLE 1 -#define CACHE_IC_ADDRESS_ARRAY 0xf0000000 /* SH-3 has unified cache system */ #define CACHE_OC_ADDRESS_ARRAY 0xf0000000 #define CACHE_VALID 1 #define CACHE_UPDATED 2 +#define CACHE_PHYSADDR_MASK 0x1ffffc00 /* 7709A/7729 has 16K cache (256-entry), while 7702 has only 2K(direct) 7702 is not supported (yet) */ @@ -44,13 +44,11 @@ static struct _cache_system_info cache_system_info = {0,}; #define CACHE_OC_WAY_SHIFT (cache_system_info.way_shift) -#define CACHE_IC_WAY_SHIFT (cache_system_info.way_shift) #define CACHE_OC_ENTRY_SHIFT 4 #define CACHE_OC_ENTRY_MASK (cache_system_info.entry_mask) -#define CACHE_IC_ENTRY_MASK (cache_system_info.entry_mask) #define CACHE_OC_NUM_ENTRIES (cache_system_info.num_entries) #define CACHE_OC_NUM_WAYS 4 -#define CACHE_IC_NUM_WAYS 4 +#define CACHE_OC_ASSOC_BIT (1<<3) /* @@ -143,3 +141,71 @@ ctrl_outl(CCR_CACHE_INIT, CCR); back_to_P1(); } + +/* + * Write back the dirty D-caches, but not invalidate them. + * + * Is this really worth it, or should we just alias this routine + * to __flush_purge_region too? + * + * START, END: Virtual Address (U0, P1, or P3) + */ + +void __flush_wback_region(void *start, int size) +{ + unsigned long v, j; + unsigned long begin, end; + + 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) { + unsigned long data, addr, p; + + p = __pa(v); + addr = CACHE_OC_ADDRESS_ARRAY|(j<<CACHE_OC_WAY_SHIFT)| + (v&CACHE_OC_ENTRY_MASK); + data = ctrl_inl(addr); + + if ((data & CACHE_PHYSADDR_MASK) == + (p & CACHE_PHYSADDR_MASK)) { + data &= ~CACHE_UPDATED; + ctrl_outl(data, addr); + break; + } + } +} + +/* + * Write back the dirty D-caches and invalidate them. + * + * START, END: Virtual Address (U0, P1, or P3) + */ +void __flush_purge_region(void *start, int size) +{ + unsigned long v; + unsigned long begin, end; + + 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) { + unsigned long data, addr; + + data = (v & 0xfffffc00); /* _Virtual_ address, ~U, ~V */ + addr = CACHE_OC_ADDRESS_ARRAY | (v&CACHE_OC_ENTRY_MASK) | + CACHE_OC_ASSOC_BIT; + ctrl_outl(data, addr); + } +} + +/* + * No write back please + * + * Except I don't think there's any way to avoid the writeback. So we + * just alias it to __flush_purge_region(). dwmw2. + */ +void __flush_invalidate_region(void *start, int size) + __attribute__((alias("__flush_purge_region"))); Index: include/asm-sh/pgtable.h =================================================================== RCS file: /cvsroot/linuxsh/kernel/include/asm-sh/pgtable.h,v retrieving revision 1.43 diff -u -r1.43 pgtable.h --- include/asm-sh/pgtable.h 2001/08/08 23:28:47 1.43 +++ include/asm-sh/pgtable.h 2001/08/10 12:18:36 @@ -44,9 +44,6 @@ #define flush_cache_sigtramp(vaddr) do { } while (0) #define p3_cache_init() do { } while (0) -#define __flush_dcache_region(start, end) do { } while (0) -#define __flush_wback_region(start, end) do { } while (0) -#define __flush_purge_region(start, end) do { } while (0) #elif defined(__SH4__) /* @@ -68,11 +65,6 @@ #define flush_page_to_ram(page) do { } while (0) #define flush_icache_page(vma,pg) do { } while (0) -/* Flush (write-back only) a region (smaller than a page) */ -extern void __flush_wback_region(void *start, int size); -/* Flush (write-back & invalidate) a region (smaller than a page) */ -extern void __flush_purge_region(void *start, int size); - /* Initialization of P3 area for copy_user_page */ extern void p3_cache_init(void); @@ -81,6 +73,14 @@ /* We provide our own get_unmapped_area to avoid cache alias issue */ #define HAVE_ARCH_UNMAPPED_AREA #endif + +/* Flush (write-back only) a region (smaller than a page) */ +extern void __flush_wback_region(void *start, int size); +/* Flush (write-back & invalidate) a region (smaller than a page) */ +extern void __flush_purge_region(void *start, int size); +/* Flush (invalidate only) a region (smaller than a page) */ +extern void __flush_invalidate_region(void *start, int size); + /* * Basically we have the same two-level (which is the logical three level -- dwmw2 |