cache.c 26.4 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

V
Vineet Gupta 已提交
40
#define PR_CACHE(p, cfg, str)						\
41 42 43 44
	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 已提交
45 46 47 48
			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" : "",			\
49
			IS_USED_CFG(cfg));
50

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

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

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

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

67 68 69
	return buf;
}

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

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

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
	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 已提交
121 122 123
	p_ic = &cpuinfo_arc700[cpu].icache;
	READ_BCR(ARC_REG_IC_BCR, ibcr);

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

127 128 129 130 131 132 133
	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 已提交
134
	p_ic->line_len = 8 << ibcr.line_len;
V
Vineet Gupta 已提交
135
	p_ic->sz_k = 1 << (ibcr.sz - 1);
V
Vineet Gupta 已提交
136
	p_ic->ver = ibcr.ver;
V
Vineet Gupta 已提交
137 138
	p_ic->vipt = 1;
	p_ic->alias = p_ic->sz_k/p_ic->assoc/TO_KB(PAGE_SIZE) > 1;
V
Vineet Gupta 已提交
139

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

V
Vineet Gupta 已提交
144
	if (!dbcr.ver)
145 146 147 148 149 150 151 152 153 154 155 156
		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 已提交
157

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

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

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

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

/*
177 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
 *		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
216
 */
217

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

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

	/* 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 已提交
239
	if (!full_page) {
240 241 242 243 244 245 246 247 248
		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 已提交
249 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

	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)
290
		write_aux_reg(aux_tag, paddr);
291 292

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

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

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
/*
 * 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 已提交
344 345 346 347
#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
348 349
#elif (CONFIG_ARC_MMU_VER > 3)
#define __cache_line_loop	__cache_line_loop_v4
V
Vineet Gupta 已提交
350 351
#endif

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

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

358
static inline void __before_dc_op(const int op)
V
Vineet Gupta 已提交
359
{
360 361 362 363 364 365
	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
		 */
366 367
		const unsigned int ctl = ARC_REG_DC_CTRL;
		write_aux_reg(ctl, read_aux_reg(ctl) | DC_CTRL_INV_MODE_FLUSH);
368 369 370
	}
}

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

377 378 379 380 381 382 383 384
		/* 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 已提交
385 386 387 388
}

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

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

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

	write_aux_reg(aux, 0x1);

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

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

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

	local_irq_save(flags);

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

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

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

	local_irq_restore(flags);
}

#else

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

#endif /* CONFIG_ARC_HAS_DCACHE */

#ifdef CONFIG_ARC_HAS_ICACHE

441 442 443 444 445 446 447 448 449
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 已提交
450 451 452 453
{
	unsigned long flags;

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

458 459 460 461 462
#ifndef CONFIG_SMP

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

#else
463

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

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

473 474 475 476 477 478
        __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)
{
479 480 481 482 483 484
	struct ic_inv_args ic_inv = {
		.paddr = paddr,
		.vaddr = vaddr,
		.sz    = sz
	};

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

#endif	/* CONFIG_SMP */

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

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

#endif /* CONFIG_ARC_HAS_ICACHE */

497 498 499
noinline void slc_op(unsigned long paddr, unsigned long sz, const int op)
{
#ifdef CONFIG_ISA_ARCV2
500 501 502 503 504 505 506 507
	/*
	 * 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);
508 509 510
	unsigned long flags;
	unsigned int ctrl;

511
	spin_lock_irqsave(&lock, flags);
512 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

	/*
	 * 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);

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

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

552 553 554 555 556 557 558 559 560 561 562 563
/*
 * 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 已提交
564 565
void flush_dcache_page(struct page *page)
{
566 567 568
	struct address_space *mapping;

	if (!cache_is_vipt_aliasing()) {
569
		clear_bit(PG_dc_clean, &page->flags);
570 571 572 573 574 575 576 577 578 579 580 581 582
		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)) {
583
		clear_bit(PG_dc_clean, &page->flags);
584 585 586
	} else if (page_mapped(page)) {

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

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

596 597 598 599 600
/*
 * 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 已提交
601
{
602
	__dc_line_op_k(start, sz, OP_FLUSH_N_INV);
603
}
604

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

610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
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 已提交
626
{
627
	__dc_line_op_k(start, sz, OP_INV);
628 629
	slc_op(start, sz, OP_INV);
}
630

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
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 已提交
658 659 660 661 662
}
EXPORT_SYMBOL(dma_cache_inv);

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

/*
668 669
 * This is API for making I/D Caches consistent when modifying
 * kernel code (loadable modules, kprobes, kgdb...)
V
Vineet Gupta 已提交
670 671 672 673 674 675
 * 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)
{
676
	unsigned int tot_sz;
V
Vineet Gupta 已提交
677

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

	/* 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)) {
691 692 693 694 695 696
		/*
		 * 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.
		 */
697
		__sync_icache_dcache(kstart, kstart, kend - kstart);
V
Vineet Gupta 已提交
698 699 700 701 702 703 704 705 706 707 708 709 710
		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) {
711 712 713
		unsigned int off, sz;
		unsigned long phy, pfn;

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

/*
726 727
 * General purpose helper to make I and D cache lines consistent.
 * @paddr is phy addr of region
728 729
 * @vaddr is typically user vaddr (breakpoint) or kernel vaddr (vmalloc)
 *    However in one instance, when called by kprobe (for a breakpt in
730 731
 *    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
732 733
 *    builtin kernel page will not have any virtual mappings.
 *    kprobe on loadable module will be kernel vaddr.
V
Vineet Gupta 已提交
734
 */
735
void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len)
V
Vineet Gupta 已提交
736
{
737
	__dc_line_op(paddr, vaddr, len, OP_FLUSH_N_INV);
738
	__ic_line_inv_vaddr(paddr, vaddr, len);
V
Vineet Gupta 已提交
739 740
}

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

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

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

	local_irq_save(flags);

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

	local_irq_restore(flags);

}

769 770 771 772 773 774 775 776 777 778 779 780
#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;

781 782
	u_vaddr &= PAGE_MASK;

783
	__flush_dcache_page(paddr, u_vaddr);
784 785 786

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

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

795 796 797 798 799 800 801 802 803 804 805
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

806 807 808
void copy_user_highpage(struct page *to, struct page *from,
	unsigned long u_vaddr, struct vm_area_struct *vma)
{
809 810
	void *kfrom = kmap_atomic(from);
	void *kto = kmap_atomic(to);
811 812 813 814 815 816 817 818 819
	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
820 821 822
	 *
	 * For !VIPT cache, all of this gets compiled out as
	 * addr_not_cache_congruent() is 0
823 824
	 */
	if (page_mapped(from) && addr_not_cache_congruent(kfrom, u_vaddr)) {
825
		__flush_dcache_page((unsigned long)kfrom, u_vaddr);
826 827 828
		clean_src_k_mappings = 1;
	}

829
	copy_page(kto, kfrom);
830 831 832 833 834 835 836 837 838

	/*
	 * 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).
	 */
839
	clear_bit(PG_dc_clean, &to->flags);
840 841 842 843 844 845

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

	kunmap_atomic(kto);
	kunmap_atomic(kfrom);
854 855 856 857 858
}

void clear_user_page(void *to, unsigned long u_vaddr, struct page *page)
{
	clear_page(to);
859
	clear_bit(PG_dc_clean, &page->flags);
860 861 862
}


V
Vineet Gupta 已提交
863 864 865 866 867 868 869 870 871 872
/**********************************************************************
 * 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;
}
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893

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);
894 895 896 897 898 899 900 901 902

		/*
		 * 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;
903 904 905 906 907 908 909 910 911 912 913 914
	}

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

915 916 917
		/* check for D-Cache aliasing on ARCompact: ARCv2 has PIPT */
		if (is_isa_arcompact()) {
			int handled = IS_ENABLED(CONFIG_ARC_CACHE_VIPT_ALIASING);
918

919 920 921 922 923
			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");
		}
924
	}
925

926 927 928 929 930 931 932 933 934 935 936 937 938 939
	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);
	}

940 941 942 943 944 945 946 947 948 949 950 951 952
	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;
953
	} else if (is_isa_arcv2() && l2_line_sz && slc_enable) {
954 955 956 957 958 959 960 961
		__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;
	}
962
}