|
|
|
@ -28,6 +28,10 @@ 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);
|
|
|
|
|
|
|
|
|
@ -35,78 +39,24 @@ 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);
|
|
|
|
|
|
|
|
|
|
char *arc_cache_mumbojumbo(int c, char *buf, int len)
|
|
|
|
|
static char *read_decode_cache_bcr_arcv2(int c, char *buf, int len)
|
|
|
|
|
{
|
|
|
|
|
int n = 0;
|
|
|
|
|
struct cpuinfo_arc_cache *p;
|
|
|
|
|
|
|
|
|
|
#define PR_CACHE(p, cfg, str) \
|
|
|
|
|
if (!(p)->line_len) \
|
|
|
|
|
n += scnprintf(buf + n, len - n, str"\t\t: N/A\n"); \
|
|
|
|
|
else \
|
|
|
|
|
n += scnprintf(buf + n, len - n, \
|
|
|
|
|
str"\t\t: %uK, %dway/set, %uB Line, %s%s%s\n", \
|
|
|
|
|
(p)->sz_k, (p)->assoc, (p)->line_len, \
|
|
|
|
|
(p)->vipt ? "VIPT" : "PIPT", \
|
|
|
|
|
(p)->alias ? " aliasing" : "", \
|
|
|
|
|
IS_USED_CFG(cfg));
|
|
|
|
|
|
|
|
|
|
PR_CACHE(&cpuinfo_arc700[c].icache, CONFIG_ARC_HAS_ICACHE, "I-Cache");
|
|
|
|
|
PR_CACHE(&cpuinfo_arc700[c].dcache, CONFIG_ARC_HAS_DCACHE, "D-Cache");
|
|
|
|
|
|
|
|
|
|
p = &cpuinfo_arc700[c].slc;
|
|
|
|
|
if (p->line_len)
|
|
|
|
|
n += scnprintf(buf + n, len - n,
|
|
|
|
|
"SLC\t\t: %uK, %uB Line%s\n",
|
|
|
|
|
p->sz_k, p->line_len, IS_USED_RUN(slc_enable));
|
|
|
|
|
|
|
|
|
|
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 buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Read the Cache Build Confuration Registers, Decode them and save into
|
|
|
|
|
* the cpuinfo structure for later use.
|
|
|
|
|
* No Validation done here, simply read/convert the BCRs
|
|
|
|
|
*/
|
|
|
|
|
static void read_decode_cache_bcr_arcv2(int cpu)
|
|
|
|
|
{
|
|
|
|
|
struct cpuinfo_arc_cache *p_slc = &cpuinfo_arc700[cpu].slc;
|
|
|
|
|
struct cpuinfo_arc_cache *p_slc = &slc_info;
|
|
|
|
|
struct bcr_identity ident;
|
|
|
|
|
struct bcr_generic sbcr;
|
|
|
|
|
|
|
|
|
|
struct bcr_slc_cfg {
|
|
|
|
|
#ifdef CONFIG_CPU_BIG_ENDIAN
|
|
|
|
|
unsigned int pad:24, way:2, lsz:2, sz:4;
|
|
|
|
|
#else
|
|
|
|
|
unsigned int sz:4, lsz:2, way:2, pad:24;
|
|
|
|
|
#endif
|
|
|
|
|
} slc_cfg;
|
|
|
|
|
|
|
|
|
|
struct bcr_clust_cfg {
|
|
|
|
|
#ifdef CONFIG_CPU_BIG_ENDIAN
|
|
|
|
|
unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8;
|
|
|
|
|
#else
|
|
|
|
|
unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7;
|
|
|
|
|
#endif
|
|
|
|
|
} cbcr;
|
|
|
|
|
|
|
|
|
|
struct bcr_volatile {
|
|
|
|
|
#ifdef CONFIG_CPU_BIG_ENDIAN
|
|
|
|
|
unsigned int start:4, limit:4, pad:22, order:1, disable:1;
|
|
|
|
|
#else
|
|
|
|
|
unsigned int disable:1, order:1, pad:22, limit:4, start:4;
|
|
|
|
|
#endif
|
|
|
|
|
} vol;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
@ -129,70 +79,83 @@ static void read_decode_cache_bcr_arcv2(int cpu)
|
|
|
|
|
ioc_enable = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
READ_BCR(AUX_IDENTITY, ident);
|
|
|
|
|
|
|
|
|
|
/* HS 2.0 didn't have AUX_VOL */
|
|
|
|
|
if (cpuinfo_arc700[cpu].core.family > 0x51) {
|
|
|
|
|
if (ident.family > 0x51) {
|
|
|
|
|
READ_BCR(AUX_VOL, vol);
|
|
|
|
|
perip_base = vol.start << 28;
|
|
|
|
|
/* HS 3.0 has limit and strict-ordering fields */
|
|
|
|
|
if (cpuinfo_arc700[cpu].core.family > 0x52)
|
|
|
|
|
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 buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void read_decode_cache_bcr(void)
|
|
|
|
|
char *arc_cache_mumbojumbo(int c, char *buf, int len)
|
|
|
|
|
{
|
|
|
|
|
struct cpuinfo_arc_cache *p_ic, *p_dc;
|
|
|
|
|
unsigned int cpu = smp_processor_id();
|
|
|
|
|
struct bcr_cache {
|
|
|
|
|
#ifdef CONFIG_CPU_BIG_ENDIAN
|
|
|
|
|
unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
|
|
|
|
|
#else
|
|
|
|
|
unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
|
|
|
|
|
#endif
|
|
|
|
|
} ibcr, dbcr;
|
|
|
|
|
struct cpuinfo_arc_cache *p_ic = &ic_info, *p_dc = &dc_info;
|
|
|
|
|
struct bcr_cache ibcr, dbcr;
|
|
|
|
|
int vipt, assoc;
|
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
|
|
p_ic = &cpuinfo_arc700[cpu].icache;
|
|
|
|
|
READ_BCR(ARC_REG_IC_BCR, ibcr);
|
|
|
|
|
|
|
|
|
|
if (!ibcr.ver)
|
|
|
|
|
goto dc_chk;
|
|
|
|
|
|
|
|
|
|
if (ibcr.ver <= 3) {
|
|
|
|
|
if (is_isa_arcompact() && (ibcr.ver <= 3)) {
|
|
|
|
|
BUG_ON(ibcr.config != 3);
|
|
|
|
|
p_ic->assoc = 2; /* Fixed to 2w set assoc */
|
|
|
|
|
} else if (ibcr.ver >= 4) {
|
|
|
|
|
p_ic->assoc = 1 << ibcr.config; /* 1,2,4,8 */
|
|
|
|
|
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->vipt = 1;
|
|
|
|
|
p_ic->alias = p_ic->sz_k/p_ic->assoc/TO_KB(PAGE_SIZE) > 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:
|
|
|
|
|
p_dc = &cpuinfo_arc700[cpu].dcache;
|
|
|
|
|
READ_BCR(ARC_REG_DC_BCR, dbcr);
|
|
|
|
|
|
|
|
|
|
if (!dbcr.ver)
|
|
|
|
|
goto slc_chk;
|
|
|
|
|
|
|
|
|
|
if (dbcr.ver <= 3) {
|
|
|
|
|
if (is_isa_arcompact() && (dbcr.ver <= 3)) {
|
|
|
|
|
BUG_ON(dbcr.config != 2);
|
|
|
|
|
p_dc->assoc = 4; /* Fixed to 4w set assoc */
|
|
|
|
|
p_dc->vipt = 1;
|
|
|
|
|
p_dc->alias = p_dc->sz_k/p_dc->assoc/TO_KB(PAGE_SIZE) > 1;
|
|
|
|
|
} else if (dbcr.ver >= 4) {
|
|
|
|
|
p_dc->assoc = 1 << dbcr.config; /* 1,2,4,8 */
|
|
|
|
|
p_dc->vipt = 0;
|
|
|
|
|
p_dc->alias = 0; /* PIPT so can't VIPT alias */
|
|
|
|
|
vipt = 1;
|
|
|
|
|
assoc = 4; /* Fixed to 4w set assoc */
|
|
|
|
|
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; /* 1,2,4,8 */
|
|
|
|
|
p_dc->colors = 1; /* PIPT so can't VIPT alias */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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%s\n",
|
|
|
|
|
p_dc->sz_k, assoc, p_dc->line_len,
|
|
|
|
|
vipt ? "VIPT" : "PIPT",
|
|
|
|
|
p_dc->colors > 1 ? " aliasing" : "",
|
|
|
|
|
IS_USED_CFG(CONFIG_ARC_HAS_DCACHE));
|
|
|
|
|
|
|
|
|
|
slc_chk:
|
|
|
|
|
if (is_isa_arcv2())
|
|
|
|
|
read_decode_cache_bcr_arcv2(cpu);
|
|
|
|
|
read_decode_cache_bcr_arcv2(c, buf + n, len - n);
|
|
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -1133,10 +1096,8 @@ static noinline void __init arc_ioc_setup(void)
|
|
|
|
|
*/
|
|
|
|
|
static noinline void __init arc_cache_init_master(void)
|
|
|
|
|
{
|
|
|
|
|
unsigned int __maybe_unused cpu = smp_processor_id();
|
|
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_ARC_HAS_ICACHE)) {
|
|
|
|
|
struct cpuinfo_arc_cache *ic = &cpuinfo_arc700[cpu].icache;
|
|
|
|
|
struct cpuinfo_arc_cache *ic = &ic_info;
|
|
|
|
|
|
|
|
|
|
if (!ic->line_len)
|
|
|
|
|
panic("cache support enabled but non-existent cache\n");
|
|
|
|
@ -1149,14 +1110,14 @@ static noinline void __init arc_cache_init_master(void)
|
|
|
|
|
* In MMU v4 (HS38x) the aliasing icache config uses IVIL/PTAG
|
|
|
|
|
* pair to provide vaddr/paddr respectively, just as in MMU v3
|
|
|
|
|
*/
|
|
|
|
|
if (is_isa_arcv2() && ic->alias)
|
|
|
|
|
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 = &cpuinfo_arc700[cpu].dcache;
|
|
|
|
|
struct cpuinfo_arc_cache *dc = &dc_info;
|
|
|
|
|
|
|
|
|
|
if (!dc->line_len)
|
|
|
|
|
panic("cache support enabled but non-existent cache\n");
|
|
|
|
@ -1168,14 +1129,13 @@ static noinline void __init arc_cache_init_master(void)
|
|
|
|
|
/* check for D-Cache aliasing on ARCompact: ARCv2 has PIPT */
|
|
|
|
|
if (is_isa_arcompact()) {
|
|
|
|
|
int handled = IS_ENABLED(CONFIG_ARC_CACHE_VIPT_ALIASING);
|
|
|
|
|
int num_colors = dc->sz_k/dc->assoc/TO_KB(PAGE_SIZE);
|
|
|
|
|
|
|
|
|
|
if (dc->alias) {
|
|
|
|
|
if (dc->colors > 1) {
|
|
|
|
|
if (!handled)
|
|
|
|
|
panic("Enable CONFIG_ARC_CACHE_VIPT_ALIASING\n");
|
|
|
|
|
if (CACHE_COLORS_NUM != num_colors)
|
|
|
|
|
if (CACHE_COLORS_NUM != dc->colors)
|
|
|
|
|
panic("CACHE_COLORS_NUM not optimized for config\n");
|
|
|
|
|
} else if (!dc->alias && handled) {
|
|
|
|
|
} else if (handled && dc->colors == 1) {
|
|
|
|
|
panic("Disable CONFIG_ARC_CACHE_VIPT_ALIASING\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1218,9 +1178,6 @@ static noinline void __init arc_cache_init_master(void)
|
|
|
|
|
void __ref arc_cache_init(void)
|
|
|
|
|
{
|
|
|
|
|
unsigned int __maybe_unused cpu = smp_processor_id();
|
|
|
|
|
char str[256];
|
|
|
|
|
|
|
|
|
|
pr_info("%s", arc_cache_mumbojumbo(0, str, sizeof(str)));
|
|
|
|
|
|
|
|
|
|
if (!cpu)
|
|
|
|
|
arc_cache_init_master();
|
|
|
|
|