This is a re-hash of patches I sent out a while ago which do a more optimal cache-flushing for pci_map_*() and pci_dma_sync_*(). It basically does an invalidate for PCI_DMA_FROMDEVICE operations and a writeback for PCI_DMA_TODEVICE pci_map_* (or writeback/invalidate if PCI_DMA_BIDIRECTIONAL). This is similar to the ARM implementation. Additionally, I filled in the _dma_cache_wback calls in the arch/mips/c-*.c to call *_dma_cache_wback_inv* instead of calling panic(). Some architectures could probably do a real writeback instead of just wback_inv, but this will at least allow code that can use writeback-only if available. Note: I'm not familiar with a lot of these CPUs, but the change should be innocuous. Could someone validate/improve these? Thanks, William Index: include/asm/pci.h =================================================================== RCS file: /cvs/linux/include/asm-mips/pci.h,v retrieving revision 1.24.2.1 diff -u -r1.24.2.1 pci.h --- include/asm/pci.h 2002/02/26 06:00:25 1.24.2.1 +++ include/asm/pci.h 2002/06/18 16:51:30 @@ -79,7 +79,40 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle); +#ifdef CONFIG_NONCOHERENT_IO +/* + * Prepare buffer for DMA transfer + */ +static inline void prep_buffer(void *ptr, size_t size, int direction) +{ + switch(direction) { + case PCI_DMA_TODEVICE: + dma_cache_wback((unsigned long)ptr, size); + break; + case PCI_DMA_FROMDEVICE: + dma_cache_inv((unsigned long)ptr, size); + break; + case PCI_DMA_BIDIRECTIONAL: + dma_cache_wback_inv((unsigned long)ptr, size); + break; + } +} + /* + * Prepare buffer for CPU access after DMA transfer + */ +static inline void sync_buffer(void *ptr, size_t size, int direction) +{ + switch(direction) { + case PCI_DMA_FROMDEVICE: + case PCI_DMA_BIDIRECTIONAL: + dma_cache_inv((unsigned long)ptr, size); + break; + } +} +#endif + +/* * Map a single buffer of the indicated size for DMA in streaming mode. * The 32-bit bus address to use is returned. * @@ -93,7 +126,7 @@ BUG(); #ifdef CONFIG_NONCOHERENT_IO - dma_cache_wback_inv((unsigned long)ptr, size); + prep_buffer(ptr, size, direction); #endif return virt_to_bus(ptr); @@ -132,7 +165,7 @@ addr = (unsigned long) page_address(page); addr += offset; #ifdef CONFIG_NONCOHERENT_IO - dma_cache_wback_inv(addr, size); + prep_buffer((void*)addr, size, direction); #endif return virt_to_bus((void *)addr); @@ -183,7 +216,7 @@ #ifdef CONFIG_NONCOHERENT_IO /* Make sure that gcc doesn't leave the empty loop body. */ for (i = 0; i < nents; i++, sg++) - dma_cache_wback_inv((unsigned long)sg->address, sg->length); + prep_buffer(sg->address, sg->length, direction); #endif return nents; @@ -221,7 +254,7 @@ BUG(); #ifdef CONFIG_NONCOHERENT_IO - dma_cache_wback_inv((unsigned long)bus_to_virt(dma_handle), size); + sync_buffer(bus_to_virt(dma_handle), size, direction); #endif } @@ -246,8 +279,9 @@ /* Make sure that gcc doesn't leave the empty loop body. */ #ifdef CONFIG_NONCOHERENT_IO for (i = 0; i < nelems; i++, sg++) - dma_cache_wback_inv((unsigned long)sg->address, sg->length); + sync_buffer(sg->address, sg->length, direction); #endif + } /* Return whether the given PCI device DMA address mask can Index: arch/mips/mm/c-mips32.c =================================================================== RCS file: /cvs/linux/arch/mips/mm/c-mips32.c,v retrieving revision 1.3.2.4 diff -u -r1.3.2.4 c-mips32.c --- arch/mips/mm/c-mips32.c 2002/05/29 03:03:17 1.3.2.4 +++ arch/mips/mm/c-mips32.c 2002/06/18 16:52:21 @@ -393,12 +393,6 @@ } } -static void -mips32_dma_cache_wback(unsigned long addr, unsigned long size) -{ - panic("mips32_dma_cache called - should not happen."); -} - /* * While we're protected against bad userland addresses we don't care * very much about what happens in that case. Usually a segmentation @@ -603,7 +597,7 @@ _flush_icache_page = mips32_flush_icache_page; _dma_cache_wback_inv = mips32_dma_cache_wback_inv_pc; - _dma_cache_wback = mips32_dma_cache_wback; + _dma_cache_wback = mips32_dma_cache_wback_inv_pc; _dma_cache_inv = mips32_dma_cache_inv_pc; } @@ -621,7 +615,7 @@ _flush_icache_page = mips32_flush_icache_page_s; _dma_cache_wback_inv = mips32_dma_cache_wback_inv_sc; - _dma_cache_wback = mips32_dma_cache_wback; + _dma_cache_wback = mips32_dma_cache_wback_inv_sc; _dma_cache_inv = mips32_dma_cache_inv_sc; } Index: arch/mips/mm/c-r3k.c =================================================================== RCS file: /cvs/linux/arch/mips/mm/c-r3k.c,v retrieving revision 1.4.2.1 diff -u -r1.4.2.1 c-r3k.c --- arch/mips/mm/c-r3k.c 2002/02/18 15:22:30 1.4.2.1 +++ arch/mips/mm/c-r3k.c 2002/06/18 16:52:21 @@ -337,7 +337,9 @@ _flush_icache_page = r3k_flush_icache_page; _flush_icache_range = r3k_flush_icache_range; + _dma_cache_inv = r3k_dma_cache_wback_inv; _dma_cache_wback_inv = r3k_dma_cache_wback_inv; + _dma_cache_wback = r3k_dma_cache_wback_inv; printk("Primary instruction cache %dkb, linesize %d bytes\n", (int) (icache_size >> 10), (int) icache_lsize); Index: arch/mips/mm/c-r4k.c =================================================================== RCS file: /cvs/linux/arch/mips/mm/c-r4k.c,v retrieving revision 1.3.2.3 diff -u -r1.3.2.3 c-r4k.c --- arch/mips/mm/c-r4k.c 2002/05/29 03:03:17 1.3.2.3 +++ arch/mips/mm/c-r4k.c 2002/06/18 16:52:21 @@ -1150,12 +1150,6 @@ } } -static void -r4k_dma_cache_wback(unsigned long addr, unsigned long size) -{ - panic("r4k_dma_cache called - should not happen."); -} - /* * While we're protected against bad userland addresses we don't care * very much about what happens in that case. Usually a segmentation @@ -1358,7 +1352,7 @@ _flush_icache_page = r4k_flush_icache_page_p; _dma_cache_wback_inv = r4k_dma_cache_wback_inv_pc; - _dma_cache_wback = r4k_dma_cache_wback; + _dma_cache_wback = r4k_dma_cache_wback_inv_pc; _dma_cache_inv = r4k_dma_cache_inv_pc; } @@ -1441,7 +1435,7 @@ ___flush_cache_all = _flush_cache_all; _flush_icache_page = r4k_flush_icache_page_s; _dma_cache_wback_inv = r4k_dma_cache_wback_inv_sc; - _dma_cache_wback = r4k_dma_cache_wback; + _dma_cache_wback = r4k_dma_cache_wback_inv_sc; _dma_cache_inv = r4k_dma_cache_inv_sc; } Index: arch/mips/mm/c-r5432.c =================================================================== RCS file: /cvs/linux/arch/mips/mm/c-r5432.c,v retrieving revision 1.4 diff -u -r1.4 c-r5432.c --- arch/mips/mm/c-r5432.c 2001/11/30 13:28:06 1.4 +++ arch/mips/mm/c-r5432.c 2002/06/18 16:52:21 @@ -414,12 +414,6 @@ bc_inv(addr, size); } -static void -r5432_dma_cache_wback(unsigned long addr, unsigned long size) -{ - panic("r5432_dma_cache called - should not happen."); -} - /* * While we're protected against bad userland addresses we don't care * very much about what happens in that case. Usually a segmentation @@ -470,7 +464,7 @@ _flush_cache_page = r5432_flush_cache_page_d32i32; _flush_icache_page = r5432_flush_icache_page_i32; _dma_cache_wback_inv = r5432_dma_cache_wback_inv_pc; - _dma_cache_wback = r5432_dma_cache_wback; + _dma_cache_wback = r5432_dma_cache_wback_inv_pc; _dma_cache_inv = r5432_dma_cache_inv_pc; _flush_cache_sigtramp = r5432_flush_cache_sigtramp; Index: arch/mips/mm/c-rm7k.c =================================================================== RCS file: /cvs/linux/arch/mips/mm/c-rm7k.c,v retrieving revision 1.4.2.2 diff -u -r1.4.2.2 c-rm7k.c --- arch/mips/mm/c-rm7k.c 2002/05/29 03:03:17 1.4.2.2 +++ arch/mips/mm/c-rm7k.c 2002/06/18 16:52:21 @@ -177,12 +177,6 @@ } } -static void -rm7k_dma_cache_wback(unsigned long addr, unsigned long size) -{ - panic("rm7k_dma_cache_wback called - should not happen."); -} - /* * While we're protected against bad userland addresses we don't care * very much about what happens in that case. Usually a segmentation @@ -342,7 +336,7 @@ _flush_icache_page = rm7k_flush_icache_page; _dma_cache_wback_inv = rm7k_dma_cache_wback_inv; - _dma_cache_wback = rm7k_dma_cache_wback; + _dma_cache_wback = rm7k_dma_cache_wback_inv; _dma_cache_inv = rm7k_dma_cache_inv; __flush_cache_all_d32i32(); Index: arch/mips/mm/c-tx39.c =================================================================== RCS file: /cvs/linux/arch/mips/mm/c-tx39.c,v retrieving revision 1.4 diff -u -r1.4 c-tx39.c --- arch/mips/mm/c-tx39.c 2001/11/30 13:28:06 1.4 +++ arch/mips/mm/c-tx39.c 2002/06/18 16:52:21 @@ -225,11 +225,6 @@ } } -static void tx39_dma_cache_wback(unsigned long addr, unsigned long size) -{ - panic("tx39_dma_cache called - should not happen."); -} - static void tx39_flush_cache_sigtramp(unsigned long addr) { unsigned long config; @@ -317,7 +312,7 @@ _flush_icache_range = tx39_flush_icache_range; _dma_cache_wback_inv = tx39_dma_cache_wback_inv; - _dma_cache_wback = tx39_dma_cache_wback; + _dma_cache_wback = tx39_dma_cache_wback_inv; _dma_cache_inv = tx39_dma_cache_inv; break; Index: arch/mips/mm/c-tx49.c =================================================================== RCS file: /cvs/linux/arch/mips/mm/c-tx49.c,v retrieving revision 1.3.2.1 diff -u -r1.3.2.1 c-tx49.c --- arch/mips/mm/c-tx49.c 2002/05/29 03:03:17 1.3.2.1 +++ arch/mips/mm/c-tx49.c 2002/06/18 16:52:21 @@ -343,12 +343,6 @@ } } -static void -r4k_dma_cache_wback(unsigned long addr, unsigned long size) -{ - panic("r4k_dma_cache called - should not happen."); -} - /* * While we're protected against bad userland addresses we don't care * very much about what happens in that case. Usually a segmentation @@ -429,7 +423,7 @@ _flush_icache_page = r4k_flush_icache_page; _dma_cache_wback_inv = r4k_dma_cache_wback_inv; - _dma_cache_wback = r4k_dma_cache_wback; + _dma_cache_wback = r4k_dma_cache_wback_inv; _dma_cache_inv = r4k_dma_cache_inv; _flush_cache_sigtramp = r4k_flush_cache_sigtramp;