// SPDX-License-Identifier: GPL-2.0-only
/*
* ARC Cache Management
*
* Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
*/
#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; /* legacy value for boot */
unsigned long perip_end = 0xFFFFFFFF; /* legacy value */
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;
/*
* As for today we don't support both IOC and ZONE_HIGHMEM enabled
* simultaneously. This happens because as of today IOC aperture covers
* only ZONE_NORMAL (low mem) and any dma transactions outside this
* region won't be HW coherent.
* If we want to use both IOC and ZONE_HIGHMEM we can use
* bounce_buffer to handle dma transactions to HIGHMEM.
* Also it is possible to modify dma_direct cache ops or increase IOC
* aperture size if we are planning to use HIGHMEM without PAE.
*/
if (IS_ENABLED(CONFIG_HIGHMEM) || is_pae40_enabled())
ioc_enable = 0;
} else {
ioc_enable = 0;
}
READ_BCR(AUX_IDENTITY, ident);
/* HS 2.0 didn't have AUX_VOL */
if (ident.family > 0x51) {
READ_BCR(AUX_VOL, vol);
perip_base = vol.start << 28;
/* HS 3.0 has limit and strict-ordering fields */
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; /* Fixed to 2w set assoc */
} else if (is_isa_arcv2() && (ibcr.ver >= 4)) {
assoc = 1 << ibcr.config; /* 1,2,4,8 */
}
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; /* Fixed to 4w set assoc */
p_dc->colors = p_dc->sz_k/assoc/TO_KB(PAGE_SIZE);
} else if