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 |
From: NIIBE Y. <gn...@m1...> - 2001-08-10 13:52:14
|
Looks good. One note: the comments about argument END are wrong (that's my falut). I'll fix cache-sh4.c as well. David Woodhouse wrote: > Next, of course, I'll need to make the PCI DMA code actually use these > functions as appropriate. OK, do you have account on SourceForge? If you have, I'll add you as developper so that you can commit the changes by yourself. Let me know. -- |
From: NIIBE Y. <gn...@m1...> - 2001-08-10 14:03:30
|
2001-08-10 NIIBE Yutaka <gn...@m1...> * arch/sh/mm/cache-sh4.c (__flush_wback_region, __flush_purge_region): Comment fix for the arguments. * arch/sh/mm/cache-sh3.c (__flush_wback_region, __flush_purge_region): Likewise. Index: arch/sh/mm/cache-sh3.c =================================================================== RCS file: /cvsroot/linuxsh/kernel/arch/sh/mm/cache-sh3.c,v retrieving revision 1.3 diff -u -r1.3 cache-sh3.c --- arch/sh/mm/cache-sh3.c 2001/08/10 13:58:55 1.3 +++ arch/sh/mm/cache-sh3.c 2001/08/10 14:01:05 @@ -148,7 +148,8 @@ * 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) + * START: Virtual Address (U0, P1, or P3) + * SIZE: Size of the region. */ void __flush_wback_region(void *start, int size) @@ -180,7 +181,8 @@ /* * Write back the dirty D-caches and invalidate them. * - * START, END: Virtual Address (U0, P1, or P3) + * START: Virtual Address (U0, P1, or P3) + * SIZE: Size of the region. */ void __flush_purge_region(void *start, int size) { Index: arch/sh/mm/cache-sh4.c =================================================================== RCS file: /cvsroot/linuxsh/kernel/arch/sh/mm/cache-sh4.c,v retrieving revision 1.14 diff -u -r1.14 cache-sh4.c --- arch/sh/mm/cache-sh4.c 2001/08/09 00:27:04 1.14 +++ arch/sh/mm/cache-sh4.c 2001/08/10 14:01:05 @@ -107,7 +107,8 @@ /* * Write back the dirty D-caches, but not invalidate them. * - * START, END: Virtual Address (U0, P1, or P3) + * START: Virtual Address (U0, P1, or P3) + * SIZE: Size of the region. */ void __flush_wback_region(void *start, int size) { @@ -127,7 +128,8 @@ /* * Write back the dirty D-caches and invalidate them. * - * START, END: Virtual Address (U0, P1, or P3) + * START: Virtual Address (U0, P1, or P3) + * SIZE: Size of the region. */ void __flush_purge_region(void *start, int size) { -- |
From: David W. <dw...@in...> - 2001-08-10 17:20:19
|
dw...@in... said: > Next, of course, I'll need to make the PCI DMA code actually use > these functions as appropriate. Done. The new config option CONFIG_SH_PCIDMA_NONCOHERENT is hard-coded off for now, because there's no code yet for the boards which actually need it. Unless anybody objects, I'll commit this soon. Index: ChangeLog =================================================================== RCS file: /cvsroot/linuxsh/kernel/ChangeLog,v retrieving revision 1.324 diff -u -r1.324 ChangeLog --- ChangeLog 2001/08/10 14:13:13 1.324 +++ ChangeLog 2001/08/10 17:02:40 @@ -1,3 +1,10 @@ +2001-08-10 David Woodhouse <dw...@in...> + + * arch/sh/config.in: New CONFIG_SH_PCIDMA_NONCOHERENT option + * include/asm-sh/pci.h: Include cache management calls for the + case where the above option is set. + * arch/sh/kernel/sh_ksyms.c: include linux/pci.h not asm/pci.h + 2001-08-10 NIIBE Yutaka <gn...@m1...> * arch/sh/mm/cache-sh4.c (__flush_wback_region, Index: arch/sh/config.in =================================================================== RCS file: /cvsroot/linuxsh/kernel/arch/sh/config.in,v retrieving revision 1.55 diff -u -r1.55 config.in --- arch/sh/config.in 2001/07/30 13:02:58 1.55 +++ arch/sh/config.in 2001/08/10 17:02:40 @@ -174,6 +174,7 @@ if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then define_bool CONFIG_PCI_DIRECT y fi + define_bool CONFIG_SH_PCIDMA_NONCOHERENT n fi source drivers/pci/Config.in Index: include/asm-sh/pci.h =================================================================== RCS file: /cvsroot/linuxsh/kernel/include/asm-sh/pci.h,v retrieving revision 1.12 diff -u -r1.12 pci.h --- include/asm-sh/pci.h 2001/07/27 06:09:47 1.12 +++ include/asm-sh/pci.h 2001/08/10 17:02:40 @@ -3,6 +3,8 @@ #ifdef __KERNEL__ +#include <linux/config.h> + /* Can be used to override the logic in pci_scan_bus for skipping already-configured bus numbers - to be used for buggy BIOSes or architectures with incomplete PCI setup by the loader */ @@ -76,9 +78,14 @@ * until either pci_unmap_single or pci_dma_sync_single is performed. */ static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, - size_t size,int directoin) + size_t size, int direction) { - flush_cache_all(); + if (direction == PCI_DMA_NONE) + BUG(); + +#ifdef CONFIG_SH_PCIDMA_NONCOHERENT + dma_cache_wback_inv(ptr, size); +#endif return virt_to_bus(ptr); } @@ -111,9 +118,17 @@ * the same here. */ static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents,int direction) + int nents, int direction) { - flush_cache_all(); +#ifdef CONFIG_SH_PCIDMA_NONCOHERENT + int i; + + for (i=0; i<nents; i++) + dma_cache_wback_inv(sg[i].address, sg[i].length); +#endif + if (direction == PCI_DMA_NONE) + BUG(); + return nents; } @@ -122,7 +137,7 @@ * pci_unmap_single() above. */ static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents,int direction) + int nents, int direction) { /* Nothing to do */ } @@ -138,9 +153,15 @@ */ static inline void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, - size_t size,int direction) + size_t size, int direction) { - /* Nothing to do */ + if (direction == PCI_DMA_NONE) + BUG(); + +#ifdef CONFIG_SH_PCIDMA_NONCOHERENT + dma_cache_wback_inv(bus_to_virt(dma_handle), size); +#endif + } /* Make physical memory consistent for a set of streaming @@ -151,9 +172,17 @@ */ static inline void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nelems,int direction) + int nelems, int direction) { - /* Nothing to do */ + if (direction == PCI_DMA_NONE) + BUG(); + +#ifdef CONFIG_SH_PCIDMA_NONCOHERENT + int i; + + for (i=0; i<nelems; i++) + dma_cache_wback_inv(sg[i].address, sg[i].length); +#endif } Index: arch/sh/kernel/sh_ksyms.c =================================================================== RCS file: /cvsroot/linuxsh/kernel/arch/sh/kernel/sh_ksyms.c,v retrieving revision 1.18 diff -u -r1.18 sh_ksyms.c --- arch/sh/kernel/sh_ksyms.c 2001/05/28 10:34:17 1.18 +++ arch/sh/kernel/sh_ksyms.c 2001/08/10 17:02:40 @@ -9,6 +9,7 @@ #include <linux/interrupt.h> #include <linux/smp_lock.h> #include <linux/vmalloc.h> +#include <linux/pci.h> #include <asm/semaphore.h> #include <asm/processor.h> @@ -18,7 +19,6 @@ #include <asm/hardirq.h> #include <asm/delay.h> #include <asm/pgalloc.h> -#include <asm/pci.h> #include <linux/irq.h> extern void dump_thread(struct pt_regs *, struct user *); -- dwmw2 |