This patch is based on Thiemo's work where he tried to minimize the dcache flushes and clean up the API a bit. The patch was posted in Debian #466977. The patch in detail: - instead of an active flush the relevant pages just get a dirty dcache bit set - the dirty bit is only set if we have userspace mapping. So we don't set it for kernel internal requests which never see userland. - since writes to the device are "read only" there is no need set the dirty bit. Signed-off-by: Thiemo Seufer <ths@xxxxxxxxxxxx> Signed-off-by: Sebastian Andrzej Siewior <sebastian@xxxxxxxxxxxxx> --- arch/mips/include/asm/cacheflush.h | 1 - arch/mips/include/asm/mach-generic/ide.h | 70 +++++++----------------------- arch/mips/mm/c-r3k.c | 5 -- arch/mips/mm/c-r4k.c | 1 - arch/mips/mm/c-tx39.c | 7 --- arch/mips/mm/cache.c | 2 - 6 files changed, 16 insertions(+), 70 deletions(-) diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h index 40bb9fd..d95a79c 100644 --- a/arch/mips/include/asm/cacheflush.h +++ b/arch/mips/include/asm/cacheflush.h @@ -92,7 +92,6 @@ extern void copy_from_user_page(struct vm_area_struct *vma, extern void (*flush_cache_sigtramp)(unsigned long addr); extern void (*flush_icache_all)(void); -extern void (*local_flush_data_cache_page)(void * addr); extern void (*flush_data_cache_page)(unsigned long addr); /* diff --git a/arch/mips/include/asm/mach-generic/ide.h b/arch/mips/include/asm/mach-generic/ide.h index e80e47f..9360586 100644 --- a/arch/mips/include/asm/mach-generic/ide.h +++ b/arch/mips/include/asm/mach-generic/ide.h @@ -20,107 +20,69 @@ #include <asm/processor.h> /* MIPS port and memory-mapped I/O string operations. */ -static inline void __ide_flush_prologue(void) +static inline void __ide_set_pages_dirty(const void *addr, unsigned long size) { -#ifdef CONFIG_SMP - if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) - preempt_disable(); -#endif -} + unsigned long end = (unsigned long)addr + size; -static inline void __ide_flush_epilogue(void) -{ -#ifdef CONFIG_SMP - if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) - preempt_enable(); -#endif -} + if (!(cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc)) + return; -static inline void __ide_flush_dcache_range(unsigned long addr, unsigned long size) -{ - if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) { - unsigned long end = addr + size; + while ((unsigned long)addr < end) { + struct page *p = virt_to_page(addr); + struct address_space *mapping = page_mapping(p); - while (addr < end) { - local_flush_data_cache_page((void *)addr); - addr += PAGE_SIZE; - } + if (mapping && mapping_mapped(mapping)) + SetPageDcacheDirty(p); + addr += PAGE_SIZE; } } -/* - * insw() and gang might be called with interrupts disabled, so we can't - * send IPIs for flushing due to the potencial of deadlocks, see the comment - * above smp_call_function() in arch/mips/kernel/smp.c. We work around the - * problem by disabling preemption so we know we actually perform the flush - * on the processor that actually has the lines to be flushed which hopefully - * is even better for performance anyway. - */ static inline void __ide_insw(unsigned long port, void *addr, unsigned int count) { - __ide_flush_prologue(); insw(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 2); - __ide_flush_epilogue(); + __ide_set_pages_dirty(addr, count * 2); } -static inline void __ide_insl(unsigned long port, void *addr, unsigned int count) +static inline void __ide_insl(unsigned long port, void *addr, + unsigned int count) { - __ide_flush_prologue(); insl(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 4); - __ide_flush_epilogue(); + __ide_set_pages_dirty(addr, count * 4); } static inline void __ide_outsw(unsigned long port, const void *addr, unsigned long count) { - __ide_flush_prologue(); outsw(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 2); - __ide_flush_epilogue(); } static inline void __ide_outsl(unsigned long port, const void *addr, unsigned long count) { - __ide_flush_prologue(); outsl(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 4); - __ide_flush_epilogue(); } static inline void __ide_mm_insw(void __iomem *port, void *addr, u32 count) { - __ide_flush_prologue(); readsw(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 2); - __ide_flush_epilogue(); + __ide_set_pages_dirty(addr, count * 2); } static inline void __ide_mm_insl(void __iomem *port, void *addr, u32 count) { - __ide_flush_prologue(); readsl(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 4); - __ide_flush_epilogue(); + __ide_set_pages_dirty(addr, count * 4); } static inline void __ide_mm_outsw(void __iomem *port, void *addr, u32 count) { - __ide_flush_prologue(); writesw(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 2); - __ide_flush_epilogue(); } static inline void __ide_mm_outsl(void __iomem * port, void *addr, u32 count) { - __ide_flush_prologue(); writesl(port, addr, count); - __ide_flush_dcache_range((unsigned long)addr, count * 4); - __ide_flush_epilogue(); } /* ide_insw calls insw, not __ide_insw. Why? */ diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c index 54e5f7b..d841170 100644 --- a/arch/mips/mm/c-r3k.c +++ b/arch/mips/mm/c-r3k.c @@ -267,10 +267,6 @@ static void r3k_flush_cache_page(struct vm_area_struct *vma, r3k_flush_icache_range(kaddr, kaddr + PAGE_SIZE); } -static void local_r3k_flush_data_cache_page(void *addr) -{ -} - static void r3k_flush_data_cache_page(unsigned long addr) { } @@ -324,7 +320,6 @@ void __cpuinit r3k_cache_init(void) local_flush_icache_range = r3k_flush_icache_range; flush_cache_sigtramp = r3k_flush_cache_sigtramp; - local_flush_data_cache_page = local_r3k_flush_data_cache_page; flush_data_cache_page = r3k_flush_data_cache_page; _dma_cache_wback_inv = r3k_dma_cache_wback_inv; diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 6721ee2..a103185 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1403,7 +1403,6 @@ void __cpuinit r4k_cache_init(void) flush_cache_sigtramp = r4k_flush_cache_sigtramp; flush_icache_all = r4k_flush_icache_all; - local_flush_data_cache_page = local_r4k_flush_data_cache_page; flush_data_cache_page = r4k_flush_data_cache_page; flush_icache_range = r4k_flush_icache_range; local_flush_icache_range = local_r4k_flush_icache_range; diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c index 6515b44..f98bfad 100644 --- a/arch/mips/mm/c-tx39.c +++ b/arch/mips/mm/c-tx39.c @@ -221,11 +221,6 @@ static void tx39_flush_cache_page(struct vm_area_struct *vma, unsigned long page tx39_blast_icache_page_indexed(page); } -static void local_tx39_flush_data_cache_page(void * addr) -{ - tx39_blast_dcache_page((unsigned long)addr); -} - static void tx39_flush_data_cache_page(unsigned long addr) { tx39_blast_dcache_page(addr); @@ -366,7 +361,6 @@ void __cpuinit tx39_cache_init(void) local_flush_icache_range = (void *) tx39h_flush_icache_all; flush_cache_sigtramp = (void *) tx39h_flush_icache_all; - local_flush_data_cache_page = (void *) tx39h_flush_icache_all; flush_data_cache_page = (void *) tx39h_flush_icache_all; _dma_cache_wback_inv = tx39h_dma_cache_wback_inv; @@ -395,7 +389,6 @@ void __cpuinit tx39_cache_init(void) local_flush_icache_range = tx39_flush_icache_range; flush_cache_sigtramp = tx39_flush_cache_sigtramp; - local_flush_data_cache_page = local_tx39_flush_data_cache_page; flush_data_cache_page = tx39_flush_data_cache_page; _dma_cache_wback_inv = tx39_dma_cache_wback_inv; diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index e716caf..cb5bf1a 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -37,11 +37,9 @@ void (*__flush_cache_vunmap)(void); /* MIPS specific cache operations */ void (*flush_cache_sigtramp)(unsigned long addr); -void (*local_flush_data_cache_page)(void * addr); void (*flush_data_cache_page)(unsigned long addr); void (*flush_icache_all)(void); -EXPORT_SYMBOL_GPL(local_flush_data_cache_page); EXPORT_SYMBOL(flush_data_cache_page); #ifdef CONFIG_DMA_NONCOHERENT -- 1.6.6