#include <linux/module.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/cache.h>
#include <linux/mmu_context.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
#include <linux/pagemap.h>
#include <asm/cacheflush.h>
#include <asm/cachectl.h>
#include <asm/setup.h>
#ifdef CONFIG_ISA_ARCV2
#define USE_RGN_FLSH 1
#endif
static int l2_line_sz;
static int ioc_exists;
int slc_enable = 1, ioc_enable = 1;
unsigned long perip_base = ARC_UNCACHED_ADDR_SPACE;
unsigned long perip_end = 0xFFFFFFFF;
static struct cpuinfo_arc_cache {
unsigned int sz_k, line_len, colors;
} ic_info, dc_info, slc_info;
void (*_cache_line_loop_ic_fn)(phys_addr_t paddr, unsigned long vaddr,
unsigned long sz, const int op, const int full_page);
void (*__dma_cache_wback_inv)(phys_addr_t start, unsigned long sz);
void (*__dma_cache_inv)(phys_addr_t start, unsigned long sz);
void (*__dma_cache_wback)(phys_addr_t start, unsigned long sz);
static int read_decode_cache_bcr_arcv2(int c, char *buf, int len)
{
struct cpuinfo_arc_cache *p_slc = &slc_info;
struct bcr_identity ident;
struct bcr_generic sbcr;
struct bcr_clust_cfg cbcr;
struct bcr_volatile vol;
int n = 0;
READ_BCR(ARC_REG_SLC_BCR, sbcr);
if (sbcr.ver) {
struct bcr_slc_cfg slc_cfg;
READ_BCR(ARC_REG_SLC_CFG, slc_cfg);
p_slc->sz_k = 128 << slc_cfg.sz;
l2_line_sz = p_slc->line_len = (slc_cfg.lsz == 0) ? 128 : 64;
n += scnprintf(buf + n, len - n,
"SLC\t\t: %uK, %uB Line%s\n",
p_slc->sz_k, p_slc->line_len, IS_USED_RUN(slc_enable));
}
READ_BCR(ARC_REG_CLUSTER_BCR, cbcr);
if (cbcr.c) {
ioc_exists = 1;
if (IS_ENABLED(CONFIG_HIGHMEM) || is_pae40_enabled())
ioc_enable = 0;
} else {
ioc_enable = 0;
}
READ_BCR(AUX_IDENTITY, ident);
if (ident.family > 0x51) {
READ_BCR(AUX_VOL, vol);
perip_base = vol.start << 28;
if (ident.family > 0x52)
perip_end = (vol.limit << 28) - 1;
}
n += scnprintf(buf + n, len - n, "Peripherals\t: %#lx%s%s\n",
perip_base,
IS_AVAIL3(ioc_exists, ioc_enable, ", IO-Coherency (per-device) "));
return n;
}
int arc_cache_mumbojumbo(int c, char *buf, int len)
{
struct cpuinfo_arc_cache *p_ic = &ic_info, *p_dc = &dc_info;
struct bcr_cache ibcr, dbcr;
int vipt, assoc;
int n = 0;
READ_BCR(ARC_REG_IC_BCR, ibcr);
if (!ibcr.ver)
goto dc_chk;
if (is_isa_arcompact() && (ibcr.ver <= 3)) {
BUG_ON(ibcr.config != 3);
assoc = 2;
} else if (is_isa_arcv2() && (ibcr.ver >= 4)) {
assoc = 1 << ibcr.config;
}
p_ic->line_len = 8 << ibcr.line_len;
p_ic->sz_k = 1 << (ibcr.sz - 1);
p_ic->colors = p_ic->sz_k/assoc/TO_KB(PAGE_SIZE);
n += scnprintf(buf + n, len - n,
"I-Cache\t\t: %uK, %dway/set, %uB Line, VIPT%s%s\n",
p_ic->sz_k, assoc, p_ic->line_len,
p_ic->colors > 1 ? " aliasing" : "",
IS_USED_CFG(CONFIG_ARC_HAS_ICACHE));
dc_chk:
READ_BCR(ARC_REG_DC_BCR, dbcr);
if (!dbcr.ver)
goto slc_chk;
if (is_isa_arcompact() && (dbcr.ver <= 3)) {
BUG_ON(dbcr.config != 2);
vipt = 1;
assoc = 4;
p_dc->colors = p_dc->sz_k/assoc/TO_KB(PAGE_SIZE);
} else if (is_isa_arcv2() && (dbcr.ver >= 4)) {
vipt = 0;
assoc = 1 << dbcr.config;
p_dc->colors = 1;
}
p_dc->line_len = 16 << dbcr.line_len;
p_dc->sz_k = 1 << (dbcr.sz - 1);
n += scnprintf(buf + n, len - n,
"D-Cache\t\t: %uK, %dway/set, %uB Line, %s%s\n",
p_dc->sz_k, assoc, p_dc->line_len,
vipt ? "VIPT" : "PIPT",
IS_USED_CFG(CONFIG_ARC_HAS_DCACHE));
slc_chk:
if (is_isa_arcv2())
n += read_decode_cache_bcr_arcv2(c, buf + n, len - n);
return n;
}
#define OP_INV 0x1
#define OP_FLUSH 0x2
#define OP_FLUSH_N_INV 0x3
#define OP_INV_IC 0x4
static inline
void __cache_line_loop_v3(phys_addr_t paddr, unsigned long vaddr,
unsigned long sz, const int op, const int full_page)
{
unsigned int aux_cmd, aux_tag;
int num_lines;
if (op == OP_INV_IC) {
aux_cmd = ARC_REG_IC_IVIL;
aux_tag = ARC_REG_IC_PTAG;
} else {
aux_cmd = op & OP_INV ? ARC_REG_DC_IVDL : ARC_REG_DC_FLDL;
aux_tag = ARC_REG_DC_PTAG;
}
if (!full_page) {
sz += paddr & ~CACHE_LINE_MASK;
paddr &= CACHE_LINE_MASK;
vaddr &= CACHE_LINE_MASK;
}
num_lines = DIV_ROUND_UP(sz, L1_CACHE_BYTES);
if (full_page)
write_aux_reg(aux_tag, paddr);
if (is_pae40_enabled() && op == OP_INV_IC)
write_aux_reg(ARC_REG_IC_PTAG_HI, (u64)paddr >> 32);
while (num_lines-- > 0) {
if (!full_page) {
write_aux_reg(aux_tag, paddr);
paddr += L1_CACHE_BYTES;
}
write_aux_reg(aux_cmd, vaddr);
vaddr += L1_CACHE_BYTES;
}
}
#ifndef USE_RGN_FLSH
static inline
void __cache_line_loop_v4(phys_addr_t paddr, unsigned long vaddr,
unsigned long sz, const int op, const int full_page)
{
unsigned int aux_cmd;
int num_lines;
if (op == OP_INV_IC) {
aux_cmd = ARC_REG_IC_IVIL;
} else {
aux_cmd = op & OP_INV ? ARC_REG_DC_IVDL : ARC_REG_DC_FLDL;
}
if (!full_page) {
sz += paddr & ~CACHE_LINE_MASK;
paddr &= CACHE_LINE_MASK;
}
num_lines = DIV_ROUND_UP(sz, L1_CACHE_BYTES);
if (is_pae40_enabled()) {
if (op == OP_INV_IC)
write_aux_reg(ARC_REG_IC_PTAG_HI, (u64)paddr >> 32);
else
write_aux_reg(ARC_REG_DC_PTAG_HI, (u64)paddr >> 32);
}
while (num_lines-- > 0) {
write_aux_reg(aux_cmd, paddr);
paddr += L1_CACHE_BYTES;
}
}
#else
static inline
void __cache_line_loop_v4(phys_addr_t paddr, unsigned long vaddr,
unsigned long sz, const int op, const int full_page)
{
unsigned int s, e;
if (op == OP_INV_IC) {
s = ARC_REG_IC_IVIR;
e = ARC_REG_IC_ENDR;
} else {
s = ARC_REG_DC_STARTR;
e = ARC_REG_DC_ENDR;
}
if (!full_page) {
sz += paddr & ~CACHE_LINE_MASK;
paddr &= CACHE_LINE_MASK;
sz += L1_CACHE_BYTES - 1;
}
if (is_pae40_enabled()) {
if (op == OP_INV_IC)
write_aux_reg(ARC_REG_IC_PTAG_HI, (u64)paddr >> 32);
else
write_aux_reg(ARC_REG_DC_PTAG_HI, (u64)paddr >> 32);
}
write_aux_reg(e, paddr + sz);
write_aux_reg(s, paddr);
}
#endif
#ifdef CONFIG_ARC_MMU_V3
#define __cache_line_loop __cache_line_loop_v3
#else
#define __cache_line_loop __cache_line_loop_v4
#endif
#ifdef CONFIG_ARC_HAS_DCACHE
#ifndef USE_RGN_FLSH
static inline void __before_dc_op(const int op)
{
if (op == OP_FLUSH_N_INV) {
const unsigned int ctl = ARC_REG_DC_CTRL;
write_aux_reg(ctl, read_aux_reg(ctl) | DC_CTRL_INV_MODE_FLUSH);
}
}
#else
static inline void __before_dc_op(const int op)
{
const unsigned int ctl = ARC_REG_DC_CTRL;
unsigned int val = read_aux_reg(ctl);
if (op == OP_FLUSH_N_INV) {
val |= DC_CTRL_INV_MODE_FLUSH;
}
if (op != OP_INV_IC) {
val &= ~DC_CTRL_RGN_OP_MSK;
if (op & OP_INV)
val |= DC_CTRL_RGN_OP_INV;
}
write_aux_reg(ctl, val);
}
#endif
static inline void __after_dc_op(const int op)
{
if (op & OP_FLUSH) {
const unsigned int ctl = ARC_REG_DC_CTRL;
unsigned int reg;
while ((reg = read_aux_reg(ctl)) & DC_CTRL_FLUSH_STATUS)
;
if (op == OP_FLUSH_N_INV)
write_aux_reg(ctl, reg & ~DC_CTRL_INV_MODE_FLUSH);
}
}
static inline void __dc_entire_op(const int op)
{
int aux;
__before_dc_op(op);
if (op & OP_INV)
aux = ARC_REG_DC_IVDC;
else
aux = ARC_REG_DC_FLSH;
write_aux_reg(aux, 0x1);
__after_dc_op(op);
}
static inline void __dc_disable(void)
{
const int r = ARC_REG_DC_CTRL;
__dc_entire_op(OP_FLUSH_N_INV);
write_aux_reg(r, read_aux_reg(r) | DC_CTRL_DIS);
}
static void __dc_enable(void)
{
const int r = ARC_REG_DC_CTRL;
write_aux_reg(r, read_aux_reg(r) & ~DC_CTRL_DIS);
}
#define __dc_line_op_k(p, sz, op) __dc_line_op(p, p, sz, op)
static inline void __dc_line_op(phys_addr_t paddr, unsigned long vaddr,
unsigned long sz, const int op)
{
const int full_page = __builtin_constant_p(sz) && sz == PAGE_SIZE;
unsigned long flags;
local_irq_save(flags);
__before_dc_op(op);
__cache_line_loop(paddr, vaddr, sz, op, full_page);
__after_dc_op(op);
local_irq_restore(flags);
}
#else
#define __dc_entire_op(op)
#define __dc_disable()
#define __dc_enable()
#define __dc_line_op(paddr, vaddr, sz, op)
#define __dc_line_op_k(paddr, sz, op)
#endif
#ifdef CONFIG_ARC_HAS_ICACHE
static inline void __ic_entire_inv(void)
{
write_aux_reg(ARC_REG_IC_IVIC, 1);
read_aux_reg(ARC_REG_IC_CTRL);
}
static inline void
__ic_line_inv_vaddr_local(phys_addr_t paddr, unsigned long vaddr,
unsigned long sz)
{
const int full_page = __builtin_constant_p(sz) && sz == PAGE_SIZE;
unsigned long flags;
local_irq_save(flags);
(*_cache_line_loop_ic_fn)(paddr, vaddr, sz, OP_INV_IC, full_page);
local_irq_restore(flags);
}
#ifndef CONFIG_SMP
#define __ic_line_inv_vaddr(p, v, s) __ic_line_inv_vaddr_local(p, v, s)
#else
struct ic_inv_args {
phys_addr_t paddr, vaddr;
int sz;
};
static void __ic_line_inv_vaddr_helper(void *info)
{
struct ic_inv_args *ic_inv = info;
__ic_line_inv_vaddr_local(ic_inv->paddr, ic_inv->vaddr, ic_inv->sz);
}
static void __ic_line_inv_vaddr(phys_addr_t paddr, unsigned long vaddr,
unsigned long sz)
{
struct ic_inv_args ic_inv = {
.paddr = paddr,
.vaddr = vaddr,
.sz = sz
};
on_each_cpu(__ic_line_inv_vaddr_helper, &ic_inv, 1);
}
#endif
#else
#define __ic_entire_inv()
#define __ic_line_inv_vaddr(pstart, vstart, sz)
#endif
static noinline void slc_op_rgn(phys_addr_t paddr, unsigned long sz, const int op)
{
#ifdef CONFIG_ISA_ARCV2
static DEFINE_SPINLOCK(lock);
unsigned long flags;
unsigned int ctrl;
phys_addr_t end;
spin_lock_irqsave(&lock, flags);
ctrl = read_aux_reg(ARC_REG_SLC_CTRL);
if (!(op & OP_FLUSH))
ctrl &= ~SLC_CTRL_IM;
else
ctrl |= SLC_CTRL_IM;
if (op & OP_INV)
ctrl |= SLC_CTRL_RGN_OP_INV;
else
ctrl &= ~SLC_CTRL_RGN_OP_INV;
write_aux_reg(ARC_REG_SLC_CTRL, ctrl);
end = paddr + sz + l2_line_sz - 1;
if (is_pae40_enabled())
write_aux_reg(ARC_REG_SLC_RGN_END1, upper_32_bits(end));
write_aux_reg(ARC_REG_SLC_RGN_END, lower_32_bits(end));
if (is_pae40_enabled())
write_aux_reg(ARC_REG_SLC_RGN_START1, upper_32_bits(paddr));
write_aux_reg(ARC_REG_SLC_RGN_START, lower_32_bits(paddr));
read_aux_reg(ARC_REG_SLC_CTRL);
while (read_aux_reg(ARC_REG_SLC_CTRL) & SLC_CTRL_BUSY);
spin_unlock_irqrestore(&lock, flags);
#endif
}
static __maybe_unused noinline void slc_op_line(phys_addr_t paddr, unsigned long sz, const int op)
{
#ifdef CONFIG_ISA_ARCV2
static DEFINE_SPINLOCK(lock);
const unsigned long SLC_LINE_MASK = ~(l2_line_sz - 1);
unsigned int ctrl, cmd;
unsigned long flags;
int num_lines;
spin_lock_irqsave(&lock, flags);
ctrl = read_aux_reg(ARC_REG_SLC_CTRL);
if (!(op & OP_FLUSH))
ctrl &= ~SLC_CTRL_IM;
else
ctrl |= SLC_CTRL_IM;
write_aux_reg(ARC_REG_SLC_CTRL, ctrl);
cmd = op & OP_INV ? ARC_AUX_SLC_IVDL : ARC_AUX_SLC_FLDL;
sz += paddr & ~SLC_LINE_MASK;
paddr &= SLC_LINE_MASK;
num_lines = DIV_ROUND_UP(sz, l2_line_sz);
while (num_lines-- > 0) {
write_aux_reg(cmd, paddr);
paddr += l2_line_sz;
}
read_aux_reg(ARC_REG_SLC_CTRL);
while (read_aux_reg(ARC_REG_SLC_CTRL) & SLC_CTRL_BUSY);
spin_unlock_irqrestore(&lock, flags);
#endif
}
#define slc_op(paddr, sz, op) slc_op_rgn(paddr, sz, op)
noinline static void slc_entire_op(const int op)
{
unsigned int ctrl, r = ARC_REG_SLC_CTRL;
ctrl = read_aux_reg(r);
if (!(op & OP_FLUSH))
ctrl &= ~SLC_CTRL_IM;
else
ctrl |= SLC_CTRL_IM;
write_aux_reg(r, ctrl);
if (op & OP_INV)
write_aux_reg(ARC_REG_SLC_INVALIDATE, 0x1);
else
write_aux_reg(ARC_REG_SLC_FLUSH, 0x1);
read_aux_reg(r);
while (read_aux_reg(r) & SLC_CTRL_BUSY);
}
static inline void arc_slc_disable(void)
{
const int r = ARC_REG_SLC_CTRL;
slc_entire_op(OP_FLUSH_N_INV);
write_aux_reg(r, read_aux_reg(r) | SLC_CTRL_DIS);
}
static inline void arc_slc_enable(void)
{
const int r = ARC_REG_SLC_CTRL;
write_aux_reg(r, read_aux_reg(r) & ~SLC_CTRL_DIS);
}
void flush_dcache_folio(struct folio *folio)
{
clear_bit(PG_dc_clean, &folio->flags);
return;
}
EXPORT_SYMBOL(flush_dcache_folio);
void flush_dcache_page(struct page *page)
{
return flush_dcache_folio(page_folio(page));
}
EXPORT_SYMBOL(flush_dcache_page);
static void __dma_cache_wback_inv_l1(phys_addr_t start, unsigned long sz)
{
__dc_line_op_k(start, sz, OP_FLUSH_N_INV);
}
static void __dma_cache_inv_l1(phys_addr_t start, unsigned long sz)
{
__dc_line_op_k(start, sz, OP_INV);
}
static void __dma_cache_wback_l1(phys_addr_t start, unsigned long sz)
{
__dc_line_op_k(start, sz, OP_FLUSH);
}
static void __dma_cache_wback_inv_slc(phys_addr_t start, unsigned long sz)
{
__dc_line_op_k(start, sz, OP_FLUSH_N_INV);
slc_op(start, sz, OP_FLUSH_N_INV);
}
static void __dma_cache_inv_slc(phys_addr_t start, unsigned long sz)
{
__dc_line_op_k(start, sz, OP_INV);
slc_op(start, sz, OP_INV);
}
static void __dma_cache_wback_slc(phys_addr_t start, unsigned long sz)
{
__dc_line_op_k(start, sz, OP_FLUSH);
slc_op(start, sz, OP_FLUSH);
}
void dma_cache_wback_inv(phys_addr_t start, unsigned long sz)
{
__dma_cache_wback_inv(start, sz);
}
EXPORT_SYMBOL(dma_cache_wback_inv);
void dma_cache_inv(phys_addr_t start, unsigned long sz)
{
__dma_cache_inv(start, sz);
}
EXPORT_SYMBOL(dma_cache_inv);
void dma_cache_wback(phys_addr_t start, unsigned long sz)
{
__dma_cache_wback(start, sz);
}
EXPORT_SYMBOL(dma_cache_wback);
void flush_icache_range(unsigned long kstart, unsigned long kend)
{
unsigned int tot_sz;
WARN(kstart < TASK_SIZE, "%s() can't handle user vaddr", __func__);
tot_sz = kend - kstart;
if (tot_sz > PAGE_SIZE) {
flush_cache_all();
return;
}
if (likely(kstart > PAGE_OFFSET)) {
__sync_icache_dcache(kstart, kstart, kend - kstart);
return;
}
while (tot_sz > 0) {
unsigned int off, sz;
unsigned long phy, pfn;
off = kstart % PAGE_SIZE;
pfn = vmalloc_to_pfn((void *)kstart);
phy = (pfn << PAGE_SHIFT) + off;
sz = min_t(unsigned int, tot_sz, PAGE_SIZE - off);
__sync_icache_dcache(phy, kstart, sz);
kstart += sz;
tot_sz -= sz;
}
}
EXPORT_SYMBOL(flush_icache_range);
void __sync_icache_dcache(phys_addr_t paddr, unsigned long vaddr, int len)
{
__dc_line_op(paddr, vaddr, len, OP_FLUSH_N_INV);
__ic_line_inv_vaddr(paddr, vaddr, len);
}
void __inv_icache_pages(phys_addr_t paddr, unsigned long vaddr, unsigned nr)
{
__ic_line_inv_vaddr(paddr, vaddr, nr * PAGE_SIZE);
}
void __flush_dcache_pages(phys_addr_t paddr, unsigned long vaddr, unsigned nr)
{
__dc_line_op(paddr, vaddr & PAGE_MASK, nr * PAGE_SIZE, OP_FLUSH_N_INV);
}
noinline void flush_cache_all(void)
{
unsigned long flags;
local_irq_save(flags);
__ic_entire_inv();
__dc_entire_op(OP_FLUSH_N_INV);
local_irq_restore(flags);
}
void copy_user_highpage(struct page *to, struct page *from,
unsigned long u_vaddr, struct vm_area_struct *vma)
{
struct folio *src = page_folio(from);
struct folio *dst = page_folio(to);
void *kfrom = kmap_atomic(from);
void *kto = kmap_atomic(to);
copy_page(kto, kfrom);
clear_bit(PG_dc_clean, &dst->flags);
clear_bit(PG_dc_clean, &src->flags);
kunmap_atomic(kto);
kunmap_atomic(kfrom);
}
void clear_user_page(void *to, unsigned long u_vaddr, struct page *page)
{
struct folio *folio = page_folio(page);
clear_page(to);
clear_bit(PG_dc_clean, &folio->flags);
}
EXPORT_SYMBOL(clear_user_page);
SYSCALL_DEFINE3(cacheflush, uint32_t, start, uint32_t, sz, uint32_t, flags)
{
flush_cache_all();
return 0;
}
static noinline void __init arc_ioc_setup(void)
{
unsigned int ioc_base, mem_sz;
if (read_aux_reg(ARC_REG_IO_COH_ENABLE) & ARC_IO_COH_ENABLE_BIT)
panic("IOC already enabled, please upgrade bootloader!\n");
if (!ioc_enable)
return;
__dc_disable();
if (read_aux_reg(ARC_REG_SLC_BCR))
slc_entire_op(OP_FLUSH_N_INV);
mem_sz = arc_get_mem_sz();
if (!is_power_of_2(mem_sz) || mem_sz < 4096)
panic("IOC Aperture size must be power of 2 larger than 4KB");
write_aux_reg(ARC_REG_IO_COH_AP0_SIZE, order_base_2(mem_sz >> 10) - 2);
ioc_base = CONFIG_LINUX_RAM_BASE;
if (ioc_base % mem_sz != 0)
panic("IOC Aperture start must be aligned to the size of the aperture");
write_aux_reg(ARC_REG_IO_COH_AP0_BASE, ioc_base >> 12);
write_aux_reg(ARC_REG_IO_COH_PARTIAL, ARC_IO_COH_PARTIAL_BIT);
write_aux_reg(ARC_REG_IO_COH_ENABLE, ARC_IO_COH_ENABLE_BIT);
__dc_enable();
}
static noinline void __init arc_cache_init_master(void)
{
if (IS_ENABLED(CONFIG_ARC_HAS_ICACHE)) {
struct cpuinfo_arc_cache *ic = &ic_info;
if (!ic->line_len)
panic("cache support enabled but non-existent cache\n");
if (ic->line_len != L1_CACHE_BYTES)
panic("ICache line [%d] != kernel Config [%d]",
ic->line_len, L1_CACHE_BYTES);
if (is_isa_arcv2() && ic->colors > 1)
_cache_line_loop_ic_fn = __cache_line_loop_v3;
else
_cache_line_loop_ic_fn = __cache_line_loop;
}
if (IS_ENABLED(CONFIG_ARC_HAS_DCACHE)) {
struct cpuinfo_arc_cache *dc = &dc_info;
if (!dc->line_len)
panic("cache support enabled but non-existent cache\n");
if (dc->line_len != L1_CACHE_BYTES)
panic("DCache line [%d] != kernel Config [%d]",
dc->line_len, L1_CACHE_BYTES);
if (is_isa_arcompact() && dc->colors > 1) {
panic("Aliasing VIPT cache not supported\n");
}
}
BUILD_BUG_ON_MSG(L1_CACHE_BYTES > SMP_CACHE_BYTES,
"SMP_CACHE_BYTES must be >= any cache line length");
if (is_isa_arcv2() && (l2_line_sz > SMP_CACHE_BYTES))
panic("L2 Cache line [%d] > kernel Config [%d]\n",
l2_line_sz, SMP_CACHE_BYTES);
if (is_isa_arcv2() && l2_line_sz && !slc_enable)
arc_slc_disable();
if (is_isa_arcv2() && ioc_exists)
arc_ioc_setup();
if (is_isa_arcv2() && l2_line_sz && slc_enable) {
__dma_cache_wback_inv = __dma_cache_wback_inv_slc;
__dma_cache_inv = __dma_cache_inv_slc;
__dma_cache_wback = __dma_cache_wback_slc;
} else {
__dma_cache_wback_inv = __dma_cache_wback_inv_l1;
__dma_cache_inv = __dma_cache_inv_l1;
__dma_cache_wback = __dma_cache_wback_l1;
}
}
void __ref arc_cache_init(void)
{
unsigned int __maybe_unused cpu = smp_processor_id();
if (!cpu)
arc_cache_init_master();
if (is_isa_arcv2() && pae40_exist_but_not_enab()) {
if (IS_ENABLED(CONFIG_ARC_HAS_ICACHE))
write_aux_reg(ARC_REG_IC_PTAG_HI, 0);
if (IS_ENABLED(CONFIG_ARC_HAS_DCACHE))
write_aux_reg(ARC_REG_DC_PTAG_HI, 0);
if (l2_line_sz) {
write_aux_reg(ARC_REG_SLC_RGN_END1, 0);
write_aux_reg(ARC_REG_SLC_RGN_START1, 0);
}
}
}