Skip to content

Commit

Permalink
MIPS: cache: Provide cache flush operations for XFS
Browse files Browse the repository at this point in the history
Until now flush_kernel_vmap_range() and invalidate_kernel_vmap_range() did
not exist on MIPS resulting in heavy cache corruption on XFS filesystems.

Left for the post-3.0 time: optimization and make this work with highmem,
too.  Since the combination of highmem + cache aliases atm doesn't work
this isn't a regression.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Patchwork: https://patchwork.linux-mips.org/patch/2505/
  • Loading branch information
ralfbaechle committed Oct 20, 2011
1 parent 2e5db86 commit d9cdc90
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 0 deletions.
24 changes: 24 additions & 0 deletions arch/mips/include/asm/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,28 @@ unsigned long run_uncached(void *func);
extern void *kmap_coherent(struct page *page, unsigned long addr);
extern void kunmap_coherent(void);

#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
static inline void flush_kernel_dcache_page(struct page *page)
{
BUG_ON(cpu_has_dc_aliases && PageHighMem(page));
}

/*
* For now flush_kernel_vmap_range and invalidate_kernel_vmap_range both do a
* cache writeback and invalidate operation.
*/
extern void (*__flush_kernel_vmap_range)(unsigned long vaddr, int size);

static inline void flush_kernel_vmap_range(void *vaddr, int size)
{
if (cpu_has_dc_aliases)
__flush_kernel_vmap_range((unsigned long) vaddr, size);
}

static inline void invalidate_kernel_vmap_range(void *vaddr, int size)
{
if (cpu_has_dc_aliases)
__flush_kernel_vmap_range((unsigned long) vaddr, size);
}

#endif /* _ASM_CACHEFLUSH_H */
6 changes: 6 additions & 0 deletions arch/mips/mm/c-octeon.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ static void octeon_flush_cache_page(struct vm_area_struct *vma,
octeon_flush_icache_all_cores(vma);
}

static void octeon_flush_kernel_vmap_range(unsigned long vaddr, int size)
{
BUG();
}

/**
* Probe Octeon's caches
Expand Down Expand Up @@ -273,6 +277,8 @@ void __cpuinit octeon_cache_init(void)
flush_icache_range = octeon_flush_icache_range;
local_flush_icache_range = local_octeon_flush_icache_range;

__flush_kernel_vmap_range = octeon_flush_kernel_vmap_range;

build_clear_page();
build_copy_page();
}
Expand Down
7 changes: 7 additions & 0 deletions arch/mips/mm/c-r3k.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,11 @@ static void r3k_flush_cache_sigtramp(unsigned long addr)
write_c0_status(flags);
}

static void r3k_flush_kernel_vmap_range(unsigned long vaddr, int size)
{
BUG();
}

static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size)
{
/* Catch bad driver code */
Expand All @@ -323,6 +328,8 @@ void __cpuinit r3k_cache_init(void)
flush_icache_range = r3k_flush_icache_range;
local_flush_icache_range = r3k_flush_icache_range;

__flush_kernel_vmap_range = r3k_flush_kernel_vmap_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;
Expand Down
35 changes: 35 additions & 0 deletions arch/mips/mm/c-r4k.c
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,39 @@ static void r4k_flush_icache_all(void)
r4k_blast_icache();
}

struct flush_kernel_vmap_range_args {
unsigned long vaddr;
int size;
};

static inline void local_r4k_flush_kernel_vmap_range(void *args)
{
struct flush_kernel_vmap_range_args *vmra = args;
unsigned long vaddr = vmra->vaddr;
int size = vmra->size;

/*
* Aliases only affect the primary caches so don't bother with
* S-caches or T-caches.
*/
if (cpu_has_safe_index_cacheops && size >= dcache_size)
r4k_blast_dcache();
else {
R4600_HIT_CACHEOP_WAR_IMPL;
blast_dcache_range(vaddr, vaddr + size);
}
}

static void r4k_flush_kernel_vmap_range(unsigned long vaddr, int size)
{
struct flush_kernel_vmap_range_args args;

args.vaddr = (unsigned long) vaddr;
args.size = size;

r4k_on_each_cpu(local_r4k_flush_kernel_vmap_range, &args);
}

static inline void rm7k_erratum31(void)
{
const unsigned long ic_lsize = 32;
Expand Down Expand Up @@ -1403,6 +1436,8 @@ void __cpuinit r4k_cache_init(void)
flush_cache_page = r4k_flush_cache_page;
flush_cache_range = r4k_flush_cache_range;

__flush_kernel_vmap_range = r4k_flush_kernel_vmap_range;

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;
Expand Down
7 changes: 7 additions & 0 deletions arch/mips/mm/c-tx39.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,11 @@ static void tx39_flush_icache_range(unsigned long start, unsigned long end)
}
}

static void tx39_flush_kernel_vmap_range(unsigned long vaddr, int size)
{
BUG();
}

static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size)
{
unsigned long end;
Expand Down Expand Up @@ -394,6 +399,8 @@ void __cpuinit tx39_cache_init(void)
flush_icache_range = tx39_flush_icache_range;
local_flush_icache_range = tx39_flush_icache_range;

__flush_kernel_vmap_range = tx39_flush_kernel_vmap_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;
Expand Down
5 changes: 5 additions & 0 deletions arch/mips/mm/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ void (*local_flush_icache_range)(unsigned long start, unsigned long end);
void (*__flush_cache_vmap)(void);
void (*__flush_cache_vunmap)(void);

void (*__flush_kernel_vmap_range)(unsigned long vaddr, int size);
void (*__invalidate_kernel_vmap_range)(unsigned long vaddr, int size);

EXPORT_SYMBOL_GPL(__flush_kernel_vmap_range);

/* MIPS specific cache operations */
void (*flush_cache_sigtramp)(unsigned long addr);
void (*local_flush_data_cache_page)(void * addr);
Expand Down

0 comments on commit d9cdc90

Please sign in to comment.