提交 41700e73 编写于 作者: A Atsushi Nemoto 提交者: Ralf Baechle

[MIPS] Add protected_blast_icache_range, blast_icache_range, etc.

    
Add blast_xxx_range(), protected_blast_xxx_range() etc. for common
use.  They are built by __BUILD_BLAST_CACHE_RANGE().
Use protected_cache_op() macro for various protected_ routines.
Output code should be logically same.
Signed-off-by: NAtsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: NRalf Baechle <ralf@linux-mips.org>
上级 63077519
...@@ -471,61 +471,29 @@ struct flush_icache_range_args { ...@@ -471,61 +471,29 @@ struct flush_icache_range_args {
static inline void local_r4k_flush_icache_range(void *args) static inline void local_r4k_flush_icache_range(void *args)
{ {
struct flush_icache_range_args *fir_args = args; struct flush_icache_range_args *fir_args = args;
unsigned long dc_lsize = cpu_dcache_line_size();
unsigned long ic_lsize = cpu_icache_line_size();
unsigned long sc_lsize = cpu_scache_line_size();
unsigned long start = fir_args->start; unsigned long start = fir_args->start;
unsigned long end = fir_args->end; unsigned long end = fir_args->end;
unsigned long addr, aend;
if (!cpu_has_ic_fills_f_dc) { if (!cpu_has_ic_fills_f_dc) {
if (end - start > dcache_size) { if (end - start > dcache_size) {
r4k_blast_dcache(); r4k_blast_dcache();
} else { } else {
R4600_HIT_CACHEOP_WAR_IMPL; R4600_HIT_CACHEOP_WAR_IMPL;
addr = start & ~(dc_lsize - 1); protected_blast_dcache_range(start, end);
aend = (end - 1) & ~(dc_lsize - 1);
while (1) {
/* Hit_Writeback_Inv_D */
protected_writeback_dcache_line(addr);
if (addr == aend)
break;
addr += dc_lsize;
}
} }
if (!cpu_icache_snoops_remote_store) { if (!cpu_icache_snoops_remote_store) {
if (end - start > scache_size) { if (end - start > scache_size)
r4k_blast_scache(); r4k_blast_scache();
} else { else
addr = start & ~(sc_lsize - 1); protected_blast_scache_range(start, end);
aend = (end - 1) & ~(sc_lsize - 1);
while (1) {
/* Hit_Writeback_Inv_SD */
protected_writeback_scache_line(addr);
if (addr == aend)
break;
addr += sc_lsize;
}
}
} }
} }
if (end - start > icache_size) if (end - start > icache_size)
r4k_blast_icache(); r4k_blast_icache();
else { else
addr = start & ~(ic_lsize - 1); protected_blast_icache_range(start, end);
aend = (end - 1) & ~(ic_lsize - 1);
while (1) {
/* Hit_Invalidate_I */
protected_flush_icache_line(addr);
if (addr == aend)
break;
addr += ic_lsize;
}
}
} }
static void r4k_flush_icache_range(unsigned long start, unsigned long end) static void r4k_flush_icache_range(unsigned long start, unsigned long end)
...@@ -619,27 +587,14 @@ static void r4k_flush_icache_page(struct vm_area_struct *vma, ...@@ -619,27 +587,14 @@ static void r4k_flush_icache_page(struct vm_area_struct *vma,
static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
{ {
unsigned long end, a;
/* Catch bad driver code */ /* Catch bad driver code */
BUG_ON(size == 0); BUG_ON(size == 0);
if (cpu_has_subset_pcaches) { if (cpu_has_subset_pcaches) {
unsigned long sc_lsize = cpu_scache_line_size(); if (size >= scache_size)
if (size >= scache_size) {
r4k_blast_scache(); r4k_blast_scache();
return; else
} blast_scache_range(addr, addr + size);
a = addr & ~(sc_lsize - 1);
end = (addr + size - 1) & ~(sc_lsize - 1);
while (1) {
flush_scache_line(a); /* Hit_Writeback_Inv_SD */
if (a == end)
break;
a += sc_lsize;
}
return; return;
} }
...@@ -651,17 +606,8 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) ...@@ -651,17 +606,8 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
if (size >= dcache_size) { if (size >= dcache_size) {
r4k_blast_dcache(); r4k_blast_dcache();
} else { } else {
unsigned long dc_lsize = cpu_dcache_line_size();
R4600_HIT_CACHEOP_WAR_IMPL; R4600_HIT_CACHEOP_WAR_IMPL;
a = addr & ~(dc_lsize - 1); blast_dcache_range(addr, addr + size);
end = (addr + size - 1) & ~(dc_lsize - 1);
while (1) {
flush_dcache_line(a); /* Hit_Writeback_Inv_D */
if (a == end)
break;
a += dc_lsize;
}
} }
bc_wback_inv(addr, size); bc_wback_inv(addr, size);
...@@ -669,44 +615,22 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) ...@@ -669,44 +615,22 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
{ {
unsigned long end, a;
/* Catch bad driver code */ /* Catch bad driver code */
BUG_ON(size == 0); BUG_ON(size == 0);
if (cpu_has_subset_pcaches) { if (cpu_has_subset_pcaches) {
unsigned long sc_lsize = cpu_scache_line_size(); if (size >= scache_size)
if (size >= scache_size) {
r4k_blast_scache(); r4k_blast_scache();
return; else
} blast_scache_range(addr, addr + size);
a = addr & ~(sc_lsize - 1);
end = (addr + size - 1) & ~(sc_lsize - 1);
while (1) {
flush_scache_line(a); /* Hit_Writeback_Inv_SD */
if (a == end)
break;
a += sc_lsize;
}
return; return;
} }
if (size >= dcache_size) { if (size >= dcache_size) {
r4k_blast_dcache(); r4k_blast_dcache();
} else { } else {
unsigned long dc_lsize = cpu_dcache_line_size();
R4600_HIT_CACHEOP_WAR_IMPL; R4600_HIT_CACHEOP_WAR_IMPL;
a = addr & ~(dc_lsize - 1); blast_dcache_range(addr, addr + size);
end = (addr + size - 1) & ~(dc_lsize - 1);
while (1) {
flush_dcache_line(a); /* Hit_Writeback_Inv_D */
if (a == end)
break;
a += dc_lsize;
}
} }
bc_inv(addr, size); bc_inv(addr, size);
......
...@@ -44,8 +44,6 @@ __asm__ __volatile__( \ ...@@ -44,8 +44,6 @@ __asm__ __volatile__( \
/* TX39H-style cache flush routines. */ /* TX39H-style cache flush routines. */
static void tx39h_flush_icache_all(void) static void tx39h_flush_icache_all(void)
{ {
unsigned long start = KSEG0;
unsigned long end = (start + icache_size);
unsigned long flags, config; unsigned long flags, config;
/* disable icache (set ICE#) */ /* disable icache (set ICE#) */
...@@ -53,33 +51,18 @@ static void tx39h_flush_icache_all(void) ...@@ -53,33 +51,18 @@ static void tx39h_flush_icache_all(void)
config = read_c0_conf(); config = read_c0_conf();
write_c0_conf(config & ~TX39_CONF_ICE); write_c0_conf(config & ~TX39_CONF_ICE);
TX39_STOP_STREAMING(); TX39_STOP_STREAMING();
blast_icache16();
/* invalidate icache */
while (start < end) {
cache16_unroll32(start, Index_Invalidate_I);
start += 0x200;
}
write_c0_conf(config); write_c0_conf(config);
local_irq_restore(flags); local_irq_restore(flags);
} }
static void tx39h_dma_cache_wback_inv(unsigned long addr, unsigned long size) static void tx39h_dma_cache_wback_inv(unsigned long addr, unsigned long size)
{ {
unsigned long end, a;
unsigned long dc_lsize = current_cpu_data.dcache.linesz;
/* Catch bad driver code */ /* Catch bad driver code */
BUG_ON(size == 0); BUG_ON(size == 0);
iob(); iob();
a = addr & ~(dc_lsize - 1); blast_inv_dcache_range(addr, addr + size);
end = (addr + size - 1) & ~(dc_lsize - 1);
while (1) {
invalidate_dcache_line(a); /* Hit_Invalidate_D */
if (a == end) break;
a += dc_lsize;
}
} }
...@@ -241,42 +224,21 @@ static void tx39_flush_data_cache_page(unsigned long addr) ...@@ -241,42 +224,21 @@ static void tx39_flush_data_cache_page(unsigned long addr)
static void tx39_flush_icache_range(unsigned long start, unsigned long end) static void tx39_flush_icache_range(unsigned long start, unsigned long end)
{ {
unsigned long dc_lsize = current_cpu_data.dcache.linesz;
unsigned long addr, aend;
if (end - start > dcache_size) if (end - start > dcache_size)
tx39_blast_dcache(); tx39_blast_dcache();
else { else
addr = start & ~(dc_lsize - 1); protected_blast_dcache_range(start, end);
aend = (end - 1) & ~(dc_lsize - 1);
while (1) {
/* Hit_Writeback_Inv_D */
protected_writeback_dcache_line(addr);
if (addr == aend)
break;
addr += dc_lsize;
}
}
if (end - start > icache_size) if (end - start > icache_size)
tx39_blast_icache(); tx39_blast_icache();
else { else {
unsigned long flags, config; unsigned long flags, config;
addr = start & ~(dc_lsize - 1);
aend = (end - 1) & ~(dc_lsize - 1);
/* disable icache (set ICE#) */ /* disable icache (set ICE#) */
local_irq_save(flags); local_irq_save(flags);
config = read_c0_conf(); config = read_c0_conf();
write_c0_conf(config & ~TX39_CONF_ICE); write_c0_conf(config & ~TX39_CONF_ICE);
TX39_STOP_STREAMING(); TX39_STOP_STREAMING();
while (1) { protected_blast_icache_range(start, end);
/* Hit_Invalidate_I */
protected_flush_icache_line(addr);
if (addr == aend)
break;
addr += dc_lsize;
}
write_c0_conf(config); write_c0_conf(config);
local_irq_restore(flags); local_irq_restore(flags);
} }
...@@ -311,7 +273,7 @@ static void tx39_flush_icache_page(struct vm_area_struct *vma, struct page *page ...@@ -311,7 +273,7 @@ static void tx39_flush_icache_page(struct vm_area_struct *vma, struct page *page
static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size) static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size)
{ {
unsigned long end, a; unsigned long end;
if (((size | addr) & (PAGE_SIZE - 1)) == 0) { if (((size | addr) & (PAGE_SIZE - 1)) == 0) {
end = addr + size; end = addr + size;
...@@ -322,20 +284,13 @@ static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size) ...@@ -322,20 +284,13 @@ static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size)
} else if (size > dcache_size) { } else if (size > dcache_size) {
tx39_blast_dcache(); tx39_blast_dcache();
} else { } else {
unsigned long dc_lsize = current_cpu_data.dcache.linesz; blast_dcache_range(addr, addr + size);
a = addr & ~(dc_lsize - 1);
end = (addr + size - 1) & ~(dc_lsize - 1);
while (1) {
flush_dcache_line(a); /* Hit_Writeback_Inv_D */
if (a == end) break;
a += dc_lsize;
}
} }
} }
static void tx39_dma_cache_inv(unsigned long addr, unsigned long size) static void tx39_dma_cache_inv(unsigned long addr, unsigned long size)
{ {
unsigned long end, a; unsigned long end;
if (((size | addr) & (PAGE_SIZE - 1)) == 0) { if (((size | addr) & (PAGE_SIZE - 1)) == 0) {
end = addr + size; end = addr + size;
...@@ -346,14 +301,7 @@ static void tx39_dma_cache_inv(unsigned long addr, unsigned long size) ...@@ -346,14 +301,7 @@ static void tx39_dma_cache_inv(unsigned long addr, unsigned long size)
} else if (size > dcache_size) { } else if (size > dcache_size) {
tx39_blast_dcache(); tx39_blast_dcache();
} else { } else {
unsigned long dc_lsize = current_cpu_data.dcache.linesz; blast_inv_dcache_range(addr, addr + size);
a = addr & ~(dc_lsize - 1);
end = (addr + size - 1) & ~(dc_lsize - 1);
while (1) {
invalidate_dcache_line(a); /* Hit_Invalidate_D */
if (a == end) break;
a += dc_lsize;
}
} }
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <asm/asm.h> #include <asm/asm.h>
#include <asm/cacheops.h> #include <asm/cacheops.h>
#include <asm/cpu-features.h>
/* /*
* This macro return a properly sign-extended address suitable as base address * This macro return a properly sign-extended address suitable as base address
...@@ -78,22 +79,25 @@ static inline void flush_scache_line(unsigned long addr) ...@@ -78,22 +79,25 @@ static inline void flush_scache_line(unsigned long addr)
cache_op(Hit_Writeback_Inv_SD, addr); cache_op(Hit_Writeback_Inv_SD, addr);
} }
#define protected_cache_op(op,addr) \
__asm__ __volatile__( \
" .set push \n" \
" .set noreorder \n" \
" .set mips3 \n" \
"1: cache %0, (%1) \n" \
"2: .set pop \n" \
" .section __ex_table,\"a\" \n" \
" "STR(PTR)" 1b, 2b \n" \
" .previous" \
: \
: "i" (op), "r" (addr))
/* /*
* The next two are for badland addresses like signal trampolines. * The next two are for badland addresses like signal trampolines.
*/ */
static inline void protected_flush_icache_line(unsigned long addr) static inline void protected_flush_icache_line(unsigned long addr)
{ {
__asm__ __volatile__( protected_cache_op(Hit_Invalidate_I, addr);
" .set push \n"
" .set noreorder \n"
" .set mips3 \n"
"1: cache %0, (%1) \n"
"2: .set pop \n"
" .section __ex_table,\"a\" \n"
" "STR(PTR)" 1b, 2b \n"
" .previous"
:
: "i" (Hit_Invalidate_I), "r" (addr));
} }
/* /*
...@@ -104,32 +108,12 @@ static inline void protected_flush_icache_line(unsigned long addr) ...@@ -104,32 +108,12 @@ static inline void protected_flush_icache_line(unsigned long addr)
*/ */
static inline void protected_writeback_dcache_line(unsigned long addr) static inline void protected_writeback_dcache_line(unsigned long addr)
{ {
__asm__ __volatile__( protected_cache_op(Hit_Writeback_Inv_D, addr);
" .set push \n"
" .set noreorder \n"
" .set mips3 \n"
"1: cache %0, (%1) \n"
"2: .set pop \n"
" .section __ex_table,\"a\" \n"
" "STR(PTR)" 1b, 2b \n"
" .previous"
:
: "i" (Hit_Writeback_Inv_D), "r" (addr));
} }
static inline void protected_writeback_scache_line(unsigned long addr) static inline void protected_writeback_scache_line(unsigned long addr)
{ {
__asm__ __volatile__( protected_cache_op(Hit_Writeback_Inv_SD, addr);
" .set push \n"
" .set noreorder \n"
" .set mips3 \n"
"1: cache %0, (%1) \n"
"2: .set pop \n"
" .section __ex_table,\"a\" \n"
" "STR(PTR)" 1b, 2b \n"
" .previous"
:
: "i" (Hit_Writeback_Inv_SD), "r" (addr));
} }
/* /*
...@@ -295,4 +279,28 @@ __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64) ...@@ -295,4 +279,28 @@ __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64) __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64)
__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128) __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128)
/* build blast_xxx_range, protected_blast_xxx_range */
#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \
static inline void prot##blast_##pfx##cache##_range(unsigned long start, \
unsigned long end) \
{ \
unsigned long lsize = cpu_##desc##_line_size(); \
unsigned long addr = start & ~(lsize - 1); \
unsigned long aend = (end - 1) & ~(lsize - 1); \
while (1) { \
prot##cache_op(hitop, addr); \
if (addr == aend) \
break; \
addr += lsize; \
} \
}
__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_)
__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_)
__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_)
__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, )
__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, )
/* blast_inv_dcache_range */
__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, )
#endif /* _ASM_R4KCACHE_H */ #endif /* _ASM_R4KCACHE_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册