cache.c 26.3 KB
Newer Older
V
Vineet Gupta 已提交
1
/*
2
 * ARC Cache Management
V
Vineet Gupta 已提交
3
 *
4
 * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
V
Vineet Gupta 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#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>
19
#include <linux/pagemap.h>
V
Vineet Gupta 已提交
20 21 22 23
#include <asm/cacheflush.h>
#include <asm/cachectl.h>
#include <asm/setup.h>

24
static int l2_line_sz;
25
int ioc_exists;
26
volatile int slc_enable = 1, ioc_enable = 1;
27

28 29 30
void (*_cache_line_loop_ic_fn)(unsigned long paddr, unsigned long vaddr,
			       unsigned long sz, const int cacheop);

31 32 33 34
void (*__dma_cache_wback_inv)(unsigned long start, unsigned long sz);
void (*__dma_cache_inv)(unsigned long start, unsigned long sz);
void (*__dma_cache_wback)(unsigned long start, unsigned long sz);

V
Vineet Gupta 已提交
35
char *arc_cache_mumbojumbo(int c, char *buf, int len)
36 37
{
	int n = 0;
38
	struct cpuinfo_arc_cache *p;
39

40
#define IS_USED_RUN(v)		((v) ? "" : "(disabled) ")
V
Vineet Gupta 已提交
41
#define PR_CACHE(p, cfg, str)						\
42 43 44 45
	if (!(p)->ver)							\
		n += scnprintf(buf + n, len - n, str"\t\t: N/A\n");	\
	else								\
		n += scnprintf(buf + n, len - n,			\
V
Vineet Gupta 已提交
46 47 48 49 50
			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_ENABLED(cfg) ? "" : " (not used)");
51

V
Vineet Gupta 已提交
52 53
	PR_CACHE(&cpuinfo_arc700[c].icache, CONFIG_ARC_HAS_ICACHE, "I-Cache");
	PR_CACHE(&cpuinfo_arc700[c].dcache, CONFIG_ARC_HAS_DCACHE, "D-Cache");
54

55 56 57
	if (!is_isa_arcv2())
                return buf;

58 59 60
	p = &cpuinfo_arc700[c].slc;
	if (p->ver)
		n += scnprintf(buf + n, len - n,
61 62
			       "SLC\t\t: %uK, %uB Line%s\n",
			       p->sz_k, p->line_len, IS_USED_RUN(slc_enable));
63

64
	if (ioc_exists)
65 66
		n += scnprintf(buf + n, len - n, "IOC\t\t:%s\n",
				IS_USED_RUN(ioc_enable));
67

68 69 70
	return buf;
}

V
Vineet Gupta 已提交
71 72 73 74 75
/*
 * 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
 */
76
static void read_decode_cache_bcr_arcv2(int cpu)
V
Vineet Gupta 已提交
77
{
78
	struct cpuinfo_arc_cache *p_slc = &cpuinfo_arc700[cpu].slc;
79 80 81 82 83 84 85 86 87 88
	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;

89 90 91 92 93 94 95 96
	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;

97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
	READ_BCR(ARC_REG_SLC_BCR, sbcr);
	if (sbcr.ver) {
		READ_BCR(ARC_REG_SLC_CFG, slc_cfg);
		p_slc->ver = sbcr.ver;
		p_slc->sz_k = 128 << slc_cfg.sz;
		l2_line_sz = p_slc->line_len = (slc_cfg.lsz == 0) ? 128 : 64;
	}

	READ_BCR(ARC_REG_CLUSTER_BCR, cbcr);
	if (cbcr.c && ioc_enable)
		ioc_exists = 1;
}

void read_decode_cache_bcr(void)
{
	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;

V
Vineet Gupta 已提交
122 123 124
	p_ic = &cpuinfo_arc700[cpu].icache;
	READ_BCR(ARC_REG_IC_BCR, ibcr);

V
Vineet Gupta 已提交
125 126 127
	if (!ibcr.ver)
		goto dc_chk;

128 129 130 131 132 133 134
	if (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 */
	}

V
Vineet Gupta 已提交
135
	p_ic->line_len = 8 << ibcr.line_len;
V
Vineet Gupta 已提交
136
	p_ic->sz_k = 1 << (ibcr.sz - 1);
V
Vineet Gupta 已提交
137
	p_ic->ver = ibcr.ver;
V
Vineet Gupta 已提交
138 139
	p_ic->vipt = 1;
	p_ic->alias = p_ic->sz_k/p_ic->assoc/TO_KB(PAGE_SIZE) > 1;
V
Vineet Gupta 已提交
140

V
Vineet Gupta 已提交
141
dc_chk:
V
Vineet Gupta 已提交
142 143 144
	p_dc = &cpuinfo_arc700[cpu].dcache;
	READ_BCR(ARC_REG_DC_BCR, dbcr);

V
Vineet Gupta 已提交
145
	if (!dbcr.ver)
146 147 148 149 150 151 152 153 154 155 156 157
		goto slc_chk;

	if (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 */
	}
V
Vineet Gupta 已提交
158

V
Vineet Gupta 已提交
159
	p_dc->line_len = 16 << dbcr.line_len;
V
Vineet Gupta 已提交
160
	p_dc->sz_k = 1 << (dbcr.sz - 1);
V
Vineet Gupta 已提交
161
	p_dc->ver = dbcr.ver;
162 163

slc_chk:
164 165
	if (is_isa_arcv2())
                read_decode_cache_bcr_arcv2(cpu);
V
Vineet Gupta 已提交
166 167 168
}

/*
169
 * Line Operation on {I,D}-Cache
V
Vineet Gupta 已提交
170 171 172 173 174
 */

#define OP_INV		0x1
#define OP_FLUSH	0x2
#define OP_FLUSH_N_INV	0x3
175 176 177
#define OP_INV_IC	0x4

/*
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
 *		I-Cache Aliasing in ARC700 VIPT caches (MMU v1-v3)
 *
 * ARC VIPT I-cache uses vaddr to index into cache and paddr to match the tag.
 * The orig Cache Management Module "CDU" only required paddr to invalidate a
 * certain line since it sufficed as index in Non-Aliasing VIPT cache-geometry.
 * Infact for distinct V1,V2,P: all of {V1-P},{V2-P},{P-P} would end up fetching
 * the exact same line.
 *
 * However for larger Caches (way-size > page-size) - i.e. in Aliasing config,
 * paddr alone could not be used to correctly index the cache.
 *
 * ------------------
 * MMU v1/v2 (Fixed Page Size 8k)
 * ------------------
 * The solution was to provide CDU with these additonal vaddr bits. These
 * would be bits [x:13], x would depend on cache-geometry, 13 comes from
 * standard page size of 8k.
 * H/w folks chose [17:13] to be a future safe range, and moreso these 5 bits
 * of vaddr could easily be "stuffed" in the paddr as bits [4:0] since the
 * orig 5 bits of paddr were anyways ignored by CDU line ops, as they
 * represent the offset within cache-line. The adv of using this "clumsy"
 * interface for additional info was no new reg was needed in CDU programming
 * model.
 *
 * 17:13 represented the max num of bits passable, actual bits needed were
 * fewer, based on the num-of-aliases possible.
 * -for 2 alias possibility, only bit 13 needed (32K cache)
 * -for 4 alias possibility, bits 14:13 needed (64K cache)
 *
 * ------------------
 * MMU v3
 * ------------------
 * This ver of MMU supports variable page sizes (1k-16k): although Linux will
 * only support 8k (default), 16k and 4k.
 * However from hardware perspective, smaller page sizes aggrevate aliasing
 * meaning more vaddr bits needed to disambiguate the cache-line-op ;
 * the existing scheme of piggybacking won't work for certain configurations.
 * Two new registers IC_PTAG and DC_PTAG inttoduced.
 * "tag" bits are provided in PTAG, index bits in existing IVIL/IVDL/FLDL regs
217
 */
218

V
Vineet Gupta 已提交
219 220 221
static inline
void __cache_line_loop_v2(unsigned long paddr, unsigned long vaddr,
			  unsigned long sz, const int op)
222
{
V
Vineet Gupta 已提交
223
	unsigned int aux_cmd;
224
	int num_lines;
V
Vineet Gupta 已提交
225
	const int full_page = __builtin_constant_p(sz) && sz == PAGE_SIZE;
226

227
	if (op == OP_INV_IC) {
228
		aux_cmd = ARC_REG_IC_IVIL;
V
Vineet Gupta 已提交
229
	} else {
230
		/* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */
231
		aux_cmd = op & OP_INV ? ARC_REG_DC_IVDL : ARC_REG_DC_FLDL;
232 233 234 235 236 237 238 239
	}

	/* Ensure we properly floor/ceil the non-line aligned/sized requests
	 * and have @paddr - aligned to cache line and integral @num_lines.
	 * This however can be avoided for page sized since:
	 *  -@paddr will be cache-line aligned already (being page aligned)
	 *  -@sz will be integral multiple of line size (being page sized).
	 */
V
Vineet Gupta 已提交
240
	if (!full_page) {
241 242 243 244 245 246 247 248 249
		sz += paddr & ~CACHE_LINE_MASK;
		paddr &= CACHE_LINE_MASK;
		vaddr &= CACHE_LINE_MASK;
	}

	num_lines = DIV_ROUND_UP(sz, L1_CACHE_BYTES);

	/* MMUv2 and before: paddr contains stuffed vaddrs bits */
	paddr |= (vaddr >> PAGE_SHIFT) & 0x1F;
V
Vineet Gupta 已提交
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290

	while (num_lines-- > 0) {
		write_aux_reg(aux_cmd, paddr);
		paddr += L1_CACHE_BYTES;
	}
}

static inline
void __cache_line_loop_v3(unsigned long paddr, unsigned long vaddr,
			  unsigned long sz, const int op)
{
	unsigned int aux_cmd, aux_tag;
	int num_lines;
	const int full_page = __builtin_constant_p(sz) && sz == PAGE_SIZE;

	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;
	}

	/* Ensure we properly floor/ceil the non-line aligned/sized requests
	 * and have @paddr - aligned to cache line and integral @num_lines.
	 * This however can be avoided for page sized since:
	 *  -@paddr will be cache-line aligned already (being page aligned)
	 *  -@sz will be integral multiple of line size (being page sized).
	 */
	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);

	/*
	 * MMUv3, cache ops require paddr in PTAG reg
	 * if V-P const for loop, PTAG can be written once outside loop
	 */
	if (full_page)
291
		write_aux_reg(aux_tag, paddr);
292 293

	while (num_lines-- > 0) {
V
Vineet Gupta 已提交
294
		if (!full_page) {
295 296 297
			write_aux_reg(aux_tag, paddr);
			paddr += L1_CACHE_BYTES;
		}
298 299 300 301 302

		write_aux_reg(aux_cmd, vaddr);
		vaddr += L1_CACHE_BYTES;
	}
}
V
Vineet Gupta 已提交
303

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
/*
 * In HS38x (MMU v4), although icache is VIPT, only paddr is needed for cache
 * maintenance ops (in IVIL reg), as long as icache doesn't alias.
 *
 * For Aliasing icache, vaddr is also needed (in IVIL), while paddr is
 * specified in PTAG (similar to MMU v3)
 */
static inline
void __cache_line_loop_v4(unsigned long paddr, unsigned long vaddr,
			  unsigned long sz, const int cacheop)
{
	unsigned int aux_cmd;
	int num_lines;
	const int full_page_op = __builtin_constant_p(sz) && sz == PAGE_SIZE;

	if (cacheop == OP_INV_IC) {
		aux_cmd = ARC_REG_IC_IVIL;
	} else {
		/* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */
		aux_cmd = cacheop & OP_INV ? ARC_REG_DC_IVDL : ARC_REG_DC_FLDL;
	}

	/* Ensure we properly floor/ceil the non-line aligned/sized requests
	 * and have @paddr - aligned to cache line and integral @num_lines.
	 * This however can be avoided for page sized since:
	 *  -@paddr will be cache-line aligned already (being page aligned)
	 *  -@sz will be integral multiple of line size (being page sized).
	 */
	if (!full_page_op) {
		sz += paddr & ~CACHE_LINE_MASK;
		paddr &= CACHE_LINE_MASK;
	}

	num_lines = DIV_ROUND_UP(sz, L1_CACHE_BYTES);

	while (num_lines-- > 0) {
		write_aux_reg(aux_cmd, paddr);
		paddr += L1_CACHE_BYTES;
	}
}

V
Vineet Gupta 已提交
345 346 347 348
#if (CONFIG_ARC_MMU_VER < 3)
#define __cache_line_loop	__cache_line_loop_v2
#elif (CONFIG_ARC_MMU_VER == 3)
#define __cache_line_loop	__cache_line_loop_v3
349 350
#elif (CONFIG_ARC_MMU_VER > 3)
#define __cache_line_loop	__cache_line_loop_v4
V
Vineet Gupta 已提交
351 352
#endif

V
Vineet Gupta 已提交
353 354 355 356 357 358
#ifdef CONFIG_ARC_HAS_DCACHE

/***************************************************************
 * Machine specific helpers for Entire D-Cache or Per Line ops
 */

359
static inline void __before_dc_op(const int op)
V
Vineet Gupta 已提交
360
{
361 362 363 364 365 366
	if (op == OP_FLUSH_N_INV) {
		/* Dcache provides 2 cmd: FLUSH or INV
		 * INV inturn has sub-modes: DISCARD or FLUSH-BEFORE
		 * flush-n-inv is achieved by INV cmd but with IM=1
		 * So toggle INV sub-mode depending on op request and default
		 */
367 368
		const unsigned int ctl = ARC_REG_DC_CTRL;
		write_aux_reg(ctl, read_aux_reg(ctl) | DC_CTRL_INV_MODE_FLUSH);
369 370 371
	}
}

372
static inline void __after_dc_op(const int op)
373
{
374 375 376
	if (op & OP_FLUSH) {
		const unsigned int ctl = ARC_REG_DC_CTRL;
		unsigned int reg;
377

378 379 380 381 382 383 384 385
		/* flush / flush-n-inv both wait */
		while ((reg = read_aux_reg(ctl)) & DC_CTRL_FLUSH_STATUS)
			;

		/* Switch back to default Invalidate mode */
		if (op == OP_FLUSH_N_INV)
			write_aux_reg(ctl, reg & ~DC_CTRL_INV_MODE_FLUSH);
	}
V
Vineet Gupta 已提交
386 387 388 389
}

/*
 * Operation on Entire D-Cache
390
 * @op = {OP_INV, OP_FLUSH, OP_FLUSH_N_INV}
V
Vineet Gupta 已提交
391 392 393
 * Note that constant propagation ensures all the checks are gone
 * in generated code
 */
394
static inline void __dc_entire_op(const int op)
V
Vineet Gupta 已提交
395 396 397
{
	int aux;

398
	__before_dc_op(op);
V
Vineet Gupta 已提交
399

400
	if (op & OP_INV)	/* Inv or flush-n-inv use same cmd reg */
V
Vineet Gupta 已提交
401 402 403 404 405 406
		aux = ARC_REG_DC_IVDC;
	else
		aux = ARC_REG_DC_FLSH;

	write_aux_reg(aux, 0x1);

407
	__after_dc_op(op);
V
Vineet Gupta 已提交
408 409
}

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

V
Vineet Gupta 已提交
413
/*
414
 * D-Cache Line ops: Per Line INV (discard or wback+discard) or FLUSH (wback)
V
Vineet Gupta 已提交
415
 */
416
static inline void __dc_line_op(unsigned long paddr, unsigned long vaddr,
417
				unsigned long sz, const int op)
V
Vineet Gupta 已提交
418
{
419
	unsigned long flags;
V
Vineet Gupta 已提交
420 421 422

	local_irq_save(flags);

423
	__before_dc_op(op);
V
Vineet Gupta 已提交
424

425
	__cache_line_loop(paddr, vaddr, sz, op);
V
Vineet Gupta 已提交
426

427
	__after_dc_op(op);
V
Vineet Gupta 已提交
428 429 430 431 432 433

	local_irq_restore(flags);
}

#else

434 435 436
#define __dc_entire_op(op)
#define __dc_line_op(paddr, vaddr, sz, op)
#define __dc_line_op_k(paddr, sz, op)
V
Vineet Gupta 已提交
437 438 439 440 441

#endif /* CONFIG_ARC_HAS_DCACHE */

#ifdef CONFIG_ARC_HAS_ICACHE

442 443 444 445 446 447 448 449 450
static inline void __ic_entire_inv(void)
{
	write_aux_reg(ARC_REG_IC_IVIC, 1);
	read_aux_reg(ARC_REG_IC_CTRL);	/* blocks */
}

static inline void
__ic_line_inv_vaddr_local(unsigned long paddr, unsigned long vaddr,
			  unsigned long sz)
V
Vineet Gupta 已提交
451 452 453 454
{
	unsigned long flags;

	local_irq_save(flags);
455
	(*_cache_line_loop_ic_fn)(paddr, vaddr, sz, OP_INV_IC);
V
Vineet Gupta 已提交
456 457 458
	local_irq_restore(flags);
}

459 460 461 462 463
#ifndef CONFIG_SMP

#define __ic_line_inv_vaddr(p, v, s)	__ic_line_inv_vaddr_local(p, v, s)

#else
464

465
struct ic_inv_args {
466 467 468 469 470 471
	unsigned long paddr, vaddr;
	int sz;
};

static void __ic_line_inv_vaddr_helper(void *info)
{
N
Noam Camus 已提交
472
        struct ic_inv_args *ic_inv = info;
473

474 475 476 477 478 479
        __ic_line_inv_vaddr_local(ic_inv->paddr, ic_inv->vaddr, ic_inv->sz);
}

static void __ic_line_inv_vaddr(unsigned long paddr, unsigned long vaddr,
				unsigned long sz)
{
480 481 482 483 484 485
	struct ic_inv_args ic_inv = {
		.paddr = paddr,
		.vaddr = vaddr,
		.sz    = sz
	};

486 487
	on_each_cpu(__ic_line_inv_vaddr_helper, &ic_inv, 1);
}
488 489 490 491

#endif	/* CONFIG_SMP */

#else	/* !CONFIG_ARC_HAS_ICACHE */
V
Vineet Gupta 已提交
492

493
#define __ic_entire_inv()
V
Vineet Gupta 已提交
494 495 496 497
#define __ic_line_inv_vaddr(pstart, vstart, sz)

#endif /* CONFIG_ARC_HAS_ICACHE */

498 499 500
noinline void slc_op(unsigned long paddr, unsigned long sz, const int op)
{
#ifdef CONFIG_ISA_ARCV2
501 502 503 504 505 506 507 508
	/*
	 * SLC is shared between all cores and concurrent aux operations from
	 * multiple cores need to be serialized using a spinlock
	 * A concurrent operation can be silently ignored and/or the old/new
	 * operation can remain incomplete forever (lockup in SLC_CTRL_BUSY loop
	 * below)
	 */
	static DEFINE_SPINLOCK(lock);
509 510 511
	unsigned long flags;
	unsigned int ctrl;

512
	spin_lock_irqsave(&lock, flags);
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544

	/*
	 * The Region Flush operation is specified by CTRL.RGN_OP[11..9]
	 *  - b'000 (default) is Flush,
	 *  - b'001 is Invalidate if CTRL.IM == 0
	 *  - b'001 is Flush-n-Invalidate if CTRL.IM == 1
	 */
	ctrl = read_aux_reg(ARC_REG_SLC_CTRL);

	/* Don't rely on default value of IM bit */
	if (!(op & OP_FLUSH))		/* i.e. OP_INV */
		ctrl &= ~SLC_CTRL_IM;	/* clear IM: Disable flush before Inv */
	else
		ctrl |= SLC_CTRL_IM;

	if (op & OP_INV)
		ctrl |= SLC_CTRL_RGN_OP_INV;	/* Inv or flush-n-inv */
	else
		ctrl &= ~SLC_CTRL_RGN_OP_INV;

	write_aux_reg(ARC_REG_SLC_CTRL, ctrl);

	/*
	 * Lower bits are ignored, no need to clip
	 * END needs to be setup before START (latter triggers the operation)
	 * END can't be same as START, so add (l2_line_sz - 1) to sz
	 */
	write_aux_reg(ARC_REG_SLC_RGN_END, (paddr + sz + l2_line_sz - 1));
	write_aux_reg(ARC_REG_SLC_RGN_START, paddr);

	while (read_aux_reg(ARC_REG_SLC_CTRL) & SLC_CTRL_BUSY);

545
	spin_unlock_irqrestore(&lock, flags);
546 547 548
#endif
}

V
Vineet Gupta 已提交
549 550 551 552
/***********************************************************
 * Exported APIs
 */

553 554 555 556 557 558 559 560 561 562 563 564
/*
 * Handle cache congruency of kernel and userspace mappings of page when kernel
 * writes-to/reads-from
 *
 * The idea is to defer flushing of kernel mapping after a WRITE, possible if:
 *  -dcache is NOT aliasing, hence any U/K-mappings of page are congruent
 *  -U-mapping doesn't exist yet for page (finalised in update_mmu_cache)
 *  -In SMP, if hardware caches are coherent
 *
 * There's a corollary case, where kernel READs from a userspace mapped page.
 * If the U-mapping is not congruent to to K-mapping, former needs flushing.
 */
V
Vineet Gupta 已提交
565 566
void flush_dcache_page(struct page *page)
{
567 568 569
	struct address_space *mapping;

	if (!cache_is_vipt_aliasing()) {
570
		clear_bit(PG_dc_clean, &page->flags);
571 572 573 574 575 576 577 578 579 580 581 582 583
		return;
	}

	/* don't handle anon pages here */
	mapping = page_mapping(page);
	if (!mapping)
		return;

	/*
	 * pagecache page, file not yet mapped to userspace
	 * Make a note that K-mapping is dirty
	 */
	if (!mapping_mapped(mapping)) {
584
		clear_bit(PG_dc_clean, &page->flags);
585 586 587
	} else if (page_mapped(page)) {

		/* kernel reading from page with U-mapping */
588
		unsigned long paddr = (unsigned long)page_address(page);
589 590 591 592 593
		unsigned long vaddr = page->index << PAGE_CACHE_SHIFT;

		if (addr_not_cache_congruent(paddr, vaddr))
			__flush_dcache_page(paddr, vaddr);
	}
V
Vineet Gupta 已提交
594 595 596
}
EXPORT_SYMBOL(flush_dcache_page);

597 598 599 600 601
/*
 * DMA ops for systems with L1 cache only
 * Make memory coherent with L1 cache by flushing/invalidating L1 lines
 */
static void __dma_cache_wback_inv_l1(unsigned long start, unsigned long sz)
V
Vineet Gupta 已提交
602
{
603
	__dc_line_op_k(start, sz, OP_FLUSH_N_INV);
604
}
605

606 607 608
static void __dma_cache_inv_l1(unsigned long start, unsigned long sz)
{
	__dc_line_op_k(start, sz, OP_INV);
V
Vineet Gupta 已提交
609 610
}

611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
static void __dma_cache_wback_l1(unsigned long start, unsigned long sz)
{
	__dc_line_op_k(start, sz, OP_FLUSH);
}

/*
 * DMA ops for systems with both L1 and L2 caches, but without IOC
 * Both L1 and L2 lines need to be explicity flushed/invalidated
 */
static void __dma_cache_wback_inv_slc(unsigned long 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(unsigned long start, unsigned long sz)
V
Vineet Gupta 已提交
627
{
628
	__dc_line_op_k(start, sz, OP_INV);
629 630
	slc_op(start, sz, OP_INV);
}
631

632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
static void __dma_cache_wback_slc(unsigned long start, unsigned long sz)
{
	__dc_line_op_k(start, sz, OP_FLUSH);
	slc_op(start, sz, OP_FLUSH);
}

/*
 * DMA ops for systems with IOC
 * IOC hardware snoops all DMA traffic keeping the caches consistent with
 * memory - eliding need for any explicit cache maintenance of DMA buffers
 */
static void __dma_cache_wback_inv_ioc(unsigned long start, unsigned long sz) {}
static void __dma_cache_inv_ioc(unsigned long start, unsigned long sz) {}
static void __dma_cache_wback_ioc(unsigned long start, unsigned long sz) {}

/*
 * Exported DMA API
 */
void dma_cache_wback_inv(unsigned long start, unsigned long sz)
{
	__dma_cache_wback_inv(start, sz);
}
EXPORT_SYMBOL(dma_cache_wback_inv);

void dma_cache_inv(unsigned long start, unsigned long sz)
{
	__dma_cache_inv(start, sz);
V
Vineet Gupta 已提交
659 660 661 662 663
}
EXPORT_SYMBOL(dma_cache_inv);

void dma_cache_wback(unsigned long start, unsigned long sz)
{
664
	__dma_cache_wback(start, sz);
V
Vineet Gupta 已提交
665 666 667 668
}
EXPORT_SYMBOL(dma_cache_wback);

/*
669 670
 * This is API for making I/D Caches consistent when modifying
 * kernel code (loadable modules, kprobes, kgdb...)
V
Vineet Gupta 已提交
671 672 673 674 675 676
 * This is called on insmod, with kernel virtual address for CODE of
 * the module. ARC cache maintenance ops require PHY address thus we
 * need to convert vmalloc addr to PHY addr
 */
void flush_icache_range(unsigned long kstart, unsigned long kend)
{
677
	unsigned int tot_sz;
V
Vineet Gupta 已提交
678

679
	WARN(kstart < TASK_SIZE, "%s() can't handle user vaddr", __func__);
V
Vineet Gupta 已提交
680 681 682 683 684 685 686 687 688 689 690 691

	/* Shortcut for bigger flush ranges.
	 * Here we don't care if this was kernel virtual or phy addr
	 */
	tot_sz = kend - kstart;
	if (tot_sz > PAGE_SIZE) {
		flush_cache_all();
		return;
	}

	/* Case: Kernel Phy addr (0x8000_0000 onwards) */
	if (likely(kstart > PAGE_OFFSET)) {
692 693 694 695 696 697
		/*
		 * The 2nd arg despite being paddr will be used to index icache
		 * This is OK since no alternate virtual mappings will exist
		 * given the callers for this case: kprobe/kgdb in built-in
		 * kernel code only.
		 */
698
		__sync_icache_dcache(kstart, kstart, kend - kstart);
V
Vineet Gupta 已提交
699 700 701 702 703 704 705 706 707 708 709 710 711
		return;
	}

	/*
	 * Case: Kernel Vaddr (0x7000_0000 to 0x7fff_ffff)
	 * (1) ARC Cache Maintenance ops only take Phy addr, hence special
	 *     handling of kernel vaddr.
	 *
	 * (2) Despite @tot_sz being < PAGE_SIZE (bigger cases handled already),
	 *     it still needs to handle  a 2 page scenario, where the range
	 *     straddles across 2 virtual pages and hence need for loop
	 */
	while (tot_sz > 0) {
712 713 714
		unsigned int off, sz;
		unsigned long phy, pfn;

V
Vineet Gupta 已提交
715 716 717 718
		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);
719
		__sync_icache_dcache(phy, kstart, sz);
V
Vineet Gupta 已提交
720 721 722 723
		kstart += sz;
		tot_sz -= sz;
	}
}
724
EXPORT_SYMBOL(flush_icache_range);
V
Vineet Gupta 已提交
725 726

/*
727 728
 * General purpose helper to make I and D cache lines consistent.
 * @paddr is phy addr of region
729 730
 * @vaddr is typically user vaddr (breakpoint) or kernel vaddr (vmalloc)
 *    However in one instance, when called by kprobe (for a breakpt in
731 732
 *    builtin kernel code) @vaddr will be paddr only, meaning CDU operation will
 *    use a paddr to index the cache (despite VIPT). This is fine since since a
733 734
 *    builtin kernel page will not have any virtual mappings.
 *    kprobe on loadable module will be kernel vaddr.
V
Vineet Gupta 已提交
735
 */
736
void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len)
V
Vineet Gupta 已提交
737
{
738
	__dc_line_op(paddr, vaddr, len, OP_FLUSH_N_INV);
739
	__ic_line_inv_vaddr(paddr, vaddr, len);
V
Vineet Gupta 已提交
740 741
}

742 743
/* wrapper to compile time eliminate alignment checks in flush loop */
void __inv_icache_page(unsigned long paddr, unsigned long vaddr)
V
Vineet Gupta 已提交
744
{
745
	__ic_line_inv_vaddr(paddr, vaddr, PAGE_SIZE);
V
Vineet Gupta 已提交
746 747
}

748 749 750 751
/*
 * wrapper to clearout kernel or userspace mappings of a page
 * For kernel mappings @vaddr == @paddr
 */
752
void __flush_dcache_page(unsigned long paddr, unsigned long vaddr)
753
{
754
	__dc_line_op(paddr, vaddr & PAGE_MASK, PAGE_SIZE, OP_FLUSH_N_INV);
755 756
}

V
Vineet Gupta 已提交
757 758 759 760 761 762
noinline void flush_cache_all(void)
{
	unsigned long flags;

	local_irq_save(flags);

763
	__ic_entire_inv();
V
Vineet Gupta 已提交
764 765 766 767 768 769
	__dc_entire_op(OP_FLUSH_N_INV);

	local_irq_restore(flags);

}

770 771 772 773 774 775 776 777 778 779 780 781
#ifdef CONFIG_ARC_CACHE_VIPT_ALIASING

void flush_cache_mm(struct mm_struct *mm)
{
	flush_cache_all();
}

void flush_cache_page(struct vm_area_struct *vma, unsigned long u_vaddr,
		      unsigned long pfn)
{
	unsigned int paddr = pfn << PAGE_SHIFT;

782 783
	u_vaddr &= PAGE_MASK;

784
	__flush_dcache_page(paddr, u_vaddr);
785 786 787

	if (vma->vm_flags & VM_EXEC)
		__inv_icache_page(paddr, u_vaddr);
788 789 790 791 792 793 794 795
}

void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
		       unsigned long end)
{
	flush_cache_all();
}

796 797 798 799 800 801 802 803 804 805 806
void flush_anon_page(struct vm_area_struct *vma, struct page *page,
		     unsigned long u_vaddr)
{
	/* TBD: do we really need to clear the kernel mapping */
	__flush_dcache_page(page_address(page), u_vaddr);
	__flush_dcache_page(page_address(page), page_address(page));

}

#endif

807 808 809
void copy_user_highpage(struct page *to, struct page *from,
	unsigned long u_vaddr, struct vm_area_struct *vma)
{
810 811
	unsigned long kfrom = (unsigned long)page_address(from);
	unsigned long kto = (unsigned long)page_address(to);
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
	int clean_src_k_mappings = 0;

	/*
	 * If SRC page was already mapped in userspace AND it's U-mapping is
	 * not congruent with K-mapping, sync former to physical page so that
	 * K-mapping in memcpy below, sees the right data
	 *
	 * Note that while @u_vaddr refers to DST page's userspace vaddr, it is
	 * equally valid for SRC page as well
	 */
	if (page_mapped(from) && addr_not_cache_congruent(kfrom, u_vaddr)) {
		__flush_dcache_page(kfrom, u_vaddr);
		clean_src_k_mappings = 1;
	}

827
	copy_page((void *)kto, (void *)kfrom);
828 829 830 831 832 833 834 835 836

	/*
	 * Mark DST page K-mapping as dirty for a later finalization by
	 * update_mmu_cache(). Although the finalization could have been done
	 * here as well (given that both vaddr/paddr are available).
	 * But update_mmu_cache() already has code to do that for other
	 * non copied user pages (e.g. read faults which wire in pagecache page
	 * directly).
	 */
837
	clear_bit(PG_dc_clean, &to->flags);
838 839 840 841 842 843 844

	/*
	 * if SRC was already usermapped and non-congruent to kernel mapping
	 * sync the kernel mapping back to physical page
	 */
	if (clean_src_k_mappings) {
		__flush_dcache_page(kfrom, kfrom);
845
		set_bit(PG_dc_clean, &from->flags);
846
	} else {
847
		clear_bit(PG_dc_clean, &from->flags);
848 849 850 851 852 853
	}
}

void clear_user_page(void *to, unsigned long u_vaddr, struct page *page)
{
	clear_page(to);
854
	clear_bit(PG_dc_clean, &page->flags);
855 856 857
}


V
Vineet Gupta 已提交
858 859 860 861 862 863 864 865 866 867
/**********************************************************************
 * Explicit Cache flush request from user space via syscall
 * Needed for JITs which generate code on the fly
 */
SYSCALL_DEFINE3(cacheflush, uint32_t, start, uint32_t, sz, uint32_t, flags)
{
	/* TBD: optimize this */
	flush_cache_all();
	return 0;
}
868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888

void arc_cache_init(void)
{
	unsigned int __maybe_unused cpu = smp_processor_id();
	char str[256];

	printk(arc_cache_mumbojumbo(0, str, sizeof(str)));

	if (IS_ENABLED(CONFIG_ARC_HAS_ICACHE)) {
		struct cpuinfo_arc_cache *ic = &cpuinfo_arc700[cpu].icache;

		if (!ic->ver)
			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 (ic->ver != CONFIG_ARC_MMU_VER)
			panic("Cache ver [%d] doesn't match MMU ver [%d]\n",
			      ic->ver, CONFIG_ARC_MMU_VER);
889 890 891 892 893 894 895 896 897

		/*
		 * In MMU v4 (HS38x) the alising icache config uses IVIL/PTAG
		 * pair to provide vaddr/paddr respectively, just as in MMU v3
		 */
		if (is_isa_arcv2() && ic->alias)
			_cache_line_loop_ic_fn = __cache_line_loop_v3;
		else
			_cache_line_loop_ic_fn = __cache_line_loop;
898 899 900 901 902 903 904 905 906 907 908 909
	}

	if (IS_ENABLED(CONFIG_ARC_HAS_DCACHE)) {
		struct cpuinfo_arc_cache *dc = &cpuinfo_arc700[cpu].dcache;

		if (!dc->ver)
			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);

910 911 912
		/* check for D-Cache aliasing on ARCompact: ARCv2 has PIPT */
		if (is_isa_arcompact()) {
			int handled = IS_ENABLED(CONFIG_ARC_CACHE_VIPT_ALIASING);
913

914 915 916 917 918
			if (dc->alias && !handled)
				panic("Enable CONFIG_ARC_CACHE_VIPT_ALIASING\n");
			else if (!dc->alias && handled)
				panic("Disable CONFIG_ARC_CACHE_VIPT_ALIASING\n");
		}
919
	}
920

921 922 923 924 925 926 927 928 929 930 931 932 933 934
	if (is_isa_arcv2() && l2_line_sz && !slc_enable) {

		/* IM set : flush before invalidate */
		write_aux_reg(ARC_REG_SLC_CTRL,
			read_aux_reg(ARC_REG_SLC_CTRL) | SLC_CTRL_IM);

		write_aux_reg(ARC_REG_SLC_INVALIDATE, 1);

		/* Important to wait for flush to complete */
		while (read_aux_reg(ARC_REG_SLC_CTRL) & SLC_CTRL_BUSY);
		write_aux_reg(ARC_REG_SLC_CTRL,
			read_aux_reg(ARC_REG_SLC_CTRL) | SLC_CTRL_DISABLE);
	}

935 936 937 938 939 940 941 942 943 944 945 946 947
	if (is_isa_arcv2() && ioc_exists) {
		/* IO coherency base - 0x8z */
		write_aux_reg(ARC_REG_IO_COH_AP0_BASE, 0x80000);
		/* IO coherency aperture size - 512Mb: 0x8z-0xAz */
		write_aux_reg(ARC_REG_IO_COH_AP0_SIZE, 0x11);
		/* Enable partial writes */
		write_aux_reg(ARC_REG_IO_COH_PARTIAL, 1);
		/* Enable IO coherency */
		write_aux_reg(ARC_REG_IO_COH_ENABLE, 1);

		__dma_cache_wback_inv = __dma_cache_wback_inv_ioc;
		__dma_cache_inv = __dma_cache_inv_ioc;
		__dma_cache_wback = __dma_cache_wback_ioc;
948
	} else if (is_isa_arcv2() && l2_line_sz && slc_enable) {
949 950 951 952 953 954 955 956
		__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;
	}
957
}