Skip to content

Commit

Permalink
ARC: [mm] Aliasing VIPT dcache support 1/4
Browse files Browse the repository at this point in the history
This preps the low level dcache flush helpers to take vaddr argument in
addition to the existing paddr to properly flush the VIPT dcache

Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
  • Loading branch information
Vineet Gupta committed May 9, 2013
1 parent a690984 commit 6ec18a8
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 18 deletions.
2 changes: 1 addition & 1 deletion arch/arc/include/asm/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ void flush_cache_all(void);
void flush_icache_range(unsigned long start, unsigned long end);
void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len);
void __inv_icache_page(unsigned long paddr, unsigned long vaddr);
void __flush_dcache_page(unsigned long paddr);
void __flush_dcache_page(unsigned long paddr, unsigned long vaddr);

#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1

Expand Down
48 changes: 32 additions & 16 deletions arch/arc/mm/cache_arc700.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,10 @@ static inline void __dc_entire_op(const int cacheop)
* Per Line Operation on D-Cache
* Doesn't deal with type-of-op/IRQ-disabling/waiting-for-flush-to-complete
* It's sole purpose is to help gcc generate ZOL
* (aliasing VIPT dcache flushing needs both vaddr and paddr)
*/
static inline void __dc_line_loop(unsigned long paddr, unsigned long sz,
int aux_reg)
static inline void __dc_line_loop(unsigned long paddr, unsigned long vaddr,
unsigned long sz, const int aux_reg)
{
int num_lines;

Expand All @@ -284,31 +285,41 @@ static inline void __dc_line_loop(unsigned long paddr, unsigned long sz,
if (!(__builtin_constant_p(sz) && sz == PAGE_SIZE)) {
sz += paddr & ~DCACHE_LINE_MASK;
paddr &= DCACHE_LINE_MASK;
vaddr &= DCACHE_LINE_MASK;
}

num_lines = DIV_ROUND_UP(sz, ARC_DCACHE_LINE_LEN);

#if (CONFIG_ARC_MMU_VER <= 2)
paddr |= (vaddr >> PAGE_SHIFT) & 0x1F;
#endif

while (num_lines-- > 0) {
#if (CONFIG_ARC_MMU_VER > 2)
/*
* Just as for I$, in MMU v3, D$ ops also require
* "tag" bits in DC_PTAG, "index" bits in FLDL,IVDL ops
* But we pass phy addr for both. This works since Linux
* doesn't support aliasing configs for D$, yet.
* Thus paddr is enough to provide both tag and index.
*/
write_aux_reg(ARC_REG_DC_PTAG, paddr);
#endif

write_aux_reg(aux_reg, vaddr);
vaddr += ARC_DCACHE_LINE_LEN;
#else
/* paddr contains stuffed vaddrs bits */
write_aux_reg(aux_reg, paddr);
#endif
paddr += ARC_DCACHE_LINE_LEN;
}
}

/* For kernel mappings cache op index is same as paddr */
#define __dc_line_op_k(p, sz, op) __dc_line_op(p, p, sz, op)

/*
* D-Cache : Per Line INV (discard or wback+discard) or FLUSH (wback)
*/
static inline void __dc_line_op(unsigned long paddr, unsigned long sz,
const int cacheop)
static inline void __dc_line_op(unsigned long paddr, unsigned long vaddr,
unsigned long sz, const int cacheop)
{
unsigned long flags, tmp = tmp;
int aux;
Expand All @@ -331,7 +342,7 @@ static inline void __dc_line_op(unsigned long paddr, unsigned long sz,
else
aux = ARC_REG_DC_FLDL;

__dc_line_loop(paddr, sz, aux);
__dc_line_loop(paddr, vaddr, sz, aux);

if (cacheop & OP_FLUSH) /* flush / flush-n-inv both wait */
wait_for_flush();
Expand All @@ -346,7 +357,8 @@ static inline void __dc_line_op(unsigned long paddr, unsigned long sz,
#else

#define __dc_entire_op(cacheop)
#define __dc_line_op(paddr, sz, cacheop)
#define __dc_line_op(paddr, vaddr, sz, cacheop)
#define __dc_line_op_k(paddr, sz, cacheop)

#endif /* CONFIG_ARC_HAS_DCACHE */

Expand Down Expand Up @@ -462,19 +474,19 @@ EXPORT_SYMBOL(flush_dcache_page);

void dma_cache_wback_inv(unsigned long start, unsigned long sz)
{
__dc_line_op(start, sz, OP_FLUSH_N_INV);
__dc_line_op_k(start, sz, OP_FLUSH_N_INV);
}
EXPORT_SYMBOL(dma_cache_wback_inv);

void dma_cache_inv(unsigned long start, unsigned long sz)
{
__dc_line_op(start, sz, OP_INV);
__dc_line_op_k(start, sz, OP_INV);
}
EXPORT_SYMBOL(dma_cache_inv);

void dma_cache_wback(unsigned long start, unsigned long sz)
{
__dc_line_op(start, sz, OP_FLUSH);
__dc_line_op_k(start, sz, OP_FLUSH);
}
EXPORT_SYMBOL(dma_cache_wback);

Expand Down Expand Up @@ -555,7 +567,7 @@ void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len)

local_irq_save(flags);
__ic_line_inv_vaddr(paddr, vaddr, len);
__dc_line_op(paddr, len, OP_FLUSH);
__dc_line_op(paddr, vaddr, len, OP_FLUSH);
local_irq_restore(flags);
}

Expand All @@ -565,9 +577,13 @@ void __inv_icache_page(unsigned long paddr, unsigned long vaddr)
__ic_line_inv_vaddr(paddr, vaddr, PAGE_SIZE);
}

void __flush_dcache_page(unsigned long paddr)
/*
* wrapper to clearout kernel or userspace mappings of a page
* For kernel mappings @vaddr == @paddr
*/
void __flush_dcache_page(unsigned long paddr, unsigned long vaddr)
{
__dc_line_op(paddr, PAGE_SIZE, OP_FLUSH_N_INV);
__dc_line_op(paddr, vaddr & PAGE_MASK, PAGE_SIZE, OP_FLUSH_N_INV);
}

void flush_icache_all(void)
Expand Down
2 changes: 1 addition & 1 deletion arch/arc/mm/tlb.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned,
int dirty = test_and_clear_bit(PG_arch_1, &page->flags);
if (dirty) {
unsigned long paddr = pte_val(*ptep) & PAGE_MASK;
__flush_dcache_page(paddr);
__flush_dcache_page(paddr, paddr);
__inv_icache_page(paddr, vaddr);
}
}
Expand Down

0 comments on commit 6ec18a8

Please sign in to comment.